using System; using System.Linq; using Unity.Mathematics; using UnityEngine; using UnityEngine.Rendering; using static AffectingForcesManager; public class NimbleZoneDetection : MonoBehaviour { public AffectingForcesManager forcesManager; public GameObject renderedZoneObject; public enum Gravities { DownGravity, NoGravity, InwardsGravity, OutwardsGravity } [SerializeField] private static float gravityFactor = 30f; [SerializeField] private Gravities outsideGravityFunction = Gravities.NoGravity; [SerializeField] private Zone zone = Zone.NimbleZone; // Ripple properties [SerializeField] private float rippleFrequency = 3f; [SerializeField] private float rippleDensity = 30f; [SerializeField] private float rippleAmplitude = 0.1f; [SerializeField] private float rippleRadius = 1f; [SerializeField] private float rippleDuration = 1f; [SerializeField] private float impactVelocityModifier = 1f; [SerializeField] [Range(0, 1)] private float minImpact = 0.2f; [SerializeField] private float maxVelocity = 45f; private int maxRippleAmount = 5; private int playerCount = 2; private int spawnedCount = 0; private MeshRenderer meshRenderer; private Material material; void Awake() { meshRenderer = renderedZoneObject.GetComponent(); material = meshRenderer.material; ResetRippleShaderProperties(); } private Func[] gravityFunctions = { DownGravity, NoGravity, InwardsGravity, OutwardsGravity }; private static Func NoGravity = new Func(position => new Vector3()); private static Func DownGravity = new Func(position => Vector3.down * gravityFactor); private static Func InwardsGravity = new Func (position => new Vector3(position.x, position.y, 0).normalized * -gravityFactor); private static Func OutwardsGravity = new Func (position => new Vector3(position.x, position.y, 0).normalized * gravityFactor); public Func GetGravityFunction(Gravities gravity) { return gravityFunctions[(int)gravity]; } private void OnTriggerEnter(Collider collider) { int instanceID = collider.gameObject.GetInstanceID(); if (spawnedCount < playerCount) { ++spawnedCount; } else if (collider.tag == "Spike") { SpawnRipple(collider, false); return; } if (collider.tag == "Character" || collider.tag == "Player") { forcesManager.SetGravityForInstance(instanceID, NoGravity); forcesManager.SetZoneForInstance(instanceID, zone); } } private void OnTriggerExit(Collider collider) { int instanceID = collider.gameObject.GetInstanceID(); if (collider.tag == "Spike") { SpawnRipple(collider, true); return; } if (collider.tag == "Character" || collider.tag == "Player") { forcesManager.SetGravityForInstance(instanceID, GetGravityFunction(outsideGravityFunction)); forcesManager.SetZoneForInstance(instanceID, Zone.OutsideZone); } } private void Update() { material.SetFloat("_ShaderTime", Time.timeSinceLevelLoad); } private float ImpactVelocityEffect(float x, float velocity) { return math.max(math.smoothstep(0, maxVelocity, velocity), minImpact) * impactVelocityModifier * x; } private void SpawnRipple(Collider collider, bool isOutwardsRipple) { Rigidbody body = collider.attachedRigidbody; GameObject gameObject = collider.gameObject; float velocity = body.velocity.magnitude; Vector3 position = (gameObject.transform.position - transform.position).normalized; Vector4[] rippleOrigins = material.GetVectorArray("_RippleOrigins"); float currentTime = Time.timeSinceLevelLoad; float[] startedTimes = material.GetFloatArray("_RippleStartTimes"); float[] startedRippleDurations = material.GetFloatArray("_RippleDurations"); float[] rippleAmplitudes = material.GetFloatArray("_RippleAmplitudes"); float[] rippleFrequencies = material.GetFloatArray("_RippleFrequencies"); float[] rippleDensities = material.GetFloatArray("_RippleDensities"); float[] rippleRadii = material.GetFloatArray("_RippleRadii"); for (int i = 0; i < startedTimes.Length; ++i) { if (startedTimes[i] + startedRippleDurations[i] < currentTime) { rippleOrigins[i] = new Vector4(position.x, position.y, position.z, 0); material.SetVectorArray("_RippleOrigins", rippleOrigins); startedTimes[i] = currentTime; material.SetFloatArray("_RippleStartTimes", startedTimes); float amplitude = isOutwardsRipple ? rippleAmplitude : -rippleAmplitude; rippleAmplitudes[i] = ImpactVelocityEffect(amplitude, velocity); rippleFrequencies[i] = ImpactVelocityEffect(rippleFrequency, velocity); rippleDensities[i] = ImpactVelocityEffect(rippleDensity, velocity); startedRippleDurations[i] = ImpactVelocityEffect(rippleDuration, velocity); rippleRadii[i] = ImpactVelocityEffect(rippleRadius, velocity); material.SetFloatArray("_RippleAmplitudes", rippleAmplitudes); material.SetFloatArray("_RippleFrequencies", rippleFrequencies); material.SetFloatArray("_RippleDensities", rippleDensities); material.SetFloatArray("_RippleAmplitudes", rippleAmplitudes); material.SetFloatArray("_RippleDurations", startedRippleDurations); material.SetFloatArray("_RippleRadii", rippleRadii); break; } } } private void ResetRippleShaderProperties() { Vector4[] rippleOrigins = new Vector4[maxRippleAmount]; float[] startedTimes = new float[maxRippleAmount]; float[] rippleAmplitudes = new float[maxRippleAmount]; float[] rippleFrequencies = new float[maxRippleAmount]; float[] rippleDensities = new float[maxRippleAmount]; float[] rippleDurations = new float[maxRippleAmount]; float[] rippleRadii = new float[maxRippleAmount]; // Initialize Ripple Shader Properties material.SetVectorArray("_RippleOrigins", rippleOrigins); material.SetFloatArray("_RippleStartTimes", startedTimes); material.SetFloatArray("_RippleAmplitudes", rippleAmplitudes); material.SetFloatArray("_RippleFrequencies", rippleFrequencies); material.SetFloatArray("_RippleDensities", rippleDensities); material.SetFloatArray("_RippleDurations", rippleDurations); material.SetFloatArray("_RippleRadii", rippleRadii); } }