Search Unity

Designing for a chaining projectile (2D)

Discussion in 'Scripting' started by OverthinkingThis, Sep 15, 2021.

  1. OverthinkingThis

    OverthinkingThis

    Joined:
    Sep 4, 2020
    Posts:
    5
    Hey all,

    Still a bit new to the Unity scene, but got some programming background.

    My current short-term goal is to produce a script interaction that allows X number of chains on a projectile, naturally decrementing each time it hits an enemy.

    As of right now my strategy is using a OnTriggerEnter2D function on the projectile itself (passing X as number of chains on a constructor). So when the projectile collides with an object tagged as 'Enemy' (later possibly 'Terrain' and such) it will trigger logic to decrement the chain count and find+attack the nearest enemy, repeating the process.

    ala
    Code (CSharp):
    1. void OnTriggerEnter2D (Collider2D col) {
    2.  
    3.         if (col.tag == "Enemy"){
    4.           EnemyHealth Healthinter = col.GetComponent<EnemyHealth>();
    5.           //This check can be used later to differ behaviours between enemies/terrain/other
    6.           if (Healthinter != null) {
    7.             killed = Healthinter.damageReceived(damage);
    8.           }
    9.         }
    10.         chain--;
    11.         // logic for finding nearest enemy
    12.     }
    This code does what I need it to so far, but here's where my design indecision is coming into play.

    * Would it be better to send the current projectile with a decremented count? Or maybe destroy the current projectile after creating a new projectile?
    * Would it be better to use a global 'FindObjectWithTag(Enemy)' or is there a better way to track enemy proximity to a specific projectile object? (Maybe secondary OnTriggerStay with a set range?)
    * Is OnTriggerEnter the right tool for this, or is there some other more advanced strategy that's better for performance and/or sanity I'm missing? Being projectiles, there will be a lot of these entities and I don't feel a col.GetComponent<enemyHealth>() check *per projectile* scales well, but I could be wrong.

    I can't shake the feeling that there's some significantly easier way to do this or at the very least to do the second half of this and I am confident this isn't a rare scenario for many games (chain lightning and the like).

    Apologies if this is a common question.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,674
    What exactly do you mean by "chains?" Do you mean how many times this bullet can hit enemies during its lifetime? If so then I suppose your approach would be just fine... but a little odd because the bullet will continue THROUGH the entire trigger zone doing nothing else, since it would only impact at the "Enter" point.
     
  3. WhipJr

    WhipJr

    Joined:
    Aug 3, 2011
    Posts:
    125
    Destoying the curent projectile would be wasteful of the memory used to keep track of it, definitely don't do that. reuse the projectile where possible.

    What I would probably do in this instance to find the next enemy is use Physics2D.OverlapCircleAll() to get the enemies with a certain radius of the player, then select randomly from that list, set the new target as the next destination, and so-on. OnTriggerEnter would be the only proper time to use this in the way you've described. using OnTriggerStay will happen as long as the projectile is in an object so it will fire multiple times as its travelling though so that's probably not what you want.

    as for using GetComponent, its probably the only reliable way to do this.. at least that I can think of
     
  4. OverthinkingThis

    OverthinkingThis

    Joined:
    Sep 4, 2020
    Posts:
    5
    Chaining meaning when the bullet hits Enemy 1, it then gets thrown at Enemy 2, then Enemy 3, etc etc. Other synonymous mechanics might be Ricochets or similar. An easy example would be a Chain Lightning Spell (granted that'd be a ray not a projectile but same principle), when the Enemy 1 is hit the lightning needs to chain to Enemy 2 in range and then Enemy 3 and so on.

    it's a bit tricky to encompass everything needed because you need the projectile in question to:
    A) Keep track of the number of times it's chained
    B) Stop chaining when it reaches its max
    C) Exclude the target it just hit so it doesn't just hit the same enemy X times.
    D) Ideally (stretch goal) limit the chaining range and angle to avoid weird edge cases
     
  5. OverthinkingThis

    OverthinkingThis

    Joined:
    Sep 4, 2020
    Posts:
    5
    Cool, I'll give that function a look, thanks! Yeah you're probably right on the OnTriggerStay, I'm thinking it'll be mostly on getting the actual collider area of both to play and look nice.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,674
    Ah gotcha, that makes sense.

    You would want to find the nearest enemy, one that this bullet has NOT hit before, as you note above. Could just put a reference to him in a collection on the bullet and check that collection at retargeting time.

    ALSO... you might want to have the bullet die if it has travelled beyond a certain distance too, not just times hit, just in case the enemies are spread out, that one bullet might live a long time if it has a long way to go.

    Another approach might be to find ALL the enemies you plan to hit when the first hit happens, then just play them down one after the other from the found list, so if others join the group while the bullet is going, it won't hit them... or maybe you want that!