using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.MuseAssets.Shared;
using UnityEngine;
using UnityEngine.Serialization;
namespace Shared
{
[ExecuteInEditMode]
public class AbilityFx : MonoBehaviour
{
public AbilityFxDefinition AbilityFxDefinition;
public GameObject Caster;
public List<GameObject> Targets;
GameObject _casterFx;
List<GameObject> _targetFxs = new();
List<GameObject> _casterTargetFxs= new();
List<GameObject> _impactFxs= new();
List<Coroutine> _routines = new();
public void Play()
{
StartCoroutine(PlayFxRoutine());
}
public IEnumerator PlayFxRoutine()
{
if (!string.IsNullOrWhiteSpace(AbilityFxDefinition._casterAnimation))
{
var casterAnimator = Caster.GetComponent<Animator>();
if (casterAnimator == null)
casterAnimator = Caster.GetComponentInChildren<Animator>();
if (casterAnimator != null)
casterAnimator.SetTrigger(AbilityFxDefinition._casterAnimation);
}
var casterTransform = Caster.transform.FindDeepChild(AbilityFxDefinition._casterTargetTransform);
if (casterTransform == null)
casterTransform = Caster.transform;
if (AbilityFxDefinition._casterFx != null)
{
yield return new WaitForSeconds(AbilityFxDefinition._casterFxDelay);
_casterFx = Instantiate(AbilityFxDefinition._casterFx,
casterTransform.position,
casterTransform.rotation,
casterTransform);
if (AbilityFxDefinition._parentCasterFx)
_casterFx.transform.SetParent(casterTransform);
_casterFx.SetActive(true);
}
if (AbilityFxDefinition._targetFx != null || AbilityFxDefinition._targetGroundFx != null)
{
yield return new WaitForSeconds(AbilityFxDefinition._targetFxDelay);
}
if (AbilityFxDefinition._targetGroundFx != null)
{
var target = Targets.FirstOrDefault();
if (target != null)
{
var targetGroundFx = Instantiate(
AbilityFxDefinition._targetGroundFx,
target.transform.position,
target.transform.rotation);
targetGroundFx.SetActive(true);
_targetFxs.Add(targetGroundFx);
}
}
foreach (var target in Targets)
{
if (!string.IsNullOrWhiteSpace(AbilityFxDefinition._targetAnimation))
{
var targetAnimator = target.GetComponent<Animator>();
if (targetAnimator == null)
targetAnimator = target.GetComponentInChildren<Animator>();
if (targetAnimator != null)
targetAnimator.SetTrigger(AbilityFxDefinition._targetAnimation);
}
var targetTransform = target.transform.FindDeepChild(AbilityFxDefinition._targetTargetTransform);
if (targetTransform == null)
targetTransform = target.transform;
if (AbilityFxDefinition._targetFx != null)
{
var targetFx = Instantiate(
AbilityFxDefinition._targetFx,
targetTransform.position,
targetTransform.rotation,
targetTransform); // FindFirstObjectByType<ParticlePoolManager>().Get(AbilityFxDefinition._targetFx);
targetFx.SetActive(true);
_targetFxs.Add(targetFx);
}
if (AbilityFxDefinition._casterTargetFx != null)
{
_routines.Add(StartCoroutine(
CasterToTargetFx(casterTransform, targetTransform, target)));
}
}
foreach(var routine in _routines)
yield return routine;
yield return new WaitForSeconds(AbilityFxDefinition._waitTime);
Debug.Log("Destroying fx", gameObject);
Destroy(_casterFx);
foreach(var fx in _targetFxs)
Destroy(fx);
foreach (var fx in _casterTargetFxs)
Destroy(fx);
foreach (var fx in _impactFxs)
Destroy(fx);
Destroy(gameObject);
}
IEnumerator CasterToTargetFx(Transform casterTransform, Transform targetTransform, GameObject target)
{
var casterTargetFx = Instantiate(
AbilityFxDefinition._casterTargetFx,
casterTransform.position,
casterTransform.rotation,
transform);
casterTargetFx.transform.position = casterTransform.position;
casterTargetFx.transform.rotation = casterTransform.rotation;
casterTargetFx.SetActive(true);
_casterTargetFxs.Add(casterTargetFx);
var lastDistanceToTarget = float.MaxValue;
var distanceToTarget = Vector3.Distance(
casterTargetFx.transform.position,
targetTransform.position + AbilityFxDefinition._casterTargetFxImpactOffset);
while (distanceToTarget > 0.1f && distanceToTarget <= lastDistanceToTarget)
{
lastDistanceToTarget = distanceToTarget;
var direction = ((targetTransform.position + AbilityFxDefinition._casterTargetFxImpactOffset) - casterTransform.position).normalized;
//var offsetPosition = direction * AbilityFxDefinition._casterTargetFxImpactOffset;
casterTargetFx.transform.forward = direction;
casterTargetFx.transform.Translate(
Vector3.forward * Time.deltaTime * AbilityFxDefinition._casterTargetFxSpeed,
Space.Self);
distanceToTarget =
Vector3.Distance(casterTargetFx.transform.position, targetTransform.position + AbilityFxDefinition._casterTargetFxImpactOffset);
yield return null;
Debug.Log($"Distance: {distanceToTarget}", casterTargetFx);
}
if (!string.IsNullOrWhiteSpace(AbilityFxDefinition._impactAnimation))
{
var animator = target.GetComponent<Animator>();
if (animator == null)
animator = target.GetComponentInChildren<Animator>();
if (animator != null)
animator.SetTrigger(AbilityFxDefinition._impactAnimation);
}
if (AbilityFxDefinition._casterTargetImpactFx != null)
{
var impactFx = Instantiate(
AbilityFxDefinition._casterTargetImpactFx,
targetTransform.position + AbilityFxDefinition._casterTargetFxImpactOffset,
targetTransform.rotation,
targetTransform);
impactFx.SetActive(true);
_impactFxs.Add(impactFx);
}
}
}
}
using UnityEngine;
namespace Shared
{
[CreateAssetMenu(fileName = "AbilityFx", menuName = "Game/AbilityFx")]
public class AbilityFxDefinition : ScriptableObject
{
public GameObject _casterFx;
public bool _parentCasterFx;
public GameObject _targetFx;
public GameObject _targetGroundFx;
public GameObject _casterTargetFx;
public GameObject _casterTargetImpactFx;
public string _casterTargetTransform;
public string _targetTargetTransform;
public float _targetFxDelay;
public float _casterFxDelay;
public string _casterAnimation; // turn these into enums
public string _targetAnimation;
public string _impactAnimation = "Impact";
public float _casterTargetFxSpeed = 1;
public float _waitTime = 3;
public Vector3 _casterTargetFxImpactOffset;
}
}
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Shared
{
public class AbilityFxTester : MonoBehaviour
{
public GameObject Caster;
public List<GameObject> Targets;
public AbilityFxDefinition _abilityFxDefinition;
[Button]
public void PlayFx()
{
var fx = new GameObject("AbilityFx");
var abilityFx = fx.AddComponent<AbilityFx>();
abilityFx.Caster = Caster;
abilityFx.Targets = Targets;
abilityFx.AbilityFxDefinition = _abilityFxDefinition;
abilityFx.Play();
}
}
}
using System.Collections.Generic;
using Shared;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class AbilityFxListPanel : MonoBehaviour
{
public List<AbilityFxDefinition> AllAbilities;
[SerializeField] Button _buttonPrefab;
void OnValidate()
{
AllAbilities = PrefabsManager.GetAssetsOfType<AbilityFxDefinition>();
}
void OnEnable()
{
_buttonPrefab.GetComponentInChildren<TMP_Text>().text = "Refresh";
_buttonPrefab.onClick.AddListener(RefreshButtons);
RefreshButtons();
}
void RefreshButtons()
{
AllAbilities = PrefabsManager.GetAssetsOfType<AbilityFxDefinition>();
foreach (Transform child in transform)
{
if (child == _buttonPrefab.transform)
continue;
Destroy(child.gameObject);
}
foreach (var ability in AllAbilities)
{
var button = Instantiate(_buttonPrefab, transform);
button.onClick.AddListener(() => SelectAbility(ability));
button.GetComponentInChildren<TMP_Text>().text = ability.name;
}
}
void OnDisable()
{
foreach (Transform child in transform)
Destroy(child.gameObject);
}
void SelectAbility(AbilityFxDefinition ability)
{
FindFirstObjectByType<AbilityFxTester>()._abilityFxDefinition = ability;
FindFirstObjectByType<AbilityFxTester>().PlayFx();
}
}