using UnityEngine; /// /// Old film projector feel for the credits projected on the theatre screen: the projector light, /// the projected image and the light rays share the same subtle brightness flicker, with rare /// short dips like a skipping film. /// public class CreditsProjector : MonoBehaviour { [SerializeField] private Light _light; [SerializeField] private CanvasGroup _image; [SerializeField] private Renderer[] _rays; [Tooltip("Continuous brightness variation (0 = steady)")] [SerializeField, Range(0f, 1f)] private float _flickerAmount = .08f; [SerializeField, Min(0f)] private float _flickerSpeed = 7f; [Tooltip("Average number of short brightness dips per second")] [SerializeField, Min(0f)] private float _dipsPerSecond = .3f; [SerializeField, Range(0f, 1f)] private float _dipAmount = .25f; [SerializeField, Min(0f)] private float _dipDuration = .06f; [Tooltip("How much of the flicker reaches the projected image (the light and rays get all of it)")] [SerializeField, Range(0f, 1f)] private float _imageFlicker = .5f; private static readonly int ColorId = Shader.PropertyToID("_Color"); private float _baseIntensity; private float _baseAlpha; private Color[] _baseRayColors; private MaterialPropertyBlock _block; private float _dipTimer; private float _seed; private void Awake() { _seed = Random.Range(0f, 100f); _block = new MaterialPropertyBlock(); if (_light) _baseIntensity = _light.intensity; if (_image) _baseAlpha = _image.alpha; _baseRayColors = new Color[_rays.Length]; for (int i = 0; i < _rays.Length; i++) _baseRayColors[i] = _rays[i] && _rays[i].sharedMaterial ? _rays[i].sharedMaterial.GetColor(ColorId) : Color.white; } private void Update() { float noise = Mathf.PerlinNoise(Time.time * _flickerSpeed, _seed); float brightness = 1f - _flickerAmount * noise; if (_dipTimer > 0f) _dipTimer -= Time.deltaTime; else if (Random.value < _dipsPerSecond * Time.deltaTime) _dipTimer = _dipDuration; if (_dipTimer > 0f) brightness *= 1f - _dipAmount; if (_light) _light.intensity = _baseIntensity * brightness; if (_image) _image.alpha = _baseAlpha * Mathf.Lerp(1f, brightness, _imageFlicker); for (int i = 0; i < _rays.Length; i++) { if (!_rays[i]) continue; _rays[i].GetPropertyBlock(_block); Color color = _baseRayColors[i]; _block.SetColor(ColorId, new Color(color.r * brightness, color.g * brightness, color.b * brightness, color.a)); _rays[i].SetPropertyBlock(_block); } } }