일반적인 저격총 발사방법은 사실 돌격소총과 크게 다를바가 없다.
단지, 총의 발사주기나 반동 등 몇가지 설정해놓은 변수값만 바꿔주면 되기 때문이다.
그럼 어떤 특징이 있는지 생각해보자.
저격총의 특징
1. 줌
저격총은 배율기를 사용해 먼 거리에 있는 적을 조준하고 사격하는데 의의가 있다. 때문에, 줌 기능을 구현해야한다.
2. 관통
저격게임으로 유명한 스나이퍼엘리트 시리즈를 해보면 적 2명이 1자로 서있을 때, 총을 쏴 앞에 서있는 적을 맞추면 총알이 관통해 뒤에 있는 적까지 처치할 수 있다. 저격총은 다른 총에 비해 무겁고, 탄약 또한 강력하기 때문에 이러한 설정은 괜찮다고 생각한다.
( 아쉽게도 미디어 자료는 찾을 수 없어 삽입할 수 없었다...)
1. 변수 설정
public class Sniper : MainWeapon
{
private bool canReset = true; // 처음에만 총알 넣어주기 위해
private float nextFireTime; // 다음 발사 주기
public TextMeshProUGUI ammoTxt; // 탄약 UI 표시
private int canPenetrateEnemy = 2; // 관통 가능한 숫자
public GameObject scope;
protected override void Awake()
{
bulletSpread = 2f;
spentBullet = 1;
maxSpread = 4f;
base.Awake();
initializeAmmo = 50; // 총기 최대 탄약
maxLoadedAmmo = 5; // 장전될 수 있는 탄약
damage = 75; // 데미지
bulletRange = 200f; // 총알 발사 거리
fireRate = 2.5f; // 총알 발사 주기
recoilX = 0.5f; // 좌우 반동
recoilY = 10f; // 수직 반동
recoilRecoverySpeed = 3.5f; // 반동 회복 속도
reloadTime = 4.5f; // 장전 시간
adsSpeed = 4; // 정조준 속도
adsFOV = 10; // 정조준시 CameraFOV
ResetAmmo(initializeAmmo); // 탄약 세팅
adsPos = new Vector3(0, -0.17f, 0.5f); // 스나만 다른 위치로 정조준 ( 조준경 때문에 )
}
// 탄약 세팅 함수
public void ResetAmmo(int _totalAmmo)
{
if (canReset)
{
loadedAmmo = maxLoadedAmmo;
remainAmmo = _totalAmmo - loadedAmmo;
canReset = false;
}
}
}
저격총에선 2가지를 추가로 설정해주었다. 관통가능한 숫자와 정조준시 총의 위치값이다.
관통가능한 숫자를 조절하면 최대 몇 명까지 관통할 수 있는지 선택할 수 있다.
예를 들어 현재는 2로 설정하였기에, 3명이 1자로 서있다면 맨 뒤에 있는 적은 죽지 않는다.
또한, 다른 총들과 다르게 저격총만 정조준시에 총이 이동할 위치값을 따로 지정해줬는데 이유는 줌을 하는 과정에서 Fov 값을 많이 낮추고 저격 UI를 켜면 총구가 앞을 가리거나 하는 등 시야가 확보되지 않는 경우가 발생해 따로 지정해주었다.
2. 슈팅과 장전
돌격소총과 같은 형식이다.
똑같이 누르면 쏘고 장전시에 한번에 모든 탄약이 채워지기에 부모가 되는 메인웨폰 클래스에서 받아와 사용하면 된다.
3. 발사
public override void PlayerFireBullet()
{
int _penetrateEnemy = 0;
RaycastHit hit;
Vector3 _bulletDir = GetShootDir(cam.transform);
Vector3 currentPosition = cam.transform.position;
Vector3 direction = cam.transform.forward + _bulletDir;
float distanceTraveled = 0f;
Debug.DrawRay(cam.transform.position, direction * bulletRange, Color.red, 5f);
if (canShoot)
{
while (_penetrateEnemy <= canPenetrateEnemy && distanceTraveled < bulletRange)
{
if (Physics.Raycast(currentPosition, direction, out hit, bulletRange - distanceTraveled))
{
// canAttackMask에 해당하지 않는 오브젝트에 닿으면 즉시 중단
if ((canAttackMask.value & (1 << hit.transform.gameObject.layer)) == 0)
{
Debug.Log($"벽에 닿음: {hit.transform.name}");
break;
}
IDamageAble target = hit.transform.GetComponent<IDamageAble>();
if (target != null)
{
target.Damaged(damage, hit.point);
_penetrateEnemy++;
}
// 거리 계산하고 레이캐스트 다시 앞으로 나가기
distanceTraveled += hit.distance;
currentPosition = hit.point + direction * 0.001f;
}
else
{
break; // 아무것도 맞지 않았다면 루프 종료
}
}
}
}
저격총의 기본적인 발사 방법은 다른 총과 같은 로직을 가진다.
그렇기 때문에 겹치는 로직을 메인웨폰에 합치고 base로 받아오는 방법이 더 좋다고 생각한다.
총알은 관통이 되게 만든다고 했으니 while문으로 만들어,
관통 가능한 숫자를 넘고 총알의 최대 거리를 지나기 전까진 계속 앞으로 나갈 수 있다.
주의: RaycastAll로 관통을 구현하게 되면, layer 상관없이 설정한 거리까지 무조건 관통이 되므로 적합하지 않다
그 안에 로직은 설정한 Layer가 아닌 다른 Layer 마주쳤을때, 즉시 종료되는 로직과
부딪힌 후, 남은 거리를 계산해 다시 앞으로 나가는 로직이다.
4. 결과
'유니티 > 기능구현' 카테고리의 다른 글
[Unity] 유니티 C#) 메트로배니아 미니맵과 전체맵 ( 기본기능편 ) (1) | 2024.12.20 |
---|---|
[Unity] 유니티 C#) 2D 매트로베니아 미니맵과 전체맵 ( 유니티 설정편 ) (0) | 2024.12.19 |
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 샷건 ) (0) | 2024.10.23 |
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 돌격소총 ) (0) | 2024.10.17 |
[Unity] 유니티 C#) FPS 주무기를 어떻게 구현할까? ( 주무기 클래스 ) (10) | 2024.10.17 |