유니티/유니티 프로젝트

Road Kill 개발 일지 3일차 - 코드 리팩토링

강목근 2024. 7. 9. 06:48

https://github.com/khsfashi/Road-Kill

 

GitHub - khsfashi/Road-Kill: 유니티 3D를 통해 레이싱 게임을 제작합니다.

유니티 3D를 통해 레이싱 게임을 제작합니다. Contribute to khsfashi/Road-Kill development by creating an account on GitHub.

github.com

 

코드 리팩토링

코드 리팩토링을 먼저 하자. 

기능 구현 목적으로 코드를 때려 박아 작성한 걸 빨리 분할하지 않으면 겉잡을 수 없이 커진다.

미리 분할을 해둬야 한다. 애초에 짤 때부터 분할을 하면 좋겠지만... 이번에 기획 단계에서 그렇게 세세하게 해두지 않아 생긴 문제다.

현재 컨트롤러 클래스가 가지고 있는 기능

정말 기능을 많이 가지고 있다.

일단 대분류로 Movement, VFX, Suspension, Collision으로 나누어뒀다. 

우선 제일 상위에서 실행되는 코드는 다음과 같다.

  • 사용자 입력 받기
  • 서스펜션 연산하기
  • 땅에 닿은 바퀴 세기
  • 현재 속도 계산하기
  • 이동하기
  • 이펙트 출력하기
  • 충돌 검사하기

Movement에 해당하는 건 사용자 입력 받기, 땅에 닿은 바퀴 세기, 현재 속도 계산하기, 이동하기이다.

땅에 닿은 바퀴 세기라는 함수만 현재 이동 가능한지 체크하기로 바꿔서 추상화를 해보자.

근데 코드를 리팩토링 하다보니 Suspension에서 광선을 쏠 때 땅에 닿은 바퀴 수를 같이 세고 있어서 Movement 관련 기능을 구현할 때 Suspension에 의존적이게 된다.

그렇다고 Movement에서 광선을 또 쏴서 같은 작업을 두 번 할 수도 없는 노릇이고...

Suspension을 Movement 안에 넣어야 할 것 같다. Movement 컴포넌트를 가진 모든 객체가 Suspension 연산을 할 필요가 없으므로 Movement를 추상 클래스로 작성하고 하위 클래스 ArcadeCarMovement 클래스에 포함되게 해야겠다.

VFX에 존재하는 바퀴 위치 변경 기능이 Suspension 결과에 따라 달라지므로 이 기능도 Suspension에 포함되게 바꾼다.

 

현재 속도를 계산하는 함수도 자동차 클래스만 사용하니까 하위 클래스에서 구현해야겠다.

입력 시스템은 지금 직접 받아서 사용하고 있는데, 유니티의 New Input System으로 구현해보고자 한다.

 

근데 그렇게 하니까 그냥 메서드가 완전 적은 추상 클래스가 탄생했다.

와우!

계속 리팩토링 하다보니, 나중에 AI 자동차를 만들 때 ArcadeCarMovement를 그대로 사용해야 할 것 같아서... 키보드 입력 부분을 조금 더 상위로 빼서 의존성을 좀 낮추고자 했다.

원래 코드에서 입력 값을 사용하는 건 Acceleration과 Deceleration밖에 없으니 그 코드를 호출하기 전에 값을 세팅할 수 있도록 Movement 클래스에 UpdateDirection 함수를 추가하자.

인자에 벡터로 방향을 받아올 건데, Movement를 상속받는 다른 클래스도 사용할 수 있게 Vector3를 사용하자. 이 게임은 3D 게임이니까...(사용자 입력만 받는 게 아니라, 임의의 값도 사용할 수 있게 하기 위함)

다른 클래스에서 지금 객체가 이동할 수 있는 상태인지 알아와야 하므로 CanMove 함수도 추가하자.

수정된 클래스
ArcadeCarMovement에서 override된 함수들

이제 하위 클래스에서 각 함수를 private하게 구현하고, 오버라이딩 해야 하는 함수들에서 호출만 하면 된다.

다음으로는 VFX를 구현한다.

VFX는 이펙트를 재생하고 멈추는 코드를 작성한다.

자동차 바퀴를 돌리는 함수는 VFX안에 들어가기에 적절하지 않다 판단했다. (현재 자동차 회전 방향 등이 필요하기 때문)

그래서 Movement 함수에 넣었다. 기존 코드가 서로 간의 의존성이 너무 높았어서 좀 생각하고 고치는 게 버거웠다.

간단하게 작성했다.

다음은 충돌 검사인데, 굳이 클래스로 따로 뺄 필요 없을 것 같아서 작성하지 않았다.

이제 이걸 ArcadeCarController 클래스로 넣어서 코드를 작성해보자.

기존 319줄의 코드가 85줄의 코드로 줄어들었다.

바뀐 코드
모든 컴포넌트를 부착한 모습
변경된 구조를 간단하게 표현한 순서도

흠, 근데 원래 컴포넌트 하나를 넣고 그 안에 모든 변수 넣는 게 안헷갈리고 더 좋았던 것 같다.

안그래도 하위 클래스에서 사용하는 변수가 겹치는 경우가 있었으니까... Serialize Field 대신 생성자로 전달하기를 해볼까 생각중이다.

그게 더 나을까? 고민이다. 그렇게 하면 Start 함수에서 각 클래스를 new로 생성해줘야 한다.

아무튼 이건 차차 고민해보고...

문제점

1. 감속 연산은 있는데 마찰력 계산이 없어서 미끄러짐 (빙판 같음)
2. 공중에 뜨면 조작이 안되게 해놨는데, 중력이 약한 건지 그냥 공중에 떠버림(혹은 전진 속도가 너무 빠른 것 같기도 함)
3. 엄청 빠른 속도로 측면으로 돌면서 부딪히면 바퀴가 옆으로 빠져나가려는 현상이 발생함

 

트랙을 설치하고 쭉 한 번 돌아보니까 문제점이 한가득이다.

로직을 금방 마무리하고 컨텐츠 개발로 들어갈 줄 알았더니 그게 아니었나보다

 

일단 오늘은 여기까지 하고..

오류 수정은 다음에 해야겠다.

리팩토링에 시간을 좀 많이 쓴 것 같다.