Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Options for making an area of effect

Discussion in 'Scripting' started by PaperMouseGames, Jul 2, 2019.

  1. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    Hi there, I'm still learning a lot in Unity and I've been messing around with ways to get an area of effect attack in the RPG I'm making.

    I've found a couple of things online and have been experimenting, but they mostly boil down to:

    1. Collider with the desired area using methods like OnTriggerEnter

    2. Finding all the Enemies in the scene, and then figuring out which ones are within range using vector distances, then only affecting those.

    I kinda like the second method better because I feel like it's more precise, but I don't like that I have to find every enemy in the scene. That seems like it could be a bit much if it's an ability that's constantly being used by the player, say many times in a single fight.

    So are there there any other ways? Or maybe ways of making these two methods a bit more precise?

    Any opinions on this would be really great to hear, thank you!
     
  2. chubbspet

    chubbspet

    Joined:
    Feb 18, 2010
    Posts:
    1,220
    It depends what you are going to do when you have determined the enemies within range, but almost guarenteed, the second option will be the correct and best way. If you are going to run a lot of code repeatedly, you need to decide if it is really needed to check it every frame. If not needed, you could check it in a co routine.
     
  3. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    You think the second option is good? I definitely agree about the coroutine aspect, but is it still a viable option if, say, there are 50 or even 100 Enemies in the scene and it's finding them all and checking their distance?
     
  4. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,737
    I guess you could maintain a list of enemies in range which is added to on OnTriggerEnter and removed from on OnTriggerExit.

    That way you'll instantly know at any given time which objects are within the collider area.
     
  5. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,669
    There's also a third option of using Unity Physic's immediate collision check functions, such as OverlapSphere and others.
     
    BarriaKarl likes this.
  6. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    This is an interesting option I had completely forgotten about, thanks for this!

    Also, are there any opinions on how to do this for something like a Cone in front of the player? I know I could make a cone mesh and a mesh collider, but then I'm stuck using the OnTriggerEnter-like options and that's it right?

    So is there a way to detect a non spherical/box/capsule area other than using a OnTriggerEnter?
     
  7. adibichea

    adibichea

    Joined:
    Jul 15, 2015
    Posts:
    73
    An idea is to make AoE a prefab with a FX (like splash FX) with a sphere collider. When this collider hits somenthing and this somenthing is an enemy, then apply damage to that enemy. After x seconds, the AoE gameobject FX, will self destroy.
    Take care to not apply same effect to the enemy.. only if you want to do so. Like AoE damage per second.
     
  8. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,669
    For arbitrary colliders, I think Rigidbody.SweepTest should work.

    You should be able to use a mesh collider with the SweepTest that I mentioned.
    Another way to do this is to take the vector dot product between player's forward vector and the direction vector between the player and the enemy, and then check the result and see if it's close enough to 1. The trick with that is finding the exact value that corresponds with the angle that you want.
     
    PaperMouseGames likes this.
  9. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    Oh this is super helpful! I hadn't heard of SweepTest, and I hadn't thought of dot product angles, so I'll spend some time experimenting with these, thanks a million!

    Also, thanks to everyone else who contributed, It'll take me a while to see what method works best for me, but I learned a lot in this discussion and there seem to be some good options, thanks again!
     
  10. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    Update: Serious thanks to everyone who helped with this, here's what I ended up doing for now and it seems to be working in case anyone has a similar question (or more tips):

    Code (CSharp):
    1. public void UseAbility(Ability ability)
    2.     {
    3.         NPC[] npcs = FindObjectsOfType<NPC>();
    4.         npcsInRange = new List<NPC>();
    5.  
    6.         foreach (NPC npc in npcs)
    7.         {
    8.             toOther = npc.transform.position - abilityTargetingObject.transform.position;
    9.             float angle = Vector3.Angle(toOther, player.transform.forward);
    10.             Debug.Log("Angle: " + angle);
    11.             if (angle < Mathf.Abs(abilityAngle))
    12.             {
    13.                 distance = Vector3.Distance(npc.transform.position, player.transform.position);
    14.                 if (distance <= ability.Range)
    15.                 {
    16.                     npcsInRange.Add(npc);
    17.                 }              
    18.             }
    19.         }
    20. }
    So this works great as far as I can tell for a cone shapped AoE ability. I'm not showing the code for spherical/circular AoE but that's a lot easier, just gotta check the distance rather than angle and distance.

    In case anyone is wondering, I'm using the abilityTargetingObject rather than the player to get the angle because that's an object I attached to the player prefab and it's just an empty game object that hangs out slightly behind the player so the cone can reach the player's sides well rather than starting at the player origin. This makes it easier to target stuff that kind of in the "peripheral vision" of the player.

    So yeah, this works great, a big thanks to everyone who pointed me to the right resources for this, the people in these forums are seriously the most helpful!
     
  11. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,737
    I'd be inclined to have the NPC class add itself to a static list when instantiated (and remove itself from the list when destroyed).

    That way you can query that list in your foreach loop and avoid the FindObjectsOfType call, which is relatively slow.
     
  12. PaperMouseGames

    PaperMouseGames

    Joined:
    Jul 31, 2018
    Posts:
    434
    Oh, that's a great idea! I'll look into this, thanks!
     
  13. unity_46365D0A3E6277567CAD

    unity_46365D0A3E6277567CAD

    Joined:
    Mar 17, 2024
    Posts:
    1
    Instead of doing Vector3.Distance(), you could compare the square distance between the player and an enemy and the squared AoE range, which will be more performant since Vector3.Distance() does square root calculations.
     
  14. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,491
    Don't necro-post a five year old dead thread.

    The actual amount of time saved with this often-repeated micro-optimization is ridiculously small, and doesn't really add anything to the conversation these people were having about broad approaches to the problem.