Unity 포트폴리오/플젝2. 3D FPS게임
Unity FPS : 총 스크립트
jjiing
2022. 6. 21. 00:45
(본 글은 프로젝트 중 공부했던 내용을 개인적으로 기록하기 위한 용도입니다.)
총 스크립트에서는
총의 발사 / 재장전 / 정조준 / 총 애니메이션 등에 대해 다룬다.
공격(데미지)는 레이캐스트를 사용해 구현했다.
<Script>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
public float range; //사거리
public float fireRate; //연사속도
public float currentFireRate;
public float reloadTime; //재장전 속도
int damage;
//총알 수 관련 - powershot용
float bulletMax;
public float bulletCurrent;
private float fuelCellRatio;
public Vector3 originPos;
public Vector3 fineSightPos; //정조준시 총 위치
//사운드 & 이펙트 관련
public Transform weaponMuzzle;
public Transform powerShotPoint;
public GameObject muzzleFlash;
public AudioClip fireSound;
public AudioClip reloadSound;
public Animator anim;
private AudioSource audioSource;
public Camera cam;
public GameObject hit_effect;
public LineRenderer bulletOrbit_lazer;
public GameObject aimPoint;
//총이 쏴지면 안되는 화면에서의 총 제어를 위한 bool 변수
public static bool isPaused;
public bool isReload; //재장전중
public bool isFineSightMode; //정조준 모드
public bool isFire; //발사
GameObject player;
PlayerMove playerMove;
float originTurnSpeed; //정조준시 감도제어를 위해 미리 받아두는 원래 플레이어 감도
private RaycastHit hit; //레이저 충돌 정보 받아옴
//프로퍼티
public float FuelCellRatio
{
get { return fuelCellRatio; }
set { fuelCellRatio = value; }
}
public float BulletCurrentRatio { get; set; }
void Awake()
{
//참조
player = GameObject.FindGameObjectWithTag("Player");
playerMove = player.GetComponent<PlayerMove>();
audioSource = GetComponent<AudioSource>();
anim = GetComponent<Animator>();
//초기화
range = 200;
fireRate = 0.2f;
reloadTime = 1f;
damage = 40;
bulletMax = 10;
bulletCurrent = bulletMax;
fuelCellRatio = 1;
//bool
isReload = false;
isFineSightMode = false;
isFire = false;
isPaused = false;
}
void Update()
{
TryFire(); //발사
TryReload(); //재장전
TryFineSight(); //정조준(우클릭)
GunAnim(); //총 애니메이션
UpdateBullet(); //파워샷 위해 fuelcellRatio관리
}
private void TryFire()
{
//연사속도 계산
GunFireRateCalc();
if (!isReload && !isPaused)
if (bulletCurrent > 0)
{
if (Input.GetButton("Fire1") && currentFireRate <= 0)
{
isFire = true;
Fire(); //실제 한발 발사 함수
}
if (Input.GetButtonUp("Fire1"))
isFire = false;
}
else
StartCoroutine(ReloadCo()); //총알 없으면 자동재장전
}
private void GunFireRateCalc()
{
//연사속도계산 - currentFireRate을 계속 감소하게 하고 0이되면 발사가능하게끔
if (currentFireRate > 0)
currentFireRate -= Time.deltaTime;//1초에 1 감소시킨다.
}
private void Fire()
{
currentFireRate = fireRate; //연사속도제어변수 초기화
bulletCurrent--; //총알 개수 감소
//muzzle 초록색 플래쉬 이펙트
GameObject muzzleFlashInstance = Instantiate(muzzleFlash, weaponMuzzle.position,
weaponMuzzle.rotation, weaponMuzzle.transform);
muzzleFlashInstance.transform.SetParent(weaponMuzzle); //복제를 gun muzzle의 자식으로
Destroy(muzzleFlashInstance, 2f);
//사운드
PlaySE(fireSound);
//조준시 함수
Hit();
}
private void Hit()
{
//총알 궤적 이펙트 - 라인렌더러
Vector3 lazerStartPos = weaponMuzzle.transform.position;
bulletOrbit_lazer.startWidth = 0.1f;
bulletOrbit_lazer.endWidth = 0.2f;
bulletOrbit_lazer.SetPosition(0, weaponMuzzle.transform.position);
bulletOrbit_lazer.SetPosition(1, aimPoint.transform.position);
bulletOrbit_lazer.gameObject.SetActive(true);
StartCoroutine(bulletOrbitDeactiveCo());
//레이캐스트로 발사
if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, range))
{
//벽 콜라이더에 맞으면 총알궤적이펙트만 넣고 적중이펙트는X
if (!hit.transform.CompareTag("Wall"))
{
var clone = Instantiate(hit_effect, hit.point, Quaternion.LookRotation(hit.normal));
Destroy(clone, 2f);
}
//몬스터 적중시
if (hit.transform.CompareTag("Monster"))
{
hit.transform.GetComponent<Monster>().Hp -= damage;
hit.transform.GetComponent<Monster>().isDamaged = true;
if (hit.transform.GetComponent<Monster>().isDead ==false)
fuelCellRatio -= 0.08f; //파워샷 스킬용(적중시 스킬 게이지 증가)
}
}
}
private void TryReload() //R눌러서 직접 재장전
{
if (Input.GetKeyDown(KeyCode.R) && !isReload && bulletCurrent < bulletMax)
{
StartCoroutine(ReloadCo());
}
}
IEnumerator bulletOrbitDeactiveCo()
{
yield return new WaitForSeconds(0.05f);
bulletOrbit_lazer.gameObject.SetActive(false);
}
//재장전
IEnumerator ReloadCo()
{
isReload = true;
anim.SetTrigger("isReload");
PlaySE(reloadSound);
yield return new WaitForSeconds(reloadTime);
StopSE(reloadSound);
bulletCurrent = bulletMax;
isReload = false;
isFire = false;
}
private void TryFineSight()
{
if (!Stage1UI.isPopUp)
{
if (Input.GetButton("Fire2"))
{
isFineSightMode = true;
cam.fieldOfView = 30; //카메라필드오브 뷰 바꿔줘서 더 가까이 보이게 조절
originTurnSpeed = playerMove.TurnSpeed; //원래감도 조절
playerMove.TurnSpeed = 1f; //감도 줄여줌
range = 250; //사거리 증가
}
if (Input.GetButtonUp("Fire2"))
{
isFineSightMode = false;
cam.fieldOfView = 45;
playerMove.TurnSpeed = originTurnSpeed;
playerMove.TurnSpeed = 1.6f;
range = 200;
}
}
}
private void UpdateBullet()
{
BulletCurrentRatio = bulletCurrent / bulletMax;
}
//애니메이션
private void GunAnim()
{
anim.SetBool("isWalk", playerMove.isWalk);
anim.SetBool("isRun", playerMove.isRun);
anim.SetBool("isFire", isFire);
anim.SetBool("isFineSightMode", isFineSightMode);
anim.SetBool("isSlow", playerMove.isSlow);
}
//오디오
private void PlaySE(AudioClip _clip)
{
audioSource.clip = _clip;
audioSource.Play();
}
private void StopSE(AudioClip _clip)
{
audioSource.clip = _clip;
audioSource.Stop();
}
}