유니티에서 자동차의 스키드 마크를 표현하는 간단한 예
앞선 내용 참고 : http://micropilot.tistory.com/category/Unity3D%20Car/Skid%20Sound
자동차가 주행시 브레이크를 적용하거나 급회전을 하면 바퀴가 노면에서 미끄러지면 소음과 함께 노면에 스키드 마크가 나타난다.
스키드 마크가 중요한 것은 아니지만 여기서 알아보고자 하는 내용은 동적으로 결정된 위치의 표면에 원하는 텍스쳐를 표시하는 방법이다.
WheelCollider를 이용하면 바퀴와 지면의 마찰력을 확인할 수 있고 바퀴의 마찰력이 일정한 수준 이상에 도달하면 미끄러지는 것으로 간주하여 바퀴가 지나가는 자리에 스키드 마크를 올려두면 된다
바퀴가 지나가는 지면 위에 스키드 마크를 올려둔다면 지면의 위치(x,y,z)를 알아야 하는데, WheelCollider.GetGroundHit()를 사용하면 된다.
[스키드 텍스쳐를 적용하여 테스트한 결과]
[사용된 스키드 텍스쳐 이미지]
[스키드 마크 이미지를 Plane 오브젝트에 설정하여 Prefab으로 등록하는 절차]
스키드 마크 텍스쳐 이미지 준비(흰색부분이 투명하게 처리된 png 파일)
텍스쳐 이미지를 탐색기에서 드래그하여 Project 뷰에 복사한다
Project 뷰에서 Material 을 생성하고 선택하여 Inspector 뷰의 select 아이콘에 텍스쳐 이미지를 드래그하여 할당한다
Inspector 뷰의 Shader 형식을 Transparent/Cutout/diffuse 로 선택하여 투명한 부분이 유지되도록 한다
Plane 오브젝트를 생성하고 위에서 생성한 Material을 Hierarchy 뷰의 Plane 오브젝트에 적용한다
Plane 오브젝트의 폭을 타이어 폭 정도로 조절한다
Project 뷰에서 Prefab 생성하고 위에서 완성한 Plane 오브젝트를 드래그하여 설정한다
Hierarchy 뷰에 있는 Plane 오브젝트를 삭제한다
스크립트에서 Prefab 인스턴스를 생성하려면 스크립트에 GameObject 변수를 선언한다
스크립트를 포함한 오브젝트를 선택하고 Inspector뷰의 GameObject 변수에 에 Prefab을 드래그하여 할당한다
스크립트에서는 다음과 같은 방법으로 Prefab 인스턴스를 생성하면 된다
더 이상 필요 없는 Prefab 인스턴스는 Destroy()를 이용하여 삭제하면 된다
아래의 코드를 각 바퀴의 WheelCollider가 포함된 오브젝트에 드래그하여 할당한다
using UnityEngine;
using System.Collections;
public class SkidSound : MonoBehaviour {
public float currentFrictionValue;
public GameObject skidSound;
private float waitTime = 0.1f;
public GameObject skidPrefab;
void Start () {
}
void Update () {
WheelHit hit;
transform.GetComponent<WheelCollider>().GetGroundHit(out hit);
currentFrictionValue = hit.sidewaysSlip;
currentFrictionValue = Mathf.Abs (currentFrictionValue);
if (currentFrictionValue >= 1.5f && waitTime>=0.1f) {
Instantiate(skidSound, hit.point, Quaternion.identity);
waitTime = 0f;
}else{
waitTime += Time.deltaTime;
}
if (currentFrictionValue >= 1.5f){
setSkidMark();
}
}
private Vector3 prevPos = Vector3.zero;
private float skidTime;
void setSkidMark() {
WheelHit hit;
transform.GetComponent<WheelCollider>().GetGroundHit(out hit);
if (prevPos == Vector3.zero){
prevPos = hit.point;
return;
}
if(skidTime>0.05f){
Vector3 relativePos = prevPos - hit.point;;
Quaternion rot = Quaternion.LookRotation(relativePos);
GameObject skidInstance = (GameObject) Instantiate (skidPrefab, hit.point, rot);
prevPos = hit.point;
skidInstance.AddComponent<GameObjectDestroy> ();
skidTime = 0;
}else{
skidTime += Time.deltaTime;
}
}
}
[위의 코드에서 사용된 GameObjectDestroy.cs 내용]
using UnityEngine;
using System.Collections;
public class GameObjectDestroy : MonoBehaviour {
private float destroyTime;
void Start () {
}
void Update () {
if(destroyTime>=2f) {
Destroy(gameObject);
}else {
destroyTime += Time.deltaTime;
}
}
}