21 July 2011

Day 1 Part 2 - Shooting

The next part to making this game is to allow the player to shoot on a click of the mouse.  To do this I need a movieclip for the bullet, and I'm going to need a whole lot of variables in the code.  Because there can be more than one bullet on screen at a time I'll need arrays to hold all the bullet data.  For each bullet I need to know its x and y coordinates, its x and y speeds, its rotation speed (the bullets will rotate), how much damage it does to the enemy, how much it pushes the enemy back, and an ID number which identifies which bullet I'm working with.  So I need to create arrays for all of these variables.  I'm not sure if there is a more efficient way of doing this, but if there is, let me know in the comments!

The next thing I need is a few functions to control the bullets.  I need a function to create bullets, a function to move the bullets every frame, and a function to remove the bullets once they leave the screen.

I'll run through the code function by function:

Function makebullet()

function makebullet(){
    //bullet appears at end point of barrell
    //bl = barrell length, barrell_rad = barrell angle in radians
    bxl = Math.cos(barrell_rad) * bl; 
    byl = Math.sin(barrell_rad) * bl;
    bullet_xs[bulletcount] = gunbarrell._x + bxl;
    bullet_ys[bulletcount] = gunbarrell._y + byl;
    bulletspeed = 10;
    
    //split bulletspeed into an x and y value
    ratio = bulletspeed / bl;
    bullet_xspeeds[bulletcount] = bxl * ratio;
    bullet_yspeeds[bulletcount] = byl * ratio;
    bullet_rspeeds[bulletcount] = 10; //rotation speed
    bullet_hps[bulletcount] = 10;     //damage
    bullet_powers[bulletcount] = 4;   //repelling power
    bullet_IDs[bulletcount] = nextbulletID;
    
    //attach a new instance of bullet from the library with name bullet_1, bullet_2 etc.
    bul = _root.attachMovie("bullet","bullet_"+nextbulletID,_root.getNextHighestDepth());
    bul._x = bullet_xs[bulletcount];  //position the movie clip
    bul._y = bullet_ys[bulletcount];
    nextbulletID++;   //increment IDs
    bulletcount++;    //increment bullet count
}

This function will create a new bullet.  It will be called whenever the mouse is clicked.  The comments in this function make it pretty self explanatory but I'll run through it quickly.

    Lines 4 - 7 are finding the end point of the barrell which is also the start point of the bullet.

    Line 8 sets the speed of the bullet

    Lines 11 - 13 convert the bullets speed into an x and y value

    Lines 14 - 17 set up all the other properties of the bullet

    Lines 20 - 22 create the bullet and move it into position

    Lines 23 and 24 increment the variables bulletcount and nextbulletID.

You might wonder why I have two variables, bulletcount and nextbulletID.  This is because bulletcount will be decremented when a bullet is removed (or goes off) the screen but nextbulletID will always increment.

Function bulletstep()
function bulletstep(){
    for (a=0;a<bulletcount;a++){  //step through the array from 0
        curID = bullet_IDs[a]  
        bullet_xs[a] += bullet_xspeeds[a];  //change x and y values based
        bullet_ys[a] += bullet_yspeeds[a];  //on xspeed and yspeed
        _root['bullet_'+curID]._x = bullet_xs[a];  //apply new positions to
        _root['bullet_'+curID]._y = bullet_ys[a];  //relevant bullet on screen
        _root['bullet_'+curID]._rotation += bullet_rspeeds[a]; //rotate bullet
        bulletcheck(a);  //check screen boundaries etc.
    }
}

This function will be called every frame, so 30 times a second, and will move the bullets across the screen.  Again pretty self explanatory but I'll run through it.
    Line 2 - a loop that steps through the array from 0 with the variable a representing position in the array.
    Line 3 - Get the ID of the current bullet.
    Lines 4 and 5 - change the x and y values of the bullet based on the speed.
    Lines 6 and 7 - apply the new position to the bullet on screen.
    Line 8 - rotate the bullet, just cos it looks cool.
    Line 9 - calls a function which we'll write in a second.

It took me a while to figure out that you can dynamically reference attached movieclips based on variables using the block brackets [ ] like this : _root['bullet_'+curID]so that's pretty cool.  Well it's not cool that it took me a while to figure it out but it's cool that you can do that...anyway on to the next function!

 Function bulletcheck(arraypos:Number)
function bulletcheck(arraypos:Number){
    cx = _root['bullet_'+bullet_IDs[arraypos]]._x;  //get x and y position
    cy = _root['bullet_'+bullet_IDs[arraypos]]._y;
    //check stage boundaries
    if (cx < stagexmin || cx > stagexmax || cy < stageymin || cy > stageymax){
        killbullet(arraypos);
    }
} 

Ok, this one is very simple. For the given array position it checks if the bullet is outside the stage boundaries. If it is it calls a function killbullet(arraypos) which will destroy the bullet.

 Function killbullet(arraypos:Number)

function killbullet(arraypos:Number){
    removeMovieClip(_root['bullet_'+bullet_IDs[arraypos]]); //remove the bullet
    if (!(arraypos == (bulletcount - 1))){        //if its not the end of the array
        for (i = arraypos+1;i<bulletcount;i++){ //then move everything in the array    
            bullet_xs[i-1] = bullet_xs[i];        //above this point down one position
            bullet_ys[i-1] = bullet_ys[i];
            bullet_xspeeds[i-1] = bullet_xspeeds[i];
            bullet_yspeeds[i-1] = bullet_yspeeds[i];
            bullet_rspeeds[i-1] = bullet_rspeeds[i];
            bullet_powers[i-1] = bullet_powers[i];
            bullet_hps[i-1] = bullet_hps[i];
            bullet_IDs[i-1] = bullet_IDs[i];
        }
    }
    bulletcount--;  //decrement bullet count
}
  

Again a pretty simple function, this one removes the movieclip from the stage and, if this bullet is not the last one in the array it moves all the higher array elements down once...if that makes sense? LOL it makes sense in my head but I'm getting tired now! ANYWAY, if it IS the last element in the array then you don't need to worry, because the data will be overwritten later.

The last little bit of code we need calls bulletstep every time the gunbarrell enters frame, which is every frame because gunbarrell is attached in the first line of code.

gunbarrell.onEnterFrame = function(){
 bulletstep();
}


So the complete code now looks like this, and it works. The barrel will follow the mouse pointer and a projectile will be fired when the mouse is clicked. There is a reload time so the gun won't fire as fast as the mouse is clicked. Test it out below!

_root.attachMovie ("gunbarrell","gunbarrell",_root.getNextHighestDepth())
gunbarrell._x = 275;
gunbarrell._y = 780;

//bullet vars
bullet_xs = new Array()
bullet_ys = new Array();   
bullet_xspeeds = new Array(); 
bullet_yspeeds = new Array();
bullet_rspeeds = new Array(); //rotation speed
bullet_powers = new Array();  //amount the bullet repels enemies
bullet_hps = new Array();  //amount of damage done by the bullet
bullet_IDs = new Array();
bulletcount = 0;  //how many bullets exist at the moment
shottimer = 0;  //controls shooting speed
stagexmin = 0;  //stage boundaries
stagexmax = 550;
stageymin = 0;
stageymax = 800;
nextbulletID = 0;
curID = 0;
reloadspeed = 200;  //lower number = faster reload speed
bl = gunbarrell._height;

gunbarrell.onEnterFrame = function(){
 bulletstep();
}

onMouseDown = function () {  //when the mouse is clicked
 timesinceshot = getTimer() - shottimer;
 if (timesinceshot >= reloadspeed){
  shottimer = getTimer();
  makebullet();
 }
}
onMouseMove = function () {  //when mouse is moved
    mouse_xdist = _root._xmouse-gunbarrell._x;
    mouse_ydist = _root._ymouse-gunbarrell._y;
    // calculate the angle
    barrell_rad = Math.atan2(mouse_ydist, mouse_xdist);
    // convert to degrees and set rotation
    barrell_angle = toDeg(barrell_rad) + 90;
    gunbarrell._rotation = barrell_angle;
}
 
function toDeg(Rad:Number){return (Rad * 180 / Math.PI);}
function makebullet(){
    //bullet appears at end point of barrell
    //bl = barrell length, barrell_rad = barrell angle in radians
    bxl = Math.cos(barrell_rad) * bl;
    byl = Math.sin(barrell_rad) * bl;
    bullet_xs[bulletcount] = gunbarrell._x + bxl;
    bullet_ys[bulletcount] = gunbarrell._y + byl;
    bulletspeed = 10;
     
    //split bulletspeed into an x and y value
    ratio = bulletspeed / bl;
    bullet_xspeeds[bulletcount] = bxl * ratio;
    bullet_yspeeds[bulletcount] = byl * ratio;
    bullet_rspeeds[bulletcount] = 10; //rotation speed
    bullet_hps[bulletcount] = 10;     //damage
    bullet_powers[bulletcount] = 4;   //repelling power
    bullet_IDs[bulletcount] = nextbulletID;
     
    //attach a new instance of bullet from the library with name bullet_1, bullet_2 etc.
    bul = _root.attachMovie("bullet","bullet_"+nextbulletID,_root.getNextHighestDepth());
    bul._x = bullet_xs[bulletcount];  //position the movie clip
    bul._y = bullet_ys[bulletcount];
    nextbulletID++;   //increment IDs
    bulletcount++;    //increment bullet count
}

function bulletstep(){
    for (a=0;a<bulletcount;a++){  //step through the array from 0
        curID = bullet_IDs[a] 
        bullet_xs[a] += bullet_xspeeds[a];  //change x and y values based
        bullet_ys[a] += bullet_yspeeds[a];  //on xspeed and yspeed
        _root['bullet_'+curID]._x = bullet_xs[a];  //apply new positions to
        _root['bullet_'+curID]._y = bullet_ys[a];  //relevant bullet on screen
        _root['bullet_'+curID]._rotation += bullet_rspeeds[a]; //rotate bullet
        bulletcheck(a);  //check screen boundaries etc.
    }
}

function killbullet(arraypos:Number){
    removeMovieClip(_root['bullet_'+bullet_IDs[arraypos]]); //remove the bullet
    if (!(arraypos == (bulletcount - 1))){        //if its not the end of the array
        for (i = arraypos+1;i<bulletcount;i++){ //then move everything in the array   
            bullet_xs[i-1] = bullet_xs[i];        //above this point down one position
            bullet_ys[i-1] = bullet_ys[i];
            bullet_xspeeds[i-1] = bullet_xspeeds[i];
            bullet_yspeeds[i-1] = bullet_yspeeds[i];
            bullet_rspeeds[i-1] = bullet_rspeeds[i];
            bullet_powers[i-1] = bullet_powers[i];
            bullet_hps[i-1] = bullet_hps[i];
            bullet_IDs[i-1] = bullet_IDs[i];
        }
    }
    bulletcount--;  //decrement bullet count
}

function bulletcheck(arraypos:Number){
    cx = _root['bullet_'+bullet_IDs[arraypos]]._x;  //get x and y position
    cy = _root['bullet_'+bullet_IDs[arraypos]]._y;
    //check stage boundaries
    if (cx < stagexmin || cx > stagexmax || cy < stageymin || cy > stageymax){
        killbullet(arraypos);
    }
}



I think I might have to muck around with the size of the stage because it looks a lot bigger on the blog than it does in cs3. Anyway that's enough for tonight, I'm going to have a drink!

16 comments:

  1. Great work! I just can't believe how much work needs to be done to just get the gun to fire and move! I can see you are very talented, keep at it.
    I can't wait to see the final thing!

    ReplyDelete
  2. wow, i cant wait to see this game in action. sounds like you really are going the extra mile.
    im following this blog. thanks.

    ReplyDelete
  3. WOW I wish I could do that....seriously,the only thing I can do is make my robot on robocode go faster...

    ReplyDelete
  4. I've a new found respect for games developers! its insane how much work goes into the smallest element, can't wait to see how this game turns out!! We're always available for beta-testing! Keep up the good work

    ReplyDelete
  5. hey awesome man! im taking a class in java and python next semester maybe we can team up

    ReplyDelete
  6. Um, wow. This has come a LONG way in just two days. And a working example embedded in the blog? Yes please! I am really looking forward to you developing more features of the game.

    ReplyDelete
  7. Nice game you made there !

    ReplyDelete
  8. It seems like you're making excellent progress already. I had no idea that it took so much coding to make a basic flash game. Keep it up!

    ReplyDelete
  9. That's really interesting! If you need a 2D artist for a game you wanna make, just visit my blog (Carton Caron).
    I love your blog man! Follow!

    ReplyDelete
  10. Wow! It's really cool seeing the code, and getting a step by step on what it means and how it will affect the game. Awesome blog. Keep up the good work, and I can't wait to check this game out!

    ReplyDelete
  11. Wait, lemme guess if I got this straight: you're writing a game and posting about it daily? Omg, that's so exciting!
    Following and supporting, can't wait for more! :)

    ReplyDelete
  12. awesome dude! that some pretty nice code ya got there!

    ReplyDelete
  13. This post made me appreciate all the hard work that goes into video game development that much more. It's fascinating how much coding is necessary for what seems like such a simple thing on the surface. Kudos to you good sir. +follow

    ReplyDelete
  14. Wooooah! Now you just gotta figure out upgrades and bullet types...

    I'm rootin' for ya, m'man! Go go, make a whompin' game!!

    ReplyDelete
  15. This is dizzying. Had no idea so much went into this stuff. Keep it up.

    ReplyDelete