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

파티클에 나선 기둥과 물고기 유영 모션을 추가하며 나온 것들.

기능을 데이터로 두면

새 기능이 값 조합이 된다

앞선 TIL 1에서 파티클 모션을 종류마다 따로 짜지 않고, 태어날 때(스폰) 속도·중력·흔들림·수명 같은 값으로 환원해 공용 적분기 하나로 굴리는 구조를 잡았다.

이 구조의 값을 이번에 실감했다. “토네이도 같은데 위로 안 퍼지고 원통으로 도는 것”이라는 새 모션이, 알고 보니 값 하나 차이였다. 흔들림 진폭이 시간에 따라 커지는 정도(퍼짐)를 0으로 두면 원뿔이 원통이 된다.

이러면 새 기능을 만들 때 묻는 질문이 “어떻게 구현하지”가 아니라 “어떤 값이면 그 모양이 나오지”로 바뀐다. 뒤엣것은 만들어 보면서 슬라이더를 움직여 답할 수 있고, 앞엣것은 코드를 새로 짜야 답할 수 있다.

기능 종류가 앞으로 늘어날 것 같으면, 종류마다 코드를 두는 대신 값으로 환원되는 공통 계산을 먼저 만들어 두는 게 크게 남는다. 대신 처음 한두 개는 더 오래 걸린다.


여럿이 만드는 것

형태는 개체가 아니라 분포가 만든다

나선 기둥은 파티클 하나하나가 그냥 좌우로 왔다 갔다 한다. 그런데 개체마다 그 왕복의 시작 지점 — 사인파에서 지금 어디쯤인지를 가리키는 값, 곧 위상 — 을 다르게 주면, 멀리서 볼 때 원통 표면을 도는 것처럼 보인다.

개체가 하는 일은 단순한 좌우 왕복인데 군집이 만드는 형태는 입체다. 개체의 궤적과 전체 인상은 다른 층위의 이야기다.

여럿이 모여 무언가를 만드는 화면을 설계할 때, 개체를 복잡하게 만드는 것과 개체를 흩는 방식을 바꾸는 것 중 후자가 대개 싸고 효과가 크다. 개체를 복잡하게 하면 개수만큼 비용이 늘지만, 흩는 방식은 값 하나다.

두 움직임을 같은 박자로 묶으면 인과가 보인다

물고기는 좌우로 꼬리만 흔들게 했더니 헤엄으로 안 보였다. 실제 물고기는 꼬리를 칠 때 훅 나아가고 그 사이에는 미끄러진다.

그래서 나아가는 속도도 같이 출렁이게 했는데(추진 맥동), 중요한 건 그 출렁임을 꼬리 흔들림과 같은 위상에 묶은 것이다. 따로 두면 꼬리 따로 몸 따로 노는 기계처럼 보인다. 같은 박자로 묶으니 “꼬리를 쳐서 나아간다”는 인과가 눈에 보인다.

여러 움직임을 겹칠 때 각각 자연스럽게 만드는 것만으로는 부족하다. 그것들 사이의 관계가 보여야 하나의 동작으로 읽힌다. 무작위를 줄 때도 “무엇은 흩고 무엇은 묶을지”를 갈라야 한다.


나오면 안 되는 값

조건문으로 걸러 내지 말고 분포로 뺀다

물고기가 왼쪽이나 오른쪽으로 가게 하려고 좌우 속도를 무작위로 흩었더니, 0 근처가 뽑힌 개체는 방향 없이 애매하게 직진했다.

원하는 건 “왼쪽이든 오른쪽이든 정하고 그쪽으로 가는 것”이다. 그래서 방향과 크기를 따로 뽑았다. 방향은 좌우 중 하나, 크기는 최소값 이상에서 무작위. 이러면 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