Throughout Spring 2013 - Fall 2014, I have taken part in building three games using the ImpactJS Game Engine within the City College of New York (CCNY) Game development club. This tutorial serves as a guide for building a simple platformer game using ImpactJS and is intended for all audiences.
What we will cover
This tutorial will cover the following topics:
- Why use ImpactJS?
- Project Structure
- Understanding ImpactJS game loop
- Game logic implementation
- Player / enemy implementation
- Creating a simple powerup
- Creating levels
Throughout the lifetime of this tutorial, it will be updated with new features.
At the start of the Game Development club in Spring 2013, our group was experimenting with several game engines at the time. After spending a few weeks trying out various frameworks and building simple games, we realized how much functionality would have to be built just to create a simple, complete game. These features revolved around player physics, camera options, enemies/artificial intelligence, level transitioning, level building and collision. At that time, building our own game framework was not an option - which is when we stumbled upon ImpactJS.
ImpactJS provides all of the features noted above and more, exposing easy methods for creating entities (players, enemies), level transitioning, camera functionalities and collision. To top it all off, ImpactJS comes with its own Tile Editor - Weltmeister. Weltmeister provides an easy to use interface for loading level assets, adding/removing layers, setting up collisions, and exporting the level for use within ImpactJS itself. At the moment, ImpactJS costs a hefty $99, but if you can get over the cost then you’ve got your hands on a very powerful game engine.
Skills / Pre-requisites
To get the most of this tutorial, you should have some understanding of the following:
- Basic usage of your terminal (Navigating directories, creating folders and files)
- Github account (for cloning the completed project repository)
Having a Github account is not mandatory, as you can download repositories as a zip file. However, I highly encourage you to create an account if you do not have one already - Version Control Systems such as
mercurial (hg) are the defacto standard when working on software at any company. By getting started with learning
git (the command line program used for interacting with Github) and becoming familar with
Github (A website for storing repositories containing source code), you will be gaining highly valuable knowledge, as well as the ability to read other people’s source code and contribute to open source projects.
Knowledge of using your terminal is not required(as you can create files manually), but it is recommended to learn. Throughout this tutorial, I will often use bash commands native to UNIX systems (Mac OS X, Linux). I have provided some useful resources for learning below.
At the end of this tutorial, your project structure should look like the following:
Please note that the following files are provided for you upon downloading ImpactJS:
First, we create a root folder for our project and other necessary folders.
Within the root folder
weltmeister.html (received from purchasing ImpactJS),
server.py (obtained from here ), and
index.html (also received from purchasing ImpactJS). Within
tutorial/lib, place the
weltmeister folders. Lastly, you may obtain all of the media for this project here .
ImpactJS will look for two things when loading a game: a
main.js file within
lib/impact. These are referenced within
index.html, which is the file that gets served by our web server,
server.py. These directories can be changed as needed, so long as the updated changes are reflected within
Running the game / Using Weltmeister
In order to run an ImpactJS game or access the tile editor, Weltmeister, you will need a web server to serve
index.html. For this, we can run
server.py which will provide us with two links:
http://localhost:8080 for accessing the game, and
http://localhost:8080/editor for accessing Weltmeister. The screenshot below shows the output of running
I suggest just letting the server run in a separate tab/terminal, as we will constantly be navigating to our game and level editor.
This tutorial will reference the use of
Weltmeister, ImpactJS’s built in Tile Editor program often. However, usage of
Weltmeister will not be covered here, as there already exists a great video on using Weltmeister by ImpactJS’s own creator, Dominic Szablewski. See the references below for learning to use
With all of our directories in place, we move onto building our main game file,
main.js, we require any modules needed in the game (all entities, levels and plugins), set up key bindings, camera settings, draw to the screen, and initialize our game instance. We begin by declaring our module and setting up our basic game instance.
Here, we declare that
main.js is a
ig.module('game.main'). We then chain
.requires to include the ImpactJS core game library,
impact.game. Next, we chain
.defines to create a game class
MyGame which extends from ImpactJS
Game class. Notice that our
ig.Game, which means that we inherit all functionality contained within
impact.game.js. This provides us with default implementations of
draw, which we can override to develop our game.
init method is only run once in the game loop, making it a good place to bind keys to control our game load levels, and initialize any temporary variables needed for our game logic. After loading our level, we create an instance of our game through
passing in the canvas element from our
index.html page, our game class
MyGame, frames per second (fps)
height: 320, width: 240, scaled up by a factor of
2. By running
server.py and navigating to
http://localhost:8080, you should see the level displayed.
Having a plain level with no player is no fun, right? Let’s start implementing our
Here we only create our player module, define an animation sheet and just a single animation (idle). To learn more about setting up animations, see the documentation below.
http://localhost:8080/editor and drop in our Player Entity, then navigate to the game page. We can see our
Our Player isn’t very interesting right now, as he only has one animation. Let’s go ahead and add in animations for running, jumping and falling:
On its own, the above code does not change anything - we cannot interact with our player. We must bind keys to move our player, which we can easily do inside of our
init function within
There are many different input keys available for use in our game. See the reference below to learn more about key bindings and the properties available for use.
If we navigate to the game, we see the same thing. We still cannot move our player, despite pressing our keys which bind to movement. The reason for this is that we must write our logic for moving the player when certain keys are pressed. How can we trigger events based on key presses and move our
player accordingly? ImpactJS provides an
update method for both entities and
main.js which is where implement any logic our game requires.
update gets called once per frame, meaning that if you configure your game to run 60fps,
update will be called 60 times per minute. Below we handle the left/right movement case for our
By observing the boolean value of
this.standing, we determine our acceleration based on the values we defined for
accelGround. Based on the key pressed to move our
(ig.input.state('button')), we toggle our acceleration based on direction and adjust
this.flip accordingly so that we face the right direction. One thing to note is
this.parent(), which will appear many times over the course of this tutorial (and when developing games using ImpactJS). Let us take a moment to go over the functionality of this call.
As mentioned earlier, ImpactJS uses its own
class inheritance system to have objects (game entities, game classes, etc) inherit from the core game classes. This means that by extending our
EntityPlayer automatically inherits defintions of any properties and methods defined within
ig.Entity. This inheritance system should seem familiar to those with a background in C++ and Java (or any language that supports classical inheritance).
this.parent() calls the
update method of the
parent that it inherits from, meaning that we are calling
update() method for our
EntityPlayer (referenced by
this). We know that
ig.Entity provides default implementations of methods such as
draw, so calling
this.parent() will not actually override any behavior. However, we can use
this.parent() to inherit from other
Entities as well. Take the following code as an example.
The above code should seem familiar to us: we are simply defining a player entity called
EntityPlayer, which extends from
ig.Entity class. Now observe the next example:
Notice how we are extending our
EntityGameplayer from our
EntityPlayer, meaning that we inherit all properties and methods defined within
this.parent() will call the same method from the
superclass of the callee, in this case
this.parent will call the
init method within
superclass from which our
Gameplayer extends from. By calling the
superclass init() method, we can inherit any functionality that exists there. For the most part, this example will not be relevant within this tutorial, but
this.parent is required to be called in methods such as
draw in order for the game loop to correctly cycle.
Now that we’ve covered
this.parent(), navigate to the game and try to move the
player left and right. Success…?
player just slides around, left to right. He doesn’t animate to the left/right based on keypress. This is a simple fix, by simply adding
this.currentAnim.flip.x = this.flip; to our
player will still slide around in midair, but he will properly animate and respond to left/right key movement. Speaking of sliding around in midair, we can fix this by adding attaching the
gravity property to the game. Let’s go ahead and do that:
Since we added
main.js, all entities in the game world will be affected by it.
After moving to the right, we notice we are stuck in the pit and cannot get out. Now is a good time to implement the
jump button is pressed and the player is standing (has not jumped yet), we invert the Player’s
y-velocity based on their jump factor. By making this value higher/lower, we can effectively control how high our Player can jump. What do we do when the
player is falling though? We should also handle this case as well.
player will not animate any different from before because we haven’t actually written any logic to determine which animation should be playing based on all key inputs. To handle this, observe the changes below:
.standing property, we can determine what animation should be displaying based on key press. Our
player finally moves and animates correctly! He’s still sliding all over the place though, as if unaffected by friction. Luckily, we can easily fix this by using the
friction property belonging to any Entity to control how our
player is affected.
By capping the
maxVel value and applying
friction, we now move properly without sliding all over the stage. With this last step, we have fully implemented our
player entity. A game wouldn’t be challenging without having enemies, so how about we implement Mario’s mortal enemy, the
As we did with our
player, we begin by implementing
goomba animation frames.
If we go ahead to our level editor and drop in an enemy, then run our game we should see the following:
Our enemy animates properly, but does not move. As with our
player, we need to implement its movement within the
Here, we define
speed which determines how quickly our entity will move. Within
update, we determine the
xdir movement of the entity based on
flip. Depending on the value of
this.flip, we invert the velocity of
goomba. Below we can see the changes:
Our enemy now moves left, but gets stuck on the wall. We need a way to detect when an entity collides with a wall, and if so, make it start walking the opposite way. We can do this easily using the
handleMovementTrace method, which detects when an entity collides with a collison tile within the
collisionMap. The implementation of
handleMovementTrace is shown below:
When an entity collides with the
handleMoevmentTrace is called and the entity in question is passed as a parameter. Through this, we can flip the entity if it collides on the
x-axis. Due to the
update logic, the entity will keep moving until it hits another collison tile, causing
handleMovementTrace to trigger again and so on - making our entity able to move left/right indefinitely. To read more about
handleMovementTrace, see the link below.
goomba is almost done, but we cannot interact with it. We can overlap our enemy, but neither the
player nor the enemy takes damage. In order to make entities in our game world interact, we must set up collision properties for both entities. ImpactJS provides a simple method for setting up collision between groups of entities. First, we will set up collision for our
Here, we set a
type property which denotes the
player belongs to. It is common to set all friendly entities to be
TYPE.A, and all unfriendly entities to be
checkAgainst determines which entities in our game world our Player will interact with, and
collides determines which entity will be moved upon collision. To read more about collison properties, refer to the documentation below.
Similarly, we implement
goomba with collision properties as well.
Here, we set the
type to be of
TYPE.B (enemy group).
checkAgainst is set to check against entities of
TYPE.A, namely our
player Entity. Lastly, we set
collides to passive, meaning that on collion, our goomba entity will not be the one pushed back. With this, our entities can now interact with each other. Go ahead and test out the changes!
Now that our entities can interact, we notice that nothing interesting happens on collision between our
goomba. We’d like to make our player take damage on collision with an entity, so let’s go ahead and do that by implementing
collideWith gets called on collision with an entity. When this method is called, the entity which collided with this one is passed in as the
other parameter. We then check
other to see if it is our
player entity using
instanceof. Notice how we reference our player: we use
other instanceof EntityPlayer, where
EntityPlayer is the name we gave to our Player Entity when we defined it. If this condition is true, we call
other.receiveDamage, which is a method inherited by the Player Entity from
impact.entity. By calling
player will take
1 damage each time it collides with our
If we test these changes, we notice that our
player entity can now be killed by taking enough damage. We have not defined any methods to handle death, and we never defined
health for our
player, so how does this work? As mentioned before, any entity we create is extended from
impact.entity, meaning that it inherits several properties and methods. It turns out that
health: 10 is automatically defined by
impact.entity, and our
Player inherits this property. Whenever the
health property of any entity is reduced to
.kill() method is automatically called for the entity in question, removing it from the game world. Like
.kill() is automatically defined for all entities.
It is currently hard to track how much health our
player has, so next we will create a simple display for our health. ImpactJS provides a
draw method which allows us to draw an image or text to the screen. In order to draw text, we will need to import a
font. Downloading ImpactJS provides us with a default
bitmap font, so we go ahead and load it within
font property defined, we can now use it within our
draw, we check if
font exists. If it does, we get a reference to our player Entity by using
ig.game.getEntitiesByType, which takes in an
EntityName and returns an array of all Entities with the matching name. Here, we grab the first element of this array by using
 - which refers to our
player entity. With a reference to our
player, we can now access its
health property through
player.healthand print it out to any position on the screen
(X: 50, Y: 10), in this case. Go ahead and reload to see the changes.
We can now see our health, which adjusts as we take damage. Exciting stuff!
Things seem a little bit unfair now, as we cannot damage the enemy, but the enemy can damage us. As in traditional Mario games, we should be able to jump on top of enemies to defeat them. How can we accomplish this? If we recall our
collidesWith method, it takes in two parameters:
axis. We can check the
axis which collision occured, and if it is vertical (
y-axis), we know that we have jumped on the entity. Below is the impmementation of this:
With this simple change, we can now instantly kill the
Goomba if we jump on it.
Before we wrap up this tutorial, how about we add a simple, classic
Powerup? We will implement a
mushroom powerup, although in this game we will have it increase our
player health by
10 on collision. With all that we have covered before, this should be a straightforward task. The entire implementation for
mushroom.js is shown below:
All of this code should look very familar to the
goomba entity we created earlier. The only difference here is within the
check method: it calls the
receiveDamage method on collision with the player (defined inside the
checkAgainst property). Instead of doing positive damage to the player, we pass in a negative number to instead restore
10 health to the
player. If we go into our
editor and drop in a mushroom, we can test the changes and watch our health increase.
We’ve implemented everything we’ve set to do, but before wrapping up, let us briefly discuss the purpose of
When running the game with
impact.debug.debug required inside
main.js, you will see a debug panel on the bottom of your game instance.
Here we can see that the debug panel gives us useful information, such as performance of our game, collision boxes around all entities, and velocity trajectories of all moving entities. We can also see how many draws are being performed on screen, as well as the number of entities in the game world. Alongside our browser developer tools and these analytics, we have a powerful set of tools for debugging our game.
If you’ve made it this far, congratulations! You now have a working example of a simple platforming game built with ImpactJS. This tutorial will be updated with more content as times goes on. The topics I would like to cover are:
- Using ImpactJS default camera
- More powerups, such a projectile attacks
- Implementations of different types of enemies
- Creating different game states for Title Screens and Game Over screens
Stay tuned, and thanks for reading.