238 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			238 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | using System.Collections.Generic; | |||
|  | using UnityEngine; | |||
|  | #if UNITY_EDITOR | |||
|  | using UnityEditor; | |||
|  | #endif | |||
|  | 
 | |||
|  | namespace CartoonFX | |||
|  | { | |||
|  | 	[RequireComponent(typeof(ParticleSystem))] | |||
|  | 	public partial class CFXR_Effect : MonoBehaviour | |||
|  | 	{ | |||
|  | 		[System.Serializable] | |||
|  | 		public class CameraShake | |||
|  | 		{ | |||
|  | 			public enum ShakeSpace | |||
|  | 			{ | |||
|  | 				Screen, | |||
|  | 				World | |||
|  | 			} | |||
|  | 
 | |||
|  | 			static public bool editorPreview = true; | |||
|  | 
 | |||
|  | 			//-------------------------------------------------------------------------------------------------------------------------------- | |||
|  | 
 | |||
|  | 			public bool enabled = false; | |||
|  | 			[Space] | |||
|  | 			public bool useMainCamera = true; | |||
|  | 			public List<Camera> cameras = new List<Camera>(); | |||
|  | 			[Space] | |||
|  | 			public float delay = 0.0f; | |||
|  | 			public float duration = 1.0f; | |||
|  | 			public ShakeSpace shakeSpace = ShakeSpace.Screen; | |||
|  | 			public Vector3 shakeStrength = new Vector3(0.1f, 0.1f, 0.1f); | |||
|  | 			public AnimationCurve shakeCurve = AnimationCurve.Linear(0, 1, 1, 0); | |||
|  | 			[Space] | |||
|  | 			[Range(0, 0.1f)] public float shakesDelay = 0; | |||
|  | 
 | |||
|  | 			[System.NonSerialized] public bool isShaking; | |||
|  | 			Dictionary<Camera, Vector3> camerasPreRenderPosition = new Dictionary<Camera, Vector3>(); | |||
|  | 			Vector3 shakeVector; | |||
|  | 			float delaysTimer; | |||
|  | 
 | |||
|  | 			//-------------------------------------------------------------------------------------------------------------------------------- | |||
|  | 			// STATIC | |||
|  | 			// Use static methods to dispatch the Camera callbacks, to ensure that ScreenShake components are called in an order in PreRender, | |||
|  | 			// and in the _reverse_ order for PostRender, so that the final Camera position is the same as it is originally (allowing concurrent | |||
|  | 			// screen shake to be active) | |||
|  | 
 | |||
|  | 			static bool s_CallbackRegistered; | |||
|  | 			static List<CameraShake> s_CameraShakes = new List<CameraShake>(); | |||
|  | 
 | |||
|  | 			static void OnPreRenderCamera_Static(Camera cam) | |||
|  | 			{ | |||
|  | 				int count = s_CameraShakes.Count; | |||
|  | 				for (int i = 0; i < count; i++) | |||
|  | 				{ | |||
|  | 					var ss = s_CameraShakes[i]; | |||
|  | 					ss.onPreRenderCamera(cam); | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			static void OnPostRenderCamera_Static(Camera cam) | |||
|  | 			{ | |||
|  | 				int count = s_CameraShakes.Count; | |||
|  | 				for (int i = count-1; i >= 0; i--) | |||
|  | 				{ | |||
|  | 					var ss = s_CameraShakes[i]; | |||
|  | 					ss.onPostRenderCamera(cam); | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			static void RegisterStaticCallback(CameraShake cameraShake) | |||
|  | 			{ | |||
|  | 				s_CameraShakes.Add(cameraShake); | |||
|  | 
 | |||
|  | 				if (!s_CallbackRegistered) | |||
|  | 				{ | |||
|  | 					Camera.onPreRender += OnPreRenderCamera_Static; | |||
|  | 					Camera.onPostRender += OnPostRenderCamera_Static; | |||
|  | 
 | |||
|  | 					s_CallbackRegistered = true; | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			static void UnregisterStaticCallback(CameraShake cameraShake) | |||
|  | 			{ | |||
|  | 				s_CameraShakes.Remove(cameraShake); | |||
|  | 
 | |||
|  | 				if (s_CallbackRegistered && s_CameraShakes.Count == 0) | |||
|  | 				{ | |||
|  | 					Camera.onPreRender -= OnPreRenderCamera_Static; | |||
|  | 					Camera.onPostRender -= OnPostRenderCamera_Static; | |||
|  | 
 | |||
|  | 					s_CallbackRegistered = false; | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			//-------------------------------------------------------------------------------------------------------------------------------- | |||
|  | 
 | |||
|  | 			void onPreRenderCamera(Camera cam) | |||
|  | 			{ | |||
|  | #if UNITY_EDITOR | |||
|  | 				//add scene view camera if necessary | |||
|  | 				if (SceneView.currentDrawingSceneView != null && SceneView.currentDrawingSceneView.camera == cam && !camerasPreRenderPosition.ContainsKey(cam)) | |||
|  | 				{ | |||
|  | 					camerasPreRenderPosition.Add(cam, cam.transform.localPosition); | |||
|  | 				} | |||
|  | #endif | |||
|  | 
 | |||
|  | 				if (isShaking && camerasPreRenderPosition.ContainsKey(cam)) | |||
|  | 				{ | |||
|  | 					camerasPreRenderPosition[cam] = cam.transform.localPosition; | |||
|  | 
 | |||
|  | 					switch (shakeSpace) | |||
|  | 					{ | |||
|  | 						case ShakeSpace.Screen: cam.transform.localPosition += cam.transform.rotation * shakeVector; break; | |||
|  | 						case ShakeSpace.World: cam.transform.localPosition += shakeVector; break; | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			void onPostRenderCamera(Camera cam) | |||
|  | 			{ | |||
|  | 				if (camerasPreRenderPosition.ContainsKey(cam)) | |||
|  | 				{ | |||
|  | 					cam.transform.localPosition = camerasPreRenderPosition[cam]; | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			public void fetchCameras() | |||
|  | 			{ | |||
|  | #if UNITY_EDITOR | |||
|  | 				if (!EditorApplication.isPlayingOrWillChangePlaymode) | |||
|  | 				{ | |||
|  | 					return; | |||
|  | 				} | |||
|  | #endif | |||
|  | 
 | |||
|  | 				foreach (var cam in cameras) | |||
|  | 				{ | |||
|  | 					if (cam == null) continue; | |||
|  | 
 | |||
|  | 					camerasPreRenderPosition.Remove(cam); | |||
|  | 				} | |||
|  | 
 | |||
|  | 				cameras.Clear(); | |||
|  | 
 | |||
|  | 				if (useMainCamera && Camera.main != null) | |||
|  | 				{ | |||
|  | 					cameras.Add(Camera.main); | |||
|  | 				} | |||
|  | 
 | |||
|  | 				foreach (var cam in cameras) | |||
|  | 				{ | |||
|  | 					if (cam == null) continue; | |||
|  | 
 | |||
|  | 					if (!camerasPreRenderPosition.ContainsKey(cam)) | |||
|  | 					{ | |||
|  | 						camerasPreRenderPosition.Add(cam, Vector3.zero); | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			public void StartShake() | |||
|  | 			{ | |||
|  | 				if (isShaking) | |||
|  | 				{ | |||
|  | 					StopShake(); | |||
|  | 				} | |||
|  | 
 | |||
|  | 				isShaking = true; | |||
|  | 				RegisterStaticCallback(this); | |||
|  | 			} | |||
|  | 
 | |||
|  | 			public void StopShake() | |||
|  | 			{ | |||
|  | 				isShaking = false; | |||
|  | 				shakeVector = Vector3.zero; | |||
|  | 				UnregisterStaticCallback(this); | |||
|  | 			} | |||
|  | 
 | |||
|  | 			public void animate(float time) | |||
|  | 			{ | |||
|  | #if UNITY_EDITOR | |||
|  | 				if (!editorPreview && !EditorApplication.isPlaying) | |||
|  | 				{ | |||
|  | 					shakeVector = Vector3.zero; | |||
|  | 					return; | |||
|  | 				} | |||
|  | #endif | |||
|  | 
 | |||
|  | 				float totalDuration = duration + delay; | |||
|  | 				if (time < totalDuration) | |||
|  | 				{ | |||
|  | 					if (time < delay) | |||
|  | 					{ | |||
|  | 						return; | |||
|  | 					} | |||
|  | 
 | |||
|  | 					if (!isShaking) | |||
|  | 					{ | |||
|  | 						this.StartShake(); | |||
|  | 					} | |||
|  | 
 | |||
|  | 					// duration of the camera shake | |||
|  | 					float delta = Mathf.Clamp01(time/totalDuration); | |||
|  | 
 | |||
|  | 					// delay between each camera move | |||
|  | 					if (shakesDelay > 0) | |||
|  | 					{ | |||
|  | 						delaysTimer += Time.deltaTime; | |||
|  | 						if (delaysTimer < shakesDelay) | |||
|  | 						{ | |||
|  | 							return; | |||
|  | 						} | |||
|  | 						else | |||
|  | 						{ | |||
|  | 							while (delaysTimer >= shakesDelay) | |||
|  | 							{ | |||
|  | 								delaysTimer -= shakesDelay; | |||
|  | 							} | |||
|  | 						} | |||
|  | 					} | |||
|  | 
 | |||
|  | 					var randomVec = new Vector3(Random.value, Random.value, Random.value); | |||
|  | 					var shakeVec = Vector3.Scale(randomVec, shakeStrength) * (Random.value > 0.5f ? -1 : 1); | |||
|  | 					shakeVector = Vector3.Lerp(Vector3.zero, shakeVec, shakeCurve.Evaluate(delta)); | |||
|  | 					//shakeVector = shakeVec * shakeCurve.Evaluate(delta); // TODO this is the same? | |||
|  | 				} | |||
|  | 				else if (isShaking) | |||
|  | 				{ | |||
|  | 					StopShake(); | |||
|  | 				} | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | } |