Skip to content

세그먼트 이동 알고리즘을 chase-following에서 path-following으로 변경#60

Merged
gangjung merged 1 commit intomainfrom
feature/BEYONDWORM-122
Mar 5, 2026
Merged

세그먼트 이동 알고리즘을 chase-following에서 path-following으로 변경#60
gangjung merged 1 commit intomainfrom
feature/BEYONDWORM-122

Conversation

@gangjung
Copy link
Copy Markdown
Collaborator

BEYONDWORM-122: 지렁이 세그먼트 Path-Following 구현

문제

지렁이가 회전할 때 세그먼트가 머리의 경로를 정확히 따라가지 않고 코너를 자르는 현상.

기존 방식의 문제점

기존 chase-following은 각 세그먼트가 앞 세그먼트의 현재 위치를 향해 직선으로 이동한다.
이 방식은 이동량이 작을 때는 path-following과 거의 동일한 결과를 내지만, 다음 조건에서 오차가 발생한다:

1. 스프린트 시 틱당 이동량 > 세그먼트 간격

  • 일반 속도: 350px/s ÷ 30tick = ~11.67px/tick (< SEGMENT_SPACING 14px) → 오차 작음
  • 스프린트: 550px/s ÷ 30tick = ~18.33px/tick (> SEGMENT_SPACING 14px) → 머리가 한 틱에 세그먼트 간격보다 멀리 이동하여 경로를 크게 벗어남

2. 오차 누적

  • seg1이 코너를 자르면 seg2는 잘못된 seg1의 위치를 기준으로 또 코너를 자름
  • 뒤쪽 세그먼트로 갈수록 오차가 누적되어 지렁이가 길수록 꼬리 쪽이 심하게 경로를 이탈

3. 급회전 시 오차 증폭

  • TURN_RATE(5.0 rad/s)로 틱당 최대 ~9.5도 회전 가능
  • 급회전이 연속되면 머리는 곡선으로 이동하지만, 세그먼트는 직선으로 쫓아가기 때문에 곡선 안쪽으로 경로를 잘라먹음
  • 특히 스프린트 + 급회전이 겹치면 오차가 크게 증폭됨

4. deltaTime 변동

  • setTimeout은 정확한 타이밍을 보장하지 않음 (GC, 서버 부하 등)
  • deltaTime이 순간적으로 커지면 머리가 평소보다 훨씬 멀리 이동하여 코너 자르기가 심해짐

Chase-Following vs Path-Following

Chase-Following (기존)

각 세그먼트가 이전 세그먼트의 현재 위치를 향해 직선으로 이동하는 방식.
경로를 기록하지 않고, 매 틱마다 앞 세그먼트가 지금 어디 있는지만 보고 쫓아감.

머리가 급회전한 경우:

  HEAD →→↓
          ↓
         ↙   ← seg1이 HEAD의 "현재 위치"로 직선 이동 → 코너를 자름
       ↙     ← seg2도 마찬가지로 코너를 자름

일반 속도(~11.67px/tick)에서는 이동량이 작아 path-following과 거의 동일하게 보이지만,
스프린트(~18.33px/tick)나 지렁이가 길어지면 오차가 누적되어 눈에 띔.

Path-Following (변경 후)

매 틱마다 머리 위치를 배열에 기록하고, 각 세그먼트를 기록된 경로 위의 정확한 지점에 배치하는 방식.
경로를 역순(최신→과거)으로 걸어가며 거리를 누적하고, i × SEGMENT_SPACING 거리 지점을 보간(interpolation)으로 계산.

머리가 급회전한 경우:

  HEAD →→↓
          ↓    ← seg1이 HEAD가 실제로 지나간 곡선 경로 위에 배치
          ↓    ← seg2도 같은 곡선 위에 배치
          ↓

속도나 deltaTime 변동에 관계없이 항상 정확한 경로를 따라감.

성능

메모리

  • 경로 기록: 지렁이당 {x, y} 배열, 세그먼트 100개 기준 약 120개 기록 ≈ ~2KB
  • 매 틱 트리밍으로 필요한 길이만 유지하여 무한히 쌓이지 않음
  • 세그먼트가 극단적으로 많아질 경우(10,000개 → ~160KB) 경로 기록보다 네트워크 전송/렌더링이 더 큰 병목

CPU

  • 기존 chase-following: O(N) — 세그먼트마다 이전 세그먼트와의 거리 계산
  • path-following: O(N) — 경로 포인트를 한 번 순회하며 세그먼트 배치 (경로 길이 ≈ 1.2N)
  • 머리 위치 기록: push O(1), unshift O(H)를 회피하기 위해 배열을 [과거 → 최신] 순서로 저장

@gangjung gangjung self-assigned this Feb 28, 2026
@notion-workspace
Copy link
Copy Markdown

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 지렁이 게임에서 세그먼트가 머리의 경로를 정확히 따라가지 못하고 코너를 자르는 문제를 해결하기 위해 지렁이 세그먼트의 이동 알고리즘을 근본적으로 개선합니다. 기존 방식은 스프린트나 급회전 시 오차가 누적되어 시각적 결함이 발생했지만, 새로운 '경로-따라가기' 방식은 머리의 실제 이동 경로를 기록하고 세그먼트들이 이 경로를 따라 정확히 배치되도록 함으로써 이러한 문제를 해결합니다. 이는 게임의 시각적 일관성과 플레이 경험을 크게 향상시키며, 메모리 및 CPU 사용량 측면에서도 효율성을 고려하여 구현되었습니다.

Highlights

  • 세그먼트 이동 알고리즘 변경: 지렁이 세그먼트의 이동 방식을 기존의 '추적-따라가기(chase-following)'에서 '경로-따라가기(path-following)'로 변경하여, 지렁이 머리의 실제 이동 경로를 정확히 추적하도록 개선했습니다.
  • 경로 기록 시스템 도입: 각 지렁이의 머리 위치를 시간 순서대로 기록하는 positionHistory 배열을 도입하여, 세그먼트들이 이 기록된 경로를 따라 움직이도록 했습니다.
  • 세그먼트 업데이트 로직 개선: updateWormSegments 함수를 완전히 재작성하여, 경로 기록을 역순으로 순회하며 각 세그먼트를 SEGMENT_SPACING 간격에 맞춰 보간(interpolation)하여 배치하도록 했습니다.
  • 메모리 관리 최적화: 경로 기록(positionHistory)이 무한히 커지는 것을 방지하기 위해, 필요한 길이 이상의 오래된 기록은 주기적으로 트리밍하는 로직을 추가했습니다.
  • 전반적인 게임 로직 통합: 새로운 positionHistory 시스템을 updateWormHead, updateSingleWorm, updateWorld, handleKilledWorms, respawnBot, initializeBots, removeAllBots, manageBots, setupSocketHandlers, handleSetUsername, handlePlayerDisconnection 등 게임 서버의 핵심 로직 전반에 걸쳐 통합하고 파라미터를 추가했습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • game-server/src/game/engine.ts
    • initializePositionHistory 함수가 추가되어 지렁이의 초기 경로 기록을 생성합니다.
    • updateWormHead 함수가 positionHistory를 인자로 받아 머리의 새 위치를 기록에 추가하도록 수정되었습니다.
    • updateWormSegments 함수가 경로-따라가기 로직으로 완전히 재작성되어, 경로 기록을 기반으로 세그먼트 위치를 보간하고 기록을 트리밍합니다.
    • updateSingleWorm, updateWorld, removeDeadPlayer, handleKilledWorms, respawnBot 함수들의 시그니처가 positionHistories 맵을 인자로 받도록 업데이트되었습니다.
  • game-server/src/index.ts
    • initializePositionHistory 함수가 임포트되었습니다.
    • 각 지렁이의 경로 기록을 저장하는 positionHistories 맵이 선언 및 초기화되었습니다.
    • initializeBots, removeAllBots, manageBots, updateAndBroadcastGameState, createGameLoop 함수들의 시그니처가 positionHistories 맵을 인자로 받도록 업데이트되었습니다.
    • setupSocketHandlerscreateGameLoop 호출 시 positionHistories 맵이 전달되도록 수정되었습니다.
  • game-server/src/socket/handlers.ts
    • initializePositionHistory 함수가 임포트되었습니다.
    • handleSetUsername 함수가 positionHistories를 인자로 받아 새 플레이어의 경로 기록을 초기화하도록 수정되었습니다.
    • handlePlayerDisconnection 함수가 positionHistories를 인자로 받아 연결 해제된 플레이어의 경로 기록을 삭제하도록 수정되었습니다.
    • setupSocketHandlers 함수 시그니처가 positionHistories 맵을 인자로 받도록 업데이트되었으며, 이를 handlePlayerDisconnectionhandleSetUsername에 전달합니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

지렁이 세그먼트 이동 로직을 기존의 chase-following에서 path-following으로 개선한 점이 인상적입니다. PR 설명에 작성해주신 것처럼, 새로운 방식은 특히 스프린트나 급회전 시의 정확도를 크게 향상시켜 사용자 경험을 개선할 것으로 기대됩니다. 전체적인 코드 변경은 새로운 로직을 잘 반영하고 있으며, 관련 함수들에게 positionHistories를 전달하는 방식도 일관성 있게 적용되었습니다. 코드 품질을 더욱 높이기 위해 몇 가지 리팩터링 제안을 포함했습니다.

}

// 머리의 새 위치를 경로 기록에 추가 (배열 끝 = 최신)
const head = worm.segments[0];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

head 상수가 여기서 다시 선언되고 있습니다. if (magnitude > 0) 블록 내에도 동일한 목적의 상수가 선언되어 있어 혼란을 줄 수 있습니다. 함수 상단에서 const head = worm.segments[0];와 같이 한 번만 선언하고 전체 함수에서 재사용하도록 리팩터링하는 것을 권장합니다. 이렇게 하면 코드 가독성이 향상되고 worm.segments[0]에 대한 반복적인 접근을 피할 수 있습니다.

Copy link
Copy Markdown
Contributor

@konempty konempty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다 👍 👍
지렁이의 몸통 움직임이 저도 뭔가 이상하다 싶었는데 예훈님이 작성해주신 분석자료를 보니까 이해되네요
한가지 걱정되는게 있다면 연산량이 기존 로직보다 확 늘어난것 같은데 성능 문제가 발생하면 그때 최적화 패치 해도 될것 같네요 ㅋㅋㅋ

@gangjung
Copy link
Copy Markdown
Collaborator Author

gangjung commented Mar 5, 2026

고생하셨습니다 👍 👍 지렁이의 몸통 움직임이 저도 뭔가 이상하다 싶었는데 예훈님이 작성해주신 분석자료를 보니까 이해되네요 한가지 걱정되는게 있다면 연산량이 기존 로직보다 확 늘어난것 같은데 성능 문제가 발생하면 그때 최적화 패치 해도 될것 같네요 ㅋㅋㅋ

@konempty
맞아요, 최적화는 일단 추후로 미루려구요ㅋㅋㅋㅋ

@gangjung gangjung merged commit 1eba66f into main Mar 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants