Unity 최종 프로젝트 - 11 [Feat.게임수학]

이준호·2024년 1월 29일
0

📌 Unity 최종 프로젝트



📌 현재 작업중 목록

➔ FOV (Field Of View)

좀비가 플레이어를 인지하는 범위가 마치 사람이 보는 시야의 각처럼 시야각안에 들어와야지만 인지가 되는것이 3D에서 훨씬 자연스럽다. 그 시야각을 구현하기 위한 기술(?)이다.

FOV 사용 이유

  • 원래는 Physics.OverlapSphere를 사용하여 _detectDistance를 반지름으로 한 원을 그려 그 안에 들어오면 인지를 하도록 하였는데, 그것은 이러한 장르의 게임에서 어색하다는 느낌을 받았다.

FOV를 사용하기 위해 현재 하고있는 것

  • 삼각함수를 이용한 Field Of View, 즉 시야각을 구현하기로 생각하여 피타고라스부터 벡터의 내적까지 선행공부를 하고있다.

FOV를 어떤식으로 사용할지 구상

  • Vector3.Angle은 두 벡터 사이의 각도(Degree)를 계산하기에 직관적으로 이해하기 편하고 시인성이 좋지만, 내부적으로 ArcCos함수를 사용하여 계산하므로 연산비용이 비교적 높다.

  • 나의 경우는 Behavior Tree에서 트리가 매 프레임마다 순회를 돌고있고, 좀비가 플레이어를 감지하는 로직의 노드는 매우 자주일어나는 연산이기에 이 부분에서는 최대한 최적화를 진행해주는 것이 좋겠다고 생각하였다.

  • 그래서 생각중인 방식이 Vector3.Dot인데, Vector3.Dot은 두 벡터의 내적을 계산하기에 두 벡터의 길이와 각도(Cos)에 의해서 결정된다. 그래서 Angle보다 연산 비용이 낮다. "참고로 벡터의 내적은 스칼라(Scaler, 방향 x 크기만 존재)"

  • 또는 아예 벡터를 이용해 직접 각을 라디안으로 구하여 비교할지도 고민중이다.












📌 선행 게임 수학

➔ 피타고라스 정리

출저 - 나무위키




➔ 벡터의 덧셈과 뺄셈

  • 벡터의 덧셈 : a벡터 + b벡터라면 a와 b벡터가 서로 벡터만큼 (ax + bx) + (ay + by) 하면 평행사변형이 나오는데 그 두 벡터의 중심으로 나가는 방향 길이는 두 벡터의 합만큼 나온다.

  • 벡터의 뺄셈 : a벡터 + (-b)벡터라면 b벡터에서 a벡터로 향하는 방향이 나온다. (벡터의 덧셈에서 평행사변형이 반대편에서 이루어지는 걸로 보면 쉽다.)

  • magnitude : 벡터의 길이(힘|속력|거리)만 남긴다.

  • normalized : 벡터의 방향만 남긴다.




➔ 원주율

π = 3.14 , 원주율
원의 지름이 1 일 때, 한바퀴 굴렀을때의 거리 : 3.14

  • 원의 중심으로 하여 정육각형으로 만들고 다음 정십이각형 계속해서 분할하여 원에 가까워질 때까지 한 후 나온 원의 둘레가 π이다.

출저 - 유니티지현쨩




➔ 라디안(Radian)

  • 부채꼴의 반지름이 1이고 호의 길이도 1이라 했을 때, 1 라디안 이라고 한다 (𝜽 = 세타 = 1 radian)

  • 원의 둘레는 2π, 지름을 1로 하였을 때, π = 원주 즉, 원주가 π이고 반지름을 1로 하였을 때, 반원주 = π이다.
  • Mathf.Rad2Deg : Radian -> Degree

  • Mathf.Deg2Rad : Degree -> Radian

출저 - 유니티지현쨩




➔ Sin과 Cos

  • 𝜽를 각으로 하는 삼각형을 만들었을 때, 𝜽와 마주보는 변의 길이름 Sin 이라고 한다.

  • Sin은 y축(높이)을 나타내고 있는것이니, Cos은 그 반대로 x축(밑변)을 타나낸다.

  • 삼각함수의 Sin과 Cos을 합치면 원이 된다. (Sin을 y축으로, Cos을 x축으로 두고 서로 그래프를 그리면 원이 된다.)

  • Sin이 클 수록 Cos은 작아지고, Cos이 클 수록 Sin은 작아진다.
    Sin이 y축으로 움직이는 동시에 Cos이 x축으로 움직이면서 원이 그려진다.

  • 빗변이 1이라고 하였을 때, (normalize, 정규화 하여 방향만 남음)

  • Cos𝜽 = 밑변/빗변(=1)을 하면 밑변이 나오는데 그 밑변의 길이가 x축 즉 Cos𝜽가 된다.

  • Sin𝜽는 높이/빗변(=1)을 하면 높이가 나오는데 그 높이의 길이가 y축 즉 Sin가 된다.

출저 - 유니티지현쨩




➔ Tan

출저 - 유니티지현쨩




➔ 백터의 내적

  • A벡터와 B벡터의 내적 (내적은 · 부호를 생략 불가능) = A벡터와 x B벡터의 크기(Magnitude) x Cos𝜽 = 각 벡터의 성분(x, y, z)

제 1 코사인 법칙

제 2 코사인 법칙

1,2 법칙의 공식

내적의 증명/유도

  • 분배법칙으로 나온 값과 제2 코사인 법칙으로 나온 값은 같기에 공통적으로 빠지는 부분을 빼면 공식화 된다.
    A벡터 · B벡터 (내적) = A벡터(Magnitude) · B벡터 (magnitude) · Cos𝜽

  • a와 b벡터 모두 normalized(정규화)된 벡터라면 즉, 길이가 1인 벡터라면, a와 b벡터의 내적은 Cos𝜽가 된다.

  • 벡터 a가 있다고 생각하면 높이는 ay이고 밑변은 ax일 것이다.

  • a^이 아니라 ab로 바꿔보면 ab = 내적의 공식이 나온다.

  • 검은 화살표의 벡터를 빗변으로 삼각형을 그리면 밑변은 ax - bx, 높이는 ay - by 이다. 그 바탕의 각각 분배법칙과 피라고라스의 정리로 나온 계산식이다.

  • 두 식(분배 법칙, 피타고라스 정리)을 풀어서 정리.

벡터 내적의 응용

  • 벡터 a, b가 normalize(정규화)되어서 둘 다 방향만 남아 길이가 1인 경우, a 와 b벡터의 내적은 Cos𝜽이다.

  • 그러면 두 벡터가
    같은 방향을 바라본다면, 1
    수직인 경우, 0
    반대 방향인 경우는, -1

출저 - 유니티지현쨩

이후 정리 방향

  • 아직 익숙치 못하여 정리가 뒤죽박죽 시인성이 좋지 않다. 나중에 게임수학 관련만 따로 모아서 더 추가하여 다시 정리할 예정이다.











📌 튜터님 피드백

➔ 내가 한 질문의 피드백

Behavior Tree의 노드 구조 및 구현

  • BT의 현재 구현 방식은 효과적이지만, 액션 노드를 별도의 클래스로 분리하면 좋겠네요. 예를 들어, BTActionNode.cs 클래스를 생성하여 각각의 행동을 구현할 수 있습니다.
  • FSM과 BT의 조합을 고려할 때, 예를 들어 PlayerFSM.cs 내에서 특정 상태에서 BT를 실행하는 방식으로 구현할 수 있을겁니다. BT 실행 로직은 ExecuteUpdate 메서드 내에서 호출하면 되겠죠?

BT의 Script Object 활용

  • Scriptable Object를 사용하면 BT 구성을 데이터로 관리한다면, BehaviorTreeAsset.cs라는 Scriptable Object 클래스를 생성하고, 이를 통해 트리의 구조와 노드의 설정을 관리하는 형태가 되겠죠? BT 설정을 쉽게 조정할 수 있다는 장점이 있어서 개발 효율성이 높아진다는 장점이 있긴한데, 꼭 반드시 구현해야만하는 것은 아니니까 시간이 된다면 한번 도전해보세요.

BT의 업데이트 방식

  • BT가 매 프레임 업데이트되는 것은 비효율적일 수 있어요. 대신, 특정 이벤트나 조건에 따라 BT를 업데이트하는 방식을 고려해보세요. 예를 들어, EnemyAI.cs에서 플레이어의 위치 변화나 환경 변화에 따라 BT를 업데이트하도록 할 수 있습니다.

플레이어 감지 및 추적

  • 플레이어 감지에 Raycast를 추가하는 것은 좋은 방법입니다. 예를 들어, EnemySight.cs에서 OverlapSphere로 플레이어를 감지한 후, Raycast를 사용하여 시야 내에 플레이어가 있는지 확인할 수 있겠네요.

애니메이터 관리

  • 애니메이터 관리는 명확하고 유연하게 해야 합니다. 예를 들어, EnemyAnimator.cs에서 상태에 따른 애니메이션 전환 로직을 구현하고, 외부에서 애니메이션 파라미터를 조절할 수 있도록 해보세요.



➔ 이 외 피드백

  • BT의 노드들을 별도의 클래스로 분리하여 각 노드별로 책임을 명확히 하는 것이 좋습니다. 현재 Func을 사용하여 행동을 정의하는 부분을 각기 다른 클래스로 분리합니다. 예를 들어, ActionNode, SequenceNode, SelectorNode 등으로 나눌 수 있을겁니다.

  • BT의 업데이트 메커니즘을 매 프레임마다 전체 트리를 순회하는 대신, 이벤트 기반으로 변경하여 필요할 때만 트리의 일부를 업데이트하고 순회하도록 하면 좋을듯해요.




➔ 이 후 방향성

  • 일단 FOV기능을 완성 시키고, 자잘한 버그를 잡은 뒤에 튜터님이 말씀해주신 부분에 대해서 리팩토링을 진행할 예정이다. (노드 클래스 분할, 업데이트 지향 이벤트 사용, 애니메이터 따로 클래스 관리)

  • 차근차근 빠르면서 천천히 하나씩 해보도록 하겠다.

  • 바쁘신 와중에 이렇게 자세하고 뼈와 살이 되는 피드백을 주신 튜터님에게 너무 감사하다.

profile
No Easy Day

0개의 댓글