1. 요금 획득 구현
먼저 요금 계산을 위한 공식을 먼저 고민하여 아래와 같은 공식을 만들어 봤습니다.
- 승객을 태우고 이동한 거리
- d = b − a
- a : 승객이 탑승한 위치
- b : 승객이 하차한 위치
- , 모두 Bézier Path Creator 이용하여 계산한 이동량을 저장
- d = b − a
- 요금 계산
- m = d × ((70+i) / 100)
- m : 택시 요금(소수점 뒤는 버림)
- d : 승객을 태우고 이동한 거리
- i : 스테이지 인덱스(배열 인덱스 개념이기 때문에 0부터 시작)
- 승객을 태우고 이동한 거리의 70%를 요금으로 지급
- 스테이지가 증가할 수록 1%씩 증가
- m = d × ((70+i) / 100)
그리고 GameLogic의 TakeOut 메소드에 위의 공식을 이용하여 계산한 요금을 획득하는 코드를 추가하였습니다.
var distance = PlayerCar.Movement - customerTakePos;
var reward = Mathf.FloorToInt(
distance * ((70f + stageIndex) / 100f)
);
if (reward > 0)
coin += reward;
2. CustomerTrigger 클래스 수정
각각의 클래스들이 최대한 각자도생을 하는 구조로 만들어 보기 위해 기존에 GameLogic.Instance.OnCarEnterTrigger 대신 EventHandler를 사용하도록 수정하였습니다.
public event EventHandler OnPlayerEntered;
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
OnPlayerEntered?.Invoke(this, EventArgs.Empty);
}
3. 승객 구현

어차피 자동차 모델도 다 바꿨고, 샘플에서 제공하는 캐릭터 모델들도 개인적으로 안 귀여워 보여서 에셋 스토어에서 Low Poly 3D Animated Donguri Brothers 에셋을 추가하였습니다.

새로 추가한 캐릭터 모델도 마젠타색으로 출력되어 머테리얼을 모두 Universal Renderer Pipeline/Lit로 변경하였습니다.

CapsuleCollider, Rigidbody와 Customer클래스를 만들어 새로 추가한 캐릭터 모델에 연결하여 승객 프리팹을 만들었습니다.

승객 프리팹 택시와 물리적 충돌을 일으키지 않도록 CapsuleCollider의 Is Trigger 체크하였습니다.
그리고 바닥을 뚫고 떨어지지 않도록 Rigidbody의 Is Kinematic 체크하였습니다.
캐릭터 모델에 연결되어 있던 Donguri_Controller.controller 파일을 복사하여 Customer_Controller.controller 파일을 만든 후 IsMoving 파라미터를 이용하여 Idle 동작을 할지 Run 동작을 할지 선택하도록 설정하였습니다.

승객이 왼쪽 문으로 들어가고 나갈지, 오른쪽 문으로 들어가고 나갈지 처리하기 위해 자동차 프리팹에 LeftPoint, RightPoint 라고 이름 지은 빈 오브젝트를 추가하여 PlayerCar와 연결하였습니다.

PlayerCar 클래스에서 차량의 승객이 등장하는 위치를 시작점과의 거리가 왼쪽, 오른쪽 중 더 가까운 곳을 계산하는 메소드를 추가하였습니다.
public Transform SelectNearestPoint(Vector3 poisition)
{
var left = (LeftPoint.position - poisition).sqrMagnitude;
var right = (RightPoint.position - poisition).sqrMagnitude;
return left < right ? LeftPoint : RightPoint;
}
CustomerManager 클래스를 추가하여 씬에 빈 오브젝트를 만들어 연결한 후 배치하였습니다.
먼저 만들어 두었던 승객 프리팹들을 CustomerManager에 연결하여 승객이 렌덤하게 등장하도록 구현하였습니다.
Customer Spawn(Vector3 position, Quaternion rotation)
{
customerIndex = Random.Range(0, customers.Length);
if (customers[customerIndex] == null)
{
var go = Instantiate(customerPrefabs[customerIndex]);
customers[customerIndex] = go.GetComponent<Customer>();
customers[customerIndex].OnTakeIn += (sender, args) =>
{
if (!WasCustomerTaken)
(sender as Customer).StopMove();
};
}
customers[customerIndex].transform.SetPositionAndRotation(position, rotation);
customers[customerIndex].gameObject.SetActive(true);
return customers[customerIndex];
}
GameLogic 클래스에 있던 WasCustomerTaken 프로퍼티는 CustomerManager 클래스에 옮겨두었습니다.
GameLogic 클래스의 TakeIn, TakeOut 메소드에서 3초 대기하던 부분을 승객이 자동차에 탑승하거나 내려서 건물로 들어갈 때까지 대기하도록 수정하였습니다.
IEnumerator TakeIn(CustomerTrigger trigger)
{
PlayerCar.StopMoving();
yield return StartCoroutine(
customerManager.TakeIn(trigger, PlayerCar)
);
customerTakePos = PlayerCar.Movement;
PlayerCar.PlayMoving();
}
IEnumerator TakeOut(CustomerTrigger trigger)
{
PlayerCar.StopMoving();
var distance = PlayerCar.Movement - customerTakePos;
var reward = Mathf.FloorToInt(
distance * ((70f + stageIndex) / 100f)
);
if (reward > 0)
coin += reward;
yield return StartCoroutine(
customerManager.TakeOut(trigger.CustomerPoint, PlayerCar)
);
customerTakePos = 0f;
PlayerCar.PlayMoving();
}
구현 결과

깃 허브 저장소 : taxi-game-3d-unity
'개발노트 > Taxi Game 3D' 카테고리의 다른 글
Devlog) Taxi Game 3D) 8) 맵 제작 1 (2) | 2023.12.04 |
---|---|
Devlog) Taxi Game 3D) 7) 템플릿 제작 (0) | 2023.11.29 |
Devlog) Taxi Game 3D) 5) 게임 로직 구현 2 (3) | 2023.11.23 |
Devlog) Taxi Game 3D) 4) 게임 로직 구현 1 (0) | 2023.11.21 |
Devlog) Taxi Game 3D) 3) 자동차 구현 2 (0) | 2023.11.20 |