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

파티클 나선 이펙트에 “나선형(토네이도)”과 “나선 기둥” 두 모션이 있었다. 둘을 조절 가능한 하나로 합치려다, 회전을 시간이 아니라 공간(오른 높이) 기준으로 계산해야 코일 간격을 원하는 대로 다룰 수 있다는 걸 배웠다.


두 모션은 같은 물리의 프리셋

파티클 모션은 spawn(파티클이 새로 생겨나는 순간) 시점에 물리값(속도·중력·흔들림 진폭·주파수·성장률·수명)으로 환원되고 update(매 프레임 갱신 함수)는 하나의 제네릭 물리로 돈다. 나선형과 나선 기둥은 이 상수만 달랐다 — 나선형은 흔들림 진폭이 시간에 따라 커지고(swayGrow>0, 원뿔), 나선 기둥은 안 커진다(swayGrow=0, 원통). 그래서 상수를 슬라이더로 노출하면 둘은 하나의 “나선”의 두 프리셋이 된다.

motionPhysics가 speed만 받던 걸 params 전체를 받게 바꿔 이 값들을 읽는다.

// ❌ 전: 케이스마다 상수 고정
function motionPhysics(mode, speed) { /* spiral·helix 별개 case */ }

// ✅ 후: 파라미터를 읽어 하나의 나선으로
function motionPhysics(params) {
  const speed = params.speed;
  // swayAmp: 반경, swayGrow: params.spiralSpread (0=기둥, >0=토네이도)
}

시간 기반 회전의 한계

처음엔 회전을 시간 기준으로 그렸다. x = 중심 + 반경 × sin(회전빈도 × 나이). 이러면 코일 간격(코일 사이 세로 거리)이 상승 속도·회전빈도에 함께 묶인다.

// 시간 기반 — 코일 간격 = 상승속도 × (2π / 회전빈도)
p.x += (p.vx + swayAmp * Math.sin(p.swayFreq * p.age + p.swayPhase)) * dt;

그래서 “코일 간격만” 넓히려 해도 상승 속도나 회전빈도 중 하나가 딸려 움직였다.


코일 간격 = 상승 속도 ÷ 회전 수

이게 핵심 물리다. 이 셋은 한 식으로 묶여 있어 둘을 정하면 나머지는 자동이다.

  • 코일 간격을 넓히며 회전 속도를 유지 → 상승이 빨라진다(날아감)
  • 코일 간격을 넓히며 상승을 유지 → 회전이 느려진다

“넓은 간격 + 빠른 회전 + 느린 상승”은 동시에 불가능하다. 이걸 모르고 슬라이더를 서로 반대로 올려 상쇄시키는 삽질을 반복했다.


공간 회전으로 코일 간격 분리

회전 위상을 시간이 아니라 “오른 높이(climbed)”에 비례시키면 코일 간격이 공간상 고정된다 — 얼마나 빨리 오르든 같은 높이 간격마다 한 바퀴.

const climbed = SPAWN_Y - p.y;  // 스폰 높이에서 얼마나 올랐나
p.x = cx + radius * Math.sin(p.coilK * climbed + p.swayPhase);
// coilK = 2π / 코일간격 → 간격이 넓으면 coilK가 작아 한 바퀴에 더 높이

이러면 코일 간격을 넓혀도 상승 속도와 무관해 “천천히 올라오는 넓은 나선”이 된다. update에서 y를 먼저 갱신한 뒤 climbed로 x를 구하는 순서가 중요하다(x가 현재 높이에 의존하므로).


중복 파라미터를 덜어내기

공간 회전으로 바꾸니 “회전 속도” 슬라이더가 결국 상승 속도(vy)와 같은 걸 조절하고 있었다 — 공용 속도/높이와 중복. 슬라이더를 늘리기보다 중복을 제거하는 게 정리였다. 나선 슬라이더는 회전 반경·퍼짐·코일 간격 셋으로 줄고, 상승·회전 빠르기는 공용 속도/높이가 담당한다.


요약

  • 나선형·나선 기둥은 같은 제네릭 물리의 상수 차이(퍼짐 swayGrow)라 하나로 합쳐 프리셋으로.
  • motionPhysics를 params 전체를 받게 바꿔 상수를 슬라이더로 노출.
  • 코일 간격 = 상승속도 ÷ 회전수 — 셋이 묶여 독립 불가.
  • 회전을 시간→공간(오른 높이) 기준으로 바꾸면 코일 간격이 공간상 고정돼 상승과 분리.
  • 공간 회전은 update에서 y를 먼저 갱신한 뒤 climbed로 x 산출.
  • 파라미터가 중복되면(회전 속도=vy) 늘리지 말고 덜어낸다.

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 습관만들기 Pawbit TIL 1 27 insertOnConflictUpdate vs DoUpdate(target) 28 세션 필터 29 아코디언(Accordiaon) UI를 펼친상태로 만들기 30 input의 step 31 습관만들기 Pawbit TIL 2 32 습관만들기 Pawbit TIL 3 33 Word Cloud 34 Google Sheets를 데이터 버스로(with AppSheet) 35 Django 모델 텍스트 필드 자동 수집 패턴 36 localStorage로 섹션 토글 상태 유지 37 순차 ID 생성(`select_for_update()` + `max()` 조합) 38 역참조 검색과 distinct() 39 xlsx 다운로드와 로딩 오버레이 충돌 40 Android 파일 공유 MIME 타입 41 AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 42 크레센도 Phaser + TypeScript TIL 1 43 크레센도 Phaser + TypeScript TIL 2 44 크레센도 Phaser + TypeScript TIL 3 45 크레센도 Phaser + TypeScript TIL 4 46 크레센도 Phaser + TypeScript TIL 5 47 여둘까 Office Layout TIL 1 48 습관만들기 Pawbit TIL 4 49 여둘까 Office Layout TIL 2 50 여둘까 Office Layout TIL 3 51 크레센도 Phaser + TypeScript TIL 6 52 UTF-8 BOM과 PowerShell 파일 쓰기 53 소리꽃 KeyBloom TIL 1 54 소리꽃 KeyBloom TIL 2 55 소리꽃 KeyBloom TIL 3 56 소리꽃 KeyBloom TIL 4 57 소리꽃 KeyBloom TIL 5 58 습관만들기 Pawbit TIL 5 59 여둘까 Office Layout TIL 4 60 소리꽃 KeyBloom TIL 6 61 소리꽃 KeyBloom TIL 7 62 소리꽃 KeyBloom TIL 8 63 메트로놈 Simple Metronome TIL 1 64 소리꽃 KeyBloom TIL 9 65 메트로놈 Simple Metronome TIL 2 66 소리꽃 KeyBloom TIL 10 67 습관만들기 Pawbit TIL 6 68 크레센도 Phaser + TypeScript TIL 7 69 메트로놈 Simple Metronome TIL 3 70 습관만들기 Pawbit TIL 7 71 정적 블로그 SEO 정비와 Pagefind 검색 도입 72 크레센도 Phaser + TypeScript TIL 8 73 메트로놈 Simple Metronome TIL 4 74 습관만들기 Pawbit TIL 8 75 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 76 메트로놈 Simple Metronome TIL 5 77 모래게임 Sandrop TIL 1 78 습관만들기 Pawbit TIL 9 79 메트로놈 Simple Metronome TIL 6 80 모래게임 Sandrop TIL 2 81 모래게임 Sandrop TIL 3 82 습관만들기 Pawbit TIL 10 83 습관만들기 Pawbit TIL 11 84 메트로놈 Simple Metronome TIL 7 85 모래게임 Sandrop TIL 4 86 모래게임 Sandrop TIL 5 87 습관만들기 Pawbit TIL 12 88 모래게임 Sandrop TIL 6 89 소리꽃 KeyBloom TIL 11 90 모래게임 Sandrop TIL 7 91 모래게임 Sandrop TIL 8 92 소리꽃 KeyBloom TIL 12 93 모래게임 Sandrop TIL 9 94 소리꽃 KeyBloom TIL 13 95 모래게임 Sandrop TIL 10 96 소리꽃 KeyBloom TIL 14 97 소리꽃 KeyBloom TIL 15 98 소리꽃 KeyBloom TIL 16 99 콘티온 Conti On TIL 1 100 소리꽃 KeyBloom TIL 17 101 콘티온 Conti On TIL 2 102 습관만들기 Pawbit TIL 13 103 콘티온 Conti On TIL 3 104 모래게임 Sandrop TIL 11 105 소리꽃 KeyBloom TIL 18 106 여둘까 Office Layout TIL 5 107 모래게임 Sandrop TIL 12 108 모래게임 Sandrop TIL 13 109 콘티온 Conti On TIL 4 110 모래게임 Sandrop TIL 14 111 소리꽃 KeyBloom TIL 19 112 소리꽃 KeyBloom TIL 20 113 소리꽃 KeyBloom TIL 21 114 소리꽃 KeyBloom TIL 22 115 습관만들기 Pawbit TIL 14 116 모래게임 Sandrop TIL 15 117 모래게임 Sandrop TIL 16 118 소리꽃 KeyBloom TIL 23 읽는 중 119 소리꽃 KeyBloom TIL 24 120 소리꽃 KeyBloom TIL 25 121 소리꽃 KeyBloom TIL 26 122 온실 GreenHouse TIL 1 123 콘티온 Conti On TIL 5 124 모래게임 Sandrop TIL 17 125 소리꽃 KeyBloom TIL 27 126 온실 GreenHouse TIL 2 127 콘티온 Conti On TIL 6 128 모래게임 Sandrop TIL 18 129 콘티온 Conti On TIL 7 130 모래게임 Sandrop TIL 19 131 소리꽃 KeyBloom TIL 28 132 모래게임 Sandrop TIL 20 133 모래게임 Sandrop TIL 21