[Practice] 간단한 콤보 어택 만들기에 카메라 흔들기 추가



간단한 콤보 어택 만들기에 카메라 흔들기 추가해보자.

(1) 간단한 콤보 어택 만들기 프로젝트를 열어서 ShakeCamera스크립트를 추가한다.

(2) CameraController 스크립트를 수정한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    [SerializeField] private Transform target;
    [SerializeField] private float minDistance=3;
    [SerializeField] private float maxDistance = 30;
    [SerializeField] private float wheelSpeed = 500;
    [SerializeField] private float xMoveSpeed = 500;
    [SerializeField] private float yMoveSpeed = 250;
    private float yMinLimit = 5;
    private float yMaxLimit = 80;
    private float x, y;
    private float distance;

    // 카메라 흔들림 효과를 재생 중인지 체크 (흔들림 효과 재생 중일 땐 이동/회전 중지)
    public bool IsOnShake { set; get; }

    private void Awake()
    {
        distance=Vector3.Distance(transform.position, target.position);
        Vector3 angles = transform.eulerAngles;
        x= angles.y;
        y= angles.x;
    }
    private void Update()
    {
        if(target == null) return;

        // 카메라 흔들림 효과를 재생 중일 때는 이동/회전 값을 제어하지 않는다.
        if (IsOnShake == true) return;

        x+=Input.GetAxis("Mouse X")*xMoveSpeed*Time.deltaTime;
        y-= Input.GetAxis("Mouse Y") * yMoveSpeed * Time.deltaTime;

        y = ClampAngle(y, yMinLimit, yMaxLimit);

        transform.rotation=Quaternion.Euler(y , x,0);

        distance-=Input.GetAxis("Mouse ScrollWheel")*wheelSpeed*Time.deltaTime;
        distance = Mathf.Clamp(distance, minDistance, maxDistance);
    }
    private void LateUpdate()
    {
        if (target == null) return;

        // 카메라 흔들림 효과를 재생 중일 때는 이동/회전 값을 제어하지 않는다.
        if (IsOnShake == true) return;

        transform.position=transform.rotation*new Vector3(0,0,-distance) + target.position; 
    }
    
    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;

        return Mathf.Clamp(angle, min, max);
    }
}

(3) 이에 맞게 ShakeCamera스크립트도 수정한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShakeCamera : MonoBehaviour
{
    private static ShakeCamera instance;
    public static ShakeCamera Instance => instance;

    private float shakeTime;
    private float shakeIntensity;

    private CameraController cameraController;

    private void Awake()
    {
        cameraController = GetComponent<CameraController>();
    }

    public ShakeCamera()
    {
        instance = this;
    }

    //  외부에서 카메라 흔들림을 조작할 때 호출하는 메소드
    //  ex) OnShakeCamera(1);       => 1초간 0.1의 세기로 흔들림
    //  ex) OnShakeCamera(0.5f,1);       => 0.5초간 1의 세기로 흔들림
    /// <param name="shakeTime">카메라 흔들림 지속 시간 (설정하지 않으면 디폴트 1)
    /// <param name=shakeIntensity">카메라 흔들림 세기 (값이 클수록 세게 흔들린다)(설정하지 않으면 디폴트 0.1)
    public void OnShakeCamera(float shakeTime=1.0f,float shakeIntensity = 0.1f)
    {
        this.shakeTime = shakeTime;
        this.shakeIntensity = shakeIntensity;

        //현재 코루틴이 실행중일 수도 있기 때문에 중복 실행하지 않기 위해 멈춘 후 실행한다.
        StopCoroutine("ShakeByRotation");
        StartCoroutine("ShakeByRotation");
    }

    // 카메라를 shakeTime동안 shakeIntensity의 세기로 흔드는 코루틴 함수
    private IEnumerator ShakeByPosition()
    {
        // 흔들리기 직전의 시작 위치 (흔들림 종료 후 돌아올 위치)
        Vector3 startPosition=transform.position;

        while (shakeTime>0.0f)
        {
            // 특정 축만 변경하길 원하면 아래 코드 이용 (이동하지 않을 축은 0 값 사용)
            // float x = Random.Range(-1f, 1f);
            // float y = Random.Range(-1f, 1f);
            // float z = Random.Range(-1f, 1f);
            // transform.position = startPosition + new Vector3(x, y, z) * shakeIntensity;

            // 초기 위치로부터 구 범위(Size 1) * shakeIntensity의 범위에서 카메라 위치 변동
            transform.position=startPosition+Random.insideUnitSphere*shakeIntensity;

            // 시간 감소
            shakeTime-=Time.deltaTime;

            yield return null;
        }

        transform.position=startPosition;
    }

    private IEnumerator ShakeByRotation()
    {
        // 카메라 흔들림 효과 재생 시작
        cameraController.IsOnShake = true;

        // 흔들리기 직전의 회전 값
        Vector3 startRotation = transform.eulerAngles;

        // 회전의 경우 shakeIntensity에 더 큰 값이 필요하기 때문에 변수로 만들었음
        // (클래스 멤버변수로 선언해 외부에서 조작가능)
        float power = 10f;

        while (shakeTime > 0.0f)
        {
            // 회전하길 원하는 축만 지정해서 사용 (회전하지 않을 축은 0으로 설정
            // (클래스 멤버변수로 선언해 외부에서 조작하면 더 좋다)
            float x = 0;//Random.Range(-1f,1f)
            float y = 0;//Random.Range(-1f,1f)
            float z = Random.Range(-1f, 1f);
            transform.rotation = Quaternion.Euler(startRotation + new Vector3(x, y, z) * shakeIntensity * power);

            // 시간 감소
            shakeTime-=Time.deltaTime;

            yield return null;
        }
        // 흔들리기 직전의 회전 값으로 설정
        transform.rotation=Quaternion.Euler(startRotation);

        // 카메라 흔들림 효과 재생 종료
        cameraController.IsOnShake = false;
    }
}

(4) 플레이어의 공격이 적에게 적중 했을 때 화면을 흔들기 위해 PlayerAttackCollision스크립트를 수정한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAttackCollision : MonoBehaviour
{
    private void OnEnable()
    {
        StartCoroutine("AutoDisable");
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag=="Enemy")
        {
            // 플레이어의 공격이 적에게 적중했을 때 카메라 흔들기
            ShakeCamera.Instance.OnShakeCamera(0.1f, 0.5f);

            other.GetComponent<EnemyAnimator>().TakeDamage(10);
        }  
    }

    private IEnumerator AutoDisable()
    {
        yield return new WaitForSeconds(0.1f);

        gameObject.SetActive(false);
    }
}

(5) MainCamera 오브젝트에 ShakeCamera스크립트를 추가해준다.

그리고 게임을 실행해보면 플레이어의 공격이 적에게 닿았을때는 카메라가 흔들리지만 적에게 닿지 않으면 흔들리지 않는 모습을 볼 수 있다.




© 2022. by KSC

Powered by sora