Blitz2D Intermediates: 2D Space Physics and More BlitzBasic
by Krylar

Introduction:

One thing that I've always wanted to do is put a little 2D ship up and have it fly around on a parallaxing star field and have some halfway decent physics. I've studied a number of pieces of code to accomplish this and have taken various suggestions and just plain messed with ideas in my own head.

First off I'd like to thank the following folks for helping me...I've used a little bit from each of them to figure this out and they got me as far as getting the ship moving with the Sin and Cos functions. So...thanks to:

  • "FlameDuck" from the www.blitzbasic.com board for the plane demo
  • "BlitzSupport" from the www.blitzbasic.com board for the Depravity Engine demo
  • "ncsu121978" from the www.gamedev.net board for the tips

Please forgive me if my math descriptions are lacking or worse. I'm not the best at math and I'm even worse at trying to describe it. Much of the Sin/Cos stuff you'll see here I picked up as tips from those folks above and/or from the TLC Trigonometry CD I've got ;)

The source included herein is written using BlitzBasic. You can certainly get the point of the code without using BlitzBasic, but I'd highly recommend you try this increadible engine out! If you're interested in seeing all this in action, please grab the latest version of BlitzBasic by going to the BlitzBasic Website. You'll also need to have DirectX 7.0 or higher. If you want to understand some, er, Basics on BlitzBasic, check out the Getting Started with BlitzBasic article.

Quick note, I'll likely use "BB" in place of writing "BlitzBasic" everywhere...so now you'll know what that means ;)

Using Sin/Cos to get X, Y angle data

In order to get a ship moving at a particular angle with a balanced thrust, you'll need to use the Sin and Cos functions. Simply pass them your ship's direction multiplied by 10 and you'll get a floating point value. Multiply that value to the thrust in order to move the ship properly.

Now you can either do this calculation real-time (slow) or you can setup a table when your program launches. I decided on option two for mine...here's the code:


Top speeds per angle

This part I had to struggle through myself and it wasn't fun. The basic problem goes like this: Top speeds don't adjust for X,Y based on direction. "Huh?" Exactly how I felt. Read on...

Let's say that the top speed of a ship is 1.0, that *should* mean the following breakdown will happen when turning our ship to the right (taken at full thrust and top speed):

0-degrees(Due North): x=0, y=1.0
10-degrees: x=.1, y=.9
20-degrees: x=.2, y=.8
...
90-degress(Due East) x=1.0, y=0
etc..

Plus we need to consider that ships have different top speeds and different thrust values.

It's easy to give a top speed of, say, 1.0 and just let your X and Y values go all the way up to, but not past, that value. Unfortunately, it's also VERY innacurate. Problem with that is at a 45-degree angle the X speed will be 1.0 AND your Y speed will be 1.0, which effectively gives the ship a full speed of 2.0...1.0 full point past it's supposed top speed.

If you don't put a cap on speed the game will be unplayable, so that's not an option either. The only method I can think of is this: As the Angle causes X to increase in velocity, Y should likewise decrease in it's velocity, thus keeping both X and Y in a constant state of change and allowance for individual top speeds.

With that in mind, I put together another set of tables that determine the top-speeds allowable for both X and Y from 0 to 80 degrees. I then just reversed these values for the 90-170, 180-260, and 270-350 degrees. Here's the code:


I know that's not exactly pretty, but it works really swell and it builds the tables in such a way that I don't have to do unnecessary math during run-time.

Ship Direction and Applying Thrust/Braking:

The next piece of this is how we use these tables to set the proper angle velocities. First we'll need to know the angle of the ship at all times. Every time the player his the left or right arrow key, the ship spins appropriately. Whenever the up arrow is pressed, the direction of the ship is used to grab the Sin/Cos values and apply thrust to that angle. Here's the Code for handling the direction control:


Now that we have that information, we'll need to apply the thrust. This next section of code does just that. But study this section carefully as it also handles the fluctuating speeds that I described above.

Before showing the code, I need to explain one thing. In order to get a reasonable descent during strong moves away from an X or Y angle, I opted to cheat a little. I'm using the center value as a speed modifier when past the center point on an angle. So, if the ship is pointing at 10 degrees (N-NW), the Y top speed will be very high but X will be very low. This basically means that if you were floating along for a while and had a high X top speed and low Y speed, but you wanted to turn, your X speed would take forever to get down low enough while your Y speed would get to it's new destination very quickly. This is because X will have a low modifier. Since the Center point between N and E is a high modifier for both X and Y, I use this as the default for lowering high X and Y speeds appropriately.

With any luck, that made sense. If not, hopefully the code will:


Lastly, the down arrow allows the player to slow the ship down to a complete stop. To do this we simply multiply the current X, Y velocities by the Braking value, as follows:


Loading Images, Parallaxing Starfields, and Displaying the Ship:

The last piece of this equation is the movement of the starfields and the displaying of your ship at it's appropriate angle.

Firstly, though, you're going to need to load the graphics in. The following function loads in three starfield images, each being a little brighter than the last. Then it loads in a ship graphic which has only one frame. This frame is then rotated 360-degrees in 10-degree increments, placing each rotated frame in an array of images. Here's the code:


When doing this type of game, it's not really the ship that you want to move around, but rather the background. This will make it appear that the ship is moving when in reality it's sitting in the center of the screen doing nothing but spinning around. The stars give it the illusion of movement.

But one layer of stars gives very little life to the environment. So we're going to use some REALLY cool functions that come with BB to help us out a bit. These functions basically tile an image on the background for us, but we can alter their default starting points...and since they'll wrap for us, we don't need to do anything more!

Now, the starfield parallaxing effect needs more explaination. Hopefully this is clear. Also, I should note that I pretty much lifted this method from the Insectoids demo.

If you load all three star maps in a paint program, you'll notice that they are identical as far as star placement goes. The difference then is that starsfar.bmp is dimmer than starsmid.bmp, and starsmid.bmp is likewise dimmer than stars.bmp. This is to give the illusion of depth. I space them out during the rendering phase so they don't overlap initially...it looks weird when they overlap.

The black parts are transparent. That's the default mask color, anyway. You could change that mask to make any color transparent using the MaskImage function. Transparency is ONLY used with TileImage. TileBlock does not use transparency (for speed reasons). This is why starsfar.bmp uses TileBlock...since everything is drawn on top of it, there's no need for transparency and so we save on speed by using TileBlock.

So, what happens is:

  • TileBlock the starsfar.bmp. Doesn't use masking, thus is a bit speedier.
  • TileImage the starsmid.bmp. Moves the image over 7 pixels to the right so it's not sitting directly on top of starsfar.bmp. Uses transparency.
  • TileImage the stars.bmp. Moves the image over 23 pixels to the right of starsfar.bmp so it's not sitting directly on top of starsfar.bmp or starsmid.bmp. Uses transparency.
  • Calculate the new x,y position to START drawing the starsfar.bmp image. Note that whatever scrolls off the screen, either x or y, will wrap the drawing to the opposite side of the screen.
  • Repeat

Here's the source for a 3 layer parallaxing star field (using our X, Y angle information, of course):


Okay, now rendering our ship is painfully simple. So simple, it needs no explaination. Here is the function:


Actually, you don't even need a function for that. I just chose to put the DrawImage call in a function to keep my steps seperated for ease of reading.

Conclusion:

I hope this is clear enough to help you understand this. This was a major brain-bender for me, so don't feel bad if it takes you awhile to get it. Also, this is NOT perfect but it's certainly good enough to get a neat little 2D space game going ;)

In order to get the full effect of this tutorial, you'll need to download and study the code (plus you can see it in action this way!). In order to read the full code, you'll need to have at least the demo version of BlitzBasic. You can get that by going to the BlitzBasic Website (it's less than 2 megs last I checked). You'll also need to have DirectX 7.0 or higher.

To get the full source and and such for this article: Click Here

Thanks to the creator of SpriteLib, Ari Feldman, for the little ship graphic and to BB for the starfields!

Keep an eye on this area as I plan to add more and more stuff as time permits.

Until next time...cya!

-Krylar


For a printable copy of this article, please click HERE.


This site is Copyright© 2000-2004, BlitzCoder. All rights reserved.