[유니티]탑다운 슈팅 따라하기 #20 반동 및 재장전

안녕하세요 유랑입니다.

 

 

실력향상을 위해서 오늘은 유튜브를 따라하면서 공부하겠습니다.

궁금하신점 있으시다면 댓글로 남겨주세요^^

 

 

 

1. 탑다운 슈팅 따라하기

 

 

이번 강의는 Sebastian Lague님께서 만든 예제이며,

유튜브를 보시면 자세한 내용을 배우실 수 있습니다.

 

유튜브 사이트 => 유튜브 

 

 

 

유니티 슈팅

 

 

 

2. 반동 및 재장전

 

 

이번 시간에는 반동 및 재장전을 만들어 보겠습니다.

애니메이션으로 만들어도 되지만, 코딩으로 구현해 보겠습니다.

 

 

 

유니티 슈팅

 

 

 

2-1) 스크립트 작성 -㉠Gun

 

 

Gun 스크립트에 반동과 재장전에 대한 내용을 추가해 주겠습니다.

총알을 발사할 때 총에 움직임을 줘 반동효과를,

그리고 재장전이 가능하도록 메소드도 추가해 주세요.

그리고 총이 조준점을 바라보도록 코드도 수정해 주겠습니다.

 

 

 

using UnityEngine;
using System.Collections;

// 총에 해당
public class Gun : MonoBehaviour
{
    // 발사 모드
    public enum FireMode { Auto, Burst, Single };
    public FireMode fireMode;

    public Transform[] projectileSpawn; // 발사 위치
    public Projectile projectile; // 총알
    public float msBetweenShots = 100; // 연사 간격
    public float muzzleVelocity = 35;  // 총알 속도
    public int burstCount; // 버스트 횟수
    public int projectilesPerMag; // 총알 갯수
    public float reloadTime = 0.3f;

    // 반동
    [Header("Recoil")]
    public Vector2 kickMinMax = new Vector2(0.05f, 0.2f);
    public Vector2 recoilAngleMinMax = new Vector2(3, 5);
    public float recoilMoveSettleTime = 0.1f;
    public float recoilRotationSettleTime = 0.1f;
    // 효과
    [Header("Effects")]
    public Transform shell; // 탄피
    public Transform shellEjection; // 탄피 생성위치
    MuzzleFlash muzzleflash; // 머즐플래쉬효과
    float nextShotTime;

    bool triggerReleasedSinceLastShot; // 총알발사 가능여부
    int shotsRemainingInBurst; // 남아있는 버스트 횟수
    int projectilesRemainingInMag;
    bool isReloading;

    Vector3 recoilSmoothDampVelocity;
    float recoilRotSmoothDampVelocity;
    float recoilAngle; // 반동 각도

    void Start()
    {
        muzzleflash = GetComponent<MuzzleFlash>();
        shotsRemainingInBurst = burstCount;
        projectilesRemainingInMag = projectilesPerMag;
    }

    void LateUpdate()
    {
        // 반동 효과(제자리로)
        transform.localPosition = Vector3.SmoothDamp(transform.localPosition, Vector3.zero, ref recoilSmoothDampVelocity, recoilMoveSettleTime);
        recoilAngle = Mathf.SmoothDamp(recoilAngle, 0, ref recoilRotSmoothDampVelocity, recoilRotationSettleTime);
        transform.localEulerAngles = transform.localEulerAngles + Vector3.left * recoilAngle;

        if (!isReloading && projectilesRemainingInMag == 0)
        {
            Reload();
        }
    }

    void Shoot()
    {
        if (!isReloading && Time.time > nextShotTime && projectilesRemainingInMag > 0)
        {
            // 버스트 모드
            if (fireMode == FireMode.Burst)
            {
                if (shotsRemainingInBurst == 0)
                {
                    return;
                }
                shotsRemainingInBurst--;
            }
            // 싱글 모드
            else if (fireMode == FireMode.Single)
            {
                if (!triggerReleasedSinceLastShot)
                {
                    return;
                }
            }
            // 총알 생성
            for (int i = 0; i < projectileSpawn.Length; i++)
            {
                if (projectilesRemainingInMag == 0)
                {
                    break;
                }
                projectilesRemainingInMag--;
                nextShotTime = Time.time + msBetweenShots / 1000;
                Projectile newProjectile = Instantiate(projectile, projectileSpawn[i].position, projectileSpawn[i].rotation) as Projectile;
                newProjectile.SetSpeed(muzzleVelocity);
            }

            Instantiate(shell, shellEjection.position, shellEjection.rotation); // 탄피 생성
            muzzleflash.Activate(); // 머즐플래쉬 효과
            transform.localPosition -= Vector3.forward * Random.Range(kickMinMax.x, kickMinMax.y); // 반동 효과
            recoilAngle += Random.Range(recoilAngleMinMax.x, recoilAngleMinMax.y);
            recoilAngle = Mathf.Clamp(recoilAngle, 0, 30);
        }
    }
    // 재장전
    public void Reload()
    {
        if (!isReloading && projectilesRemainingInMag != projectilesPerMag)
        {
            StartCoroutine(AnimateReload());
        }
    }
    IEnumerator AnimateReload()
    {
        isReloading = true;
        yield return new WaitForSeconds(0.2f);

        float reloadSpeed = 1f / reloadTime;
        float percent = 0;
        Vector3 initialRot = transform.localEulerAngles;
        float maxReloadAngle = 30;

        while (percent < 1)
        {
            percent += Time.deltaTime * reloadSpeed;
            float interpolation = (-Mathf.Pow(percent, 2) + percent) * 4;
            float reloadAngle = Mathf.Lerp(0, maxReloadAngle, interpolation);
            transform.localEulerAngles = initialRot + Vector3.left * reloadAngle;

            yield return null;
        }


        isReloading = false;
        projectilesRemainingInMag = projectilesPerMag;
    }
    // 조준점 바라보기
    public void Aim(Vector3 aimPoint)
    {
        if (!isReloading)
        {
            transform.LookAt(aimPoint);
        }
    }
    // 마우스 버튼을 누르고 있을 때
    public void OnTriggerHold()
    {
        Shoot();
        triggerReleasedSinceLastShot = false;
    }
    // 마우스 버튼을 땠을 때
    public void OnTriggerRelease()
    {
        triggerReleasedSinceLastShot = true;
        shotsRemainingInBurst = burstCount;
    }
}

 

 

2-2) 스크립트 작성 -㉡GunController

 

 

GunController 스크립트는 Gun의 조준점과 리로드 기능을 실행하도록 

코도를 구현해 줄게요!!

 

 

 

유니티 슈팅

 

 

 

2-3) 스크립트 작성 -㉢Player

 

 

최종적으로 Player 스크립트에서 일정 범위 밖이면 총이 조준점을 바라보도록,

그리고 "R"키를 누르면 재장전이 되도록 코드구현을 해줍니다.

 

 

 

유니티 슈팅

 

 

총이 조준점을 따라가며,

플레이어 가까이 가져다 놓아도 별 문제가 없죠ㅎㅎ

 

 

유니티 슈팅

 

 

 

2-4) 스크립트 적용

 

 

총알의 개수를 증가시켜주고,

테스트를 해보겠습니다.

 

 

 

유니티 슈팅

 

 

반동과 함께 총알을 다쓰면 재장전이 되는걸 확인할 수 있습니다!!

 

 

유니티 슈팅

 

 

 

3. 마무리

 

 

오늘 강의는 여기까지입니다.

탑다운 슈팅을 따라하면서 반동 및 재장전을 구현하였습니다.

감사합니다.

 

 

 

수업자료: 탑다운 슈팅 따라하기 #20 반동 및 재장전

 

 

 

 

 

 

 

댓글

Designed by JB FACTORY