[Part 11] 채점 알고리즘 & Trigger, Collsion

그 다음 요소는 본 프로젝트에서 사용자에게 운전 점수를 알려주기 위한 중심 로직인 채점 알고리즘을 구현하였다. 

이전에 채점표를 기준으로 구현: https://mineral-mine.tistory.com/55

 

<채점 관리 Manager>

 

  • 문제 
    • 아래와 같은 초기 채점 알고리즘에서 감점 요인을 감지하는 부분과 점수를 관리하는 부분이 합쳐져 있었다. 
    • 코드의 구분이 어렵고 나중에 사용자에게 어떤 요인에서 감점 횟수를 알려주기 어려웠다

 

public class ScoreTest_hj : MonoBehaviour
{
    public int stagePoint = 100;
    public PlayerTest_hj playcar;

    //한번충돌시 한번 점수 감점
    private bool onetimededuction = false;

    //시간
    private string time;
    private string pasttime;

    //과속
    public SpeedCalculate speedCalculate;

    //급정거
    //드래그드랍해줘야함
    private SDKInputManager IM;
    private float lastbrakeInput;


    // Collider 컴포넌트의 is Trigger가 false인 상태로 충돌을 시작했을 때
    private void OnCollisionEnter(Collision other)
    {
        Debug.Log("collision");
        
        if (other.gameObject.CompareTag("Animals") && (pasttime != time || pasttime == null))
        {
            //Debug.Log("동물 충돌");
            if (!onetimededuction )
            {
                //scoretest_hj.stagePoint -= 5;
                stagePoint -= 7;

                onetimededuction = !onetimededuction;
                pasttime = time;
            }

            //Debug.Log("Score: " + stagePoint);
            //UIPoint.text = "Score: " + Managers.Score.GetScore();

            if (stagePoint <= 60)
            {
                //Debug.Log("실격");
                playcar.OnDie();

            }
        }
        else if (other.gameObject.CompareTag("Car"))
        {
            //Debug.Log("차량 충돌");
            stagePoint = 0;
            if (stagePoint <= 0)
            {
                playcar.OnDie();

            }
        }
        else if (other.gameObject.CompareTag("Cliff"))
        {
            stagePoint = 0;
            if (stagePoint <= 0)
            {
                //Debug.Log("절벽 충돌");
                playcar.OnDie();

            }
        }
        else if (other.gameObject.CompareTag("FinishLine"))
        {
            playcar.OnDie();
            //TotalPoints.text = stagePoint.ToString();
            Debug.Log("Finish");
            //scorePanel.SetActive(true);
        }
    }

    private void OnCollisionExit(Collision other) 
    {
        if (other.gameObject.CompareTag("Animals"))
        {
            onetimededuction = !onetimededuction;
        }
    }

    // Start is called before the first frame update
    void Start()
    {
        IM = playcar.GetComponent<SDKInputManager>();
        //pausePanel.SetActive(false);
        //scorePanel.SetActive(false);

        //UIPoint.text = "Score: " + stagePoint.ToString();
    }

}

 이전 채점 코드

 

  • ScoreManager 만들기 
    • ScoreManager를 만들어 사용자의 운전 점수만을 관리하도록하였다. ScoreDeduct 함수를 통해 감점 요인에 따라 점수를 감점하며 DeductCount로 감점 요인 횟수를 저장한다. => 오직 점수만을 관리
    • 이를 위해 감점 요인에 대한 정의와 주행 결과를 정의
public enum ScoreDeduct
    {
        StartMiss, // 출발
        AnimalCollision, // 동물 충돌
        CarCollision, // 자동차 충돌
        ClifCollision, // 절벽 충돌
        Speeding, // 과속
        SuddenStop, // 급정거
        LineCollision, // 도로선 밟음
        BuildingCollision, // 건물 충돌
        PedestrainsCollision, // 보행자 충돌
        TrafficsignViolation, // 신호위반 
        MaxCount, // 감점 요소의 개수 


    }
    // 주행 결과 요소
    public enum ScoreOut
    {
        TimerOut, // 타이머 종료
        Threshold, // 점수 미달
        Collision, // 충돌 
        Clear, // 주행 성공 
    }

Define.cs: 감점요인과 주행 결과 요인 정의 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScoreManager
{
    private int Score = 100;
    private int[] DeductCount = new int [(int)Define.ScoreDeduct.MaxCount];
    private int Threshold = 60;
    private Define.ScoreOut scoreout; // 실격 이유 저장

    public void ScoreDeduct(Define.ScoreDeduct type, Define.Scene scene = Define.Scene.Game)
    {
        Debug.Log($"{type} 발생");

        switch (type)
        {
            case Define.ScoreDeduct.BuildingCollision:
                Score -= 5;
                DeductCount[(int)Define.ScoreDeduct.BuildingCollision]++;
                break;

            case Define.ScoreDeduct.AnimalCollision:
                Score -= 7;
                DeductCount[(int)Define.ScoreDeduct.AnimalCollision]++;
                break;

            case Define.ScoreDeduct.CarCollision:
                DeductCount[(int)Define.ScoreDeduct.CarCollision]++;
                if (scene == Define.Scene.Park_Level_1_Day || scene == Define.Scene.Park_Level_1_Night
                    || scene == Define.Scene.Park_Level_2_Day || scene == Define.Scene.Park_Level_2_Night
                    || scene == Define.Scene.Park_Level_3_Day || scene == Define.Scene.Park_Level_3_Night)
                    Score -= 5;
                // 실격
                else
                {
                    //Score = -1;
                    ScoreOut(Define.ScoreOut.Collision);//Score = 0;
                }
                    break;

            case Define.ScoreDeduct.ClifCollision:
                //Score = -1;
                ScoreOut(Define.ScoreOut.Collision); // Score = 0;
                DeductCount[(int)Define.ScoreDeduct.ClifCollision]++;
                // Player state End로 바꾸기 
                break;

            case Define.ScoreDeduct.Speeding:
                Score -= 5;
                DeductCount[(int)Define.ScoreDeduct.Speeding]++;
                break;

            case Define.ScoreDeduct.StartMiss:
                Score -= 10;
                DeductCount[(int)Define.ScoreDeduct.StartMiss]++;
                break;

            case Define.ScoreDeduct.SuddenStop:
                Score -= 10;
                DeductCount[(int)Define.ScoreDeduct.SuddenStop]++;
                break;

            // 실격
            case Define.ScoreDeduct.PedestrainsCollision:
                //Score = -1;
                DeductCount[(int)Define.ScoreDeduct.PedestrainsCollision]++;
                ScoreOut(Define.ScoreOut.Collision);
                break;

            case Define.ScoreDeduct.TrafficsignViolation:
                Score -= 7;
                DeductCount[(int)Define.ScoreDeduct.TrafficsignViolation]++;
                break;


        }

        // 점수 표 아래 일시, 실격
        if(Score < Threshold)
        {
            // 각 Scene 마다 다르게 해야하기 때문에 
            ScoreOut(Define.ScoreOut.Threshold);
        }
    }
    // 실격 or Game Over
    public void ScoreOut(Define.ScoreOut type)
    {
        // Game Over 
        scoreout = type;
        Managers.State.Set_State(Play_State.GameOver); // Play State를 Gameover로 바꿈 
        Debug.Log($"{type} GameOver");
    }

    public int GetScore()
    {
        return Score;
    }

    public Define.ScoreOut GetScoreOut()
    {
        return scoreout;
    }
    public int[] GetDeductInfo()
    {
        return DeductCount;
    }
}

ScoreManager.cs

 

<Trigger 및 Collider 감지(충돌 감지)>

 

1. tag를 이용: Unity의 tag를 이용하여 충돌 객체를 구분하였다. 

2. PlayerScore를 통해서 충돌만을 감지한다. 객체와 충돌할 시  OnCollisionEnter와 OnTriggerEnter가 실행된다. 해당 함수는 충돌한 객체를 switch 문으로 구분하여 감점 요인 변수를 ScoreDeduct에게 넘겨준다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;

public class PlayerScore : MonoBehaviour
{
    private int Collicount = 0;
    Define.Scene MyScene;

    // 과속 및 급정거
    private SDKInputManager IM;
    private float lastbrakeInput;
    public SpeedCalculate speedCalculate;
    private bool onetimededuction_forover = false;
    private bool onetimededuction_forsudd = false;

    // Parking Flag
    private bool[] ParkFlag = new bool[4];
    private bool isParkSuccess = false;


    //시간
    private string time;
    private string pasttime_forover;
    private string pasttime_forsudd;

    private void Awake()
    {
        for (int i = 0; i < ParkFlag.Length; i++)
        {
            ParkFlag[i] = false;
        }
    }

    // 물리적인 충돌 감지 - Collision에 들어왔을때, 감점
    private void OnCollisionEnter(Collision collision)
    {
        //Debug.Log($"Collision Event {collision.gameObject.tag}");

        switch (collision.gameObject.tag)
        {
            case "Building":
                Collicount++;
                Debug.Log($"Collicount {Collicount}");
                Managers.Score.ScoreDeduct(Define.ScoreDeduct.BuildingCollision);
                break;
            case "Animals":
                Managers.Score.ScoreDeduct(Define.ScoreDeduct.AnimalCollision);
                break;

            case "Car":
                Managers.Score.ScoreDeduct(Define.ScoreDeduct.CarCollision, MyScene);
                break;

            case "Cliff":
                Managers.Score.ScoreDeduct(Define.ScoreDeduct.ClifCollision);
                break;

            case "Pedestrains":
                Managers.Score.ScoreDeduct(Define.ScoreDeduct.PedestrainsCollision);
                break;

            case "End":
                Managers.Score.ScoreOut(Define.ScoreOut.Clear);
                break;
        }

        //Debug.Log($"Score {Managers.Score.GetScore()}");
    }

    // 물리적인 충돌은 일어나지 않지만 Trigger 발생: 주차 Timeout 시 선이 밟아져 있나 확인
    private void OnTriggerEnter(Collider other)
    {
        Debug.Log($"Trigger Event {other.gameObject.tag}");

        switch (other.gameObject.tag)
        {
            case "Line":
                break;

            case "":

                break;
        }
    }

    void Start()
    {
        // Scene script 가져오기
        Component[] components = GameObject.Find("@Scene").GetComponents(typeof(Component));

        foreach (Component component in components)
        {
            Debug.Log($"component: {component}");
            PropertyInfo prop = component.GetType().GetProperty("SceneType");

            if (prop != null)
                MyScene = (Define.Scene)prop.GetValue(component, null);
            else Debug.LogError("There is no @Scene");

        }

        // assignment
        IM = GameObject.FindGameObjectWithTag("Player").GetComponent<SDKInputManager>();
        speedCalculate = GameObject.Find("Speed").GetComponent<SpeedCalculate>();
    }
    void Update()
    {
        time = System.DateTime.Now.ToString();
        if (Managers.State.Get_State() == Play_State.Playing)
        {
            deduction_for_speeding();
            suddenstop();
        }



    }


}

PlayerScore.cs

 

<WheelCollider 감지안됨>

 

1. 문제

    사용자 차량의 바퀴에 WheelCollider가 있음에도 불구하고 도로의 선 Line Object가 감지가 안되어 감점되지 않은 문제가 발생하였다. 

    구글링을 해보니 다른 사람들도 WheelCollider가 Collision이 안된다는 글이 있지만, 원인을 알 수 없었다. 

 

2. 해결

   WheelCollider 말고 Capsule Collider를 추가로 넣어 아래와 같이 했더니 잘 감지되었다. 

Capsule Collider를 적용한 바퀴