Timer within a loop

Hello! Your projects are continuing and looking amazing. I’ll put mine up when I feel brave enough, and get closer to completion.

My problem with code is that I want to have a timer within a loop. I just happen to have chosen a do until loop. (Be nice if do until had two options: do until(timeUp || bIDshown) but it isn’t going to happen.). I’ve tried timers but as I thought initially the timers will just keep resetting in the loop… I’ve set them short but they don’t seem to trigger. ie: setTimer(1). Also: setTimer(1,false,‘SetTimerElsewhereInsideAFunction’);



        do
        {
            GolikeBuggery(); //speed 340, player (default 320)
            MoveToward(KFZp, Target);
            PlaySingleSirenSound();
            Sleep(0.1);
        }until(KFZp.bIDShown);


(That code works fine except online where I get “Accessed None KFZp” sometimes online stuff is often inconsistent or I just don’t get the logic XD- I’ll fix all that as the code proceeds.)

Hope you can help me out. I’m still learning so yeah I’m fuzzy on what’s exactly it going on. A timer within a loop…

not sure what KFXp is. It sounds as if you have not replicated it, so online it wont work until it is replicated to a client or all clients, depending on what your after.

these pages will help you with the replicating of code for online use.

https://api.unrealengine.com/udk/Three/ReplicationHome.html

https://api.unrealengine.com/udk/Three/ReplicationRelevancy.html

https://api.unrealengine.com/udk/Three/ReplicationInfos.html

The code you typed above could work, if it’s state code and not inside a function somewhere. I wouldn’t put a do loop inside state code, but maybe that’s just me.

So I think there are two topics to grasp here:

Delays and timing in a state machine.
Delays and timing everywhere else.

For a state machine (UDK | UnrealScriptStates) I would do something like this:



var bool ThingHappened

state WaitingForSomethingToHappen
{
    Begin:
        if(ThingHappened)
        {
            GotoState("DoingSomethingElseNow");
        }
        else
        {
            sleep(0.5);
            goto 'Begin';
        }
}


Everywhere else, I would do it like this:



var bool ThingHappened

event PostBeginPlay()
{
    CheckIfThingHappened();
}

function CheckIfThingHappened()
{
    if(ThingHappened)
    {
        DoStuff();
    }
    else
    {
        SetTimer(0.5, 'CheckIfThingHappened')
    }
}


Thanks, **Nathaniel3W and gamepainters. **

Heyya! I am grateful for your replies.

Using Nathaniel3W’s approach there are no more KFZp Accessed None’s when online. But why, I don’t know. I’ll be facing the same problem later, gamepainter, but I hadn’t thought of online replication vs offline in that way thanks for that!

Nathaniel3W, I had tunnel vision in my approach and absolutely your state suggestion works, thank you!

But, I still don’t know where to correctly place the timer - which is due to me not explaining myself properly in the first place.

Sorry, here goes again: The bot has asked the player for ID, and bot’s siren is going.

What I intend:
First option: If the player presents ID, the bot goes away.
Second: if player doesn’t show ID, the bot attacks.
Third, (but actually overriding factor): the bot wait for ID is timed, ie: if no ID shown by the player after a specific time, the bot attacks the player.

So currently in the (hopeful) code below the bot waits 5.0 to be presented with ID before attacking. “Hopeful code” well, this is what happens: All is good if the player shows ID within 5.0. If ID not shown the bot keeps chasing… forever, except if ID is shown. But, even if the player shows ID after 5.0 (as intended, the bot accepts it walks away), but what happens is: 5.0 after that - after bot and player separate - the player is shot. (fyi with a melee gun at a distance way beyond its range).

Well, what can I say, that’s what the amended code below instructs the bot to do. The problem here is with me the coder.
I’ve been trying different things, but the problem remains where to put the timer.

I’m confusing myself separating in my mind loop from timer. I know it’s easy but I can’t see it!!



begin:
    GolikeBuggery(); //bot speed 340 so that it chases player. Player default speed = 320.
    MoveToward(KFZp, Target);  //KFZp = playerPawn
    PlaySingleSirenSound();
    if(KFZp.bIDShown)
    {
        KFZShowsID();  // Player shows bot ID, so all is fine, bot moves on 
    }
    else if(!KFZp.bIDShown)
    {
        sleep(0.1);  // low sleep number so the bot doesn't appear visibly halting during MoveToward actions.
        setTimer(5.0,false,'KFZNoShowID');  // bot attacks player if ID not shown after 5.0, .
        goto 'Begin';
        }
}


As you discovered, the code you wrote will not do what you expect. There are several problems with it. Probably the best way to think about it is to read through it like a list of instructions. Your instructions tell the bot to do this:

Increase speed.
Move toward the player.
Play the siren sound.
Check to see if the player has ID. (The function here should tell the bot to go to a different state.)
If no ID, sleep for 0.1 seconds, then set a 5 second timer to attack the player.

Then you do it all again. So you’re going to be playing the siren sound 0.1 seconds apart, which will probably sound like an annoying constant tone. And you’ll keep setting the 5 second timer every 0.1 seconds, so the bot never attacks.

What I think you probably want to do is this:

Increase speed.
Move toward player.
Play siren sound 2x per second (or something like that)
When you’ve reached the player, begin 5 second countdown.
If player has presented ID, stop the countdown, stop playing the siren sound, and return to whatever the bot was doing before.
If the countdown completes, attack the player

I would do that with 3 states:

Sitting around doing nothing, the default state
Waiting for player to present ID
Attacking

The code would look like this:



var float CountdownTimeRemaining;

auto state Waiting
{
    Begin:
    // Set speed back to normal
    // Start doing whatever bots do when they're not on alert
    CountdownTimeRemaining = 5;
}

state Countdown
{
    event Tick(float DeltaTime)
    {
        if(KFZp.bIDShown)
        {
            GotoState('Waiting');
        }
        else
        {
            CountdownTimeRemaining -= DeltaTime;
            if(CountdownTimeRemaining <= 0)
            {
                GotoState('Attacking');
            }
        }
    }
    Begin:
    // Increase speed
    // Move toward player
}

state Attacking
{
    // Code to attack the player
}

DefaultProperties
{
    CountdownTimeRemaining=5
}


In the Countdown tick event you could do pretty much the same thing as CountdownTimeRemaining, but with a different variable, to countdown the time until the next siren sound. Or … I can think of at least three ways you could do the siren sound timing (looping sound that you start/stop, start a timer that calls a function to play the sound and then set a timer to call itself…), but you can figure out what works best for you.

**Nathaniel3W **Appreciate you taking time to reply!

Ah, the tick is per second which I’ve read in some of the UDNs (now API)! With your help it’s come together in my head at last :slight_smile: (Also btw I didn’t mention, thanks for the link above!)

The setup you’ve explained gives the player 5 seconds to respond. (btw, the 0.1 siren racket was ok, because it stressed the player: siren and bot in the player’s face) But yep, as you’ve explained the time between siren sounds can now be longer.). MoveToward is difficult to place (compiler whinges) so as yet the bot’s not charging after the player. I tried an intermediate state with moveToward but the Accessed None KFZp returned resulting in the bot running off the edge of the map, as during some of my previous revisions.

But that problem and others I can fix. Main thing is the timer’s operational and I’ll perfect the code.

Thanks for the tutoring, Nathaniel3W, (and gamepainters snippet). Much appreciated!



auto state Roaming  
{
  snipped.........


     event SeePlayer(Pawn SeenPlayer)
    {
        local int DiceB;
        DiceB = Rand(21);
        KFZPawn = SeenPlayer;
        PerceptionDistance = 200;
        distanceToPlayer = VSize(SeenPlayer.Location - Pawn.Location);

            if (distanceToPlayer < perceptionDistance && DiceB <1 )
            {
            PlayRequestIDSound();
            PawnPlayLights();
            SetTimer(2.0,false,'PlaySingleSirenSound');
            CountDownTimeRemaining = 5;                 // <- timer number
            GotoState('CheckPlayerCredentials');
        }
snip...
}

simulated state CheckPlayerCredentials
{
    event Tick(float DeltaTime)
    {
        if(KFZp.bIDShown)
        {
            GotoState('KFZShowsID');  /// the KFZShowID was previously a function, but that was causing problems - all part of the 'perfecting'
        }
        else
        {
            CountdownTimeRemaining -= DeltaTime;
            if(CountdownTimeRemaining <= 0)
            {
                GotoState('KFZNoShowID');
            }
        }
    }
    Begin:
            GolikeBuggery(); //speed 340, player (default 320)
            MoveToward(KFZp, Target);
            PlaySingleSirenSound();
}