Humility

아무리 노력해도 최고가 되지 못할 수 있다⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀그럼에도 노력하는자가 가장 겸손한 것 아닌가

공부하는 블로그

유니티/기능구현

[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 돌격소총 )

새벽_글쓴이 2024. 10. 17. 22:05
반응형

이제 본격적으로 주무기를 만들어보자

 

1. 변수 할당

public class Rifle : MainWeapon
{
  private bool canReset = true;  // 처음에만 총알 넣어주기 위해
  private float nextFireTime;  // 다음 발사 주기

  protected override void Awake()
  {
    base.Awake();
    maxLoadedAmmo = 30;  // 장전될 수 있는 탄약
    initializeAmmo = 180;  // 총기 최대 탄약
    damage = 27;  // 데미지
    bulletRange = 50f;  // 총알 발사 거리
    fireRate = 0.06f;  // 총알 발사 주기
    recoilX = 0.2f;  // 좌우 반동
    recoilY = 1.5f;  // 수직 반동
    recoilRecoverySpeed = 2f;  // 반동 회복 속도
    reloadTime = 2.5f;  // 장전 시간
    adsSpeed = 6;  // 정조준 속도
    adsFOV = 45;  // 정조준시 CameraFOV
    bulletSpread = 0.3f;  // 탄 퍼짐 정도
    maxSpread = 1f;  // 최대 탄퍼짐
    ResetAmmo(initializeAmmo);  // 탄약 세팅
  }
  // 시작할 때, 탄약 세팅 함수
  public void ResetAmmo(int _totalAmmo)
  {
    if (canReset)
    {
      loadedAmmo = maxLoadedAmmo;
      remainAmmo = _totalAmmo - loadedAmmo;
      canReset = false;
    }
  }  
}

우선 라이플은 메인 웨폰을 상속받는다

그리고 탄약을 세팅해주자

탄약 세팅시 최초 1회만 해주어야 하기 때문에 bool변수로 더 이상 호출되는 일을 막자

 

2. 슈팅과 장전

// 슈팅 함수
public override void Shoot(Transform _firePos)
{
    if (Time.time >= nextFireTime && !isReloading && canShoot)
    {
        nextFireTime = Time.time + fireRate;
        base.Shoot(_firePos);

        if (loadedAmmo <= 0)
        {
            Reload();
        }
    }
}

// 장전 함수
public override void Reload()
{
    base.Reload();
}

 

총을 쏠때 마우스 왼쪽키가 눌려있으면 계속 발사를 해줄 것이기 때문에 강제적으로 텀을 만들어줘야한다

Time.time이 nextFireTime 보다  클 때만 발사가 가능하게 해주고 총을 발사할 수 없는 상황이나 장전중에도 발사를 막는다

또한 만약 장전되어 있는 총알이 0보다 작거나 같다면 재장전을 해주도록 하자

 

장전함수는 이미 부모 클래스에서 다 만들어줬으므로 받아오기만 하면 된다

 

3. 발사 함수

public override void FireBullet()
{
    RaycastHit hit;
    Vector3 _bulletDir = GetShootDir(cam.transform);
    Vector3 direction = cam.transform.forward + _bulletDir;

    Debug.DrawRay(cam.transform.position, direction * bulletRange, Color.red, 1f);

    if (canShoot)
    {
        base.FireBullet(firePos);
        // 카메라 포지션에서 정면으로 총알 사거리만큼 쏨
        if (Physics.Raycast(cam.transform.position, direction, out hit, bulletRange))
        {
            if ((canAttackMask.value & (1 << hit.transform.gameObject.layer)) == 0)
            {
                return;
            }
            IDamageAble target = hit.transform.GetComponent<IDamageAble>();
            if (target != null)
            {
                target.Damaged(damage, hit.point);
            }
        }
    }
}

 

총알은 레이캐스트로 만들었다.

이는 총알을 Instantiate 하지 않고 가상의 레이저를 쏴 대상을 확인 후, 데미지를 입히는 방식이다.

 

먼저 설정해줘야 하는 부분이 있는데, 총알을 맞을 수 있는 대상은 레이어와  IDamageAble 인터페이스를 가지고 있어야 한다.

 

레이캐스트는 맞은 대상의 레이어를 판단할 수 있기 때문에 이부분을 활용했는데,

Layer를 비교하려면 비트 연산을 사용해야 하는 것을 배웠다.

// 처음 작성한 코드
if (hit.transform.gameObject.layer == canAttackMask)
// 결과 : 비교가 불가능 하므로 오류 발생


// 수정한 코드
if ((canAttackMask.value & (1 << hit.transform.gameObject.layer)) == 0)

 

4. 결과

 

반응형