Skip to main content

News

Topic: Error running While-Loops (Read 2508 times) previous topic - next topic

Error running While-Loops
When using While-Loops, is it suppose to freeze the game like RenderMap automatically?

Code: [Select]

function TB_Battle(ET){

BattleIsOver = false;

//Start_Cycle();

while (BattleIsOver == false){

//DrawBattle();
Side = 1 - Side;
if (Side == 0) {P_Cycle();} //<--Player's Turn Cycle
else {E_Cycle();}   //<--Enemy's Turn Cycle
}
}



I'm running this inside of a trigger, but when it's activated it just totally stops the map and all input.

There's nothing defined in the functions so I'm not understanding why it's just stopping. And it's isolated to this function, because when I remove it works.

-----

Also, should I put the battle through Render() since I'm drawing stuff, or should I just use FlipScreen()?

  • Last Edit: February 26, 2014, 12:56:43 am by Vakinox

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Error running While-Loops
Reply #1
In the Sphere community we call that "blocking code". It's code that blocks all other input from happening. It's completely normal, and a natural construct about all programming languages. In games in particular though it can be a challenge.

There is nothing wrong with your code; it's doing exactly what you wrote it to do. So why does it stop everything? Because while the loop is running only the code inside of it gets executed - and nothing else! So, how do we let other events to "simultaneously" happen? We use the more advanced features of the map engine.

But, do you really need the map engine to run in the background? The whole idea of a turn based battle system is it pauses what happens on the map. Therefore, I don't think we should delve into those advanced features but focus instead on what you can do to alleviate your problem.

Take a look at your code, at the loop. Is there a FlipScreen() present inside of it? No? Ok, now does it draw anything or calls a function that draws anything? No? So that's where your problem lies. It is simply doing nothing, so far, spinning forever doing those rote actions.

So how do we fix it? We make it do something. It's still be "blocking code" since it blocks the map engine, but that doesn't stop us from handling our own input and graphics logic. So, here's what a general-purpose game loop looks like:

Code: (javascript) [Select]

var done;
function BattleSystem() {
  done = false;
  while (!done) { // the only while loop we need
    // draw stuff
    MyRender();

    // update stuff
    MyUpdate();

    // FlipScreen
    FlipScreen();

    // Key Handling
    while (AreKeysLeft()) {
      switch(GetKey()) {
          case KEY_ESCAPE: Exit(); break;
      }
    }
  }
}

function MyUpdate() {
  /** Put your battle system update logic here **/
}
function MyRender() {
  /** Put your battle system render logic here **/
}


In fact that's similar to what the MapEngine looks like internally! So, now that we understand the basic game loop, we can draw stuff in the MyRender() function and update stuff in the MyUpdate() function... Or you can just put everything above the FlipScreen call in the game loop.

When designing your battle system it's good to know these things. ;)

Oh, and if you are wondering how something in the update script can affect something in the render script, just use global variables. Once you get good enough you can start creating managers of these things and not use the global scope. I should write a tutorial on this. ;)

Notice the game loop has the one single while loop, this is important and a unique, interesting feature of game loops. (In fact it's so unique web browsers can't even handle it easily, causing traditional game design to not be very effective on the browser). You do not want to put extra while loops in a game loop unless you are certain they terminate. Only things that run indefinitely whether it is a battle system or a map engine, must be programmed in this game-loop style. By indefinitely I mean, in a deterministic way: It's not known when all enemies die, the player kills them off at his or her own discretion or chooses to run away. This is an industry standard on desktop video games. It's really the whole trick, and once you master it the sky's the limit.

For example, I'm so far advanced I've created what's known as a game state manager. This is a high-level way of popping off and moving between "game states". Most common example: switching from the world map to a menu, or from the map to a battle system, or the battle system to a menu, and so on and so forth. Anyways you'll learn as you progress. Have fun! If you need any clarifications, ask away.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Error running While-Loops
Reply #2
Quote
"blocking code"


That makes sense, the problem though is even the stuff I'm putting inside of the While-Loop isn't working and I'm not understanding that.

I now understand that everything outside of the While-Loop is being blocked while everything inside of the loop is being processed.
However, when I do this:

Code: [Select]
 
function TB_Battle(){

BattleIsOver = false;

while (BattleIsOver == false){

QueuePersonCommand(Person[1].Name, COMMAND_FACE_NORTH, false);

}
}


It doesn't even make the character Face North, it just remains stuck in the same frame that triggered the trigger (which is South).
So everything is freezing, not just the code outside of the while-loop.

Also, I'm already running a update and render script for separate functions. (menu and movement)
Am I suppose to make other ones, or will two update or render scripts conflict with each other?

Also, doesn't FlipScreen() conflict with render script? When I place it inside the battle system, the screen turns black.
Isn't that because it's drawing on top of the screen?
I'm wanting to draw on the map engine, however I do want everything else in the map engine to be blocked... so I've gotten there halfway unknowingly.

And lemme go ahead and get this straight:
Is everything dealing with calculations and modifying values suppose to go into the update script? Or just input (e.g. keys and such)?
And is everything dealing with 'blit' or drawing stuff ontop of the map engine going to go inside of the render script? Or do I need FlipScreen() too?
  • Last Edit: February 26, 2014, 03:00:24 am by Vakinox

Re: Error running While-Loops
Reply #3
You should do anything that draws in RenderScript. You should do anything that doesn't draw in UpdateScript. You aren't forced to, but it's for best results.

You shouldn't use FlipScreen while the map engine is running, unless you specifically want to render something independent of the map engine's logic (for instance, a pause menu). This usually means you shouldn't have a FlipScreen in the Update or Render scripts. The map engine has an implicit call to FlipScreen (or so you could say) after every call to the Render script.

Code: [Select]


function TB_Battle(){

BattleIsOver = false;

while (BattleIsOver == false){

QueuePersonCommand(Person[1].Name, COMMAND_FACE_NORTH, false);

}
}


This is blocking code. How will this loop ever exit? You are queueing commands for person[1].name, over and over again.

I suspect this is more like what you want:

Code: [Select]


function TB_TendBattle(){
QueuePersonCommand(Person[1].Name, COMMAND_FACE_NORTH, false);
}

function UpdateFunction(){
/*...*/
if(BattleIsHappening){
/*...*/
TB_TendBattle();
}

}


That way you queue a command to face north ever frame, rather than just sitting in a tight, blocking loop of it.

There are probably better ways of accomplishing what queueing that command over does, too, but that's a different matter.


Also, I'm already running a update and render script for separate functions. (menu and movement)
Am I suppose to make other ones, or will two update or render scripts conflict with each other?


I'm not sure what you mean by this. Every call to SetRenderScript or SetUpdateScript gets rid of whatever it was set to previously.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Error running While-Loops
Reply #4
Vakinox I'm sorry, I don't think you understood my post; I'm not dealing with the map engine. I thought your battle system worked outside of it. When you say "isn't working" you are tricking yourself because it's all there, it's all working! You just aren't noticing it since it's looping infinitely.

Take another look at what my post is trying to accomplish. ;) If you do stuff in an infinite loop that updates the screen in any ways then you aren't "blocking" anything per se.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Error running While-Loops
Reply #5
This is blocking code. How will this loop ever exit?


To clarify, from what's been stated I understand that the While-Loop blocks everything else until what's inside the loop is executed. Is that correct?


You are queuing commands for person[1].name, over and over again.


And yet the commands aren't displaying results is the part I'm not understanding.
Shouldn't anything inside the While-Loop be executed? Or is it only when the While-Loop is ended that it executes commands?
That's what I'm not understanding. Does the While-Loop block everything placed inside itself too until ended?
Why is only this While-Loop blocking, and not any other that deals with GetKey() like this:

Code: [Select]

function Interface_Update() //<--grabs input
{
while (AreKeysLeft()) {
if (GetKey() == KEY_SPACE) {      //<--Space Key acts as the Select Button
select += select_direct;
if (select == 1) select_direct *= -1;
if (select == 4) select_direct *= -1;
return select;
}
  }
}


- - - - - -

Every call to SetRenderScript or SetUpdateScript gets rid of whatever it was set to previously.


So when I place another separate SetUpdateScript or SetRenderScript (2nd), it stops executing the previous Update and Render scripts (1st) set before it?
Say there's two different SetUpdateScript, does one block or overwrite the other? That's what I'm meaning to say.

- - - - - -

Quote
If you do stuff in an infinite loop that updates the screen in any ways then you aren't "blocking" anything per se.


So it is just never getting executed?


  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Error running While-Loops
Reply #6
Wow, you really don't understand loops, do you?

Look.
Code: (javascript) [Select]

while (true) {
    QueuePersonCommand(...);
}


The above is doing work. It'll be queuing forever! It is executing the code. There is nothing wrong. It's just doing it forever.

Look.
Code: (javascript) [Select]

function Interface_Update() //<--grabs input
{
while (AreKeysLeft()) {
if (GetKey() == KEY_SPACE) {      //<--Space Key acts as the Select Button
select += select_direct;
if (select == 1) select_direct *= -1;
if (select == 4) select_direct *= -1;
return select;
}
}


AreKeysLeft() is only true when you press keys. So the while loop only executes when you press keys, allowing for other events to happen.

Look.
Code: (javascript) [Select]

while (true) {
    QueuePersonCommand(...);
    UpdateMapEngine();
    RenderMap();
    FlipScreen();
}


Will not block anything. But this doesn't stop the fact you are looping the queue forever. A loop is a loop is a loop. It doesn't execute after it is finished, no, it's executing all the time. You just won't notice it until you either break out of the loop or manually run your own update or render logic.

Here's a brain-dead simple loop.
Code: (javascript) [Select]

var i = 0;

while (true) {
    i++;
    if (i == 5) break;
}


What is the value of i when the loop breaks? 0 or 5? It's 5. So therefore things are being executed during the loop. Now, will you ever see the value increment to 5? No! Gosh, it's hard to explain but video games are not mindless loops, they have graphics to display and other such things. Let's try this out.

Code: (javascript) [Select]

var i = 0;
var font = GetSystemFont();

while (true) {
    i++;
    if (i == 5) break;
    else {
        font.drawText(0, 0, i);
        FlipScreen();
        GetKey();
    }
}


Now what happens here is that GetKey() itself is blocking code too, but now at least you can see the damn number update. This is the illusion of control. You need to show this in your own loops in order for them to look like they are doing work. Otherwise there is nothing wrong with your loops - they just seemingly go on forever, as loops should!
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Error running While-Loops
Reply #7
Look, please drop the condescension for a minute and read carefully.

I understand your examples ONE and TWO.
The problem in my code and understanding was in your example THREE.

Quote
Will not block anything, but this doesn't stop the fact you are looping the queue forever...
You just won't notice it until you either: (1) break out of the loop or (2) manually run your own update or render logic.  


That's the answer I was requiring, and what I previously could not comprehend.
It is exactly the solution to what I was asking about.

However what I'm still not understanding is why does the While-Loop have to break in order to produce results from:
QueuePersonCommand(Person[1].Name, COMMAND_FACE_NORTH, false);

Shouldn't results be produced during the loop? Why is the break necessary?


And no I possibly still don't fully understand loops to the extent that you may.
There's differences between you and me that may result in me being unable to achieve that possibility, but I'm still trying though.
So please bare with me, and thank you for taking the small significant time to share honest advice. I still appreciate it.
  • Last Edit: February 26, 2014, 06:24:45 pm by Vakinox

Re: Error running While-Loops
Reply #8
I think I understand what you are missing, Vakinox.

You'll have to excuse me if this looks a bit simplistic, or you already understand it. I just want to be sure that you know it, because it's important.

Sphere is linear. Computers are, for that matter, but they do their best to hide it.
Imagine this:

Code: [Select]


//A loop:

var condition = true;

while (condition){
  Action();
}

AnoterAction();



What will happen? As in, what are the operations that will be performed, in the entire system? It will look like this:

Code: [Select]

Action();
Action();
Action();
Action();
Action();
Action();
Action();
Action();
//...until the judgement day.


If you consider the loop, too:

Code: [Select]

//Beginning of the loop.
Action();
//End of the loop.
//Beginning of the loop.
Action();
//End of the loop.
//Beginning of the loop.
Action();
//End of the loop.
//Beginning of the loop.
Action();
//...ad infinitum.


That's all that will happen. It's linear, only one thing happens at a time. Loops aren't like setting some wheels in motion (like starting a thread or process), they are the motion itself. `AnotherAction()` will never be called, because the loop will just keep repeating, forever. If you want, say, two actions to execute, you need to call both. That's why I showed the examples I did above. The Map Engine has its own loop.

By using SetRenderScript and SetUpdateScript, you are giving it code to execute every frame. This is how you get your functions to be called in the main game loop. Unless you make your own game loop...let's not deal with that part just yet, though.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Error running While-Loops
Reply #9
Hey Vakinox, sorry if I was a little rude, it just seems like you were acting like a broken record rather than really trying to learn something about loops. I know they can be tough to work with first when you can point to two different examples of loops and one seems to work but another doesn't. I totally understand your confusion. I guess it's just that I don't know how else to explain it. I mean a loop loops infinitely, and you are using Sphere functions which do things behind the scenes.

So, let's clarify a bit more.
Code: (javascript) [Select]

while (true) {
    QueuePersonCommand(...);
}


The reason why the thing above works after the while loop breaks/ends has to do with the internal command queue. This is really only useful for queuing movement commands. It doesn't help you make a battle system (or at least one that doesn't run on the map engine). So, when the loop runs, it does what Jest just showed you:

Code: (javascript) [Select]

QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
QueuePersonCommand(...);
// ad infinitium


Now, when you break from the loop, and resume the map engine, and say you were using COMMAND_MOVE_EAST, then the sprite will start to 'chew up' the command queue and move:

Code: (text) [Select]

sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;
sphere-sprite-move: COMMAND_MOVE_EAST;


That's why it seems to do nothing while the loop is running. It is queuing things up behind-the scenes and not until the map engine resumes control will it update the sprite.

Now, outside of the map engine, say in your battle system, you are getting these 'pauses' since you made the computer think forever. But it doesn't have to.

I already showed you the game loop philosophy, all you need to do is follow it:
Code: (javascript) [Select]

var done;
function BattleSystem() {
  done = false;
  while (!done) { // the only while loop we need
    // draw stuff
    MyRender();

    // update stuff
    MyUpdate();

    // FlipScreen
    FlipScreen();

    // Key Handling
    while (AreKeysLeft()) {
      switch(GetKey()) {
          case KEY_ESCAPE: Exit(); break;
      }
    }
  }
}

function MyUpdate() {
  /** Put your battle system update logic here **/
}
function MyRender() {
  /** Put your battle system render logic here **/
}


That means while it's thinking about things like who goes next, it can still draw stuff to screen. Now, I keep saying loops go on forever - that is only true if you don't give it a stopping condition. But game loops like the map engine or a battle system don't have a definite end. Sure a battle system ends when all enemies are dead, but it can't know that ahead of time. So it must loop forever, and only break when all enemies are dead - whenever that happens - or when you run away. The problem here is that since it is looping forever, waiting for enemies to die, it'll do nothing unless you giver it the ability to update controls and draw stuff to screen. That's why the game loop philosophy I posted above is so important. You need to manually handle rendering and key presses so it doesn't 'feel' like blocking code.

The MapEngine makes it easier on you with the help of SetUpdateScript and SetRenderScript. But inside your own game loop those SetUpdate/Render functions are meaningless, since they only work on the map engine. So you must handle that stuff manually. Again take a look at the code I posted above for handling your own custom game loops and I hope you can see how remarkably easy it is to make a battle system in that way. I should really post this as a tutorial on the wiki.

I might be getting a little bit frustrated here since I feel like I'm pointing out and explaining why the sky is blue and you are just not understanding. But I digress, it was also very hard for me to figure some of this stuff out and I've just gotten so use to working with these loops it's just a second nature for me to know how it's done. It'll click for you eventually. :)

I mean when you begin to realize you can do your own stuff outside of the map engine is when you'll realize the impact of 'blocking' code and how to minimize it. I struggled a long time to understand what the heck this 'blocking code' concept was. That was until I realized all code is blocking code, it's whether or not you update input and render stuff that makes it seem not so blocking. I think a good example of blocking code is in Bruce's Scenario library for Sphere. It deliberately blocks the map engine as it waits for other events to finish.

Also sometimes it's hard to tell when your code ends or begins when working with the map engine since so much is done for you. But once you get past these little things you'll begin to realize that you can have a lot of fun designing your own systems. ;)

tl'dr: A while loop is not like a thread: it can't run thing simultaneously along with other things. I think I see what you were trying to do: use a loop to repeat an event over the map engine without blocking anything. I feel that you use the while loop as a way to 'loop' code as other stuff happens. But it doesn't work like that. SetUpdate/Render Scripts are already in a loop and will act accordingly. But a loop within those will block the map engine. Meaning, you'll have to manually handle input and graphics (which is not so bad).

Hey, take a look at your menu code. You'll notice it too has a kind of game loop structure in it like I showed you, you just never noticed it. ;)
  • Last Edit: February 26, 2014, 09:16:14 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: Error running While-Loops
Reply #10
Vakinox, to put it as succinctly as possible, the problem with your QueuePersonCommand example--and by extension your original code--is that the map rendering code (i.e. the part of the Sphere engine that draws your map and sprites) simply doesn't run while the loop is in progress.  That's why you have to call UpdateMapEngine(), RenderMap() and FlipScreen() during the loop--to keep the gears turning, so to speak.  Sphere is a game engine, not an operating system, so it won't do it for you.
miniSphere 5.0b2 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enormous man-eating pigs ~Rhuan