궁 미로 PalaceMaze TIL 4
타임라인은 명령이 아니라 상태다
궁 미로 통로에 문을 달았다. 순간이동하듯 열리는 게 싫어서 타임라인(시간에 따라 커브를 타며 0에서 1로 흐르는 값을 내 주는 블루프린트 노드)을 넣고 노드를 직접 이었다. 여기서 세 번 걸렸다.
한 번은 부드럽고 두 번째부터 순간이동했다
열어 봤다. 부드러웠다. 닫아 봤다. 그것도 부드러웠다. 됐다 싶었는데 다시 열려니까 툭 하고 붙었다.
Play 핀으로 시작한 게 원인이었다. Play는 재생헤드가 있는 자리에서 앞으로 가라는 뜻이다. 한 번 끝까지 가면 헤드가 끝에 멈춰 있으니, 다시 불러도 갈 데가 없어 아무 일도 안 일어난다. 처음부터 다시 돌리려면 PlayFromStart, 되감으려면 Reverse다.
타임라인은 부르면 실행되는 명령이 아니라 재생헤드를 가진 상태 기계(지금 어떤 상태냐에 따라 같은 호출에도 다르게 반응하는 구조)다. 이름이 Play라서 명령처럼 읽히는데, 실제로는 “지금 위치에서 계속”이라는 뜻이다.
열기와 닫기를 따로 만든 게 결함을 한 번 더 숨겼다
타임라인을 넷이나 만들어 뒀다. 열기용 둘, 닫기용 둘. 그래서 각자 한 번씩은 제대로 동작했다. 열고 닫는 것까지 성공하니 통과한 것처럼 보였고, 결함은 세 번째 동작에서야 나왔다.
대칭으로 쪼개 놓으면 같은 결함이 절반마다 한 번씩 성공해서 두 배 늦게 보인다. 토글할 수 있는 것은 세 번 돌린다. 켜고, 끄고, 다시 켠다. 두 번까지는 구조가 가려 줄 수 있다.
흐르는 자리에 “시작해”를 두면 영원히 시작만 한다
문짝이 두 장이라 경첩도 둘이었다. 왼쪽 타임라인의 Update 안에서 오른쪽 타임라인을 시작하도록 이어 놨다.
Update는 매 프레임 돈다. 오른쪽 타임라인은 매 프레임 처음부터 다시 시작됐다. 영원히 0에서 못 벗어난다. 오른쪽 문짝은 한 번도 제대로 돈 적이 없었다.
루프 안에 초기화를 넣은 것과 같은 실수인데, 시간 축에서는 눈에 잘 안 띈다. 뭔가 “안 움직인다”가 나오면 그 시작 명령이 어디서 불리는지부터 본다.
이어 붙일 수 없다는 게 설계를 알려줬다
고치려고 보니 타임라인 노드는 exec 출력(실행 흐름을 다음 노드로 넘기는 핀)이 Update와 Finished뿐이다. 시작한 뒤에 다른 걸 이어 붙일 수가 없다. 둘을 동시에 켜려면 Sequence(실행 흐름을 여러 갈래로 차례로 나눠 주는 노드)를 따로 둬야 했다.
Sequence를 넣어야겠다고 생각한 순간이 신호였다. 그럴 바에는 타임라인 하나가 두 경첩을 다 돌리면 된다. Update 하나에서 Lerp(두 값 사이를 비율만큼 섞는 계산)로 왼쪽은 Lerp(0, 90, alpha), 오른쪽은 Lerp(0, -90, alpha). 넷이던 타임라인이 하나가 됐고, 닫기는 같은 커브를 Reverse로 거꾸로 타면 끝이었다.
도구가 이어 붙이기를 막는 건 대개 그렇게 쓰지 말라는 뜻이다. 우회로가 필요해지면 구조를 의심한다.
다시 계산할 수 있으면 저장이 필요 없다
기와 420장이 한순간에 원점으로 모였다
담장 위에 기와를 420장 얹어 둔 상태에서 크기만 살짝 고치려다 전부 원점으로 쏟아졌다. 한 번의 호출로 420개가 동시에 무너졌다.
되돌리기는 답이 아니었다. 대량 작업은 만들 때 한 번이어도 취소는 개수만큼이다. 앞선 Unreal Engine MCP TIL 1에서 배운 것이다.
살린 건 이름이었다. 타일 이름을 <담장이름>_r<번호>로 지어 뒀다. 담장은 그대로 있으니, 이름만 보면 어느 담장의 몇 번째 타일인지 알 수 있고, 담장 위치에서 타일 위치를 다시 계산할 수 있다. 420장을 전부 제자리로 돌려놓는 데 한 번의 작업이면 됐다.
판단에 쓰는 방식
되돌릴 방법을 미리 정하라는 건 알고 있었는데, 그동안은 저장만 생각했다. 저장은 시점 단위라 거칠다. 저장 이후에 한 다른 작업까지 같이 날아간다.
이번엔 다른 방법이 통했다. 결과물이 스스로 어디서 왔는지 말하게 해 두면, 저장 없이도 복원된다. 이름에 유래를 담아 두는 것이 곧 백업이었다.
그래서 대량으로 만들 때 이름을 짓는 기준이 바뀌었다. 구분만 되면 되는 게 아니라, 그 이름만 보고 원래 값을 다시 구할 수 있어야 한다. 좌표를 되읽어 고치는 방식은 좌표가 망가지면 같이 망가진다.
실물을 알면 설계가 풀린다
담장도 돌, 바닥도 돌이라 답답했다
담장에 전벽돌 머티리얼을 넣고 바닥에 기단석을 깔았다. 둘 다 제대로 들어갔고 타일링도 맞췄는데 보기에 이상했다. 블록 위에 블록이라 눈이 쉴 데가 없었다.
조형 감각으로는 여기까지가 끝이다. “답답하다”는 알겠는데 “그럼 뭘로 바꾸지”는 안 나온다.
답은 실물에 있었다. 궁 마당은 돌바닥이 아니라 마사토(화강암이 풍화된 굵은 모래흙)다. 기단석은 전각 밑에만 깔린다. 바닥을 흙으로 바꾸니 담장 무늬가 그제야 살아났다.
판단에 쓰는 방식
레퍼런스가 실재하는 것을 만들 때는, 취향으로 고민하기 전에 실물이 어떻게 생겼는지 확인한다. 조형 문제처럼 보이는 게 사실은 자료 조사 문제인 경우가 있다.
그리고 이건 역할이 갈리는 지점이기도 하다. “답답하다”는 도구가 못 잡는다. 도구는 머티리얼 값을 되읽고 “정상”이라고 답하던 중이었다. 반대로 “궁 마당은 마사토다”는 알면 바로 나온다. 감각으로 문제를 발견하고, 지식으로 답을 고른다.
안 만들기로 한 것은 감출 방법까지 정해야 끝난다
문을 일부러 땅에 묻었다
문을 통로에 세웠는데 밑면이 바닥보다 60 아래에 있었다. 도구가 그걸 규칙 위반으로 보고 0으로 올리려 했다.
의도였다. 한국 문은 밑에 돌계단이 있어야 하는데, 계단을 만들 생각이 없으니 계단이 들어갈 만큼 문을 묻어 버린 것이었다. 올렸으면 계단 없이 허공에 뜬 문이 됐을 것이다.
판단에 쓰는 방식
생략은 빼는 것으로 끝나지 않는다. 빠진 자리를 어떻게 처리할지까지 정해야 완성이다. 안 만들기로 했으면, 안 만든 게 티 안 나게 하는 방법이 같이 있어야 한다.
그리고 하나 더. 의도인지 실수인지는 만든 사람만 안다. 규칙에서 벗어난 값을 보면 자동으로 고치고 싶어지는데, 고치기 전에 왜 그런지 한 번 물어야 한다. 이번에 내가 말을 안 했으면 문이 조용히 떠올랐을 것이다.