Posts Tagged ‘bullets’
-
Phaser Coding Tips 7
23rd Feb 20151Phaser Coding Tips is a free weekly email – subscribe here.
Welcome!
Shmupjam is a game jam dedicated to creating shoot-em-up games. As it’s now in full flow I figured it’d be great to see some Phaser entries for it. Therefore this weeks Coding Tips is dedicated to all things bullety and shooty.
Get the source
I’m only going to highlight the most important parts of the code here. So please always look at the source first. If you’ve questions about something I didn’t cover then ask on the forum.
Run / Edit the code on jsbin or codepen
Clone the phaser-coding-tips git repo.
Infinite Ammo
The whole point of a shoot-em-up is of course shooting things. For this you need bullets. Lots of them. Creating new objects in JavaScript (or indeed any language) is expensive. So what we do is pre-build all our bullets up front. Then as they are fired, they move across the screen and once outside we free them up, putting them back into the pool, ready to be reset and fired again as needed. This way we don’t generate any new objects at all during the game loop.
To manage this I’m using a single
Bullet
object. This is essentially a Sprite with a couple of extra features:var Bullet = function (game, key) { Phaser.Sprite.call(this, game, 0, 0, key); this.texture.baseTexture.scaleMode = PIXI.scaleModes.NEAREST; this.anchor.set(0.5); this.checkWorldBounds = true; this.outOfBoundsKill = true; this.exists = false; this.tracking = false; this.scaleSpeed = 0; };
The first line tells Pixi to use nearest neighbour scaling. This means when the bullet is scaled from its default size it won’t be automatically ‘smoothed’ as will retain its pixel crispness.
The
checkWorldBounds
andoutOfBoundsKill
lines pretty much do exactly what they say. They will check if the bullet is within the world bounds and if not kill it, freeing it up for use in the bullet pool again.The
tracking
property tells the Bullet to rotate to face the direction it is moving in, as it moves. This is handled in itsupdate
method. FinallyscaleSpeed
is how fast the bullet should grow in size as it travels. Both of these settings are used by some of the weapons as you’ll see shortly. Read More -
Flash Game Dev Tip #8 – Building a Shoot-em-up Part 3 – Return Fire
5th Apr 2011Tip #8 – Flixel – Building a Shoot-em-up, Part 3 – Return Fire
This tip follows-on from Tip #4, where we added enemies and explosions into our game. But it was a little one-sided. This time the enemy are going to shoot back. And you’ll feel it, by way of a health bar and set of lives in our new HUD. Finally we’ll drop in the scrolling tile-map background and simple menu / game-over states. By the end it will look like this:
Note: I’ve embedded the game at the bottom of the tip.
Return Fire
Last time we added the Enemy Manager, which spawned a regular supply of enemies at us. Each enemy had a launch function which set it moving. Let’s add the ability to fire to that:
// Will they shoot at the player? 70% chance of doing so if (FlxMath.chanceRoll(70)) { willFire = true; fireTime = new FlxDelay(1000 + int(Math.random() * 500)); fireTime.start(); }
This uses a new FlxMath function chanceRoll. The enemy has a 70% chance of firing at you. If this happens we create a new FlxDelay Timer of 1 second + up to an extra 0.5 second, and start it running.
Then in the Enemy update function we check that timer:
if (willFire && fireTime.hasExpired) { Registry.enemyBullets.fire(x, y); willFire = false; }
As you can see, this is calling the fire function in our Enemy Bullet Manager, passing in the x/y coordinates of the Enemy, which launches a bullet from the bullet pool:
public function fire(bx:int, by:int):void { x = bx; y = by; FlxVelocity.moveTowardsObject(this, Registry.player, speed); exists = true; }
FlxVelocity tells the bullet (this) to move towards the player at the value of speed (which in our case is 240 pixels per second).
-
Flash Game Dev Tip #4 – Bullet Manager Part 2
5th Mar 2011Tip #4 – Flixel – Bullet Manager Part 2
This tip follows-on from Tip #3, where we got a player controlled space-ship up, and had it fire all kinds of bullet death. In this tip we’re going to add something to use those bullets on – an Enemy manager, and a particle effect for when they are shot. By the end it’ll look like this:
Enemy Manager
As with the bullets in the previous tip we are going to create an Enemy Manager. This class will be responsible for creating a pool of enemies, launching them and recycling them when killed.
package { import org.flixel.*; import flash.utils.getTimer; public class EnemyManager extends FlxGroup { private var lastReleased:int; private var releaseRate:int = 500; public function EnemyManager() { super(); for (var i:int = 0; i < 100; i++) { add(new Enemy); } } public function release():void { var enemy:Enemy = Enemy(getFirstAvail()); if (enemy) { enemy.launch(); } } override public function update():void { super.update(); if (getTimer() > lastReleased + releaseRate) { lastReleased = getTimer(); release(); } } public function bulletHitEnemy(bullet:FlxObject, enemy:FlxObject):void { bullet.kill(); enemy.hurt(1); Registry.fx.explodeBlock(enemy.x, enemy.y); FlxG.score += 1; } } }
Our Enemy Manager works identically to the Bullet Manager from before. It starts by creating a pool of 100 enemies, which I admit is probably 90 more than we actually need at this stage of the game! Enemies are just extensions of an FlxSprite, and by default they have their exists value set to false, so they are free for allocation by the manager.
The manager overrides the flixel update function. All we do in there is check the value of the timer. getTimer() is a Flash utility class that gives you the number of milliseconds since the SWF started playing. It’s a really good way of timing things without having to use Timer Events, as it’s just integer based, fast and pretty accurate.
Our releaseRate is set to 500. That’s in milliseconds, so 500 would be every half a second (1000 ms per second). If enough time has elapsed we release a new enemy. This simply pull the next available enemy from the pool and call its launch function.
The enemy class looks like this:
package { import org.flixel.*; public class Enemy extends FlxSprite { [Embed(source = '../assets/space-baddie.png')] private var enemyPNG:Class; public function Enemy() { super(0, 0, enemyPNG); exists = false; } public function launch():void { x = 64 + int(Math.random() * (FlxG.width - 128)); y = -16; velocity.x = -50 + int(Math.random() * 100); velocity.y = 100; health = 4; exists = true; } override public function kill():void { super.kill(); FlxG.score += 20; } override public function update():void { super.update(); if (y > FlxG.height) { exists = false; } } } }
We extend an FlxSprite but make two significant changes.
3, 2, 1, Launch!
The code in the Enemy launch function does two things. 1) It places the enemy at a random x coordinate, and just off the top of the screen, with a random x velocity. And 2) it resets its health to 4 and tells flixel it now exists.
By giving it 4 health it means it’ll take 4 shots to kill the alien.
We also override the kill function to give the player + 20 points to their score once the alien is dead.
The final small change is in the update function. If the alien flies off the bottom of the screen, we set its exists to false. If we didn’t do this it’d just carry on flying down into game space, where the player will never see it, and eventually our pool would run out of aliens to launch.
Collision
Our PlayState.as class has been expanded ever so slightly from last time. It now includes the enemies on the flixel display list, and the fx class which we’ll cover in a moment.
Crucially in the update function we run a collision check:
FlxU.overlap(Registry.bullets, Registry.enemies, Registry.enemies.bulletHitEnemy);
FlxU is the flixel general utilities class. And one of those utilities is called “overlap” which will tell us if any two objects are overlapping. The parameters you pass are the two objects to test and a function to call if the overlap is true.
You can pass in whole groups of objects, which is what we do in this case. We’re asking flixel to check all bullets in the bullets group, against all enemies in the enemies group. And if it finds an overlap from two “alive” (existing) objects it will call the bulletHitEnemy function inside the Enemy Manager class.
The code for this function can be seen above, but it works by taking the 2 objects as parameters (in the order in which you define them in the overlap call, so in our case bullet first and enemy second.
In this game bullets can only hit once. So we call
bullet.kill();
which will remove the bullet from the screen, and free it up ready for use again by the bullet manager.
The alien however is a little more robust. Remember we set it to have a health of 4? So when it gets shot we’ll “hurt” it by 1. Flixel objects have a hurt() method, which when called will reduce the objects health variable by the amount given:
enemy.hurt(1);
In this instance we’ll “hurt” it by 1. Perhaps if the player was using super-bullets we could hurt it by 4, which would kill it instantly. Flixel will minus this amount from the health of the alien, and if its equal to zero it then calls kill on the object. As we over-rode the kill() method in Enemy.as we know the result of this is that the player gets 20 points added to their score.
After the bullet has been removed, and the alien hurt, we unleash a particle effect and increase the players score by 1. So for every bullet that hits an alien their score increases by 1, and a small particle shower happens.
The particle effect is controlled by the Fx class. When the alien is hit we call:
Registry.fx.explodeBlock(enemy.x, enemy.y);
Our explodeBlock function takes 2 parameters, and x and a y value which it uses to control where to start the explosion effect.
Boom, shake the room
The Fx class is responsible for controlling our FlxEmitters. In the world of flixel these are objects capable of emitting a series of FlxSprites with pre-defined velocity, rotation and gravity. Basically, you can make pretty particle effects using them.
Our Fx class creates a pool of 40 FlxEmitters and puts them into an FlxGroup. Every emitter is the same.
It also creates one more emitter called jets. This is used to create the jets trail that comes from the back of the players space ship.
In the Fx class we over-ride the update function and use it to position the jets at the x/y coordinates of the player:
jet.x = Registry.player.x + 4; jet.y = Registry.player.y + 12;
The +4 and +12 values are just to position the emitter into the correct place, so it looks like it is coming from the back of the ship rather than the top left (the default x/y origin).
As you can see, having access to the player via the Registry is extremely handy here (see Tip #1 if you don’t know what the Registry is)
The explodeBlock function is the one that launches the particle shower when an alien is shot. It’s extremely simple:
public function explodeBlock(ax:int, ay:int):void { var pixel:FlxEmitter = FlxEmitter(pixels.getFirstAvail()); if (pixel) { pixel.x = ax; pixel.y = ay; pixel.start(true); } }
It just gets a new emitter from the pool (if there is one available), places it into the correct x/y location for where the bullet hit the alien, and starts it running. The true parameter tells the emitter this is an explosion, so all of the particles will be fired out at once rather than bursting continuously.
Download
With just a few extra classes our game has now come on quite a way. We’ve got aliens that fly down at you, bullets that can blow them to shreds, a nice particle trail following the ship and a pretty explosion for when things go boom. All in very few lines of hopefully easy to follow code.
In the next tip I’ll make the enemies fire back at you, give you a health bar and a number of lives. We’ll then add a scrolling tilemap background to really elevate things.
Download the source code and SWF from the Flash Game Dev Tips Google Code Project page.
-
Flash Game Dev Tip #3 – Bullet Manager Part 1
25th Feb 2011Tip #3 – Flixel – Bullet Manager Part 1
If you are coding a shoot-em-up, or even a platformer with guns, then you’ll have a need for the player to be able to fire bullets. Or the enemies to fire at you. This tip is about creating a Bullet Manager class. The class is responsible for the launch, update, pooling and re-use of bullets.
Object Pool
Creating new objects in Flash is expensive. By “new objects” I mean code such as:
var bullet:Bullet = new Bullet();
… which creates a brand new object an assigns it to bullet.
And by “expensive” I mean it takes time for Flash to process the request for the new object, assign memory to it and create it. If you are firing off tens of bullets every few seconds this can take its toll. And if you don’t actively clean-up the objects created you can quickly run out of resources.
To mitigate this problem we create a “pool”. This is a pool of resources (in our case bullets) that the Bullet Manager can dip in to. It will look for a free bullet, and recycle it for use in the game. When the bullet has finished doing what bullets do best, it will free itself up for use again. By using a pool you avoid creating new objects on the fly, and help keep memory in check.
Meet FlxGroup
Thankfully flixel has a class you can use to make this process simple. It’s called FlxGroup. You can add objects to a group, there are plenty of functions for getting the next available resource, and you can even perform group to group collision. Objects in a group are all rendered on the same layer, so are easy to position within your game. The first task is to create a pool of bullets to draw from.
In this example we’ve got a class called Bullet.as. Bullet extends FlxSprite with a few extra values such as damage and bullet type.
package { import org.flixel.FlxSprite; public class Bullet extends FlxSprite { [Embed(source = '../assets/bullet.png')] private var bulletPNG:Class; public var damage:int = 1; public var speed:int = 300; public function Bullet() { super(0, 0, bulletPNG); // We do this so it's ready for pool allocation straight away exists = false; } public function fire(bx:int, by:int):void { x = bx; y = by; velocity.y = -speed; exists = true; } override public function update():void { super.update(); // Bullet off the top of the screen? if (exists && y < -height) { exists = false; } } } }
The important part is that the bullet sets exists to false when created to make it immediately available for use. When fired the bullet will travel up the screen. The check in the update method simply sets the bullet to not exist once it has passed y 0 (the top of our screen).
So far, so simple. Next up is the BulletManager.as class. This extends FlxGroup. It begins by creating a pool of 40 bullet objects and adding them to the group ready for use. As all of them have exists equal to false none will render yet.
package { import org.flixel.*; public class BulletManager extends FlxGroup { public function BulletManager() { super(); // There are 40 bullets in our pool for (var i:int = 0; i < 40; i++) { add(new Bullet); } } public function fire(bx:int, by:int):void { if (getFirstAvail()) { Bullet(getFirstAvail()).fire(bx, by); } } } }
It has one extra method called fire. This gets the first available bullet from the pool using getFirstAvail (the first bullet with exists equal to false) and then launches it from the given x/y coordinates by calling the bullets fire function.
Are you feeling lucky?
I insert the Bullet Manager into the games Registry (see Tip #1 if you don’t know what the Registry is) so my Player class has easy access to it. My Player class is a simple sprite with keyboard controls to move it around. When you press CTRL it will fire a bullet:
Registry.bullets.fire(x + 5, y);
The Bullet Manager handles the request and launches a bullet up the screen. The +5 after the x value is just to visually align the bullet with the middle of the space ship, otherwise it’d appear off to the left.
At the beginning of the Bullet Manager class I hard-coded in a limit of 40 bullets. That is enough for my game. As you can see in the screen shot above I’m only using 32 bullets out of a pool size of 40.
This value may not be suitable for your game. I don’t know what value you need, only you do. Perhaps you are coding the next Ikaruga, in which case you probably need 40 bullets per pixel 🙂 The thing is, you can tweak this as needed. And you can tweak it in-game too. It’s not a value that should change dynamically, but it could easily change from level to level as the game progresses.
Download
This example is about as simple as I could make it, but hopefully you can see the benefits already. In the next tip I’ll add group collision detection and something for you to shoot at.
Download the source code and SWF from the new Google Code Project page.
Hire Us
All about Photon Storm and our
HTML5 game development services
Recent Posts
OurGames
Filter our Content
- ActionScript3
- Art
- Cool Links
- Demoscene
- Flash Game Dev Tips
- Game Development
- Gaming
- Geek Shopping
- HTML5
- In the Media
- Phaser
- Phaser 3
- Projects
Brain Food