내일배움캠프/TIL

내일배움캠프 24일차 TIL - 로컬 멀티플레이 인풋 시스템

서보훈 2024. 10. 18. 20:33

유니티 입문주차 프로젝트 진행중, 로컬 멀티플레이 기능을 설계하면서 발생한 문제입니다.

문제상황

캐릭터를 생성했을 때, 1P 캐릭터는 정상적으로 조작이 가능하지만, 2P 는 조작이 불가능한 상황이 발생했습니다.

당시, 캐릭터가 같은 액션 에셋을 공유하고, 액션맵을 바꾸는 방식으로 구현하려고 하였습니다.

 

당시 처음 시도했던 조작 코드입니다.

public void IsPlayer2(bool isPlayer2)
{
    if (isPlayer2)
    {
        playerInput.defaultActionMap = "Player2P";
    }
    else
    {
        playerInput.defaultActionMap = "Player1P";
    }
}

 

시도해본 것

처음 시도해본것은 캐릭터의 조작을 변경할 때 PlayerInput 클래스의 defaultActionMap 이 아닌 currentActionMap 을 사용한다는점을 알고 변경하여 시도해보았습니다.

public void IsPlayer2(bool isPlayer2)
{
    if (isPlayer2)
    {
        playerInput.currentActionMap = "Player2P";
    }
    else
    {
        playerInput.currentActionMap = "Player1P";
    }
}

 

하지만 문제는 여전하였고 이후 액션에셋 자체를 나누어서 시도해보고자 하였습니다.

public InputActionAsset player1Asset;
public InputActionAsset player2Asset;


public void IsPlayer2(bool isPlayer2)
{
    if (isPlayer2)
    {
        playerInput.actions = player2Asset;
    }
    else
    {
        playerInput.currentActionMap = player2Asset;
    }
}

이 방법으로도 조작이 불가능하여 다른방법을 찾아보기 시작했습니다.

 

해결방법

문제 해결을 위해 오브젝트들을 확인해보던중, 한 씬에 PlayerInput 이 2개 존재할경우 한쪽 PlayerInput에 사용 키보드 정보등이 전달되지 않고, 유저가 갈리는것을 확인하게 되었습니다.

여기에서 액션맵이나 액션 에셋을 사용하는것에는 의미가 없고, PlayerInput이 여러개 존재하는것 자체가 문제라는것을 알게되었습니다.

 

이에 맞추어서 2P 의 캐릭터가 생성될 때, PlayerInput으로부터 입력을 받는 InputController 스크립트를 비활성화 하고,

실제로 움직임을 처리하는 CharacterMoveBase의 InputController 정보를 1P 의 캐릭터의 컴포넌트로 변경하여 해결하게 되었습니다.

private void OnMove2P(InputValue value)
{
    player2Dir = value.Get<float>();
    OnPlayer2Move?.Invoke(player2Dir);
}

public void IsPlayer2(CharacterMoveBase _player2Move)
{
    player2Move = _player2Move;

    player2Move.SetThis2P(this);
}

이를통해, 2P 는 1P 의 InputController 입력을 받아서 움직임을 구현하여 복수의 PlayerInput으로 인해 생기는 문제를 해결하였습니다.

 

이런 문제를 미리 알았다면, 조작을 받는 상위 스크립트를 만든 뒤, 그 자식오브젝트로 캐릭터를 넣거나, 캐릭터를 생성할때 조작용 스크립트에 등록하는 방식으로 해결할 수 있지 않았을까라는 생각이 들었습니다.

 

알게된점

사실 이 문제를 해결하기위해 많은 정보를 찾아봤으며, 실제로 다수의 PlayerInput을 사용하는 경우도 알게되었습니다.

이때 알게된것이 PlayerInputManager 입니다.

이 방식은, 플레이어 프리팹을 등록해 놓을경우, JoinBehavior 에 따라서 플레이어를 게임에 추가해줍니다.

여기서 Join Players When Button Is Pressed 의 경우, 같은 Action에 다른 입력방식이 있을때 해당 입력방식이 입력되면 캐릭터가 추가로 생성되는 방식입니다.

 

현재 Player Input Manager에 PlayerInput를 컴포넌트로 가지고 있는 Cube 프리팹을 등록해준 상태입니다.

공유될 액션에셋입니다.

Move 액션에, 키보드와 마우스로 각각 등록해준 상태입니다.

 

키보드로 움직일떄는 기존에 존재하던 큐브만 움직이다가, 마우스를 입력하면 새로운 프리팹을 생성해서 움직이는 모습을 볼 수 있습니다.

 

단, 이 방법으로는 하나의 키보드로 2개의 오브젝트를 움직일 수 없다는점

-※ 실제로는 Keyboard Splitter 방법을 통해  구현할 수 있다고 합니다. 단, 시간과 또다른 문제점으로 인해 사용하지 못했습니다.

 

현재 캐릭터 프리팹이 나뉘어져 있으며 다른 스크립트를 통해서 캐릭터를 생성하는 문제로 인하여 이 내용을 사용하지 못했습니다.

 

그래서 임시로 다른방법을 생각하게 되었고, 위와 같이 1P 의 InputController 를 공유하는 방법을 구상하여 적용하게 되었습니다.

 

그런데

Default Scheme 을 Any 로 설정, 디폴트 맵을 나눠주면 작동합니다...

 

난 뭘 한걸까...