Recent Posts

Pages: [1] 2 3 ... 10
1
Scripting / Re: Improving enemy vision
« Last post by Galavant Garde 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
2
Scripting / Improving enemy vision
« Last post by Galavant Garde 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?
3
dim3 Versions / Re: dim3 v24 Release
« Last post by ggadwa on February 01, 2018, 04:08:48 PM »
http://www.klinksoftware.com/download/dim3Code.zip

There you go!  That's definitely the last version of it.

[>] Brian
4
dim3 Versions / Re: dim3 v24 Release
« Last post by Galavant Garde on February 01, 2018, 09:43:28 AM »
Wicked, thanks Brian!   ;D
5
dim3 Versions / Re: dim3 v24 Release
« Last post by ggadwa on February 01, 2018, 08:01:56 AM »
I never threw it up on github, so I can't be sure what that is.  Tonight when I get home I'll zip it up and put it somewhere were you can grab an archive.

[>] Brian
6
dim3 Versions / Re: dim3 v24 Release
« Last post by Galavant Garde on February 01, 2018, 07:39:36 AM »
Oh hey again, where can I get the v24 source? I went to github for the first time in years to download it, but the version on there was last committed in 2009.
7
Idle Chatter / Re: One Of Them
« Last post by Galavant Garde on January 13, 2018, 04:05:25 PM »
Little update video:

https://youtu.be/NXkaeJc0S_E

The biggest thing to look out for is actually something you can't see.  It's the unnoticeable checkpoint saving and loading with no save screen or input from the player!  Less is more, plus I'm not a fan of the dim3 save screen, and it crashes a lot too.

I've rewritten the bots' vision and movement routines from scratch plugging a bunch of logic gaps and dead ends that caused odd behaviour in the past.  This has made them a lot better at filling a small space without getting stuck on each other (see up the top of the stairs in the video)

I also rewrote the math for bot aim when standing on different levels, and when the player height decreases.

The checkpoint thing is all manually scripted - was a big learning curve for me, but let's just say I'm dreaming in 'for' loops now.  The biggest issue I found with it was packing the Y angle of objects in the save data...took ages to work out that it was often freaking out because the Y angle had too many decimal places.  The way it works is, while still playing you can reload from a checkpoint smoothly, but if you quit and come back to the game later, it'll be at the start of that level. It's a tradeoff I know, but I'm pretty happy with it.

& before you say it, I know the action icon in the middle of the screen is terrible - it's on the list. Also I won't upload any more playable demos since nobody seems to try them out - will just do videos instead I think.
8
Scripting / Re: Scripting checkpoints
« Last post by Galavant Garde on January 05, 2018, 11:45:51 AM »
Meanwhile I've written a routine into my game script that constructs a 9-digit simple save ID with each number representing a different parameter.  I used a much more basic version of this with 2 digits when I made Ronja all those years ago.  Anyway I can use this to manually reconfigure the level after loading it so it works a little more like a full game save state.  At the moment it allows me to know which map, which music, which checkpoint to move the player to, what the player's health was, whether the player is carrying a rock, the player's model animation settings (he runs differently depending on what's going on), and whether bots are alerted to the player's presence or not.

It's a bit much to try incorporate stuff like enemy locations / health / if they're dead / what they were in the middle of, but I'm sure I'll come up with ways to squeeze more data in there  :D

EDIT - I rounded this bit out.  So yes I've made a simple save ID that clumps together basic data so loading a map after quitting the engine can put the player back where he was and with the same vitals / equipment, but all that remains of the bots' previous state is their collective awareness of the player...they sadly get sent back to their starting spots (because simple save IDs can't pack enough data into them to include the x/y/z/angY details of all the bots.  What I HAVE therefore been able to do is, while you're still playing i.e. you die and respawn but you don't quit and reopen the engine, the game remembers where to put all the bots and restores them fairly faithfully to their states as of the time you hit the checkpoint.

It involves using For loops in the game script that call bots sequentially to gather important vitals/stats, and stores them in arrays inside the game script. I'm then able to run more For loops to manually return all those values to every bot when the player calls the game telling it to restore the bots' old state.  Effectively, it's an auto-save that returns things essentially back to the way they were after the player hit the checkpoint but before the player died.

And it's fast!  No visible lag whatsoever - it just seamlessly puts things back the way they were.  Here's a messy look at how it works:

Code: [Select]
// SAVE ROUTINE - in player script

// Simple save ID will effectively form an array-like string - use JS string methods to read it. The positions will mean the following:

// 0 - Map              // 0 is Yard, 1 is Road, 2 is Sewers
// 1 - Music            // 0 is Prison, 1 is Prison_beat
// 2 - Checkpoint ID    // used to allow searching for the checkpoint, which allows pinpointing its map position so the player may be placed there
// 3-5 - Health         // occupies 3 places as the player default health is 200
// 6 - Holding rock or not  // 0 - false, 1 - true
// 7 - Player move animation    // 0 - Trudge, 1 - Limp, 2 - Run, 3 - Sprint
// 8 - Global bot awareness // 0 - Low, 1 - Medium, 2 - High

// When respawning without quitting, individual bot data can be restored. If loading a simple save, only the above parameters will be applied meaning
// only general data can be used to set bots up. This means their location and movement data won't restore, and they will all have the same awareness

function constructSaveString(game,x,y,z) // note the checkpoint includes its x/y/z position when calling the game script
{
    pos0=data.get('map name');  // this is set when the map loads
    pos0=pos0.toString();   // convert to a string - this will mean all other values added at end will be strings also
    pos1=data.get('current music');  // this is set when the music starts
    pos2=data.get('checkpoint');  // this is set when the checkpoint object spawns into the map

    playerhealth=map.object.getHealth(0);
    data.add('health',playerhealth);
    playerhealth=playerhealth.toString();   // convert to string otherwise the JS slice method cannot be used

    if (playerhealth>99) {  // 3 digits
        pos3=playerhealth.slice(0,1);
        pos4=playerhealth.slice(1,2);
        pos5=playerhealth.slice(2);
        }
    else if (playerhealth>9) {  // 2 digits
        pos3=0;
        pos4=playerhealth.slice(0,1);
        pos5=playerhealth.slice(1);
        }
    else {  // 1 digit
        pos3=0;
        pos4=0;
        pos5=playerhealth;
    }

    if (data.get('holding rock')==null) pos6=0; // data container won't exist if a rock was never picked up
    else pos6=data.get('holding rock');

    pos7=data.get('move animation');  // set whenever player walk animation changes
    pos8=data.get('alert level');  // set globally by the last bot to change its alert level, default is 0

    simpleSaveString=pos0+pos1+pos2+pos3+pos4+pos5+pos6+pos7+pos8;
    map.action.setSimpleSave(simpleSaveString,map.info.title);

    data.add('respawn x',x);
    data.add('respawn y',y);
    data.add('respawn z',z);
    respawnAngle=map.object.getAngle(0);
    data.add('respawn angle',respawnAngle.y.toFixed(0));    // Y angle with no decimals rounded up

    for (i=0; i<botRoll.length; i++) {  // runs bot data capture for each ID stored on the roll array
        botX.push(game.event.callObjectById(botRoll[i],'captureX',null));
        botY.push(game.event.callObjectById(botRoll[i],'captureY',null));
        botZ.push(game.event.callObjectById(botRoll[i],'captureZ',null));
        botYangle.push(game.event.callObjectById(botRoll[i],'captureYang',null));
        botAlert.push(game.event.callObjectById(botRoll[i],'captureAwareness',null));
        botPath.push(game.event.callObjectById(botRoll[i],'capturePath',null));
        botMove.push(game.event.callObjectById(botRoll[i],'captureMovement',null));
        botHealth.push(game.event.callObjectById(botRoll[i],'captureHealth',null));
    }

    iface.console.write('auto-save complete - '+simpleSaveString);
}

All those calls to the bots look like this:

Code: [Select]
// This is in each bot script
function captureX(obj)
{
return(obj.position.x);
}

function captureY(obj)
{
return(obj.position.y);
}

function captureZ(obj)
{
return(obj.position.z);
}

function captureYang(obj)
{
return(obj.angle.y.toFixed(0)); // Y angle rounded up with no decimals
}

function captureAwareness(obj)
{
return(awareness);
}

function capturePath(obj)
{
return(pathID);
}

function captureMovement(obj)
{
return(moving);
}

function captureHealth(obj)
{
return(obj.health.current);
}

From that, when the player dies it calls:

Code: [Select]
// this is in the player script - attached to the Die event
function die(obj)
{
    hideHUD(obj);
    freezePlayer(obj);

    sound.stopMusic();
sound.playGlobalPlayer("Game Over",1);

obj.motionVector.stop();
obj.motionAngle.turnStop();

dying=true;

obj.model.animation.start('Die');
obj.event.chain(1,'playerFallOver');
}

function playerFallOver(obj)
{
obj.event.callGame('playerHasDied',null);
    headTurn=new Angle(90,90,0);
    camera.angle.turn(headTurn,2000);
    obj.status.tintView(black,1,2000,3500,500);
    obj.event.chain(25,'checkForSaveData');
}

function checkForSaveData(obj)
{
obj.setting.hidden=true;

if (data.get('health')==null) obj.event.chain(10,'resetCamera');
else obj.event.chain(10,'resumeFromCheckpoint');
}

function resumeFromCheckpoint(obj)
{
obj.event.callGame('restoreBotState',null);
camera.angle.x=0;
camera.angle.y=0;
camera.angle.z=0;
obj.event.chain(20,'raiseTheCurtain');
}

function raiseTheCurtain(obj)
{
posX=data.get('respawn x');
posY=data.get('respawn y');
posZ=data.get('respawn z');
spot=new Point(posX,posY,posZ);
ang=data.get('respawn angle');
obj.position.place(spot,ang);
obj.health.add(data.get('health'));
obj.model.animation.start('Breathing');

obj.setting.hidden=false;

if (obj.health.current<50) walkSlower(obj);
    else if (obj.health.current<100) walkNormal(obj);
    else if (obj.health.current<150) runSlower(obj);
    else runNormal(obj);

iface.bitmap.hideAll();
dying=false;
unfreezePlayer(obj);

musicID=data.get('current music');
switch (musicID) {
case 0:
sound.startMusic('Prison');
return;

case 1:
sound.startMusic('Prison_beat');
return;
}

if (checkpoint1) checkpoint1=false;
}

You'll see in that second bit, the player calls the game after dying:

Code: [Select]
// this is in the game script
function playerHasDied(game)
{
    for (i=0; i<botRoll.length; i++) game.event.callObjectById(botRoll[i],'stopAllActivity',null);
}

That cycles through every bot telling them to stop what they're doing.  After they're all done, the player calls the game asking it to do this:

Code: [Select]
// this is also in the game script
function restoreBotState(game)
{
    for (i=0; i<botRoll.length; i++) {
        if (botHealth[i]<1) iface.console.write('skipping restore of bot '+botRoll[i]+' because he is dead');
        else game.event.callObjectById(botRoll[i],'restoreState',botX[i],botY[i],botZ[i],botYangle[i],botAlert[i],botPath[i],botMove[i]);
        }
    iface.console.write('all bots restored');
}

Which checks the health the bot was saved with.  If it has no health, it won't bother restoring its old state because it's dead so hasn't changed state.  If it WASN'T dead at the time of hitting the checkpoint, it reconstructs all of the saved data and packages it up into a call to each bot script sequentially:

Code: [Select]
// this is in each bot script
function restoreState(obj,x,y,z,angY,prevAwareness,prevPathID,prevMoving)
{
obj.health.reset();
    obj.setting.contact=true;

spot=new Point(x,y,z);
obj.position.place(spot,angY);

switch (prevAwareness) {
case 0:
lowAlert(obj);
break;

case 1:
mediumAlert(obj);
break;

case 2:
highAlert(obj);
break;
}

obj.watch.start(listeningDistance);
pathID=prevPathID; // revert to previous path iD
if (flashlight) useFlashlight(obj,false);
if (prevMoving) resumeInterruptedPath(obj); // if moving, resume previous path
else if (pathID==null) spawnOntoMap(obj);
else whereToNext(obj); // if not moving, decide on a new path based on previous awareness
}

Moral of the story?  There's always a way, even for coding noobs like me
9
Scripting / Re: Scripting checkpoints
« Last post by Galavant Garde on January 05, 2018, 09:34:11 AM »
Simple saves work great; it's the entire game state saves that I'm getting stuck with.  So is the map.action.restartMapFromSave(); a command intended for simple saves then?  I assumed it must be for the full game state saves.  If it is for simple saves, would it for example reload the map while simultaneously returning the simple save ID or something like that?
10
Scripting / Re: Scripting checkpoints
« Last post by ggadwa on January 05, 2018, 09:04:23 AM »
That simple save was implemented for Scruffy and I doubt it was ever tested in any other place and it is probably buggy and not you.  I suspect (I'll have to relook over the code) that it's really works in a very "restart the entire level" type of thing, and not a save the current state.  It's probably not something very useful for more complex games.

[>] Brian
Pages: [1] 2 3 ... 10