유니티/게임 프로젝트

2D RPG - (15 - 5) 단검 투척 스킬 구현_05

monstro 2025. 2. 4. 21:03
728x90
반응형

이번 포스트에서는 단검 투척 스킬을 개선하고 일부 버그를 수정하겠습니다.

개선사항은 다음과 같습니다.

  • 단검을 조준하는 상태에서 커서에 따라 플레이어를 회전
  • 단검이 회수될 때 회수되는 단검을 향해 플레이어를 회전
  • 기존의 ClearTheSword 함수 이름 CatchTheSword로 변경
  • 회수 애니메이션특정 프레임에서 CatchState 탈출
  • 단검이 회수될 때 살짝 밀리게끔 수정
  • 단검을 던진 직후와 회수 직후 일시적으로 다른 상태로의 전환을 막음

버그 수정사항은 다음과 같습니다.

  • 단검이 어딘가에 부딪히기 전 회수하는 경우RigidBody가 무시되는 현상
  • 단검이 회수될 때 적에게 부딪히는 경우부딪힌 것으로 판정되는 현상
  • 달리는 상태에서 단검 조준시 움직일 수 있는 현상

각각의 개선 사항과 버그 수정사항에 번호를 붙여 1부터 9라고 표기하겠습니다.

이 경우에 각 번호와 관련된 클래스는 다음과 같습니다.

 

  • 1 - PlayerStateAimSword
  • 2 - PlayerStateCatchSword
  • 3 - PlayerController
  • 4 - PlayerStateCatchSword
  • 5 - PlayerStateCatchSword
  • 6 - PlayerStateAimSword, PlayerStateCatchSword
  • 7 - SkillThrowingSwordController
  • 8 - SkillThrowingSwordController
  • 9 - PlayerStateAimSword

 

1) PlayerStateAimSword

public class PlayerStateAimSword : PlayerState
{
    
	.
	.
	.

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

        _controller.StartCoroutine("DoSomething", 0.2f);
    }

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

        _controller.SetZeroVelocity();

        if (_isThrowingSword == false)
            _stateMachine.ChangeState(_controller._idleState);

        Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);

        // 플레이어가 마우스 커서보다 오른쪽에 위치하면서 오른쪽을 보고 있는 경우
        if (_controller.transform.position.x > mousePosition.x && _controller._facingDir == 1)
            _controller.Flip();
        // 플레이어가 마우스 커서보다 왼쪽에 위치하면서 왼족을 보고 있는 경우
        else if(_controller.transform.position.x < mousePosition.x && _controller._facingDir == -1)
            _controller.Flip();
    }
}

 

단검을 조준하는 PlayerStateAimSword의 경우 로직을 위와 같이 수정하였습니다.

 

우선, 현재 State를 탈출하는 Exit 메서드에서는 

PlayerController의 DoSomething을 호출하여 다른 상태로의 전환을 일시적으로 막겠습니다.

 

또한 현재 State에서 매 프레임마다 수행하는 Update 메서드에서는

플레이어의 속력을 0으로 초기화하여 조준하는 동안 움직일 수 없도록 막겠습니다.

그리고 마우스 커서와 플레이어의 X 좌표 차이를 계산하여 커서에 따라 플레이어를 회전시키겠습니다.

 

2) PlayerStateCatchSword

public class PlayerStateCatchSword : PlayerState
{
    private Transform _sword;

	.
	.
	.

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

        _sword = _controller._sword.transform;

        // 플레이어가 회수되는 단검보다 오른쪽에 위치하면서 오른쪽을 보고 있는 경우
        if (_controller.transform.position.x > _sword.position.x && _controller._facingDir == 1)
            _controller.Flip();
        // 플레이어가 회수되는 단검보다 왼쪽에 위치하면서 왼족을 보고 있는 경우
        else if (_controller.transform.position.x < _sword.position.x && _controller._facingDir == -1)
            _controller.Flip();

        _rigidbody2D.velocity = new Vector2(_controller._swordReturnImpact * -_controller._facingDir, _rigidbody2D.velocity.y);
    }

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

        _controller.StartCoroutine("DoSomething", 0.1f);
    }

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

        if (_triggerCalled)
            _stateMachine.ChangeState(_controller._idleState);
    }
}

 

단검을 회수하는 상태PlayerStateAimSword에서는 위와 같은 수정사항을 거쳤습니다.

우선, 단검의 위치를 저장하기 위한 지역 변수를 하나 추가하였습니다.

 

State에 돌입하는 경우 호출하는 Enter 메서드에서는 추가한 지역 변수를 초기화하고,

지역 변수와 플레이어의 X 좌표 차이를 계산하여 플레이어가 단검을 향하도록 수정하였습니다.

또, 단검을 회수한 직후 약간의 충격을 받도록 설정하였습니다.

 

State를 탈출하는 Exit 메서드의 경우

일시적으로 다른 State로의 전환막도록 하겠습니다.

 

매 프레임마다 State에서 호출되는 Update의 경우,

회수 애니메이션의 특정 프레임에서 _triggerCalled를 true로 설정하는 경우

즉시, State를 전환하도록 하겠습니다.

 

3) PlayerController

public class PlayerController : BaseCharacterController
{
	
	.
	.
	.

    // Skill Info
	.
	.
	.
    [SerializeField]
    public float _swordReturnImpact;

	.
	.
	.

    public void CatchTheSword()
    {
        _stateMachine.ChangeState(_catchSwordState);
        Destroy(_sword);
    }
	
	.
	.
	.
    
}

 

플레이어를 조종하면서 플레이어 그 자체를 의미하는

PlayerController에는 새로운 프로퍼티를 추가하였습니다.

새로운 프로퍼티는 단검 회수 시 받을 충격을 설정합니다.

 

또한 기존의 메서드 ClearTheSwordCatchTheSword라는 이름으로 수정하였고,

해당 메서드가 호출되면 CatchSwordState로 현재 State를 변경합니다.

 

4) SkillThrowingSwordController

public class SkillThrowingSwordController : MonoBehaviour
{
    
	.
	.
	.

    public void ReturnSword()
    {
        _rigidBody2D.constraints = RigidbodyConstraints2D.FreezeAll;
        transform.parent = null;
        _isReturning = true;
    }

	.
	.
	.

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (_isReturning)
            return;

        _animator.SetBool("Rotation", false);

        _canRotate = false;
        _circleCollider2D.enabled = false;

        _rigidBody2D.isKinematic = true;
        _rigidBody2D.constraints = RigidbodyConstraints2D.FreezeAll;

        transform.parent = collision.transform;
    }
}

 

단검 투척 스킬을 조작하기 위한 SkillThrowingSwordController의 수정사항은 위와 같습니다.

 

우선, 투척된 단검을 회수하는 ReturnSword 메서드에서

기존의 투척된 단검을 Kinematic으로 설정하는 로직에서

위와 같이 FreezeAll로 바꿔 회전 / 이동의 연산을 완전히 막겠습니다.

이에 따라 회수되는 단검물리적으로 작용은 하되 Transform이 변하지는 않게 됩니다.

 

또한 단검이 특정 대상과 부딪히는 경우 수행되는 OnTriggerEnter2D에서는

단검이 회수되고 있는 경우에는 수행하지 않도록 수정하였습니다.

 

최종 실행 결과는 다음과 같습니다.

 

728x90
반응형