내가 만들고 싶었던 투척무기는 위 사진과 같이 배틀그라운드의 투척무기 같은 느낌이였다
그렇다면 어떻게 스크립트를 작성하면 좋을까?
1. 구조 설계
- 플레이어 인풋 클래스
- 기본 투척 무기 클래스 정의
- 투척 무기 하위 클래스 계획 (Grenade, Flashbang, SmokeShell 등)
2. 필요한 변수
- 어떤 종류의 투척 무기가 필요한가? 수류탄, 연막탄, 섬광탄
- 각 무기의 공통특성은 무엇인가? 폭발 반경, 폭발 시간 등
- 투척 메커니즘은 어떻게 작동해야 하는가? 궤적 표시, 던지는 힘, 마우스 각도 등
3. 필요한 로직
- 기본 메서드 구현
- 투척 매커니즘
- 폭발 로직
- 특정 무기 클래스 구현
투척무기를 만들려고 했을 때, 이정도 생각을 들었다.
일단 제일 만만한 폭발 부터 만들어 보자..
public abstract class ThrowingWeapon : MonoBehaviour
{
public float explosiondelay = 3f; // 폭발 시간
public float explosionRadius = 5f; // 폭발 반경
public float throwForce = 15f; // 던지는 힘
private void Awake()
{
}
// 폭발
public void Explosion()
{
StartCoroutine(Explode());
}
protected abstract IEnumerator Explode();
}
========================================================================
public class Grenade : ThrowingWeapon
{
public int damage = 100; // 데미지
public LayerMask attackableMask;
protected override IEnumerator Explode()
{
yield return new WaitForSeconds(explosiondelay);
Collider[] _colliders = Physics.OverlapSphere(transform.position, explosionRadius, attackableMask);
foreach(Collider _collider in _colliders)
{
_collider.GetComponent<IDamageAble>().Damaged(damage);
}
}
}
하지만 문제가 하나 있다.
바로 레이어로 설정해준것이 폭발 반경 안의 들어오면 무조건 죽어버리는 것이다.
수류탄이 터지는 시점에서 거리를 측정해 데미지를 입혀보자
먼저 Vector3.Distance를 사용해 수류탄과 수류탄 안의 들어온 물체의 거리를 구해주자
float _distance = Vector3.Distance(transform.position, _collider.transform.position);
그 다음, 거리의 따라 입을 데미지값을 구해야한다
거리가 멀어질 수록 데미지 값이 낮아져야한다.
float _damagePersent = 1 - (_distance/explosionRadius);
이 부분은 값을 대입 해보면 조금 더 쉽게 이해가 간다
explosionRadius가 10m 라고 가정해보자
- 중심(0m)에서: 0 / 10 = 0
- 5m 거리에서: 5 / 10 = 0.5
- 10m 거리에서: 10 / 10 = 1
결국 _damagePersent 는
0 <= damagePersent <= 1 이라는 결과가 나온다
그 후, 본래 데미지의 곱해서 데미지 값을 낮춰주면 될 것이다.
int _calDamage = Mathf.RoundToInt(damage * _damagePersent);
_collider.GetComponent<IDamageAble>().Damaged(_calDamage);
Mathf.RoundToInt(damage * _damagePersent) // (int)(damage * _damagePersent)
둘 다 똑같이 float 값을 int로 바꿔주는데 위 두개의 차이는 무엇일까?
결정적인 차이는 바로 반올림에 있다.
Mathf.RoundToInt는 0.5 이상은 올림, 0.5 미만은 내림 처리되지만
(int)는 무조건 내림 처리이다.
게임으로 예를 들어보자,
HP가 1이 남았는데 더 정밀한 계산으로 이루어진 수류탄을 가장 끝쪽에서 맞아 0.6이 닳았다고 가정해보자.
Mathf.RoundToInt로 작성한 경우에는 반올림이 되어 죽을 것이다
하지만 (int) 작성한 경우에는 내림 처리 이므로 죽지 않고 살아있을 것이다.
게임적으로 본다면 Mathf.RoundToInt 가 좀 더 현실적이기 때문에, 더욱 많이 쓰일 것 같다.
하지만 특정 상황에서 단순 절삭이 필요하다면 (int) 처리 하는 것도 괜찮아 보인다.
수류탄 부분 종합 코드
public class FragGrenade : ThrowingWeapon
{
public int damage = 100; // 데미지
public LayerMask attackableMask;
protected override IEnumerator Explode()
{
yield return new WaitForSeconds(explosiondelay);
Collider[] _colliders = Physics.OverlapSphere(transform.position, explosionRadius, attackableMask);
foreach(Collider _collider in _colliders)
{
float _distance = Vector3.Distance(transform.position, _collider.transform.position);
float _damagePersent = 1 - (_distance/explosionRadius);
int _calDamage = Mathf.RoundToInt(damage * _damagePersent);
_collider.GetComponent<IDamageAble>().Damaged(_calDamage);
}
}
}
'유니티 > 기능구현' 카테고리의 다른 글
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 샷건 ) (0) | 2024.10.23 |
---|---|
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 돌격소총 ) (0) | 2024.10.17 |
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 주무기 클래스 ) (10) | 2024.10.17 |
[Unity] 유니티 C#) 투척무기 구현을 어떻게 할까? ( 던지기 ) (0) | 2024.08.11 |
[Unity] 유니티 C#) 투척무기 구현을 어떻게 할까? ( 궤적 표시 ) (0) | 2024.08.10 |