【Unity】战斗摄像机效果:视野拉近,屏幕抖动

通过缩放Camera的Field of View实现相机拉近/远效果,比如按下摇杆视野拉近,松开摇杆视野拉远

利用AnimationCurve控制相机抖动曲线,实现类似爆炸效果视野震动

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

public class CameraEffectTest : MonoBehaviour
{
    [Space]
    //震动时间
    [SerializeField] float shakeDuration = 0.5f;
    //震动强度
    [SerializeField] float shakeStrength = 1;
    //震动曲线
    [SerializeField] AnimationCurve shakeCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.13f, 0.4f), new Keyframe(0.28f, -0.33f), new Keyframe(0.45f, 0.4f), new Keyframe(0.63f, -0.3f), new Keyframe(0.84f, 0.35f), new Keyframe(1, 0));

    //----------

    [Space]
    //视野缩放速度
    [SerializeField, Range(0.01f, 1)] float scaleFieldLerpSpeed = 0.1f;

    //----------

    //相机
    public Camera mainCamera { get; private set; }

    //震动节点
    private Transform shakeNode;

    //----------

    private void Awake()
    {
        mainCamera = Camera.main;
        if (mainCamera == null)
            mainCamera = GetComponentInChildren();

        shakeNode = transform.Find("ShakeNode");
        if (shakeNode == null)
            shakeNode = transform;
    }

    private void Start()
    {
        InitField();
        InitShake();
    }

    private void Update()
    {
        UpdateShake();

        if (Input.GetMouseButtonDown(1))
            StartShakeWithDirection(Vector3.one);

        if (Input.GetMouseButtonDown(0))
            ScaleFieldOfView(10);
        if (Input.GetMouseButtonUp(0))
            ResetFieldOfView();
    }

    private void LateUpdate()
    {
        UpdateField();
    }

    #region --- Screen Shake ---

    //节点初始位置
    private Vector3 shakeNodeInitPos = Vector3.zero;

    private float shakeTime = 0;
    private bool shakeRandom = false;
    private bool isShaking = false;
    private Vector3 shakeDirection;

    private void InitShake()
    {
        shakeNodeInitPos = shakeNode.transform.position;
        shakeTime = 0;
        isShaking = false;
        shakeDirection = Vector3.zero;
    }

    //开始震动
    public void StartShakeWithDirection(Vector3 direction)
    {
        //停止未完成的震动
        if (isShaking)
            StopShake();

        shakeTime = 0;
        shakeDirection = direction.normalized;
        isShaking = true;
        shakeRandom = false;
    }
    public void StartShakeRandomDirection()
    {
        if (isShaking)
            StopShake();

        shakeTime = 0;
        shakeDirection = (new Vector3(Random.Range(0.0f, 1.0f), 0, Random.Range(0.0f, 1.0f))).normalized;
        isShaking = true;
        shakeRandom = false;
    }
    public void StartShakeRandomDirAndPower()
    {
        if (isShaking)
            StopShake();

        shakeTime = 0;
        isShaking = true;
        shakeRandom = true;
    }

    // ----------

    private void UpdateShake()
    {
        if (isShaking)
        {
            shakeTime += Time.deltaTime;

            if (shakeTime < shakeDuration)
            {
                if (shakeRandom)
                    shakeNode.transform.localPosition = shakeNodeInitPos + Random.insideUnitSphere * shakeStrength;
                else
                    shakeNode.transform.localPosition = shakeNodeInitPos + shakeDirection * shakeStrength * shakeCurve.Evaluate((shakeTime % 1) / shakeDuration);
            }
            else
                StopShake();
        }
    }

    //停止震动
    private void StopShake()
    {
        if (shakeNode != null)
            shakeNode.localPosition = shakeNodeInitPos;
        shakeDirection = Vector3.zero;
        isShaking = false;
        shakeTime = 0;
    }

    #endregion

    #region --- Scale FieldOfView ---

    //默认视野值
    private float defaultFieldValue;
    private bool isScaleField;
    private float targetFieldValue;

    private void InitField()
    {
        defaultFieldValue = mainCamera.fieldOfView;

        isScaleField = false;
        targetFieldValue = defaultFieldValue;
    }

    private void UpdateField()
    {
        if (isScaleField)
        {
            if (Mathf.Abs(mainCamera.fieldOfView - targetFieldValue) > 0.01f)
            {
                mainCamera.fieldOfView = Mathf.Lerp(mainCamera.fieldOfView, targetFieldValue, scaleFieldLerpSpeed);
            }
            else
            {
                StopField();
            }
        }
    }
    private void StopField()
    {
        isScaleField = false;
        targetFieldValue = defaultFieldValue;
    }

    public void ScaleFieldOfView(float changeValue)
    {
        targetFieldValue = defaultFieldValue + changeValue;
        isScaleField = true;
    }
    public void ResetFieldOfView()
    {
        ScaleFieldOfView(0);
    }

    #endregion

}

 

你可能感兴趣的:(功能Demo)