Page 1 of 1

Pause while for() cycle

PostPosted: Wed Oct 19, 2011 11:14 am
by Leif
Hi, guys :)

Encountered an interesting thing. When PC is making decision ( for () cycle in b_shoot->Mouse Button Up ), game pauses fo 2-3 sec, even animations does not work :D
for() cycle is about 46.000 times with calculating every iteration :)

Code: Select all
for (i1=0; i1<6; i1++)
for (i2=0; i2<6; i2++)
for (i3=0; i3<6; i3++)
for (i4=0; i4<6; i4++)
for (i5=0; i5<6; i5++)
for (i6=0; i6<6; i6++)
{ ....operations.... }


So, the question is - how to split such operation into much quicker parts ? :D Is it possible?
How can one make AI with lot of calculations and do not stop animation, movement etc?

SixShot.zip
(684.29 KiB) Downloaded 98 times

Re: Pause while for() cycle

PostPosted: Wed Oct 19, 2011 3:44 pm
by EvanBlack
There are many solutions to this problem. The one I think you might be most interested in is learning to use a timer for functions.

In a game a lot of things need to happen during a couple of frames. If one thing makes the frame stop for it to complete its task, it shuts the whole game down until its finished.

The job is to limit how much a single function can do during any given frame. So you limit it and only do as much as necessary to get to the next frame. So you use a limited loop, store any variables that need to be worked on the next frame and then continue where you left off. This way everything runs smoothly.

Also, with for loops, you can unroll them, so that instead of running through the loop checking if the statement is true, you just run through it a fraction of the time and you do the same action multiple times adding the number of function calls -1 at the end.

Code: Select all
    for(i = 0; i < g_MAXOBJECTSTACK; ++i)    //g_MAXOBJECTSTACK = 25
    {
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        ++i;
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        ++i;
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        ++i;
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        ++i;
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        g_TreesOnStack = g_TreesOnStack +5;
    }

//or

    for(i = 0; i < g_MAXOBJECTSTACK;)    //g_MAXOBJECTSTACK = 25
    {
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        g_TreeStack[i] = CreateActor("tree", "tree", "(none)", "(none)", -2000, -2000, true);
        i = i +5;
        g_TreesOnStack = g_TreesOnStack +5;
    }


The reason you would use i + numberofcalls - 1 is because at the end of the loop it add 1 to i.

Re: Pause while for() cycle

PostPosted: Wed Oct 19, 2011 6:55 pm
by Leif
Well, I understood what you mean.

I created an actor, and On_Draw ->
Code: Select all
i1=AI_intermediate[0]; i2=AI_intermediate[1]; i3=AI_intermediate[2];  // get values from intermediate array
i4=AI_intermediate[3]; i5=AI_intermediate[4]; i6=AI_intermediate[5];


for (z=0; z<200;z++)  // 200 iterations per frame
{

.... operations....

i6++;                         // add steps
if (i6>5) { i6=0; i5++; }
if (i5>5) { i5=0; i4++; }
if (i4>5) { i4=0; i3++; }
if (i3>5) { i3=0; i2++; }
if (i2>5) { i2=0; i1++; }

if (i1==5) DestroyActor("Event Actor");  // end of search
}

AI_intermediate[0]=i1; i2=AI_intermediate[1]=i2; AI_intermediate[2]=i3;  // put values into intermadiate array
AI_intermediate[3]=i4; i5=AI_intermediate[4]=i5; AI_intermediate[5]=i6;


so, it works. With 200 iterations in a frame FPS is stable
Thanks ))

Re: Pause while for() cycle

PostPosted: Wed Oct 19, 2011 7:27 pm
by EvanBlack
OnDraw happens every frame, so just make sure that you want that to happen every frame rather then happen every couple of frames.

Sometime separating this stuff into every other frame will allow it to run faster and let you do more, even allowing for multiple uses of the same code.


Say you have 20 AI's looking for the player, you don't need to have them searching and moving every frame, because the player won't even recognize it if it only happened every .3 seconds instead.

If you are running a game at 24FPS then you can make calls to your AI code at frame intervals of 4. So AI code runs only 6 times every second. Which is more than enough times for any game.

If you are running your AI code OnDraw() then you are running your AI code 24 times per second. That means that the AI or player doesn't even have a chance to move before its rethinking its strategy.

Generally, an animation doesn't happen in consecutive frames. So if you are moving across the map, your player is only moving(in pixel measures) 12 to 20 times per second. If you have an animation running, say an attack animation that runs about 9 frames, it only runs 2.78 times a second. So, if you have a player move 5 (20px)spaces at a speed of 3pps then attack once, thats about 2 seconds.

So you AI would only need to react every 6th frame. So at 24FPS AI code only runs 4 times per second rather then 24 times per second.


Just a little break down of how to make sure that you aren't over doing calculations for something. It doesn't even have to just be AI, it could be something even simpler, such as updating a health bar or checking if the player or AI has been defeated.

You don't need to make some checks every frame, only the most important things should be checked every frame such as player input.

Re: Pause while for() cycle

PostPosted: Thu Oct 20, 2011 6:28 am
by Fuzzy
Leif wrote:I created an actor, and On_Draw ->
Code: Select all
i6++;                         // add steps
if (i6>5) { i6=0; i5++; }
if (i5>5) { i5=0; i4++; }
if (i4>5) { i4=0; i3++; }
if (i3>5) { i3=0; i2++; }
if (i2>5) { i2=0; i1++; }

if (i1==5) DestroyActor("Event Actor");  // end of search



I'm not sure I like seeing all those if()statements. Seeing those and six numbered i variables makes me think of one word: "clutter". Since you came up with a clever solution to your original problem, I bet you can apply that same reasoning to reduce your if() block down to just a few lines. Hint: switch/case is going to be just as long, and wrapping it in a function is going to add the speed overhead back in.

Do you accept the challenge?

Re: Pause while for() cycle

PostPosted: Thu Oct 20, 2011 7:37 am
by Leif
Fuzzy wrote:Do you accept the challenge?

Ok, i'll do it, mortal enemy of IF )))

EvanBlack wrote:So you AI would only need to react every 6th frame. So at 24FPS AI code only runs 4 times per second rather then 24 times per second

Well, correct me if i'm not right.
If i have an actor with animation speed 6 frames per second and game speed 30 fps, then:
- if I do DrawActor->ScriptEditor->...enter code...->press OK->choose "Immediate action" then OnDraw will be made 30 times per second;
- if I do DrawActor->ScriptEditor->...enter code...->press OK->choose "Wait for frame action" then OnDraw will be made 6 times per second;

Correct ?

And another one. In my case I created 1 actor and AI thinks for 7-9 secs. If I'll made two of them - will it be two times faster ?

Re: Pause while for() cycle

PostPosted: Thu Oct 20, 2011 10:00 am
by EvanBlack
Umm.. I don't use on frame animation thing. I think it just checks the animation every frame to see if it has reached the point but I don't know.. I don't understand the use of the wait for frame animation.

On Draw though happens every frame, because the sprite is drawn every frame.

Instead of using On Draw, try using a timer.

How the AI thinks is dependent of how long the loop is and how fast it can reach an answer. If you have a good sorted data structure or a good algorithm then it will be fast. But you can also shed speed for accuracy, and accuracy for cost, and cost for speed and everything other way.

Two loops performing the same function won't be twice as fast, it will be twice as long and check twice. If there was a way to add a thread to another cpu then it would be faster.

Programs run in a linear fashion. One problem at a time, one loop at a time.

The best thing to do is never run a function every frame, and never check to an if loop more than twice. If your programs is checking an if every frame and 3/4s of the time its not even running the loop, then that loop shouldn't be there. Also, if the loop is checking a value thats always true, then it shouldn't be there.

If loop + OnDraw == slow

Re: Pause while for() cycle

PostPosted: Sat Oct 22, 2011 9:41 am
by Fuzzy
Leif, I'll tell you.

GE has a built in variable called frame. It is automatically updated with the number of frames drawn since the game started. Apply the modulus operator against it with a number of frames to wait.

Code: Select all
if ((frame % 20) == 0) { DestroyActor("Event Actor"); } // every 20th frame, kill event actor


Rather than putting a bare 20 in there, I would use a global var to store the value. It makes it easier to find and change.

Here is a reference for what each built in var and function does. You can learn lots from here. http://game-editor.com/docs/script_reference.htm

Re: Pause while for() cycle

PostPosted: Mon Oct 24, 2011 6:23 am
by Leif
Thanks, i'll see.