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

확인하는 방법이 대상마다 다르다

좌표는 다시 재면 되는데 로직은 안 된다

지금까지는 액터를 배치하는 일만 했다. 그건 검증이 쉽다. 배치한 뒤 좌표를 다시 읽어 반지름이 같은지 간격이 고른지 계산하면 끝난다. 숫자로 떨어진다.

닿으면 사라지는 픽업 아이템을 블루프린트로 만들면서 그게 안 통했다. 노드가 그래프에 들어가 있다는 것과 실제로 실행되는 것은 다른 문제다. 컴포넌트 설정을 아무리 되읽어도 “값은 잘 들어갔다”까지만 나오고 “동작한다”는 안 나온다.

그래서 PIE 로그를 봤다

에디터에서 게임을 잠깐 실행(PIE)하고, 로직 중간에 Print String을 심어 두고, 그 줄이 로그에 찍히는지 본다. 이게 새 검증 방식이 됐다.

한 가지 더 있었다. PIE 중에 액터를 검색하면 플레이 월드가 잡히기 때문에, 개수를 세면 실제로 Destroy됐는지가 나온다. 그래서 신호를 두 개 보게 됐다.

로그가 찍혔나        로직이 실행됐나
액터 수가 줄었나      결과가 실제로 반영됐나

둘 중 하나만 보면 놓친다. Print는 찍혔는데 Destroy가 안 된 경우가 실제로 있었다.

판단에 쓰는 방식

무엇을 만들었느냐에 따라 검증 방법을 새로 정해야 한다. 앞 단계에서 쓰던 방법이 다음 단계에도 통할 거라고 가정하면 “다 됐다”는 보고를 그대로 믿게 된다.

그리고 검증 방법이 없는 작업은 그 자체로 위험 신호다. 확인할 방법을 먼저 정하고 시작하는 편이 낫다.


안 될 때 뒤지는 순서가 있다

콜리전 설정만 계속 뒤졌다

픽업에 닿아도 아무 일이 없었다. 콜리전 프로파일을 보고, 컴포넌트가 루트에 제대로 붙었는지 보고, Begin Overlap 이벤트가 그래프에 있는지 보고, 컴파일 경고를 봤다. 전부 정상이었다. 스피어 콜리전 반지름을 상식 밖으로 키워도 반응이 없었다.

원인은 위치였다. 픽업은 공중에 떠 있고 캐릭터는 바닥에 서 있어서 Z가 200 넘게 벌어져 있었다. PlayerStart 좌표를 그대로 썼는데, 캐릭터는 거기서 떨어져 바닥에 선다는 걸 생각 못 했다.

순서를 바꾸니 빨라졌다

돌이켜보니 설정을 먼저 뒤진 게 문제였다. 설정은 눈에 보이니 자꾸 손이 가는데, 가짓수가 많아 시간만 든다.

지금은 이 순서로 본다.

1. 이벤트가 들어오기는 하나    이벤트 직후에 Print String 한 줄
2. 거리 문제인가             콜리전 반지름을 크게 키워 재시도
3. 위치가 맞나               PIE 중 실제 좌표를 재서 대조

1번이 특히 값을 한다. Print가 찍히는 순간 “이벤트는 오고 그 뒤가 문제”로 좁혀져서 후보의 절반이 날아간다. 안 찍히면 반대쪽 절반이 날아간다. 어느 쪽이든 한 번에 절반이 준다.

콜리전 설정 확인은 마지막에 해도 늦지 않다.


에디터에 적힌 값과 런타임 결과는 다르다

PlayerStart는 시작 지점이 아니었다

플레이어 주변에 픽업을 놓으려고 PlayerStart 좌표를 썼다. 그런데 캐릭터가 실제로 서는 자리는 거기가 아니었다.

PlayerStart 위치        (0,   0, 302)
캐릭터의 실제 위치        (0,  60,  92)

공중에서 스폰되니 중력으로 떨어져 바닥에 서고, 레벨에 캐릭터가 미리 배치돼 있으면 PlayerStart를 아예 안 쓴다. 그래서 XY까지 어긋난다.

판단에 쓰는 방식

에디터에 적힌 값은 의도이지 결과가 아니다. 물리가 개입하거나 다른 규칙이 끼어들면 런타임 값은 달라진다.

지금은 실제 좌표가 필요하면 PIE에서 재고 그 값을 쓴다. 한 번 재두면 계속 쓸 수 있어서 비용도 얼마 안 든다.

이건 좌표만의 이야기가 아니었다. 나중에 블루프린트 클래스의 컴포넌트 크기를 바꿨는데 이미 레벨에 배치된 인스턴스에는 안 내려간 일도 있었다. 클래스를 고쳤다고 인스턴스가 따라오는 게 아니다.


사람에게 보여주려고 번역한 이름을 기계도 쓰면 깨진다

문서 예제가 하나도 안 맞았다

블루프린트 그래프를 텍스트(DSL)로 쓰는 기능이 있어서 문서 예제를 그대로 따라 썼는데 계속 실패했다. 실제 노드 타입 이름을 찍어 보니 한글로 번역돼 있었다.

문서 예제   Development|PrintString
실제        개발|PrintString

에디터 표시 언어를 한국어로 쓰고 있었는데, 그 번역이 노드 타입 ID에까지 들어가 있었다. 문서와 예제는 전부 영어 기준이라 하나도 안 맞는 게 당연했다.

더 나쁜 건 일부만 번역됐다는 것이다. 상속 이벤트를 만드는 접두어는 영어로 고정돼 있어서, 뒤에 무엇을 넣어도 짝이 안 맞는 조합이 생겼다. 에디터 언어를 영어로 바꾸는 것 말고는 방법이 없었다.

판단에 쓰는 방식

사람 보라고 번역한 이름을 식별자로도 쓰면, 로케일(언어·지역 설정)이 바뀌는 순간 문서와 예제가 전부 무효가 된다.

이건 언리얼만의 문제가 아니다. 표시 이름과 식별자를 분리하지 않은 도구는 다 이렇게 된다. 앞으로 도구를 고를 때 이 구분이 있는지 보게 될 것 같다.

당장 얻은 실천은 단순하다. 예제가 통째로 안 먹으면 문법을 의심하기 전에 환경 설정이 예제와 다른지 본다. 특히 언어와 지역 설정을 본다.


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