Files
WhiteMan_Unity2D/Assets/Hovl Studio/HSFiles/Scripts/HS_ProjectileMover.cs

321 lines
9.3 KiB
C#

using System.Collections;
using UnityEngine;
namespace Hovl
{
public class HS_ProjectileMover : MonoBehaviour
{
[SerializeField] protected float speed = 15f;
[SerializeField] protected float hitOffset = 0f;
[SerializeField] protected bool UseFirePointRotation;
[SerializeField] protected Vector3 rotationOffset = Vector3.zero;
[Header("Effects")]
[SerializeField] protected GameObject hit;
[SerializeField] protected ParticleSystem hitPS;
[SerializeField] protected GameObject flash;
[SerializeField] protected ParticleSystem projectilePS;
[SerializeField] protected GameObject[] Detached;
[Header("Components")]
[SerializeField] protected Rigidbody rb;
[SerializeField] protected Collider col;
[SerializeField] protected Light lightSourse;
[Header("Lifetime")]
[SerializeField] protected bool notDestroy = false;
[SerializeField] protected float lifeTime = 5f;
[SerializeField] protected float detachedLifeTime = 1f;
protected bool initialized;
protected bool collided;
protected Coroutine lifeRoutine;
protected Coroutine disableAfterHitRoutine;
[System.Serializable]
protected class DetachedState
{
public GameObject obj;
public Transform originalParent;
public Vector3 localPosition;
public Quaternion localRotation;
public Vector3 localScale;
}
protected DetachedState[] detachedStates;
protected virtual void Awake()
{
if (rb == null)
rb = GetComponent<Rigidbody>();
if (col == null)
col = GetComponent<Collider>();
SetupDetachedCache();
}
protected virtual void Start()
{
initialized = true;
if (flash != null)
flash.transform.SetParent(null, true);
StartLifeTimer();
}
protected virtual void OnEnable()
{
collided = false;
if (!initialized)
return;
StopRunningCoroutines();
if (lightSourse != null)
lightSourse.enabled = true;
if (col != null)
col.enabled = true;
if (rb != null)
{
rb.constraints = RigidbodyConstraints.None;
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = Vector3.zero;
#else
rb.velocity = Vector3.zero;
#endif
rb.angularVelocity = Vector3.zero;
}
if (projectilePS != null)
{
projectilePS.Clear(true);
projectilePS.Play(true);
}
if (notDestroy)
RestoreDetachedObjects();
StartLifeTimer();
}
protected virtual void OnDisable()
{
StopRunningCoroutines();
}
protected virtual void StopRunningCoroutines()
{
if (lifeRoutine != null)
{
StopCoroutine(lifeRoutine);
lifeRoutine = null;
}
if (disableAfterHitRoutine != null)
{
StopCoroutine(disableAfterHitRoutine);
disableAfterHitRoutine = null;
}
}
protected virtual void SetupDetachedCache()
{
if (Detached == null || Detached.Length == 0)
return;
detachedStates = new DetachedState[Detached.Length];
for (int i = 0; i < Detached.Length; i++)
{
GameObject obj = Detached[i];
if (obj == null)
continue;
detachedStates[i] = new DetachedState
{
obj = obj,
originalParent = obj.transform.parent,
localPosition = obj.transform.localPosition,
localRotation = obj.transform.localRotation,
localScale = obj.transform.localScale
};
}
}
protected virtual void RestoreDetachedObjects()
{
if (detachedStates == null || detachedStates.Length == 0)
return;
for (int i = 0; i < detachedStates.Length; i++)
{
DetachedState state = detachedStates[i];
if (state == null || state.obj == null)
continue;
Transform t = state.obj.transform;
t.SetParent(state.originalParent, false);
t.localPosition = state.localPosition;
t.localRotation = state.localRotation;
t.localScale = state.localScale;
ParticleSystem[] systems = state.obj.GetComponentsInChildren<ParticleSystem>(true);
for (int j = 0; j < systems.Length; j++)
{
ParticleSystem ps = systems[j];
if (ps == null)
continue;
ps.Clear(true);
ps.Play(true);
}
}
}
protected virtual void StartLifeTimer()
{
if (lifeRoutine != null)
StopCoroutine(lifeRoutine);
lifeRoutine = StartCoroutine(LifeTimerRoutine(lifeTime));
}
protected virtual IEnumerator LifeTimerRoutine(float time)
{
yield return new WaitForSeconds(time);
if (notDestroy)
{
if (gameObject.activeSelf)
gameObject.SetActive(false);
}
else
{
Destroy(gameObject);
}
}
protected virtual void FixedUpdate()
{
if (collided || rb == null || speed == 0f)
return;
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = transform.forward * speed;
#else
rb.velocity = transform.forward * speed;
#endif
}
protected virtual void OnCollisionEnter(Collision collision)
{
if (collided)
return;
collided = true;
StopRunningCoroutines();
if (rb != null)
{
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = Vector3.zero;
#else
rb.velocity = Vector3.zero;
#endif
rb.angularVelocity = Vector3.zero;
rb.constraints = RigidbodyConstraints.FreezeAll;
}
if (lightSourse != null)
lightSourse.enabled = false;
if (col != null)
col.enabled = false;
if (projectilePS != null)
projectilePS.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
if (collision.contactCount > 0)
SpawnHit(collision.contacts[0]);
ReleaseDetachedObjects();
float endDelay = 1f;
if (hitPS != null)
endDelay = Mathf.Max(hitPS.main.duration, 0.05f);
if (notDestroy)
disableAfterHitRoutine = StartCoroutine(DisableAfterHit(endDelay));
else
Destroy(gameObject, endDelay);
}
protected virtual IEnumerator DisableAfterHit(float delay)
{
yield return new WaitForSeconds(delay);
if (gameObject != null && gameObject.activeSelf)
gameObject.SetActive(false);
}
protected virtual void SpawnHit(ContactPoint contact)
{
if (hit == null)
return;
Vector3 pos = contact.point + contact.normal * hitOffset;
Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal);
hit.transform.position = pos;
hit.transform.rotation = rot;
if (UseFirePointRotation)
hit.transform.rotation = transform.rotation * Quaternion.Euler(0f, 180f, 0f);
else if (rotationOffset != Vector3.zero)
hit.transform.rotation = Quaternion.Euler(rotationOffset);
else
hit.transform.LookAt(contact.point + contact.normal);
if (hitPS != null)
{
hitPS.Clear(true);
hitPS.Play(true);
}
}
protected virtual void ReleaseDetachedObjects()
{
if (detachedStates == null || detachedStates.Length == 0)
return;
for (int i = 0; i < detachedStates.Length; i++)
{
DetachedState state = detachedStates[i];
if (state == null || state.obj == null)
continue;
Transform t = state.obj.transform;
t.SetParent(null, true);
ParticleSystem[] systems = state.obj.GetComponentsInChildren<ParticleSystem>(true);
for (int j = 0; j < systems.Length; j++)
{
ParticleSystem ps = systems[j];
if (ps == null)
continue;
ps.Stop(true, ParticleSystemStopBehavior.StopEmitting);
}
if (!notDestroy)
Destroy(state.obj, detachedLifeTime);
}
}
}
}