Sprite Tutorial - Understanding Sprites

By: Kevin Picone



I N D E X:






      This tutorial is set out in the form of an FAQ. You can jump into the various topics at will, but some of examples in those topics may be building upon previous articles. So it might be an idea to read through those sections.

      Much of the source code examples in this tutorial are cut'n'paste friendly. That means, you can grab that code (inside the code blocks) and paste it into PlayBASIC and run it. Since we're talking about sprites and things like animation here, many of the examples will read their media from the within the Help Files. So you don't need to create project, save it and copy the media into it. Like you would when developing your very own game.

Be warned this is a bit of long tutorial. So grab a drink and prepare to be really... really... bored.. :)





Recommended Reading


      This tutorial covers a lot of ground, way too much to absorb in one sitting. Throughout these articles, we're going to be using Variables , Arrays, Types and LinkedLists just to name a few. So if you're not too sure about those, then now might be a good time to just give yourself a quicker refresher.




What are Sprites ?



      In 2D video games, Sprites is label that's often pinned onto the moving characters in a game. Some famous examples of sprites would be Nintendo's Mario and Sega's Sonic The Hedgehog characters. But the concept is used in virtually every 2d video game dating back from Pong through to Space Invaders, Mario, Tetris, Silk Worm, Street Fighter, R-Type etc etc all the way up to modern games like Angry Birds. I say concept, because when you dig down inside a video game, we discover there's actually a number ways of creating sprite like moving characters. There not all done the same way, which also extends to PlayBASIC programming.


      If we define a Sprite as any moving object in our video game, then we can create such effects in PlayBASIC in multiple ways. Obviously we can use the built in Sprite Command Set, but we're not limited to just using those commands, as we can produce many of the same effects use Images. Those real lateral thinkers our there, may even use Maps , Bitmap Fonts, Texture Mapping (TextureTri) or some other ingenious combination to achieve their goal. For some, this freedom is will be overwhelming at first, but it's better to allow such liberties, than be stuck with a one solution fits all approach.


      The following screen shot is from a PlayBASIC game called "Who Framed Waldo", which was written for 2008 PlayBASIC game programming competition.






      In simplest terms, this game consists of a backdrop picture and some foreground sprites. The obvious sprites would be the Player and at any items it may interact with, such as the bombs and the crabs characters towards the bottom. But they're not the only ones though, as you could also consider the score and health bars sprites too. Showing that while they may not be drawn using the same commands, we can achieve the same things in different ways.


     So what does the PlayBASIC sprite command set do ?

      In a null shell, Sprites can be thought of as an extended control layer over the image commands. The sprite system gives the user an easier interface for controlling many images as once, which we'll most like need when writing a game.

      The sprite system includes controls for handling sprites positions, render/depth ordering, collisions, movement, Rotation, Scaling, local data through to real time rendering effects like Alpha Blending and Bilinear Filtering to name a few.

      So you can think of PlayBASIC sprites as being the entity that houses the display/collision properties of a characters appearance in our game, where the Image is merely the picture information. This is nicely demonstrated by talking a look back the at the Who Frame Waldo shot above. A close look back revels there's approximately 16 different bombs and 2 crab sprites on screen in that shot. The bombs are a good example, they're clearly all using the same image, but are different sprites.

      When we create a sprite, the CreateSprite or NewSprite commands initializes the sprite properties to their defaults. It's properties are things like it's position, rotation angle, draw mode, collision mode, local data and of course it's current image. Before a sprite can be visualized to the screen, it needs to be assigned an image to render (see SpriteImage). When a sprite is drawn, PlayBASIC then uses the sprites current properties (it's X position,Y position, DrawMode, Rotation etc) to render the sprites assigned image at it's current location/rotation and drawmode. Allowing us to share the same image between many sprites.



     When should I use Sprites or just Images ?

      This is a really good question, and one we really can't possibly answer without knowing what you'll be wanting to write. Why ? - Well as we've touched on it already, one of the greats things about programming, is that there's often many solutions to any one problem. Which is fine for people who've been programming forever, but when you're new to this stuff, that can be down right confusing. One area, that some new comers get confused by, is when to use Images and when to use Sprites.

      Unfortunately, there's no single answer, so here's a few questions to help you choose.


      Q.) Do characters need using visual effects like Alpha Blending ?
           Yes.) Using Sprites would generally be the easiest option

           No.) Still possible using Images also. (see DrawAlphaImage). But these have limited draw mode support and no built in collision. So if you needed to rotate the image also, then sprites would most likely be the better solution.


      Q.) Do you need characters that rotate and scale ?
           Yes.) Using Sprites would generally be the easiest option

           No.) Still possible with only Images (see DrawRotatedImage). But these have limited draw mode support, and no built in collision.



      Q.) Do characters need to rotate/scale with collision ?
           Yes.) Using Sprites would be much easiesr option in this case.

           No.) Still possible with only Images, but you'd have limited draw modes and have to manually write the collision code yourself.



      Q.) Will you need to control the draw order of characters ?

           This is doable using both. Sprites include a built in depth value Z (See PositionSpriteZ), so you can render by depth using DrawOrderedSprites. Alternatively you could use Images and a camera to control the draw order. See CameraBasics, or even a mix of both.



      We've barely scratched the surface here, so my advise really would be to seek the help of other PlayBASIC programmers on our forums (www.PlayBASIC.com). Lay out specifically what you're trying to do, so you need to help them, help you! - The more information you provide, the more tailored responses tend to be. Some people might post code examples, others might just shares ideas on how you approach the problem at hand. But remember, people aren't going to do everything for you, that doesn't help anybody.



Top








Getting Started With Sprites


      To get started using sprites, we're first going to have to load or create an appropriate image. Sprites don't actually house the image data, rather they're a collection of display & collision properties for it's associated image, so properties for how the sprite engine should draw this image.

      This allows two or more sprites to share the same image and be rendered in completely different ways without changing the image. Also by sharing images between sprites, we dramatically decrease the amount of the memory sprites would use, if they all used unique versions of the image.

      So to get started using sprites, lets imagine we've created a new project and copied our game images into our projects folder. I'd recommended storing your media in sub folder like Images or GFX or something. It just helps keep the files tidy. Anyway, for the sake of this example i'll be using the following ship image.



      Now to load this image media we'd use the LoadImage command. The command requires the Filename and Folder of the file and the image index, this image should be placed in memory. Once the image is loaded, we can render it by telling PlayBASIC to draw this particular slot (See DrawImage).

     E.g. Loading our ship image into Image slot #1, then draws the Image at coordinate 200x, 100y on the screen

  
; Load the image into slot #1
  LoadImage "ship.bmp" , 1
  
; Draw image #1, at coordinate 200X,100Y
  DrawImage 1,200,100
  
; Show the screen and wait for the key press
  Sync
  WaitKey
  



      Hmmm, those with a keen eye might now be thinking, if I can load and render images directly, then why do I need sprites ? - Well, the short answer is that for something as simple as this, you don't need them. Meaning, as programmers we'll need to choose which method is the most appropriate for our program/game rather than just taking a one approach fits all. We could also use Bitmap Fonts / Maps or even DOT/LINE commands to draw the same image, All of which are potentially valid approaches, given the right circumstance. The trick is, identifying which approach is the best fit for what we're trying to achieve. Unfortunately, we can't answer such things for you, just give hints to point you in the right direction.

      Let's imagine our program is going to need five sprites, all using our SHIP image from above. We could render the image manually at every position we need it, but this time we're going to use sprites for the actual characters. To do this, we load the Ship image into a unused slot, then we create and set up our sprites.

      To create a sprite we have two command choices. Those being CreateSprite and NewSprite. Generally newcomers seem to find the CreateSprite approach easier to follow. Sprites, like all media in PlayBASIC are referred to by an Index. We can either manually assign indexes or have PlayBASIC return one for us.

      In the following example we're going to manually create a block of sprites with sequential indexes from 1 to 5. The code creates each sprite, sets it's image to the ship image, then randomly position it within an 800X by 600Y space, the default PlayBASIC screen size.


  
; Load the image into slot #1
  LoadImage "ship.bmp" , 1
  
; Start a FOR/NEXT loop to count from 1 through to 5,
; using the INDEX variable as it's counter
  For Index=1 To 5
     
   ; Create this sprite.  When a sprite is created it's
   ; properties are all initialized to the defaults
     CreateSprite Index
     
   ; Tell this sprite to use Image #1 as it's visual
   ;  representation
     SpriteImage Index, 1
     
   ; Give this sprite a random position on screen
     PositionSprite Index,Rnd(800),Rnd(600)
     
  Next
  
; Show the screen and wait for the key press
  Sync
  WaitKey
  



     Now if we ran this example, you might be expecting to see the five ships splodged across the screen ? - Well, here's it's output.






      So where are the sprites ? Well, in order to display any sprite you'll need to tell PlayBASIC to render them. We can do that a number of ways, the easiest is to render them as a batch via DrawAllSprites, DrawSpriteRange or DrawOrderedSprites

      Since we know we've five sprites in range, let's use the DrawSpriteRange function to render them.

  
; Load the image into slot #1
  LoadImage "ship.bmp" , 1
  
  
; Start a FOR/NEXT loop to count from 1 through to 5,
; using the INDEX variable as it's counter
  For Index=1 To 5
     
   ; Create this sprite.  When a sprite is created it's
   ; properties are all initialized to the defaults
     CreateSprite Index
     
   ; Tell this sprite to use Image #1 as it's visual
   ;  representation
     SpriteImage Index, 1
     
   ; Give this sprite a random position on screen
     PositionSprite Index, Rnd(800), Rnd(600)
     
  Next
  
; Tell PB to render sprites 1 through to 5
  DrawSpriterange 1,5
  
; Show the screen and wait for the key press
  Sync
  WaitKey
  



     And hey presto, if we ran it now, we'd get something a little more interesting.



      So we've got finally got them on screen, which is our first step. Next we'll look into moving them around the screen.

Top







Sprites In Motion - Render Loop


     So far we'd just briefly looked at creating and rendering a batch of sprites once to the screen, but we haven't actually attempted to create something that resembles motion in a video game. When we play our favorites games we're used to seeing characters/projectiles moving around screen. At the heart of all game software is a multi stage process, where the computer draws the current scene to an invisible screen. Once the drawing is complete, the program swaps the image we're seeing (on the tv/monitor) for the newly drawn image. Giving the player the illusion of motion.

     How does this relate to PlayBASIC ? - Well, PB gives us control over the rendering and swapping process. When we tell PB to render, it's actually drawing to an invisible version of the screen, often called the Back Buffer. So the screen is really made up of two separate images, the Front Buffer and Back Buffer. The Front Buffer is the completely drawn version of the screen image (The version we see), and the back buffer is the version we're currently drawing that will be shown to the player/user once it's complete. So we're never showing the player a half drawn version of the scene. If we did, it'd flicker and flash like crazy.

      To swap the Back Buffer with the Front Buffers we use SYNC command. This command swaps or copies the two images around for us. So our recently drawn back buffer, becomes the front buffer. Those with computer animation experience will no doubt know this as Double Buffering. While it might seem like an abstract concept, it's an important one we'll need to wrap our minds around in order to create programs that use moving graphics like games.

      Creating Motion in the computer program is much like how a motion pictures work. When broken down a Motion Picture ( film / movie ) is made up of nothing more than a sequence of still photos, that when shown to the viewer at speed (25 to 30 photos per second), give the appearance of motion. Computer programs rely upon the same technique, except rather than showing the user a sequence pre-made photos, the program is drawing the next frame for us. So it's showing the player the front buffer, while rendering the back buffer.


      Simple Motion


      The create the illusion of motion in a computer program, we need to draw the image (or sprite/shape ot map) in new position between syncs (Also known as frames). So each time the player sees the object in a new position on screen. For our first example, we'll use a CIRCLE (So you can cut 'n paste the example and run in) to move a single circle across the screen Left to Right.

      For this we'll need to set up a main loop (See Loops) for our program that clears the older graphics (CLS), change the circles position, draw the circle in this position, then Sync to show this new frame to the user.

      To keep track of the circles position, we'll be using Variables, if you haven't yet read about variables then now would be a good time. For those that are up to speed we'll be using an INTEGER variable called XPOS to store our moving circles current X coordinate on the screen. In order to make the circle appear to move from the left hand side of the screen to the right, we'll need to ADD (See Operators) an amount to our XPOS variable. Then whenever we draw the circle, we give it our XPOS variable for it's X coordinate. Making it will magically appear to move..

      Here's some example code for you to study. Cut'n'paste the code fragment in an empty PlayBASIC project and hit F5 to run. Hit ESC to ABORT


  
  
; Initialize our XPOS variable with the starting value of zero
  Xpos = 0
  
  
; Start of DO/LOOP
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Add 1 to whatever is in the XPOS variable
   ; This will make the circle appear to move to RIGHT
     Xpos=Xpos + 1
     
     
   ; Draw a circle at our user defined X coordinate
   ; with a fixed Y position of 100, a rAdius of 50
   ; and tell PB to FILL the circle
     Circle Xpos,100,50,true
     
     
     
   ; Show the user the newly drawn back buffer
     Sync
     
   ; End of DO/LOOP.. Program will jump back to DO statement
   ; and repeat this section of code forever (hit ESC key quit)
  Loop
  
  
  


      So if we run the program, we'll see the circle will move from the across the screen and off.



Note: Animation repeats




      Adding Image Graphics

      So our next step is going to animate some graphics. This time we'll move the ship image from the top down the screen. To do this, will mean using a variable to store the current Y coordinate. To move the down the screen we'll be adding to the y coordinate variable. Adding ? - Yeah, this is because the 0x,0y coordinate of the screen, is the top left position, so positive Y points down the screen.

      Just like our previous example with the circle, this next program will clear the screen, bump our characters position, draw the image and then call sync. It'll do all this inside an DO/LOOP structure to keep PlayBASIC executing this sequence of code forever. The main change in this version is going to be loading our image and drawing the image.

      To load the image file into PlayBASICs graphics memory we use the LoadImage command. The command expect you supply it with the Filename of the file and the image slot this image should be placed in memory. To draw the image in screen we'll use the DrawImage command to paint our image at whatever location we desire.

      Here's our image version of our motion demo. This one requires that you tell it where the "ship.bmp" file is on your computer. It'll fail to run if you don't. None the less you should be able to follow the logic. It's almost identical to the previous demo.

  
  
; Initialize our YPOS variable with the starting value of zero
; This variable we're using to hold our objects current
; y coordinate on screen
  Ypos = 0
  
  
; Load the ship.bmp image from the current folder into Image slot 1
  LoadImage "ship.bmp",1
  
  
; Start of DO/LOOP
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Add 1 to whatever is in the YPOS variable
   ; This will make the image appear to move down
   ; the screen
     Ypos=Ypos + 1
     
     
   ; Draw image #1,  100 pixels across the x axis, at our
   ; Y coordinate stored in our YPOS variable
     
     DrawImage 1100, YPos,  true
     
     
   ; Show the user the newly drawn back buffer
     Sync
     
   ; End of DO/LOOP.. Program will jump back to DO statement
   ; and repeat this section of code forever (hit ESC key quit)
  Loop
  
  






      As you can see, this code will move the ship is down the screen and off. Here the animation is massively slowed down. If you actually ran this code in PlayBASIC, all you'd see if the ship flash off the bottom of the screen. Why ? - Well, the reason is this would be the speed of your computer. Since modern computers will be able to render this simple screens at one thousand of times per second or more. Meaning the ship could have easily moved off the screen inside a second. To counter this we need to look at way to limited the number frames our program is allowed to render per second. The easier option would be the SetFPS command.


      Sprites In Motion

      Now for this next step, we're going to take a look at building a sprite scene with motion. However, unlike the previous example that loads ship image media from disc, this time we're going to a build our image media within the program. Nothing special, we'll just be making a shaded ball image by using the RenderPhongImage function. This will ensure the program can be cut'n'pasted and run.

      In this version, we're going to create 10 sprites and move them all in unison across the screen left to right. Each sprite will share the same randomly coloured Ball/Blob image that program creates. When the program starts up, it first loops through our range of ten sprites using a FOR/NEXT loop. In this loop it first creates the sprite, assigns it the ball image (using SpriteImage) then randomly position it within the screen.

      Once we've create our Blob image and sprites, we're ready to enter the main DO/LOOP of the program. The main loop is a little more complex this time, but follows the same steps as previous examples. Where it first clears the screen, moves all the sprites, draws the sprites and then Syncs. This process is then repeated over and over until the user hits the ESC key to exit.

      The main difference in this program to the others, is we're moving 10 sprites in stead of just one. To do that, we're using a FOR/NEXT loop that runs through the sequences of sprite indexes 1 to 10. For each sprite, it first moves the sprite along the X axis using the MoveSpriteX command. Now if we just keep moving the sprite right, it'll soon move off the screen and we'll no longer be able to see it. So to make the demo a more interesting, we'll check if the sprite has moved off the screen and reset it's position when it does.

      We do this, by our sprite current position along the X axis (GetSpriteX) to the width of the screen (Which is 800 pixels wide by default). If the sprites position is greater than the screen width it's off the screen. When this occurs reposition it so that it appears start from the off the left hand side of the screen. Creating a type of endless star field.

      Here's the code, with an mock up animation of what the demo looks like bellow. This example is cut'n'paste friendly also, So feel free to paste it into the PB and experiment. Don't forget, you can find lots of examples in the PlayBASIC projects under Examples->Sprites.

  
  
;*=--------------------------------------------=*
; CReate Ball Image
;*=--------------------------------------------=*
  
; Call a function to draws an blob
; like ball image.
  BallIMage=Make_Ball_Image(32)
  
  
;*=--------------------------------------------=*
; CReate our Sprites
;*=--------------------------------------------=*
  
; Lets create 10 sprites from 1 to 10.
  
  For ThisSprite=1 To 10
     
   ; Create the sprite
     CreateSprite ThisSprite
     
   ; Set the Image this sprite should use
     SpriteImage ThisSprite,  BallImage
     
   ; Position this sprite on screen randomly
     Xpos=Rnd(800)
     Ypos=Rnd(600)
     PositionSprite ThisSprite,Xpos,Ypos
     
  Next
  
  
  
;*=--------------------------------------------=*
;     MAIN LOOP
;*=--------------------------------------------=*
  
; Tell PB to limit program to a max of 60 SYNC's
; per second
  SetFPS 60
  
; Main DO/LOOP
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Use a For/Next to loop through the
   ; sprites 1 to 10
     For ThisSprite =1 To 10
        
      ; Add one to this sprite X coordinate
      ; moving the sprite right
        MoveSpriteX ThisSprite,1
        
      ; Check if the Sprite has moved off the
      ; right hand side of the screen
        If GetSpriteX(ThisSprite)>800
           
         ; Reset this sprites position
         ; setting to -32 on the x axis
         ; so it's slightly off the screen
         ; and randomly set it's y coord
         ;
           PositionSprite ThisSprite,-32,Rnd(600)
           
        EndIf
        
      ; continue the FOR loop until THISSPRITE is
      ; greater than 10
     Next
     
     
   ; Draw All the sprites to the screen
     DrawAllSprites
     
     
   ; Show the newly drawn scene to the user
     Sync
     
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
; Tell PlayBASIC To END this program
  End
  
  
;*=--------------------------------------------=*
;      >> MAKE THE SHADED BLOB/BALL IMAGE  <<
;*=--------------------------------------------=*
  
Psub Make_Ball_Image(Size)
  
; Create a image using the Ball and size variables
  Ball=NewImage(Size,Size,2)
  
  Size=Size/2
  
  MAx#=255
  FallOff#=Max#/(Size)
  Colour=RndRGB()
  RenderPhongImage  Ball,Size,Size,Colour,Max#,FallOff#
  
EndPsub Ball
  
  




NOTE: Animation Loops



      Ok, so hopefully by now you've starting to get wrap your mind around the various concepts being expressed. We've not only jumping into Sprites here, but we're starting to get an understanding of how PlayBASIC programs render the screen and keep the program running. So now, when you look through the various examples in the Help Files / PROJECT PACKS / FORUMS you'll start to notice that many of them use the same structure as outline above. There are other ways mind you, but generally this is most common.



     TIP: You can also use floating point variables for finer control of sprite movement.




Top







Sprite Animation - Introduction


     Sprite Animation is an interesting subject, as different people have very ideas as to what sprite animation is. Here we're only going to be touching on the most basic form of animation, which is achieved simply stepping our sprites current image (via SpriteImage) through a collection of images.

     To program frame based animation, we really only need two things, first we need a series of frames that represent our characters action (like walking, jumping, running for example) and a bit code to load and play these images back in sequence. The concept we'll be using ties back in the our Sprites In Motion topic earlier. Where to create the appearance of motion, our program would first clear the back ground, change our characters position, draw the character and then sync. When this is executed, the character appears to move in whatever direction we want. Animation works the same way, Except this time instead of moving the character, we're going to be changing the SpriteImage each frame.

     First, let's take a look at some frames. Bellow we've a collection of eight frames that when played back to the viewer, give the illusion of spinning star.





      Each frame in the animation is stored as separate bitmap file. The artist has conveniently named the files star0001.bmp, star0002.bmp .. through to star0008.bmp. Why is this convenient ? Well, it means we can use a For/Next loop to load the sequences of frames. But that'll have to wait a moment. Our first objective is to just load the materials and display the animation on screen.

      Just like "Sprite Motion" section of the tutorial above, our program can be broken down into two main parts. The first part is the initialization, or set up code. In this case, that section of code will load our sequence of frames. The Main Loop section well clear the screen, bumps the animation frame through it's set of images, draw the current image and then sync.

      First we'll tackle the loading problem. To load image into memory in PlayBASIC, we've a few command options, namely LoadImage and command. The reason for this, is that when PlayBASIC loads any image into memory, it's stored them in an internal array. You can think of this like a series of slots. Where each slot has a numerical number or index.

      We can use this behavior to our benefit, by loading our set of STAR frames into sequential image slots. The image slots start from 1 up to around 1000 by default. You can use more (See ImageQuantity), but very few programs actually do. Anyway, for this example we're going to load our sequences of eight Star frames into image slots 100 through to 107. You can use any slots, I'm only using 100 onwards to open you up to the idea. One thing to careful of though when making bigger programs,. would be to make sure you're not loading your images into slots that already in used. (Hint LoadNewImage)

      So for our animation example, here's what our initialization code might look like. This is not actually runable code, as if you cut'n'paste this example into PB and try and run it, It won't know where the fine the Star001.bmp files on your computer. In order to make it run, you'd need to either need to set up a Project and copy the Star bitmaps files into the project folder, or set the location of the file on your computer.


  
; Load frame one of the star anim to image slot 100
  LoadImage "star0001.bmp"100
  
; Load frame two of the star anim to image slot 101
  LoadImage "star0002.bmp"101
  
; load frame three into image slot 102
  LoadImage "star0003.bmp"102
  
; load frames 4,5,6,7,8 into slots 103 to 107
  LoadImage "star0004.bmp"103
  LoadImage "star0005.bmp"104
  LoadImage "star0006.bmp"105
  LoadImage "star0007.bmp"106
  LoadImage "star0008.bmp"107
  
  

Note: This example is NOT cut'n'paste friendly


      Now all the above code does is loads the eight files into the eight image slots in memory. Once loaded, we can tell PlayBASIC to Draw any one of those slots whenever we like. We do need to be a little bit careful when doing this, as if we try and make PlayBASIC draw an image that doesn't exist, then PB will halt the program and give you an error message.

      Moving on, in order to keep track of the current animation frame, we're going to need to use a variable in our program. We'll give this variable a meaningful name of 'CurrentFrame' since it's going to store the value of the current image slot we'll be drawing each sync. Now since we're loading our star animations into image slot 100. We'll need to initialize the CurrentFrame variable to the starting value of 100. So when we enter the main loop it's ready for use with DrawImage.

      Example,

  
; initialize the integer variable CurrentFrame
; to the integer value of 100
  CurrentFrame = 100
  



      So we've loaded our animation frames and setup our CurrentFrame variable, now it's time to write the Main Loop of the program. The basic structure of the code is just like previous movement examples above. Were each loop we clear the screen, change the current frame variable, draw this current frame and then sync.

      The only thing that different from the Sprite Motion examples, is now we're changing the current frame variable. To change frames, all we're going to be doing, is adding one to the CurrentFrame variable each time the main loop executes.

      How does adding one give us animation ? - Well remember that our animation frames are loaded into image slots 100,101,102.. up to 107. So if we set our CurrentFrame variable to start the program to value of 100. We're using this variable to store what image slot we wish to render at any given time. To draw this frame at location 100x,200y on screen, we'd called DrawImage CurrentFrame,100,200,false. So if currentFrame ='s 100, this would drawn image 100. If we add one to the CurrentFrame variable making it 101 and draw it again using DrawImage CurrentFrame,100,200,false PlayBASIC would draw image 101 at this position on screen.


      Let's have a look at how our main loop for our animation program might look.

  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Add one to the CurrentFrame variable
     CurrentFrame=CurrentFrame+1
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage CurrentFrame, 300,200,true
     
   ; Show the newly drawn scene to the user
     Sync
     
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  



     Now on the surface that might seem like i'd work, and it will for a little while, eight frames to be exact. If we ran this program (assuming we'd loaded the star frames into slots [100->107 and set our CurrentFrame variable before entering the loop) the program would clear the screen, bump the CurrentFrame value by one, drawn the currentframe (which would be image 101), sync and then loop back to repeat the process. It'd happily repeat that same process until CurrentFrame equals 108, where PlayBASIC would error when trying drawimage 108, since it doesn't exist.

     To overcome this, all we need do is check if CurrentFrame is greater than the last frame in our animation sequence of 107. When it is, we reset CurrentFrame to our starting value of image slot 100. This would make the animation appear endless.

     So our CurrentFrame comparison / reset code might look a bit like this. ([red]See[/red] if/then and operators )

  
  
; Add one to the CurrentFrame variable
  CurrentFrame=CurrentFrame+1
  
; Check if Current Frame is larger than 107
; if it is, we reset it to 100.
  If CurrentFrame>107 Then CurrentFrame=100
  
  


      So that's the mechanics of animations, now let's put it all together into a working example. The only new thing in the code bellow, is how it's locating the folder where the STAR animation frames are stored within the PlayBASIC documentation. To run the exchange you cut'n'paste the code into a new project and hit F5.

  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  
; --
  
  
; Load frame one of the star anim to image slot 100
  LoadImage Path$+"star0001.bmp"100
  
; Load frame two of the star anim to image slot 101
  LoadImage Path$+"star0002.bmp"101
  
; load frame three into image slot 102
  LoadImage Path$+"star0003.bmp"102
  
; load frames 4,5,6,7,8 into slots 103 to 107
  LoadImage Path$+"star0004.bmp"103
  LoadImage Path$+"star0005.bmp"104
  LoadImage Path$+"star0006.bmp"105
  LoadImage Path$+"star0007.bmp"106
  LoadImage Path$+"star0008.bmp"107
  
  
  
;*=--------------------------------------------=*
; Set Current Frame
;*=--------------------------------------------=*
  
  CurrentFrame =100
  
  
  
; Tell PlayBASIC to only allow 10 sync
; per second
  
  SetFPS 10
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Add one to the CurrentFrame variable
     CurrentFrame=CurrentFrame+1
     
   ; Check if Current Frame is larger than 107
   ; if it is, we reset it to 100.
     If CurrentFrame>107 Then CurrentFrame=100
     
     
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage CurrentFrame, 300,200,true
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  


      Now if we run this example this we'll get something like this, A spinning star on screen.






     Improvements

      While the above code works, and you could happily use that method in your game. But there's a few ways we can could improvement it also. For the first improvement we'll look at using a For/Next loop to load our sequence of frames.

      This time we'll use a loop to load the following Heart animation frames. Just like the Star animation used above, the Artist who the made the following Heart animation has saved each frame using a numbered filename. For example heart0001.Bmp, heart0002.Bmp up to heart0008.Bmp. That may not seem useful initially, but what we can do, is make some code that constructs the Filename.

      To create one of the Heart file names we're going use the String adding and the Digits$() function. If we look at the names, then we can the see the header part of the name is same in each file. Which in this case is "Heart", this is followed by a four digit number (Which we'll use digits for), following by the file extension. To store the file name we'll use a called File$.

      To construct the file name and store it in our file$ variable, we're adding (joining) the header string with the digits$ result and the tail string fragment. Which gives up some code that might look like this.

  
  File$ = "Heart" + Digits$(Count,4+ ".bmp"
  



      Now if we run this code, the file name that the expression creates will depend upon the value in the Count variable. Since Count hasn't been initialized to anything, it'll default to being zero. Which would make our filename "Heart0000.bmp"

      Try this in PB.

  
  File$ = "Heart" + Digits$(Count,4+ ".bmp"
  Print File$
  Sync
  WaitKey
  



      Since we can dynamically construct the file name as above, then we could use the For/Next Loop to count through the set of files we'd like to load. In this case the files name start from 1 and run through to 8. So our For loop will count from 1 to 8. Each loop it builds this new file name and loads it.

      This example loops through and creates the names and just prints them to the screen.

  
  For Count = 1 To 8
     File$ = "Heart" + Digits$(Count,4+ ".bmp"
     Print File$
  Next
  Sync
  WaitKey
  



      If you run this example, PB will print out a list of file names to the screen and then wait for a key press. In order to move beyond just creating the file names. The next step is going to be loading the frames (Shown bellow) into the required image slots. To do this, we'll need to not only add the LoadImage code, but we'll also need to tell PB where these media files can be found within the PlayBASIC documentation.

      This is the files we're going to be loading.





      Example,

  
; get location of the Heart Animation
; from within the PlayBASIC help media files
  path$=ProgramDir$()+"Help\Commands/Media/Animations\Heart\"
  
; Start of for next that uses COUNT to count from 1 to 8
  For Count = 1 To 8
   ; Build this version of the filename
     File$ = "Heart" + Digits$(Count,4+ ".bmp"
     
     
   ; Load the image into Slot 200+Count
   ; The total filename is made by joining the PATH$
   ; and our FILE$ strings together
     LoadImage Path$+File$, 200+Count
     
  Next
  
; To show that our images are loaded into the right
; slots lets drawn them to the screen.
  Xpos=100
  For ThisImage =201 To 208
     DrawImage ThisImage,Xpos,100,0
     Xpos=Xpos+50
  Next
  
; Show the screen and wait for a key press
  Sync
  WaitKey
  


      When cut'n'paste this example the program loads the animation frames in image slot 201 to 208. To valid the images have loaded the second part of the program renders the various frames across the screen. Just so we can see that the code actually did something, like so.





      Clearly using a simple loop and save us a lot of programming.


      Updated Star Animation Example

      Here's a version of the previous star animation program with the For/Loop image loader. The program still functions the same, it's just shorter.

  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Set Current Frame
;*=--------------------------------------------=*
  
  CurrentFrame =100
  
  
; Tell PlayBASIC to only allow 10 sync
; per second
  
  SetFPS 10
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Add one to the CurrentFrame variable
     CurrentFrame=CurrentFrame+1
     
   ; Check if Current Frame is larger than 107
   ; if it is, we reset it to 100.
     If CurrentFrame>107 Then CurrentFrame=100
     
     
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage CurrentFrame, 300,200,true
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  


Top






Sprite Animation - Frame Rate


      In the previous section we kicked off the whole sprite animation subject, concluding with a simple example of a spinning star above. In that example the program simply bumps the Currentframe counter every time the main loop was executed. This might be simple to program and easy to understand, but it also ties the speed of our Star animation directly to the speed the main loop. So the faster then main loop runs, the faster the animation plays.

      To dive deeper, let's imagine PlayBASIC is executing our programs Main Loop at say 60 times per second and our animation is eight frames long, changing frames every time through the main loop. Then the program will run through the entire animation (60/8)=7.5 times per second. That's way too fast for the viewer to clearly see it. Thankfully, there's a number of ways we can tackle such problems. Some are more complicated than than others. But first we'll look introducing a FrameRate counter to slow our animation code down.

      If we wanted to run our game at 60fps (Frames Per Second see SetFps), but limit our sprite animation speed to say 10fps. Then one way of doing that is introducing a FrameRate counter variable. This variable is then used to dictate how frequently our program should change our CurrentFrame variable. So now rather than increasing the CurrentFrame variable each time the main loop executes, we'll be decreasing the FrameRate counter until it reaches zero. When it hits zero, we then reset the FrameRate counter to it's starting position, andn bump the CurrentFrame variable to the next frame in the animation.

      So FrameRate is basically the number of times the main loop is allowed to be executed, between changes to CurrentFrame, so it's the a delay between CurrentFrame changes. For example, If we want our animation to play at 30fps, then we need to only update CurrentFrame every second frame. In this case we'd set FrameRate value of (60/30)=two. If we wanted our animation to run at 10fps, then we'd need to use an AnimRate of (60/10)=six.

      Before we add this concept to our main Animation example, let's have a look at how our new main loop is structured. Bellow the main loop from the STAR animation example from above. In that example the Animation frames are loaded into image slots 100 through to 107.

  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Subtract one from our FrameRate variable
     FrameRate=FrameRate - 1
     
   ; Check if the frame rate counter has hit zero
     If FrameRate=0
        
      ; Reset the frame rate counter six
        FrameRate=6
        
      ; Add one to the CurrentFrame variable
        CurrentFrame=CurrentFrame+1
        
      ; Check if the CurrentFrame is beyond 107 (last frame),
      ; if so, reset
        
        If CurrentFrame>107
         ; Reset Current Frame to the first (100 in this case)
           CurrentFrame=100
        EndIf
        
     EndIf
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage CurrentFrame, 300,200,true
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  

Not a cut'n paste friendly example



      In this example, the program will only change the CurrentFrame variable every 6th time through the Main Loop. So if we tell PB to limit the program to a max of 60fps, then our animation will be running at a 6th of main loop speed, (60/6)=10FPS.


      FrameRate Controlled Sprite Animation

      Now here's a version of the 'STAR' animation example with Frame Rate control and movement on the X axis added, just to spice the demo up a little. Just like the earlier section we'll be using a variable called XPOS to store our current X coordinate. Each time through the main loop we'll be adding one to this variable, which will make the Star appear to move RIGHT. When it reaches the edge of the screen it'll reset back to zero. So it loops around.


  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Set Character Variables
;*=--------------------------------------------=*
  
; Set Current frame to the first in our animation
  CurrentFrame =100
  
; Init FrameRate to it's starting value of 6, so it's
; updates very 6th frame
  FrameRate =6
  
; Init the XPOS variable to it's starting position
; of 400 (middle of the screen)
  
  Xpos = 400
  
  
; Tell PlayBASIC to limit the number of syncs
; 60 per second.
  
  SetFPS 60
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Add one to the X coordinate of our character
     Xpos =Xpos +1
     
   ; check if it's position is off the screen ?
     If Xpos>800 Then Xpos =-32
     
     
     
   ; Subtract one from the frame rate varibale
     FrameRate =FrameRate-1
     If FrameRate=0
        
      ; reset frame rate to variable to it's
      ; starting value of every 6th frame
        Framerate=6
        
      ; Add one to the CurrentFrame variable
        CurrentFrame=CurrentFrame+1
        
      ; Check if Current Frame is larger than 107
      ; if it is, we reset it to 100.
        If CurrentFrame>107 Then CurrentFrame=100
        
     EndIf
     
     
   ; Draw this image at XPOS, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage CurrentFrame, Xpos,200,true
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  
  


      If you cut'n'paste and run this code in PB, then you'll see something like this.



      So now we've actually got something that we could use for our video games sprite animations, but it's not the only way. Since, all we're doing it counting through some a range of values and then using that value to render a particular sprite.

Top





Sprite Animation - Floating Point


      Up until now we've been using Integer variables for our FrameRate and CurrentFrame variables. But it's not the only way, If we changed to floating point we could combine the two things into a single variable. This is possible as floating points values contain a fractional part. Floating point variables can be easily distinguished from Integer and String as they use a # identifier. This tells PB and the programmer, that this variable is floating point.

      The key difference between floats and integers is that floats allow us a make finer steps than one, since floating point variables support fractional values and integers don't. We can use them to our advantage in our animation code, as rather than stepping CurrentFrame# by one each time through the main loop, we could move in smaller fractions. So to move at 1/2 the main loop speed we'd add 0.5 to CurrentFrame# each time through.

      So what we'll do is replace our trusty FrameRate variable from the previous examples with a new floating point variable called AnimSpeed#. Prior to our programs main loop, we'll be setting this variable with the speed of the animation, when compared to the games frame rate. This might be little tricky to get your head, but hang in there. To do means simply dividing our programs frame rate, by our desired animation frame rate. Giving us the following calculation AnimSpeed#= DesiredFramerate / Game FPS

      We can test this formula with a bit of example. Imagine we wanted our game to run at 60fps, so we'd use SetFps 60 at the start of our program. Now imagine we have a running animation that looks best when played at 20fps. So if plug our values into the formula above we get a calculation like this, AnimSpeed# = 20.0 / 60.0

      Please note the use of floating point literals, as we need these to make sure PlayBASIC performs a floating point division between the 20.0 and 60.0. If we just wrote 20/60, then PlayBASIC would perform an Integer division, giving us an incorrect result.

      Anyway, when we divide 20.0/60.0 we get an Animation Speed of 0.3333 (a third), so approximately every third time the main loop is executed our CurrentFrame# variable will step to the next frame. I say approximately, as float point values can be bit lossy.

      Before trying this is our main example, let's have look at the setup and main loop now looks using this method. Remember that in the original example, our STAR Animation frames are loaded into image slots 100 through to 107. So that's why it's comparing with those values.


  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
; Calc the speed based upon the
; programs Frame Rate limit
  AnimSpeed# = 20.0 / GetFPS()
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
     
     CurrentFrame#=CurrentFrame#+AnimSpeed#
     
   ; Check if the CurrentFrame is beyond 107 (last frame),
   ; if so, reset
     
     If CurrentFrame#>107
      ; Reset Current Frame to the first (100 in this case)
        CurrentFrame#=100
     EndIf
     
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage Floor(CurrentFrame#), 300,200,true
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  
  



      Now a quick overview of the example, and the first thing you'll notice is that it's less code than the previous method, but what's Floor(CurrentFrame#) function call doing in the DrawImage line ? Well, all it's doing is converting the whole number part of the Floating Point number (CurrentFrame#) into an Integer version. Once it's convert we can happily pass that converted integer into DrawImage. You might be able to get away without flooring the float, as PB will automatically convert the float to integer for DrawImage, but it may round the value up. Which is likely to cause 'image doesn't exist' errors at runtime. So my advice is to use floor.



  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Set Character Variables
;*=--------------------------------------------=*
  
; Set Current frame to the first in our animation
  CurrentFrame# =100
  
  
; Calc the speed based upon the
; programs Frame Rate limit
  AnimSpeed# = 10.0 / GetFPS()
  
  
  
; Init the XPOS variable to it's starting position
; of 400 (middle of the screen)
  
  Xpos = 400
  
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Add one to the X coordinate of our character
     Xpos =Xpos +1
     
   ; check if it's position is off the screen ?
     If Xpos>800 Then Xpos =-32
     
     
   ; Add our fractional speed to the current frame
     CurrentFrame#=CurrentFrame#+AnimSpeed#
     
   ; Check if the CurrentFrame is beyond 107 (last frame),
   ; if so, reset
     If CurrentFrame#>107
        
      ; Reset Current Frame to the first (100 in this case)
        CurrentFrame#=100
        
     EndIf
     
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage Floor(CurrentFrame#), Xpos,200,true
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  



     This is a pretty flexible approach and if you dig through some of example games in the PlayBASIC project packs or on the forums, you'll no doubt find programs using this very method. Now what's interesting, is that we can make the animation code even simpler by using the WrapValue function.

     The WrapValue function takes three parameters, those being the value we want to wrap and the min/max range that the resulting value should fall within. So we could use this function to keep our CurrentFrame# counter value within our desired range limits.

      For example, CurrentFrame#= WrapValue(CurrentFrame#, 100, 107) This would keep the CurrentFrame# variable between the 100 and 107 range. Allowing us to further simplify our programs Main Loop.

      So this section,

  
; Add our fractional speed to the current frame
  CurrentFrame#=CurrentFrame#+AnimSpeed#
  
; Check if the CurrentFrame is beyond 107 (last frame),
; if so, reset
  If CurrentFrame#>107
     
   ; Reset Current Frame to the first (100 in this case)
     CurrentFrame#=100
     
  EndIf
  


      Can be replaced with this.

  
  
; Add our fractional speed to the current frame
  CurrentFrame#=CurrentFrame#+AnimSpeed#
  
; Wrap the current frame variable within our
; animations  bounds
  CurrentFrame#= WrapValue(CurrentFrame#, 100107)
  
  



      Which can be further simplified as just this.


  
  
; Add our fractional speed to the current frame
; and wrap it within the animations bounds
  CurrentFrame#= WrapValue(CurrentFrame#+AnimSpeed#, 100107)
  
  



      Now here's what our animation example has been reduced down to. This program loads our media, sets up our required variables and renders our animated moving star. Might not seem like much, but if you're following how we got here, then your well on your way.


  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Set Character Variables
;*=--------------------------------------------=*
  
; Set Current frame to the first in our animation
  CurrentFrame# =100
  
  
; Calc the speed based upon the
; programs Frame Rate limit
  AnimSpeed# = 10.0 / GetFPS()
  
  
  
; Init the XPOS variable to it's starting position
; of 400 (middle of the screen)
  
  Xpos = 400
  
  
; Start of Main Loop
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Add one to XPOS and wrap to within
   ; our screen limits of -32 to 800
     Xpos=WrapValue(Xpos+1,-32,800)
     
     
   ; Add our fractional speed to the current frame
   ; and wrap it within the animations bounds
     CurrentFrame#= WrapValue(CurrentFrame#+AnimSpeed#, 100107)
     
     
   ; Draw this image at 300x, 200Y on the screen
   ; the image it draws is determined by the value
   ; of CurrentFrame
     DrawImage Floor(CurrentFrame#), Xpos,200,true
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  







Top









Sprite Management


      So far our most of the programs through this tutorial have been only controlling one sprite. The reason for this is, was so we can separate the concepts (like animation and motion) from any management code around it. In this section, we're going to explore how a programmer might go about controlling a group of moving/animated sprites.

      To do this, we're going need to store and manipulate information about many different game characters all at once. In our previous examples, we've been using Variables to store the individual pieces of information about a single character. Using variables to hold information such as our characters position (Xpos,Ypos), it's current animation frame (CurrentFrame#) as well it's animation frame rate (FrameRate, AnimSpeed#). When you think about, we're using all these separate variables to hold the various bits of information about one character.

      Using variables for each character works fine for small examples, and situations where we only need one or maybe two characters, but it's not ideal for controlling many characters. To do that, we'll need to use either Arrays or User Defined Types to hold the many properties about our individual game characters. I suggest if you haven't read those tutorials now if the time.


     Managing Sprites With User Defined Types

      What we're going to do is break this step into two stages, in our first stage we're going to build a user Defined Type version of the our running Star examples so we can see the difference, this version will also only handle one character, then we'll look a few ways to expanding it to handle more than one character.

      User defined types allow us to group collections of variables together under one banner (see types for more), to convert our previous approach to types, means we first need to declare a Type structure that holds our required variables. For this example, lets say that we want our character to have variables that will hold it's X and Y coordinates (Xpos,Ypos), it's animation Current Frame (CurrentFrame#) and the speed our animation (AnimSpeed#).

      So our type declaration might look like this.

  
; Start of Type declaration called "GameCharacter"
  Type GameCharacter
     
   ; Now we add our variables (also know as fields)
   ; to our "GameCharacter" structure
     
   ; Here we're declaring XPOS and YPOS fields as integers
     Xpos
     Ypos
     
   ; Declare Current animation frame as float
     CurrentFrame#
     
   ; add the anim speed field as float
     AnimSpeed#
     
  EndType
  
  


      Now this might seem like a lot code, but all we're done so far is declare to PlayBASIC our user defined type called GameCharacter and added a bunch of fields to it. The cool thing is that once it's declared, we can then dimension Variables and Arrays of type GameCharacter. For our first step we're going to create a variable called "Star" of type "GameCharacter", do that we use the Dim command.

  
  Dim Star As GameCharacter
  


      Now unlike regular integer/float or string variables, typed variables contain the fields from whatever type they're created from. So our Star variable, would now contain the four fields from the GameCharacter type. So it's got it's own XPOS,YPOS, CURRENTFRAME and ANIMSPEED fields. To access these fields we use the "." character. So to access the Xpos field from Star, we type Star.Xpos. We can then read or write to it like a normal variable.

      Here's an example of the our program initialization code. This code declared our GameCharacter, dimension our Star Variable, then initialized the various field to there starting values.


  
  
; Create Type called "GameCharacter"
  Type GameCharacter
     
   ; declare XPOS and YPOS fields as integers
     Xpos
     Ypos
     
   ; Declare Current animation frame as float
     CurrentFrame#
     
   ; add the anim speed field as float
     AnimSpeed#
     
  EndType
  
; Dimension STAR of type GameCharacter
  Dim Star As GameCharacter
  
; Allocate our structure and store it in STAR
  Star = New GameCharacter
  
; Set the Xpos and Ypos fields to 400 / 300
  Star.XPos  = 400
  Star.Ypos  = 300
  
; Set the field CurrentFrame to 100
  Star.CurrentFrame = 100
  
; Set the Speed to 10 fps
  Star.AnimSpeed      = 10.0 / GetFPS()
  
  



      It's about now you're probably wondering why do all this extra work, just to get the same result as just using regular variables ? That's true, at this point we're not gaining much in using this method at all. In fact the only benefit that comes to mind, would come from the compiler requiring pre-declaration of type variable fields. So if you made a typo in your variable name, PlayBASIC will give you an error at compile time. But you could just as easily enable Explicit mode when using variables.

      Now the let's have a look at the 'Star Animation' example from above converting to using User Defined Types. This code basically moves our Star character left to right around the screen, while animating it at 10fps.


  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Setup our  Game Character Type
;*=--------------------------------------------=*
  
  
; Create Type called "GameCharacter"
  Type GameCharacter
     
   ; declare XPOS and YPOS fields as integers
     Xpos
     Ypos
     
   ; Declare Current animation frame as float
     CurrentFrame#
     
   ; add the anim speed field as float
     AnimSpeed#
     
  EndType
  
  
;*=--------------------------------------------=*
; Init the our Star variable
;*=--------------------------------------------=*
  
  
; Dimension STAR of type GameCharacter
  Dim Star As GameCharacter
  
; Allocate a new empty GameCharacter and store it in STAR
  Star = New GameCharacter
  
; Set the Xpos and Ypos fields to 400 / 300
  Star.XPos  = 400
  Star.Ypos  = 300
  
; Set the field CurrentFrame to 100
  Star.CurrentFrame = 100
  
; Set the Speed to 10 fps
  Star.AnimSpeed      = 10.0 / GetFPS()
  
  
;*=--------------------------------------------=*
; MAIN LOOP OF PROGRAM
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the screen to black
     Cls
     
   ; Add one to XPOS and wrap to within
   ; our screen limits of -32 to 800
     Star.Xpos=WrapValue(Star.Xpos+1,-32,800)
     
     
   ; Step Animation Frame forward and
   ; wrap within the animations bounds
     Star.CurrentFrame#= WrapValue(Star.CurrentFrame#+Star.AnimSpeed#, 100107)
     
   ; Draw this image at it's current position and frame
     DrawImage Floor(Star.CurrentFrame#), Star.Xpos,Star.Ypos,true
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  
  


      At this point, we've shifted our program over to User Defined Type version, but we've still only controlling one character. The problem is we've using a Typed Variable. Which by design is singular. So even though we've stored all of our character properties in 'Star', there's only one instance of that Star variable in our program. So in order to control more than one character, we're going to have to look at Typed Arrays or Linked Lists.




Sprite Management - Typed Array


     Managing Sprites With Typed Arrays

      The previous step has given us the frame work, all we're going to do now is use a Typed Array, rather than Typed Variable. From a set up point of view we'll be using the "GameCharacter" Type declaration as before, but this time we'll dimension a Stars() array that's big enough to hold 10 different characters inside it. All characters will share the same animation frames though, but they'll each be randomly assigned different positions on screen and frame rates.

      To do it, we'll need to change our dimension statement and set up a For->Next Loop to run through the set of characters and initialize each of them. We'll be randomly giving each character a position and a frame rate, so the program would give us different results every time we run it.

      Here's what our new Typed Array set up code is going to look like.


  
  
; Dimension STAR array of type GameCharacter
  Dim Star(10As GameCharacter
  
  
; Set up a for / loop to count from 1 to 10
  For lp = 1 To 10
     
   ; init this star with a empty
     Star(lp) = New GameCharacter
     
   ; Random set the Xpos and Ypos fields
     Star(lp).Xpos  = Rnd(800)
     Star(lp).Ypos  = Rnd(600)
     
   ; Set CurrentFrame to 100
     Star(lp).CurrentFrame = 100
     
   ; Randomly pick our animation speed.  The rate
   ; will range from Fps to as high as 25fps
     Star(lp).AnimSpeed      = RndRange#(5,25/ GetFPS()
     
  Next
  
  



      This code create our array called Star with space for 10 separate types in it. We can access the different stars using a numeric index just like any other array.

      To make initializing the game characters easier, we're using a for loop to count through the available indexes, from 1 to 10. So each time PlayBASIC executes the code inside the loop, we've using the loop counter variable lp as our index each individual character inside the Star array. So the first time through, LP would equal 1, which is like saying Star(1).Xpos = Rnd(800) for example. The next time through, Lp would be 2, so it's like say Star(2).Xpos = Rnd(800) etc until lp is beyond 10. At this point the For/Next loop ends and our program continues onto the line following the next statement

      By now you've not doubt guessed that our next step is going to be updating our programs Main Loop to handle our group of characters. To do this means wrapping a for / next loop around the animation and draw image logic. We'll have to modify that code from typed variables to arrays, but that'll ensure our program runs through and updates the set of characters stored in our stars array. This version is slightly different to the other version so the loop in that the characters don't move in this version. But they're each uniquely position on screen and spinning at different speeds.


      Here's our updated example.


  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Setup our  Game Character Type
;*=--------------------------------------------=*
  
  
; Create Type called "GameCharacter"
  Type GameCharacter
     
   ; declare XPOS and YPOS fields as integers
     Xpos
     Ypos
     
   ; Declare Current animation frame as float
     CurrentFrame#
     
   ; add the anim speed field as float
     AnimSpeed#
     
  EndType
  
  
;*=--------------------------------------------=*
; Init the our Star variable
;*=--------------------------------------------=*
  
  
  
; Dimension STAR array of type GameCharacter
  Dim Star(10As GameCharacter
  
  
; Set up a for / loop to count from 1 to 10
  For lp = 1 To 10
     
   ; init this star with a empty
     Star(lp) = New GameCharacter
     
   ; Random set the Xpos and Ypos fields
     Star(lp).XPos  = Rnd(800)
     Star(lp).Ypos  = Rnd(600)
     
   ; Set CurrentFrame to 100
     Star(lp).CurrentFrame = 100
     
   ; Randomly pick our animation speed.  The rate'
   ; can be from as low as 5Fps and as high as 25fps
     Star(lp).AnimSpeed      = RndRange#(5,25/ GetFPS()
     
  Next
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP OF PROGRAM
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Update all the Star Characters
     For lp =1 To 10
        
      ; Add this characters anim speed to it's
      ; current frame and wrap the results
        Star(lp).CurrentFrame#= WrapValue(Star(lp).CurrentFrame#+Star(lp).AnimSpeed#, 100107)
        
      ; Draw this image at it's current position and frame
        DrawImage Floor(Star(lp).CurrentFrame#), Star(lp).Xpos, Star(lp).Ypos,true
        
     Next
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  


      The following animation just gives us an idea of what the program will look like running.




      Up until now we've been using images (ie. DrawImage) mainly to represent our on screen characters. Why ? Well, the programs we've been writing haven't really needed to use the PlayBASIC's sprite system as yet. You could just as easily write sprite versions, but at this point the we're focusing on the concept. Don't worry we'll be stepping it all too soon !

Top







Sprite Management - Linked Lists


      Next up, we're going to transform our user defined type usage from Type Arrays into a Typed Linked List. A linked list is way of storing groups of types all connected together, inside what appears to be a typed variable. Up until now, we've been using either Variables or Arrays, where we specifically tell PB what item from within the array we would like to read or write information to. But with a linked list, we don't need to, the list keeps a hidden pointer to the current item in the list. Internally you could imagine that PlayBASIC is routing our accesses (Read/Writes) to where they should be in the list. Making accesses to of typed linked list fields look just like a regular typed variable. Which nice from typing point of view.

      To move through the items held inside a typed linked list, we generally use the For EACH loop. This works much like a regular For/NEXT loop, but we don't need to supply it a loop counter. When PlayBasic starts executing a for each loop, it resets the current item pointer inside the linked type, back to the first item in the list for us, since it may have been previously to set to anywhere in the list. Now just like the regular For/NEXT loop, PlayBASIC will step our types internal current item list pointer to the next item, every time it reaches the next statement. The loop is complete when there's no more items in the list.

      Conceptually it's a bit to wrap our minds around, but there's a number of cool by-products to using linked lists. Like we no longer have to supply it with the item we want to access within the array, so there's less typing, and nor do we have to keep track of how many items are in the list. If you're really lost then i recommend checking the linked List Tutorial

      Let's have a look at the what our previous Typed Array program becomes once we've converted it to using Typed Linked Lists. The following code does the same thing as that example we're just using a different method. Which is pretty common in Video Game Programming. There's often many ways of doing the same thing. The method we choose is often determined by other requirements in our program. So Linked Lists is convenient in some programming situations and not in others.


  
  
; Force PlayBASIC to limit the program to
; a max of 60 frames per second
  SetFPS 60.0
  
  
;*=--------------------------------------------=*
; Load Animation Frames
;*=--------------------------------------------=*
  
  
; get PlayBASIC compiler path to guess
; location of the help file media
  
  path$=ProgramDir$()+"\Help\Commands/Media/Animations\Star\"
  
  For Count=1 To 8
     
   ; build this filename
     File$="Star"+Digits$(Count,4)+".bmp"
     
   ; Load this frame into the required image slot
     LoadImage Path$+File$, 99 +Count
     
  Next
  
  
  
;*=--------------------------------------------=*
; Setup our  Game Character Type
;*=--------------------------------------------=*
  
  
; Create Type called "GameCharacter"
  Type GameCharacter
     
   ; declare XPOS and YPOS fields as integers
     Xpos
     Ypos
     
   ; Declare Current animation frame as float
     CurrentFrame#
     
   ; add the anim speed field as float
     AnimSpeed#
     
  EndType
  
  
;*=--------------------------------------------=*
; Init the our Star variable
;*=--------------------------------------------=*
  
  
  
; Dimension STAR typed with LINK LIST Support
  Dim Star As GameCharacter List
  
  
; Set up a for / loop to count from 1 to 10
  For lp = 1 To 10
     
   ; Add a new Empty star to the list
   ; The new item is now the current item
   ; within star. So we're now accessing it
   ; every time we access star's fields
     Star = New GameCharacter
     
   ;  set the Xpos and Ypos fields of current star
     Star.XPos  = Rnd(800)
     Star.Ypos  = Rnd(600)
     
   ; Set CurrentFrame to 100
     Star.CurrentFrame = 100
     
   ; Randomly pick our animation speed.  The rate'
   ; can be from as low as 5Fps and as high as 25fps
     Star.AnimSpeed      = RndRange#(5,25/ GetFPS()
     
  Next
  
;*=--------------------------------------------=*
; MAIN LOOP OF PROGRAM
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the screen to black
     Cls
     
     
   ; Update all the Star Characters
     For Each STAR()
        
      ; Add this characters anim speed to it's
      ; current frame and wrap the results
        Star.CurrentFrame#= WrapValue(Star.CurrentFrame#+Star.AnimSpeed#, 100107)
        
      ; Draw this image at it's current position and frame
        DrawImage Floor(Star.CurrentFrame#), Star.Xpos, Star.Ypos,true
        
     Next
     
     
   ; Show the newly drawn scene to the user
     Sync
     
   ; Check if the ESC key is press ?, if not,
   ; loop back to the DO statement until it is
  Loop EscKey()=true
  
  





Top







Sprite Collision


      2D Video games can be broken down in a number of often small concepts all connected together. These concepts could be loosely categorized as A.I. (Artificial Intelligence), Physic's, Animation and Collision Detection. Generally speaking, traditional 2D video Games don't really use much in the way of A.I. or Physics. Often using very simplistic algorithms to give the appearance of such behaviors. What might be a shock though, is that collision detection can be central to both of concepts . Making collision detection is pretty vast subject, and one we can't possible dream to cover in this tutorial. Knowingly this, PlayBASIC was designed to incorporate as many generic collision functions as possible, not only for Sprites, but you'll also find collision functions for Maps, Shapes and even built in mathematically functions. Even though we've built so much into the product, in some situations you may find that you'll need to write your own custom solution or bend the built in stuff in some way. But in order to that we need to get a clear idea of PlayBASIC supports internally.

      The PlayBASIC sprite command set includes two general types of collision detection, which could be summarized as Vector and Pixel collision. Vector collision can be boiled down into methods that detect when two mathematical areas such as Rectangles, Circle or polygon shapes are overlapping. Since the detection methods are mathematical, it tends to be one of the fastest approaches. But of course for that speed there's a trade off, which is if we're just checking if the two areas overlay and not the sprite images directly, then it might not be the most accurate. In those situations, we could use Pixel level collision detection instead, also know as Pixel Perfect Collision. Pixel collisions are generally more work for the Sprite Engine to process than Vector, but they do allow for greater precision if that's what the game requires. Your approach is going to vary based upon what you're trying to achieve, so I'm afraid there's no one solution fits all.

      By default the Sprite Engine uses Vector collision mode set to rectangles (See SpriteCollisionMode). Enabling this mode means, sprite engine creates an invisible rectangle around the size of the sprites current image. This rectangle isn't scaled or rotated with the sprite, rather it's just mathematically represents of the area that sprite is taking up. There are other collision modes, this is just the default.

      We can query if sprites are overlapping in a number of ways. If all you want to do is check two sprites, then we've the SpritesOverlap function. Alternatively we can use SpriteHit function, which compares our sprite with any other sprites with sprite collision enabled. (See SpriteCollision)

      Just like the previous sections of this tutorial, we're now going to and cover some basic usages. The examples will be stripped down to the bare bones. You can find more elaborate sprite collision examples both in the PlayBASIC projects pack that comes with PlayBASIC and on our forums.


Top






Sprite Collision - Vector - Rectangle



      The Sprites default collision mode is rectangle. This mode is one of the most basic forms of vector collision that PlayBASIC supports. When in rectangle mode the Sprite Engine uses a bounding box around the sprites position in the size of the image. The box isn't scaled or rotated, so this mode is purposely designed for use with sprites that aren't being scaled or rotated. This falls in line with the sprite engines default draw mode which just happens to be BlitMode (mode 0, see SpriteDrawMode). When in BlitMode a sprite can't be rotated/scaled and have some effects applied to it. In this mode the sprite is drawn as is.

      What we'll do is set up a simple scene of two sprites. One will be user controlled (via Mouse) and the other will just be randomly position on screen. In this first test, both sprites will use their default sprite collision modes of rectangle. Just like previous example, we'll reuse the ship.bmp(Bellow) for our sprites o screen representation. Just so we've something a bit more interesting to look at.




      Let's jump straight into our first example we can dissect it afterwards.

  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image
  ShipIMage=     LoadNewImage(Path$+"ship.bmp")
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug Badguy,true
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
; Turn debug mode for the Player Sprite
  SpriteCollisionDebug Player,true
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
     
   ; Check for a collision between the Player
   ; Player and the BadGuy sprites
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  



      Hopefully, you're familiar with most of the code in this example by now, so we'll just tackle the collision aspect. When we run this example we get something like the picture bellow. The code uses the SpritesOverlap to determine if our two sprites are sharing the same area. Both sprites are using their default collision modes of rectangle, so we don't actually need to tell PlayBASIC to enable sprite collision or set the mode in this example, as it's the default. Now to help visualize what's going on, we're enabling the Sprite Collision Debug Modes (See SpriteCollisionDebug) in both sprites. When a sprite has debug mode enabled and is rendered, the sprite engine draws not only the Image (our ship in this example), but two outlines that represent the collision modes area. In the picture bellow, we can just make out there's two different sets of lines being rendered ( one set in White another in RED) since they're overlapping each other. It's easier to see them both in rotated collision modes.




      Now If we examine the program and picture closely, the first thing that should stand out is that the SpritesOverlap function is returning a true, when any part of the two rectangles overlap. Depending upon the game, this might be problematic for the player. In particular if the images you use in your game, have a lot of blank pixels around the actual picture, like our ship image above. This can be a problem in games, as the player then feels like there's some invisible barrier around the character, so where if they get too close, the game will register a collision when the two things might not be touching. If you've played a lot of retro 2d games, you'll be pretty familiar with this. We can improve this by removing any transparent pixels around our images, this would help as we're making the collision rectangle a closer fit to the actual image, but it's still not going to be a perfect solution one.

      Rect Mode is ideally suited for character images that are entirely or almost entirely solid. Bellow is an animation of this example.







Top





Sprite Collision - Vector - Rotated Rectangle


      The collision mode we're going take a look at next is rotated rectangle. To enable this mode, we need set the sprites collision mode to mode #1 (Rotated Rectangle) (See SpriteCollisionMode). As you've not doubt guessed, this is a rotated version of the default 'rectangle' mode. When in rotated rectangle mode, the sprite collision engine will apply the same rotation (RotateSprite) and scaling of the sprite, to the collision area. Making a four sided convex polygon.

      Before we press on, It's worth point out that the PlayBASIC collision engine can detect impacts between combinations of sprite collision modes. So if one sprite is set to Rectangle Mode and another is set to Rotated Rectangle, it can happily work out if they overlap or not. This also extents to mixing Vector and Pixel collision. Be aware however that some of the collision modes are fairly complex and mixing them can have a negative impact upon our games performance.

      In this example we're set up a Player controlled character (via mouse) and stationary BagGuy sprite, this time we'll use rotated rectangle mode for both sprites. To show the rotation, we'll turn both sprites at different speeds. This will give us clearer idea of when the collision engine detects an impact. You'll notice that in this example we can see debug boxes around our sprites. The RED box shows the bounding area and the WHITE is the rotated rectangle that's being used for collision comparisons. The engine uses the bounding boxes for early rejection. So if the two sprites bounding boxes don't overlap, it doesn't even bother comparing to the rotated versions.

      This time we've got a little more setup, but the main loop is basically the same (apart from the TurnSprite commands)


  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image in FX format since
; we're going to rotate it real time
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Enable Rotation mode in the sprite
  SpriteDrawMode BadGuy , 2
  
; Set Sprite To Rotated Rect Collision Mode
  SpriteCollisionMode BadGuy, 1
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug Badguy,true
  
; Center Rotation Handle
  CenterSpriteHandle BadGuy
  
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
  
; Enable Rotation mode in the sprite
  SpriteDrawMode Player , 2
  
; Set Sprite To Rotated Rect Collision Mode
  SpriteCollisionMode Player, 1
  
; Turn debug mode for the Player Sprite
  SpriteCollisionDebug Player,true
  
; Center Rotation Handle
  CenterSpriteHandle Player
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
   ; Turn the Player and Badguy
     TurnSprite Player, 1
     TurnSprite BadGuy, 0.25
     
     
     
   ; Check for a collision between the
   ; Player and the BadGuy sprites
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  
  



      The main change to the program, since the first demo, is that we need a little more set up code to initialize the sprites draw and collision modes. Since we're going to rotate the sprites real time, we have to tell the sprite engine that each sprite is to be drawn using the rotation, this is done via the SpriteDrawMode command. Next we initialize the sprites collision mode to mode #1 by calling SpriteCollisionMode. It's at this point we're ready to run collisions and render the rotating sprites, but to make it easier to visualize what's happening, we're also enabling the sprite debug mode and centering the rotation handles. The debug mode is what the makes the sprite engine draw the bounding boxes around sprites. The centering just makes the sprite rotate around it's center, where as the default handle is the top left hand corner. Try commenting those lines and see happens to the rotation.

      Here's a close up picture of the sprites colliding, as you can see the collision only occurs when the White regions overlap. If we turned Sprite Collision Debug off, we wouldn't see the bounding lines around the two sprites and might get the impression that this is false positive collision. To make the accuracy of the collision better we could trim the image of it's transparent space around the ship, or look into using SHAPE or PIXEL collision.







      Rotated Rectangle mode is probably best used like it's none rotated brother, with images that are smaller or where the image doesn't have much or or transparent pixels around the edge..

      Here's a mock up animation of this demo in action.







     Tip: User Defined Functions can help us simplify this program further!

     To demonstrate this, here's a variation of the previous example. In this version, we've built a function to that will initialize the properties of any sprite that we pass into it. So in this version, we created each sprite then passed to the initialize function. The function sets the draw and collision modes of the sprite, allowing us to remove some lines of code from our example. If you're not familiar with Functions & Psubs then we highly recommend you learn them. They make your programming life easier in the long run.


  
  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image in FX format since
; we're going to rotate it real time
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Set up the sprite how we want
  InitSprite(BadGuy)
  
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
; Set up the sprite how we want
  InitSprite(Player)
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
   ; Turn the Player and Badguy
     TurnSprite Player, 1
     TurnSprite BadGuy, 0.25
     
     
     
   ; Check for a collision between the
   ; Player and the BadGuy sprites
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  
  
  
  
Function InitSprite(ThisSprite)
  
; Enable Rotation mode in the sprite
  SpriteDrawMode ThisSprite , 2
  
; Set Sprite To Rotated Rect Collision Mode
  SpriteCollisionMode ThisSprite, 1
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug ThisSprite,true
  
; Center Rotation Handle
  CenterSpriteHandle ThisSprite
  
EndFunction
  
  
  
  
  





Top







Sprite Collision - Vector - Circle


      Next up we're looking at the circle collision mode, to enable this mode we set the sprites collision mode to mode #2 (Circular) (See SpriteCollisionMode). Just setting the mode activates it, but we also need to specify the size of the circle. We do that by using the SpriteCollisionRadius function, which is specifically for this purpose. When setting the radius, we're defining the area the collision engine should consider as this sprites hard body. The area it self doesn't actually have to even line up with the image, so when in this mode, the sprite image and sprite collision are indeed two separate things. Making circle mode somewhat different from the others, since they modes tend to relate more to the sprites image.

      In our next example, we're going to continue with the mouse controlled player sprite and stationary bad guy sprite. The only real changes we'll be making is setting the sprite collision modes to circle and giving them different radius values. For the player, we'll set a radius of 50 and the bad guy to 30. The area is represented on screen when in debug mode using the White Circle (pictured bellow). This shows us exactly what the sprite engine is using as each sprites hard region. For a collision to occur, our sprites circular area has to be overlapped by another sprites region.






      Here's our example code for this version of the demo. The only next thing is the use of the SpriteCollisionRadius command, everything else is the same as previous demos.


  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image in FX format since
; we're going to rotate it real time
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Set up this sprite to circle with a radius of 30
  InitSprite(BadGuy,30)
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
; Set up this sprite to circle with a radius of 50
  InitSprite(Player,50)
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
   ; Turn the Player and Badguy
     TurnSprite Player, 1
     TurnSprite BadGuy, 0.25
     
     
     
   ; Check for a collision between the
   ; Player and the BadGuy sprites
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  
  
  
  
Function InitSprite(ThisSprite,RAdius)
  
; Enable Rotation mode in the sprite
  SpriteDrawMode ThisSprite , 2
  
; Set Sprite To CIRCLE Collision Mode
  SpriteCollisionMode ThisSprite, 2
  
; Set the Collision Radius of this sprite
  SpriteCollisionRadius ThisSprite, Radius
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug ThisSprite,true
  
; Center Rotation Handle
  CenterSpriteHandle ThisSprite
  
EndFunction
  
  



      This animation will give you and idea of what demo looks like running.







Top






Sprite Collision - Vector - Shape


      So far we've looked at creating basic rectangle and circular collisions, but what if we wanted an area that more closely resembled our sprites image, without resorting to Pixel based collision ? For this we have the Shape collision mode. Shapes allow us to create complex polygon shapes by positioning a set of vertex (points) and connecting these points together to form the outline of our object. There's a couple of common ways to create shapes, you can code them inside your PlayBASIC program in code, but the easier option would be to use a tool like PlaySHAPE. PlaySHAPE is a simple free tool that lets the user load an image, scale it up, then draw the collision shape over the top. It's not pretty, but does the job. You can find on www.PlayBASIC.com

      One of the coolest things about using shapes for collision, is that we can choose the exact parts of the image that should be considered hard. Personally, I tend to draw my shapes slightly inside the edges of the image they're going to represent. This is can be handy as some images have shading or transparency around the outer edges. So by making the shape slightly smaller than the image, we can make the collision more friendly to the player. If we oversize the shape, then it'd appear to have an invisible zone around it, much like the Circle and Rectangle modes can give off.


      Just like over previous sections on collision, we'll use the same basic demo frame work where the user controls a sprite with the mouse that we're checking for intersections against a static sprite. To this set up, all we really need to is tell our sprites to use Shape Collision ( Mode 3 ) in SpriteCollisionMode and assign our Image it's shape representation for collision. Now for sake of this example, I've already created a shape that suits our lovely ship.bmp image using PlaySHAPE, this file is stored in the same folder and called ship.Shape.

      Before we jump into our bigger example, let's load our ship image and shape into memory and render them on screen. To further help you visualize how the shape fits our image, we'll draw the shape blended over the ship. Allowing us to see through it and get a really good idea of how well it matches.

      Here's our test code.
  
; Include the Shape library commands in this program
  #Include "Shape"
  
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image as an FX image
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
; Load our shape into shape slot #1
  LoadShape Path$+"ship.Shape",1
  
  
; Draw the Ship image to the screen at 100x,100y
  DrawImage ShipIMage, 100100,true
  
  
; Set ink colour for following drawing commands
  Ink RGB(200,40,40)
  
; draw the shape (Filled) to 200x,100y
  DrawShape 1,200,100,2
  
  
; Draw our ship image with the masked over it
  DrawImage ShipIMage, 300100,true
  InkMode 1+32
  DrawShape 1,300,100,2
  
  Sync
  WaitKey
  
  



      Depending upon how much you've looked through the help section, there many well be a few new commands in this example, such as #Include or LoadShape. I would hope that LoadShape is pretty self explanatory (it loads a shape into a shape memory) , but you never know. So if you're not up to speed on those, then you might want to go have a quick look at those sections. But let's press on.

      Bellow we can see the output from this program. From Left to Right, it draws our Ship image, a filled version of our shape (DrawShape) in red, followed by our ship again with the shape transparently masked over the top of it (See InkMode. From that, we can tell the shape is pretty good match for the image and certainly useable in game. It's worth noting, that the player rarely (if ever) gets to see the fine accuracy of our games collision system up close, so a pixel here or there is nothing to worry about. In fact, for fast pace games, you can get away with really low quality of shapes quite happily.






      The only thing left to do now, is jump in and build our shape collision version of the our running example. To activate Shape Collision we need to do two things. For each sprite that is to use shape collision, we'll need to set it's collision mode to 3 via (see SpriteCollisionMode), this will switch the sprite to shape collision. You we've read through the Circular collision section previous to this section, you're probably guessing that there must be a sprite command that we use to tell the sprite what shape to use for collision. Well, there's not. So how do we do it ? - Well, since the shape is drawn from to match our image, then rather than having assign our shape to sprite, we tell the image what shape is it's representation using the SpriteImage command. Once the shape is associated with it's image, we no longer have to worry about it. When ever the sprite engine is checking a sprite that's set to shape collision mode, it looks at it's current image and grabs the shape it should use from there.


  
; Include the shape load commands
  #Include "Shape"
  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image in FX format since
; we're going to rotate it real time
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
; Load our premade shape that represents
; the hard regions of the ship.bmp image
  LoadShape Path$+"ship.Shape",1
  
; Associate this shape with our Ship Image
; then any time this image is used with a
; sprite using shape collision, the engine
; will look at the image to see what shape
; is associated and use that for it's collision
  ImageShape ShipIMage, 1
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Set up this sprite to circle with a radius of 30
  InitSprite(BadGuy,30)
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
; Set up this sprite to circle with a radius of 50
  InitSprite(Player,50)
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
   ; Turn the Player and Badguy
     TurnSprite Player, 1
     TurnSprite BadGuy, 0.25
     
     
     
   ; Check for a collision between the
   ; Player and the Bad Guy sprite
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  
Function InitSprite(ThisSprite,RAdius)
  
; Enable Rotation mode in the sprite
  SpriteDrawMode ThisSprite , 2
  
; Set Sprite To SHAPE Collision Mode
  SpriteCollisionMode ThisSprite, 3
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug ThisSprite,true
  
; Center Rotation Handle
  CenterSpriteHandle ThisSprite
  
EndFunction
  
  
  



      Now if we have a look at a close up taken from the demo, we can see the sprite debug mode (SpriteCollisionDebug) is rendering the attached shape outlines over the top of the rotated images. Just like the rotated rectangle mode, any associated shapes are rotated and scaled just as the image is for rendering. Since this the detection is mathematical between vector collision modes, it takes the sprite engine a fixed time to detection the collision. Obviously the more complex the shape is, the slower this will get, but size and rotation don't really matter. Making it perfect for collision.







      This animation will give you an idea of what demo looks like running. This time you can the objects really have to be overlapping to register a collision. You're not limited to collisions between sprites that use shape collision either. The sprite engine can resolve any combination you give it.










Sprite Collision - Pixel - Pixel Perfect


      So far we've been traveling through the wonderful world of Vector Sprite collisions, but this time we're changing tact and jumping into the more traditional world of Pixel Perfect sprite collision. Pixel Perfect is something of an umbrella term that's used to describe collision detection algorithms that work by comparing the raw pixels between sprites. So in essence the sprite engine is comparing each pixel from Sprite A against Sprite B, if any pair of solid (none transparent) pixels overlap, a collision occurs. It's the brute force nature that potentially makes this approach one of the most expensive types of collision detection. I say potentially, because just like everything else in game programming, it depends upon the situation as to how suitable Pixel level collisions are for your game.

     Pixel collisions are actually a three stage process. So when a sprite is checked, it doesn't just jump straight into pixel to pixel comparisons immediately, rather it first compares the sprites bounding boxes for a trivial level impact, if they overlap, then it compares if the rotated rectangle around the sprite, only continuing to the pixel level when the areas overlap. It does this to make sure that the engine isn't passing near misses to the pixel to pixel stage. This is important, as the comparison process can be a fairly expressive one, in particular when comparing large images that has are mostly transparent. In such situations, it's entirely possible that no collision would have occurred, costing us some runtime speed. Therefore it's often best to cut large images up into smaller sections, or even use Maps if the situation suits. This can be a little more work for the programmer, but would give more efficient results than comparing big images. Small images generally aren't much of an issue, to the point where Pixel Perfect Collision can be as fast or faster than Shape collision. But I wouldn't take that as a absolute rule though.

      To enable Pixel Perfect collision for any sprite, we set it's collision mode to #6 (See SpriteCollisionMode). Once activated, the collision engine uses the sprites current image (see SpriteImage) when checking for pixel level impacts. The collision engine fully supports rotated and scaled sprites alike. Rotation and scaling linear though, so it's not filtering (smoothing) the images while comparing the pixels. Linear Rotation/Scaling might be fast, but it can lose the finer details of some images.

      For example, if you had an image containing a cross hash dot pattern or lines on it and rotate that, much of the detail would be lost at certain rotations. This is not so bad when scaling up, but gets worse when scaling down. Unfortunately this a by product of linear scaling/rotation algorithm, it might be fast, but it's not always pretty. Filtering would help, but that's much slower, making it far from ideal for collision.

      The following code snippet demonstrates the lossy nature of linear scaling/rotations. The program creates an image with some random lines on it, three sprites of different scales and spins them on screen.


  
; Make our image
  MyIMage=NewImage(128,128,2)
  RenderToImage MyIMage
  For lp =0 To 10
     x1=Rnd(128)
     y1=Rnd(128)
     x2=Rnd(128)
     y2=Rnd(128)
     Line x1,y1,x2,y2
  Next
  
  
  
; Create a sprite2
  Spr1=NewSprite(80,100,MyImage)
  SpriteDrawMode Spr1,2
  CenterSpriteHandle spr1
  ScaleSprite spr1,0.5
  
  Spr2=NewSprite(200,100,MyImage)
  SpriteDrawMode Spr2,2
  CenterSpriteHandle spr2
  ScaleSprite spr2,1
  
  Spr3=NewSprite(400,100,MyImage)
  SpriteDrawMode Spr3,2
  CenterSpriteHandle spr3
  ScaleSprite spr3,1.5
  
; redirect drawing to the screen
  RenderToScreen
  
  SetFPS 60
  
  Do
     Cls
     
     TurnSprite Spr1, 0.25
     TurnSprite Spr2, 0.25
     TurnSprite Spr3, 0.25
     
     DrawAllSprites
     Sync
  Loop
  
  







      From the picture, we can clearly see the linear rotation / scaling process is quite a destructive one. If we were using the sprite on the left and expecting high quality impacts from it, when rotated or scaled, then we're sadly going to be disappointed. A better solution in this case, would actually be to use shape collision, which doesn't suffer from such the artifacts when rotated. Now this also works the other way too, as some times we'll have big chunky character sprites and don't mind if they're not super accurate. Basically the bigger the sprites, the more work the sprite engine needs to generally do in order to detect an impact.

     For these types of situations, we've added a global accuracy setting to the sprite engine, just for pixel to pixel collisions modes called SpriteCollisionAccuracy. What this command does, is it let's the programmer tweak the quality of the images, by scaling them up or down. Setting the accuracy down to 0.5 say, makes the engine halve the size of the sprites when comparing them at pixel to pixel level. So by reducing the quality, we also reduce the amount of work the collision engine might need to do, in order to resolve such pixel to pixel collisions. Alternatively, if we raise the accuracy value above one, this would scale the sprites up. So if we set the accuracy to 2.0, then we'd be doubling the size of the rotated/scaled sprite image, which can help reduce linear rotation/scaling artifacts. So that'd make our lines example above work better, but it'd also make our collision detection slower. So there's no one easy 'one solution' fits mode.


     Pixel Collision Example

      Bellow we have a version of our running collision example set up to use pixel collision mode. From the code point of view, all we need do, is tell the sprite to use the Pixel Perfect collision mode. There is one other important thing we'll need to when loading our SHIP image. Which is we must load the image into memory in either FX or AFX format. Why ? - Well the reason for this a pretty low level one, but we could summarized it by saying that pixel level collisions are calculated using the your computer main processor (CPU), and in order to keep this calculation as fast as possible, it prefers to access image pixels stored in your computers main system memory. You can detect collisions against Video images, but that forces the main CPU to read video memory which is up to 20->30 times slower. (See Images)

      Cut'n'paste this example into PB and hit f5 to execute. Press ESC to exit the running demo.

  
  
; Get Max FPS
  SetFPS 60.0
  
; calc the path of Media files in the help
  path$=ProgramDir$()+"\Help\Commands/Media/"
  
; Load our ship image in FX format since
; we're going to rotate it real time
  ShipIMage=     LoadNewImage(Path$+"ship.bmp",2)
  
  
;*=--------------------------------------------=*
; Set up Sprites
;*=--------------------------------------------=*
  
  
; Create the Bad guy sprite, giving it the position
; of 400x, 300Y using the SHIPIMAGE
  BadGuy= NewSprite(400,300,ShipIMage)
  
; Set up this sprite to circle with a radius of 30
  InitSprite(BadGuy,30)
  
  
; Create the PLAYER sprite, giving it the position
; of 0x, 0Y using the SHIPIMAGE
  Player= NewSprite(0,0,ShipIMage)
  
; Set up this sprite to circle with a radius of 50
  InitSprite(Player,50)
  
  
  
;*=--------------------------------------------=*
; MAIN LOOP
;*=--------------------------------------------=*
  
  Do
     
   ; Clear the Screen to black
     Cls
     
     
   ; Position the Player Sprite at the Mouse coordinates
     PositionSprite PLayer, MouseX(), MouseY()
     
   ; Turn the Player and Badguy
     TurnSprite Player, 1
     TurnSprite BadGuy, 0.25
     
     
   ; Check for a collision between the
   ; Player and the Bad Guy sprite
     If SpritesOverlap(PLayer,Badguy)=true
        
      ; render text message if there's
      ; a collision
        CenterText 400,200,"Sprites Have Collided"
        
     EndIf
     
     
   ; Tell PlayBASIC to render all the Sprites
     DrawAllSprites
     
   ; Show the newly drawn scene to the player
     Sync
     
   ; loop back to the DO, until the ESC key is pressed
  Loop EscKey()=true
  
  
Function InitSprite(ThisSprite,RAdius)
  
; Enable Rotation mode in the sprite
  SpriteDrawMode ThisSprite , 2
  
; Set Sprite To PIXEL PERFECT Collision Mode
  SpriteCollisionMode ThisSprite, 6
  
; Enable debug mode for the bad guy sprite
  SpriteCollisionDebug ThisSprite,true
  
; Center Rotation Handle
  CenterSpriteHandle ThisSprite
  
EndFunction
  
  
  


      Bellow we have a close up shot of what an impact looks look. You'll notice that like previous examples, sprite debug mode is enabled, which is useful as a visual indication of what the sprite engine is actually comparing the sprites at pixel level. We can tell this as it's compares the red boxes first, then the white boxes, and only when they overlap it compares the pixels.






      Here's and animation, just to give you and idea of what the demo does.






Top








Sprite Engine Render Process


      If you're looked through the sprite command set you'll notice there's a number of methods that can be combined together. For example, you could happily Rotate, Filter, Tint and Alpha blend a sprite. Moreover it'll even support reading and writing to different image formats. This is made possible because the PlayBASIC Sprite Engine tries to handle all combinations of drawmodes as seamlessly as possible for you. If it can't, then the combination will most likely produce nothing as it's output.


      The actual sprite engine in PlayBASIC V1.64 is based around a three stage concept, which can be classified as Fetch Pixel, Modify Pixels and Write Pixels. It's this separation that allows us to mix the various input formats, blenders and output formats together.

     Stage 1) Fetch Pixels In the fetch stage, the engine reads the pixel data from the sprites image. it rotates/scales/clips and filters out mask colour/or any completely transparent pixels from the source data. So we're left with a series of pixels to be passed onto the modify stage. When filtering is enabled (See SpriteFilter) the fetch process prefilters the pixel data from the sprites image.

     Stage 2) Modify Pixels The modifier stage is as the name suggests and is optional. It's in this stage that the fetched pixel data is altered. So if you set SpriteTint, then the engine would run the Tint modifier over the pixel data.

      The same as many of the SpriteDrawMode mode's which will be applied here. So they're applied after the pixel data is fetched form the sprite image. This means that we can modify the image without breaking the sprites mask colour.

     Stage 3) Write Pixels The write stage takes the pixel data and renders it to the destination the surface. Effectively stamping this sprite into the destination. The default write mode is solid (opaque), so pixels are written as is, other write modes are Variable Alpha Blend, Alpha 50, Alpha Addition and Alpha Subtraction (See SpriteDrawMode) - These modes are output modes, so they take the pixels data after it's been through the previous stages and write/blend it to the output.

      The stage approach allows the sprite engine to support many variations without having to hard code every possible render combination into the engine, which is what older version of PlayBASIC did. Having said that, the engine tries to optimize your sprite draw modes the best it can, but using hard coded versions of the most common draw mode combinations. It also includes support for power of two sized images. Which can be handy when trying to squeeze out that little be extra performance.


Top







History


      For those with a long gaming history, or perhaps previous game programming experience, are most likely familiar with the term sprite, from retro (8/16 bit) computing / game console and arcade hardware, then you're probably familiar with the concept of Hardware Sprites. Traditionally most retro video game systems used hardware sprites, where modern computer systems use software sprites.

      Conceptually it can be little difficult to explain the difference. But the fundamental difference is that systems that offer Hardware sprites, treat the screen and the sprites as entirely separate layers. To visualize it, each sprites becomes like transparent overlay stacked on top of the screen image.

      This has some great advantages and some pitfalls also. The main benefit of true hardware sprites is speed, since they're never part of the screen the game never has to merge the images pixel data together. Making this approach the most viable on classic arcade and computer/console hardware with slow processors. The down side with them, is they're often very limited. Since the graphics chip will have a physical limit to the number of sprites on screen, as well as colour and size restrictions.

      One example that comes to mind would be the commodore C64 and Amiga systems. The Commodore 64 supports 8 hardware sprites for your on screen characters. Which for early games could often be enough, But what if you wanted more than 8 characters on screens at once ? - Well, then the game developer had to resort to more complex raster programming. Which is a method where the programmer creates the illusion of more sprites on screen at once, by repositioning previously used sprites at the top of the screen, further down the display while the video hardware is displaying the screen. Which works, but it's also problematic, in that you can never display more than the hardware limit in one zone and if often causes sprites to flicker.

      The Amiga computer systems also only supports 8 hardware sprites. But unlike it's older cousin the C64, this limitation is more easily overcome, By using a mixture of hardware and software sprites, or BOBs (Blitter Objects) as they're often called on the Amiga.

      A software sprite is a manually processed image, so the programmer makes computer draw the required image (like our game character for example) onto the screen at the required coordinates. Once it's drawn there, it becomes part of the screen . You can visualize software sprites much like we're stamping our image into a sheet of paper. While we can stamp our image as many times as we'd like and in any location, Once it's drawn there, we can't easily remove it. So software sprites solutions either require the screen to redrawn or implement some way to restoring the backdrop picture between refreshes.

      On the surface, it may seem that software sprites don't stack up against native hardware sprites, since the programmer has more work for the same end result, But the software sprites offer a greater flexibility than hardware sprites ever could. Such as, programmers are not limited to any fixed by size, colour or even visual effect, and software solutions allow us to render as many as we need. The down side, is that they introduce rendering overhead to our program. To combat this, modern computers/game consoles include special hardware to aid in sprite rendering, in both the CPU and GPU.

Top








 
Related Info: CameraBasics | CreateSprite | Images | Loops | Maps | Types | Variables :
 


(c) Copyright 2002 - 2024 - Kevin Picone - PlayBASIC.com