Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question I think im being dumb but want to make sure

Discussion in 'Scripting' started by WhitlockDEV, Dec 1, 2023.

  1. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    I have an enemy in my scene, and it has an enemy ai script attached to it, the enemy has 2 spheres for detection, one where the enemy will chase the player around, and one where the enemy will chase & attack the player.

    I have a separate script that handles some functionality for the game, for example when the player is in any of these detection areas, a variable "combatmode" will become true and teh player can fight back.

    The issue im having is that this works perfectly fine with one enemy, however when i instantiate multiple of these enemies, it doesnt, i know the areas of detection work because the enemies will behave separately, and shoot and chase me, however this combatmode variable isnt getting set to true. upload_2023-12-1_22-24-23.png
    upload_2023-12-1_22-24-43.png
    upload_2023-12-1_22-25-20.png
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,346
    Are all your enemies referencing your player prefab? This will be different to the actual player in your scene.
     
    Kurt-Dekker likes this.
  3. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    They all reference the player in the scene, because i have the enemies get Instantiatiated on scene load
     
  4. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,981
    OK, so the enemies set the player's combatMode variable to true when in range. Do they also set it to false when out of range. It gets set to false somehow, right? I'm wondering if the enemy not in range keeps resetting it to false.
     
  5. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,586
    Did you use Debug.Log to make sure that PlayerInSightRange and PlayerInAttackRange are set to true when you think that should be?
     
  6. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    i nknow that these get set to true because the enemy chases me around when it is true upload_2023-12-2_16-19-49.png
     
  7. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    it gets set to false on scene load in the stat manager, then to true when a player is in any of the ranges, then back to false on two conditions, if the player isnt in range, and if the enemy dies
     
  8. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,586
    So what if the player becomes out of range of one enemy but not another? What if an enemy dies and there are still other enemies? You don't want it set to false unless the player is out of range of all the enemies, not just one.
     
    halley likes this.
  9. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    each script is technically specific to THAT enemy no? atleast thats what i thought i was doing with Quaternion.identity when i instantiate the enemies on load
     
  10. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,586
    Yes, but that has nothing to do with Quaternian.identity. Quaternian.identity is just what direction the enemy's rotation. :confused:

    Let me try again. You said:
    So what does "in range" mean? Are you checking if the player is in range of any and all of the enemies? If you have a script on one enemy that checks if the player is in range of that enemy, does it check if the player is in range of other enemies too?

    What does "the enemy dies" mean? You said there was more than one enemy. Is the player suddenly out of range when any enemy dies? If you have script that sets the player out of range when the enemy dies, does it make sure that there are no other enemies right next to it?

    Edit: I'll just get to the point: I think it would make more sense if it was up to the player controller to decide whether the player should be in combat mode or not. Right now you have multiple agents trying to make that determination and it doesn't work, because I'm imagining each enemy agent is only aware of their own relationship to the player and not looking at the big picture.
     
    Last edited: Dec 2, 2023
  11. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    the in range is a gizmos.draw circle around an enemy, if the player is within this circle, the enemy will chase, and a smaller cirlce inside of that one, if the player is in the smaller circle the enemy stops moving and attacks the player. It is one script, that all the enemies have on them, each enemy has this script.

    As for the death, when an enemy dies, the player is pulled out of combat, but that doesnt matter at the moment as the player can only enter combat with one specific instance of the enemy, the original, the clones dont work
     
  12. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,586
    Oops, I added more to my post right as you were replying. See my edit.
     
  13. WhitlockDEV

    WhitlockDEV

    Joined:
    Nov 11, 2023
    Posts:
    9
    so essentially make a check on the player to see if the player is in an enemies range? Like keep using the enemies detection areas but put the detection checks in the player code instead of the enemy code?
     
  14. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,586
    I don't see why you need the enemy's range, the player just needs to check if there any enemies close enough. Maybe use OverlapSphere or something.
     
  15. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,981
    It might help to really understand how "each enemy independently controls the player's attack status" can be a problem. Suppose two enemies come near the player. Both put the player in attack mode, which is fine. But then enemy B goes out of range (or dies). Enemy B's script takes the player out of combat, even though enemy A is right there. Here I'm assuming changes are only made when the player enters or exits the range.

    If instead each enemy sets the player's attack status every frame, then the last enemy always wins -- the player is in attack status only if the last enemy is nearby. So that doesn't work either.

    There's a way to make it work. The enemies use the "only change the player when they go in/out of range" method, and the player's attack status is a counter of how many enemies. Instead of setting to true or false, add or subtract 1. 1 or more means there's someone to attack. But that's easy to break: when anything weird messes up the count it stays broken forever. Plus the player still has to decide who to attack.

    It's way easier to have the player do the player's thinking. Every so often the player checks their own area for enemies and sets itself to attack or not. It's not really expensive, since 10 enemies already means 10 checks. Adding one more for the player isn't much extra (plus the enemies are doing less work, so it may even be less work total).
     
  16. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    613
    Obviously add debug statements to test your assumptions don't rely on what you think you see. But... if you are willing to entertain a slightly different tack on solving this you really should spend a little time housecleaning. You are calling GetComponent in the Update() method. There is no way the reference can change on a per frame basis is there?

    You have two Booleans "in sight" and "in range" that aren't used directly but only to decide if ChasePlayer or AttackPlayer is appropriate. Why not a property that reflects those two conditions directly and if they are exclusive (which they are) why not tri-state logic as you might get with an enum value. So Idle, Chase and Attack (or something).

    I'm not suggesting you stop and rewrite everything but rather pointing out you can easily get trapped into solving a problem that is due to convoluted code. Simplify and then look for flaws in the logic. In reality the pattern can be written without any actual chasing/attacking going on. You create a tiny system that sets and maintains state and outputs log statements. When that works you substitute other code for the logging.