유니티 RPG - 37. 무기 공격판정 구현
Intro
이번 포스팅은 플레이어의 공격 애니메이션에 맞게 공격판정을 구현해보았습니다.
공격 판정을 구현하는 방법은 여러가지가있습니다.
- Raycast 활용
- Collider 활용
- Overlap 활용
- Projectile 활용
전략패턴으로 무기를 만들어놓았으니, 각 무기마다 적절한 방법을 골라서 적용할 수 있습니다.
Sword
검은 Collider를 활용하여 공격판정을 구현해보았습니다.
Sword 클래스에서 공격판정을 위한 함수를 구현합니다.
/*
Sword : 무기(검) 클래스
- BoxCollider를 사용해서 공격판정 구현
*/
public class Sword : Weapon
{
private BoxCollider hitBox; // 공격 판정
private void Awake()
{
// 무기 타입 설정
type = WeaponType.Sword;
hitBox = GetComponent<BoxCollider>();
}
// 공격 데미지 등
public override void Attack()
{
Debug.Log("몬스터 공격성공");
}
protected override void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Monster"))
{
Attack();
}
}
public override void SetHitBox(bool isEnabled)
{
hitBox.enabled = isEnabled;
}
}
-
콜라이더의 Trigger 옵션을 통해 공격의 성공여부를 판단할것이므로 OntriggerEnter를 사용했습니다.
-
SetHitBox()는 애니메이션 이벤트를 사용하기위한 함수로, PlayerController 클래스에서 호출합니다.
Staff
스태프 공격은 범위내의 모든 적을 공격하는 범위공격으로 만들어보았습니다.
RayCast를 활용한 방법입니다.
/*
Staff : 무기(스태프) 클래스
- RayCast를 사용해서 공격판정 구현
*/
public class Staff : Weapon
{
private float attackRange = 3f; // 공격 범위
private float attackRadius = 3f; // 공격 반경
private Vector3 attackOrigin;
private Vector3 attackDir;
private List<RaycastResult> rrList;
private void Awake()
{
type = WeaponType.Staff;
}
// 공격 구현
public override void Attack()
{
attackOrigin = GameManager.Instance.player.transform.position + GameManager.Instance.player.transform.forward * 2f;
attackDir = GameManager.Instance.player.transform.forward;
// 공격범위
RaycastHit[] hits = Physics.SphereCastAll(
attackOrigin,
attackRadius,
attackDir,
attackRange,
LayerMask.GetMask("Monster")
);
// 공격범위에 몬스터가 있을경우
foreach(RaycastHit hit in hits)
{
Monster monster = hit.collider.GetComponent<Monster>();
if(monster != null)
{
// .. 몬스터에게 데미지
Debug.Log("몬스터를 맞추었음.");
}
}
}
public override void SetHitBox(bool isEnabled)
{
}
// 공격범위 시각화
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(attackOrigin, attackRadius);
Gizmos.color = Color.yellow;
Gizmos.DrawLine(attackOrigin, attackOrigin + attackDir * attackRange);
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(attackOrigin + attackDir * attackRange, attackRadius);
}
}
-
구형(Sphere) Raycast를 사용하여 범위내 적을 공격합니다.
- OnDrawGizmos는 Raycast 하려는 모양을 시각화해주는 함수입니다.
- 빨간색 부분은 공격의 시작점, 초록색 부분은 공격이 끝나는지점으로 눈으로 확인할 수 있도록 했습니다.
- 마찬가지로 플레이어의 애니메이션 이벤트를 통해 공격함수를 호출합니다.
PlayerController
공격 애니메이션은 플레이어 애니메이터 존재하고, 각 무기에 공격함수가 달려있으므로
애니메이션 이벤트를 사용하기위해서는 플레이어 오브젝트에 무기 클래스가 붙어있어야합니다.
하지만 무기클래스는 각 무기에 달려있으므로 애니메이션 이벤트에서 무기클래스에 접근하기위해서는
WeaponManager를 통해 간접적으로 접근해야합니다.
// 플레이어 공격
private void Attack()
{
if (isAttackKeyDown && !isAttacking)
{
anim.SetTrigger(hashAttackTrigger);
}
}
#region ** Animation Events **
private void IsAttacking() => isAttacking = !isAttacking;
private void EnableAttackHitbox() => WeaponManager.Instance.currentWeapon.SetHitBox(true);
private void DisableAttackHitbox() => WeaponManager.Instance.currentWeapon.SetHitBox(false);
private void TriggerAttack() => WeaponManager.Instance.currentWeapon.Attack();
#endregion
- 플레이어가 공격중에는 움직이지 못하도록하였습니다.
- bool형 변수 isAttacking 를 통해 플레이어가 공격중인지 판별합니다.
- IsAttacking()는 애니메이션이 시작될때와 끝날 때 호출하여 플레이어가 공격중인지를 변경합니다.
- EnableAttackingHitBox()와 DisableAttackHitbox() 는 Collider를 활용한 공격에 사용될 메서드입니다.
- TriggerAttack()는 ‘Weapon’ 클래스의 Attack() 함수를 호출하기위한 메서드입니다.
댓글남기기