오늘 한 것: 줄어드는 고리와 별을 잡는 조작
1편 마지막에 “하드코딩한 것들부터 인스펙터로 빼고, 그다음이 게임다운 부분”이라고 적어뒀는데 오늘 그게 다 됐습니다. 타이머에 맞춰 고리가 줄어들고, 터치하면 판정이 들어가고, 콤보가 쌓이면 위성이 빨라집니다. 게임 루프라 부를 만한 게 이제야 하나 생겼다.
위성별 데이터(id, comboRange, value)는 ScriptableObject로 뺐습니다. 인스턴스마다 복사본을 갖는 대신 자산 하나를 참조로 공유하는 게 이 클래스의 원래 용도라고 하니 맞게 쓴 것 같습니다. 다만 struct를 SO로 옮기는 순간 기존 SatelliteRing.cs 안의 같은 이름과 겹쳐 CS0101이 났다. 링 쪽을 SatelliteObject로 개명해 넘어갔다.
각도를 더하지 않으니 360도 문제가 사라졌다
결론부터 말하면 회전 방식을 바꿨더니 1편에서 빠뜨렸던 버그가 알아서 없어졌습니다. 1편에서는 offset += Time.deltaTime * speed로 각도를 계속 더했고, 값이 무한정 커지는데 wrap 처리를 안 해뒀다. 지금은 타이머 경과 비율에서 매번 새로 계산합니다.
m_timer += Time.deltaTime;
var velocity = m_timer / m_duration;
m_currentOffset = 360f * velocity;
m_currentRadius = Mathf.Lerp(BASE_RADIUS, BASE_RADIUS * 0.5f, velocity);
transform.localScale = Vector3.one * m_baseScale * (m_currentRadius / BASE_RADIUS);
비율 하나로 각도와 반지름을 동시에 굴립니다. 각도는 360f * velocity라 한 바퀴를 넘길 일이 없고, 반지름은 3.6에서 1.8까지 줄어듭니다. Mathf.Lerp는 t가 0~1로 자동 클램프되니 경과 비율을 그대로 넣어도 안전합니다.
localScale까지 건드린 이유는 씬에 그려둔 고리 스프라이트 때문이다. 반지름만 줄이면 위성은 안으로 들어오는데 그림은 그대로라 둘이 따로 논다. 그래서 반지름 비율을 스케일에도 먹였습니다. 최선은 아닌 것 같아(본인 기준) TODO로 남겨뒀다.
 - 2/body-1.png)
콤보가 오르면 한 바퀴가 빨라진다
private float[] m_angularVelocity = new float[4] { 100, 140, 180, 240 };
m_duration = 360f / m_angularVelocity[m_comboIndex];
콤보 구간이 각속도를 고르고, 각속도가 한 바퀴 시간을 정합니다. 콤보 10 미만이면 초당 100도라 한 바퀴에 3.6초, 30을 넘기면 초당 240도라 1.5초. 처음엔 속도를 상수로 박아뒀는데 돌려보니 너무 빨라서 배열로 빼고 콤보에 물렸습니다. 난이도 곡선을 숫자 네 개로 만지면 되니 이쪽이 나았다.
 - 2/body-2.png)
판정은 상단 90도에서 좌우 60도씩
var deltaAngle = Mathf.DeltaAngle(m_satellites[i].offset, 90f);
if (deltaAngle <= 60f && -60f < deltaAngle)
처음엔 위성 위치 벡터와 위쪽 단위 벡터로 각도를 구할까 고민했는데, 어차피 좌표를 각도에서 만들어 쓰는 중이라 각도를 좌표로 바꿨다가 되돌릴 이유가 없었다. Mathf.DeltaAngle은 두 각도의 최단 차이를 -180~180 범위로 돌려주니 350도와 10도처럼 경계를 넘는 경우도 뺄셈처럼 어긋나지 않습니다.
판정창은 기획 단계에서 115도로 잡았다가 120도로 확정했습니다. 5도 차이가 대수인가 싶지만 한 바퀴가 1.5초까지 빨라지는 구간에서는 이 폭이 곧 체감 난이도다.
 - 2/body-3.png)
다음에 할 것
콤보가 끊기는 조건을 아직 안 만들어서 지금은 쌓이기만 합니다. 여기부터 손볼 생각입니다.
그다음은 잡았을 때와 놓쳤을 때의 연출이 될 것 같다.
참고 소스