Home
Products
Community
Manuals
Contact
Login or Signup

How to make Asteroids in an hour or so

BlitzMax Forums/BlitzMax Tutorials/How to make Asteroids in an hour or so

Tibit(Posted 1+ years ago) #1
A "step by step" guide on how to make a simple game.

Contains:
- Short on gamedesign and planing
- Code structure
- Vector Physics (you can always copy N paste it)

Dowload ZIP with source,images, pdf and doc here: How to make Asteroids in an hour or so!

html version see post below

Feel free to post your suggestions, improvements, questions and comments.


skidracer(Posted 1+ years ago) #2
I tried adding <code> </code> tags around your code but that blew the margins out so have tried with <codebox> instead which I don't really like either, this one's a mix of the two:

A "step by step" guide on how to make a simple game by Wave.

Contains:
- Short on gamedesign and planing
- Code structure
- Vector Physics (you can always copy N paste it)

Dowload ZIP with source,images, pdf and doc here: How to make Asteroids in an hour or so!

And in crappy html, without tabs because they don't copy?!:


How to make asteroids in an hour or so

This is a step by step example of how to make a simple asteroids clone. Iíll be simple and should show a good practical example for people new to BlitzMax.

First we need a plan, a design plan to be exact. Asteroids are a simple game so itís not going to be very long. The design part is one of the most important steps in making a game. Without it or if it lacks in detail youíll have to remake and change stuff which in turn will result in a longer production time.

Overview Design
Visual (Design)
ē Explain how it would be to play the game
ē The goal of the game
ē Draw sample images of the game in action
Technical (Programming)
ē Types Overview
ē Methods/functions Overview
ē Image/sound files

In a bigger game this would be much more complicated and involve many more steps. Start your stopwatch (on your mobile) and get ready to make asteroids in an hour or so.
Asteroid Wars Ė Design Overview
Overview Ė whatís the game about?
This game is similar to the classic asteroids. This version will be simple, fast-paced and difficult.
Controls Ė How does the player interact?
The player can rotate this ship, clockwise and counter-clockwise with the left and right keys. He can control his thrust with up and reverse thrust (80%) by pressing down. The player can fire in the direction of their ship by pressing space.
Game play Ė What does the player do?
The game is played in levels and the goal of each level is to destroy stones. Stones come in three sizes, small, medium and large. You start each level with one ship. When you hit a stone it breaks into smaller stones except small stones that evaporate into dust. The first level you meet one medium stone, as you progress through levels the starting stones increases in numbers while getting larger. The game has infinite levels. If you hit a stone you will destroy your ship = game over. One life only...
Goal
The long term goal of the game is to get the highest score possible.

That was the design part of our game plan. At ďGame PlayĒ you should draw on paper some ideas of the ďlook and feelĒ so that the game gets easier to visualize later on when you are making the graphics. I skipped that part this time... Now itís time for the technical stuff. We are using BlitzMax so letís get down to the types we want to use and what graphics we require.

Data structures:
TShip, TShot, TRock each inherit TSpaceObject
I have decided each of these should have their own file named ďNameofType.bmxĒ
This is actually not redundant in this simple game, it will give your code more structure and in the end it will save us time. See it as good practice. Iíll have one file called AsteroidWars, in which the actual game loop will be and from which the game is going to be run.
The methods and functions of SpaceObject are:
Create Ė Function, New, Update, UpdateAll Ė Function, Destroy, Draw
The rest Iíll make when I see they are required.



Start to code
Ok letís get down to programming, start by creating all bmx-files we need. Open the new and empty ďTSpaceObject.bmxĒ

The first thing to do would be to define the Typeís fields.
We need:
X and Y for position
Direction for rotation
Thrust for speed in current direction.
Implement the methods, they should be empty for now. Keep this file open so that you can easily check back later.
TSpaceObject.bmx
Type TSpaceObject

	Field X#,Y#
	Field XSpeed#,YSpeed#
	Field Direction

	Function Create() EndFunction
	
	Function UpdateAll() EndFunction
	
	Method New() EndMethod
	
	Method Update() EndMethod

	Method Destroy() EndMethod

	Method Draw() EndMethod

End Type

Create the files TShip.bmx, TRock.bmx, TShot.bmx and AsteroidWars.bmx.

Have them all open at the same time. Go to main and import TSpaceObject, TShip, TRock and TShot.

AsteroidWars.bmx
Include "SpaceObject.bmx"
Include "Ship.bmx"
Include "Shot.bmx"
Include "Rock.bmx"

Jump to TShip, because now we are going to get things moving. Create the Type (guess the name yourself) and extend it from (guess again).
TShip.bmx
Type TShip Extends TSpaceObject

End Type

So far so good, when you are making you own game try using a similar approach with multiple files. If this game would have been made in one file it would have been much harder to get a good overview. As soon as you have several types you should jump to several files.

Our type TShip might look very empty but donít get fooled by that! TShip extends TSpaceObject therefore it contains every field and method that TSpaceObject contains.
Iíll start with Create() Ė It needs to spawn a new Ship type and add that type to a list. We need someplace to keep this list so create a global in the TShip Type called List, it need to be of the TList Type. We also need to create the list the first time it is used. We are only going to have one ship so I donít really need to add it to a list, but I want to be open in case someone wants to add more players, AI, enemies or perhaps even multiplayer support and it makes the example more general. We also want to setup some default values, startX and startY. Make a method New() and set the default values of X and Y. New() is called when you create a new instance of the type it lies in.

TShip.bmx
Type TShip Extends TSpaceObject

	Global List:TList
	Global Image:Timage
		
	Function Create()
		Ship:TShip = New TShip	 
		If List = Null List = CreateList()
		List.AddLast Ship 'Add Ship Last in List
	EndFunction
	
	Method New()
		X = 300
		Y = 400
	EndMethod

End Type

Time for a break... This part can take forever but Iím confident that if you focus you can make it within 20min and 30sec. Open up your favorite paint/graphics program. With favorite I mean the program you are best at. How you make the graphics are up to you, this is just the guide lines. Make a new picture at a good ship-size, Iíll make it 25x25 pixels. Paint a high-tech space ship in this small image while using black as your background color. Save as.. Ēship.pngĒ if you canít save as png try jpg or bmp. We got two more images we need, shot and rock. Make a new image 20x10, this is going to be our shot or missile. Use black as background. I saved it as Ēmissile.pngĒ in the same folder. Next image is the rock. It need to be much bigger than our ship. Iíll make only one rock and then I will scale it to the smaller sizes. Make it 100x100 and fill it with a stone texture or something.

Now load our Ēship.pngĒ image in the Function create() you will also have to center the image using MidHandleImage( Image ). Our image is set to a global; all ships will look the same. Make a new method called Draw(). In draw we want to set image rotation to our shipís rotation, and then draw it at our current position.

TShip.bmx
Type TShip Extends TSpaceObject

	Global List:TList	
	Global Image:Timage
	
	Function Create()
		Local Ship:TShip = New TShip	 
		If List = Null List = CreateList()
		List.AddLast Ship 'Add Ship Last in List
		
		If Not Image 
			Image = LoadImage("ship.png")
			MidHandleImage( Image )'Center
		EndIf
	EndFunction
	
	Method New()'Starting Values
		X = 300
		Y = 400
	EndMethod

	Method Draw()
		SetRotation( Direction )
		DrawImage( Image,X,Y )
	EndMethod

End Type

Now we are going to fix the update method and the updateAll function. In update we want to update the movement and controls and finally draw the ship. Just so that we can do a test-run letís put in the method Draw() in method Update. In updateAll() we want to loop every ship we have, we only got one, but in case, if we ever add more of them then no extra code will be required. Make an eachin-loop with the global List and make each object run its Update() method.

TShip.bmx
Type TShip Extends TSpaceObject

	Global List:TList	
	Global Image:Timage
	
	Function Create()
		Local Ship:TShip = New TShip	 
		If List = Null List = CreateList()
		List.AddLast Ship 'Add Ship Last in List
		
		If Not Image 
			Image = LoadImage("ship.png")
			MidHandleImage( Image )'Center
		EndIf
	EndFunction
	
	Method New()'Starting Values
		X = 300
		Y = 400
	EndMethod

	Method Draw()
		SetRotation( Direction )
		DrawImage( Image,X,Y )
	EndMethod

	Method Update()
		Draw()
		'To add later:
		'GetInput, Controls
		'Update physics, Movement
	EndMethod

	Function UpdateAll()
		For Ship:TShip = EachIn List
			Ship.Update()
		Next
	EndFunction

End Type

Everything clear? No questions? Are you wondering if there could have been Ēanother wayĒ to do it? Donít hesitate to ask in the forum! Feedback = Good. Questions = Better. Asking = Learning.

Letís see what we got so far. Jump to your main file. Setup a graphicsmode, I choose 800,600,0. Call the function Create() in TShip. Remember that to access a function that lies inside a type you need to access the function from the type; Type.Function() Ė or in our case - TShip.Create(). Create a basic loop and exit when someone presses Esc. Run the function UpdateAll() in the middle of it and before the end of the loop call Flip and Cls.

AsteroidWars.bmx
Include "TSpaceObject.bmx"
Include "TShip.bmx"
Include "TShot.bmx"
Include "TRock.bmx"

Graphics 800,600,0

TShip.Create()

'Main Loop
Repeat' - - - - - - - - - - - - - - - - - 

	TShip.UpdateAll()
		
Flip
Cls
Until KeyDown(Key_Escape)'- - - - - - - -

Build and Run! You canít do anything except watch your pretty ship but itís a start and weíve built a solid base for years to come, or more exact ~42min.

Now we need interactivity. Jump to TShip again. We are going to implement the actual physics, the control feeling of the ship. This part is an important and a bit advanced, Iíll try to explain it as simple as thorough as possible. Still you need to know some about vectors to get it, or Iíll have to explain vectors to, but I wonít, not this time. Nothing strange with vectors there itís just out-of-scope for this guide. So here is the code for method Update, Step One:

In file TShip.bmx
	Method Update()
		Draw()

		'Possible Actions
		Local Up,Down,Left,Right,Fire
		
		'Controls affect actions
		If KeyDown(Key_Up) 	  	Up 		= True
		If KeyDown(Key_Down)  	Down 	= True
		If KeyDown(Key_Left)  	Left 	= True
		If KeyDown(Key_Right) 	Right 	= True 
		If KeyDown(Key_Space)   Fire	= True
		
		' P H Y S I C S 
		'---------------------------------------
		'Alter these to alter the ships movement
			
			Local Acceleration# 		= 0.04
			Local Friction# 			= 0.014
			Local TopSpeed# 			= 2.0
			
			Local TurnAcceleration#	= 0.18
			Local TurnFriction#			= 0.06		
			Local TurnMax# 				= 3
	
		'---------------------------------------	

What I do when I set Left,Right,Up,Down and Fire is to separate the actions from the keys. Itís not required in this game unless we want to add more players or AI.
That wasnít that hard, was it? I hope not because the actual physics/trouble is yet to come, Step Two:

In file TShip.bmx in method Update()

Before you try to understand this and before you go any further I would strongly suggest you try the above addition. Compile and run. Test.

So what is this all about, with one word: Vectors. Vectors it the key to physics. Vectors work in 2D and 3D. Without telling you what a vector is Iím going to explain what I did, the problem is thatÖ well youíll find out.

When we press Up or Down we want our thruster to give us a push forward. One could refer to this push over time as force. What is a force then? A force is something that accelerates things. You have probably seen the equation: Force = Mass x Acceleration. This means that our thruster will accelerate a heavier ship (bigger mass) much slower than a light one. Acceleration = Force / Mass. In this game I have set Mass = 1 and it was never provided in the equations. So in this game our thruster gives a force equal to the acceleration. Letís look at the code:
If Up
	XSpeed:+ Cos(Direction)*Acceleration
	YSpeed:+ Sin(Direction)*Acceleration	
EndIf

XSpeed and YSpeed is the values of our speed vector. Acceleration in this case is the Ship-thrusterís ďpushĒ value. I take this value and assume itís a vector in the direction of the ship and add it too the speed-vector.
If I had been using a vector library/module the above could have looked something like this:
If Up
	Local Thruster:Vector = NewVector()
	Thruster.SetLength( Acceleration )
	Thruster.SetDir( Direction )
	Speed.Add( Thruster )
EndIf

To be able to reduce our speed we need to reduce the speed-vectors length and not the values directly. To get the length we use Pythagoras Theorem.
Local SpeedVectorLength# = Sqr(XSpeed*XSpeed + YSpeed*YSpeed)

Friction is applied to our SpeedVectors length like this:
If SpeedVectorLength > 0
	XSpeed:- (XSpeed/SpeedVectorLength)*Friction
	YSpeed:- (YSpeed/SpeedVectorLength)*Friction
EndIf

The calculation (XSpeed/SpeedVectorLength) creates a unit vector of the speed vector. This means I set the length of the speedvector to one but I keep the direction. When I then multiply this unitvector with Friction I create a vector with the same direction as our speedvector but with the length of our friction value. Then I substract this vector from the speed vector.
With a vector library it would have looked something like this:
Speed.Sub( Speed.Unit().Multiply(Friction) )
Or
Speed.Decrease( Friction )

We also need to keep a speed limit. This speed limit would in a real-world be dependant on friction, in space we donít have any friction. In my asteroids-world I dictate the physics and I use both friction and a speedlimit, both without breaking the laws of physics, I merly bend them.
If SpeedVectorLength > TopSpeed
	XSpeed:+ (XSpeed/SpeedVectorLength)*(TopSpeed - SpeedVectorLength)
	YSpeed:+ (YSpeed/SpeedVectorLength)*(TopSpeed - SpeedVectorLength)
EndIf

If our speed surpasses a certain limit I will substract the speed with the amount that it was surpassed, (TopSpeed - SpeedVectorLength). Itís the same as friction only that the amount of friction I add is depending on the speed.
Vector Lib equvivalent:
If Speed.Length() > MaxSpeed Then Speed.SetLength( MaxSpeed )
The last part is to update your position based on your speed
X:+ XSpeed
Y:+ Yspeed
In a vector lib that would have been:
Position.Add( Speed )

The rotation part is easier and I assume it donít need much futher explination. Please go ahead and change any/all of the six values and try for different physics behaviors. This model could be used for most topdown games to give a fair feel. If you have a race game I suggest having a higher turn acceleration to get more responsive controls, the turn friction would in a car game be equvivalent to the grip of the tires. Test and try for your self.

TShip.bmx so far
Type TShip Extends TSpaceObject

	Global List:TList
	Global Image:Timage

	Field TurnSpeed#
		
	Function Create()
		Local Ship:TShip = New TShip	 
		If List = Null List = CreateList()
		List.AddLast Ship 'Add Ship Last in List
		
		If Not Image 
			Image = LoadImage("ship.png")
			MidHandleImage( Image )'Center
		EndIf
	EndFunction
	
	Method New()'Starting Values
		X = 300
		Y = 400
	EndMethod
	
	Method Draw()
		SetRotation( Direction )
		DrawImage( Image,X,Y )
	EndMethod

	Method Update()
		Draw()

		'Possible Actions
		Local Up,Down,Left,Right,Fire
		
		'Controls affect actions, Player 1
		If KeyDown(Key_Up) 	  	Up 		= True
		If KeyDown(Key_Down)  	Down 	= True
		If KeyDown(Key_Left)  	Left 	= True
		If KeyDown(Key_Right) 	Right 	= True 
		If KeyDown(Key_Space)  Fire	= True
	
	
		' P H Y S I C S 
		'---------------------------------------
		'Alter these to alter the ships movement
			
			Local Acceleration# 		= 0.04
			Local Friction# 			= 0.014
			Local TopSpeed# 			= 2.0
			
			Local TurnAcceleration#	= 0.18
			Local TurnFriction#			= 0.03		
			Local TurnMax# 				= 5
	
		'---------------------------------------	
		
								
		'M O V E M E N T  P H Y S I C S
		'--------------------------------------
		'									
		If Up
			'Create a Acceleration Vector and
			'add it to the Speed Vector
			XSpeed:+ Cos(Direction)*Acceleration
			YSpeed:+ Sin(Direction)*Acceleration	
		EndIf
		
		If Down
			'Create a Acceleration Vector and
			'substract it from the Speed Vector
			XSpeed:- Cos(Direction)*Acceleration
			YSpeed:- Sin(Direction)*Acceleration
		EndIf
		
		'Calculate the length of the Speed Vector
		Local SpeedVectorLength# = Sqr(XSpeed*XSpeed + YSpeed*YSpeed)
		
		If SpeedVectorLength > 0
			'Decrease Speed with Friction if we are moving
			XSpeed:- (XSpeed/SpeedVectorLength)*Friction
			YSpeed:- (YSpeed/SpeedVectorLength)*Friction
		EndIf
		
		If SpeedVectorLength > TopSpeed
			'If we are going beyond the speed barrier then reduce our speed
			'with the amount in which it surpases TopSpeed
			XSpeed:+ (XSpeed/SpeedVectorLength)*(TopSpeed - SpeedVectorLength)
			YSpeed:+ (YSpeed/SpeedVectorLength)*(TopSpeed - SpeedVectorLength)
		EndIf
		
		'Move
		X:+ XSpeed
		Y:+ YSpeed
				
		'Rem 'Visualize the vectors		
		SetRotation 0
		SetColor 255,0,0 'Red 
			DrawLine X,Y,X,Y + YSpeed*50
		SetColor 0,255,0 'Green
			DrawLine X,Y,X+XSpeed*50,Y
		SetColor 0,0,255 'Blue
			'This is the SpeedVector's Length
			'Note that this vector is built by
			'Adding the Red and the Green
			DrawLine X,Y,X+XSpeed*50,Y+YSpeed*50
		SetColor 255,255,255
		'EndRem	
				
		'R O T A T I O N  P H Y S I C S
		'--------------------------------------
		'									
		If Left	TurnSpeed:-TurnAcceleration
		If Right	TurnSpeed:+TurnAcceleration			
		
		'Limit TurnSpeed
		If TurnSpeed >  TurnMax TurnSpeed =  TurnMax
		If TurnSpeed < -TurnMax TurnSpeed = -TurnMax
				
		Direction:+TurnSpeed
		
		If Direction > 360 	Direction:- 360
		If Direction < 0 	Direction:+ 360
		
		'Apply Friction To Rotation
		If TurnSpeed >  TurnFriction	TurnSpeed:- TurnFriction
		If TurnSpeed < -TurnFriction TurnSpeed:+ TurnFriction
		
		'If Friction is Greater than Speed then Stop
		If TurnSpeed < TurnFriction And TurnSpeed > -TurnFriction TurnSpeed = 0
		
	EndMethod

	Function UpdateAll()
		Local Ship:TShip
		For Ship = EachIn List
			Ship.Update()
		Next
	EndFunction

End Type

Now Iím going to add shots. Open up Tshot.bmx and create a TShot type that extends TSpaceObject. We are going to need a list for the shots. Make the create method similar to the shipís create method. Weíll load the image we made, shot.png.

TShot.bmx
Type TShot Extends TSpaceObject

	Global List:TList
	Global Image:TImage
	
	Function Create()
		Local Shot:TShot = New TShot	 
		If List = Null List = CreateList()
		List.AddLast Shot 'Add Ship Last in List
		
		If Not Image
			Shot.Image = LoadImage("shot.png")
			MidHandleImage( Shot.Image )
		EndIf
	EndFunction
	

	Function UpdateAll() EndFunction
		
	Method Update() EndMethod

	Method Destroy() EndMethod

	Method Draw() EndMethod
	
EndType

Now we can create shots, but where will the shots appear? The shots should always be created at the front of the ship who fired it. This requires us to add some parameters to create().
Function Create( X, Y, Direction, XSpeed, YSpeed )
	Local Shot:TShot = New TShot	 
	If List = Null List = CreateList()
	List.AddLast Shot 'Add Ship Last in List
		
	Shot.X = X
	Shot.Y = Y
	Shot.Direction = Direction
	Shot.XSpeed = XSpeed

	Shot.YSpeed = YSpeed
		
	If Not Image
		Shot.Image = LoadImage("shot.png")
		MidHandleImage( Shot.Image )
	EndIf
	
EndFunction

Letís fix Update() and UpdateAll(), I copied what I have in these methods in TShip.bmx and altered them to fit our shot. This is what came out of it:
Type TShot Extends TSpaceObject

	Global List:TList
	Global Image:TImage

	Function Fire( X, Y, Direction, XSpeed, YSpeed 	)
		Local Shot:TShot = New TShot	 
		If List = Null List = CreateList()
		List.AddLast Shot
		
		If Not Image'First Time
			Image = LoadImage("missile.png")
			MidHandleImage( Image )
		EndIf

		Local ShotSpeed#= 8
		Shot.X 			= X
		Shot.Y 			= Y
		Shot.Direction 	= Direction
		
		'Add Shot Start Speed
		Shot.XSpeed= Cos(Direction)*ShotSpeed + XSpeed
		Shot.YSpeed= Sin(Direction)*ShotSpeed + YSpeed
	EndFunction
	
	Method Draw()
		SetRotation( Direction )
		DrawImage( Image,X,Y )
	EndMethod
	
	Method Update()
		Draw()
		X:+ XSpeed
		Y:+ YSpeed					
		If X > 800 Or Y > 600 Or X < 0 Or Y < 0 Destroy()
	EndMethod

	Function UpdateAll()
		If Not List Return 
		
		Local Shot:TShot
		For Shot = EachIn List
			Shot.Update()
		Next
	EndFunction

	Method Destroy() 
		List.Remove( Self )
	EndMethod
	
EndType	

The code above should say most just by itself, except:
Shot.XSpeed= Cos(Direction)*ShotSpeed + XSpeed
Shot.YSpeed= Sin(Direction)*ShotSpeed + YSpeed
Here is the vector code again =)
Itís the same as when we thrust forward. The shots in this game are not affected by friction and they canít rotate so the update code is therefore much more simple than that in TShip.bmx.

To fire a shot we need to add one line to our Shipís Update method:

If Fire TShot.Fire( X, Y, Direction, XSpeed, YSpeed )

Ok cool we can move around and fire. Now we need some targets Ė rocks. But before that Iíll add a border so that if you go out on one side you appear on the other.
Add to TShip.bmx in the update method:
	If X > 800 X = 0
	If Y > 600 Y = 0
	If X < 0 X = 800
	If Y < 0 Y = 600

Jump to TRock.bmx. This type is very similar to Tshot. We have to take into account that the rocks come in different sizes, I added one field Size and one called Rotation.
Type TRock Extends TSpaceObject

	Global List:TList
	Global Image:TImage
	Field Size
	Field Rotation#

I will also add three constants. Whenever I want to refere to a size I could write Size = 1 or 2. With constants It would be: Size = SMALL or MEDIUM. To have constants in all caps is just very common in programming and itís not required by BMax.
	Const LARGE  = 3
	Const MEDIUM = 2
	Const SMALL  = 1

Instead of Create I call this function Spawn, it does almost the same thing as create in Shot and Ship.
	Function Spawn( X, Y ,Size )
		Local Rock:TRock = New TRock	 
		If Not List List = CreateList()
		List.AddLast Rock
		
		If Not Image'First Time
			Image = LoadImage("rock.png")
			MidHandleImage( Image )
		EndIf
				
		Local RockSpeed# = 0
		Select Size
			Case LARGE'Large		
				RockSpeed = 0.2
			Case MEDIUM'Medium
				RockSpeed = 0.5
			Case SMALL'Small	
				RockSpeed = 1
		EndSelect
		
		Rock.X 			 = X
		Rock.Y 			 = Y
		Rock.Direction 	 = Rand(360)
		Rock.Rotation 	 = Rock.Direction
		Rock.Size 		 = Size
		
		'Add Rock Start Speed
		Rock.XSpeed= Cos(Rock.Direction)*RockSpeed
		Rock.YSpeed= Sin(Rock.Direction)*RockSpeed
	EndFunction

The above code should speak for itself, the rocks start with a constant speed that it keep aslong as it stays alive.
	Method Draw()

		Select Self.Size
			Case LARGE		
				SetScale 2,2
			Case MEDIUM'Medium
				SetScale 1,1
			Case SMALL'Small	
				SetScale 0.5, 0.5
		EndSelect
			
		SetRotation( Rotation )
		Rotation:+0.5
		DrawImage( Image,X,Y )
		SetScale 1,1
	EndMethod

Note the collision() method below, I will come to that in a moment.
	Method Update()
		Draw()
		X:+ XSpeed
		Y:+ YSpeed			
		
		Collision()
				
		If X > 800 X = 0
		If Y > 600 Y = 0
		If X < 0 X = 800
		If Y < 0 Y = 600 	
	EndMethod

	Function UpdateAll()
		If Not List Return 
		
		For Local Rock:TRock = EachIn List
			Rock.Update()
		Next
	EndFunction

	Method Destroy() 
		List.Remove( Self )
	EndMethod

Until now the rock would just tumble around in space. We want it to interact with the shp and your shots, so that they pose a threat and can be destroyed.
	Method Collision()
		Local Radius
		Select Size
			Case LARGE		
				Radius = 100
			Case MEDIUM'Medium
				Radius = 50
			Case SMALL
				Radius = 20
		EndSelect
	
		'If a rock hit a ship
		If TShip.List
			For Local Ship:TShip = EachIn TShip.List
				If Distance( X, Y, Ship.X, Ship.Y ) < Radius
					Ship.Destroy()'Ship = Dead		
				EndIf
			Next
		EndIf

Collision Rock versus Ship. I use the simple fact that if the ship ever gets closer to the rocks center than the rocks radius then it will collide with the rock. The rock is round so this should work very good. The same goes for the shots, if they are close enought to the rock the rock is hit.
		'If a shot hit a rock
		If Not TShot.List Return
		For Local Shot:TShot = EachIn TShot.List
			If Distance( X, Y, Shot.X, Shot.Y ) < Radius
				
				Shot.Destroy()
				
				Select Size
					Case LARGE	
						Destroy()'Destory the rock	
						Spawn( X, Y , MEDIUM )
						Spawn( X, Y , MEDIUM )
					Case MEDIUM
						Destroy()	
						Spawn( X, Y , SMALL )
						Spawn( X, Y , SMALL )
					Case SMALL
						Destroy()'
				EndSelect
	
			EndIf
		Next	
	EndMethod

If the rocks is Large we destroy the large and spawn two medium. This part of the code is very easy to follow. This is the great about max, some part of the programs almost becomes trival. And of course you need a way to calculate the Distance from the Rock to whatever. I made a quick function for that:
Function Distance#( X1, Y1, X2, Y2 )
	Local DX# = X2 - X1
	Local DY# = Y2 - Y1
	Return Sqr(Dx*Dx + Dy*Dy)
EndFunction

Dx is the Distance from X1 to X2. Dy is the distance from Y1 to Y2. I want to know the diagonal length of these and therefore use pythogeras again. Youíll need to know some basic math to get this.

Now thatís about it. Now itís a good time to tweak the game. Alter the ships physics and the rock speed and size. Try to make everything fit together as smooth as possible.

Time to make a game out of this engine. Here is what we need for that:

1. Introduction Screen with controls Ė Press Space to Start Game , Q QuitĖ
2. If you kill all rocks spawn a new level
3. Keep track of your score. Only small rocks give score, 1point each.
4. If the player dies, tell them their score. Restart game with R, Quit Q.

To implement this we need to go to our main file, AsteroidWars.bmx

First I create a global called Mode, and then three constants, one for each mode. Intro, Death and Playing. Also a global for Score and one for highest Score.
Const Intro 	= 1
Const Death 	= 2
Const Playing	= 3

Global Mode = Intro
Global Score, HighestScore

Now I added the main stuff, nothing really special but it required a lot of tweaking. Therefore I canít write it step by step. Instead Iíll finnish off by giving you the complete source. I recommend that you make your own version. Use this as a base. Tweak it, add features. My gamepley for this game sucks. Itís an example and nothing more. I hope it prove a good base for anyone wanting to try out game programming. Have fun with it!

AsteroidWars.bmx


Feel free to post your suggestions, improvements, questions and comments.

Next I'm going to make a vector physics tutorial. But it's a long long time until next time.


stosh(Posted 1+ years ago) #3
Thanks wave and racer!


SillyPutty(Posted 1+ years ago) #4
very very nice guys !!

Cant wait to see what you do next !


Augen(Posted 1+ years ago) #5
Haven't had a chance to go through it yet. Thanks guys for helping us less experienced understand this.


z80jim(Posted 1+ years ago) #6
Thanks a million for the tutorial. Very well done.

I'v used it as a reason to learn about BMax bitmap collisions. Slows things down a bit on my machine though. I'm thinking of just using bounding rectangles for a nearness check and then use ImagesCollide for a final check. Seems that would be quicker as it only needs to do the bitmap check on images that MAY be colliding. Does that make sense?


RmB303(Posted 1+ years ago) #7
Not had a chance to look at it yet, but thanks a lot.
Exactly the kind of thing I've been looking for.


Tibit(Posted 1+ years ago) #8
Thanks for the respone, any suggestions for improvements are also welcome.

If you need pixel perfect collision then using bounding box or a range check before bitmap collisions should save a lot of CPU, so that would certainly make sense even for a low number of objects. Last time I tested the bitmap collide it was way slow to be used all the time. But if you manage to find a good use for it then please share.


BODYPRINT(Posted 1+ years ago) #9
Just to help with any confusion for absolute beginners, at the start of the tutorial when you import the files into AsteroidWars.bmx, there is an error in the example...

Include "SpaceObject.bmx"
Include "Ship.bmx"
Include "Shot.bmx"
Include "Rock.bmx"


should read...

Include "TSpaceObject.bmx"
Include "TShip.bmx"
Include "TShot.bmx"
Include "TRock.bmx"


Sorry to be picky, but this is for beginners, yes?


Arcadenut(Posted 1+ years ago) #10
I would like to thank Wave and Skidracer as this solved one of my problems with Acceleration in the game I am working on!

Let me know how you want to be shown in the credits. Right now it will be as "Wave" and "Skidracer".

Thanks!


Tibit(Posted 1+ years ago) #11
@Phil, Thanks I'll correct that. This should be for beginners, please suggest if you come up with more improvements or tips.

Second, Skidracer simply made codeboxes, he is not a part of the credits. He did not help me or Co-wrote this in any way. I feel there is a misconception about that.

Please Skidracer, change your post and if you have admin rights paste it into my first post (so I can edit). I'll give you credit for the translation to forum code ofcourse.


Arcadenut(Posted 1+ years ago) #12
Wave, no problem, just saw Skidracer on most of the stuff :-)


zcbeaton(Posted 1+ years ago) #13
This looks like a pretty good tutorial so far, I'll have a proper look later. Should be excellent for getting me started into BlitzMAX, eh?


WarpZone(Posted 1+ years ago) #14
Okay, I can't get the source code provided in the zip file to comile. It says Compiller Error: Identifier "AppTitle" not found. I guess it's refering to the second line of AsteriodWarz.bmx, I dunno.

AsteriodWarz.bmx is still the main, root, primary file we're supposed to Compile and Run in order to build the EXE that coumes with the zip file, right?

Yes, I'm new. Very very new. That's why I need bug-free code to learn from. The code provided produces a mysterious error that I don't know enough to know how to fix.

I guess lots of people with a little BMX experience have gotten this example to run, because nobody else complains of an error. Can anybody tell me how to make it work?

Thanks.


Triforce Guardian(Posted 1+ years ago) #15
this works perfectly for me..


Foolish(Posted 1+ years ago) #16
Great tutorial. I started off my BlitzMax education with this tutoral. I then built off of it to include the following:

1. Different asteroid types.
2. Basic ImageCollision function
3. Option/Preference screen for key mapping
4. Shields
5. UFO (animated sprite)
6. Fonts (using true type fonts)
7. Basic Sounds

The result is available here.
http://www.foolishgames.zoomshare.com/files/AsteroidDefenderSource.zip


Tibit(Posted 1+ years ago) #17
I'm really impressed. It looks very professional. Great work.


Foolish(Posted 1+ years ago) #18
Thanks much. I appreciate you taking the time to check it out.


Augen(Posted 1+ years ago) #19
This tutorial should be stickied?


Matt Merkulov(Posted 1+ years ago) #20
Thanks, Wave, very useful tutorial.

Here's version russified by Maniak_dobrii:
http://blitzetc.boolean.name/articles/asteroids.htm