Background NPCs walk and wait

Started by The creature, Thu 30/07/2020 17:03:51

Previous topic - Next topic

The creature

Hi all

I'm wanting NPC characters to walk around in the background, wait for a little while and then move to a new point. I was wandering if there is Wait(#) but a wait that doesn't block. Or would I require timers? I'm just asking because I can't find anything in the manual but could just be searching for the wrong thing...

Would would be the best practice??

Laura Hunt

I did this exact thing once, but unfortunately I didn't end up using it and deleted my code :-\

I do remember that I did indeed use timers. The logic I used was to check in repeatedly_execute_always whether the character is walking or not, and if it's stopped + there is no timer already running, start a timer. You would also check if the timer has expired and in that case, move the character to the next waypoint.

Would this be enough to get you started?

Cassiebsg

Yes, that is basically it.
Define your point A, B, C, etc. They all have a x,y coord. Then get them moving to A with Noblock, and check in rep_exec if they are moving and if not if they have reached the destiny (if they haven't reached the destiny, just move them to it again, otherwise start a wait or animation, or whatever they should be doing while there.  Then send the NPC to point B, check if he's moving and if he's reached the destiny... repeat the process. :)

I did this in my game "Out of Gas".

Once I had the code up, it took me about 10 minutes to add an NPC, including creating the NPC, render it, import the sprites, add a new character with the corresponding views and adding him to the room and the walking path.  ;)

If you can't figure it out by your self, I can post the code later.
There are those who believe that life here began out there...

The creature

Thanks guys, I don't need to see any code, I was just curious if there were different ways. Timers will suffice  (nod)

Cheers

The creature

#4
Ok, I may need a little help as this isn't going well haha

Code: ags
// room script file
function room_AfterFadeIn()
{
  SetTimer(1, 200);
}


function room_RepExec()
{ 
  if (!cMan1.Moving)
  {
    if (IsTimerExpired(1) && cMan1.x==327)
    {
      cMan1.Walk(564, 372, eNoBlock, eWalkableAreas);
      cMan1.FaceDirection(eDirectionUp, eNoBlock);
      SetTimer(1, 200);
    }
    if (IsTimerExpired(1) && cMan1.x==564)
    {
      cMan1.Walk(418, 406, eNoBlock, eWalkableAreas);
      cMan1.FaceCharacter(cFemale4, eNoBlock);
      cFemale4.FaceCharacter(cMan1, eNoBlock);
      SetTimer(1, 240);
    }
    if (IsTimerExpired(1) && cMan1.x==418)
    {
      cMan1.Walk(563, 372, eNoBlock, eWalkableAreas);
      cMan1.FaceDirection(eDirectionUp, eNoBlock);
      SetTimer(1, 240);
    }
    if (IsTimerExpired(1) && cMan1.x==563) //Start Location
    {
      cMan1.Walk(327, 487, eNoBlock, eWalkableAreas);
      cMan1.FaceDirection(eDirectionDown, eNoBlock);
      SetTimer(1, 240);
    }
  }
}


That's what I have in my room script, it's probably terrible but I'm no coder....and as predicted my NPC is doing some odd things.

Laura Hunt

#5
The problem you have here is that you're triggering the walk command and then immediately facing another direction and triggering the timer, so all these commands get run right one after the other. Like I said at first, you need to check if the timer is running, and if it's not, then start it. And you need to do things like facing a certain direction on arrival, not on departure, so to say.

Unfortunately, as far as I know, AGS has no way to track if a timer is running, so we'll have to use a variable for that ("but what about IsTimerExpired?", you say. The problem with that is that IsTimerExpired only gets checked once, and then the timer is disabled, so it's not a real "is timer running" check). Put this at the top of your room script, outside any functions:

Code: ags
bool istimerruning = true;


Now set your first timer, like you did in your code:
Code: ags
function room_AfterFadeIn()
{
  SetTimer(1, 200);
}


And now try this in repeatedly_execute_always, not rep_Exec.

Code: ags
function repeatedly_execute_always()
{

  if (!Man1.Moving) {
    
    if (!istimerruning) {
      if (cMan1.x == 564) {
        cMan1.FaceDirection(eDirectionUp, eNoBlock);
        SetTimer(1, 200);
      }
      if (cMan1.x == 418) {
        cMan1.FaceCharacter(cFemale4, eNoBlock);
        cFemale4.FaceCharacter(cMan1, eNoBlock);
        SetTimer(1, 240);
      }
      if (cMan1.x == 563) {
        cMan1.FaceDirection(eDirectionUp, eNoBlock);
        SetTimer(1, 240);
      }
      if (cMan1.x == 327) {
        cMan1.FaceDirection(eDirectionDown, eNoBlock);
        SetTimer(1, 240);
      }
      istimerruning = true;
    }
    
    if (IsTimerExpired(1)){
      if (cMan1.x == 327) cMan1.Walk(564, 372, eNoBlock, eWalkableAreas);
      if (cMan1.x == 564) cMan1.Walk(418, 406, eNoBlock, eWalkableAreas);
      if (cMan1.x == 418) cMan1.Walk(563, 372, eNoBlock, eWalkableAreas);
      if (cMan1.x == 563) cMan1.Walk(327, 487, eNoBlock, eWalkableAreas);
      istimerruning = false;
    }
    
  }

}


The logic here is:
- Is the character moving? If it is, do nothing.

- If not moving, is a timer running?
- If no timer is running, then it means we just got to our destination. In this case, face towards the appropriate direction and now we start the timer and set istimerrunning to true.

- Is the timer expired?
- If it's not, do nothing.
- If it is, set istimerrunning to false and tell the character to move to the next spot.

Let me know if it works!

Khris

The coordinate check should probably use ranges, to prevent the NPC from accidentally ceasing to move.

Laura Hunt

You could also use a small region at every waypoint and check if the NPC is inside it, but why would this be necessary? What could make a NPC stop moving accidentally?

The creature

Thanks, that works great Laura. Looking at the code it makes perfect sense but it's not something I'd have figured out myself.

So thank you again 💖

Laura Hunt

Happy to know! :)

Earlier today I remembered that the way I did it in my game was not by checking the coordinates but by using four different timers, one for each waypoint. Checking which timer has expired tells you which waypoint you're at, and thus to which one you should go next (if timer 2 has expired, then you need to move to point 3, and so on). The advantage of this is that if the NPC stops before reaching a waypoint for any reason, he won't just stand there forever but he'll head to the next scheduled point once the timer has run out. You could try coding this variant yourself as an exercise if you feel like it!

Crimson Wizard

Quote from: Laura Hunt on Fri 31/07/2020 05:38:44
Unfortunately, as far as I know, AGS has no way to track if a timer is running, so we'll have to use a variable for that ("but what about IsTimerExpired?", you say. The problem with that is that IsTimerExpired only gets checked once, and then the timer is disabled, so it's not a real "is timer running" check).

I wrote alternate Timer module a while ago: https://www.adventuregamestudio.co.uk/forums/index.php?topic=55545.0

Among other things it allows to test if timer is active.

The creature

I'll check out the module CW. it might make things more manageable as I'll need a lot of timers for different NPC's going about.

X

SMF spam blocked by CleanTalk