Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Check if player is seen by any enemy

Discussion in 'Scripting' started by alessiodg749, Mar 11, 2021.

  1. alessiodg749

    alessiodg749

    Joined:
    Jun 8, 2020
    Posts:
    2
    Hi, thanks in advance for reading this!

    I'm learning Unity day-by-day, and I'm working on a stealth mechanic.

    At the moment I have a player, a gamecontroller object, a guard and a camera. Guard and Camera work with a collision trigger, wich sends to gamecontroller the player position when is within the right range. The game controller has a script called LastPlayerSighting, and as I designed it, should provide to all enemies the following information:
    - position: set to a invalid value if no enemy sent a position through their colliders;
    - alert - has some enemy sent a position of the player?
    - playerInSight - is currently the player being seen by anyone?

    alert is implemented by checking if the value position is not set to resetPosition. The problem comes with playerInSight, since my check in the code shown below returns true only if the player stands still: as soon as he moves, playerInSight becomes false.

    My question is: is this the right way to implement such values? I was thinking to fix the check by checking if the player is within a circle range from LastPlayerSighting, but seems a bit too dumb to me.


    Sorry if it's explained badly, i'm a newbie. Hopefully this makes things clear, here is my code(I'm simplifying a bit the code so that only the thread related content is shown)

    GameController:
    Code (CSharp):
    1. public class LastPlayerSighting : MonoBehaviour
    2. {
    3.     private GameObject player;
    4.  
    5.     public Vector3 position = new Vector3(1000f, 1000f, 1000f);
    6.     public static Vector3 resetPosition = new Vector3(1000f, 1000f, 1000f);
    7.    
    8.  
    9.    
    10.     public float resetCautionTime = 10f;
    11.     public float cautionTime;
    12.  
    13.     public bool alert = false;
    14.     public bool playerInSight = false;
    15.  
    16.     void Update()
    17.     {
    18.  
    19.         Debug.Log("SendAlert()");
    20.  
    21.         if (position != resetPosition)
    22.         {
    23.             alert = true;
    24.             //check if player is in sight of some enemy. bugged: sets false every time the player moves
    25.             if (position == player.transform.position)
    26.             {
    27.                 playerInSight = true;
    28.                 cautionTime = resetCautionTime;
    29.             }
    30.             else
    31.             {
    32.                 playerInSight = false;
    33.                 cautionTime -= Time.deltaTime;
    34.             }
    35.  
    36.             if (cautionTime <= 0f)
    37.             {
    38.                 cautionTime = resetCautionTime;
    39.                 position = resetPosition;
    40.             }
    41.         }
    42.         else
    43.         {
    44.             alert = false;
    45.         }
    46.     }
    47.  
    48.  
    Trigger colliders behaviour:
    Code (CSharp):
    1. public class VisionCollider : MonoBehaviour {
    2.  
    3.     private GameObject player;
    4.     private LastPlayerSighting lastPlayerSighting;
    5.  
    6. //if is visible
    7. lastPlayerSighting.position = player.transform.position;
    8.  
    9. }
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I usually expect raycasts or similar to be involved when determining if an object can be seen by another object. Cast a ray from one to the other, if it hits something else first, then not in sight. If it hits the other object within a certain distance, than is in sight. That's the fairly simple approach I usually see.
     
    SparrowGS likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,760
    Awesome, best way to do it. Welcome.

    Everything Uncle Joe says above is good... raycasting is good.

    Other implementation details are to cache where the enemy sees the player so that the enemy remembers to keep going there for a little while, even if the player disappears from sight. This can make the enemy run over to where he saw the player and then you can even make him do more stuff like say "Huh, where did he go?" and then turn around slowly looking some more.

    For things like darkness, one easy way is to encase dark areas in a collider that is flagged to NOT affect physics, but that the line-of-sight raycast will hit. Of course this can have issues if it is just a small shadow area and the player is standing in bright light on the other side. But there's a bunch of ways you can google how to simulate hiding in shadows.
     
    SparrowGS and Joe-Censored like this.
  4. DaRealXDev

    DaRealXDev

    Joined:
    Feb 5, 2021
    Posts:
    13
    I use raycasting or magnitude but I'm new to unity so idk if thats good
     
  5. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    one thing I recommend doing in a guards-looking-for-player scenario is keeping a "last seen position" variable and a timer for how long ago that was, when player is not in sight but was recently seen guards look for him around this position.

    I would use square magnitude to cull distance objects and then raycast the closer by ones.

    always use the square magnitude if you don't need the actual distance and just comparing with another squared value, it saves processing power.
     
  6. DaRealXDev

    DaRealXDev

    Joined:
    Feb 5, 2021
    Posts:
    13
    Thanks for that! I'll do some more research on square magnitude.
     
  7. alessiodg749

    alessiodg749

    Joined:
    Jun 8, 2020
    Posts:
    2
    Thanks for all the kind replies!
    The raycast is already written in the code as comment //if player is visible, as well as the lastplayersighting value (as i wrote, i simplified the code to ensure you could read just the important part).

    This will be really useful, thanks!

    What i'm trying to get is for the gamecontroller to inform every enemy if someone sees the player. One use case example:

    - player is spotted by a guard
    - guard sends the player position to gamecontroller variable position
    - gameobject sets alert state to true
    - every enemy in the scene checks if alert is set to true, so as soon as the value is flagged they run towards the enemy (guards and not cameras of course)
    - gameobject holds other two variables:
    a float called cautionTime that works as alert timer. if it goes to zero, the alert is dismissed (alert = false)
    a boolean, playerInSight, which should check if any enemy in the scene sees the player.
    - If playerInSight returns false (as the player tries to escape), the timer should slowly get down to zero.

    After i posted this thread, I kinda found a correct way to check if player is in sight:
    GameController script: LastPlayerSighting
    Code (CSharp):
    1. if (position != resetPosition)
    2.         {
    3.             alert = true;
    4.             //check if player is in sight of some enemy
    5.  
    6.             float delta = Vector3.Distance(player.transform.position, position);
    7.  
    8.             if (delta < 0.5f)
    9.             {
    10.                 playerInSight = true;
    11.                 cautionTime = resetCautionTime;
    12.             }
    13.             else
    14.             {
    15.                 playerInSight = false;
    16.                 cautionTime -= Time.deltaTime;
    17.             }
    18.  
    19.             if (cautionTime <= 0f)
    20.             {
    21.                 cautionTime = resetCautionTime;
    22.                 position = resetPosition;
    23.             }
    24.         }
    25.         else
    26.         {
    27.             alert = false;
    28.         }

    Hopefully this made things more clear[/QUOTE]