fbpx

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();
    }

}