323 lines
11 KiB
C#
323 lines
11 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace RayFire
|
|
{
|
|
[AddComponentMenu ("RayFire/Rayfire Wind")]
|
|
[HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-wind-component/")]
|
|
public class RayfireWind : MonoBehaviour
|
|
{
|
|
public Vector3 gizmoSize = new Vector3 (30f, 2f, 50f);
|
|
public bool showGizmo = true;
|
|
public float globalScale = 10f;
|
|
public float lengthScale = 100;
|
|
public float widthScale = 100;
|
|
public float speed = 15;
|
|
public bool showNoise = false;
|
|
public float minimum = 0f;
|
|
public float maximum = 1f;
|
|
public float torque = 2f;
|
|
public bool forceByMass = true;
|
|
public float divergency = 120f;
|
|
public float turbulence = 0.5f;
|
|
public float previewDensity = 1f;
|
|
public float previewSize = 1f;
|
|
public int mask = -1;
|
|
public string tagFilter = "Untagged";
|
|
|
|
Transform transForm;
|
|
Collider[] colliders = null;
|
|
Vector3 halfExtents;
|
|
Vector3 center;
|
|
float offset;
|
|
public List<Rigidbody> rigidbodies = new List<Rigidbody>();
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Common
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Awake
|
|
void Awake()
|
|
{
|
|
// Cache variables
|
|
DefineComponents();
|
|
}
|
|
|
|
// Cache variables
|
|
void DefineComponents()
|
|
{
|
|
// Cache transform
|
|
transForm = GetComponent<Transform>();
|
|
|
|
// Set base length
|
|
colliders = new Collider[10];
|
|
}
|
|
|
|
// Main wind force coroutine
|
|
IEnumerator WindForceCor()
|
|
{
|
|
while (enabled == true)
|
|
{
|
|
// Get all colliders inside gizmo
|
|
SetColliders();
|
|
|
|
// Set rigid bodies by colliders
|
|
SetRigidBodies();
|
|
|
|
// Set force to rigid bodies
|
|
SetForce();
|
|
|
|
yield return new WaitForSeconds (0.05f);
|
|
}
|
|
}
|
|
|
|
// Enabling
|
|
void OnEnable()
|
|
{
|
|
// Main wind force coroutine
|
|
StartCoroutine (WindForceCor());
|
|
}
|
|
|
|
// Reset
|
|
void Reset()
|
|
{
|
|
globalScale = 10f;
|
|
}
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Force
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Set colliders by range type
|
|
void SetColliders()
|
|
{
|
|
// Set collider gizmo info
|
|
SetColliderGizmo();
|
|
|
|
// TODO make colAmount to private var and check/adjust length before overlap
|
|
|
|
// Get overlaps
|
|
int colAmount = Physics.OverlapBoxNonAlloc (center, halfExtents, colliders, transForm.rotation, mask);
|
|
|
|
// Increase array if not enough
|
|
if (colAmount == colliders.Length)
|
|
{
|
|
colliders = new Collider[colAmount + 30];
|
|
Physics.OverlapBoxNonAlloc (center, halfExtents, colliders, transForm.rotation, mask);
|
|
}
|
|
|
|
// Decrease array if too much
|
|
if (colliders.Length > colAmount + 50)
|
|
{
|
|
int newCol = colAmount - 30;
|
|
if (newCol > 0)
|
|
{
|
|
colliders = new Collider[newCol];
|
|
Physics.OverlapBoxNonAlloc (center, halfExtents, colliders, transForm.rotation, mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set collider gizmo info
|
|
void SetColliderGizmo()
|
|
{
|
|
//windDirection = transform.forward;
|
|
//halfWidth = widthScale / 2;
|
|
//halfLength = lengthScale / 2;
|
|
halfExtents = gizmoSize / 2f; // Consider Y height, not at center
|
|
center = transForm.position;
|
|
center.y += halfExtents.y;
|
|
}
|
|
|
|
// 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 same random state
|
|
Random.InitState (1);
|
|
|
|
// Set speed offset
|
|
SetSpeed();
|
|
|
|
// Set forceMode by mass state
|
|
ForceMode forceMode = ForceMode.Acceleration;
|
|
if (forceByMass == true)
|
|
forceMode = ForceMode.Force;
|
|
|
|
// Get str for each object by expl type with variation
|
|
foreach (Rigidbody rb in rigidbodies)
|
|
{
|
|
Vector3 rbPos = rb.transform.position;
|
|
|
|
// Get perlin noise at object position
|
|
float perlinVal = PerlinFixedGlobal (rbPos);
|
|
|
|
// Get wind strength at object position
|
|
float windStr = WindStrength (perlinVal) * 10f;
|
|
|
|
// Get vector
|
|
Vector3 vector = GetVectorGlobal (rbPos);
|
|
|
|
// Apply force
|
|
rb.AddForce (vector * windStr, forceMode);
|
|
|
|
// Set rotation impulse
|
|
if (torque > 0)
|
|
rb.AddTorque (windStr * torque * transForm.right, forceMode);
|
|
|
|
// TORQUE by divergence
|
|
}
|
|
}
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Vector
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Get vector for global position
|
|
Vector3 GetVectorGlobal (Vector3 worldPos)
|
|
{
|
|
return GetVectorLocal (transform.InverseTransformPoint (worldPos));
|
|
}
|
|
|
|
// Get vector for local position
|
|
public Vector3 GetVectorLocal (Vector3 localPos)
|
|
{
|
|
// Initial vector TODO optimise for runtime. slow because of editor
|
|
Vector3 vector = transform.forward;
|
|
|
|
// Add divergency
|
|
if (divergency > 0)
|
|
{
|
|
// Get perlin noise for rotation vector
|
|
float perlinCustomVal = PerlinCustomLocal (localPos, gizmoSize.x, gizmoSize.z, widthScale, lengthScale, globalScale * turbulence, offset + gizmoSize.z);
|
|
float ang = Mathf.Lerp (-divergency, divergency, perlinCustomVal);
|
|
|
|
// Get wind vector
|
|
vector = Quaternion.Euler (0, ang, 0) * vector;
|
|
}
|
|
|
|
return vector;
|
|
}
|
|
|
|
// Get vector for local position
|
|
public Vector3 GetVectorLocalPreview (Vector3 localPos)
|
|
{
|
|
// Initial vector TODO optimise for runtime. slow because of editor
|
|
Vector3 vector = Vector3.forward;
|
|
|
|
// Add divergency
|
|
if (divergency > 0)
|
|
{
|
|
// Get perlin noise for rotation vector
|
|
float perlinCustomVal = PerlinCustomLocal (localPos, gizmoSize.x, gizmoSize.z, widthScale, lengthScale, globalScale * turbulence, offset + gizmoSize.z);
|
|
float ang = Mathf.Lerp (-divergency, divergency, perlinCustomVal);
|
|
|
|
// Get wind vector
|
|
vector = Quaternion.Euler (0, ang, 0) * vector;
|
|
}
|
|
|
|
return vector;
|
|
}
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Perlin Fixed
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Get strength for global position
|
|
float PerlinFixedGlobal (Vector3 worldPos)
|
|
{
|
|
return PerlinFixedLocal (transForm.InverseTransformPoint (worldPos));
|
|
}
|
|
|
|
// Get strength for local position
|
|
public float PerlinFixedLocal (Vector3 localPos)
|
|
{
|
|
// Set local position
|
|
localPos.z += offset;
|
|
|
|
// Coordinates values
|
|
float xVal = (localPos.x + gizmoSize.x / 2f) / widthScale * globalScale;
|
|
float zVal = (localPos.z + gizmoSize.z / 2f) / lengthScale * globalScale;
|
|
|
|
// Perlin noise strength
|
|
float val = Mathf.PerlinNoise (xVal, zVal);
|
|
|
|
return val;
|
|
}
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Perlin Custom
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Get strength for global position
|
|
public float PerlinCustomGlobal (Vector3 worldPos, float SizeX, float SizeZ, float WidthScale, float LengthScale, float GlobalScale, float Offset)
|
|
{
|
|
return PerlinCustomLocal (transForm.InverseTransformPoint (worldPos), SizeX, SizeZ, WidthScale, LengthScale, GlobalScale, Offset);
|
|
}
|
|
|
|
// Get strength for local position
|
|
public float PerlinCustomLocal (Vector3 localPos, float SizeX, float SizeZ, float WidthScale, float LengthScale, float GlobalScale, float Offset)
|
|
{
|
|
// Set local position
|
|
localPos.z += Offset;
|
|
|
|
// Coordinates values
|
|
float xVal = (localPos.x + SizeX / 2f) / WidthScale * GlobalScale;
|
|
float zVal = (localPos.z + SizeZ / 2f) / LengthScale * GlobalScale;
|
|
|
|
// Perlin noise strength
|
|
float val = Mathf.PerlinNoise (xVal, zVal);
|
|
|
|
return val;
|
|
}
|
|
|
|
/// /////////////////////////////////////////////////////////
|
|
/// Other
|
|
/// /////////////////////////////////////////////////////////
|
|
|
|
// Get average strength
|
|
public float WindStrength (float val)
|
|
{
|
|
return Mathf.Lerp (minimum, maximum, val);
|
|
}
|
|
|
|
// Set speed offset
|
|
void SetSpeed()
|
|
{
|
|
if (speed != 0)
|
|
{
|
|
// Get offset by time
|
|
offset -= 0.015f * speed;
|
|
|
|
// Reset offset
|
|
if (offset < -100000 || offset > 100000)
|
|
offset = 0;
|
|
}
|
|
}
|
|
}
|
|
} |