The personal website of @erikwittern

Gravity Quest - Distribution

September 11th 2014

Other posts in this series:

In the previous article, I discussed how I created Gravity Quest's (see at Apple's app store) levels using a custom level editor and a participatory approach. This final article of the series will address the game's distribution in the Apple app store.

Selecting a distribution strategy

One huge advantage of using a Web technology-based game engine like Phaser is that it can basically run on any platform or device with a browser. Ideally, this means that one code base can drive multiple distributions, like on a Web site, in the Apple app store, Android's Google Play store, or the Firefox Marketplace.

One possible strategy to distribute a Web technology-based game is to provide it on a Web site. One advantage of this approach is that the game is immediately accessible from any device / platform with a browser. Furthermore, many born-on-the-Web tools can easily be used this way, like Google Analytics to track how often and long the game is played. On the other hand, there are less monetization options using this approach compared to selling the game in one of the many app stores. Advertisements are one option, but selling the game or even in-app purchases need custom solutions. Another point to consider, despite probably rather for professional game developers, is that JavaScript code is made available when distributing a game on a Web site.

Another possible strategy to distribute a Web technology-based game is by selling it through one of the many app stores. This strategy has the advantage that payment mechanics and global distribution including user reviews are typically provided by the store. Furthermore, users can download games from the store and play them independent of being online. When choosing this strategy, typically, a container is required that runs the game's HTML page and is compatible with the stores technical requirements and guidelines. Luckily, there are some options available nowadays, like PhoneGap or Cocoon.js.

A main driver when deciding for a distribution strategy is monetization. I initially intended to sell Gravity Quest and then not to bother customers with ads or in-app purchases in the future. I don't like adverts in games and find many in-app purchases annoying, especially when they are designed as a last resort for players to avoid artificial obstacles or fun-reducing mechanics (e.g., waiting times before being able to continue the game). Based on this decision, I chose to distribute the game (initially) on Apple's app store for two reasons rather than on the second most obvious option, Google's Play store for Android. First, there is supposedly a higher tendency of users of the Apple app store to pay for content as compared to users in the Google Play store. Second, when developing for phones, there is a significant smaller amount of devices to test for in the Apple universe as compared to the Android universe.

Building the game for Apple's app store with gulp.js and Cocoon.js

Having decided to target Apple's app store, I quickly settled on Cocoon.js as a container. Cocoon.js specifically claims to be intended for mobile games, offering some specific optimizations. Furthermore, there exists an extensive forum post about known issues when developing Phaser games with Cocoon.js.

To build the final game I relied on gulp.js to perform some optimization tasks. These optimizations result primarily in reduced file sizes, making the game more lightweight on storage. Gulp.js is a stream-based build system depending on Node.js. Gulp.js allows to specify different tasks to perform in order to build a Web-technology-based project or game. Many great resources about gulp.js are available at their documentation page on GitHub. Listing 1 shows the specific gulpfile that I created to build Gravity Quest.

1
var gulp = require('gulp'),
2
uglify = require('gulp-uglify'),
3
concat = require('gulp-concat'),
4
rename = require('gulp-rename'),
5
notify = require('gulp-notify'),
6
clean = require('gulp-clean'),
7
optipng = require('gulp-optipng');
8
9
gulp.task('scripts', function(){
10
return gulp.src([ 'public/javascripts/phaser.js',
11
'public/javascripts/load.js',
12
'public/javascripts/mute.js',
13
'public/javascripts/menu.js',
14
'public/javascripts/intro.js',
15
'public/javascripts/outro.js',
16
'public/javascripts/play.js',
17
'public/javascripts/levels.js',
18
'public/javascripts/game.js',
19
'public/javascripts/asteroid.js',
20
'public/javascripts/alien.js',
21
'public/javascripts/nova.js',
22
'public/javascripts/astronaut.js',
23
'public/javascripts/antiForceField.js',
24
'public/javascripts/mineral.js',
25
'public/javascripts/pauseMenu.js',
26
'public/javascripts/victoryMenu.js'
27
])
28
.pipe(concat('gravityquest.js'))
29
.pipe(gulp.dest('build/javascripts'))
30
.pipe(rename({suffix: '.min'}))
31
.pipe(uglify())
32
.pipe(gulp.dest('build/javascripts'))
33
.pipe(notify({message: 'Scripts task complete'}));
34
});
35
36
gulp.task('fonts', function(){
37
return gulp.src('public/fonts/*')
38
.pipe(gulp.dest('build/fonts'))
39
.pipe(notify({message: 'Copy fonts task complete'}));
40
});
41
42
gulp.task('sounds', function(){
43
return gulp.src('public/sounds/*')
44
.pipe(gulp.dest('build/sounds'));
45
});
46
47
gulp.task('images', function(){
48
return gulp.src('public/assets/*.png')
49
.pipe(optipng(['-o2']))
50
.pipe(gulp.dest('build/assets'));
51
});
52
53
gulp.task('clean', function() {
54
return gulp.src(['build/javascripts', 'build/assets', 'build/sounds', 'build/fonts'], {read: false})
55
.pipe(clean());
56
});
57
58
// this grouping task run by the 'gulp' command:
59
gulp.task('default', ['clean'], function(){
60
gulp.start(
61
'scripts',
62
'fonts',
63
'images'
64
'sounds'
65
);
66
});
Listing 1: gulpfile used to build Gravity Quest.

As shown in listing 1, a scripts task concatenates all the game's JavaScript files into a new file created in the build destination called gravityquest.js. Furthermore, a second, minified version of this file is created. The fonts and soundstasks copy all font- and sound-related files (see the article about visuals and sound) into the build destination. The images task does the same for images, but also applies an optimization to reduce file sizes. The clean task empties the build destination. Finally, the default task brings everything together. It runs the clean task initially to set the stage and then performs all other defined tasks, resulting in a minified build of the game, that relies only on a single JavaScript file.

Having the final game built, it can be zipped and then uploaded to the Cocoon.js cloud-based compilation system. The compilation system creates a xCode iOS project from the zipped folder to download and further process in xCode. To actually submit the game to the app store, further steps are required like replacing load screen or icon images (makeappicon.com drastically speeds up the latter task). Furthermore, the code generated by Cocoon.js needs to be signed with the right certificates etc. To get a detailed description of the necessary steps, I recommend this video on how to submit an app to Apple's app store.

Conclusion

Distributing Gravity Quest through Apple's app store was my first attempt in distributing any game. I learned multiple things using this approach:

  • Tools like gulp.js, Cocoon.js, or makeappicon.com, make distribution easier and faster - their utilization may induce some up-front efforts for learning or configuration but reduce efforts in the long run, for example when pushing multiple versions over time.
  • Some of the known issues when developing Phaser games with Cocoon.js affected the way the game turned out. For example, sound is only activated after the first user input, which results in users not being able to hear the music in the menu as intended. Or, WebGL is as of writing this article not supported in the standard iOS WebView in which Cocoon.js runs the game. (Note: this will change with the introduction of WebGL in WebViews iOS 8).
  • The monetization strategy chosen for Gravity Quest, i.e., selling the game for a fixed price, was motivated by my opinion that games should ideally not bother gamers with adverts or in-app purchases. However, as of writing this article, the game has sold only few over 50 copies. Admittedly, marketing measures for Gravity Quest have so far been sparse - I consider this series of articles to have mostly contributed to this regard. Still, from the so far hundreds of visitors on Wittern.net, very few bought the game. My impression is, thus, that my monetization strategy is not fit for the game or generally difficult to succeed with. In consequence, I might consider different strategies in the future, e.g., making the game free and showing ads. I would be very interested in any options / experiences you have to share to this regard!

Gravity Quest has been a great project during the last months. From technology choice, over gameplay design and implemention, creating the game's visuals and sound, a participatory approach to level design, to distributing the game on Apple's app store, I learned a whole lot - which motivated me to write this series of articles. Sales figures might not be great, but I perceive the effort I spent well invested considering the lessons, discussions, and social interactions I got out of it.

Thus, I can only recommend to develop your own mobile game!

Resources linked in this article