280 lines
9.2 KiB
C#
280 lines
9.2 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Lightbug.CharacterControllerPro.Core;
|
|
using Lightbug.Utilities;
|
|
|
|
namespace Lightbug.CharacterControllerPro.Demo
|
|
{
|
|
|
|
/// <summary>
|
|
/// This component handles all the particles effects associated with the character.
|
|
/// </summary>
|
|
[AddComponentMenu("Character Controller Pro/Demo/Character/Character Particles")]
|
|
public class CharacterParticles : MonoBehaviour
|
|
{
|
|
[HelpBox("This script contains a \"PlayFootstep\" method, which is intended to be used as an animation event function. " +
|
|
"Please make sure the animation clip does trigger this event (if you want to see the effect in action).", HelpBoxMessageType.Warning)]
|
|
[Tooltip("This prefab will be used by the grounded and the footsteps particles.")]
|
|
[SerializeField]
|
|
GameObject groundParticlesPrefab = null;
|
|
|
|
[Header("Grounded particles")]
|
|
|
|
[Tooltip("The character vertical speed at the moment of impact (on the horizontal axis) vs the particle system main module start speed (on the vertical axis).")]
|
|
[SerializeField]
|
|
AnimationCurve groundParticlesSpeed = AnimationCurve.Linear(0f, 0.5f, 10f, 3f);
|
|
|
|
[Header("Footsteps particles")]
|
|
|
|
[Tooltip("The character on ground speed (on the horizontal axis) vs the particle system main module start speed (on the vertical axis).")]
|
|
[SerializeField]
|
|
AnimationCurve footstepParticleSpeed = AnimationCurve.Linear(0f, 0.5f, 10f, 3f);
|
|
|
|
[Tooltip("The character on ground speed (on the horizontal axis) vs the particle system main module start size (on the vertical axis).")]
|
|
[SerializeField]
|
|
AnimationCurve footstepParticleSize = AnimationCurve.Linear(0f, 0.5f, 10f, 3f);
|
|
|
|
|
|
|
|
ParticleSystem[] groundParticlesArray = new ParticleSystem[10];
|
|
|
|
ParticleSystemPooler particlesPooler = null;
|
|
|
|
MaterialController materialController = null;
|
|
|
|
CharacterActor CharacterActor = null;
|
|
|
|
|
|
void Awake()
|
|
{
|
|
CharacterActor = this.GetComponentInBranch<CharacterActor>();
|
|
|
|
|
|
materialController = this.GetComponentInBranch<CharacterActor, MaterialController>();
|
|
|
|
if (materialController == null)
|
|
{
|
|
Debug.Log("CharacterMaterial component missing");
|
|
this.enabled = false;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (groundParticlesPrefab != null)
|
|
particlesPooler = new ParticleSystemPooler(groundParticlesPrefab, CharacterActor.transform.position, CharacterActor.transform.rotation, 10);
|
|
|
|
}
|
|
|
|
void OnEnable() => CharacterActor.OnGroundedStateEnter += OnGroundedStateEnter;
|
|
void OnDisable() => CharacterActor.OnGroundedStateEnter -= OnGroundedStateEnter;
|
|
|
|
void OnGroundedStateEnter(Vector3 localVelocity)
|
|
{
|
|
Vector3 particlePosition = CharacterActor.transform.position;
|
|
Quaternion particleRotation = Quaternion.LookRotation(CharacterActor.GroundContactNormal);
|
|
|
|
float fallingSpeed = Mathf.Abs(localVelocity.y);
|
|
|
|
float particlesStartSpeed = groundParticlesSpeed.Evaluate(fallingSpeed);
|
|
|
|
particlesPooler.Instantiate(
|
|
particlePosition,
|
|
particleRotation,
|
|
materialController.CurrentSurface.color,
|
|
particlesStartSpeed
|
|
);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Public method used by the animation events to play the footsteps particles.
|
|
/// </summary>
|
|
public void PlayFootstep()
|
|
{
|
|
if (!enabled)
|
|
return;
|
|
|
|
Vector3 particlePosition = CharacterActor.transform.position;
|
|
Quaternion particleRotation = CharacterActor.GroundContactNormal != Vector3.zero ? Quaternion.LookRotation(CharacterActor.GroundContactNormal) : Quaternion.identity;
|
|
|
|
float groundedSpeed = CharacterActor.Velocity.magnitude;
|
|
particlesPooler.Instantiate(
|
|
particlePosition,
|
|
particleRotation,
|
|
materialController.CurrentSurface.color,
|
|
footstepParticleSpeed.Evaluate(groundedSpeed),
|
|
footstepParticleSize.Evaluate(groundedSpeed)
|
|
);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
particlesPooler.Update();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// This class implements a simple "Particle System Pooler". By using this system it is possible to reuse a fixed number of particles, avoiding runtime instantiation (thus improving performance).
|
|
/// </summary>
|
|
public class ParticleSystemPooler
|
|
{
|
|
List<ParticleSystem> activeList = new List<ParticleSystem>();
|
|
List<ParticleSystem> inactiveList = new List<ParticleSystem>();
|
|
|
|
public ParticleSystemPooler(GameObject particlePrefab, Vector3 position, Quaternion rotation, int bufferLength)
|
|
{
|
|
for (int i = 0; i < bufferLength; i++)
|
|
{
|
|
GameObject gameObject = GameObject.Instantiate<GameObject>(particlePrefab, position, rotation);
|
|
ParticleSystem particleSystem = gameObject.GetComponent<ParticleSystem>();
|
|
ParticleSystem.MainModule mainModule = particleSystem.main;
|
|
mainModule.playOnAwake = false;
|
|
particleSystem.Stop(true);
|
|
|
|
if (particleSystem != null)
|
|
inactiveList.Add(particleSystem);
|
|
}
|
|
}
|
|
|
|
ParticleSystem SelectParticle()
|
|
{
|
|
ParticleSystem selectedParticle = null;
|
|
|
|
if (inactiveList.Count == 0)
|
|
{
|
|
selectedParticle = activeList[0];
|
|
}
|
|
else
|
|
{
|
|
selectedParticle = inactiveList[0];
|
|
inactiveList.RemoveAt(0);
|
|
activeList.Add(selectedParticle);
|
|
}
|
|
|
|
return selectedParticle;
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Puts a particle from the pool into the scene.
|
|
/// </summary>
|
|
public void Instantiate(Vector3 position, Quaternion rotation)
|
|
{
|
|
ParticleSystem particleSystem = SelectParticle();
|
|
|
|
particleSystem.transform.position = position;
|
|
particleSystem.transform.rotation = rotation;
|
|
|
|
particleSystem.Play(true);
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Puts a particle from the pool into the scene.
|
|
/// </summary>
|
|
public void Instantiate(Vector3 position, Quaternion rotation, Color color)
|
|
{
|
|
ParticleSystem particleSystem = SelectParticle();
|
|
|
|
ParticleSystem.MainModule mainModule = particleSystem.main;
|
|
|
|
particleSystem.transform.position = position;
|
|
particleSystem.transform.rotation = rotation;
|
|
|
|
Color particleColor = mainModule.startColor.color;
|
|
particleColor.r = color.r;
|
|
particleColor.g = color.g;
|
|
particleColor.b = color.b;
|
|
|
|
mainModule.startColor = particleColor;
|
|
|
|
particleSystem.Play(true);
|
|
|
|
activeList.Add(particleSystem);
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Puts a particle from the pool into the scene.
|
|
/// </summary>
|
|
public void Instantiate(Vector3 position, Quaternion rotation, Color color, float startSpeed)
|
|
{
|
|
ParticleSystem particleSystem = SelectParticle();
|
|
|
|
ParticleSystem.MainModule mainModule = particleSystem.main;
|
|
|
|
particleSystem.transform.position = position;
|
|
particleSystem.transform.rotation = rotation;
|
|
|
|
Color particleColor = mainModule.startColor.color;
|
|
particleColor.r = color.r;
|
|
particleColor.g = color.g;
|
|
particleColor.b = color.b;
|
|
|
|
mainModule.startColor = particleColor;
|
|
mainModule.startSpeed = startSpeed;
|
|
|
|
particleSystem.Play(true);
|
|
|
|
activeList.Add(particleSystem);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Puts a particle from the pool into the scene.
|
|
/// </summary>
|
|
public void Instantiate(Vector3 position, Quaternion rotation, Color color, float startSpeed, float startSize)
|
|
{
|
|
ParticleSystem particleSystem = SelectParticle();
|
|
|
|
ParticleSystem.MainModule mainModule = particleSystem.main;
|
|
|
|
particleSystem.transform.position = position;
|
|
particleSystem.transform.rotation = rotation;
|
|
|
|
Color particleColor = mainModule.startColor.color;
|
|
particleColor.r = color.r;
|
|
particleColor.g = color.g;
|
|
particleColor.b = color.b;
|
|
|
|
mainModule.startColor = particleColor;
|
|
mainModule.startSpeed = startSpeed;
|
|
mainModule.startSize = startSize;
|
|
|
|
particleSystem.Play(true);
|
|
|
|
activeList.Add(particleSystem);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the system.
|
|
/// </summary>
|
|
public void Update()
|
|
{
|
|
for (int i = activeList.Count - 1; i >= 0; i--)
|
|
{
|
|
ParticleSystem particleSystem = activeList[i];
|
|
|
|
if (!particleSystem.isPlaying)
|
|
{
|
|
activeList.RemoveAt(i);
|
|
|
|
inactiveList.Add(particleSystem);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|