#!/usr/bin/perl -w # # Copyright 2000 by Michael Coyle # Released under GPL. # # Call it with: # [an error occurred while processing this directive] # # Get the file name from the browser... $file_name = $ENV{'QUERY_STRING'}; # Open the file... open (EP, $file_name); # Print to the browser... print "Content-Type: text/html \n\n"; # Load the file and keep spitting it out to the browser... while () { chomp; print "$_ "; } # Close the file and go home... close EP #!/usr/bin/perl -w # # Copyright 2000 by Michael Coyle # Released under GPL. # # Call it with: # [an error occurred while processing this directive] # # Get the file name from the browser... $file_name = $ENV{'QUERY_STRING'}; # Open the file... open (EP, $file_name); # Print to the browser... print "Content-Type: text/html \n\n"; # Load the file and keep spitting it out to the browser... while () { chomp; print "$_ "; } # Close the file and go home... close EP

3D
3D Photo Gallery (Part 1)
3D Photo Gallery (Part 2)

Audio
Poor Man's MIDI
Make A Metronome
iPod Tricks (Part 1)
iPod Tricks (Part 2)
iPod Tricks (Part 3)
Laugh Track Machine
Audio Player with Reverb
Shepard Melody
RB Phone Home
Build a Drum Machine

Custom Controls and Windows
Double Click Listbox
Draggable Metal Window
Double Click Canvas
Custom Buttons
Custom Buttons Part II
iTunes-style Listboxes
Custom Controls


General RB
Scrolling Windows
Using Mesage Dialogs
Case-Sensitive Word Finder
Introduction to Stacks
Wiggle Window
JPEG in PDF
Listbox Checkboxes
Background Applications
Listbox Auto-Find
Virtual Volumes
Time Tracker
Software Distribution (Part 1)
Software Distribution (Part 2)
Software Distribution (Part 3)
Software Distribution (Part 4)
Exceptions
Tips and Tricks
Text Clippings Made Easy

Graphics
Drawing a Simple Gradient
The SpriteSurface: Space Game
Image Spinner
Cropping Graphics (Part 1)
Cropping Graphics (Part 2)
Cropping Graphics (Part 3)
Cropping Graphics (Part 4)
Shimmer Graphics
Lissajous Figures
Simple Screen Capture
Vector Graphics
Kaleidoscope Images
Stegonography
Spirals!
Image Table
RB Magnifying Lens
Screen Capture
Color Picker Tutorial

Hacks
Ghost Grab
Speedy Mouse Extension
iTunes Plugins
iTunes Skinner

Mac OS X
Global Hot Key Event (Carbon Events)
Login Welcomer (Carbon Events)
Add/Remove Buttons
Resizable Sheets
Mac OS X Preferences Window
Using Sheets in REALbasic
Build a Bundle (Part 1)
Build a Bundle (Part 2)
Dock Your Passwords
Mac OS X Debugging
REALbasic Mac OS X Icon Tutorial
Animate Your Dock
RB and the Command Line

Menus
Window Menu
Templates Menu
Listbox Menu

Novelty
Guessing Game
Calendar Trivia
Tile Mixer
Zip Code Finder
Happy Valentine's Day
Merlin Simulator (Part 1)
Merlin Simulator (Part 2)
Merlin Simulator (Part 3)
Buzzword Machine
AppleSoft BASIC

Printing
Print to PDF

Registration
Registration Code Validation
Network Registration Codes

Resources
Picture Extractor (Part 1)
Picture Extractor (Part 2)

Serial
Caller ID (Part 1)
Caller ID (Part 2)
Caller ID (Part 3)

Speech
Speech Recognition

Socket Communication
Easy Peer-to-Peer File Sharing
MacPAD Version Checking
Display Web Image In Canvas
HTML IMG Tags
Version Tracking
Even Smarter Instant Messaging
Web Tiler
JavaScript and REALbasic
Stock Ticker (Part I)
Stock Ticker (Part 2)
AIM Mate

XML Manipulation
Simple XML Introduction

Video
Big Brother Video Capture

Note: All articles without a byline were written by Erick Tejkowski. When cleaning the site I removed them because the code differed from page to page, and I have yet to put them back in.

resexc2.gif (20k)




REALbasic for Dummies
by Erick Tejkowski

$19.99 @ Amazon





Files are in Stuffit 6.5 or earlier, or ZIP format.
Download Stuffit Expander

Tell us about a bad link.

Introduction to SpriteSurfaces by Seth Willits
11-13-03




The SpriteSurface control is a fairly power animation system for two-dimensional (2d) graphics. Although it may not be king of the mountain for any and every 2d game, it certainly deserves a good look as it can accomplish a lot if used cleverly.

A "SpriteSurface" is an area of the screen in which images are moved around on the screen independently of the background. These images, or "sprites," are typically characters or objects such as the ghosts in PacMan or a boomerang thrown by Link in the Legends of Zelda. To create the illusion of seamless movement, a SpriteSurface runs, or redraws, at a specified rate which is typically about 20-40 frames per second depending on the type of game. On each redraw or "frame" of the animation, the sprites may move a certain small distance and/or change its image. For example, the PacMan sprite changes its image by opening and closing it's mouth (or what I assume is supposed to be a mouth) a tiny portion on each frame. When the sprite's image is changed fast enough or moves a short distance on the screen several times in very quick succession, our eyes are fooled into believing that we're seeing a smooth movement.


The frames of a PacMan sprite.

The SpriteSurface class in REALbasic is a RectControl subclass which must be embedded in a window. In REALbasic 2.x and earlier, the SpriteSurface was a bit different and would essentially create it's own window, but in 3.0, it behaves in the same manner as any other RectControl such as a PushButton or canvas. The objects which move around inside of our SpriteSurface, our sprites, are implemented through the Sprite class. Sprites are attached to a SpriteSurface and thereafter are involved in any collisions that happen in and all drawing that the SpriteSurface does.

If you drag a SpriteSurface instance to a window, you will see some of its properties in the Properties window. There are of course the standard left, top, width, and height properties, but there are also SurfaceLeft, SurfaceTop, SurfaceWidth, and SurfaceHeight properties. What are they, and what do they do? Well, they're actually carry overs from the previous SpriteSurface implementation and no longer do anything. You can completely ignore them. Although they maybe the same values as left, top, width, and height, don't count it because they can be changed at anytime.

Other properties include Backdrop, which is a picture just as in a Canvas, Depth, which is the bit depth of the surface (8 is 256 colors, 16 is 65k colors, and 32 is millions), FrameSpeed, and ClickToStop. The last two properties, FrameSpeed and ClickToStop, are related in that they both only affect the SpriteSurface if its Run method is called which brings us to our next point.

The SpriteSurface in REALbasic can be driven in one of two ways. I can be ran with the Run method, or it can be updating using the Update method. Run is a synchronous method which will halt all processing in your application, enter a tight loop, and continue to redraw the surface at a specified rate, which is (60/FrameSpeed) times a second. So if you set the FrameSpeed property of a SpriteSurface to 2, then the surface will run at 30 frames per second. The ClickToStop property allows the end user to be able to click the mouse button to make the SpriteSurface stop animating. If the CickToStop property is unchecked, then the programer (you), has to at some point call the SpriteSurface's Stop method from within the NextFrame event.

What's the NextFrame event, you say? Well, in order to animate any of the sprites within our SpriteSurface we need an event which is fired before each time the SpriteSurface redraws. Inside of this event is where we would make changes to our sprite's properties such as position after the player presses a key, or the image when the game character dies. After we're done making any changes we want to make for that particular frame, the SpriteSurface then draws itself onto the screen.

What the Run method does is enter a loop which continually calls the NextFrame event, checks for collisions (and if any occur, the Collision event is fired), and then draws to the screen. The second way to drive a SpriteSurface is to use our own loop and continually call the Update method of the surface. The update method is the same thing as one iteration of the make believe look that the Run method uses. Each time Update is called, the NextFrame event is fired, the surface checks for collisions, fires the Collision event if needed, and then draws to the screen. Simple. To compare the Run and Update methods, consider the following bits of code:

Sub Action()
SpriteSurface.ClickToStop = true
SpriteSurface.Run
End Sub

Sub Action()
do
SpriteSurface.Update
while System.MouseDown = false
End Sub

These two pieces of code function in the same way except for one. The top method will make the surface run at 60/FrameSpeed frames per second, but the bottom method will make the surface run as fast as it possibly can, and both stop when the user clicks the mouse. The flexibility of using the Update method gives you a little bit more control as you can write code which calls invokes a redraw of the surface exactly when you want it to, but they really are the same for all practical purposes. The Update method allows you to update the surface one frame at a time if you wish. So which should you use? It's up to you.


Alright, so we're just going to get our hands wet today, so drag a spritesurface to a window and resize it to be 640 pixels wide and 480 tall and fit exactly into a 640x480 window. Set FrameSpeed to 2 (which will give us 30 frames per second) and make sure that ClickToStop is checked. Next, create a menu item in the File menu named "Run" and implement a menu handler in the same window as the spritesurface for the menu item and use the following code:
Function Action As Boolean
SpriteSurface1.Run
End Function


If you run the project and select Run from the File menu, you should see absolutely nothing happen. If you wait, your cursor may turn into a spinning beachball or watch, but that's it. The black still stays black, but that black is being drawn by a sprite surface! Pretty cool huh? No. It's not. So lets make it cool.

In many games there's a background which we're always looking at and which the characters are on top of. In asteroids, we're looking at space, in Mario we're looking at the sky and clouds. Well the background in this games is usually just a single image which doesn't change but moves. For this tutorial we're going to drop in a background and make it move. So go ahead and download this image, rename it "Space.jpg", and drop it inside of your REALbasic project.


Control/Right-Click the image to save it.

Next, set the the Background property of the spritesurface in the Properties Window to the "Space" image. The background is exactly as you'd expect. It's the background of whatever is drawn to the spritesurface. Anything drawn in the surface including sprites will always appear in front of the background.

If you run the project again, you'll now see the space background in the window. Well, it's a little nicer now, at least we know something's being drawn, but lets make it move! The SpriteSurface class has a handy method (although demanding on the CPU) called "Scroll" which is very similar to the canvas' Scroll(dx, dy) method. Scroll takes two integer values, an "x" delta, and a "y" delta. The dx and dy passed to Scroll determine in which direction and to what degree the SpriteSurface's background and all objects inside of it are moved. If you were to pass scroll (-1, 2), then the background and objects would move 10 pixels to the right and 2 pixels up. When you use small numbers like this and have a relatively high frame rate, then the movement of the surface will look smooth. This effect is used all over. In fact, most 2d platform games (Super Mario Bros, Megaman, Captain Bumper, etc.) use it.

So how can we scroll? Remember that the NextFrame event is fired for each time the SpriteSurface is redrawn. So if we place "me.Scroll 1, 0" in the NextFrame event of the SpriteSurface, then for each of the 30 frames per second that our surface updates, the surface will scroll one pixel to the left and not move vertically.

I realize this is a very short introduction to sprite surfaces, but you've got to start somewhere! Next week we'll learn about sprites and begin to actually build something interesting!


SpriteSurfaces Part II



In the next "n" tutorials, we're going to be creating a very basic Space Invaders-like game in order to introduce you to the ideas of sprite animation. First, download the project I've written. It's a completed project with all of the necessary images included, so you can build it right out of the box if you want.



Starting and Stopping

The first thing every animation needs is a loop which drives the animation. In the last tutorial I breifly covered the Run method, but in this tutorial we're going to make our own. Out of all of the things I'll do in this tutorial which are against "good" design (good being whatever I think it is ;^) I'm going to actually use this one. Instead of using the Run method, I always make my own variation which looks similar to this:

Sub RunGame()
    dim lastFrameTime, frameTime as Double
   
    /// Set FPS for surface
    frameTime = 1000000 / 30 '1sec / 30fps
   
    /// Run game
    gDone = false
    do
       if Microseconds - lastFrameTime >= frameTime then
          Surface.Update
          lastFrameTime = Microseconds
       end if
    loop until gDone
End Sub

Now the above code is really no different than the Run method with the surface's FrameSpeed property set to 2; It calculates the minimum time which should pass between updates (frameTime) and then enters a loop which updates the sprite surface only when the time has passed. It's not this code, but variations of it will have its advantages. In our project, we're going to write all of the "game" code in the NextFrame event, the event that is called before a frame is drawn. In other projects, the task of updating the objects in the world are/may be separated from the event of a frame drawing. The purpose of this would be to set a priority for whether the objects in the world should update or whether they should be drawn. In a physics simulation which is being recorded to disk, the updating of the objects is more critical than actually seeing the objects. However in a speed-critical situation, you could give more time to drawing. How much time to give to what depends on what you're doing and warrants at topic on its own, but for the most part, a 1:1 update ratio should work out fine.

You may have noticed the gDone variable used in the code above which is a boolean property of the window that the sprite surface Surface is in. The game's animation will run as long as this property is false, thus in order to stop the game, we set it to true which is done with our StopGame method:

   Sub StopGame()
    gDone = true
   End Sub



Creating the Player

The other critical part of an animation is having something to animate. In Main window, there is a property "PlayerShip as Sprite". Recall from the previous article that the Sprite property is the base class representing an object which is being animated. REALbasic Sprites have a few properties. The have an Image, X and Y positions, Group, and Priority. The Image property is the current image of the sprite and X and Y make up the position in the surface at which the sprite's image is being drawn. The Priority values of sprites determine what order the sprites are drawn in on each frame. A lower Priority value (closer to 0) means that the sprite is drawn before (and thus under or behind) other sprites. The Group value determines whether and who the sprite collides with. Only sprites with different Group values will collide and cause the Collision event to fire with the exception of sprites with a Group value of 0. If the value is 0, then the sprite cannot collide with any other sprite. We will use the group property in a later tutorial.

Sub Open()
    // Surface Background
    Surface.Backdrop = PicSpace
   
    // Create PlayerShip
    PlayerShip = New Sprite
    PlayerShip.Image = PicShipCenter
    PlayerShip.Group = 1
    PlayerShip.X = Surface.Width/2 - PicShipCenter.Width/2
    PlayerShip.Y = Surface.Height - 70
    Surface.Attach PlayerShip
End Sub

In the Open event of the sprite surface named Surface, we create a new sprite for PlayerShip and assign it an image, group, and position (priority doesn't matter to us). Since a sprite must have at least one image but does not have to have more, there is only a single Image property in the Sprite class. In our project however, we want the space ship's image to change depending on the direction it is moving. To accomplish this, we begin by setting the image the ship's stationary image, and when the player presses a key to move left or right, we will change the Image property's value and change it back if no key is held down.

The last step when creating a sprite is to attach it to the sprite surface it will be used in by using the surface's Attach method. What this does is let the surface know that the given sprite should be drawn in the surface. If you don't attach a sprite to a surface, you'll never seen it drawn.



Moving Sprites

To move the sprites attached to a surface, we move them in the NextFrame event. (The code which does this for our Space Invaders clone is already in the NextFrame event in the downloadable project. It's also below, but the order in which it's given is different than the order in the project. It's differen below for the purposes of explaination.)

One of the first things you should account for when writing a game, is making a way to stop it. To do this you pretty much will always need to determine if the user is doing something (holding down a key or the mouse button) unless you want to set a time limit or simply have the user unplug their computer when they want the game to stop. To determine whether the user is holding down a certain key or not, we use the SpriteSurface class' KeyTest() method. The KeyTest() method accepts a single parameter, a number representing the key code for the key, and returns a boolean variable which is true if the key is currently being held down. Key codes for keys are NOT the ASCII value. Instead it is a number unique to the key's position on the keyboard. The reason that the KeyTest() method asks for a KeyCode rather than ASCII value is so that the '1' in the number pad will have a different key code than the '1' above the 'Q'.

To stop the game in this project, we will test for the Escape key being held down and if it is, we'll call the StopGame method which will then set gDone to false which will make the animation loop in RunGame end.

/////////// Escape key ///////////
if me.KeyTest(&h35) then
   StopGame
end if

As you can see, the key code for the Escape key is 53, or 35 in hexadecimal. The key code values for all of the keys on the QWERTY and DVORAK keyboards can be found in the User Guide at the end of the "Work with Text and Graphics" section.

Other instances in which we want to test for keys being pressed is the player pressing the right and left arrow keys to move the ship right and left.

//////////// User Input ///////////
Const kShipSpeed = 8
if me.KeyTest(&h7B) then // Left
  PlayerShip.X = PlayerShip.X - kShipSpeed
  if PlayerShip.X < 0 then
    PlayerShip.X = 0
  end if
  PlayerShip.Image = PicShipLeft
elseif me.KeyTest(&h7C) then // Right
  PlayerShip.X = PlayerShip.X + kShipSpeed
  if PlayerShip.X > Surface.Width - PlayerShip.Image.Width then
    PlayerShip.X = Surface.Width - PlayerShip.Image.Width
  end if
  PlayerShip.Image = PicShipRight
else
  PlayerShip.Image = PicShipCenter
end if

Above, we test for the key codes &h7B and &h7C which lets us know if the left and right arrow keys are being held down respectively. In either case we move the ship a specified amount of pixels (kShipSpeed) to the right or left, and then check to make sure that the ship is within the boundaries of the surface. If the ship goes outside of the surface, we move it back inside. The last line of code in either case sets the image of the PlayerShip sprite to the the left-banking or right-banking ship image. In the case that neither key is being held down, we set the image to the stationary PicShipCenter image so that the ship does not appear to be moving.

So now we have a ship, moving left and right in our sprite surface. It's not much, but we're pretty close to getting the basics of a game implemented. All that is left is to add bullets which are fired from the ship (see if you can do it! Most of what you need to know is already done in the project) and finally making obstacles appear in the way of the player which (s)he must shoot.


SpriteSurfaces Part III



The last two pieces of our Space Invaders-like game is to make our ship fire and have enemy ships come down from the top of the window and the two are remarkably similar. At the moment we have our space background in place and we have a working spritesurface which shows our player's space ship which we can move using the arrow keys. The completed game is only about 100 lines of code and we're well on our way there, so lets get started.

The first thing you should do is resize the window and sprite surface to be 540 x 600 or something where the window is narrower than it is tall. The standard 640 x 480 works, but it's too wide and stubby for my taste.

Okay, so bullets... The general concept behind projectiles is, you test for a certain key being pressed (we'll use the spacebar) and you fire a projectile, a bullet. (Obviously!) However, there are two things you need to consider before firing. 1) Do I have a bullet to shoot? 2) Am I able to shoot, or is it too soon after my last shot?

The first consideration is really your prerogative. Many shoot 'em up games have unlimited ammo so it's nothing but pure non-stop bloody mahem for the player. Generally, you want to give the player enough ammo so they don't have to be a sniper to pass a level, but you want to limit what they have so they can't simply beat the game by holding down the fire key all the time.

The second consideration is critical. If your game is running at 60 frames per second and on each frame you test for the fire key being pressed, you'd be sending bullets out every 60th of a second unless you limit the rate of fire. Machine guns don't even fire that fast!

After you've established that a bullet can be fired it's put into its initial position (right at the end of the barrel, or simply infront of the ship in our case), then on each passing frame, the bullet is moved a certain amount of pixels in the direction of where the gun was pointed; up, in our case. After the bullet is moved in each frame, you should also test whether the bullet is still in the visible area. If the bullet is outside of the visible area, then there's no point in using it any longer so we remove it from the spritesurface using the Sprite.Close method.

Enemy ships, work in a very similar fasion. Instead of the ships being triggered by a key being pressed, ships are triggered by time. What we do is set a random time in the future which a ship will be sent towards the player. After the ship is sent, we set the random time for which the next ship will be sent. Similar to the bullets, we want to 1) test for the ship trigger rate (don't want them coming at us in too big of swarms!), 2) update the ships' positions on each frame, and 3) check to make sure that the ship is still visible and if it isn't, destroy it.

Checking for collisions between a bullet and an enemy ship is easily done. Recall that in the previous tutorial we said that the Group value determines whether a sprite collides with other sprites, and who the sprite collides with. Remember that only sprites with different Group values will collide and cause the Collision event to fire and that the Group values must not be 0 for the sprites to collide.

In our game, we will set the bullets' Group values to 2 and the enemy ships' Group values to 3. This way whenever a bullet and an enemy ship collide the Collision event of the sprite surface is fired. When a collision occurs, we will remove both of the sprites from the sprite surface (again, using the Close event) and beep so that we know they hit.

That's all there is to it! It's simple enough once you've done it, so let's get to it. Hooah!


Implementation

First, lets cover the constants we'll be using:

  Const kShipSpeed = 12
  Const kBulletSpeed = 16
  Const kMaxBullets = 82
  Const kBulletTime = 100000
  Const kMaxEnemyTime = 1500000
  Const kMaxEnemies = 7
  Const kEnemySpeed = 14

kShipSpeed: the speed the player's ship moves side to side (pixels per frame).
kBulletSpeed: the speed the player's bullets travel (pixels per frame)
kMaxBullets: the most number of bullets the player can shoot at a time
kBulletTime: the minimum time that must pass (in microseconds) between firing
kMaxEnemyTime: the maximum time (in microseconds) that passes between enemy ships appearing
kEnemies: the maximum number of enemies that can be on the screen at the same time
kEnemySpeed: the speed that the enemy ships move towards the players (pixels per frame)

Next we're going to need four new window properties:

  Bullets(-1) as Sprite
  Enemies(-1) as Sprite
  LastBulletFired as double
  NextEnemyTime as double

The Bullets() and Enemies() arrays hold sprites which represent the bullets and enemy ships currently in the sprite surface. LastBulletFired is the time that the last bullet was fired by the player, and NextEnemyTime is the random time in the future that specifies when the next ship will be shown.

The chunk of code below tests for the spacebar being held down and executes if it is true. The nested if statment checks to see that the maximum number of bullets have not been fired, and that the minimum time has passed since the last shot. The code inside the if statement creates a new sprite for the bullet, gives it the bullet image, centers it just above the player's ship, adds it to the Bullets() array so we can keep track of it in each frame, attaches it to the sprite surface, and then sets the time the bullet was fired.

/// Player shoots
if me.KeyTest(&h31) then
  if UBound(Bullets) <> kMaxBullets - 1 and Microseconds - LastBulletFired > kBulletTime then
    bullet = New Sprite
    bullet.Image = PicBullet
    bullet.Group = 2
    bullet.X = PlayerShip.X + PlayerShip.Image.Width / 2 - bullet.Image.Width / 2
    bullet.Y = PlayerShip.Y - 15
    Bullets.Append bullet
    Surface.Attach bullet
    LastBulletFired = Microseconds
  end if
end if

Moving bullets is pretty simple. The code below loops through the Bullets() array (which contains Sprites for all of the bullets that have been fired and are currently in the sprite surface) and moves them up towards the top of the surface. It then tests whether the y value of the bullet sprite is less than or equal to 0 minus the bullets height. When it is, this means that the bullet is enough outside of the top of the sprite surface that it can't be seen and thus should be removed from the sprite surface and the Bullets() array which is what the next two lines of code do. Removing the bullet from the array lets us "reclaim" the bullet so the player can fire another bullet.


/////////// Move Bullets //////////
for index = UBound(Bullets) DownTo 0
  bullet = Bullets(index)
  bullet.y = bullet.y - kBulletSpeed
  if bullet.y <= - PicBullet.Height then
    bullet.Close
    Bullets.Remove index
  end if
next

Moving enemies, as I said, is very similar to moving the bullets. Instead of checking for the enemy ship to be outside of the top of the surface, we check to see whether the ship's y value is greater than or equal to the height of the surface meaning it is below the surface and can't be seen. The code to move the enemy ships is in the for loop at the bottom of the code chunk below.

///////////// Enemies /////////////
if UBound(enemies) < kMaxEnemies - 1 and Microseconds >= NextEnemyTime then
  enemy = New Sprite
  enemy.Image = PicEnemyShip
  enemy.Group = 3
  enemy.X = rnd * (self.Width - enemy.Image.Width)
  enemy.Y = - enemy.Image.Height
  Enemies.Append enemy
  Surface.Attach enemy
  NextEnemyTime = Microseconds + rnd * kMaxEnemyTime
end if
for index = UBound(Enemies) DownTo 0
  enemy = Enemies(index)
  enemy.y = enemy.y + kEnemySpeed
  if enemy.y >= self.Height then
    enemy.Close
    Enemies.Remove index
  end if
next

Within the if statement above the for loop lies the code which creates enemy ships. The conditional in the if statement checks to see if the maximum number of ships is not currently on the screen and that the time that the next enemy ship should be released has come. In the case that both are true, an enemy ship is created, its group is set to 3 (so that it collides with Group 2 which is our bullets), it is positioned above the top of the surface so that it comes into the surface instead of magically appearing in it, places it at a random x location between 0 and the width of the surface - the width of the ship (that way it does appear half or more off the right side of the surface), attaches it to the surface, adds it to the Enemies array and then creates a time for the next ship to be released.

The last lines of code to be written handle the collision between a bullet and an enemy ship. The Collision event has two parameters, s1 and s2 which are both sprites. The tricky thing about the Collision event is that you don't know what sprite s1 or s2 are. In our case s1 could be the bullet and s2 could be the ship, or s1 could be the ship and s2 could be the bullet. We don't know how it will turn out to be, so what we do is test to see how it is. In this case, we can test the sprites' Group property values. If it is a 3, then it is an enemy ship. If it is a 2, it is a bullet. What we do for both ships and and bullets is exactly the same, we remove it from the array its in and we remove it from the sprite surface. It's that simple.

Sub Collision(s1 as Sprite, s2 as Sprite)
  dim index as integer
  dim enemy, bullet as sprite
  
  // Which sprite is which?
  if s1.Group = 3 and s2.Group = 2 then
    enemy = s1
    bullet = s2
  elseif s2.Group = 3 and s1.Group = 2 then
    enemy = s2
    bullet = s1
  end if
  
  // Remove enemy
  for index = UBound(Enemies) DownTo 0
    if Enemies(index) = enemy then
      Enemies.Remove index
      enemy.Close
    end if
  next
  
  // Remove Bullet
  for index = UBound(Bullets) DownTo 0
    if Bullets(index) = bullet then
      Bullets.Remove index
      bullet.Close
    end if
  next
  
  
  // Make noise
   beep
End Sub

If you've made it this far, congratulations. Sprite animation is simple but only once you understand it, and understanding it really takes a lot of fiddling. That's how I figured it out. Yep. Aaaaaall by myself. No help at all.... yup... All those times I asked the mailing list those questions, I was just confirming what I suspected... yeah... that's it. I wasn't asking them how to do anything. :^)






Please support ResExcellence by Visiting our Sponsors. One click makes a difference.


Download REALbasic and create your own software!

#!/usr/bin/perl -w # # Copyright 2000 by Michael Coyle # Released under GPL. # # Call it with: # [an error occurred while processing this directive] # # Get the file name from the browser... $file_name = $ENV{'QUERY_STRING'}; # Open the file... open (EP, $file_name); # Print to the browser... print "Content-Type: text/html \n\n"; # Load the file and keep spitting it out to the browser... while () { chomp; print "$_ "; } # Close the file and go home... close EP #!/usr/bin/perl -w # # Copyright 2000 by Michael Coyle # Released under GPL. # # Call it with: # [an error occurred while processing this directive] # # Get the file name from the browser... $file_name = $ENV{'QUERY_STRING'}; # Open the file... open (EP, $file_name); # Print to the browser... print "Content-Type: text/html \n\n"; # Load the file and keep spitting it out to the browser... while () { chomp; print "$_ "; } # Close the file and go home... close EP