2024/01/08 TIL
트러블 슈팅(Raycast와 Collider)
이번 팀 프로젝트에서 내가 맡은 파트 중 문을 여닫는 부분이 있었다.
카메라에서 ray를 쏘아낸 후에 door 프리팹에 달려있는 box collider에 ray가 닿으면 상호작용을 활성화 하는 방식이다.
먼저 상호작용을 담당하는 부분이다.
public class InteractionManager : MonoBehaviour
{
public float checkRate = 0.05f;
private float lastCheckTime;
public float maxCheckDistance;
public LayerMask layerMask;
private GameObject curInteractGameobject;
private IOpenDoor currentDoor;
public Text interactText;
private Camera _camera;
public void Initialize()
{
_camera = PlayerManager.Instance.m_cameraManager.GetCamera1();
}
void Update()
{
if (Time.time - lastCheckTime > checkRate)
{
lastCheckTime = Time.time;
Ray ray = _camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
RaycastHit hit;
//Debug.DrawRay(_camera.transform.position, _camera.transform.forward*maxCheckDistance, Color.green);
if (Physics.Raycast(ray, out hit, maxCheckDistance, layerMask))
{
if (hit.collider.gameObject != curInteractGameobject)
{
curInteractGameobject = hit.collider.gameObject;
if (curInteractGameobject.TryGetComponent<IOpenDoor>(out currentDoor))
{
SetDoorOpenTxt();
}
}
}
else
{
curInteractGameobject = null;
currentDoor = null;
interactText.gameObject.SetActive(false);
}
}
}
private void SetDoorOpenTxt()
{
interactText.gameObject.SetActive(true);
if (!currentDoor.IsOpen)
{
interactText.text = "<b>[E]</b> 문 열기";
}
else
{
interactText.text = "<b>[E]</b> 문 닫기";
}
}
public void OpenDoorInput(InputAction.CallbackContext callbackContext)
{
if (callbackContext.phase == InputActionPhase.Started && currentDoor != null)
{
if (!currentDoor.IsOpen)
{
currentDoor.OpenThisDoor();
}
else
{
currentDoor.CloseThisDoor();
}
curInteractGameobject = null;
currentDoor = null;
interactText.gameObject.SetActive(false);
}
}
}
- Initialize()로 카메라를 초기화 한 이유: Awake나 Start로 초기화를 진행할 경우, PlayerManager에서 카메라를 초기화 하는 것 보다 빠르게 초기화가 진행 되어서 null이 떴었기 때문.
- 왜 trigger충돌을 사용하지 않고 ray를 사용했는가: trigger 충돌은 뒤를 돌은 상태에서도 상호작용이 가능해서 게임 상 분위기에 맞지 않았고, ray를 사용하는게 추후에 확장성에 좋다고 판단했기 때문.
문제가 발생한 부분:
문에 바짝 붙은 경우 상호작용 키가 활성화 되지 않는 문제가 발생했다.
문제를 해결하기 위해 몇가지 경우의 수를 생각해 보았다.
1. ray의 maxCheckDistance를 조절하는 방법
플레이어가 쏘는 ray의 길이를 확인해서 ray의 체크 범위가 문제인가를 확인해 보았다.
이때 사용한 코드가 DrawRay이다.
Debug.DrawRay(_camera.transform.position, _camera.transform.forward*maxCheckDistance, Color.green);
이 코드를 사용해서 플레이어가 발사하는 ray의 길이를 시각적으로 체크하고 문제를 확인해 보았다.
잘 보일지 모르겠지만, ray를 그린 모습이다. ray의 끝에가 door에 닿는 순간 상호작용키가 잘 작동한다는 걸 확인했지만 여전히 가까이 붙었을 때는 작동하지 않았다. 그래서 2번째 방법을 생각해 보았다.
2. Camera의 Near 값을 조절해 보는 것.
이건 될지 말지 긴가민가 했던 방법이다. camera에서 ray가 나가므로 camera의 near 값을 조절해서 ray가 발사되는 지점을 뒤로 미뤄보는 방법이였다. 하지만 어림도 없지, 여전히 문 앞에선 작동하지 않는 모습이였다.
3. Box Collider 크기 조절.
Ray의 작동 방법은 앞에서 말했 듯 카메라에서 ray를 쏘아낸 후에 door 프리팹에 달려있는 box collider에 ray가 닿으면 활성화 되는 방식이다. 그렇다면 box collider 내부에서 ray를 발사하면 어떻게 될까? 정답은 '활성화 되지 않는다' 이다.
box collider의 신호를 받는 방식은 collider 외부 면에서 신호를 받는 방식이기 때문에 그 면에 들어올때, 들어오고 나서, 나갈때 이렇게 작동하는 것이다. 그런데 지금 프로젝트의 경우에는 문 바로 앞에 서면 box collider 내부에서 ray를 쏘아내는 상황이 되기 때문에 작동하지 않았던 것이다.
그렇기에 Box Collider의 크기를 문에 딱 맞도록 줄이고 실행을 시켜보니 정상적으로 작동했다.