KonsolScript:Tutorials:EmulatingThreads

From GPWiki
Jump to: navigation, search

Simulating Threads

Like the word "buffer", I say, you google for the technical word of threading. What I understand about "threading" is like "you dance, I dance; you stop when told but I continue until told to do so". In short, you and me are independent of what we do but obeys a command of stop and go.

In modern game programming (though not necessary 3D games), threading is very important. This gives the illusion that enemies are alive and will come to slay the hero. The hero is then being controlled by a player.

The best way to demonstrate a thread is to make a simple (but not so simple) program.

This tutorial is entitled "Simulating Threads" simply because "threading" does not exist in KonsolScript. Given that condition, I will try to make a (not-so) simple program in KonsolScript to simulate threading. And honestly, I, surely, can't do any simpler than the code I made -- let's just settle for it right now. ^_^

Screenshot of the sample program.
function main() {
  Var:Number imgMan1, imgMan2, imgMan3, imgMan4, imgMan, imgManCTR, imgManX;
  Var:Number imgBat1, imgBat2, imgBat3, imgBat4, imgBat, imgBatCTR;
  Var:Boolean bManATK;
 
  Image:Load("man1.bmp", imgMan1)
  Image:Load("man2.bmp", imgMan2)
  Image:Load("man3.bmp", imgMan3)
  Image:Load("man4.bmp", imgMan4)
 
  Image:Load("bat1.bmp", imgBat1)
  Image:Load("bat2.bmp", imgBat2)
  Image:Load("bat3.bmp", imgBat3)
  Image:Load("bat4.bmp", imgBat4)
 
  imgManCTR = 1;
  imgBatCTR = 1;
 
  imgMan = imgMan1;
 
  imgManX = 50;
 
  Screen:Show()
  while (B1 == false) {
    Screen:CLS()
 
    if (imgBatCTR == 1) {
      imgBat = imgBat1;
    } else if (imgBatCTR == 2) {
      imgBat = imgBat2;
    } else if (imgBatCTR == 3) {
      imgBat = imgBat3;
    } else if (imgBatCTR == 4) {
      imgBat = imgBat4;
    } else if (imgBatCTR == 5) {
      imgBat = imgBat3;
    } else if (imgBatCTR == 6) {
      imgBat = imgBat2;
    } else if (imgBatCTR == 7) {
      imgBat = imgBat1;
      imgBatCTR -= 7;
    }
    imgBatCTR++;
 
    if (bManATK == true) {
      if (imgManCTR == 1) {
        imgMan = imgMan1;
      } else if (imgManCTR == 2) {
        imgMan = imgMan2;
      } else if (imgManCTR == 3) {
        imgMan = imgMan3;
      } else if (imgManCTR == 4) {
        imgMan = imgMan4;
      } else if (imgManCTR == 5) {
        imgMan = imgMan1;
        imgManCTR -= 5;
        bManATK = false;
      }
      imgManX++;
      imgManCTR++;
    }
 
    Image:TBlit(imgManX, 150, imgMan, screen)
    Image:TBlit(150, 50, imgBat, screen)
 
    Konsol:Delay(100)
 
    Screen:Render()
 
    if (B3 == true) {
      if (bManATK == false) { bManATK = true; }
    }
  }
}

Whew! Pretty intimidating, huh? Did I code that one? ^_^ Let's see if I can discuss the code.

I decided to make two animating objects in one scene. One will represent the usual enemy (which happens to be called Bat) and one to be controlled by the player (which we will call Man). It so happen that both objects would use 4-picture each -- this means 8 image buffer.

  Var:Number imgMan1, imgMan2, imgMan3, imgMan4, imgMan, imgManCTR, imgManX;
  Var:Number imgBat1, imgBat2, imgBat3, imgBat4, imgBat, imgBatCTR;

The variable names, imgMan1 to imgMan4 and imgBat1 to imgBat4 are the image buffers-to-be.

And since we are going to have one animation for each, this requires us to declare 2 counters, imgManCTR and imgBatCTR.

I also added imgManX which has something to do with the horizontal location -- I'll discuss more of this later.


I declared a Boolean variable which will be utilized for some flagging whether Man should attack or not.

  Var:Boolean bManATK;


Let's load those needed pictures into our image buffers. Be sure to download the needed resources if you want to try out the not-so-simple program. (Provide link.)

  Image:Load("man1.bmp", imgMan1)
  Image:Load("man2.bmp", imgMan2)
  Image:Load("man3.bmp", imgMan3)
  Image:Load("man4.bmp", imgMan4)
 
  Image:Load("bat1.bmp", imgBat1)
  Image:Load("bat2.bmp", imgBat2)
  Image:Load("bat3.bmp", imgBat3)
  Image:Load("bat4.bmp", imgBat4)


Now, let's do some initialization.

  imgManCTR = 1;
  imgBatCTR = 1;
 
  imgMan = imgMan1;
 
  imgManX = 50;

I would also like to skip in explaining what you should already know. For instance, the Screen:Show to display the "viewing screen". The need of game programming to have a "main loop" using "while (B1 == false) { /* scope... */}". And Screen:CLS in clearing the "viewing screen".


So let us proceed to the animation programming, which by now should be familiar to you already. And since Man and Bat has separate animation, So I will discuss the code separately -- I will show the code for the Bat, first.

/* the animation code for the Bat */
    if (imgBatCTR == 1) {
      imgBat = imgBat1;
    } else if (imgBatCTR == 2) {
      imgBat = imgBat2;
    } else if (imgBatCTR == 3) {
      imgBat = imgBat3;
    } else if (imgBatCTR == 4) {
      imgBat = imgBat4;
    } else if (imgBatCTR == 5) {
      imgBat = imgBat3;
    } else if (imgBatCTR == 6) {
      imgBat = imgBat2;
    } else if (imgBatCTR == 7) {
      imgBat = imgBat1;
      imgBatCTR -= 7;
    }
    imgBatCTR++;

You could notice from the code above that no Blit or TBlit is present -- it will be a little later; I'll get back to that.

One more thing that you should notice, the approach I made is the tip I gave in 3-picture Animation. (Provide link.)


/* the animation code for the Man */
      if (imgManCTR == 1) {
        imgMan = imgMan1;
      } else if (imgManCTR == 2) {
        imgMan = imgMan2;
      } else if (imgManCTR == 3) {
        imgMan = imgMan3;
      } else if (imgManCTR == 4) {
        imgMan = imgMan4;
      } else if (imgManCTR == 5) {
        imgMan = imgMan1;
        imgManCTR -= 5;
        bManATK = false;
      }
      imgManX++;
      imgManCTR++;

Let us focus on the Number variable imgManX.

I am adding a value of 1 to imgManX while it animates (or attacks). This will give the illusion of attacking forward.


If you also notice in the complete sample code above, the animation code for the Man is written inside a scope of another if command -- I am pertaining to the if written below.

/* code before the part of the animation for the Man */
    if (bManATK == true) { /* scope... */ }

What I did to the code is that, I wanted to make the Man animate only when I pressed the ENTER key.

bManATK is a Boolean variable, declared earlier, which will have a value of true or false. You could see from the code below that I set the value of bManATK to false when the whole Man animation has completed a single playing -- it is like "play then stop" and not "play then loop continuously";

/* portion of the animation code for the Man */
      } else if (imgManCTR == 5) {
        imgMan = imgMan1;
        imgManCTR -= 5;
        bManATK = false;
      }

Let us skip to where I wrote the code which will set the value of bManATK to true.

/* part of the animation code for the Man */
    if (B3 == true) {
      if (bManATK == false) { bManATK = true; }
    }

What I did is, I first checked if B3 or ENTER key is pressed. I then check if bManATK has a value of false. If both of my questions answered to yes, I then set a value of true to bManATK.


Now, let us go back to the other code we skipped.

/* code that TBlit-ed the image buffers */
    Image:TBlit(imgManX, 150, imgMan, screen)
    Image:TBlit(150, 50, imgBat, screen)

imgManX is Number variable declared for use of moving the Man horizontally while animating.

And finally, I once again used the Delay function of Konsol classs to regulate the animation speed.

/* the delaying tactics ^_^ */
    Konsol:Delay(100)


That is all there is to this very (not-so) simple sample program that demonstrates how to fake threading in KonsolScript.

Last Words

Remember that the code above was constructed to have a logic intended for whatever I intended it to be -- to simulate threading in KonsolScript.

Do not get limited to the sample above. There are more better ways to simulate much more complicated program that needs threading.

My best last word for this tutorial would be, if you had a code that looked like the one above, better start crumbling it into small pieces using function. See the sample code below.

Var:Number imgMan1, imgMan2, imgMan3, imgMan4, imgMan, imgManCTR, imgManX;
Var:Number imgBat1, imgBat2, imgBat3, imgBat4, imgBat, imgBatCTR;
Var:Boolean bManATK;
 
function main() {
  LoadImages()
  Initialize()
 
  while (B1 == false) {
    Screen:CLS()
 
    AnimateBat()
 
    if (bManATK == true) {
      AnimateMan()
      imgManX++;
    }
 
    DisplaySprites()
 
    Screen:Render()
 
    CheckUserInput()
  }
}
 
function Initialize() {
  imgManCTR = 1;
  imgBatCTR = 1;
 
  imgMan = imgMan1;
 
  imgManX = 50;
 
  Screen:Show()
}
 
function LoadImages() {
  Image:Load("man1.bmp", imgMan1)
  Image:Load("man2.bmp", imgMan2)
  Image:Load("man3.bmp", imgMan3)
  Image:Load("man4.bmp", imgMan4)
 
  Image:Load("bat1.bmp", imgBat1)
  Image:Load("bat2.bmp", imgBat2)
  Image:Load("bat3.bmp", imgBat3)
  Image:Load("bat4.bmp", imgBat4)
}
 
function AnimateBat() {
  if (imgBatCTR == 1) {
    imgBat = imgBat1;
  } else if (imgBatCTR == 2) {
    imgBat = imgBat2;
  } else if (imgBatCTR == 3) {
    imgBat = imgBat3;
  } else if (imgBatCTR == 4) {
    imgBat = imgBat4;
  } else if (imgBatCTR == 5) {
    imgBat = imgBat3;
  } else if (imgBatCTR == 6) {
    imgBat = imgBat2;
  } else if (imgBatCTR == 7) {
    imgBat = imgBat1;
    imgBatCTR -= 7;
  }
  imgBatCTR++;
}
 
function AnimateMan() {
  if (imgManCTR == 1) {
    imgMan = imgMan1;
  } else if (imgManCTR == 2) {
    imgMan = imgMan2;
  } else if (imgManCTR == 3) {
    imgMan = imgMan3;
  } else if (imgManCTR == 4) {
    imgMan = imgMan4;
  } else if (imgManCTR == 5) {
    imgMan = imgMan1;
    imgManCTR -= 5;
    bManATK = false;
  }
  imgManCTR++;
}
 
function DisplaySprites() {
  Image:TBlit(imgManX, 150, imgMan, screen)
  Image:TBlit(150, 50, imgBat, screen)
 
  Konsol:Delay(100)
}
 
function CheckUserInput() {
  if (B3 == true) {
    if (bManATK == false) { bManATK = true; }
  }
}

That code above will not just make your code look elegant, it will also make your code look neat and more manageable.


~creek23~