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();
    }
}