All ships now have their own properties, which are modifiers for the base ship properties. The base behaviour of all ships can now be easily changed, while the individual differences are still respected. Ship states now trigger particle emissions & effects. This is still messy and mixed with sounds. Will be overhauled once ship state machine is introduced. To calculate gravity you now need to specify the gravity source transform.
238 lines
8.0 KiB
C#
238 lines
8.0 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using log4net;
|
|
using Managers;
|
|
using Unity.Mathematics;
|
|
using Unity.VisualScripting;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using static AffectingForcesManager;
|
|
|
|
public class NimbleZoneDetection : MonoBehaviour
|
|
{
|
|
private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
private static Transform _nimbleZoneTransform;
|
|
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
|
|
// These influence the shader on the nimble zone
|
|
[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, Tooltip("Minimum ripple effect intensity.")]
|
|
[Range(0, 1)]
|
|
private float minImpact = 0.2f;
|
|
[SerializeField, Tooltip("Velocity which makes the highest/most intense ripples.")]
|
|
private float maxVelocity = 45f;
|
|
private int maxRippleAmount = 5;
|
|
private MeshRenderer meshRenderer;
|
|
private Material material;
|
|
|
|
void Awake()
|
|
{
|
|
meshRenderer = renderedZoneObject.GetComponent<MeshRenderer>();
|
|
material = meshRenderer.material;
|
|
_nimbleZoneTransform = gameObject.transform;
|
|
ResetRippleShaderProperties();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Array of the available gravities.
|
|
/// </summary>
|
|
private Func<Transform, Transform, Vector3>[] gravityFunctions =
|
|
{ DownGravity, NoGravity, InwardsGravity, OutwardsGravity };
|
|
|
|
/// <summary>
|
|
/// Function which returns a gravity zero vector.
|
|
/// </summary>
|
|
private static readonly Func<Transform, Transform, Vector3> NoGravity =
|
|
new((gravitySource, target) => new Vector3());
|
|
|
|
/// <summary>
|
|
/// Function which returns a gravity vector downwards, depending
|
|
/// on the parent transforms rotation.
|
|
/// The parenting transform for a ship is the arena it's in.
|
|
/// </summary>
|
|
private static readonly Func<Transform, Transform, Vector3> DownGravity =
|
|
new((gravitySource, target) =>
|
|
gravitySource.rotation * Vector3.down * gravityFactor);
|
|
|
|
/// <summary>
|
|
/// Function which returns a gravity vector towards the center of the parenting transform.
|
|
/// The parenting transform for a ship is the arena it's in.
|
|
/// </summary>
|
|
private static readonly Func<Transform, Transform, Vector3> InwardsGravity =
|
|
new((gravitySource, target) =>
|
|
(target.position - gravitySource.position).normalized * -gravityFactor);
|
|
|
|
/// <summary>
|
|
/// Function which returns a gravity vector outwards from the center of the parenting transform.
|
|
/// The parenting transform for a ship is the arena it's in.
|
|
/// </summary>
|
|
private static readonly Func<Transform, Transform, Vector3> OutwardsGravity =
|
|
new((gravitySource, target) =>
|
|
(target.position - gravitySource.position).normalized * gravityFactor);
|
|
|
|
public Func<Transform, Transform, Vector3> GetGravityFunction(Gravities gravity)
|
|
{
|
|
return gravityFunctions[(int)gravity];
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider collider)
|
|
{
|
|
int instanceID = collider.gameObject.GetInstanceID();
|
|
if (collider.tag == "Spike"
|
|
&& collider.attachedRigidbody.velocity.magnitude > 1)
|
|
{
|
|
SpawnRipple(collider, false);
|
|
return;
|
|
}
|
|
if (collider.tag == "Ship")
|
|
{
|
|
forcesManager.SetGravityForInstance(instanceID, NoGravity, transform);
|
|
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 == "Ship")
|
|
{
|
|
forcesManager.SetGravityForInstance(instanceID,
|
|
GetGravityFunction(outsideGravityFunction), transform);
|
|
forcesManager.SetZoneForInstance(instanceID, Zone.OutsideZone);
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
material.SetFloat("_ShaderTime", Time.timeSinceLevelLoad);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the effect which a given velocity has on a ripple property.
|
|
/// </summary>
|
|
/// <param name="duration">Initial value of the ripple property</param>
|
|
/// <param name="velocity">Velocity of the impact</param>
|
|
/// <returns></returns>
|
|
private float ImpactVelocityEffect(float initial, float velocity)
|
|
{
|
|
return math.max(math.smoothstep(0, maxVelocity, velocity), minImpact)
|
|
* impactVelocityModifier * initial;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Spawns ripples on the shader of the nimble zone.
|
|
/// Up to 5 parallel ripples.
|
|
/// </summary>
|
|
/// <param name="collider"></param>
|
|
/// <param name="isOutwardsRipple"></param>
|
|
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;
|
|
position = transform.InverseTransformDirection(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");
|
|
|
|
if (startedTimes == null)
|
|
{
|
|
Log.Warn("Ripple shader properties are null. Reseting shader");
|
|
ResetRippleShaderProperties();
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the ripple shaders exposed properties to 0
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|