이번 강의에선 플레이어 인풋시스템의 Behavior을 Invoke Unity Events 로 설정해주었다. 기존의 SendMessage 방식의 경우 On + Event 이름으로 설정을 해주어야 했지만 이경우 함수명이 정해지진 않았다.
하지만 이벤트 함수의 네이밍 규칙에 따라 On 을 붙여 함수명을 만드는것이 일반적이다.
함수의 인자값으로 public void OnMoveInput(InputAction.CallbackContext context)
과 같이 CallBackContext 를 지정할경우 아래의 인스펙터의 창에 따로 칸이 만들어져 나타나게 된다.
public void OnMoveInput(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Performed) //이벤트의 발생위치를 정하는거 started면 프레임에서 맨 처음 한번/ 누르는동안 =performed/ 떼질때 Calceled
{
curMovementInput = context.ReadValue<Vector2>();
}
else if(context.phase == InputActionPhase.Canceled)
{
curMovementInput = Vector2.zero;
}
}
private void Move()
{
Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;
dir *= moveSpeed;
dir.y = _rigidbody.velocity.y;
_rigidbody.velocity = dir;
}
Input System을 이용해 플레이어의 이동을 구현한 코드이다.
사용자의 키보드 입력이 OnMoveInput 으로 Vector2로 입력이 된다.vector2 curMovementInput 에 좌우는x 전후는y 로
이 입력값이 Move 함수에서 Vector3값으로 변경이 된다.
transform.forward(0,0,1) 가 curMovementInput의 y값
transform.right(1,0,0) 가 curMovementInput의 x값이다.
3D에서는 플레이어의 평면이동은 Vector3의 x,z가 관여한다. y는 높이.
Look의 경우 Mouse의 Delta값을 반환해주도록 설정을 하였다. 하지만 이 Delta가 어떤 값을 리턴하는것인지 몰라서 InputDebugger을 확인해보기로 하였다.
InputDebugger 을 이용해 확인해본 결과
Delta값은 마우스의 움직임정도를 Vector2값으로 나타내준다는것을 알게 되었다.
void CameraLook()
{
camCurXRot += mouseDelta.y * lookSensitivity; //마우스 위아래 이동\
camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook);
cameraContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0);
transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0);
}
public void OnLookInput(InputAction.CallbackContext context)
{
mouseDelta = context.ReadValue<Vector2>();
}
회전은 생각보다 간단했다. 마우스의 값을 그냥 그대로 Transform에 적용시켜주면 된다.
좌우 회전은 플레이어가 회전하도록 하였고
transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0);
,
상하 회전은 카메라가 회전하도록 하였다.
cameraContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0);
인터페이스를 이용해 구현을 했다,
public interface IDamageable
{
void TakePhysicalDamage(int damageAmount);
}
데미지를 입을 수 있는 물체들에게 이 인터페이스를 적용시키고
public void TakePhysicalDamage(int damageAmount)
{
health.Subtract(damageAmount);
onTakeDamage?.Invoke();
}
플레이어에게 TakePhysicalDamage = 데미지를 받는 함수를 작성해주었다.
데미지를 주는 물체로 캠프파이어이다.
캠프파이어는 다른 물체외 충돌할 경우
private List<IDamageable> thingsToDamage = new List<IDamageable>();
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.TryGetComponent(out IDamageable damageable))
{
thingsToDamage.Add(damageable);
}
}
TryGetComponent 로 Idamagable인지 확인해 리스트에 추가해준다.
private void Start()
{
InvokeRepeating("DealDamage", 0, damageRate);
}
void DealDamage()
{
for(int i = 0; i< thingsToDamage.Count; i++)
{
thingsToDamage[i].TakePhysicalDamage(damage);
}
}
추가된 IDamagable에 대해서 DealDamage를 통해 TakePhysicalDamage함수를 실행한다.
화면 효과의 경우 UnityEvent를 이용하였다.
public UnityEvent onTakeDamage;
onTakeDamage 유니티 이벤트 변수를 만들어
인스펙터 상에서 위와 같이 이벤트를 할당할 수 있도록 만들어 주었다.
public void TakePhysicalDamage(int damageAmount)
{
health.Subtract(damageAmount);
onTakeDamage?.Invoke(); //화면 효과에 사용중
}
플레이어 데미지 구현에 사용했던 함수에서 onTakeDamage이벤트를 실행해주면 완성이다!
트러블 발생!
RigidBody와 collider가 설정된 부모 Empty오브젝트와 하위 실제 오브젝트 모야을 가진 >Prefab들이 따로 노는 현상이 발생
해결 방법
자식 오브젝트의 설정이 Static으로 되어있었다. 이를 체크해제하면서 해결
ScriptableObject 를 이용해 아이템 데이터 구현
이번에도 Interface을 활용해 구현하였다.
public interface IInteractable
{
string GetInteractPrompot();
void OnInteract();
}
오브젝트와의 상호작용은 Ray를 이용하였다.
Ray ray = camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
스크린의중앙에서 카메라 방향으로 향하는 레이를 생성해 오브젝트를 찾을수 있었다.