250204

Errata·2025년 2월 4일

개발 일지

목록 보기
72/350

✅ 오늘 한 일


  • 한 권으로 끝내는 블렌더 교과서 읽기
  • Project BCA
  • Project MR


📖 한 권으로 끝내는 블렌더 교과서


p.32 ~ 77

정리

Preference

오브젝트 중심 회전 : Navigation > Orbit & Pan > Orbit Around Selection 체크

Object

오브젝트 추가 : Sfhit + A
오브젝트 합치기 : Ctrl + J

  • 3D Cursor : 십자 표시, 오브젝트를 생성하는 기준, 이동 : Shift + 우클
  • Origin : 주황 점, 크기 위치 회전 중심축
    • Object 모드에선 같이 움직이고, Edit 모드에선 안 움직임
    • 이동 : 우클 > Set Origin, 오브젝트 모드 이동 : Ctrl + . > G

Transform

  • Move : G
  • Rotate : R
  • Scale : S
  • 축이 나옴 : Header 패널 > Gizmo > Object Gizmo > Move, Rotate, Scale
  • 한 축 제외 : Shift + x,y,z
  • 수치로 조절 : G,R,S + 숫자
  • 스냅 기능 : Ctrl 누르고 이동
  • 스냅 기능 (스냅) : Shift + Tab
  • 스냅 이동 (3D Cursor, Grid, Object) : Shift + S
  • 단축키 도움말 : 하단
  • Transform Pivot Point : 축의 위치 설정, ., 상단 링크 아이콘
  • Transform Orientation : 좌표계 설정, ,, 상단 축 아이콘
  • Propositional Editing : 주변 오브젝트 영향 미칠건지, O, 상단 봉우리 아이콘

View

  • Vieport Shading : Z

  • 한 오브젝트만 보이게 : /



🎮 Project BCA


체크메이트 구현 계획

체크메이트 조건

  1. 나를 체크 시킨 기물을 잡을 수 있는 기물이 없다
  2. 킹이 공격받는 길목을 차단할 수 있는 방법이 없다
  3. 킹이 공격받지 않으면서 도망갈 수 있는 칸이 없다

놓쳤던 부분 1.
체크시킨 기물을 잡거나, 공격받는 길목을 차단하거나, 킹이 도망가거나
이 세 가지에 해당하는 좌표들만 확인하면 될 줄 알았는데,
기물이 움직였을 때 킹이 노출되어 체크가 되는 가능성(Pin)이 있다.

놓쳤던 부분 2.
체스는 한 번에 한 기물만 움직이니까
킹이 두 기물에 동시에 공격당하는 이중 체크는 불가능할 줄 알았는데,
기물이 움직이며 체크를 하고, 동시에 뒤에 있던 기물의 경로가 열려 체크가 또다시 되는 경우가 발생할 수 있다.

최적화를 하려면 별도의 로직을 넣어주어야 하는데,
통밥을 굴려봤을 때 최적화 전 기물의 전체 계산 횟수는 아무리 많아도 한 번에 10000회 이하가 될 걸로 생각됨.
그러니 해당 연산이 현대 컴퓨터에서 성능에 치명적이진 않을 것.
다만 현재는 클릭할 때마다 해당 기물의 PossibleMove()를 가져오는데, 이를 캐싱하여야 하긴 함.

성능과 개발 속도를 저울질 해봤을 때 굳이 한 걸음 더 나아가 최적화할 필요 없음.

체크가 됐을 때 기물의 모든 움직임에 대해 가상으로 시뮬레이션해보고 킹이 여전히 체크됐는지 아닌지 확인해보기만 하면 됨.
그리고 자신이 움직였을 때 상대의 킹이 체크되는지도 확인해야 한다. 그래야 스테일메이트를 더 편하게 검증할 수 있다.

가상 시뮬레이션 방법

  • 턴이 돌아왔을 때 자신이 갖고 있는 모든 기물의 PossibleMove()를 호출하여 움직일 수 있는 좌표가 모든 기물에 대해 하나라도 있는지 확인한다. (PossibleMove()가 움직임을 캐싱하는 로직 추가할 것) 모든 기물에 대해 움직일 수 있는 수가 하나도 없다면, isKingChecked = true일 때 체크메이트, false일 땐 스테일메이트.
  • PossibleMove()에선 기존의 move를 return하기 전에 move를 순회하면서 해당 움직임을 시뮬레이션해본다.
  • 기물이 해당 움직임을 실행했을 때 체크가 된다면, 해당 수는 불법이니 move 리스트에서 삭제한다.
  • 체크인지 아닌지 확인할 때 상대편의 기물은 전부 새로 계산해야 한다. 캐싱도 하면 안된다. 기물이 움직여 킹으로 향하는 경로가 새로 생길 수 있기 때문이다.

이전 로직 정리

  • 마우스를 클릭했다면 각 턴 State 스크립트의 Update()에서 게임 매니저의 HandleClick()을 호출한다
  • HandleClick()은 클릭 위치에 있는 기물을 확인하여
    • 선택한 오브젝트가 아직 없고, 클릭한 오브젝트가 현재 턴에 해당하는 기물이라면 선택한다.
      • 기물을 선택했을 때, 해당 기물 스크립트에서 PossibleMove()를 호출하여 가능한 경로들을 반환받고, 게임 매니저의 validMoves에 저장해둔다.
    • 선택했던 기물이 있었고, validMoves에 있는 위치라면 MoveTo()로 이동하고, 이때에만 true를 반환한다.
      • MoveTo()에서는
        • 해당 위치에 기물이 있다면 제거한다
        • 폰이면 앙파상, 킹이면 캐슬링 여부를 검사한다
        • 해당 기물의 '씬에서의 transform 정보'와 '기물 데이터를 관리하는 Board 배열에서의 위치'를 변경한다
  • 기물이 움직여서 HandleClick()이 true를 반환했다면 상대의 턴으로 상태를 변경한다.

기물에서 (앙파상과 캐슬링의 구별 없이) 가능한 움직임을 받아오고, 움직일 때 앙파상과 캐슬링을 검증했다.

가상 시뮬레이션 구현

갔다가 다시 돌아오려면

  • 갈 곳 : move 순회할 때 나옴
  • 돌아올 곳 : 순회하기 전에 저장해둠
  • 가상의 움직임에서 희생된 말
    에 대한 정보가 필요하다

SimulateMoveAndFindCheck(x,y,newx,newy)
x랑 y는 기존 좌표, newx랑 newy는 이동해볼 좌표
앙파상과 캐슬링을 먼저 확인해본다
거기에 piece가 있으면 잠깐 해당 적 기물을 배열에서 빼버린다.
남아있는 적 기물들에 대해 possiblemove 호출하여 그 안에 킹 좌표가 있는지 확인한다
확인 다 했으면 기물들 원래대로 돌려놓는다. 캐슬링 했으면 룩도 다시 되돌려놓는다.

캐싱 도입

public enum CheckFrom
{
    MySide,
    OtherSide
}

기존에 임시로 게임 매니저에서 bool 변수 하나를 두고
필요할 때마다 true로 뒀다가 다 쓰면 false로 초기화하던 방식에서
로직마다 checkfrom == CheckFrom.MySide의 조건문을 통해
원하는 정보만을 반환하게 함

캐싱을 했다는 정보가 있으면 연산을 건너뛰고 바로 return
(CheckFrom.OtherSide는 자신의 기물의 움직임에 대해 체크 여부를 시뮬레이션 해볼 때 사용하기 때문에 캐싱을 사용하면 안된다.)

moves 리스트는 추상 클래스 레벨로 올려보내서 코드의 불필요한 중복 제거.
if (checkFrom == CheckFrom.MySide && cached)는 추상 클래스로 올려보내도
조건에 따라 연산을 건너뛰는 로직은 자식 클래스에서 따로 구현해야 해서 base 키워드를 사용하지 못하고 클래스마다 일일이 적음.

    public void EnterState()
    {
        // Debug.Log("Entering Black Turn");
        gameManager.enPassantBlackCandidate = (-1, -1);
        gameManager.black_kingcastling = false;
        gameManager.black_queencastling = false;
        gameManager.ResetAllPieceMoves(); // 캐싱했던 데이터를 전부 리셋하고
        gameManager.CalculateAllMoves(); // 미리 경로를 전부 계산해놓는다
    }

각 턴이 시작될 때마다

    public void ResetMoves()
    {
        moves.Clear();
        cached = false;
    }

모든 기물에서 ResetMoves()로 캐싱 정보를 초기화함.



🎮 Project MR


맵 아트 구현

만들고 싶은 건 이런 맵.
마우스 호버시엔 해당 노드에 대한 정보가 뜨고,
클릭하면 해당 맵에 할당된 씬이 로드된다.
(UI 판떼기들은 그대로 가져오고 싶은데, DontDestroy 어쩌구로 되는지 조사 필요)

픽셀 아트 느낌의 선을 그리기 위해 다양한 방법을 시도해보았으나,
결과물이 전혀 pixelated되지 않았음.

https://www.youtube.com/watch?v=cOyAz4msWiQ
영상을 찾긴 했으나, 겨우 픽셀 아트 때문에 fragment 셰이더까지 건드려야 하는지 의문이 듦.

굳이 복잡하게 가지 말고 아트로 해결하는게 여러모로 더 좋을 것 같다는 생각이 듦.

계획
각 노드에는 빈 게임 오브젝트를 정확하진 않지만 비슷한 위치에 수동으로 위치시키고,
노드만 빨갛게 강조한 동일한 이미지를 똑같은 위치에 덮어씌운다.
게임 오브젝트는 클릭하면 씬이 로드되는 스크립트 달아놓는다.
노드 크기보다 조금 큰 크기의 스프라이트 마스크를, 원하는 게임 오브젝트에 위치시키면 대충 될듯?

이런 식으로

profile
Penser, c'est réapprendre à voir

0개의 댓글