Webfighter is a game inspired by R-Type and Tyrian. In fact, it uses Tyrian's graphics which have been released for free. The game is a side-scrolling shooter where you hunt down an alien bug and destroy it.
It works on desktop and mobile, with much thought put into the mobile experience. This article describes how webfighter works, and explains many things learned about creating games for mobile.
Let's start with the basic architecture. This may surprise you, but webfighter does not use a game engine. I believe that there are already several examples of existing game engines out there, and this is a chance to show instead what it's like to work with only web APIs.
The result is, of course, a few files that are basically a minimal game engine. The code that makes up the core components is very small, and hackable, however. During this process I was inspired to write a detailed blog post about this very process of making games with minimal code, so feel free to dive into that as well. The post focuses on sprite animations, but another post is coming describing scene managers and renderers.
There are 3 main components: scene, renderer, and sprite. The
Scene object implements the ability to add and remove objects to the scene, update them every frame, and check collisions. The
Renderer object implements the ability to render every object in the scene and manages the viewport. The
Sprite object manages images and animating them. There are more components, but these make up the most important parts of the system.
Let's take a step back and think about art. Games are complex enough technically, who has time to sit down and develop a bunch of awesome art for it? Maybe you have an artist friend who will help out. If you do, awesome!
If you don't have any artist friends willing to help out, I would highly encourage you to use existing art released for free. You can look around HasGraphics for a graphics set that you like. As mentioned previously, webfighter reuses the Tyrian graphics for some awesome ship and enemy art.
Next you'll find several functions which trigger certain game states, like
gameWon. The most important functions are
init, which creates the scene and adds everything to it, and
hearbeat, which uses requestAnimationFrame to update and render the scene at around 60fps, or whatever is appropriate for the user.
Levels & Enemies
units.js defines every single entity in the game. An entity is an object with a
update method. Technically the system implements this as the
SceneObject type, and has a few additional methods like
sprite.js defines an object which handles animations. The game works with one big sprite sheet, with references to individual sprites inside of it, and animates by rotating through several frames in the sheet. The
Sprite class handles all of the gritty details of this. If you want more information about this, read my blog post.
level.js pulls it all together and adds everything to the scene. It uses an entity type called
Trigger which triggers when to add certain enemies to scene, and adds the background and other structural components of the game.
The Renderer and Scene Manager
There are two core components which drive the whole game: the renderer and the scene manager. The renderer, defined in
renderer.js, takes a scene and renders all the objects in it. It also handles changes in the window size and optimizes the viewport. The scene manager, defined in
scene.js allows you to add/remove objects to a scene, and handles collision detection.
Both of these objects are relatively simple, around 115 lines of code on average, and are a simple example of how to create games with relatively little code.
init in app.js, we create a scene and renderer. The main game loop,
heartbeat, updates the scene with
scene.update(dt) and renders with with
renderer.render(scene). This happens continuously, creating the fluid gameplay experience.
Input and Resources
The last two pieces are input and resource management. The input library, defined in
input.js, is a state-based manager that provides simple functions like
isDown to check to key presses. Since we already have a game loop, it's simpler to check for key presses when the scene is updating rather than using the native events.
While webfighter works on the dekstop, it is optimized for a mobile experience. This is visible in the UI, with the bar at the top with large buttons for switching to fullscreen, restarting, and pausing. I learned a few things about developing games for mobile throughout this.
Handling Various Screen Sizes
One of the more difficult things to figure out was how to fit the canvas with various screen sizes. Ideally, you want the proportion of the canvas to stay the same. Otherwise longer screens have an advantage because they can see more of the game at one time. It also needs to somehow scale up to desktop sizes, and we obviously can't make the canvas bigger because the player has the same advantage as longer screens.
One option is to keep the actual game width and height fixed, but scale the canvas to fit the screen. The problem with this is that pixel graphics with sharp edges do not scale well. They can only scale by a factor of 2, otherwise they look bad or blurry.
Here's what I ended up doing: if the screen size is larger than a certain threshold, I hardcode the the game to the dimensions 480x320. If the screen is big enough, I zoom in by a factor of 2. The the screen size is lower than a certain threshold, I set the width and height to 100%.
This gives larger screens an advantage, as mentioned before, but it's a simple way to handle scaling. The advantage is small because it's only the difference between phone screen sizes. Once it gets large enough it is capped to 480x320.
You can see the logic here. There's probably better ways to do this, but this works for now.
Another difficulty with mobile is input. Touch screens are really neat for some games, but it's difficult to map a directional pad (d-pad) to a touch screen, and you thumbs end up covering part of the game.
There are two controls needed for webfighter, a d-pad to move the ship around and a fire button. The way it works is the screen is divided in half, and if the user touches the left side they can move there finger to move the ship around, relative to the initial touch point. The right side, if touched, fires a bullet.
I hope you enjoy webfighter and are inspired to make some games for mobile, especially Firefox OS! Look for webfighter in the Firefox Marketplace near you, and feel free to file any issues here on github if you have questions.