개발일지

241007(월) [Input Manager, 무엇이 문제일까?]

게임 프로그래머 2024. 10. 7. 22:27

구 인풋 시스템(Input Manager)

캐릭터의 입력과 이동을 담당하는 이동 코드로서

구 인풋 시스템 (Input Manager)를 기반으로 코드를 작성한다.

여전히 많이 사용되는 코드지만 Input Manager는 문제가 있다.

 

구 인풋 시스템(Input Manager), 무엇이 문제인가?

1) 조이스틱 등 다양한 입력 장비 대응에 부족하고, 키를 변경하거나

다양한 플랫폼에 대응하기 어렵다.

2) 구현한 내용이 모두 한 클래스에 모여있어 유지보수성과 확장성이 떨어진다.

 

객체지향 프로그래밍에서 기능별로 클래스를 나누는 것을

단일 책임 원칙(Single Responsibility Principle)이라고 한다.

또한, 단일 책임 원칙은 모든 클래스는 하나의 책임만 가진다는 원칙이기도 하다.

그러므로 Input Manager는 단일 책임 원칙을 위반할 가능성이 높다.

 

구 인풋 시스템(Input Manager)을 개선한 New Input System

New Input System은 Input Manager에서 대응하기 어려운

다양한 플랫폼과의 호환성이 좋으며 입력 장치에 대해 일관된 방식으로 작동한다.

또한, 플레이어가 게임 내에서 자신의 키 설정을 바꿀 수 있도록 지원하고

여러 플레이어가 동일한 장치에서 또는 각각의 장치에서

게임을 플레이할 때 입력을 쉽게 처리할 수 있다.

클래스가 나뉘어져 있기 때문에 유지보수성과 확장성이 좋다.

 

New Input System 설계하기

 

TopDownController : 플레이어, 적에 사용되는 공통적인 기능을 정의한다.

PlayerInputController : 플레이어의 input을 담당, 실제 처리는 TopDownMovement에서 처리된다.

TopDownMovement : 실제 움직임 처리를 담당한다.

 

코드

TopDownController

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

public class TopDownController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent; // Action은 무조건 void만 반환, 아니면 func
    public event Action<Vector2> OnLookEvent; // 마우스
    
    public void CallMoveEvent(Vector2 direction) //MoveEvent가 발생했을때 invoke 역할
    {
        OnMoveEvent?.Invoke(direction); // ?. 없으면 말고 있으면 실행
    }

    public void CallLookEvent(Vector2 direction)
    {
        OnLookEvent?.Invoke(direction);
    }
}

 

PlayerInputController

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerInputController : TopDownController
{
    private Camera camera;

    private void Awake()
    {
        camera = Camera.main; // maincamera 태그가 붙어있는 카메라를 가져온다.
    }

    public void OnMove(InputValue value) // wasd값이 value에 저장
    {
        Vector2 moveInput = value.Get<Vector2>().normalized;
        CallMoveEvent(moveInput);
        // 실제 움직이는 처리는 여기서 하는게 아니라 PlayerMovement에서 함
    }

    public void OnLook(InputValue value)
    {
        Vector2 newAim = value.Get<Vector2>(); // 마우스 위치는 달라져야 하므로 normalized불가
        Vector2 worldPos = camera.ScreenToWorldPoint(newAim);
        newAim = (worldPos - (Vector2)transform.position).normalized;

        CallLookEvent(newAim);
    }
}

 

TopDownMovement

using System;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

public class TopDownMovement : MonoBehaviour
{
    // 실제로 이동이 일어날 컴포넌트

    private TopDownController controller;
    private Rigidbody2D movementRigidbody;
    private Vector2 movementDircetion = Vector2.zero; // 오류발생할 수 있으므로 값잡아줌

    private void Awake()
    {
        //주로 내 컴포넌트 안에서 끝나는거

        // controller랑 TopDownMovement랑 같은 게임오브젝트 안에 있다라는 가정
        controller = GetComponent<TopDownController>(); // 캐싱
        movementRigidbody = GetComponent<Rigidbody2D>();
    }

    private void Start()
    {
        controller.OnMoveEvent += Move;
    }

    private void Move(Vector2 direction) // 업데이트 베이스, 매프레임마다 누르고 안누르고 있는걸 판단, 프레임 기반
    {
        movementDircetion = direction;
    }

    private void FixedUpdate() 
    {
        // FixedUpdate는 물리업데이트
        // rigidbody의 값을 바꾸므로 fixedupdate
        // 실제 움직임 처리, 그거에 대한 함수가 applymovement
        ApplyMovement(movementDircetion);
    }

    private void ApplyMovement(Vector2 direction)
    {
        direction = direction * 5;
        movementRigidbody.velocity = direction;
    }
}

 

 

최종 정리

New Input System은 PC에만 집중되는 과거와 달리

현재는 PC뿐만 아니라 다양한 플랫폼(모바일, 콘솔 등)이 만들어졌고

이러한 플랫폼에 특성에 맞춰 입력방식을 변화할 수 있도록 Unity에서 개발되었다.

또한, New Input System은 개선된 UI, 플랫폼 확장 시

Input System을 수정해야 하는 번거로움을 방지하고

게임 내 키 변경 기능을 제공하므로 이용자에게 편의성을 제공한다.

이 로직에 대해 꾸준히 학습하여 내 것으로 만들어

다양한 방면으로 활용할 수 있도록 해야겠다.