플레이어가 NPC를 인식해야한다.
- NPCTrigger 라는 스크립트를 만들어 player에게 붙이고, npc와 player에게 콜라이더 컴포넌트를 만들어줬다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPCTrigger : MonoBehaviour
{
public delegate void NPCDetected(Transform npc);
public static event NPCDetected OnNPCDetected;
public delegate void NPCExited(Transform npc);
public static event NPCExited OnNPCExited;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("NPC"))
{
OnNPCDetected?.Invoke(other.transform);
}
}
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("NPC"))
{
OnNPCExited?.Invoke(other.transform);
}
}
}
하나하나 살펴보자.
public delegate void NPCDetected(Transform npc);
public static event NPCDetected OnNPCDetected;
public delegate void NPCExited(Transform npc);
public static event NPCExited OnNPCExited;
Delegate : delegate는 '특정 형식'의 메서드를 참조할 수 있는 타입이다. 여기서는 'Transform'을 매개변수로 받아들이는 메서드를 가리킬 수 있는 NPCDectected와 NPCExited라는 두개의 델리게이트가 정의되었다.
Event : Event 키워드는 델리게이트 타입을 기반으로 이벤트를 선언한다.
OnDectected와 OnNPCExited이벤트는 각각 NPC와의 충돌이 시작되고 종료될때 발생된다.
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("NPC"))
{
OnNPCDetected?.Invoke(other.transform);
}
}
OnTriggerEnter(Collider other) : 이 메서드는 이 스크립트가 붙어있는 객체가 다른 Collider와 충돌할 때 호출된다. 충돌한 객체의 Collider를 other로 받는다.
other.CompareTag("NPC") : 충돌한 객체의 태그가 NPC인지 확인한다. 태그가 NPC인 경우에만 해당 충돌을 처리한다.
Invoke: 이벤트가 발생했을 때 연결된 메서드를 호출하는 역할을 한다.
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("NPC"))
{
OnNPCExited?.Invoke(other.transform);
}
}
ONTriggerExit(Collider other) : 이 메서드는 충돌이 종료될때 호출된다. other는 충돌이 종료된 객체의 Collider를 나타낸다.
한 가지 문제가 생겼다. 그건 카메라가 상호작용을 하고있는데도 NPC를 바라보지 않는 문제였는데,
MainCameraAction 스크립트가 그걸 방해하고있는듯 했다. 두 스크립트가 충돌하는 상황이다.
챗 gpt는 두가지 대안을 제시해주었는데, 첫번째는 MainCameraAction 스크립트를 비활성화하는 방법이다.
private MainCamera_Action mainCameraAction; // MainCamera_Action 스크립트
private void Start()
{
// MainCamera_Action 스크립트를 찾아서 참조합니다.
mainCameraAction = mainCamera.GetComponent<MainCamera_Action>();
originalCameraPosition = mainCamera.transform.position;
originalCameraRotation = mainCamera.transform.rotation;
}
private void StartInteraction(Transform npc)
{
if (mainCameraAction != null)
{
mainCameraAction.enabled = false; // MainCamera_Action 스크립트 비활성화
}
isInteracting = true;
Vector3 npcPosition = npc.position;
Vector3 npcForward = npc.forward;
Vector3 cameraPosition = npcPosition + npcForward * 1.5f + Vector3.up * 1.5f;
mainCamera.transform.position = cameraPosition;
mainCamera.transform.LookAt(npc);
Debug.Log($"카메라 위치 변경: {cameraPosition}");
Debug.Log($"카메라 방향 변경: {npc.name}");
}
private void EndInteraction()
{
isInteracting = false;
mainCamera.transform.position = originalCameraPosition;
mainCamera.transform.rotation = originalCameraRotation;
if (mainCameraAction != null)
{
mainCameraAction.enabled = true; // MainCamera_Action 스크립트 활성화
}
Debug.Log($"카메라 복원: {originalCameraPosition}");
}
성공적이었다! 하지만, 다만, 한 가지 더 오류가 있었다. NPC와 한번 상호작용 하고나면 연속해서 상호작용 할 수가 없었다.
알고보니 마지막 EndInteraction에서 isInteractin을 true로 오타낸 내 잘못이었다...
private void EndInteraction()
{
isInteracting = false;
// 카메라를 원래 위치와 회전으로 복원합니다.
mainCamera.transform.position = originalCameraPosition;
mainCamera.transform.rotation = originalCameraRotation;
if (mainCameraAction != null)
{
mainCameraAction.enabled = true; // 스크립트 활성화
}
Debug.Log($"카메라 복원: {originalCameraPosition}");
}
}
이벤트가 끝나면 isInteracting이 false가 되도록 해주자.
NPC 카메라 앵글 변경
private void StartInteraction(Transform npc)
{
if ( mainCameraAction != null )
{
mainCameraAction.enabled = false; // 스크립트 비활성화
}
isInteracting = true;
Vector3 npcPosition = npc.position;
Vector3 npcForward = npc.forward;
Vector3 npcRight = npc.right;
Vector3 cameraPosition = npcPosition + npcForward * 1.5f + Vector3.up * 1.3f + npcRight * -1.0f;
mainCamera.transform.position = cameraPosition;
mainCamera.transform.LookAt(npc);
Quaternion CameraRotation = Quaternion.LookRotation(npc.position + Vector3.up * 1.2f - cameraPosition);
mainCamera.transform.rotation = CameraRotation;
Debug.Log($"카메라 위치 변경: {cameraPosition}");
Debug.Log($"카메라 방향 변경: {npc.name}");
}
private void EndInteraction()
{
isInteracting = false;
// 카메라를 원래 위치와 회전으로 복원합니다.
mainCamera.transform.position = originalCameraPosition;
mainCamera.transform.rotation = originalCameraRotation;
if (mainCameraAction != null)
{
mainCameraAction.enabled = true; // 스크립트 활성화
}
Debug.Log($"카메라 복원: {originalCameraPosition}");
}
}
예전부터 나왔던 Quarternion을 살펴보자.
Quarternion.LookRotation : LookRotation 함수는 두 점 사이의 방향 벡터를 받아 그 방향으로 카메라가 바라보도록 회전값을 계산해준다.
https://docs.unity3d.com/kr/2021.3/Manual/class-Quaternion.html
이제 카메라 각도는 된거같다. 이제, 대화하는 동안 캐릭터가 움직이는걸 제어하면 된다.
'게임개발 > 드림랜드' 카테고리의 다른 글
2024.09.03 플레이어 걷는 소리 구현 (0) | 2024.09.03 |
---|---|
2024.09.03 블렌드 트리를 활용한 걷기 애니메이션 (0) | 2024.09.03 |
2024.09.02 NPC 애니메이션, 카메라 스크립트와 플레이어 스크립트 그리고 커서 (0) | 2024.09.02 |
2024.08.27 NPC 만들기 (0) | 2024.08.27 |
2024.08.23 드림랜드 개발 과정(2) (0) | 2024.08.23 |