유니티/게임 프로젝트

2D RPG - (4) StateMachine의 구성과 완성 (3)

monstro 2024. 12. 9. 00:46
728x90
반응형

1) 움직이는 상태의 PlayerStateMove

public class PlayerStateMove : PlayerStateGrounded
{
    public PlayerStateMove(PlayerController inController, PlayerStateMachine inStateMachine, string inParamName) 
        : base(inController, inStateMachine, inParamName)
    {

    }

    // State에 돌입
    public override void Enter()
    {
        base.Enter();
    }

    // State에서 탈출
    public override void Exit()
    {
        base.Exit();
    }

    // State에서 매 프레임마다 진행
    public override void Update()
    {
        base.Update();

        _controller.SetVelocity(_xInput * _controller._moveSpeed, _rigidbody2D.velocity.y);

        if (_xInput == 0 || _controller.DoDetectIsFacingWall())
            _stateMachine.ChangeState(_controller._idleState);
    }
}

 

PlayerStateMove의 경우 발을 딛고있는 상태에서 수행해야 하므로

PlayerStateGrounded로부터 상속이 이뤄집니다.

 

Update함수에서는

매 프레임마다 Player의 속도를 설정하고

만약 x축 입력이 들어오지 않거플레이어가 벽을 마주한다

Player의 CurrentStatePlayerStateIdle로 변경합니다.

 

2) 점프하는 상태의 PlayerStateJump

public class PlayerStateJump : PlayerState
{
    public PlayerStateJump(PlayerController inController, PlayerStateMachine inStateMachine, string inParamName) 
        : base(inController, inStateMachine, inParamName)
    {

    }

    public override void Enter()
    {
        base.Enter();

        _controller.SetVelocity(_rigidbody2D.velocity.x, _controller._jumpForce);
    }

    public override void Exit()
    {
        base.Exit();
    }

    public override void Update()
    {
        base.Update();

        if (_rigidbody2D.velocity.y < 0)
            _stateMachine.ChangeState(_controller._inAirState);
    }
}

 

PlayerStateJump로 처음 진입하여 Enter 함수가 호출되면

설정한 JumpForce의 값만큼 Player에게 가속도를 부여합니다.

 

그리고 Update 문에서는 Player의 y축 가속도 값을 읽어가속도가 0보다 작다면,

떨어지는 중이라면 Player의 CurrentState를 공중에 떠 있는 PlayerStateInAir로 교체합니다.

 

3) 공중에 떠 있는 상태의 PlayerStateInAir

public class PlayerStateInAir : PlayerState
{
    public PlayerStateInAir(PlayerController inController, PlayerStateMachine inStateMachine, string inParamName) 
        : base(inController, inStateMachine, inParamName)
    {

    }

    public override void Enter()
    {
        base.Enter();
    }

    public override void Exit()
    {
        base.Exit();
    }

    public override void Update()
    {
        base.Update();

        if (_controller.DoDetectIsFacingWall())
            _stateMachine.ChangeState(_controller._wallSlideState);

        if (_controller.DoDetectIsGrounded())
            _stateMachine.ChangeState(_controller._idleState);

        if (_xInput != 0)
            _controller.SetVelocity(_controller._moveSpeed * 0.8f * _xInput, _rigidbody2D.velocity.y);
    }
}

 

PlayerStateInAir의 Update 함수에서는

다음의 3가지를 체크합니다.

 

우선, 벽과 닿아있는 경우 Player의 CurrentState를 벽에서 미끄러져 내리는 PlayerStateWallSlide로 교체합니다.

그리고 땅과 닿아있는 경우 Player의 CurrentStatePlayerStateIdle로 교체합니다.

마지막으로 현재 상태에서 x축으로 입력이 들어온다

0.8의 값을 곱하여 약간 체공하여 떨어지는 느낌을 부여합니다.

 

4) 대쉬 상태의 PlayerStateDash

public class PlayerStateDash : PlayerState
{
    public PlayerStateDash(PlayerController inController, PlayerStateMachine inStateMachine, string inParamName) 
        : base(inController, inStateMachine, inParamName)
    {

    }

    // State에 돌입
    public override void Enter()
    {
        base.Enter();

        _stateTimer = _controller._dashDuration;
    }

    // State에서 탈출
    public override void Exit()
    {
        base.Exit();

        _controller.SetVelocity(0, _rigidbody2D.velocity.y);
    }

    // State에서 매 프레임마다 진행
    public override void Update()
    {
        base.Update();

        if (!_controller.DoDetectIsGrounded() && _controller.DoDetectIsFacingWall())
            _stateMachine.ChangeState(_controller._wallSlideState);

        _controller.SetVelocity(_controller._dashSpeed * _controller._dashDir, 0);

        if (_stateTimer < 0.0f)
            _stateMachine.ChangeState(_controller._idleState);
    }
}

 

PlayerStateDash에서는 위와 같은 로직을 수행합니다.

State에 돌입하는 Enter에서는 먼저 State들이 사용하는 타이머_stateTimer를 초기화합니다.

 

State에서 탈출하는 Exit의 경우 Player의 속도를 설정하되,

x값을 0으로 주어 직선으로 떨어지도록 합니다.

 

마지막으로 Update 에서는 다음의 로직을 수행합니다.

만약, 땅을 딛고 있지 않고 벽을 마주하는 상황이라면

벽에 달라붙는 PlayerStateWallSlideCurrentState를 교체합니다.

대쉬하는 동안Player에게 가속도를 부여하되 높이는 변하지 않도록 y값을 0으로 줍니다.

만약 _stateTimer가 0보다 작다면,

대쉬시간이 끝났다면 Player의 CurrentState를 PlayerStateIdle로 교체합니다.

 

 

728x90
반응형