408 lines
14 KiB
C#
408 lines
14 KiB
C#
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using Random = UnityEngine.Random;
|
|||
|
|
|||
|
namespace RayFire
|
|||
|
{
|
|||
|
[AddComponentMenu ("RayFire/Rayfire Vortex")]
|
|||
|
[HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-vortex-component/")]
|
|||
|
public class RayfireVortex : MonoBehaviour
|
|||
|
{
|
|||
|
|
|||
|
[HideInInspector] public Transform transForm;
|
|||
|
[HideInInspector] public Collider[] colliders;
|
|||
|
[HideInInspector] public List<Rigidbody> rigidbodies = new List<Rigidbody>();
|
|||
|
|
|||
|
Vector3 bot, top;
|
|||
|
Vector3 normal;
|
|||
|
Vector3 direction;
|
|||
|
Vector3 rbPos;
|
|||
|
Vector3 linePoint;
|
|||
|
Vector3 vectorUp;
|
|||
|
Vector3 centerOutVector;
|
|||
|
Vector3 vectorCenter;
|
|||
|
Vector3 perpend;
|
|||
|
Vector3 vectorSwirl;
|
|||
|
Vector3 forceVector;
|
|||
|
float distancePerpend;
|
|||
|
float distanceBottom;
|
|||
|
float upRateNow;
|
|||
|
float localRadius;
|
|||
|
float upRateOwn;
|
|||
|
float centerRateOwn;
|
|||
|
float centerRateNow;
|
|||
|
float upRateDif;
|
|||
|
float centerRateDif;
|
|||
|
float maxRadius;
|
|||
|
float axisDistance;
|
|||
|
Plane bottomPlane;
|
|||
|
float torqueVal;
|
|||
|
|
|||
|
|
|||
|
public bool topHandle = false;
|
|||
|
public Vector3 topAnchor = new Vector3 (3, 30, 2);
|
|||
|
public Vector3 bottomAnchor = new Vector3 (0, 0, 0);
|
|||
|
public bool showGizmo = true;
|
|||
|
public float topRadius = 15f;
|
|||
|
public float bottomRadius = 3f;
|
|||
|
public float eye = 0.1f;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public float stiffness = 1f;
|
|||
|
public float swirlStrength = 10f;
|
|||
|
public bool forceByMass = true;
|
|||
|
public bool enableTorque = true;
|
|||
|
public float torqueStrength = 0.5f;
|
|||
|
public float torqueVariation = 0.5f;
|
|||
|
public bool enableHeightBias = true;
|
|||
|
public float biasSpeed = 0.025f;
|
|||
|
public float biasSpread = 1;
|
|||
|
public int seed = 0;
|
|||
|
public int circles = 3;
|
|||
|
public int mask = -1;
|
|||
|
public string tagFilter = "Untagged";
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Common
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Awake
|
|||
|
void Awake()
|
|||
|
{
|
|||
|
// Cache variables
|
|||
|
DefineComponents();
|
|||
|
}
|
|||
|
|
|||
|
// Cache variables
|
|||
|
void DefineComponents()
|
|||
|
{
|
|||
|
// Cache transform
|
|||
|
transForm = GetComponent<Transform>();
|
|||
|
|
|||
|
// Set base length
|
|||
|
colliders = new Collider[10];
|
|||
|
}
|
|||
|
|
|||
|
// Main vortex force coroutine
|
|||
|
IEnumerator VortexForceCor()
|
|||
|
{
|
|||
|
yield return new WaitForSeconds (Random.Range (0f, 0.95f));
|
|||
|
|
|||
|
while (enabled == true)
|
|||
|
{
|
|||
|
// Set force to rigid bodies
|
|||
|
SetForce();
|
|||
|
|
|||
|
yield return new WaitForSeconds (0.066f);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Set colliders coroutine
|
|||
|
IEnumerator SetCollidersCor()
|
|||
|
{
|
|||
|
// Set collider gizmo info
|
|||
|
SetColliderGizmo();
|
|||
|
|
|||
|
yield return new WaitForSeconds (Random.Range (0f, 0.95f));
|
|||
|
|
|||
|
while (enabled == true)
|
|||
|
{
|
|||
|
// Get all colliders inside gizmo
|
|||
|
SetColliders();
|
|||
|
|
|||
|
// Set rigid bodies by colliders
|
|||
|
SetRigidBodies();
|
|||
|
|
|||
|
yield return new WaitForSeconds (0.3f);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Enabling
|
|||
|
private void OnEnable()
|
|||
|
{
|
|||
|
// Set colliders coroutine
|
|||
|
StartCoroutine (SetCollidersCor());
|
|||
|
|
|||
|
// Main wind force coroutine
|
|||
|
StartCoroutine (VortexForceCor());
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Setups
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Set colliders by range type
|
|||
|
void SetColliders()
|
|||
|
{
|
|||
|
// Get overlaps
|
|||
|
int colAmount = Physics.OverlapCapsuleNonAlloc (bot, top, maxRadius, colliders, mask);
|
|||
|
|
|||
|
// Increase array if not enough
|
|||
|
if (colAmount == colliders.Length)
|
|||
|
{
|
|||
|
colliders = new Collider[colAmount + 30];
|
|||
|
Physics.OverlapCapsuleNonAlloc (bot, top, maxRadius, colliders, mask);
|
|||
|
}
|
|||
|
|
|||
|
// Decrease array if too much
|
|||
|
if (colliders.Length > colAmount + 50)
|
|||
|
{
|
|||
|
//colliders = new Collider[colAmount - 30];
|
|||
|
Physics.OverlapCapsuleNonAlloc (bot, top, maxRadius, colliders, mask);
|
|||
|
}
|
|||
|
|
|||
|
// Get overlapped colliders
|
|||
|
// colliders = Physics.OverlapCapsule(bot, top, maxRadius, mask);
|
|||
|
|
|||
|
|
|||
|
// Occlude
|
|||
|
//if (occluders.Length > 0)
|
|||
|
//{
|
|||
|
// occluded = Physics.OverlapBox(occluders[0].bounds.center, occluders[0].bounds.extents, occluders[0].transform.rotation);
|
|||
|
// if (occluded.Length > 0)
|
|||
|
// {
|
|||
|
// Debug.Log(occluded.Length);
|
|||
|
// for (int i = occluded.Length - 1; i >= 0; i--)
|
|||
|
// {
|
|||
|
|
|||
|
// }
|
|||
|
// }
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
// Set collider gizmo info
|
|||
|
void SetColliderGizmo()
|
|||
|
{
|
|||
|
bot = transForm.TransformPoint (bottomAnchor);
|
|||
|
top = transForm.TransformPoint (topAnchor);
|
|||
|
direction = top - bot;
|
|||
|
normal = transform.up;
|
|||
|
axisDistance = topAnchor.y - bottomAnchor.y;
|
|||
|
maxRadius = topRadius;
|
|||
|
if (bottomRadius > topRadius)
|
|||
|
maxRadius = bottomRadius;
|
|||
|
bottomPlane = new Plane (transform.up, bot);
|
|||
|
}
|
|||
|
|
|||
|
// Set rigid bodies by colliders
|
|||
|
void SetRigidBodies()
|
|||
|
{
|
|||
|
rigidbodies.Clear();
|
|||
|
|
|||
|
// Collect all rigid bodies in range
|
|||
|
foreach (Collider col in colliders)
|
|||
|
{
|
|||
|
// Missing collider
|
|||
|
if (col == null)
|
|||
|
continue;
|
|||
|
|
|||
|
// Tag filter
|
|||
|
if (tagFilter != "Untagged" && !col.CompareTag (tagFilter))
|
|||
|
continue;
|
|||
|
|
|||
|
// Get attached rigid body
|
|||
|
Rigidbody rb = col.attachedRigidbody;
|
|||
|
|
|||
|
// Create projectile if rigid body new. Could be several colliders on one object.
|
|||
|
if (rb != null && rb.isKinematic == false && rigidbodies.Contains (rb) == false)
|
|||
|
rigidbodies.Add (rb);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Apply explosion force, vector and rotation to projectiles
|
|||
|
void SetForce()
|
|||
|
{
|
|||
|
// Set collider gizmo info
|
|||
|
SetColliderGizmo();
|
|||
|
|
|||
|
// Set forceMode by mass state
|
|||
|
ForceMode forceMode = ForceMode.Impulse;
|
|||
|
if (forceByMass == false)
|
|||
|
forceMode = ForceMode.VelocityChange;
|
|||
|
|
|||
|
// Get str for each object by expl type with variation
|
|||
|
foreach (Rigidbody rb in rigidbodies)
|
|||
|
{
|
|||
|
// Null check
|
|||
|
if (rb == null)
|
|||
|
continue;
|
|||
|
|
|||
|
// Instance id for same random values
|
|||
|
int instanceId = rb.GetInstanceID();
|
|||
|
|
|||
|
// Set same random state
|
|||
|
Random.InitState (instanceId + seed);
|
|||
|
|
|||
|
// Get position
|
|||
|
rbPos = rb.transform.position;
|
|||
|
|
|||
|
// Closest point on axis
|
|||
|
linePoint = GetClosetLinePoint (rbPos); // TODO get on same plane
|
|||
|
|
|||
|
// Get distance perpendicular to axis
|
|||
|
distancePerpend = Vector3.Distance (linePoint, rbPos);
|
|||
|
|
|||
|
// Get distance to bottom plane
|
|||
|
distanceBottom = bottomPlane.GetDistanceToPoint (linePoint);
|
|||
|
|
|||
|
// Current height rate for up bias
|
|||
|
upRateNow = distanceBottom / axisDistance;
|
|||
|
|
|||
|
// Below vortex
|
|||
|
if (bottomPlane.GetSide (linePoint) == false)
|
|||
|
upRateNow = -upRateNow;
|
|||
|
|
|||
|
// Get local radius
|
|||
|
localRadius = Mathf.Lerp (bottomRadius, topRadius, upRateNow);
|
|||
|
|
|||
|
// Object not in range
|
|||
|
if (localRadius < distancePerpend)
|
|||
|
continue;
|
|||
|
|
|||
|
// Get random height and depth rates
|
|||
|
upRateOwn = Random.Range (0.03f, 0.97f);
|
|||
|
centerRateOwn = Random.Range (eye, 0.90f);
|
|||
|
|
|||
|
// Height bias for upRateOwn
|
|||
|
if (enableHeightBias == true)
|
|||
|
upRateOwn = HeightBias (upRateOwn, centerRateOwn);
|
|||
|
|
|||
|
// Get current depth rate for center bias
|
|||
|
centerRateNow = distancePerpend / localRadius;
|
|||
|
|
|||
|
// Get rate differences to correct current position
|
|||
|
upRateDif = (upRateOwn - upRateNow) * stiffness;
|
|||
|
centerRateDif = (centerRateOwn - centerRateNow) * stiffness;
|
|||
|
|
|||
|
// Up vector
|
|||
|
vectorUp = upRateDif * (stiffness + 2f) * normal; // upStr;
|
|||
|
|
|||
|
// Normalized vector from axis to rigid object
|
|||
|
centerOutVector = (rbPos - linePoint).normalized;
|
|||
|
|
|||
|
// Vector to center
|
|||
|
vectorCenter = Mathf.Abs (swirlStrength) * centerRateDif * centerOutVector;
|
|||
|
|
|||
|
// Swirl vector parallel to plane
|
|||
|
perpend = Vector3.Cross (normal, centerOutVector);
|
|||
|
vectorSwirl = swirlStrength * perpend.normalized;
|
|||
|
|
|||
|
// Get final force vector
|
|||
|
forceVector = vectorUp + vectorCenter + vectorSwirl;
|
|||
|
|
|||
|
// Apply force
|
|||
|
rb.velocity = Vector3.zero;
|
|||
|
rb.AddForce (forceVector, forceMode);
|
|||
|
|
|||
|
// Set rotation impulse TODO add variation
|
|||
|
if (enableTorque == true)
|
|||
|
{
|
|||
|
torqueVal = (torqueStrength + Random.Range (-torqueVariation, torqueVariation)) * 10f;
|
|||
|
rb.AddTorque (torqueVal * swirlStrength * Random.Range (0.0f, 1f) * transForm.up, forceMode);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Other
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Get Closest Point On Vortex Axis
|
|||
|
Vector3 GetClosetLinePoint(Vector3 worldPos)
|
|||
|
{
|
|||
|
Vector3 vectorToPos = worldPos - bot;
|
|||
|
Vector3 projection = Vector3.Project (vectorToPos, direction);
|
|||
|
return projection + bot;
|
|||
|
}
|
|||
|
|
|||
|
// Get Point On Vortex Axis with same Y as worldPos
|
|||
|
Vector3 GetParallelLinePoint(Vector3 worldPos)
|
|||
|
{
|
|||
|
// Plane with direction of Y axis and position of worldPos
|
|||
|
// Plane bottomPlane = new Plane(transform.up, worldPos);
|
|||
|
// Mathf.PingPong();
|
|||
|
|
|||
|
Vector3 vectorToPos = worldPos - bot;
|
|||
|
Vector3 projection = Vector3.Project (vectorToPos, direction);
|
|||
|
return projection + bot;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
public static bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint)
|
|||
|
{
|
|||
|
intersection = Vector3.zero;
|
|||
|
|
|||
|
//calculate the distance between the linePoint and the line-plane intersection point
|
|||
|
float dotNumerator = Vector3.Dot (planePoint - linePoint, planeNormal);
|
|||
|
float dotDenominator = Vector3.Dot (lineVec, planeNormal);
|
|||
|
|
|||
|
//line and plane are not parallel
|
|||
|
if (dotDenominator != 0.0f)
|
|||
|
{
|
|||
|
float length = dotNumerator / dotDenominator;
|
|||
|
|
|||
|
//create a vector from the linePoint to the intersection point
|
|||
|
Vector3 vector = SetVectorLength (lineVec, length);
|
|||
|
|
|||
|
//get the coordinates of the line-plane intersection point
|
|||
|
intersection = linePoint + vector;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
//output not valid
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Create a vector of direction "vector" with length "size"
|
|||
|
static Vector3 SetVectorLength(Vector3 vector, float size)
|
|||
|
{
|
|||
|
// normalize the vector
|
|||
|
Vector3 vectorNormalized = Vector3.Normalize (vector);
|
|||
|
|
|||
|
// scale the vector
|
|||
|
return vectorNormalized *= size;
|
|||
|
}
|
|||
|
|
|||
|
// Get height by height bias
|
|||
|
float HeightBias(float upRateOwnLoc, float centerRateOwnLoc)
|
|||
|
{
|
|||
|
if (biasSpread > 0)
|
|||
|
{
|
|||
|
// Get Perlin noise bias
|
|||
|
float perlinVal = Mathf.PerlinNoise (Time.time * biasSpeed * centerRateOwnLoc, upRateOwnLoc) * biasSpread;
|
|||
|
|
|||
|
// Get poitive/negative offset
|
|||
|
int biasMult = 1;
|
|||
|
if (Random.value >= 0.5)
|
|||
|
biasMult = -1;
|
|||
|
|
|||
|
// Get local bias
|
|||
|
float biasLocal = perlinVal * biasMult;
|
|||
|
|
|||
|
// Adjust up rate
|
|||
|
upRateOwnLoc += biasLocal;
|
|||
|
|
|||
|
// Fix upRate
|
|||
|
if (upRateOwnLoc > 1.0f)
|
|||
|
{
|
|||
|
if (upRateOwnLoc > 2.0f)
|
|||
|
upRateOwnLoc -= 2f;
|
|||
|
else
|
|||
|
upRateOwnLoc = 1f - (upRateOwnLoc - 1.0f);
|
|||
|
}
|
|||
|
else if (upRateOwnLoc < 0.0f)
|
|||
|
{
|
|||
|
if (upRateOwnLoc < -1.0f)
|
|||
|
upRateOwnLoc += 2f;
|
|||
|
else
|
|||
|
upRateOwnLoc = -upRateOwnLoc;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return upRateOwnLoc;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|