kevin f.


Keeping Promises

I began experimenting with the free tier of Google Firebase for apps, and other goofy purposes. I’ve since implemented a new feature on a current project using Mithril.js, wherein users are able to edit and create new pages in real-time using Markdown. Because the creation of new pages are asynchronous and the app needs to know when Firebase has inserted the new data (or if it was rejected, or if there was an error, etc), the first thing that came to mind was ‘use Promises.’

Firebase methods return promises by default. This was great! So I created a handy little tool called firetool.js that will contain all methods pertaining to my Firebase connection, and make the development of my app a little easier:

// firetool.js
import * as firebase from 'firebase/app';
import 'firebase/database';

export const firetool = {
    db: null,

    init(config) {
        firebase.initializeApp(config);
        this.db = firebase.database();
    },

    createPage(page) {
        const ref = this.db.ref('views/pages');
        return ref.child(page).set({
            content: 'blank data'
        });
    }

    ...
}

All well and good. Firebase creates the request, returns a promise that my new page will be made (or not), and will keep me posted on the news. Now, it’s a simple matter of handling the response data, and what to do in case of a fire:

// pages.js
firetool.createPage(page)
	.then(() => {
		vnode.state.message = 'page created!';
		m.redraw(); // have to tell Mithril to refresh the virtual DOM!
	})
	.catch(() => {
		vnode.state.message = 'an error occured!';
		m.redraw();
	})

This works just fine, but the more I looked at it, the more I wanted to isolate logic to firetool.js, and keep the workload off pages.js. Additionally, I need to be able to check if the page exists before I attempt to create it.

The problem becomes that the state of pages.js needs to know when to set the vnode data, and update the view.

Eventually, it made more sense to wrap the existing Firebase promise within my own:

// firetool.js
createPage(page) {
    const ref = this.db.ref('views/pages');

    return new Promise((resolve, reject) => {
    	// Check if the page already exists
        ref.child(page).once('value', (res) => {

        	// If the reference result is not null
        	// the page already exists!
            if(res.val() !== null) {
                resolve({ message: 'page already exists' });
			} 

			// Attempt to create the page
			// Return an object containing the message to return
			else {
                ref.child(page).set({ content: '' })
                    .then(() => resolve({ message: 'page created!' }))
                    .catch(() => resolve({ message: 'an error occured!' }));
            }
        }, (err) => reject(err));
    });
}

And now it’s a simple call to firetool.createPage, and I can easily handle the response data.

// pages.js
firetool.createPage(page)
	.then((res) => {
		vnode.state.message = res.message;
		m.redraw();
	})
	.catch((err) => {
		vnode.state.message = err;
		m.redraw();
	})

One of the more useful features of the flixel library is the inclusion of the FlxTypedGroup class, which makes it easier to organize, update, and render multiple instances of an FlxBasic object. A few getter methods provide useful information such as the length of the group, or an array of every member in an instantiated group.

A practical application of FlxTypedGroup can be found in the ‘Asteroids’ demo available via the HaxeFlixel repository. FlxTypedGroup’s recycle method allows us to resuse bullet objects without having to destroy, recreate, and reallocate memory each time. Instead, bullets can be respawned from the queue after the pool has been “expended.”

Note: In the demo example available in the HaxeFlixel repository, the properties of each bullet are initialized on the fly within PlayState.hx. For my example, I have created a separate Bullet class for the sake of convenience.

In the current PlayState, we can create and initialize a pool called bullets which we will populate with bullet objects from which we can spawn bullets as we please. In this case, I will create a pool with a maximum size of 3.

class PlayState extends FlxState
{
	public static var bullets:FlxTypedGroup<Bullet>;
	override public function create():Void
	{
		var poolSize:Int = 3;
		var bullet:Bullet;
		bullets = new FlxTypedGroup<Bullet>(poolSize);
	}
}

From here, we can write a simple loop to create new bullet objects and simply add them to the existing group.

...
override public function create():Void
{
	var poolSize:Int = 3;
	var bullet:Bullet;
	bullets = new FlxTypedGroup<Bullet>(poolSize);
	for(i in 0...poolSize){
		bullet = new Bullet();
		bullets.add(bullet);
	}
}
...

Within our Player class, we can then just reference the main PlayState’s bullets pool to recycle bullet objects.

if(FlxG.keys.justPressed.Z){
	var bullet:Bullet = PlayState.bullets.recycle();
	//YOUR BULLET VELOCITY CODE GOES HERE
}

After this, we just add our standard logic that handles bullet velocity, acceleration, or how, when, and where your Sprite class may spawn bullet objects. As seen in the example below, only 3 bullets may be on the screen at one time, with the earliest spawned bullet being replaced.

Building on the example of the original Asteroids arcade game, we can give each bullet a limited lifetime, meaning if the bullet does not collide with another asteroid or enemy sprite, it should cease to exist after a certain period of time. Otherwise, it would continue travelling endlessly.

I was able to do this using HaxeFlixel’s FlxTimer class, however, you may also use the standard Timer class included in the Haxe Toolkit.

Within my Bullet.hx class, I declare timer and initialize it as an FlxTimer object in the class constructor.

class Bullet extends FlxSprite
{
	public var timer:FlxTimer;
	public function new(X:Float = 0, Y:Float = 0) 
	{
		super(X, Y);
		timer = new FlxTimer();
		//YOUR OBJECT PROPERTIES GO HERE
	}
	override public function update(elapsed:Float):Void
	{
		...
	}
}

Instead of creating a new FlxTimer object each time a bullet is recycled, the existing one is simply reset when needed.

Now back in the Player.hx class, we simply set and start the FlxTimer object for each bullet as they fire. The start method of an FlxTimer object takes three arguments:

start(Time:Float = 1, ?OnComplete:FlxTimer‑>Void, Loops:Int = 1):FlxTimer

Time:Float How many seconds it takes for the timer to go off. If 0 then timer will fire OnComplete callback only once at the first call of update method (which means that Loops argument will be ignored).

OnComplete:FlxTimer->Void Optional, triggered whenever the time runs out, once for each loop. Callback should be formed “onTimer(Timer:FlxTimer);”

Loops:Int How many times the timer should go off. 0 means “looping forever”.

In the example below, I pass 2.0 for Time, an anonymous function for OnComplete that switches the bullets exists flag to false, and 1 for Loops so that the function only triggers once.

if(FlxG.keys.justPressed.Z){
	var bullet:Bullet = PlayState.bullets.recycle();
	bullet.timer.start(
		2.0,
		function(Timer:FlxTimer){
			bullet.exists = false;
		},
		1
	);
}

So now, not only do you limit the amount of bullets that can be on the screen at once, but you can limit the duration for said bullets! It’s a very neat and useful mechanic for balancing your game that can be applied to any pool of FlxBasic objects you may need, whether it be enemies, ammunition, or environmental objects.


Music from 2015

In an order kind of like this, these were albums I enjoyed from 2015. Divers by Joanna Newsom is my favorite.

  1. Joanna Newsom - Divers
  2. Protomartyr - The Agent Intellect
  3. Battles - La Di Da Di
  4. Everything Everything - Get to Heaven
  5. Natalie Prass - Natalie Prass
  6. Algiers - Algiers
  7. Cloakroom - Further Out
  8. Bjork - Vulnicura
  9. Julia Holter - Have You In My Wilderness
  10. Lightning Bolt - Fantasy Empire
  11. Deafheaven - New Bermuda
  12. Milo - So the Flies Don’t Come
  13. Neon Indian - VEGA INTL. Night School
  14. Unknown Mortal Orchestra - Multi-Love
  15. Courtney Barnett - Sometimes I Sit and Think, and Sometimes I Just Sit
  16. Natalia LaFourcade - Hasta La Raiz
  17. Chelsea Wolfe - Abyss
  18. Oneohtrix Point Never - Garden of Delete
  19. toby fox - Undertale OST
  20. Car Seat Headrest - Teens of Style
  21. Kendrick Lamar - To Pimp A Butterfly
  22. Death Grips - The Powers That B
  23. Godspeed You! Black Emperor - Asunder, Sweet and Other Distress
  24. Caspian - Dust and Disquiet
  25. Hop Along - Painted Shut
  26. Sufjan Stevens - Carrie & Lowell
  27. toe - Hear You
  28. Beach House - Thank Your Lucky Stars
  29. Father John Misty - I Love You, Honeybear