이 글은 Today I Learn 시리즈의 125번째 기록입니다. (총 125개)

타임라인은 명령이 아니라 상태다

궁 미로 통로에 문을 달았다. 순간이동하듯 열리는 게 싫어서 타임라인(시간에 따라 커브를 타며 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으로 올리려 했다.

의도였다. 한국 문은 밑에 돌계단이 있어야 하는데, 계단을 만들 생각이 없으니 계단이 들어갈 만큼 문을 묻어 버린 것이었다. 올렸으면 계단 없이 허공에 뜬 문이 됐을 것이다.

판단에 쓰는 방식

생략은 빼는 것으로 끝나지 않는다. 빠진 자리를 어떻게 처리할지까지 정해야 완성이다. 안 만들기로 했으면, 안 만든 게 티 안 나게 하는 방법이 같이 있어야 한다.

그리고 하나 더. 의도인지 실수인지는 만든 사람만 안다. 규칙에서 벗어난 값을 보면 자동으로 고치고 싶어지는데, 고치기 전에 왜 그런지 한 번 물어야 한다. 이번에 내가 말을 안 했으면 문이 조용히 떠올랐을 것이다.


Series: Today I Learn

1 C++ 자료형(Data Type) 2 MD5 vs pHash 3 C++에서 함수의 선언과 정의 4 Tkinter padx, pady 5 메모리와 포인터 변수 6 Call by Value, Call by Reference, Call by Pointer 비교 7 const 8 Gemfile — Jekyll 프로젝트의 의존성 파일 9 kramdown-parser-gfm — Jekyll의 GFM 파서 10 파서(Parser) 11 AHU vs OHU 12 I might try it vs I'll try it 뉘앙스 차이 13 SESSION_EXPIRE_AT_BROWSER_CLOSE=True 14 configuration key 15 Git stash vs discard 16 subprocess.Popen으로 Windows 탐색기에 명령어를 전달 17 Post 잔디 분석하기 18 Google Sheets Sync 최적화 19 DSL (Domain Specific Language)과 GPL (General Purpose Language) 20 마크다운 표 그리는 방법 21 쿼리 파라미터(Query Parameter). 기존 QR코드 재활용 22 Django 보안 취약점 점검 및 수정 23 OOP Object-Oriented Programming 객체 지향 프로그래밍 24 Fernet 대칭 암호화 25 Jekyll 코드블록 안의 Liquid 태그 26 insertOnConflictUpdate vs DoUpdate(target) 27 세션 필터 28 아코디언(Accordiaon) UI를 펼친상태로 만들기 29 input의 step 30 Word Cloud 31 Google Sheets를 데이터 버스로(with AppSheet) 32 Django 모델 텍스트 필드 자동 수집 패턴 33 localStorage로 섹션 토글 상태 유지 34 순차 ID 생성(`select_for_update()` + `max()` 조합) 35 역참조 검색과 distinct() 36 xlsx 다운로드와 로딩 오버레이 충돌 37 Android 파일 공유 MIME 타입 38 AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 39 UTF-8 BOM과 PowerShell 파일 쓰기 40 소리꽃 KeyBloom TIL 1 41 소리꽃 KeyBloom TIL 2 42 소리꽃 KeyBloom TIL 3 43 메트로놈 Simple Metronome TIL 1 44 소리꽃 KeyBloom TIL 4 45 메트로놈 Simple Metronome TIL 2 46 소리꽃 KeyBloom TIL 5 47 메트로놈 Simple Metronome TIL 3 48 정적 블로그 SEO 정비와 Pagefind 검색 도입 49 메트로놈 Simple Metronome TIL 4 50 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 51 메트로놈 Simple Metronome TIL 5 52 모래게임 Sandrop TIL 1 53 메트로놈 Simple Metronome TIL 6 54 모래게임 Sandrop TIL 2 55 모래게임 Sandrop TIL 3 56 메트로놈 Simple Metronome TIL 7 57 모래게임 Sandrop TIL 4 58 모래게임 Sandrop TIL 5 59 모래게임 Sandrop TIL 6 60 소리꽃 KeyBloom TIL 6 61 모래게임 Sandrop TIL 7 62 모래게임 Sandrop TIL 8 63 소리꽃 KeyBloom TIL 7 64 모래게임 Sandrop TIL 9 65 소리꽃 KeyBloom TIL 8 66 모래게임 Sandrop TIL 10 67 소리꽃 KeyBloom TIL 9 68 소리꽃 KeyBloom TIL 10 69 소리꽃 KeyBloom TIL 11 70 소리꽃 KeyBloom TIL 12 71 소리꽃 KeyBloom TIL 13 72 온실 GreenHouse TIL 1 73 소리꽃 KeyBloom TIL 14 74 온실 GreenHouse TIL 2 75 소리꽃 KeyBloom TIL 15 76 소리꽃 KeyBloom TIL 16 77 소리꽃 KeyBloom TIL 17 78 소리꽃 KeyBloom TIL 18 79 소리꽃 KeyBloom TIL 19 80 소리꽃 KeyBloom TIL 20 81 로그스톤 상표 셀프 출원 TIL 1 82 소리꽃 KeyBloom TIL 21 83 소리꽃 KeyBloom TIL 22 84 소리꽃 KeyBloom TIL 23 85 소리꽃 KeyBloom TIL 24 86 MiniMacro TIL 1 87 Astro가 무엇인지, 왜 옮기는지 88 MiniMacro TIL 2 89 메트로놈 Simple Metronome TIL 8 90 메트로놈 Simple Metronome TIL 9 91 블로그 Astro 이관 TIL 92 오픈데이 Openday TIL 1 93 오픈데이 Openday TIL 2 94 Unreal Engine MCP TIL 1 95 콘티온 Conti On TIL 11 96 오픈데이 Openday TIL 3 97 오픈데이 Openday TIL 4 98 오픈데이 Openday TIL 5 99 ScorePlayer TIL 1 100 BuildingHub TIL 1 101 ScorePlayer TIL 2 102 BuildingHub TIL 2 103 ScorePlayer TIL 3 104 Unreal Engine MCP TIL 2 105 궁 미로 PalaceMaze TIL 1 106 메트로놈 Simple Metronome TIL 10 107 메트로놈 Simple Metronome TIL 11 108 오픈데이 Openday TIL 6 109 BuildingHub TIL 3 110 Obsidian vault에서 코드만 빼기 — directory junction 111 ScorePlayer TIL 4 112 오픈데이 Openday TIL 7 113 URL은 바뀔 수 있는 것에 묶지 않는다 114 도구는 기능이 아니라 내 일에 맞는지로 고른다 115 돌이키기 힘든 변경은 작게 먼저 확인한다 116 궁 미로 PalaceMaze TIL 3 117 궁 미로 PalaceMaze TIL 2 118 소리꽃 KeyBloom TIL 29 119 오픈데이 Openday TIL 8 120 BuildingHub TIL 4 121 ScorePlayer TIL 5 122 BuildingHub TIL 5 123 MiniMacro TIL 3 124 소리꽃 KeyBloom TIL 30 125 궁 미로 PalaceMaze TIL 4 읽는 중