added animation package and made small changes
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
|
||||
// =================================
|
||||
// Namespaces.
|
||||
// =================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
// =================================
|
||||
// Define namespace.
|
||||
// =================================
|
||||
|
||||
namespace MirzaBeig
|
||||
{
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Effects
|
||||
{
|
||||
|
||||
// =================================
|
||||
// Classes.
|
||||
// =================================
|
||||
|
||||
public class AttractionParticleAffector : ParticleAffector
|
||||
{
|
||||
// =================================
|
||||
// Nested classes and structures.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
// =================================
|
||||
// Variables.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
[Header("Affector Controls")]
|
||||
|
||||
public float arrivalRadius = 1.0f;
|
||||
public float arrivedRadius = 0.5f;
|
||||
|
||||
float arrivalRadiusSqr;
|
||||
float arrivedRadiusSqr;
|
||||
|
||||
// =================================
|
||||
// Functions.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void LateUpdate()
|
||||
{
|
||||
float uniformTransformScale = transform.lossyScale.x;
|
||||
|
||||
arrivalRadiusSqr = (arrivalRadius * arrivalRadius) * uniformTransformScale;
|
||||
arrivedRadiusSqr = (arrivedRadius * arrivedRadius) * uniformTransformScale;
|
||||
|
||||
// ...
|
||||
|
||||
base.LateUpdate();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override Vector3 GetForce()
|
||||
{
|
||||
Vector3 force;
|
||||
|
||||
if (parameters.distanceToAffectorCenterSqr < arrivedRadiusSqr)
|
||||
{
|
||||
force.x = 0.0f;
|
||||
force.y = 0.0f;
|
||||
force.z = 0.0f;
|
||||
}
|
||||
else if (parameters.distanceToAffectorCenterSqr < arrivalRadiusSqr)
|
||||
{
|
||||
float inverseArrivalScaleNormalized = 1.0f - (parameters.distanceToAffectorCenterSqr / arrivalRadiusSqr);
|
||||
force = Vector3.Normalize(parameters.scaledDirectionToAffectorCenter) * inverseArrivalScaleNormalized;
|
||||
}
|
||||
else
|
||||
{
|
||||
force = Vector3.Normalize(parameters.scaledDirectionToAffectorCenter);
|
||||
}
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
base.OnDrawGizmosSelected();
|
||||
|
||||
// ...
|
||||
|
||||
float uniformTransformScale = transform.lossyScale.x;
|
||||
|
||||
float arrivalRadius = this.arrivalRadius * uniformTransformScale;
|
||||
float arrivedRadius = this.arrivedRadius * uniformTransformScale;
|
||||
|
||||
Vector3 center = transform.position + offset;
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(center, arrivalRadius);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(center, arrivedRadius);
|
||||
|
||||
//Gizmos.color = Color.white;
|
||||
//Gizmos.DrawLine(currentParticleSystem.transform.position, center);
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End functions.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End namespace.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// --END-- //
|
||||
// =================================
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bf6d970cd2b79547a98f2dbf434935f
|
||||
timeCreated: 1470567812
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d566a25d31a988844a80d2747af4986e
|
||||
timeCreated: 1458196122
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,553 @@
|
||||
|
||||
// =================================
|
||||
// Namespaces.
|
||||
// =================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// =================================
|
||||
// Define namespace.
|
||||
// =================================
|
||||
|
||||
namespace MirzaBeig
|
||||
{
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Effects
|
||||
{
|
||||
|
||||
// =================================
|
||||
// Classes.
|
||||
// =================================
|
||||
|
||||
public abstract class ParticleAffector : MonoBehaviour
|
||||
{
|
||||
// =================================
|
||||
// Nested classes and structures.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
protected struct GetForceParameters
|
||||
{
|
||||
public float distanceToAffectorCenterSqr;
|
||||
|
||||
public Vector3 scaledDirectionToAffectorCenter;
|
||||
public Vector3 particlePosition;
|
||||
}
|
||||
|
||||
// =================================
|
||||
// Variables.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
[Header("Common Controls")]
|
||||
|
||||
public float radius = Mathf.Infinity;
|
||||
public float force = 5.0f;
|
||||
|
||||
public Vector3 offset = Vector3.zero;
|
||||
|
||||
public float scaledRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return radius * transform.lossyScale.x;
|
||||
}
|
||||
}
|
||||
|
||||
float _radius;
|
||||
float radiusSqr;
|
||||
|
||||
float forceDeltaTime;
|
||||
Vector3 transformPosition;
|
||||
|
||||
float[] particleSystemExternalForcesMultipliers;
|
||||
|
||||
public AnimationCurve scaleForceByDistance = new AnimationCurve(
|
||||
|
||||
new Keyframe(0.0f, 1.0f),
|
||||
new Keyframe(1.0f, 1.0f)
|
||||
|
||||
);
|
||||
|
||||
// If (attached to a particle system): forces will be LOCAL.
|
||||
// Else if (attached to a particle system): forces will be SELECTIVE.
|
||||
// Else: forces will be GLOBAL.
|
||||
|
||||
new ParticleSystem particleSystem;
|
||||
public List<ParticleSystem> _particleSystems;
|
||||
|
||||
int particleSystemsCount;
|
||||
|
||||
// All required particle systems that will actually be used.
|
||||
|
||||
List<ParticleSystem> particleSystems = new List<ParticleSystem>();
|
||||
|
||||
// Particles in each system.
|
||||
|
||||
// Second dimension initialized to max particle count
|
||||
// and not modified unless max particle count for that system changes.
|
||||
|
||||
// Prevents allocations each frame.
|
||||
|
||||
ParticleSystem.Particle[][] particleSystemParticles;
|
||||
ParticleSystem.MainModule[] particleSystemMainModules;
|
||||
|
||||
Renderer[] particleSystemRenderers;
|
||||
|
||||
// ^I could also just put the system and the module in a struct and make a 2D array
|
||||
// instead of having a seperate array for the modules.
|
||||
|
||||
// Current iteration of the particle systems when looping through all of them.
|
||||
// Useful to derived classes (like for the vortex particle affector).
|
||||
|
||||
protected ParticleSystem currentParticleSystem;
|
||||
|
||||
// Parameters used by derived force classes.
|
||||
|
||||
protected GetForceParameters parameters;
|
||||
|
||||
// Update even when entire particle system is invisible?
|
||||
|
||||
// Default: FALSE -> if all particles are invisible/offscreen,
|
||||
// update will not execute.
|
||||
|
||||
public bool alwaysUpdate = false;
|
||||
|
||||
// =================================
|
||||
// Functions.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
particleSystem = GetComponent<ParticleSystem>();
|
||||
}
|
||||
|
||||
// Called once per particle system, before entering second loop for its particles.
|
||||
// Used for setting up based on particle system-specific data.
|
||||
|
||||
protected virtual void PerParticleSystemSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Direction is NOT normalized.
|
||||
|
||||
protected virtual Vector3 GetForce()
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Add/remove from public list of particles being managed.
|
||||
// Remember that adding specific systems will override all
|
||||
// other contexts (global and pure local).
|
||||
|
||||
// Duplicates are not checked (intentionally).
|
||||
|
||||
public void AddParticleSystem(ParticleSystem particleSystem)
|
||||
{
|
||||
_particleSystems.Add(particleSystem);
|
||||
}
|
||||
public void RemoveParticleSystem(ParticleSystem particleSystem)
|
||||
{
|
||||
_particleSystems.Remove(particleSystem);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected virtual void LateUpdate()
|
||||
{
|
||||
_radius = scaledRadius;
|
||||
radiusSqr = _radius * _radius;
|
||||
|
||||
forceDeltaTime = force * Time.deltaTime;
|
||||
transformPosition = transform.position + offset;
|
||||
|
||||
// SELECTIVE.
|
||||
// If manually assigned a set of systems, use those no matter what.
|
||||
|
||||
if (_particleSystems.Count != 0)
|
||||
{
|
||||
// If editor array size changed, clear and add again.
|
||||
|
||||
if (particleSystems.Count != _particleSystems.Count)
|
||||
{
|
||||
particleSystems.Clear();
|
||||
particleSystems.AddRange(_particleSystems);
|
||||
}
|
||||
|
||||
// Else if array size is the same, then re-assign from
|
||||
// the editor array. I do this in case the elements are different
|
||||
// even though the size is the same.
|
||||
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _particleSystems.Count; i++)
|
||||
{
|
||||
particleSystems[i] = _particleSystems[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LOCAL.
|
||||
// Else if attached to particle system, use only that.
|
||||
// Obviously, this will only happen if there are no systems specified in the array.
|
||||
|
||||
else if (particleSystem)
|
||||
{
|
||||
// If just one element, assign as local PS component.
|
||||
|
||||
if (particleSystems.Count == 1)
|
||||
{
|
||||
particleSystems[0] = particleSystem;
|
||||
}
|
||||
|
||||
// Else, clear entire array and add only the one.
|
||||
|
||||
else
|
||||
{
|
||||
particleSystems.Clear();
|
||||
particleSystems.Add(particleSystem);
|
||||
}
|
||||
}
|
||||
|
||||
// GLOBAL.
|
||||
// Else, take all the ones from the entire scene.
|
||||
|
||||
// This is the most expensive since it searches the entire scene
|
||||
// and also requires an allocation for every frame due to not knowing
|
||||
// if the particle systems are all the same from the last frame unless
|
||||
// I had a list to compare to from last frame. In that case, I'm not sure
|
||||
// if the performance would be better or worse. Do a test later?
|
||||
|
||||
else
|
||||
{
|
||||
particleSystems.Clear();
|
||||
particleSystems.AddRange(FindObjectsOfType<ParticleSystem>());
|
||||
}
|
||||
|
||||
parameters = new GetForceParameters();
|
||||
|
||||
particleSystemsCount = particleSystems.Count;
|
||||
|
||||
// If first frame (array is null) or length is less than the number of systems, initialize size of array.
|
||||
// I never shrink the array. Not sure if that's potentially super bad? I could always throw in a public
|
||||
// bool as an option to allow shrinking since there's a performance benefit for each, but depends on the
|
||||
// implementation case.
|
||||
|
||||
if (particleSystemParticles == null || particleSystemParticles.Length < particleSystemsCount)
|
||||
{
|
||||
particleSystemParticles = new ParticleSystem.Particle[particleSystemsCount][];
|
||||
particleSystemMainModules = new ParticleSystem.MainModule[particleSystemsCount];
|
||||
|
||||
particleSystemRenderers = new Renderer[particleSystemsCount];
|
||||
particleSystemExternalForcesMultipliers = new float[particleSystemsCount];
|
||||
|
||||
for (int i = 0; i < particleSystemsCount; i++)
|
||||
{
|
||||
particleSystemMainModules[i] = particleSystems[i].main;
|
||||
particleSystemRenderers[i] = particleSystems[i].GetComponent<Renderer>();
|
||||
|
||||
particleSystemExternalForcesMultipliers[i] = particleSystems[i].externalForces.multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < particleSystemsCount; i++)
|
||||
{
|
||||
if (!particleSystemRenderers[i].isVisible && !alwaysUpdate)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int maxParticles = particleSystemMainModules[i].maxParticles;
|
||||
|
||||
if (particleSystemParticles[i] == null || particleSystemParticles[i].Length < maxParticles)
|
||||
{
|
||||
particleSystemParticles[i] = new ParticleSystem.Particle[maxParticles];
|
||||
}
|
||||
|
||||
currentParticleSystem = particleSystems[i];
|
||||
|
||||
PerParticleSystemSetup();
|
||||
|
||||
int particleCount = currentParticleSystem.GetParticles(particleSystemParticles[i]);
|
||||
|
||||
ParticleSystemSimulationSpace simulationSpace = particleSystemMainModules[i].simulationSpace;
|
||||
ParticleSystemScalingMode scalingMode = particleSystemMainModules[i].scalingMode;
|
||||
|
||||
// I could also store the transforms in an array similar to what I do with modules.
|
||||
// Or, put all of those together into a struct and make an array out of that since
|
||||
// they'll always be assigned/updated at the same time.
|
||||
|
||||
Transform currentParticleSystemTransform = currentParticleSystem.transform;
|
||||
Transform customSimulationSpaceTransform = particleSystemMainModules[i].customSimulationSpace;
|
||||
|
||||
// If in world space, there's no need to do any of the extra calculations... simplify the loop!
|
||||
|
||||
if (simulationSpace == ParticleSystemSimulationSpace.World)
|
||||
{
|
||||
for (int j = 0; j < particleCount; j++)
|
||||
{
|
||||
parameters.particlePosition = particleSystemParticles[i][j].position;
|
||||
|
||||
parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x;
|
||||
parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y;
|
||||
parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z;
|
||||
|
||||
parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude;
|
||||
|
||||
if (parameters.distanceToAffectorCenterSqr < radiusSqr)
|
||||
{
|
||||
float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr;
|
||||
float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized);
|
||||
|
||||
Vector3 force = GetForce();
|
||||
float forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i];
|
||||
|
||||
force.x *= forceScale;
|
||||
force.y *= forceScale;
|
||||
force.z *= forceScale;
|
||||
|
||||
Vector3 particleVelocity = particleSystemParticles[i][j].velocity;
|
||||
|
||||
particleVelocity.x += force.x;
|
||||
particleVelocity.y += force.y;
|
||||
particleVelocity.z += force.z;
|
||||
|
||||
particleSystemParticles[i][j].velocity = particleVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 particleSystemPosition = Vector3.zero;
|
||||
Quaternion particleSystemRotation = Quaternion.identity;
|
||||
Vector3 particleSystemLocalScale = Vector3.one;
|
||||
|
||||
Transform simulationSpaceTransform = currentParticleSystemTransform;
|
||||
|
||||
switch (simulationSpace)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.Local:
|
||||
{
|
||||
particleSystemPosition = simulationSpaceTransform.position;
|
||||
particleSystemRotation = simulationSpaceTransform.rotation;
|
||||
particleSystemLocalScale = simulationSpaceTransform.localScale;
|
||||
|
||||
break;
|
||||
}
|
||||
case ParticleSystemSimulationSpace.Custom:
|
||||
{
|
||||
simulationSpaceTransform = customSimulationSpaceTransform;
|
||||
|
||||
particleSystemPosition = simulationSpaceTransform.position;
|
||||
particleSystemRotation = simulationSpaceTransform.rotation;
|
||||
particleSystemLocalScale = simulationSpaceTransform.localScale;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new System.NotSupportedException(
|
||||
|
||||
string.Format("Unsupported scaling mode '{0}'.", simulationSpace));
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < particleCount; j++)
|
||||
{
|
||||
parameters.particlePosition = particleSystemParticles[i][j].position;
|
||||
|
||||
switch (simulationSpace)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.Local:
|
||||
case ParticleSystemSimulationSpace.Custom:
|
||||
{
|
||||
switch (scalingMode)
|
||||
{
|
||||
case ParticleSystemScalingMode.Hierarchy:
|
||||
{
|
||||
parameters.particlePosition = simulationSpaceTransform.TransformPoint(particleSystemParticles[i][j].position);
|
||||
|
||||
break;
|
||||
}
|
||||
case ParticleSystemScalingMode.Local:
|
||||
{
|
||||
// Order is important.
|
||||
|
||||
parameters.particlePosition = Vector3.Scale(parameters.particlePosition, particleSystemLocalScale);
|
||||
parameters.particlePosition = particleSystemRotation * parameters.particlePosition;
|
||||
parameters.particlePosition = parameters.particlePosition + particleSystemPosition;
|
||||
|
||||
break;
|
||||
}
|
||||
case ParticleSystemScalingMode.Shape:
|
||||
{
|
||||
parameters.particlePosition = particleSystemRotation * parameters.particlePosition;
|
||||
parameters.particlePosition = parameters.particlePosition + particleSystemPosition;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new System.NotSupportedException(
|
||||
|
||||
string.Format("Unsupported scaling mode '{0}'.", scalingMode));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x;
|
||||
parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y;
|
||||
parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z;
|
||||
|
||||
parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude;
|
||||
|
||||
//particleSystemParticles[i][j].velocity += forceDeltaTime * Vector3.Normalize(parameters.scaledDirectionToAffectorCenter);
|
||||
|
||||
if (parameters.distanceToAffectorCenterSqr < radiusSqr)
|
||||
{
|
||||
// 0.0f -> 0.99...f;
|
||||
|
||||
float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr;
|
||||
|
||||
// Evaluating a curve within a loop which is very likely to exceed a few thousand
|
||||
// iterations produces a noticeable FPS drop (around minus 2 - 5). Might be a worthwhile
|
||||
// optimization to check outside all loops if the curve is constant (all keyframes same value),
|
||||
// and then run a different block of code if true that uses that value as a stored float without
|
||||
// having to call Evaluate(t).
|
||||
|
||||
float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized);
|
||||
|
||||
// Expanded vector operations for optimization. I think this is already done by
|
||||
// the compiler, but it's nice to have for the editor anyway.
|
||||
|
||||
Vector3 force = GetForce();
|
||||
float forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i];
|
||||
|
||||
force.x *= forceScale;
|
||||
force.y *= forceScale;
|
||||
force.z *= forceScale;
|
||||
|
||||
switch (simulationSpace)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.Local:
|
||||
case ParticleSystemSimulationSpace.Custom:
|
||||
{
|
||||
switch (scalingMode)
|
||||
{
|
||||
case ParticleSystemScalingMode.Hierarchy:
|
||||
{
|
||||
force = simulationSpaceTransform.InverseTransformVector(force);
|
||||
|
||||
break;
|
||||
}
|
||||
case ParticleSystemScalingMode.Local:
|
||||
{
|
||||
// Order is important.
|
||||
// Notice how rotation and scale orders are reversed.
|
||||
|
||||
force = Quaternion.Inverse(particleSystemRotation) * force;
|
||||
force = Vector3.Scale(force, new Vector3(
|
||||
|
||||
1.0f / particleSystemLocalScale.x,
|
||||
1.0f / particleSystemLocalScale.y,
|
||||
1.0f / particleSystemLocalScale.z));
|
||||
|
||||
break;
|
||||
}
|
||||
case ParticleSystemScalingMode.Shape:
|
||||
{
|
||||
force = Quaternion.Inverse(particleSystemRotation) * force;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// This would technically never execute since it's checked earlier (above).
|
||||
|
||||
default:
|
||||
{
|
||||
throw new System.NotSupportedException(
|
||||
|
||||
string.Format("Unsupported scaling mode '{0}'.", scalingMode));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 particleVelocity = particleSystemParticles[i][j].velocity;
|
||||
|
||||
particleVelocity.x += force.x;
|
||||
particleVelocity.y += force.y;
|
||||
particleVelocity.z += force.z;
|
||||
|
||||
particleSystemParticles[i][j].velocity = particleVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentParticleSystem.SetParticles(particleSystemParticles[i], particleCount);
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(transform.position + offset, scaledRadius);
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End functions.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End namespace.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// --END-- //
|
||||
// =================================
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fbb01249b8f1d8419cf21b6846cb507
|
||||
timeCreated: 1470567813
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,263 @@
|
||||
|
||||
// =================================
|
||||
// Namespaces.
|
||||
// =================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
// =================================
|
||||
// Define namespace.
|
||||
// =================================
|
||||
|
||||
namespace MirzaBeig
|
||||
{
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Effects
|
||||
{
|
||||
|
||||
// =================================
|
||||
// Classes.
|
||||
// =================================
|
||||
|
||||
public class TurbulenceParticleAffector : ParticleAffector
|
||||
{
|
||||
// =================================
|
||||
// Nested classes and structures.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
public enum NoiseType
|
||||
{
|
||||
PseudoPerlin,
|
||||
|
||||
Perlin,
|
||||
|
||||
Simplex,
|
||||
|
||||
OctavePerlin,
|
||||
OctaveSimplex
|
||||
}
|
||||
|
||||
// =================================
|
||||
// Variables.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
[Header("Affector Controls")]
|
||||
|
||||
public float speed = 1.0f;
|
||||
|
||||
[Range(0.0f, 8.0f)]
|
||||
public float frequency = 1.0f;
|
||||
|
||||
public NoiseType noiseType = NoiseType.Perlin;
|
||||
|
||||
// ...
|
||||
|
||||
[Header("Octave Variant-Only Controls")]
|
||||
|
||||
[Range(1, 8)]
|
||||
public int octaves = 1;
|
||||
|
||||
[Range(0.0f, 4.0f)]
|
||||
public float lacunarity = 2.0f;
|
||||
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float persistence = 0.5f;
|
||||
|
||||
float time;
|
||||
|
||||
// Noise start offsets.
|
||||
|
||||
float randomX;
|
||||
float randomY;
|
||||
float randomZ;
|
||||
|
||||
// Final offset.
|
||||
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
float offsetZ;
|
||||
|
||||
// =================================
|
||||
// Functions.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
// ...
|
||||
|
||||
randomX = Random.Range(-32.0f, 32.0f);
|
||||
randomY = Random.Range(-32.0f, 32.0f);
|
||||
randomZ = Random.Range(-32.0f, 32.0f);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
time = Time.time;
|
||||
|
||||
// ...
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void LateUpdate()
|
||||
{
|
||||
offsetX = (time * speed) + randomX;
|
||||
offsetY = (time * speed) + randomY;
|
||||
offsetZ = (time * speed) + randomZ;
|
||||
|
||||
// ...
|
||||
|
||||
base.LateUpdate();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override Vector3 GetForce()
|
||||
{
|
||||
// I could also pre-multiply the frequency, but
|
||||
// all the octave variants also use frequency
|
||||
// within themselves, so it would cause redundant
|
||||
// multiplication.
|
||||
|
||||
float xX = parameters.particlePosition.x + offsetX;
|
||||
float yX = parameters.particlePosition.y + offsetX;
|
||||
float zX = parameters.particlePosition.z + offsetX;
|
||||
|
||||
float xY = parameters.particlePosition.x + offsetY;
|
||||
float yY = parameters.particlePosition.y + offsetY;
|
||||
float zY = parameters.particlePosition.z + offsetY;
|
||||
|
||||
float xZ = parameters.particlePosition.x + offsetZ;
|
||||
float yZ = parameters.particlePosition.y + offsetZ;
|
||||
float zZ = parameters.particlePosition.z + offsetZ;
|
||||
|
||||
Vector3 force;
|
||||
|
||||
switch (noiseType)
|
||||
{
|
||||
case NoiseType.PseudoPerlin:
|
||||
{
|
||||
// This isn't really right, but... it gives believable-enough results.
|
||||
// It's also much faster than real perlin noise.
|
||||
|
||||
// It works well where you don't have to animate a large field where
|
||||
// the repeating pattern would otherwise be easily seen.
|
||||
|
||||
// Examples of good uses: smoke trail particle turbulence.
|
||||
// Example of bad uses: particle box simulating waves or something...
|
||||
|
||||
float noiseX = Mathf.PerlinNoise(xX * frequency, yY * frequency);
|
||||
float noiseY = Mathf.PerlinNoise(xX * frequency, zY * frequency);
|
||||
float noiseZ = Mathf.PerlinNoise(xX * frequency, xY * frequency);
|
||||
|
||||
noiseX = Mathf.Lerp(-1.0f, 1.0f, noiseX);
|
||||
noiseY = Mathf.Lerp(-1.0f, 1.0f, noiseY);
|
||||
noiseZ = Mathf.Lerp(-1.0f, 1.0f, noiseZ);
|
||||
|
||||
Vector3 forceX = (Vector3.right * noiseX);
|
||||
Vector3 forceY = (Vector3.up * noiseY);
|
||||
Vector3 forceZ = (Vector3.forward * noiseZ);
|
||||
|
||||
force = forceX + forceY + forceZ;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
default:
|
||||
case NoiseType.Perlin:
|
||||
{
|
||||
force.x = Noise.perlin(xX * frequency, yX * frequency, zX * frequency);
|
||||
force.y = Noise.perlin(xY * frequency, yY * frequency, zY * frequency);
|
||||
force.z = Noise.perlin(xZ * frequency, yZ * frequency, zZ * frequency);
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
case NoiseType.Simplex:
|
||||
{
|
||||
force.x = Noise.simplex(xX * frequency, yX * frequency, zX * frequency);
|
||||
force.y = Noise.simplex(xY * frequency, yY * frequency, zY * frequency);
|
||||
force.z = Noise.simplex(xZ * frequency, yZ * frequency, zZ * frequency);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
case NoiseType.OctavePerlin:
|
||||
{
|
||||
force.x = Noise.octavePerlin(xX, yX, zX, frequency, octaves, lacunarity, persistence);
|
||||
force.y = Noise.octavePerlin(xY, yY, zY, frequency, octaves, lacunarity, persistence);
|
||||
force.z = Noise.octavePerlin(xZ, yZ, zZ, frequency, octaves, lacunarity, persistence);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NoiseType.OctaveSimplex:
|
||||
{
|
||||
force.x = Noise.octaveSimplex(xX, yX, zX, frequency, octaves, lacunarity, persistence);
|
||||
force.y = Noise.octaveSimplex(xY, yY, zY, frequency, octaves, lacunarity, persistence);
|
||||
force.z = Noise.octaveSimplex(xZ, yZ, zZ, frequency, octaves, lacunarity, persistence);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
base.OnDrawGizmosSelected();
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End functions.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End namespace.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// --END-- //
|
||||
// =================================
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80ca8d20214f40846b9e49b318255592
|
||||
timeCreated: 1470567813
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
// =================================
|
||||
// Namespaces.
|
||||
// =================================
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
// =================================
|
||||
// Define namespace.
|
||||
// =================================
|
||||
|
||||
namespace MirzaBeig
|
||||
{
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Effects
|
||||
{
|
||||
|
||||
// =================================
|
||||
// Classes.
|
||||
// =================================
|
||||
|
||||
public class VortexParticleAffector : ParticleAffector
|
||||
{
|
||||
// =================================
|
||||
// Nested classes and structures.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
// =================================
|
||||
// Variables.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
Vector3 axisOfRotation;
|
||||
|
||||
[Header("Affector Controls")]
|
||||
|
||||
// Useful if particle affector and particle system
|
||||
// are on the same game object, and you need a seperate
|
||||
// rotation for the system, and the affector, but don't
|
||||
// want to make the two different game objects.
|
||||
|
||||
public Vector3 axisOfRotationOffset = Vector3.zero;
|
||||
|
||||
// =================================
|
||||
// Functions.
|
||||
// =================================
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void LateUpdate()
|
||||
{
|
||||
base.LateUpdate();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
void UpdateAxisOfRotation()
|
||||
{
|
||||
axisOfRotation = Quaternion.Euler(axisOfRotationOffset) * transform.up;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void PerParticleSystemSetup()
|
||||
{
|
||||
UpdateAxisOfRotation();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override Vector3 GetForce()
|
||||
{
|
||||
// With no rotation, looking at the PS with the vortex down the Z axis, you may
|
||||
// think it's spinning the wrong way because it's counter-clockwise. But it's actually correct...
|
||||
|
||||
// Because if you were to look up aligned with the up-axis of the vortex, you'd see it spinning
|
||||
// clockwise. And if that up was inverted (you looked down at the vortex from above), then it would
|
||||
// be spinning counter-clockwise since now the vector of rotation is point at you, not away from you.
|
||||
|
||||
// I can't believe I almost mixed that up by adding a negative (-) in front of the return.
|
||||
|
||||
return Vector3.Normalize(Vector3.Cross(axisOfRotation, parameters.scaledDirectionToAffectorCenter));
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
base.OnDrawGizmosSelected();
|
||||
|
||||
// ...
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
|
||||
// When not playing, I don't have a reference to the specific particle system,
|
||||
// so just use the default method of showing the axis of rotation (which may be wrong).
|
||||
|
||||
// There's no easy way around this since I may have several particle systems being updated
|
||||
// with a single vortex. It's just a visual guide anyways, so no big deal, I suppose.
|
||||
|
||||
Vector3 axisOfRotation;
|
||||
|
||||
if (Application.isPlaying && enabled)
|
||||
{
|
||||
UpdateAxisOfRotation();
|
||||
axisOfRotation = this.axisOfRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
axisOfRotation = Quaternion.Euler(axisOfRotationOffset) * transform.up;
|
||||
}
|
||||
|
||||
Gizmos.DrawLine(transform.position + offset, (transform.position + offset) + (axisOfRotation * scaledRadius));
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End functions.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// End namespace.
|
||||
// =================================
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =================================
|
||||
// --END-- //
|
||||
// =================================
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39e8c956cffbc4b4ba68531bef53e1d4
|
||||
timeCreated: 1470567812
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user