이번 포스트에서는 이전에 만든 단검 투척 스킬을 조금 더 개선해보겠습니다.
단검이 날아갈 때 시각적으로 돋보이게 개선하고
단검이 적중한 후 다시 회수할 수 있도록 만들어보겠습니다.
1) PlayerController
public class PlayerController : BaseCharacterController
{
.
.
.
// Skill Info
.
.
.
public GameObject _sword;
.
.
.
public void AssignNewSword(GameObject newSword)
{
_sword = newSword;
}
public void ClearTheSword()
{
Destroy(_sword);
}
.
.
.
}
플레이어 그 자체를 의미하면서 동시에 플레이어의 동작을 수행하는 PlayerController에서
위와 같이 생성된 단검을 캐싱하고 또 삭제하는 로직을 추가하였습니다.
단검이 생성되면 생성된 단검을 AssignNewSword 메서드를 통해 _sword에 캐싱하고,
단검을 파괴하고 싶다면 ClearTheSword 메서드로 캐싱된 단검을 파괴합니다.
2) SkillThrowingSword
public class SkillThrowingSword : SkillTemplate
{
.
.
.
public void CreateSword()
{
GameObject newSword = Instantiate(
_swordPrefab,
_playerController.transform.position,
transform.rotation
);
SkillThrowingSwordController _throwingSwordController = newSword.GetComponent<SkillThrowingSwordController>();
_throwingSwordController.SetUpSword(_finalDirection, _swordGravity, _playerController);
_playerController.AssignNewSword(newSword);
DotsActive(false);
}
.
.
.
}
단검 투척 스킬 그 자체를 의미하는 SkillThrowingSword의 경우
단검을 생성하는 함수인 CreateSword에서 PlayerController의 메서드 AssignNewSword를 호출하여
Instantiate로 생성된 인스턴스를 캐싱해놓습니다.
3) SkillThrowingSwordController
public class SkillThrowingSwordController : MonoBehaviour
{
private Animator _animator;
private Rigidbody2D _rigidBody2D;
private CircleCollider2D _circleCollider2D;
private PlayerController _playerController;
[SerializeField]
private float _returnSpeed = 12.0f;
private bool _canRotate = true;
private bool _isReturning;
private void Awake()
{
_animator = GetComponentInChildren<Animator>();
_rigidBody2D = GetComponent<Rigidbody2D>();
_circleCollider2D = GetComponent<CircleCollider2D>();
}
public void SetUpSword(Vector2 dir, float gravityScale, PlayerController player)
{
_playerController = player;
_rigidBody2D.velocity = dir;
_rigidBody2D.gravityScale = gravityScale;
_animator.SetBool("Rotation", true);
}
public void ReturnSword()
{
_rigidBody2D.isKinematic = false;
transform.parent = null;
_isReturning = true;
}
private void Update()
{
if(_canRotate)
transform.right = _rigidBody2D.velocity;
if (_isReturning)
{
transform.position = Vector2.MoveTowards(transform.position, _playerController.transform.position, _returnSpeed * Time.deltaTime);
if (Vector2.Distance(transform.position, _playerController.transform.position) < 1)
_playerController.ClearTheSword();
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
_animator.SetBool("Rotation", false);
_canRotate = false;
_circleCollider2D.enabled = false;
_rigidBody2D.isKinematic = true;
_rigidBody2D.constraints = RigidbodyConstraints2D.FreezeAll;
transform.parent = collision.transform;
}
}
단검 투척 스킬의 동작을 정의해놓은 SkillThrowingSwordController의 구조가 상당부분 변경되었습니다.
우선 단검을 투척한 Player를 기록하도록 _playerController 프로퍼티를 추가하였습니다.
또한 추가적으로
단검의 반환 속도, 단검의 회전 여부를 판단, 단검의 회수 여부를 판단하는 프로퍼티를 추가했습니다.
생성된 단검이 즉시 호출하는 SetUpSword 메서드의 경우
인자를 추가적으로 PlayerController를 받도록 설정하였습니다.
또한 단검의 애니메이터 변수 Rotation을 true로 설정하여 회전하며 날아가게끔 설정하였습니다.
단검을 회수하는 경우 호출되는 ReturnSword의 경우
RigidBody 설정을 Kinematic으로 설정하지 않아 중력과 힘의 영향을 받게끔 설정합니다.
이 상태에서 단검이 적중한 대상을 null로 초기화하고
회수 여부를 판단하는 _isReturning을 true로 변경합니다.
매 프레임마다 호출되는 Update 메서드의 로직은 다음과 같습니다.
만약 회전할 수 있다면 회전 중인것이므로, 단검의 오른쪽 방향을 RigidBody의 velocity로 고정합니다.
또 회수 중이라면, 단검이 플레이어를 향하도록 설정하고
단검과 플레이어 사이의 거리가 1보다 작다면
PlayerController의 메서드 ClearSword를 호출하여 캐싱된 단검을 삭제합니다.
단검의 Collider가 Trigger되는 경우 호출되는 OnTriggerEnter2D의 경우 다음과 같이 구성됩니다.
우선 애니메이터 변수 Rotation을 false로 설정하여 회전을 막습니다.
또한 회전 여부를 false로 바꾸고 동시에 콜라이더의 동작도 중지시킵니다.
RigidBody 설정을 Kinematic으로 설정하여 중력과 힘의 영향을 받지 않게끔 설정합니다.
그리고 constraints를 전부 적용하여 회전과 이동을 막고
마지막으로 적중한 대상을 단검의 부모로 설정합니다.
4) PlayerStateGrounded
public class PlayerStateGrounded : PlayerState
{
.
.
.
public override void Update()
{
base.Update();
if (_isThrowingSword && HasNoSword())
_stateMachine.ChangeState(_controller._aimSwordState);
.
.
.
}
private bool HasNoSword()
{
if(!_controller._sword)
return true;
_controller._sword.GetComponent<SkillThrowingSwordController>().ReturnSword();
return false;
}
}
땅을 딛고 있는 상태인 PlayerStateGrounded에서는 위와 같이 로직을 변경합니다.
우선 메서드 HasNoSword를 추가하여
검이 캐싱되어 있지 않다면 true를 리턴하고
검이 캐싱되어 있다면 ReturnSword 메서드를 호출하여 회수후에 false를 리턴합니다.
또한 Update 에서는 오른쪽 마우스 키 입력 여부와 HasNoSword를 통해
PlayerState를 AimState로 변경합니다.
5) 유니티 에디터
우선, 단검의 프리팹에 몇가지 설정을 수행합니다.
콜라이더의 동작 방식을 위와 같이 Trigger로 변경합니다.
단검 프리팹의 Layer를 Sword로 설정한 후에,
Layer간의 콜리전 설정을 위와 같이 설정합니다.
최종 실행 결과는 다음과 같습니다.
'유니티 > 게임 프로젝트' 카테고리의 다른 글
2D RPG - (15 - 6) 단검 투척 스킬 구현_06 (0) | 2025.02.05 |
---|---|
2D RPG - (15 - 5) 단검 투척 스킬 구현_05 (0) | 2025.02.04 |
2D RPG - (15 - 3) 단검 투척 스킬 구현_03 (0) | 2025.01.28 |
2D RPG - (15 - 2) 단검 투척 스킬 구현_02 (0) | 2025.01.28 |
2D RPG - (15 - 1) 단검 투척 스킬 구현_01 (0) | 2025.01.27 |