728x90
SMALL

게임 로직을 구현하기 위해 맵을 먼저 배치하였습니다.

 

Bézier Path Creator는 게임 오브젝트에 스크립트를 연결하면 Null참조 에러가 발생하고, 기즈모가 출력되지 않아 이동경로를 만들 수 없는 버그가 있습니다.

 

지난번에 자동차를 구현할 때는 데모씬에 이미 배치되어 버그가 발생하지 않 이동경로를 복사, 붙여넣기하여 기즈모를 조절하여 해당 버그를 우회하였습니다.
하지만 계속 다른 씬을 열어 복사하는 작업이 귀찮아 이 버그를 직접 고쳐보기로 하였습니다.
(이 글을 쓰면서 그냥 버그 발생하지 않는 오브젝트를 프리팹으로 만들어 사용했으면 되지 않았을까? 생각하고 있습니다.)
결국 Bézier Path Creator의 버그는 수정하였고, 이 글은 강의 시리즈가 아닌 개발과정을 정리한 노트이기 때문에 과정 설명하지 생략하겠습니다.

 

집 오브젝트 앞에 트리거를 체크한 BoxCollider를 배치하였고, 각각의 오브젝트에 CustomerTrigger 스크립트를 만들어 연결했습니다.
오브젝트에 Point라고 이름 지은 오브젝트를 자식으로 등록하였습니다.
Point 오브젝트는 나중에 택시에 탈 손님이 나타나거나 택시에 내린 손님이 이동할 목적지로 사용할 예정입니다.

 

자동차 오브젝트에 BoxCollider와 Rigidbody를 추가하여 트리거에 인식되도록 만들었습니다.
다른 내가 조작하는 자동차와 다른 자동차를 구분할 수 있도록 태그를 Player로 등록하였습니다.
자동차 오브젝트의 크기가 조금씩 다르기 때문에 자동차의 기준점은 앞으로 설정하였습니다.

 

GameLogic 클래스를 추가하여 손님의 탑승, 하차 처리를 3초 대기하는 걸로 임시 구현하였습니다.
나중에 만들 NPC자동차도 Car 스크립트를 사용할 수 있도록 만들기 위해 자동차 조작도 GameLogic으로 옮겨두었습니다.
결승점에 도착하면 3초 대기 후 씬을 다시 불러오도록 임시 구현하였습니다.

 

GameLogic.cs

using PathCreation;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

namespace TaxiGame3D
{
    public class GameLogic : MonoBehaviour, InputControls.IPlayerActions
    {
        [SerializeField]
        PathCreator path;
        [SerializeField]
        TMP_Text stateText;

        InputControls inputControls;
        bool isAccelPressing = false;

        bool wasCustomerTaken;

        public static GameLogic Instance
        {
            get;
            private set;
        }

        [field: SerializeField]
        public Car PlayerCar
        {
            get;
            private set;
        }

        void Awake()
        {
            Instance = this;
        }

        IEnumerator Start()
        {
            PlayerCar.SetPath(path.path);
            PlayerCar.OnArrive += (sender, args) =>
            {
                StartCoroutine(EndGame());
            };
            yield return new WaitForSeconds(1);
            PlayerCar.PlayMoving();
        }

        void OnEnable()
        {
            if (inputControls == null)
                inputControls = new();
            inputControls.Player.SetCallbacks(this);
            inputControls.Player.Enable();
        }

        void OnDisable()
        {
            inputControls?.Player.Disable();
        }

        void Update()
        {
            var s = $"Moving: {PlayerCar.IsEnableMoving}\n";
            s += $"Customer: {wasCustomerTaken}";
            stateText.text = s;

            if (isAccelPressing)
                PlayerCar.PressAccel();
            else
                PlayerCar.PressBrake();
        }

        public void OnAccelerate(InputAction.CallbackContext context)
        {
            isAccelPressing = context.ReadValue<float>() != 0f;
        }

        public void OnCarEnterTrigger(CustomerTrigger trigger)
        {
            if (wasCustomerTaken)
                StartCoroutine(TakeOut());
            else
                StartCoroutine(TakeIn());
        }

        /// <summary> 손님 탑승 </summary>
        IEnumerator TakeIn()
        {
            PlayerCar.StopMoving();
            yield return new WaitForSeconds(3f);
            wasCustomerTaken = true;
            PlayerCar.PlayMoving();
        }

        /// <summary> 손님 하차 </summary>
        IEnumerator TakeOut()
        {
            PlayerCar.StopMoving();
            yield return new WaitForSeconds(3f);
            wasCustomerTaken = false;
            PlayerCar.PlayMoving();
        }

        IEnumerator EndGame()
        {
            PlayerCar.StopMoving();
            yield return new WaitForSeconds(3);
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}

 

Car.cs

using PathCreation;
using System;
using UnityEngine;

namespace TaxiGame3D
{
    public class Car : MonoBehaviour
    {
        [SerializeField]
        float acceleration = 1f;
        [SerializeField]
        float maxSpeed = 5f;
        [SerializeField]
        float brakeForce = 1f;

        VertexPath path;

        float speed = 1f;
        float movement = 0f;

        Rigidbody rb;

        public bool IsEnableMoving
        {
            get;
            set;
        }

        public event EventHandler OnArrive;

        void Awake()
        {
            rb = GetComponent<Rigidbody>();
        }

        void Update()
        {
            if (!IsEnableMoving)
                return;

            movement += Time.deltaTime * speed;
            rb.MovePosition(path.GetPointAtDistance(movement, EndOfPathInstruction.Stop));
            rb.MoveRotation(path.GetRotationAtDistance(movement, EndOfPathInstruction.Stop));

            if (movement >= path.length)
                OnArrive?.Invoke(this, EventArgs.Empty);
        }

        public void SetPath(VertexPath path)
        {
            this.path = path;
            rb.position = path.GetPointAtDistance(movement, EndOfPathInstruction.Stop);
            rb.rotation = path.GetRotationAtDistance(movement, EndOfPathInstruction.Stop);
        }

        public void PlayMoving()
        {
            IsEnableMoving = true;
            speed = 1f;
        }

        public void StopMoving()
        {
            IsEnableMoving = false;
            speed = 0f;
        }

        public void PressAccel()
        {
            if (IsEnableMoving)
                speed = Mathf.Min(speed + Time.deltaTime * acceleration, maxSpeed);
        }

        public void PressBrake()
        {
            if (IsEnableMoving)
                speed = Mathf.Max(speed - Time.deltaTime * brakeForce, 1f);
        }
    }
}

 

구현결과

 

 

깃 허브 저장소 : taxi-game-3d-unity

728x90
LIST

+ Recent posts