그 다음 요소는 본 프로젝트에서 사용자에게 운전 점수를 알려주기 위한 중심 로직인 채점 알고리즘을 구현하였다.
이전에 채점표를 기준으로 구현: 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를 추가로 넣어 아래와 같이 했더니 잘 감지되었다.
'Project > VR 기반 운전 시뮬레이션: 안전 "안전 운전만해" 프로젝트' 카테고리의 다른 글
[Part 13] VR 기기(Oculus Quest2)와 Unity 연동 (0) | 2022.05.15 |
---|---|
[Part 12] 주차 성공에 대한 추가 코드 (0) | 2022.05.15 |
[Part 10] 타이머 설정 Timer & 카운트다운 CountDown: 유니티 이벤트 사용 (0) | 2022.05.14 |
[Part 9] 사용자 게임 Scene에 놓기 (0) | 2022.05.14 |
[Part 8] 주차장 맵 제작 및 이벤트 구현: Waypoint System (0) | 2022.05.14 |