Search Unity

How to script enemy AI creature "see" player's flashlight?

Discussion in 'Game Design' started by CaptCanada, Oct 1, 2018.

  1. CaptCanada

    CaptCanada

    Joined:
    Feb 3, 2013
    Posts:
    272
    Hi all,

    I would like some advice/tips on how I could create a script so that my AI creature can "see" the player's flashlight, if it is within his field of view?

    I am using Behavior Designer and have the creature AI able to turn and chase the player when it sees him, but my game takes place at night and I would like the creature to be able to "see" the player's flashlight and go after him.

    Thanks!
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I don't know Behavior Designer, but in general you'd do a raycast from the creature's eyes to whatever you want the creature to possibly see. For a flashlight, that'd probably be the flashlight itself, and whatever point the flashlight hits in the world (which you can determine with another raycast).

    Of course this is treating the flashlight beam like a laser; a real flashlight beam is a cone, and hits an infinite number of points. But you can probably get away with testing just one point in the center, and nobody'll notice the difference. If that proves not good enough, then just test a handful of additional points — say, the left, right, top, and bottom edges of the cone. If the AI can see any of those, then react to seeing the beam.
     
    Philip-Rowlands, Ryiah and hippocoder like this.
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Or just spherecast if you're rather lazy like me.
     
  4. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,639
  5. Serinx

    Serinx

    Joined:
    Mar 31, 2014
    Posts:
    788
    You could use a dot product to determine if the creature is looking in the general direction of the flashlight.

    https://docs.unity3d.com/ScriptReference/Vector3.Dot.html

    You can fiddle with the result of the dot product to create a cone of vision. e.g. dotProduct > 0.5 would give the creature a 90 degree cone of vision.

    Are you wanting them to detect the flashlight itself, or also the light/beam coming from the flashlight?

    Raycasting might not be enough for the latter, as the beam could return false for a raycast when it's actually partially visible. You need a cone of sight rather than a line of sight.

    Another option is to add multiple "visible points" on you flashlight, raycast to each of them and if you hit the flashlight for any then the creature can see the flashlight.
     
    kdgalla likes this.
  6. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,639
    That's a good idea. I hadn't ever thought of using a dot product for this.
     
  7. Serinx

    Serinx

    Joined:
    Mar 31, 2014
    Posts:
    788
    @kdgalla Yeah I've only recently learned about them in a shader course of all things, and realised how useful it would be in game logic. E.g. knowing if somethings looking at a thing, if an attack is a backstab, if the bullet should ricochet etc.
     
  8. CaptCanada

    CaptCanada

    Joined:
    Feb 3, 2013
    Posts:
    272
    Thanks for the reply.
    Since the game will take place at night , I would like the creature to be able to see the player if the flashlight is on. I have the movement pack for BD and have a tree set up so if the creature can see the player, he chases the player. But, if the player doesn't have the flashlight on, the creature shouldn't be able to see the player.

    I guess I could write a script that checks to see if the creature can see the player and the flashlight is on, then the creature can chase the player. Sounds good??
     
    Serinx likes this.
  9. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,639
    I would go with Serinx's solution, because that could potentially give you a wide "cone of vision". Basically, get a direction vector between the enemy and the flashlight. Then calculate the dot product between that direction and the enemy's forward direction (I think you might need to normalize them first). The result should be a number between 1 and -1 depending on how "close" these two vectors are to each other. 1 means that they are pointing in the exact same direction, 0 means they are perpendicular, -1 means the are pointing in the opposite direction. So... say the dot product is >0.5 that means the enemy is "close-ish" to looking directly at the flash light. You can make that 0.5 higher or lower depending on what you want the range to be.

    Maybe, another approach would be to create a really big collider that represents that flashlight's spill and have your enemy raycast to hit that collider.

    Believe it or not, professional games usually have very coarse and imprecise collision-detection. As long as you play test it and it feels about right, it's good enough.
     
    TeagansDad and Serinx like this.
  10. Serinx

    Serinx

    Joined:
    Mar 31, 2014
    Posts:
    788
    Witness my amazing mspaint skillz!


    the black dots would just be little colliders that are children of the light beam and the enemy will raycast to each of them. If any are seen then the enemy detects the player.
    If you turn the torch off, all the black dots will also be disabled, so there will be no collision.

    It sounds like you're using visual scripting or something? I'm not sure how it works but hopefully the image will give you an idea of what I'm trying to say.

    I was thinking about the Vector3.dot and realised it's not great because it gives you the direction, but doesn't know if there is anything blocking the view, so you'd need to raycast anyway. A combination of the 2 methods might be good (but your "Can See Object" script might do something like this already)
     
    DungeonBrickStudios likes this.
  11. bart_the_13th

    bart_the_13th

    Joined:
    Jan 16, 2012
    Posts:
    498
    Well... If you're not targetting mobile (i.e. not really care about performance) you can try to add camera with some lores render_to_texture to the monster's head/eye, and detect if there's some bright pixels on the texture(ecs should probably help here)
     
  12. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,157
    This strikes me as a very inefficient method compared to anything listed here or even making a procedural mesh based on LOS S***.
     
    xVergilx likes this.
  13. DungeonBrickStudios

    DungeonBrickStudios

    Joined:
    Jun 9, 2015
    Posts:
    69
    Yup, pretty much. Now if you want to have the creature detect the actual light off the flashlight and then chase the player based on that, then a lot of the replies in the topic have some good ideas on that (really good replies too btw).

    But for something simple I'd get booleans for playerInSight and player.flashLightOn then chase only if both are true. You'd need to have the monster get access to the player script that has flashlight info in order to check it. Yeah I know this is basic info to some but it could be of help to someone who doesn't specialize in programming.
     
  14. newjerseyrunner

    newjerseyrunner

    Joined:
    Jul 20, 2017
    Posts:
    966
    Usually when you have complex geometry that you want to check collision for you have an outer bounding box then more detained calculations inside of that. You could use a regular box collider for the light frustum, then use a raycast to see if what the enemy is seeing is actually lit up by the flashlight. That way it’s not doing expensive raycast all the time.
     
  15. I'm playing around with the same idea, although I'm thinking about a Thief-like game-play where only the player cares how much light falls onto they.
    For one character it's okay, I believe, especially if you don't do this every frame (as I played around, every 5th-is frame is okay, still tight response).

    But I wouldn't implement it for many characters (enemies), it's too demanding in terms of performance.
     
  16. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,157
    Honestly I think the implementation costs (time) and the performance requirements (high) don't really justify the accuracy (super high) compared to just generating what amounts to a shadow volume, which is super well documented as far as implementation is concerned, has much lower performance requirements, and the accuracy is only marginally lower.
     
  17. Exactly, this is what I want to test. Unfortunately the shadow-volumes are prone to errors, human placement is needed so you can forget one or two (if you played the "new" Thief game, you can notice).
    The ray-cast-to-light method is a bit better, but it's far from correct, especially when the indirect light falls on the character or some body parts are in the light but the points used to shoot the raycasts are in the shadows (partially blocked from the lightsources).

    My method, if proves good enough (which I'm not sure yet), would allow me to weigh in everything, because I'm measuring the light falls on the character, no matter if it's a light directly or GI or whatever.
    Now, of course, still need some tricks, because obviously I'm shooting only one frame from one direction and lowres in order to be as efficient as possible, but I can average it out and give more weight to the lighter pixels (which means I'm less forgiving if the character is partially in the shadows)
    I'm also playing with the frequency, how many measurement should I have in a timeframe in order to be precise enough.
    It looks promising. Obviously it won't be a mobile game, but for desktops, it looks usable.
     
  18. Deleted User

    Deleted User

    Guest

    This right here is a great solution. Might I add that an efficient way of scaling this might be to only test for enemies within a certain radius 'r' of the character with the torch, since beyond that it won't matter.

    I believe you could use a closest pair of points dynamic programming solution (google it) or a Ford Fulkerson algorithm to do this efficiently too.

    [edit] I just wanted to add something, instead of using a complicated algorithm involving a ton of obtuse mathematics, you could use Unity 2018's ECS. That would make it hella scaleable.
     
    Last edited by a moderator: Oct 16, 2018