Unity_3D Survival Game Development_3

💀LeeSY·2021년 4월 3일
0
  • 이번 포스트에서는 전 포스트에서 생성한 캐릭터에게 무기(총기) 시스템을 구현하는 내용을 다룬다.
  1. 총기를 구현하기 위한 기본적인 Gun 스크립트 변수 선언
public class Gun : MonoBehaviour
{
    public string gunName; // 총 이름
    public float range; // 사정 거리
    public float accuracy; // 정확도
    public float fireRate; // 연사속도
    public float reloadTime; // 재장전 속도 

    public int damage; // 총의 데미지

    public int reloadBulletCount; // 총알 재장전 개수
    public int currentBulletCount; // 현재 탄알집에 남아있는 총알의 개수
    public int maxBulletCount; // 최대 소유 가능 총알 개수
    public int carryBulletCount; // 현재 소유중 총알 개수

    public float retroActionForce; // 반동 세기
    public float retroActionFineSightForce; // 정 조준시 반동 세기

    public Vector3 fineSightOriginPos; // 발사 시야
    public Animator anim; // 총기 애니메이션 적용
    public ParticleSystem muzzleFlash; // 총 발사 효과

    public AudioClip fire_Sound; // 총 발사 효과음

    
}
  1. Animator를 통한 총기 애니메이션 적용
    • Animator : 각각의 모션으로 분할된 캐릭터 애니메이션을 흐름과 조건에 맞추어 구성한 뒤 게임 속에서 캐릭터의 자연스러운 움직임을 구현하는 기능
    • Entry : 기본 상태 애니메이션을 지정
    • Any State : 어떤 상태에서라도 넘어갈 수 있는 애니메이션 지정
    • Exit : 무조건 애니메이션 종료
  1. Hit() 공격 : Raycast라는 전방 감지 레이저 기능을 통해 전방 공간에 존재하는 물체를 발사 시 감지하여 그에 대한 정보를 출력하거나 효과를 반영시키는 내용
private void Hit()
    {
        if (Physics.Raycast(theCam.transform.position, theCam.transform.forward +
            new Vector3(Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
                        Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
                        0)
            , out hitInfo, currentGun.range, layerMask))
        { //전방의 물체를 감지하고 해당 물체에 대한 타격 내용을 출력한다.
            GameObject clone = Instantiate(hit_effect_prefab, hitInfo.point, Quaternion.LookRotation(hitInfo.normal));
            Destroy(clone, 2f);
        }
        
    }
  1. 재장전 : 키보드 R키 또는 터치패드 버튼을 누르면 재장전 애니메이션과 함께 부족한 총알 수가 새로운 탄창으로 교체되며 채워진다.
 private void TryReload() // 재장전 시도
    {
        if(Input.GetKeyDown(KeyCode.R) && !isReload && currentGun.currentBulletCount < currentGun.reloadBulletCount) 
        { //키보드 R키를 누르면 잔여 총알 수가 기본 총알 수보다 낮고 재장전 상태가 아닐 시 재장전 코루틴을 실행하여 재장전 진행
            CancelFineSight(); 
            StartCoroutine(ReloadCoroutine());
        }
    }

    public void CancelReload() 
    {
        if (isReload) //재장전을 멈추기위해 모든 코루틴을 일시적 종료
        {
            StopAllCoroutines();
            isReload = false;
        }
    }

    IEnumerator ReloadCoroutine() // 재장전
    { 
        if(currentGun.carryBulletCount > 0) 
        {
            isReload = true;

            currentGun.anim.SetTrigger("Reload"); //재장전 애니메이션 발동

            currentGun.carryBulletCount += currentGun.currentBulletCount;
            currentGun.currentBulletCount = 0; // 기존 잔여 총알 수에 새로운 재장전 총알 수를 추가 부여

            yield return new WaitForSeconds(currentGun.reloadTime);

            if (currentGun.carryBulletCount >= currentGun.reloadBulletCount)
            { //새로운 탄창으로 교체하여 총 잔여 총알 수가 차감되는 경우
                currentGun.currentBulletCount = currentGun.reloadBulletCount;
                currentGun.carryBulletCount -= currentGun.reloadBulletCount;
            }
            else 
            { // 모든 잔여 총알 수가 완전히 0이 남을 경우
                currentGun.currentBulletCount = currentGun.carryBulletCount;
                currentGun.carryBulletCount = 0;
            }
            isReload = false;
        }
        else
        {
            Debug.Log("소유한 총알이 없음");
        }
    }
  1. 정조준 : 마우스 오른쪽 버튼을 누르면 정조준 모드를 활성화/비활성화 가능
private void TryFineSight() // 정조준 시도
    {
        if (Input.GetButtonDown("Fire2") && !isReload)
        {
            FineSight(); 
        }
    }

    public void CancelFineSight() // 정조준 취소
    {
        if (isFineSightMode)
            FineSight();
    }

    private void FineSight() // 정조준 가동
    {
        isFineSightMode = !isFineSightMode;
        currentGun.anim.SetBool("FineSightMode", isFineSightMode); // 정조준 애니메이션 가동
        theCrosshair.FineSightAnimation(isFineSightMode);

        if (isFineSightMode)
        {
            StopAllCoroutines(); //모든 코루틴을 중지하고 정조준 활성화 코루틴만을 실행한다.
            StartCoroutine(FineSightActivateCoroutine()); 
        }
        else
        {
            StopAllCoroutines(); //모든 코루틴을 중지하고 정조준 비활성화 코루틴만을 실행한다.
            StartCoroutine(FineSightDeactivateCoroutine());
        }
    }

    IEnumerator FineSightActivateCoroutine() // 정조준 활성화
    {
        while(currentGun.transform.localPosition != currentGun.fineSightOriginPos)
        {  // 플레이어가 바라보는 시야에서 z값 (0.2f) 만큼의 시야 조정과 정조준 위치값을 지정하여 정조준 모드를 활성화한다.
            currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.2f);
            yield return null;
        }
    }
    IEnumerator FineSightDeactivateCoroutine() // 정조준 비활성화
    {
        while (currentGun.transform.localPosition != originPos)
        {   // 정조준 상태의 플레이어 시야가 다시 기본 originPos 시야로 복귀할수 있도록 한다.
            currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.2f);
            yield return null;
        }
    }
  1. 반동 : Vector3를 통해 저장된 좌표값을 변경해가며 화면의 앞/뒤 흔들림 정도를 조정하여 발사 시 반동 효과를 구현한다.
IEnumerator RetroActionCoroutine() // 반동 
    {
        Vector3 recoilBack = new Vector3(currentGun.retroActionForce, originPos.y, originPos.z);
        Vector3 retroActionRecoilBack = new Vector3(currentGun.retroActionFineSightForce, currentGun.fineSightOriginPos.y, currentGun.fineSightOriginPos.z);

        if (!isFineSightMode)
        {
            currentGun.transform.localPosition = originPos;

            // 반동 시작
            while(currentGun.transform.localPosition.x <= currentGun.retroActionForce - 0.02f)
            {
                currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, recoilBack, 0.4f);
                yield return null; 
            }

            // 원위치
            while(currentGun.transform.localPosition != originPos)
            {
                currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.1f);
                yield return null;
            }
        }
        else
        {
            currentGun.transform.localPosition = currentGun.fineSightOriginPos;

            // 반동 시작
            while (currentGun.transform.localPosition.x <= currentGun.retroActionFineSightForce - 0.02f)
            {
                currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, retroActionRecoilBack, 0.4f);
                yield return null;
            }

            // 원위치
            while (currentGun.transform.localPosition != currentGun.fineSightOriginPos)
            {
                currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.1f);
                yield return null;
            }
        }
    }
  1. 총기 발사 효과 : Paricle System
    • Particle System : 액체, 구름 및 불꽃 같은 유체 엔티티
    • 효과의 빛, 모양, 발생 지속 시간 등을 임의로 지정하여 개발자가 원하는 이펙트를 직접 제작할 수 있다.
  1. 총기 구현 및 발사 효과가 적용 완료된 모습

profile
A little strange but passionate, sincere hard worker.

0개의 댓글