简易的屏幕震动效果

效果

让镜头在指定时间x内,不断在自身原始位置周围选点(半径为y的球形区域内),并将位置设置到该点处。
效果结束后,将镜头设置回原来的位置

做法

在x内,每隔1帧或多帧设置一次位置

  • 位置 = 原始位置 + Random.insideUnitSphere * y


    image.png

代码

using System;
using System.Collections;
using UnityEngine;

public class CameraShake : MonoBehaviour
{
    private Transform _camTrans;
    private Transform CamTrans
    {
        get
        {
            if (_camTrans == null)
            {
                _camTrans = Camera.main.transform;
                _originalLocalPos = CamTrans.localPosition;
            }
            return _camTrans;
        }
    }
    private Vector3 _originalLocalPos;
    private static CameraShake instance;
    public static CameraShake Instance
    {
        get
        {
            if (instance == null)
            {
                GameObject camShake = new GameObject("CameraShake");
                instance = camShake.AddComponent<CameraShake>();
                var parentGo = GameObject.Find("Singleton");
                if (parentGo == null)
                {
                    parentGo = new GameObject("Singleton");
                    UnityEngine.Object.DontDestroyOnLoad(parentGo);
                }
                camShake.transform.SetParent(parentGo.transform);
            }
            return instance;
        }
    }
    private IEnumerator shakeCoroutine;

    public void ShakeCamera(CamShakeCfg cfg)
    {
        ShakeCamera(cfg.Duration, cfg.MaxShakeDistance, cfg.Rate);
    }
    /// <summary>
    /// 相机震动
    /// </summary>
    /// <param name="duration">震动持续时间</param>
    /// <param name="shakeAmount">振幅(震动厉害程度)</param>
    /// <param name="decreaseFactor">震动减缓的速率</param>
    public void ShakeCamera(float duration = 0.1f, float maxShakeDistance = 0.5f, float rate = 1f)
    {
        if (!IsEnabled)
        {
            return;
        }

        if (shakeCoroutine != null)
            shakeCoroutine = null;
        shakeCoroutine = ShakeCoroutine(duration, maxShakeDistance, rate);
        StartCoroutine(shakeCoroutine);

    }

    private IEnumerator ShakeCoroutine(float duration, float maxShakeDistance, float rate)
    {
        float timer = duration;
        while (timer > 0f)
        {
            CamTrans.localPosition = _originalLocalPos + UnityEngine.Random.insideUnitSphere * maxShakeDistance;
            timer -= Time.deltaTime * rate;
            yield return new WaitForSeconds(Time.deltaTime * rate);
        }

        CamTrans.localPosition = _originalLocalPos;
        if (shakeCoroutine != null)
        {
            StopCoroutine(shakeCoroutine);
            shakeCoroutine = null;
        }
    }

    #region 激活与否
    private const string CameraShakeEnabledStorageKey = "CameraShakeEnabled";
    private const int EnableSign = 1;
    private const int DisableSign = 0;
    // 默认激活
    public bool IsEnabled { get { return PlayerPrefs.GetInt(CameraShakeEnabledStorageKey, EnableSign) != DisableSign; } }
    public void Enable()
    {
        if (!IsEnabled)
        {
            PlayerPrefs.SetInt(CameraShakeEnabledStorageKey, EnableSign);
            ChangeEnableStateEvent?.Invoke(true);
        }
    }
    public void Disable()
    {
        if (IsEnabled)
        {
            PlayerPrefs.SetInt(CameraShakeEnabledStorageKey, DisableSign);
            ChangeEnableStateEvent?.Invoke(false);
        }
    }
    public event Action<bool> ChangeEnableStateEvent;
    #endregion
}

[System.Serializable]
public class CamShakeCfg
{
    [Header("震动持续时间")]
    public float Duration = 0.1f;
    [Header("振幅(震动厉害程度)")]
    public float MaxShakeDistance = 0.5f;
    [Header("震动减缓的速率")]
    public float Rate = 1f;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容