Author Topic: Improving enemy vision  (Read 546 times)

Galavant Garde

  • Full Member
  • ***
  • Posts: 165
  • Cayelan Mendoza
    • View Profile
    • Galavant Garde - Dark Electro Disco Pop
    • Email
Improving enemy vision
« on: February 11, 2018, 04:58:39 AM »
Oh hey guys, I've been working a lot on trying to improve my enemy's vision.  I've made a pretty streamlined vision routine that sequentially checks player distance, player angle, and the brightness of the player model before triggering a sight test, and this routine is called whenever the bot steps on a node.  Also if the player is 'close' according to the Watch event, the routine loops every second using a timer increasing the frequency of checks.  It works reasonably well, but I don't like it...it feels sloppy.

The main issue with this approach is that it's continually checking for the player whenever close/touching nodes, but because these checks are occurring concurrently with other routines like movement and combat, function chains are getting interrupted.  This does stuff like bots not switching off their flashlights when they're supposed to, or kneeling to take a shot, and while in the middle of that animation starting a node run so it looks like they're sliding around on their knees or moonwalking etc.

The other issue is of course the slow refresh rate of checks means you can sometimes run past an enemy in plain sight but they don't spot you...which is kinda dumb.

So my idea was (this is where I'd love your input) instead of my bots trying to do everything at once, getting the game script to do most of the work.  So for example:

- The game script will continually refresh the brightness of the player model
- The game script has a function that can be called adding or removing bot IDs to/from an array
- The game script calls ALL bots on that ID array whenever the player model brightness indicates the player isn't in the dark
- Bots only add their name to that ID array when their Watch event indicates the player is close within a restricted angle
- As soon as the player steps outside of the bot's Watch range/angle, the bot removes their ID from the game script's callback array

The idea of this is, having only one script refreshing the player brightness is theoretically more efficient than having every bot doing it simultaneously.  It should also mean I don't have to do stuff like looping a bot's vision routine or triggering it when touching nodes (which is where I'm getting broken chains/weird behaviour from time to time).  It could also improve bot response times so theoretically you can't just run past them in the open.  It also allows me to play some sort of intense global sound effect whenever the player is out in the open, helping the player know if they're in danger or not.

Has anyone tried a system like this before?  Any tips or pitfalls you can think of?

Galavant Garde

  • Full Member
  • ***
  • Posts: 165
  • Cayelan Mendoza
    • View Profile
    • Galavant Garde - Dark Electro Disco Pop
    • Email
Re: Improving enemy vision
« Reply #1 on: February 11, 2018, 07:55:53 AM »
Update:

My game script does this:

Code: [Select]
function botRollCall(game,id)
{
    botRoll.push(id);   // adds ID of any bots calling this function to the checkpoint roll call. Note is only called after spawn event
}

function playerWatch(game)
{
    playerPos=map.object.getPosition(0);
    brightness=game.event.callPlayer('lightLevel',null);    // player script returns bone brightness
    if (brightness>0.3) inTheLight=true;
    else inTheLight=false;

    for (i=0; i<botRoll.length; i++) {
        distance=map.object.getDistance(botRoll[i],playerPos);
        if (distance<15000) withinRange=true;
        else withinRange=false;
        inFOV=map.object.isFacingId(botRoll[i],0,120);
        game.event.callObjectById(botRoll[i],'playerProximity',withinRange,inFOV,inTheLight);
    }
    game.event.chain(5,'playerWatch');    // loops chain every 5 ticks
}

My bots do this:

Code: [Select]
function spawn(obj)
{
    obj.event.callGame('botRollCall',obj.setting.id);    // sends ID of bot to the game script
}

function playerProximity(obj,inRange,inFOV,inTheLight)
{
    if (inRange) {
        if (inFOV) {
            if (inTheLight) {
                if (obj.sight.testPlayer()) enterCombat(obj);    // only perform sight test if game script calls saying player is in range, in FOV and in light
            }
        }
    }
}

So far so good actually!  The only bit that isn't totally reliable is the map.object.isFacingId call - it sometimes says the player is in the FOV when it isn't within 120, and I'm not sure how the slop is calculated.  So I think I may have to make my own routine for verifying if the player is in the FOV

What I can then do is instead of triggering the combat routine as soon as the sight test passes, I can make a variable called something like 'spottedPlayer' which other functions rely on to decide if to carry on with what they were doing, or stop and enter combat. For example, if a bot is their way to get help or trigger an alarm, I wouldn't want the sight test to interrupt them