Sidescrolling Platformer — Part 11 — Fixing the bullets

Although we did get some functional bullets last time by using the Bullet class, we still need to make some major improvements. First of all, the bullets are added directly to the stage and have no idea about the scrollX and scrollY variables, so they don’t react when the player moves left, right, up, or down. Also, the bullets move at a sluggish pace — if they did react to the player’s movements, you could practically outrun them. Finally, they are never actually removed from the stage, so we waste precious memory that slows down the game. Imagine that we fired 1,000,000 bullets. The game would still be keeping track of all of them, constantly updating their positions, even if they are no longer on the stage. There’s some more code we can add to the bullets to handle all of this, and we are going to implement it in this tutorial.

Problem #1: Scrolling

I’m going to get right to the point on this one: our problem is that we called the addChild(bullet) method on the stage. This means that the bullets will always move at their standard speeds on the stage, no matter what the background is doing in terms of scrolling.

Solution: Call the addChild(bullet) function on the background. It makes sense, really. We want the bullets to behave as if they were moving around the background, not the stage, and so that’s exactly what we do.

Modify the code from the fireBullet() function you created in Part 10.

var bullet:Bullet = new Bullet(player.x - scrollX, player.y - scrollY, playerDirection);
back.addChild(bullet);

You might be wondering what all that “player.x – scrollX” is doing. The answer is that the coordinates of the background are different than those of the stage. If we want to add the bullet in the background so that it appears in the middle of the stage, we can’t just use the player’s x and y positions. If we did that, the bullet might appear at (320, 240) in the background, which is near its upper-left corner. To ensure that the bullet actually spawns in the correct position, we need to subtract the scrollX and scrollY variables from their respective positions.

Try it out. Your bullets should respond realistically to scrolling. But try chasing them… we have another problem…

Problem #2: Speed

As you can see if you’re following along, you can outrun the bullets (at least if you’ve used my maxSpeed variables). That’s because my player’s maxSpeed is 18, and the speed of the bullets is only 10. There are a couple things we can do to fix this. One would be to just fire the bullets at a speed so fast that it wouldn’t matter if the player was running — the bullets would still greatly outpace him. I’m going to increase the speed of my bullets to 30. If we go too much faster than this, it might look bad because the frame-rate of the game is only 30fps, so the bullets might looks like they are jumping forward instead of smoothly animating.

There is no single correct way to make the bullets look good, so you’ll have to decide on your own what to do, but here’s what I’m doing. In addition to upping the speed to 30, I am also going to add the speed of the player when the bullet was fired. So if the player is standing still, the bullet will move 30 pixels per frame away from him. If the player is running at a speed of 18, the bullet will be fired with a speed of 48, so it still looks like it is moving away from him at 30 pixels per frame. You’ll see that this has problems of its own, but it’s up to you to decide which way you want to go.

Anyways, here’s my code.

First, change the header for the constructor function of the Bullet class, so that it accepts an additional parameter: playerSpeed.

public function Bullet(playerX:int, playerY:int, playerDirection:String, playerSpeed:int) {

Then, to accomplish the speed effect I described above, edit that the conditional inside that function so that it matches this:

if(playerDirection == "left") {
    speed = -30 + playerSpeed; //speed is faster if player is running
    x = playerX - 25;
} else if(playerDirection == "right") {
    speed = 30 + playerSpeed;
    x = playerX + 25
}

By adding the player’s speed to the bullets, our bullets are guaranteed to be launched away from the player at a set speed. It isn’t perfect, because you can still shoot a bullet while you are standing still (it’s speed will only be 30), and then chase after it, but because the player’s speed can only reach 18, this still isn’t too big of an issue.

In order to make this change take effect, we must update the code on the main timeline to give the bullet the player’s speed when it is created. Find the fireBullet() function, and modify the bullet declaration:

var bullet:Bullet = new Bullet(player.x - scrollX, player.y - scrollY, playerDirection, xSpeed);

That should do the trick! Compile and run your code, and you should have semi-intelligent, fast moving bullets. Now we only have one more immediate problem: getting the bullets to disappear…

Problem #3: Removing the Bullets

As with the last problem, there are a number of different ways to fix this. And depending on how you want your game to run, you might choose a different method that I am using. For example, do you want the bullets to disappear when they leave the screen, or maybe after a set amount of time, or perhaps after they have traveled a certain distance? That’s up for you to decide. There are advantages and disadvantages for each possibility.

I’m going to go with the third option: remove the bullets after they have traveled a set distance. Because the bullets are added directly to the background, not the stage, we can’t really remove them after they leave the stage. The time-interval method would probably work just as well, but I didn’t feel like messing around with timers right now, especially when the alternative option is so easy.

I added a new variable to the Bullet.as class:

private var initialX:int;

Then add the following line of code near the end of the constructor:

initialX = x; //use this to remember the initial spawn point

The next step is to add this conditional to the bullet’s loop function:

if(speed > 0) { //if player is facing right
    if(x > initialX + 640) { //and the bullet is more than 640px to the right of where it was spawned
        removeSelf(); //remove it
    }
} else { //else if player is facing left
    if(x < initialX - 640) { //and bullet is more than 640px to the left of where it was spawned
        removeSelf(); //remove it
    }
}

Depending on which direction the player is facing, the bullet will constantly check how far away it is from where it was spawned. If the distance is ever greater than 640, the bullet will remove itself (640 is a somewhat-arbitrary number, I chose it because it is the width of the stage, but it doesn’t need to be).

One last step: we haven’t created the removeSelf() function yet. Add this function to the Bullet class:

public function removeSelf():void {
    trace("remove self");
    removeEventListener(Event.ENTER_FRAME, loop); //stop the loop
    this.parent.removeChild(this); //tell this object's "parent object" to remove this object
    //in our case, the parent is the background because in the main code we said: back.addChild(bullet);
}

As you can see, we use the keyword “this” to refer to the bullet object from within its own class. And we can use the keyword “parent” to access the bullet’s “parent object”. The parent object is the object that the bullet is added to. We added the bullet to the background, so when we call removeSelf(), the bullet tells the background to removeChild the bullet.

That concludes all of the obvious fixes we needed to make. Test the game — it should work nicely. The bullets travel independently of the player, they move fast, and they actually disappear!

The bulletList Array

I wish I had the time to introduce enemies into the levels right now, but there’s one more thing we need to do first…

What happens to our bullets after we create them? They were declared dynamically in the fireBullet() function. After that, we have no way to access them from the main timeline. We lost our reference to the bullet. Let’s say we wanted to check in our main loop to see if the bullet collided with anything. How would we tell the bullet to do anything if we don’t have access to it?

Luckily, there is a fairly easy way to manage this problem…

introducing, the array.

If you’ve never used an array before, have no fear. They don’t bite. An array is basically a list. You can store a list of numbers, a list of strings, even a list of Bullets within a single array. You can easily access the length of an array to find out how many things are in your list, and you can access a specific thing inside your list by using its index. An object’s index is just a number that represents its placement in the list. The first object has an index of (yes, this can get a little confusing, but it does begin at zero). The second object in an array has an index of 1, the third has an index of 2, etc. An array can store a practically-infinite amount of any kind of object or variable.

Arrays are very powerful, and have advanced applications as well as simple ones. If you’re interested in learning more about the awesome features of arrays, I definitely recommend this comprehensive article on ActiveTuts+

We are going to use an array to keep track of all of our bullets. Whenever we create a bullet, we can add it to our array. This way, we’ll have a reference to each bullet that we can use when we are doing hit-testing with enemies.

First things first, declare a new Array variable in at the top of your code in the main timeline, called the bulletList:

var bulletList:Array = new Array();

Next, go back to the fireBullet() function, and add the following code to the end of it, which will add the bullet to the bulletList array.

bulletList.push(bullet);

That keyword “push” is the best way to add an object to your array. It “pushes” your bullet onto the end of the array.

This however, gives us another problem: when we call the removeSelf() function inside the Bullet class, it removes the bullet from the stage — but it doesn’t remove the bullet from the array. There is a clever way to do this, which involves adding an eventListener to the bullet when we create it. This event listener will activate whenever the bullet is removed (which happens after we call the removeSelf function). Right below the line of code you just added in fireBullet, add the following:

bullet.addEventListener(Event.REMOVED, bulletRemoved);

Finally, add this new function, bulletRemoved. You probably won’t understand exactly what it’s doing the first time you read it. Don’t worry — it’s just a clever solution that removes the bullet from the array. Just how push adds an object to an array, the keyword splice removes an object from an array. The difference is that splice needs a bit more information: it needs to know the index of the object you want to remove, and it also needs to know how many objects you want to remove. For most cases (including this), you only want to remove 1 object.

function bulletRemoved(e:Event):void {
    e.currentTarget.removeEventListener(Event.REMOVED, bulletRemoved); //this just removes the eventListener so we don't get an error
    bulletList.splice(bulletList.indexOf(e.currentTarget), 1); //this removes 1 object from the bulletList, at the index of whatever object caused this function to activate
}

(Note: the “e” is used to get information specific to the event. You can use e.currentTarget to get a reference to whatever object which activated the event.)

If you run your code, you’ll see that nothing changed. That’s OK. We accomplished the important task of adding the behind-the-scenes code that will make the next tutorial possible: adding enemies!

I know you’re all waiting for the enemies, and I assure you that they are coming next. Until then, make sure your bullets are working properly. And hey, if you’re up for it, try using what you’ve learned about the bullets to create a custom Enemy class, and see if you can add one to the background so that it appears near the player when you start the game.

In case you need them, here are the source files.

Good luck!

EDIT: The enemies tutorial is now live, here: Part 12 — Basic Enemies

42 comments on “Sidescrolling Platformer — Part 11 — Fixing the bullets

  1. danman113 says:

    You should add momentum.

    • Ben Reynolds says:

      Thanks for the feedback, but can you explain this a little more — I’m not sure exactly what effect you are suggesting.

      • Mike says:

        I think he means gravity, air friction, etc. for the projectile

        • SiCong says:

          Momentum is the product of mass and speed. In this situation I think he meant to use this physics term to achieve effects like the recoil speed of the character after firing a bullet etc.

  2. Hello Ben. with the shooting animation i got a player aiming a gun when the left key or right key is held down. i want to make him when (left or right) held down then when press space shoot.

    so i have done

    1) Control to go into gun mode (Control again to go into walking mode << ignore)
    2) left aims left
    3) right aims right
    4) if left or right is down + Space is pressed shoot in that direction.

    Having big trouble with this..?

    • Ben Reynolds says:

      Alright, you basically have a big logic puzzle, so here’s what I would do:

      (I’m assuming you’ve already figured out how to go into gun-mode)

      First declare a new variable at the top of your program: var shootAvailable:Boolean = false
      If this variable is “true”, it will mean that:
      1) The player is in gun-mode.
      2) Either the left or the right arrow key is pressed down

      For simplicity’s sake, I’ll assume you have a Boolean variable called “gunMode”, which is “true” when the player is in gun-mode.

      Go to your main game loop. Create a conditional somewhere near the end of the function:

      if ( gunMode == true) {
      if( leftPressed || rightPressed) {
      shootAvailable = true;
      } else {
      shootAvailable = false;
      }
      } else {
      shootAvailable = false;
      }

      This will make shootAvailable be true during the conditions you specified.

      Now go to the keyUpHandler function, and edit the part that has to do with the spacebar:

      if( e.keyCode == Keyboard.SPACE ) {
      if(shootAvailable == true) { //this is the new part
      fireBullet();
      }
      }

      The code to fire the bullet left or right is already in the fireBullet() function, so that should be all you need.

      Let me know how it all works out. I’d love to see your game when it’s finished!

      – Ben

      • Thanks Ben Mate. I am telling you now it is looking great the game. its like a horror/side scroller/point and click game.

        Doing it for just fun really. My animation and design skills are pretty good now.

        If you can imagine a cross between resident evil, Broken Sword & (Beavis and butthead gameplay) lol thats what its shaping up to be.

        I did the first level and will send you a preview when i get home. I then tried to do the second level and realized how important using external classes are. I wrote it in the timeline and I am getting so many debugging errors when I want to move onto the next level. (Duplicate functions and all sorts more).

        I will not proceed with it until I have completely re-structured the code in a more efficient way. Timeline gets a bit messy! lol

        Well done with the tuts though they are really good.

        Shaun

        • Ben Reynolds says:

          Thanks, and sounds like a job well done on your part. I agree that programming on the timeline is messy. To be honest, the only time I ever do so is when I write tutorials for this site, the reason being that it is easier for a beginner to learn. For all of my serious projects, I always use external classes to code the game. Hopefully I’ll be able to add more advanced tutorials to this site in the future, now that I already have some covering the basics.

  3. Kalejoop says:

    Really enjoy these tutorials.

    Maybe you can add a tutorial on deadly spikes or a lava pitt. Meaning, that when you hit a certain object, you die. Or when you glitch under the map you die.

    I made both Pong and the platform game in 2 days! (I’m free because of my summer holidays, so i’ve got a lot of time on my hands) The tutorials are really well explained and it’s just so much fun! I also learned a lot following these tutorials. Maybe a few more tut’s and I’ll actually start designing own my very first game.

    Anyways, thank you so much for creating these tutorials,

    • Ben Reynolds says:

      Awesome, thanks for the feedback! Yes, lava/spikes is definitely a cool feature, and it is actually very easy to add. I can probably write about it after I add the enemies. I’m glad you’re enjoying Flash — it really is a great tool for making games. Good luck!

  4. Star says:

    Is there a way to implement some sort of Heads Up Display? I’d like to go ahead and add health bars and a score field, some enemies and maybe even a minimap as I got lost in your Cow game lol.

    Fantastic Work btw

  5. Loved all these tutorials, i was a first time user of flash a few weeks ago and managed to go through tutorials to learn the basic drawing and animation and web design parts but was struggling when it came to games but this tutorial has helped massively, took me a day in work to run through all the steps and have just started another one from scratch with better visuals than my original adding in a few pieces of my own along the way. Cant wait for the enemies tutorial, i managed to make the class and get the enemies to appear just struggling to get them to interact with my bullets but will be patient until the next step is up. also i was trying to add moving platforms/elevators to my levels, i used the hittestobject method as it was just square platforms and the elevator worked sort of ok going down the way but up the way my player fell straight through, any advice? thanks again and keep up the good work.

  6. Logan says:

    Thanks for the extra lesson on the bullets, im just curious but if you have a little time to spare for a mini lesson, is it possible to write up or direct us to a tutorial for a Inventory system?

    I know we have a key in the previous lessons, but it disappears and stays with the character, i was wondering if its possible to create a way to select items to use for the character.

    but other than that… Awesome job :D

  7. BlueLightning says:

    not sure if you will look at the comment i posted on part 8, but i really need an answer please…sorry if this is annoying…

    Hi whenever i take all your code and put it into my game it works but it comes up with this output error

    TypeError: Error #1010: A term is undefined and has no properties.
    at startGame999999_fla::MainTimeline/gotoLevel2()
    at startGame999999_fla::MainTimeline/nextLevel()
    at startGame999999_fla::MainTimeline/keyDownHandler()

    yet when i play yours it works without that error,,, and also my levels keep flashing/switching between eachother while playing….also if anyone could help with making coins that when the player touches the coin it adds to a score and disappears. Thanks everyone!

  8. BlueLightning says:

    What is the code for coins that when the character touches the coin it disappears and adds 100 to the score? Thanks

  9. BlueLightning says:

    Hey, if you can help me thanks! Iam trying to add coins to my game and well ive tried and cannot get it to work, for when player touches coin it disappears and adds 100 to a score! If you know the code for this can you please share! Thanks again!

  10. Any update on when the next enemy class will be up? Thanks

    • Ben Reynolds says:

      Sorry, but I’ve been busy with my real job, and I probably won’t get it out this weekend either. Hopefully early next week, though. Stay tuned :-)

      • jay to the jay says:

        do u reckon you can add a health bar for our character as well
        so when the enemy attacks, the character takes damage. thanks again for these awesome tutorials =)

        • Michael says:

          He made a mini tutorial showing how to add a health bar. Check it out under “Mini-Lessons”.

        • Ben Reynolds says:

          Yeah, I do already have a tutorial on making a health bar, but I can show how to integrate it into this project. And yes, I’ll show how to make the player to get hurt each time he collides with the enemy.

  11. MTB says:

    Ben, you should add a PayPal donation button on your site. Tutorials of this quality deserve support and funding. Thanks for putting the time into making them

  12. Lisa says:

    Dear Ben, you are awesome! Thank you so much for these tutorials. Can’t wait for the next one!

  13. Michael says:

    Hey Ben I know your busy with other things and working on the enemies tutorial (which I’m pumped for). But I’m working on a coin.as and I have the coins disappearing but I can’t get the score to up update. I have been racking my brain for the past 6 hours and I know I missing something stupid. Haha. Thanks for your help in advance!!

    package
    {
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.display.Stage;
    import flash.text.TextField;

    public class Coin extends MovieClip
    {
    var player:MovieClip;
    var score:uint;
    var coins:TextField = new TextField();

    public function Coin()
    {
    init();
    }

    public function init():void
    {
    // constructor code
    coins.text = String(score);
    score = 0;
    addEventListener(Event.ENTER_FRAME, coinLoop);
    }

    public function coinLoop (e:Event):void
    {
    player = MovieClip(root).player;
    if(this.hitTestObject(player))
    {
    score ++;
    coins.text = String(score);
    removeSelf();
    }
    }
    public function removeSelf():void
    {
    trace (“remove self”);
    removeEventListener(Event.ENTER_FRAME, coinLoop); //stops the loop
    this.parent.removeChild(this);
    }
    }

    }

    • Ben Reynolds says:

      What I would do (and what I will demonstrate in a future tutorial — I’m planning to add coins at some point), is to move the “score” variable back to the rest of your code on the main timeline. If you have an eventListener on the main timeline waiting for the coin to be removed (like we did with the bullets), then you can increase the score by 1 and update the score text from that function that gets called each time a coin is removed. That way, the coin itself doesn’t need to worry at all about the score. It just does its job by waiting around and disappearing. Then the main “brain” of your function (the timeline code) steps in and calculates the details.

      Let me know if you need any other help.
      Ben

  14. tyler says:

    I’m zooming everything on the stage using scaleX/scaleY (player’s left and right movements are fixed basically if the stage is zoomed = true then the appropriate scale which works fine) things are looking really cool at the moment the only problem left scaling the bullets… as they are no longer spawning on the players arm. Any ideas as i’ve tried scaling the bullets (although need too as they are scaled with the background obviously) and even rerunning initialX = x? :/

    Any help would be greatly appreciated.

  15. Adolfo Gabriel says:

    How can I do to when the player shoot, plays some kind of animation?
    I think that to do that, I must turn off the animation loop, play the animation, and then turn on the loop. But I don’t know how to create a global variable, a boolean, that will let the loop able when is true, and turn off when is false… in C# this is basicly create a public variable, but on Action Script it seems to be different…

    • Dreamonic says:

      Hello,

      I also had this problem. I wanted to add a punch animation, so that I would be able to punch the enemies rather than shooting them.

      What I did:

      I made an extra animation frame in your characters symbol (like you did for running, jumping, …), in which I made the punching animation (just the arm going back and forth).

      You give this animation a label, the same way you did with the others.

      Then you go back to your main code, and add a boolean for the key you want to activate the animation with (I did it with the spacebar).

      Go to your KeyDown- and KeyUpHandler, and add a simple if(e.keyCode = KeyCode.SPACE){} (or something like that) statement to the code, similar to the others.

      Then, in your main loop, add an if() statement to the bottom, where you say:

      if (key pressed boolean){
      animationState = “punching”; //where punching is the label you gave your animation
      }

      Be sure to NOT make these else if() statements, but IF statements! That way, if you add this code to the bottom of each of the functions, it’s priority is going to be higher than all other animations, resulting in this animation playing.

      I hope this helps a bit.

      If it doesn’t, don’t hesitate to ask for more help ;-)

      Cheers,

      Dreamonic

  16. Colt K says:

    Your solution to problem #1 caused my bullets to disappear. After adding that code I played the game to find that pressing space seemed to do nothing. Where have my bullets gone?! Help please!

  17. m weber says:

    (i hope you understand my english :D )

    thanks for your tutorials. they are very helpful for me ;)

    i think i have a improvement for the speed section.

    you have a “constant” var speed, but you must change the value manually in:

    if(playerDirection == “left”) {
    speed = -30 + playerSpeed; //here manually!
    x = playerX – 25;
    } else if(playerDirection == “right”) {
    speed = 30 + playerSpeed; //here manually!
    x = playerX + 25
    }

    that would be better:

    if (playerDirection == “left”)
    {
    speed = (speed * -1) + playerSpeed;
    x = playerX – 25;
    }
    else if (playerDirection == “right”)
    {
    speed = (speed * 1) + playerSpeed;
    x = playerX + 25;
    }

    so you must change the speed once.

  18. Noobie says:

    Hey Ben! Here’s my progress so far, this is my second Flash game (Pong was the first one)

    http://flashtestshit.webstarts.com/index.html?r=20130616054424

  19. majlan says:

    Hello, I’m wondering that nobody mentioned one thing – when you press UP+RIGHT, you can use SPACEBAR to shoot with no troubles. However, when you try to press UP+LEFT, shooting doesn’t work anymore! Do you have any idea why?

  20. majlan says:

    Hello, I’m wondering that nobody mentioned one thing – when you press UP+RIGHT, you can use SPACEBAR to shoot with no troubles. However, when you try to press UP+LEFT, shooting doesn’t work anymore! Do you have any idea why?

    • flash says:

      try this works ok for me now

      open the bullet class
      add
      private var playerX:Number;

      then change the code to below

      if(x initialX + playerX+640) { //and the bullet is more than 640px to the right of where it was spawned
      removeSelf(); //remove it
      } else { //else if player is facing left
      if(x < initialX – playerX+640) { //and bullet is more than 640px to the left of where it was spawned
      removeSelf(); //remove it
      }
      }

  21. flash says:

    Hi thx for tutorial
    I am finding that when I run right on a long screen the bullets are disappearing real quick or nor showing
    I found a simple solution listed below
    open the bullet class
    add private var playerX:Number;

    in the loop function
    change
    if(x > initialX + 640) {
    removeSelf(); //remove it
    }
    } else { //else if player is facing left
    if(x initialX + playerX+640) { //and the bullet is more than 640px to the right of where it was spawned
    removeSelf(); //remove it
    }
    } else { //else if player is facing left
    if(x < initialX – playerX+640) { //and bullet is more than 640px to the left of where it was spawned
    removeSelf(); //remove it
    }

    adding the playerX variable to the equation makes it seem to work correctly when its running right.

    hope it helps

  22. Rick says:

    Ben! Thanks for the tutorial and I’m using that for the Software Engineering project. My situation is that I’m using sword slashes as bullets but is there a code for the range limit?

    • Rick says:

      Now there’s a new problem! Ever since I added the projectiles, my game went unplayable. The character’s idle, running and jumping animations are erratic and it can’t move from place to place.

Leave a comment