New APF

같은 게임을 두 번 만들며, '구현'과 '설계'의 차이를 배우다


고등학생 시절 즐겨했던 모바일 게임 액션퍼즐 패밀리를 모작하며 프로젝트를 시작했습니다.





첫 번째 프로젝트(Project APF)에서는 기능 구현 자체에 집중했습니다.

두 번째 프로젝트(New APF)에서는 동일한 게임을 다시 제작하며,

단순 구현이 아닌 구조 설계, 성능 개선, 유지보수성 확보에 초점을 맞추었습니다.



"이 프로젝트는 '게임을 완성하는 경험'이 아니라 게임을 다시 설계하는 경험이었습니다."

1. 시스템 개선

1-1. 사운드 시스템 개선

◆ 문제

  • 효과음과 배경음이 없었으며, 사운드 관리 구조가 존재하지 않았습니다.
  • 오디오 재생이 즉시 이루어질 경우 초기 프레임에 부담이 발생할 수 있었습니다.

◆ 개선

  • Singleton 기반 SoundManager 설계
  • Resources에서 오디오 Load 후 재사용
  • 로그인 시 볼륨 0 상태로 선재생하여 오디오 지연 방지
  • PausePanel에 환경설정 UI 추가
  • BGM / SFX 개별 제어 가능하도록 설계

◆ 향후 보완

  • AudioMixer 기반 볼륨 관리
  • 사운드 정규화 도입
  • 음소거 방식 → 슬라이더 기반 세부 볼륨 조절 방식으로 변경

1-2. 불필요한 시스템 제거

◆ 튜토리얼 제거

  • UX 개선 없이 유지하는 것은 오히려 완성도를 떨어뜨린다고 판단하여 제거 후 추후 재설계 예정

◆ 지역/학교 점수 시스템 제거

  • 대규모 유저 기반이 필요한 기능으로, 현재 프로젝트 규모와 맞지 않아 제거


"기능을 추가하는 것보다, 프로젝트 규모에 맞는 설계를 유지하는 것이 더 중요하다고 판단했습니다."

2. 밥(재화) 충전 시스템 개선

2-1. 1차 설계 - 로컬 시간 기반

◆ 기존 방식

  • 마지막 사용 시간을 기준으로 충전 예정 시간 배열 저장
  • 날짜와 시간을 분리하여 자정 변경 대응

◆ 문제점

  • 로컬 시간 변경 시 무한 충전 가능
  • 시간 계산 분기 로직이 매우 복잡해짐
  • 유지보수 난이도 증가

2-2. 2차 설계 - 서버 시간 기반

◆ 개선 방식

  • 밥 사용 시 서버 시간 기록
  • 현재 서버 시간과의 차이를 계산하여 충전 개수 산출

◆ 개선된 점

  • 로컬 시간 조작 문제 해결
  • 시간 계산 단순화

◆ 문제점

  • 타이머 진행 중일 때 추가 소모 시 시간이 갱신되는 UX 문제 발생
  • 서버 시간 요청이 잦아 서버 부하 우려

2-3. 3차 설계 - 서버 오프셋 보정 방식

◆ 개선 방식

  • 로그인 시 서버 시간 1회 요청하여 로컬 시간과의 오차(offset) 저장
  • 이후 서버 호출 없이 로컬 시간 + offset으로 서버 시간 추정
  • 저장하는 시간의 기준 : '마지막 사용 시간' → '다음 충전 완료 시간'으로 변경

◆ 개선된 점

  • 서버 호출 최소화
  • UX 문제 해결
  • 시간 계산 구조 단순화
  • 유지보수 용이성 향상

◆ 한계 및 보완 방향

  • 로컬 시간을 임의로 변경하는 경우 완전 방어 불가
  • 일정 주기 서버 동기화 / 비정상적인 시간 변화 감지 트리거 도입 예정


"단순 기능 구현을 넘어 보안, UX, 서버 부하까지 고려한 설계 경험을 얻었습니다."




3. Ingame 구조 리팩토링

3-1. 매니저 구조 개선

◆ 기존 구조

  • IngameManager가 대부분의 로직 담당
  • Update 내 다수의 if 분기
  • 상태 플래그가 어지럽게 뒤섞임

◆ 개선

  • 게임 준비 / 진행 / 일시정지 등 범용 요소 객체화
  • Update 내부 로직 의도별 분리
  • 함수 단위 책임 분리
  • 가독성 향상

3-2. Callback 중심 구조로 전환

◆ 기존 구조

  • Update 내부에서 시간감소 / 입력처리 / 이동 / 판정 / 특수 타일 처리 / 게임 오버 처리 등
  • 많은 기능들이 동작하여 구조가 복잡하고 버그에 취약

◆ 개선

  • 상태 플레그를 업데이트 상단에서 조기 차단
  • 이벤트 기반 Callback 구조 활용
  • 로직 흐름 단순화

◆ 결과

  • Update 의존성 감소
  • 디버깅 난이도 감소 및 가독성 향상

3-3. GC 최소화

◆ 기존 구조

  • Instantiate / Destroy 반복 사용
  • FindGameObjectsWithTag 빈번하게 호출
  • GC 발생으로 인해 프레임 드랍 가능성 상승

◆ 개선

  • MemoryPoolManager 도입하여 반복 오브젝트 풀링 처리
  • 오브젝트 탐색 제거 및 객체 참조화

◆ 결과

  • 런타임 메모리 안정화
  • 프레임 안정성 향상

3-4. 입력 및 분기 최적화

◆ 방향키 중복 코드 제거

◆ 공통 로직 함수화

◆ Action 활용으로 가독성 향상

3-5. 프레임 독립성 확보

◆ screenScale 도입

◆ Time.deltaTime 기반 이동 처리

◆ 프레임 의존 로직 제거

항목 Project APF New APF 개선점
게임 구조 Ingame Manager 중심 Manager 구조 분리 책임 분리 및 가독성 향상
시간 시스템 로컬 시간 서버 Offset 시간 조작 방지 및 재화 충전 정확도 향상
오브젝트 생성 Instantiate/Destroy 구조 Object Pool 구조 GC 감소 및 성능 안정화
로직 구조 Update/bool 중심 Callback 구조 GC 및 Update 의존성 감소
해상도 대응 없음 Screen Scale 대응 기기별 일관성 유지

4. 기술적 보완 과제

◆ TimeManager 객체화

◆ isGameOver/isGameStart 대신 gameState enum 기반 상태 관리 구조로 변경

◆ Canvas 분리 또는 SpriteRenderer 전환을 통한 성능 개선

◆ AudioMixer 기반 사운드 개선

◆ 튜토리얼 UX 재설계

◆ 데이터베이스 기반 캐릭터 / 펫 시스템 확장

5. 마무리


같은 게임을 두 번 제작하며 저는

'기능을 완성하는 것'과 '구조를 설계하는 것'은 다르다
라는 것을 배웠습니다.

첫 번째 프로젝트에서는 '동작하는 게임'을 만들었다면,

두 번째 프로젝트에서는 '유지 가능한 게임'을 설계하려 노력했습니다.

이 프로젝트를 통해 저는 기능 구현 중심의 개발자에서

설계와 구조를 고민하는 개발자로 사고가 확장되었습니다.




구현한 코드는 여기에서 확인하실 수 있습니다.

Wanna Play New APF?

Play This Game!

Loading...