Adding a particle effect from Unity Asset Store

Hello, I added an asset from the Unity Asset Store, and the asset works, except the radius area of the asset is not the same as the summoning circle as in the tutorial. The asset randomly spawns projectiles within the radius area (basically a meteorite shower). So far, I changed the name of the variable from the asset that affects the area of the radius to areaAffectRadius, the same as in the tutorial. But, I can’t figure out how to reference the variable areaAffectRadius fromthe delayClickTargeting script (scriptable object). Here are my scripts:

DelayClickTargeting

using RPG.Control;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Abilities.Targeting
{
    [CreateAssetMenu(fileName = "Delay Click Targeting", menuName = "Abilities/Targeting/Delay Click", order = 0)]
    public class DelayClickTargeting : TargetingStrategy
    {
        [SerializeField] Texture2D cursorTexture;
        [SerializeField] Vector2 cursorHotspot;
        [SerializeField] LayerMask layerMask;
        [SerializeField] float areaAffectRadius;
        [SerializeField] Transform targetingPrefab;

        Transform targetingPrefabInstance = null;

        public override void StartTargeting(AbilityData data, Action finished)
        {
            PlayerController playerController = data.GetUser().GetComponent<PlayerController>();
            playerController.StartCoroutine(Targeting(data, playerController, finished));
        }

        private IEnumerator Targeting(AbilityData data, PlayerController playerController, Action finished)
        {
            playerController.enabled = false;
            if(targetingPrefabInstance == null)
            {
                targetingPrefabInstance = Instantiate(targetingPrefab);
            }
            else
            {
                targetingPrefabInstance.gameObject.SetActive(true);
            }
            targetingPrefabInstance.localScale = new Vector3(areaAffectRadius * 2, 1, areaAffectRadius * 2);
            while (!data.IsCancelled())
            {
                Cursor.SetCursor(cursorTexture, cursorHotspot, CursorMode.Auto);
                RaycastHit raycastHit;
                if (Physics.Raycast(PlayerController.GetMouseRey(), out raycastHit, 1000, layerMask))
                {
                    targetingPrefabInstance.position = raycastHit.point;

                    if (Input.GetMouseButtonDown(0))
                    {
                        //Absorb the whole mouse click
                        yield return new WaitWhile(() => Input.GetMouseButton(0));
                        data.SetTargetedPoint(raycastHit.point);
                        data.SetTargets(GetGameObjectsInRadius(raycastHit.point));
                        break;
                    }
                }
                yield return null;
            }
            targetingPrefabInstance.gameObject.SetActive(false);
            playerController.enabled = true;
            finished();
        }

        private IEnumerable<GameObject> GetGameObjectsInRadius(Vector3 point)
        {
            RaycastHit[] hits = Physics.SphereCastAll(point, areaAffectRadius, Vector3.up, 0);
            foreach(var hit in hits)
            {
                yield return hit.collider.gameObject;
            }            
        }
    }
}

Asset Script (SpawnCometsScript)

using RPG.Abilities.Targeting;  // I added  this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnCometsScript : MonoBehaviour {

	public DelayClickTargeting delayClickTargeting;
	public GameObject comet;
	public GameObject startPoint;
	public GameObject endPoint;
	public float delay;
	public float rateOfFire;
	//public float radius;
	public float quantity;
	public float waves;

	void Start () {
		StartCoroutine (SpawnVFX(comet, delay, rateOfFire));
	}

	IEnumerator SpawnVFX (GameObject vfx, float delay, float rateDelay){	
		for (int j = 0; j < waves; j++) { 	
			yield return new WaitForSeconds (delay);
			for (int i = 0; i < quantity; i++) {
				var startPos = startPoint.transform.position;
				if(areaAffectRadius != 0)
					startPos = new Vector3 (startPoint.transform.position.x + Random.Range (-areaAffectRadius, areaAffectRadius), startPoint.transform.position.y + Random.Range (-areaAffectRadius, areaAffectRadius), startPoint.transform.position.z + Random.Range (-areaAffectRadius, areaAffectRadius));					
				GameObject objVFX = Instantiate (vfx, startPos, Quaternion.identity) as GameObject;

				var endPos = endPoint.transform.position;
				if(areaAffectRadius != 0)
					endPos = new Vector3 (endPoint.transform.position.x + Random.Range (-areaAffectRadius, areaAffectRadius), endPoint.transform.position.y + Random.Range (-areaAffectRadius, areaAffectRadius), endPoint.transform.position.z + Random.Range (-areaAffectRadius, areaAffectRadius));
				RotateTo (objVFX, endPos);

				yield return new WaitForSeconds (rateDelay);
			}
		}
	}

	void RotateTo (GameObject obj, Vector3 destination ) {
		var direction = destination - obj.transform.position;
		var rotation = Quaternion.LookRotation (direction);
		obj.transform.localRotation = Quaternion.Lerp (obj.transform.rotation, rotation, 1);
	}

}

Thank you,
Eric

Since what you are trying to get from the DelayClickTargeting is the areaAffectRadius, you could add that field to the AbilityData. Something like

[SerializeField] float areaAffectRadius = 1;

public void SetAreaAffectRadius(float radius)
{
    areaAffectRadius = radius;
}
public float GetAreaAffectRadius()
{
   return areaAffectRadius;
}

Then include data.SetAreaAffectRadius(areaAffectRadius) in the GetMouseButtonDown(0) of the DelayedClickTargeting.Targeting().
Then you can use data.GetAreaAffectRadius. I would pass that information from your EffectStrategy to your SpawnComets script.

I want to make sure that I understand the process so that I could learn. I can’t just get the areaAffectRadius variable from DelayedClickTargeting and plug it into the SpawnCometsScript? I have to convert a variable from the SpawnCometsScript to a variable from the DelayedClickTargeting, then call that method which converts the variables into the EffectStrategy script?

Thank you,
Eric

You can set things up to read directly from the DelayedClickTargeting, but then you will have coupled the SpawnComets script with the DelayedClickTargeting script.

First I’ll show you what you need to do:
Add a Getter in DelayedClickTargeting to expose the areaAffectRadius

public float GetAreaAffectRadius()
{
    return areaEffectRadius;
}

Then you can get the areaEffectRadius in SpawnComets with

delayClickTargeting.GetAreaAffectRadius();

Now here’s the problem with that. Rather than passing the data from one Strategy to another through the AbilityData class that was quite literally designed for passing and storing data between strategies, you’re creating a dependency, where SpawnCometScript cannot function without using DelayedClickStrategy.

Suppose, however, that as you’re creating new and unique abilities that you want to have an ability that does splash damage around a specific target, i.e. not tied to a point on the ground, but cast against an enemy. In this case, you would need another script to handle spawning the comets because SpawnCometsScript only knows how to get the radius from the delayClickTargeting.

If you further wanted to use this effect for a spell that an enemy casts on you, you’d need yet another script to handle getting the radius from whatever targeting class you used for the enemy…

Oh I get it now, in other words by passing it through the EffectStrategy it becomes a plug and play. It could be used in different incidents or in this case in different abilities. So would I have to make the script from that asset (SpawnCometsScript) a scriptable object too? Cause I run into the problem, I can’t implement the SttartEffect from the EffectStrategy abstract class.

Thank you,
Eric

Actually, I hadn’t noticed that you didn’t make the SpawnComet an EffectStrategy.

Here is how I would have written this as an EffectStrategy:

SpawnCometEffect.cs
using System;
using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;

namespace RPG.Abilities.Effects
{
    [CreateAssetMenu(fileName = "SpawnComet", menuName = "Abilities/Effects/SpawnComet", order = 0)]
    public class SpawnCometEffect : EffectStrategy
    {
        [SerializeField] private GameObject comet;
        [SerializeField] private float startOffset;
        [SerializeField] private float delay = .25f;
        [SerializeField] private int waves = 3;
        [SerializeField] private int quantity = 5;
        
       
        public override void StartEffect(AbilityData data, Action finished)
        {
            data.StartCoroutine(SpawnComets(data));
        }

        private IEnumerator SpawnComets(AbilityData data)
        {
            for (int w = 0; w < waves; w++)
            {
                for (int q = 0; q < quantity; q++)
                {
                    float xMod = Random.Range(-data.GetAreaOfEffect(), data.GetAreaOfEffect());
                    float zMod = Random.Range(-data.GetAreaOfEffect(), data.GetAreaOfEffect());
                    Vector3 startPoint = data.GetTargetedPoint() + new Vector3(xMod, startOffset, zMod);
                    xMod = Random.Range(-data.GetAreaOfEffect(), data.GetAreaOfEffect());
                    zMod = Random.Range(-data.GetAreaOfEffect(), data.GetAreaOfEffect());
                    Vector3 endPoint = data.GetTargetedPoint() + new Vector3(xMod, 0, zMod);
                    GameObject go = Instantiate(comet, startPoint, Quaternion.identity);
                    RotateTo(go, endPoint);
                    yield return delay;
                }
                
            }
        }
        
        void RotateTo (GameObject obj, Vector3 destination ) {
            var direction = destination - obj.transform.position;
            obj.transform.rotation = Quaternion.LookRotation (direction);
        }
    }
}

I am sorry for the time of this reply, I had a flu and I couldn’t work on this. I thank you, the code works but there is another circle that runs the same time as the ability is casted. You will see in the video of the spell casting circle.. This circle is not the same radius as the AoE. My thought process to fix this:
Step 1: Make that circle a prefab.

Step 2: In the SpawnCometEffect script create a method to implement the circle prefab that was created in step 1.

If there is another way, please inform me.
Thank you,
Eric

It looks like that’s a leftover part of the particle effect. I bet one of those three circle particle systems under the Circle Ground is just hanging on too long. Editing the duration or in the particle’s emission section may help with that. Or a simple script attached to the whole prefab to delete the gameobject after x number of seconds.

Privacy & Terms