Fireball impact is not appearing when Instantiated

The particle effect for my fireball is not appearing even though it has been instantiated. I double checked with a Debug.Log to see if the Instantiate part was running and it was printing out in console. I also double checked if it was a visual bug with the particle effect by just putting it into the scene and playing and it seemed to be appearing then. I am not sure why the effect cannot been seen on hit when it is instantiated.

Here is my code for the Projectile:

using RPG.Attributes;
using UnityEngine;
using UnityEngine.Events;

namespace RPG.Combat
{
    public class Projectile : MonoBehaviour
    {
        [SerializeField] float speed = 1f;
        [SerializeField] float maxLifeTime = 7f;
        [SerializeField] float durationAfterImpact = 2f;
        [SerializeField] GameObject[] destroyOnHit = null;
        [SerializeField] bool isHoming = true;
        [SerializeField] GameObject hitEffect;
        [SerializeField] UnityEvent onHit; // Event triggered when Projectile hits something
        Health target = null;
        GameObject sourceOfDamage = null; // The object that fired the projectile (e.g player etc)
        float damage = 0;

        private void Start() 
        {
            transform.LookAt(GetTargetLocation()); // Ensure projectile is facing target to begin with
        }

        // Update is called once per frame
        void Update()
        {
            if (target == null) return;
            
            // If projectile is homing and target is not dead, face target each frame with updated target position
            if (isHoming && !target.IsDead()) 
            {
                transform.LookAt(GetTargetLocation());
            }      
            transform.Translate(Vector3.forward * speed * Time.deltaTime); // Moves projectile in direction it is facing
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other.GetComponent<Health>() != target) return; // If projectile does not collide with target, do nothing
            if (target.IsDead()) return; // If it collides with dead target, do nothing
            target.TakeDamage(sourceOfDamage, damage);
            
            speed = 0; // Stop the projectile from moving after colliding with target

            onHit.Invoke(); // Call onHit event

            // Instantiate onHit particle effect at position that this collides with target
            if (hitEffect != null)
            {
                Debug.Log("Hit effect for projectile has spawned");
                Instantiate(hitEffect, GetTargetLocation(), transform.rotation);
            }

            // Destroy certain GameObjects on collision defined in the destroyOnHit array
            foreach(GameObject toDestroy in destroyOnHit)
            {
                Destroy(toDestroy);
            }

            Destroy(gameObject, durationAfterImpact);
        }

        public void SetTarget(Health target, float damage, GameObject sourceOfDamage)
        {
            this.target = target;
            this.damage = damage;
            this.sourceOfDamage = sourceOfDamage; // The GameObject that launches projectile (player etc)

            Destroy(gameObject, maxLifeTime); // Destroy the projectile after maxLifeTime
        }

        private Vector3 GetTargetLocation()
        {
            CapsuleCollider targetCollider = target.GetComponent<CapsuleCollider>();           
            if (targetCollider == null) 
            {
                return target.transform.position;
            }

            /* Move the location of the projectile Z axis by half the height of the target collider.
             If this height is not added, target position is at the bottom of collider (e.g bottom of enemy)*/
            return target.transform.position + Vector3.up * targetCollider.height / 2;
        }
    }
}

Any help much appreciated.

The code looks correct…
Let’s do one more thing to see if the effect is actually spawning…

            if (hitEffect != null)
            {
                Debug.Log("Hit effect for projectile has spawned");
                GameObject effect =   Instantiate(hitEffect, GetTargetLocation(), transform.rotation);
                effect.name = "I AM THE HIT EFFECT";
            }

When you run the game, keep an eye on the heirarchy, with all of the branches collapsed so it’s just the top level item. You should see the an object I AM THE HIT EFFECT appear briefly in the heirarchy (since you’re instantiating it with the location and rotation instead of parenting the transform, it shouldn’t be childed to any other gameobject. This is what we want.

Thanks for the tip! I tried what you suggested but I can only see the Fireball Projectile in the heirachy (and its components) but don’t see the effect.name. It is also printing the “Hit effect for projectile has spawned” so does that mean its reaching that part of the code but not performing the instantiate function?

Do you have a self-destruct type script on the projectile, perhaps? (I can’t see how the Debug can run without the effect instantiating). In fact, if the effect didn’t instantiate, then changing the effect.name would cause a null reference error…

One more slight mod to the spawning code:

if (hitEffect != null)
            {
                Debug.Log("Hit effect for projectile has spawned");
                GameObject effect =   Instantiate(hitEffect, GetTargetLocation(), transform.rotation);
                effect.name = "I AM THE HIT EFFECT";
                Debug.Log("Hit effect {effect.name} spawned at {effect.transform.position}");
            }
1 Like

Yep that was the problem, I had a DestroyAfterEffect script on my fireball particle effect and instead of destroying it once IsAlive() is false, I was destroying it when IsAlive() is true.

 public class DestroyAfterEffect : MonoBehaviour
    {
        [SerializeField] GameObject targetToDestroy = null;
       
        // Update is called once per frame
        void Update()
        {
            // If the ParticleSystem has finished playing, destroy the targetToDestroy or the gameObject itself
            if (!GetComponent<ParticleSystem>().IsAlive())
            {
                if (targetToDestroy != null)
                {
                    Destroy(targetToDestroy);
                }
                else
                {
                    Destroy(gameObject);
                }
            }
        }
    }

Its working now once I changed it to this: !GetComponent().IsAlive(). Thanks for the help!

1 Like

Whew! I was running out of ideas! Glad you’ve got that up and running.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms