본문 바로가기

UNITY

UNITY_20230905[UNITY - 옵저버 패턴-Event]

UNITY에서 오브젝트를 움직이는 데는 여러 방법이 있다.

그 중 옵저버 패턴을 이용한 이동 기능 구현을 기록한다.

 

우선, 아래는 오늘 제작한 UNITY 캐릭터 이동 코드를 담은 스크립트 3개다.

using System;
using UnityEngine;

public class TopDownCharacterController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent;
    public event Action<Vector2> OnLookEvent;

    public void CallMoveEvent(Vector2 direction)
    {
        OnMoveEvent?.Invoke(direction);
    }

    public void CallLookEvent(Vector2 direction) // 아직 미구현
    {
        OnLookEvent?.Invoke(direction);
    }
}

위 스크립트는 캐릭터가 이동 입력WASD를 받을 경우 이벤트 함수OnMoveEvent, OnLookEvent를 실행하는 클래스다.

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerInputController : TopDownCharacterController
{
    private Camera _camera;

    private void Awake()
    {
        _camera = Camera.main;
    }

    public void OnMove(InputValue value)
    {
        Vector2 movePositionInput = value.Get<Vector2>().normalized; // 입력값의 vector2값을 normalize해서 할당
        CallMoveEvent(movePositionInput); // 받은 값(vector2 형식)으로 CallMoveEvent함수 실행
    } // 이 함수만으로는 아직 event함수OnMoveEvent는 null이다.

    public void OnLook(InputValue value)
    {
        Vector2 newAim = value.Get<Vector2>(); // 입력값의 vector2값을 normalized해서 할당(현재 마우스 위치)
        // 현재 스크린에 비치는 마우스의 위치를 월드 좌표로 계산해 할당
        Vector2 worldPos = _camera.ScreenToWorldPoint(newAim); 
        // (현재 마우스 좌표 - 플레이어(이 스크립트를 들고 있는 오브젝트)의 위치 좌표)를 normalize해서 할당
        newAim = (worldPos - (Vector2)transform.position).normalized;

        if (newAim.magnitude >= 0.9f) // ?if문? 그냥 방어코든가?
        {
            CallLookEvent(newAim);
        }
    }

    public void OnFire(InputValue value)
    {
        Vector2 fireVector = value.Get<Vector2>(); // 미구현, 그냥 써 놓은 거다.
        Debug.Log($"OnFire Operated at : x={fireVector.x}, y={fireVector.y}"); // 미구현, 그냥 써 놓은 거다.
    }
}

위 스크립트는 사용자의 입력값을 호출할 함수의 매개변수 형식에 맞게 수정하고, 호출한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TopDownMovement : MonoBehaviour // 캐릭터의 움직임
{
    private TopDownCharacterController _controller;

    private Vector2 _moveDirection = Vector2.zero;
    private Rigidbody2D _rigidbody;
    private void Awake()
    {
        _controller = GetComponent<TopDownCharacterController>();
        _rigidbody = GetComponent<Rigidbody2D>();
    }

    private void Start()
    {
        _controller.OnMoveEvent += Move;
    }   // 이 함수 할당으로 비로소 OnMoveEvent이벤트는 값을 가지게 된다.

    private void FixedUpdate()
    {
        ApplyMove(_moveDirection);
    }

    private void Move(Vector2 direction)
    {
        _moveDirection = direction;
    }

    private void ApplyMove(Vector2 direction)
    {
        _rigidbody.velocity = direction * 5;
    }
}

위 코드를 통해 이벤트를 보고 있는 코드(이벤트 구독 상태의 코드-옵저버)를 생성하고, 사용자의 입력이 있을 때 이벤트는 자신의 매개변수로 자신을 옵저버를 작동시킨다.

 

이렇게 이해하면 되나? 나름 반 정도는 이해를 한 것도 같은데, 나머지 Look,Fire 코드 작성 때 좀 더 확실히 하겠다.