// Copyright (C) 2023 Nicholas Maltbie
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System.Linq;
using nickmaltbie.OpenKCC.Character;
using UnityEngine;
namespace nickmaltbie.OpenKCC.MoleKCCSample
{
public class MoleParticles : MonoBehaviour
{
///
/// Default color for particles.
///
public static Color DefaultParticleColor = new Color(153 / 255.0f, 102 / 255.0f, 0 / 255.0f);
public static Color dirtColor = DefaultParticleColor;
[SerializeField]
public ParticleSystem diggingTrailParticlePrefab;
[SerializeField]
public ParticleSystem burrowParticlePrefab;
public bool DrawParticles { get; set; }
public Color GroundParticleColor(GameObject parent)
{
if (parent?.GetComponent() is DiggingParticleColor dig)
{
return dig.diggingColor;
}
else if (parent?.GetComponentInParent() is Renderer renderer)
{
if (renderer.material.HasColor("_BaseColor"))
{
return renderer.material.GetColor("_BaseColor");
}
}
return DefaultParticleColor;
}
[SerializeField]
public int maxDiggingTrails = 10;
[SerializeField]
public Vector3 particleOffset = new Vector3(0, -0.5f, 0);
///
/// Previous parent for spawning burrowing particles.
///
private Transform previousParent;
private ParticleSystem burrowParticles;
private ParticleSystem[] diggingTrails;
private int currentTrail;
private ParticleSystem CurrentTrail => diggingTrails[currentTrail];
private ParticleSystem NextTrail
{
get
{
currentTrail = (currentTrail + 1) % diggingTrails.Length;
if (CurrentTrail.isPlaying)
{
CurrentTrail.Stop();
}
CurrentTrail.Clear();
return CurrentTrail;
}
}
public void Awake()
{
burrowParticles = Instantiate(burrowParticlePrefab, transform);
diggingTrails = Enumerable.Range(0, maxDiggingTrails)
.Select(_ => Instantiate(diggingTrailParticlePrefab, transform))
.ToArray();
burrowParticles.transform.localPosition = particleOffset;
burrowParticles.Stop();
foreach (ParticleSystem trail in diggingTrails)
{
trail.transform.localPosition = particleOffset;
trail.Stop();
}
}
public void Update()
{
if (DrawParticles)
{
UpdateParticles();
}
else
{
ClearParticles();
}
}
public void ClearParticles()
{
previousParent = null;
CurrentTrail.Stop();
burrowParticles.Stop();
burrowParticles.Clear();
}
public void UpdateParticles()
{
KCCMovementEngine movementEngine = GetComponent();
Transform currentParent = movementEngine.GroundedState.Floor?.transform;
if (currentParent == null)
{
CurrentTrail.Stop();
ParticleSystem.MainModule trailParticles = NextTrail.main;
trailParticles.simulationSpace = ParticleSystemSimulationSpace.World;
trailParticles.customSimulationSpace = null;
ParticleSystem.EmissionModule emissionSettings = CurrentTrail.emission;
emissionSettings.rateOverDistanceMultiplier = 10;
}
else if (movementEngine.GroundedState.StandingOnGround && previousParent != currentParent)
{
CurrentTrail.Stop();
ParticleSystem.MainModule trailParticles = NextTrail.main;
trailParticles.simulationSpace = ParticleSystemSimulationSpace.Custom;
trailParticles.customSimulationSpace = currentParent;
ParticleSystem.EmissionModule emissionSettings = CurrentTrail.emission;
emissionSettings.rateOverDistanceMultiplier = 10 * Mathf.Max(
currentParent.lossyScale.x,
currentParent.lossyScale.y,
currentParent.lossyScale.z
);
}
if (!CurrentTrail.isPlaying)
{
CurrentTrail.Play();
ParticleSystem.MainModule trailParticles = CurrentTrail.main;
trailParticles.startColor = new ParticleSystem.MinMaxGradient(dirtColor, GroundParticleColor(currentParent?.gameObject));
}
if (!burrowParticles.isPlaying || currentParent != previousParent)
{
burrowParticles.Play();
ParticleSystem.MainModule burrowSettings = burrowParticles.main;
burrowSettings.simulationSpace = ParticleSystemSimulationSpace.Local;
burrowSettings.startColor = new ParticleSystem.MinMaxGradient(dirtColor, GroundParticleColor(currentParent?.gameObject));
burrowParticles.transform.localPosition = particleOffset;
}
previousParent = currentParent;
}
}
}