Move with the Keyboard, Aim with the Mouse

by Michael James Williams on June 25, 2009 · 34 comments

in Avoider Game Extras,Tutorial

Would you rather have more freedom of movement or shooting?

Snapshot_O09.png
Click to play. Arrows to move, mouse to aim/shoot.

This is the complement to Move with the Mouse, Aim with the Keyboard, not surprisingly, which in turn is part of my mini-series on creating a shoot-’em-up. It’ll probably be easier to follow this if you’ve read the rest of the series already, but if you want to jump right in here and try anyway, you can download all the files you need here.

Shoot with the Mouse, Don’t Aim At All

Here’s the current game:

Snapshot_O06.png
Mouse to move, WSAD to shoot

First thing’s first — let’s get the mouse button shooting a bullet.

At the minute, pressing the W key fires off an event whose handler sets wKeyIsBeingPressed, a Boolean, to true. Releasing the key sets that Boolean to false in a similar way. Every tick, the game checks to see whether that Boolean is true and, if it is, a bullet gets fired (well, there is a limit to how often the bullet can be fired).

So why not use the same approach with the mouse button? We can add an event listener to check when it’s pressed and when it’s released, and it should be easy to tie that in to our existing code. Let’s try it out.

We need to add a new public Boolean to AvoiderGame.as:

?View Code ACTIONSCRIPT3
public var mouseButtonIsBeingPressed:Boolean

…and we should set it to false in the AvoiderGame constructor:

?View Code ACTIONSCRIPT3
mouseButtonIsBeingPressed = false;

(I know, I know, this is all very familiar.)

We might as well add our mouse’s event listeners at the same time we add the keyboard event listeners:

?View Code ACTIONSCRIPT3
public function onAddToStage( event:Event ):void
{
	stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress, false, 0, true );
	stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease, false, 0, true );
	addEventListener( MouseEvent.MOUSE_DOWN, onMousePress, false, 0, true );
	addEventListener( MouseEvent.MOUSE_UP, onMouseRelease, false, 0, true );
}

(You’ll also need to import flash.events.MouseEvent.)

Unlike with the KeyboardEvents, we don’t add the MouseEvent listeners to stage. This means they are added to the current instance of AvoiderGame itself — i.e. the play screen. More specifically, and thanks to something called event bubbling, they are listening for the mouse being pressed or released while pointing to any display object inside the play screen.

We need to create the event handlers now:

?View Code ACTIONSCRIPT3
public function onMousePress( mouseEvent:MouseEvent ):void
{
	mouseButtonIsBeingPressed = true;
}
 
public function onMouseRelease( mouseEvent:MouseEvent ):void
{
	mouseButtonIsBeingPressed = false;
}

This really does work almost identically to the keyboard firing. I expect you can guess what’s coming next, but for the sake of completeness: we need to add code to the onTick() function to actually fire a bullet if our new Boolean is true.

?View Code ACTIONSCRIPT3
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
if ( ticksSinceLastShot >= 10 )
{
	if ( wKeyIsBeingPressed )
	{
		createNewBullet( 0, -1 );
	}
	else if ( sKeyIsBeingPressed )
	{
		createNewBullet( 0, 1 );
	}
	else if ( aKeyIsBeingPressed )
	{
		createNewBullet( -1, 0 );
	}
	else if ( dKeyIsBeingPressed )
	{
		createNewBullet( 1, 0 );
	}
	else if ( mouseButtonIsBeingPressed )
	{
		createNewBullet( 0, -1 );
	}
}

(New lines are 268-271. I’ve made it always fire upwards for now.)

Test it out:

Snapshot_O01.png
Click to play. Move and shoot with mouse.

Works first time; now that’s a rarity ;)

A Little Preparation

Before we go any further, we’ll need to get the avatar’s movements controlled by the keyboard again, otherwise when it shoots at the mouse it will always be shooting at its centre :P

That’s easy though; just find the line:

?View Code ACTIONSCRIPT3
useMouseControl = true;

in the AvoiderGame constructor and set it to false. You might want to comment out the lines that control WSAD shooting as well, or link them into the useMouseControl Boolean, but I’ll leave that up to you.

Snapshot_O02.png
Click to play. Arrows to move, mouse button to shoot.

We’re going to need something to aim at, too. You can create a crosshair movie clip if you like, and make it move with the mouse in the same way that the avatar used to, but I’m just going to make the mouse cursor visible again. All that takes is commenting out this line, again from the AvoiderGame constructor:

?View Code ACTIONSCRIPT3
Mouse.hide();
Snapshot_O03.png
Click to play. Arrows to move, mouse button to shoot.

While we’re here, let me show you what I meant about the mouse’s event listeners listening for events on display objects inside the play screen. Add this line to the end of your AvoiderGame constructor:

?View Code ACTIONSCRIPT3
removeChild( backgroundContainer );

That’ll remove the background from the play screen, like so:

Snapshot_O04.png
Click to play

Try playing the game. It seems impossible to shoot. But actually, if you only press and release the mouse when it’s hovering over an enemy or the avatar or the clock or score, it works fine. When you click on the big grey area, you’re clicking on nothing, and the play screen can’t “hear” you. Be careful with this!

Anyway, put the background back by deleting the last line of code we just wrote. (As the background is a display object inside the play screen, it’ll now hear all those mouse presses that would have been lost to the grey area before.) We’re about ready to get the bullet moving towards the cursor.

Variable Bullets

Currently, clicking the mouse causes this function to be run: createNewBullet( 0, -1 ). This, in turn, creates a new instance of Bullet with an x-direction of 0 and a y-direction of -1. These numbers are used to decide how the bullet moves each tick; they are multiplied by the bullet’s speed (mine is set to eight) so that every tick, my bullets will move 0 pixels to the right and 8 pixels upwards.

Confused? Try changing the numbers that get passed to createNewBullet. createNewBullet( 1, -1 ) will create a bullet moving diagonally up and to the right, for example. How about createNewBullet( -10, 3 )? createNewBullet( 0, -0.1 )?

You probably noticed that the bullet moves faster in those first two tests, and slower in the third. It’s easy to see why: in the ( 0, -0.1 ) example, we’re only moving the bullet 0.8 pixels up every tick, instead of 8 pixels as before. When we set the directions as ( 1, -1 ), we’re telling the bullet to move 8 pixels to the right and 8 pixels up every tick, for a total distance of 11.3 pixels per tick.

If you’re not sure how I got that number, check out my post on Pythagorean distance. It’s really important — the rest of this tutorial is based on it! (Same with Rasmus’s Diagonal Character Movement tutorial.)

The way I see it, the speed variable inside Bullet should define exactly how fast a bullet moves, no matter what the direction. It should not be possible to make it move faster or slower than this just by passing bigger or smaller values to it. Actually, we should be able to pass any values we want and feel confident that Bullet can keep its speed constant; ( 0, -1 ) should produce the same speed as ( 0, -0.1 ) and ( 0, -10 ).

So open up Bullet.as and let’s get that working.

Constantly Speeding Bullets

Here are the first few lines of the Bullet constructor function:

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	xDirection = startingXDirection;
	yDirection = startingYDirection;
	speed = 8;

If we want ( 0, -1 ) to give the same speed as ( 0, -0.1 ) and ( 0, -10 ), the solution is simple, right?

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	if ( startingYDirection == -0.1 )
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection * 10;
	}
	else if ( startingYDirection == -10 )
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection / 10;
	}
	else
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection;
	}
	speed = 8;

OK, maybe that’s taking things a bit too literally. Still, we may be on to something here… check this out:

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	if ( startingYDirection == -0.1 )
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection / 0.1;
	}
	else if ( startingYDirection == -10 )
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection / 10;
	}
	else
	{
		xDirection = startingXDirection;
		yDirection = startingYDirection / 1;
	}
	speed = 8;

That’s equivalent to the above code. See a pattern? We could simplify:

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	xDirection = startingXDirection;
	yDirection = startingYDirection / Math.abs( startingYDirection );
	speed = 8;

(Math.abs() turns any number into a positive; Math.abs( -10 ) is 10, for example.)

That will do the same job again as the above code, but is more general.

If you try it out, you’ll find that ( 0, -1 ) does indeed play just like ( 0, -10 ) and ( 0, -0.1 ). ( 1, -1 ) still shoots further per tick than ( 0, -1 ), however, and ( 10, -10 ) is weird:

Snapshot_O05.png
Click to play

The bullet moves faster than ( 1, -1 ), and it doesn’t move “North-East”.

Of course, this is because we’re not altering the x direction the bullet is given. The obvious solution to try is this:

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	xDirection = startingXDirection / Math.abs( startingXDirection );
	yDirection = startingYDirection / Math.abs( startingYDirection );
	speed = 8;

But think about it: ( 3, 4 ), ( 10, 0.1 ) and ( 0.1, 0.6 ) will all act the same as ( 1, 1 ). And when Bullet tries to deal with ( 0, -1 ) it’ll attempt to divide 0 by 0 and throw an error.

We’re very close, though. If the bullet is moving zero pixels to the right every tick, then the number of pixels it moves up or down per tick is the total distance it moves per tick.

That’s important!

It gives us a clue for what to try next: instead of dividing by the number of pixels moved in the y-direction per tick, try dividing by the total distance moved per tick. How do we find that? Using the Pytheagorean distance formula: (I told you we’d need it!)

?View Code ACTIONSCRIPT3
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	var totalDist:number = Math.sqrt( ( xDirection * xDirection ) + ( yDirection * yDirection ) );
	xDirection = startingXDirection / totalDist;
	yDirection = startingYDirection / totalDist;
	speed = 8;

Here’s a test of the new code, using ( 10, -10 ) as the directions again:

Snapshot_O06.png
Click to play

This time, not only do the bullets move in a North-East direction, but their speed is the same as if we were using directions of ( 0, -1 ). Great!

Aim with the Mouse

Ah, finally. Firing the bullets towards the mouse is going to be really simple, actually. All we need to do is find how far to the right the mouse cursor is from the avatar, and pass that as the x direction, and then find how far below the mouse cursor is from the avatar, and pass that as the y direction.

This is just simple subtraction! All we need to do is alter the code in AvoiderGame.as like so:

?View Code ACTIONSCRIPT3
else if ( mouseButtonIsBeingPressed )
{
	createNewBullet( mouseX - avatar.x, mouseY - avatar.y );
}

Here’s the result:

Snapshot_O07.png
Click to play. Arrows to move, mouse to aim/shoot.

Great, it works! If your bullet’s image is just a circle, you could leave it here. But unfortunately I picked a weird shape, so I’ve got to rotate it to point in the direction it’s moving.

I hate to say it, but I’m actually going to skim over this. It involves trigonometry; if you already know how to use trigonometry, this will be really simple. If not, I don’t really have room here to explain how it all works. Sorry! (If anyone wants to recommend a great beginner’s guide to using sin, cos and tan, I’d really appreciate it.)

We might as well rotate the bullet inside the Bullet class after we set the direction, so open that up again. First, we need to find the angle using Math.atan2() (arctangent):

?View Code ACTIONSCRIPT3
10
11
12
13
14
15
16
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	var totalDist:Number = Math.sqrt( ( startingXDirection * startingXDirection ) + ( startingYDirection * startingYDirection ) );
	xDirection = startingXDirection / totalDist;
	yDirection = startingYDirection / totalDist;
	speed = 8;
	var radAngle:Number = Math.atan2( yDirection, xDirection );

(Line 16 is new here.) This angle will be in radians, so we need to convert it to degrees of rotation (see my post, Angles In Flash, for more on this):

?View Code ACTIONSCRIPT3
16
var rotAngle:Number = ( 180 / Math.PI ) * radAngle;

Now we just have to set the rotation of the bullet:

?View Code ACTIONSCRIPT3
18
rotation = rotAngle;

You might as well delete all the code we wrote in the previous part to do with rotations, because that just dealt with a few angles; this new code deals with all possible angles.

So your Bullet constructor function should look like this:

?View Code ACTIONSCRIPT3
10
11
12
13
14
15
16
17
18
19
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	var totalDist:Number = Math.sqrt( ( startingXDirection * startingXDirection ) + ( startingYDirection * startingYDirection ) );
	xDirection = startingXDirection / totalDist;
	yDirection = startingYDirection / totalDist;
	speed = 8;
	var radAngle:Number = Math.atan2( yDirection, xDirection );
	var rotAngle:Number = ( 180 / Math.PI ) * radAngle;
	rotation = rotAngle;
}

Test it out:

Snapshot_O08.png
Click to play. Arrows to move, mouse to aim/shoot.

Er, hang on. That’s not right. Oh — the Math.atan2() function assumes that 0 degrees means facing to the right, which is why the bullets appear upright (i.e., their default rotation) when shooting to the right. No big deal, we just need to rotate them by a further 90 degrees:

?View Code ACTIONSCRIPT3
10
11
12
13
14
15
16
17
18
19
public function Bullet( startingXDirection:Number, startingYDirection:Number ) 
{
	var totalDist:Number = Math.sqrt( ( startingXDirection * startingXDirection ) + ( startingYDirection * startingYDirection ) );
	xDirection = startingXDirection / totalDist;
	yDirection = startingYDirection / totalDist;
	speed = 8;
	var radAngle:Number = Math.atan2( yDirection, xDirection );
	var rotAngle:Number = ( 180 / Math.PI ) * radAngle;
	rotation = rotAngle + 90;
}
Snapshot_O09.png
Click to play. Arrows to move, mouse to aim/shoot.

Sorted!

Wrapping Up

You can download a zip of all the files I used in this tutorial from this link.

What next? Well, in the last part I mentioned Mushyrulez’s Enemies tutorial and the need for garbage collection. Now I’m also going to recommend using Rasmus’s Diagonal Character Movement tutorial.

Also, you could add some animations to your game — how about making enemies blow up when shot? I’ve written a couple of posts on using animation, introducing two methods: “divided timeline” and “state MovieClips“.

{ 33 comments… read them below or add one }

Ardavan June 25, 2009 at 11:54 am

Hi Michael! This is really nice, thanks for posting it, makes the game a bit more advanced! Thanks for this very nice tutorial!

Kind regards, Ardavan

Rasmus Wriedt Larsen June 25, 2009 at 3:51 pm

great post once again Michael (and thanks for mentioning my post). I don’t really understand why you didn’t just usetrigonometry in the first place . I would also think that you are using trigonometry to define the y and x direction yourself?

tomdeaap June 25, 2009 at 4:12 pm

[flash http://gamedev.michaeljameswilliams.com/structure/AgtShooting3/SWFs/demo6.swf w=400 h=300 preview={ I can see this …. :) As for the rest … Nice tutorial.

Michael Williams June 25, 2009 at 4:33 pm

Thanks guys :)

Rasmus: What do you mean — using an angle to define the direction?

Tom: Whoops, nicely spotted. Fixed now, I think :)

Rasmus Wriedt Larsen June 25, 2009 at 5:46 pm

Well, doing something like this in the constructor function:

var direction:Number = Math.atan2( startingXDirection, startingYDirection );
xDirection = Math.cos( direction );
yDirection = Math.sin( direction );
rotation = ( 180 / Math.PI ) * direction + 90;

Michael Williams June 25, 2009 at 6:09 pm

Ah, right. Yeah good point, that’s another way of doing it. I avoided that for two reasons: first, I think it’s faster to do Pythagorus followed by a couple of divisions followed by two trig functions (but I could be very wrong there); second, that would’ve meant basing the whole tutorial around trig.

If you’re comfortable with trig, though, your method is just as good, maybe even simpler :)

Scarybug July 24, 2009 at 5:01 pm

I don’t know if it matters for the post, but a lot of these games have WASD doing things that I’m not sure you’re intending it to do. on the first “the bullets don’t go NE” game, A and D shoot bullets sideways from the top of the screen instead of from the ship.

You should turn this into an avoider/shooter that keeps randomly changing controls on you (announcing the new controls a la wario-ware)

Michael Williams July 26, 2009 at 1:09 am

Hey Scarybug, our avatars look like they could be two halves of a hilariously mismatched buddy cop team!

Hm, that’s weird — you mean this tutorial? They always shoot from the ship for me :S Anyone else?

Ha! Cool idea. I’ll put it on the list :)

Scarybug July 29, 2009 at 8:48 pm

Michael J Williams & Scarybug: Nerd Cops

FlashN00b September 29, 2009 at 1:00 pm

Hey Michael,

you know, I work on kinda game where you have to shoot down some enemies and then proceed to the next room, shoot more enemies down etc.
So far, things have gone really well.
BUT, I cannot create some good-looking explosion movieclip for it, Im just too bad in drawing such things.
Could you create a tutorial on how to create and animate an explosion (and maybe even create&animate a real-looking explosion)?

That would truly help me out, since it looks just stupid if the enemies just vanish…

Best regards

Michael Williams September 30, 2009 at 1:33 pm

Hey FlashN00b,

Are you familiar with the game Death Vs Monstars? It’s an avoider game / shoot-’em-up where you play as a skull (what a silly idea!)

Well, the creator wrote a tutorial explaining how to draw explosions like his from the game. Check it out here.

I wrote a couple of tutorials explaining how to use animations inside your game: Handling Basic Animation with a Divided Timeline and usign State MovieClips. They don’t explain how to do explosion animations specifically, but I reckon if you played about with it for a while, you could get it working :)

FlashN00b September 30, 2009 at 2:11 pm

Thanks, and yes, I know the game Death vs Monstars but I couldnt beat its boss ;D

Well actually I think this explosion is pretty good and I guess I might try creating a similar and use it in my game :)

Thanks man, you really helped me out with this one :)

Michael Williams October 1, 2009 at 10:42 am

Yeah, I got stuck on the boss too. No rope to burn :(

Great, I’d like to see it when you’ve got that explosion in :)

Dario Gutierrez October 21, 2009 at 5:21 pm

Thanks for this great tutorial.

.-= Dario Gutierrez´s last blog: Developing applications with Flash Professional CS5 for iPhone =-.

Michael Williams November 2, 2009 at 11:45 pm

You’re welcome, Dario

PLyczkowski November 11, 2009 at 9:24 pm

Hey there, I wanted to add a feature to choose bullet type to the code. At first I tried to use eval to dynamically place a bullet type according to a variable, but since eval is not available in AS3, I abandoned the idea. Then I tried to use conditions. Are conditions the proper way?

Here is the idea (or part of it):


public function createNewBullet( startingXDirection:Number, startingYDirection:Number ):void {
if (activeBullet=1){
var newBullet=new Bullet(startingXDirection, startingYDirection);
}
else if (activeBullet=2){
var newBullet=new Bullet2(startingXDirection, startingYDirection);
}

Michael Williams November 13, 2009 at 9:13 pm

Hey PLyczkowski (cool site by the way),

Yeah, that code looks like a good place to start (watch out though — you’ve got “=” instead of “==” inside your if statements).

I can see a few interesting directions you could take this in; please let me know how you get on with it :)

PLyczkowski November 13, 2009 at 10:44 pm

Thanks for checking my site.

I noticed the = seconds after posting, I’m so proud – I’m a total beginner at programming.

I’ll try to implement this idea, cheers.

Michael Williams November 14, 2009 at 8:35 pm

Hehe nice, well done :)

AlexB December 17, 2009 at 6:22 pm

Hello,
i would like make a congratulation for your Tutorial. With this I learned the the basics of OOP.
If you like check my Dodgeball extreme Flash-Shooter: http://abahlk.de/projects/dodgeball/

Bye Alex

.-= AlexB´s last blog: Dodgeball extreme: Der neue Flash-Shooter =-.

Michael Williams December 20, 2009 at 3:39 am

Thanks Alex! That is a really cool gameplay mechanic you’ve got there. Having to decide whether to race towards the dodgeball to try to get it before the enemy, or to run away so that there’s room to dodge — great stuff!

Queepo December 21, 2009 at 6:59 am

Hey,
i was wondering if you could help me give the enemies health by making it take more than 1 shot to kill them. I tried many different ways but I was not able to set a variable to each enemy in the array.
Thanks

Michael Williams December 29, 2009 at 12:53 am

Hey Queepo,

Nice idea. How about this:

Add a new public var to the Enemy class — something like, public var health:int;. Then, in your constructor, set it to whatever value you like (best to test it out with something small, I reckon).

Then, in your if ( enemyHasBeenHit ) section, you’ll be able to see how much health that particular enemy that’s just been hit has left, via enemy.health. So at that point you can subtract a health point, or destroy the enemy if it’s out of health. And of course you can change the appearance of the enemy or make it play a different animation or whatever.

Hope that helps!

DudexD January 26, 2010 at 6:51 pm

I got rid of the Non-focusing game problem after i did this part too, since i’m not using WASD anymore :P

But i got a question about the


var totalDist:number = distance = Math.sqrt( ( xDirection * xDirection ) + ( yDirection * yDirection ) );

the thing i don’t understand is the = distance =, Since when i first added it i got a error, That i got rid of simply by
making a Public var distance:Number

But then the bullet disapeared :S…
And then suddenly in ur code up there you removed it again :P so i don’t totlay understand the point of this little word… :D

Michael Williams January 28, 2010 at 5:21 am

Well, there’s a very simple explanation for why the “= distance =” is there: it’s a typo :P

I’ve corrected it now, thanks for pointing it out. But for the record, you can write code like that. Suppose I wrote:

someVar = someOtherVar = aThirdVar;

…then that’s the same as writing:

someOtherVar = aThirdVar;
someVar = someOtherVar;

…so that’s a useful shortcut sometimes. In this case, though, I just copied and pasted something incorrectly.

flashnoob January 27, 2011 at 1:27 am

hey guys.. get tuts MJW. i got a question.. is there any way of giving the enemy hit points. say it takes 3 or 4 bullets to hit them before the die?

i’ve been tryin to work it out my self but i’m not getting anyway lol.

if you could help me out or put me in the right direction that would be awesome.. cheers

Michael James Williams January 27, 2011 at 3:56 pm

Hi Flashnoob,

Check this tutorial out. It’s about adding HP or lives to the avatar, but you could modify it to work for the enemies, I’m sure.

flashnoob January 30, 2011 at 3:41 am

hey thanks for the response… i had a crack at the avatar health approach… it works ok but theres a problem with it:
-i gave the ‘enemy’ 3 hit points
-after shooting them with 3 bullets they die
however, it doesnt treat each enemy independently.. if you shoot one enemy twice and then shoot a different enemy once, that particular enemy it will die (in one shot).

i’m just trying to work how to set hit points per enemy independently of one another not as a total (like the avatar).

ExplosionsHurt July 22, 2011 at 11:52 am

I’m making a game involving a turret in the middle, and I’m trying to get the turret to constantly face the player.

I can’t figure out what to do :(

ExplosionsHurt September 18, 2011 at 5:42 am

Never mind, I got it.

Turns out that you have to use stage.mouseX instead of just mouseX.

Aseliot October 23, 2011 at 11:41 am

I don’t see how this would work also i can’t get it to work. Do i have to fill in some code myself?

Andy March 25, 2012 at 11:44 pm

Hey, MJW, (can I call you like that?) what’s up? I have two quick quick questions. While I get why we use atan2, why does it return an angle in degrees and not in radians? My understanding was inverse trig functions used radians. My guess is it is something natural of AS3, but not sure. My other question is, is there a way to check if the bullet hits the enemy in x,y position? Say for example if my bullet were to hit the enemy in the head, it can go through and hit another enemy, but if it hits in the body, it cant. The only other solution I can think of is to make the head and body separate objects and check for separate collisions

M November 30, 2012 at 9:36 pm

TY TY TY TY TY TY TY TY TY!!!
Helped me sooooooooooooo much with my coding assignment, God bless you!

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

{ 1 trackback }

Previous post:

Next post: