Its been.. oh.. about 3 years, so I figure its time for a blog update.

If you’re wondering where I’ve been: for the past few years I’ve been working with my good friends at Limbic, blowing stuff up as the resident vfx-guy and working on some fun games. (Check out Zombie Gunship Revenant on iOS if you get a chance). It was a great opportunity and I learned a number of good development practices from some really smart folks (wheee I can actually use git now!). The downside, of course, was that it kept my time on BombSquad rather limited. I’ve been able to make minor additions and fixes the past few years but I simply didn’t have the time to commit to major updates or platform releases or things of that nature. (cough cough iOS cough). Despite all this, however, I’m happy to say BombSquad has been doing quite well this whole time. In fact, I’ve hit my highest ever daily user numbers within the past few months.

So recently, after wrapping on some big projects at Limbic, I decided the time was right to bow out and hit the gas again on BombSquad. Just as with Pixar, it was bittersweet to say goodbye, but I’ve learned over the years that I work best when I can just focus on one thing that I’m passionate about. And so here I am, back on BombSquad.

I’m super excited to get this ball rolling again, though it’ll take a little time. I’m currently in the process of dusting everything off, making some sorely needed optimizations so my busy servers don’t bankrupt me (good problem to have!), getting some anti-hacker measures in place (seriously guys; play fair or get banned), and indulging in a little fun making new characters/maps. Soon, however, I’ll be making announcements about my bigger plans. (And before you all swamp me with the same question: yes, iOS is one of them.)

I wanted to ramble a bit on this topic since it has been (and continues to be) quite a learning-experience for me. Perhaps this will be useful for other developers to hear.

Last year, in preparation for releasing BombSquad on Google Play, I switched the game from paid to free on all platforms. This is something I had long been planning on doing once the pieces were in place (in-game store, tournaments, etc.), so it seemed like a good time to take the plunge.

As developers, we all hear about how F2P is the future, and admittedly everyone’s mouth waters a bit when they read SuperCell’s latest earnings report, but from my perspective there were several less-obvious incentives to going free as well. One of these was exposure. Being a solo dev with no marketing department, I liked the idea of eliminating the barrier-to-entry for new players. I’d rather someone try my game and not pay for it than not try it at all due to it’s price tag; especially as it becomes harder and harder to stand out in the crowd. I also liked the idea of potentially being able to support myself by adding to the game over time instead of being forced to abandon it once the rate of new users slowed. I started writing BombSquad 10 years ago as a hobby and still love adding to it, so anything that lets me continue doing that (while also continuing to buy groceries) is good by me.

Of course going free is a little scary as well. There is the potential to torpedo player goodwill with over-aggressive monetization, pay-to-win mechanics, or excessive pay-walls. There is also the other end of the spectrum where the game gives players little reason to spend, in which case your game won’t make money regardless of how popular or well-received it is.

But free doesn’t have to mean evil. It can work well, and I wanted to try it. So I did.

It’s now been a bit over 6 months since I flipped the switch to free, and in this time I’ve learned just how tricky it can be to find a comfy spot in the center of those two extremes. I’ve also gotten inch by inch closer to said comfy spot. If I were to go back in time a year to give my past-self advice, this would be it:

Keep in mind that free-to-play is a *lot* of work, especially adapting an existing game not explicitly designed for it. If you are a solo developer or a small team and you just want to focus on gameplay, carefully consider whether the extra time wiring up IAPs, balancing economies, and incentivizing players to purchase is worth the extra effort vs. simply releasing a paid game.

Give yourself plenty of time for tuning purchases. Don’t slap a few unlockables in a week or two before release and expect amazing things. Consider a lengthy soft-launch.

Play F2P games. This seems obvious, but I am guilty of not doing this nearly enough before I switched BombSquad over. I knew all the F2P concepts ‘on paper’ but until recently I feel like I had not played enough to really ‘get’ them. A recent Boom Beach binge worked wonders for this. The best games don’t kick you in the face; they’re fun without purchasing but just a *bit* more so if you do. If I were starting over converting BombSquad to free today I would definitely rethink a few things.

Lastly, get down and dirty with analytics. When I am balancing a game I tend to do it more by ‘feel’ than by numbers, but when it comes to virtual currencies and economies it really helps to crunch the data. On this topic, I’d like to give a shout out to the folks at Google who are going to be rolling out their new Player Analytics features in the developer console in the next few days which makes a lot of this easier for mere mortals like myself. I’ve been fortunate to get to work with them in recent months as they’ve been putting it together, and it’s been quite helpful in identifying and correcting shortcomings in my in-game economy. As a particular example, their sources & sinks report showed that most players were easily earning more tickets in the game than they were able to spend, meaning few had any incentive to purchase ticket-packs. Adjusting my numbers to bring these two back in line had a substantial positive effect on my revenue and put the game on much more sound financial ground. So if you’ve got a game on Google Play, integrate Play game services and give Player Analytics a whirl. Yay for buying groceries!

I just released BombSquad 1.4.7, which adds a big new feature under the hood: you can now now create new co-op mode games, complete with their own online high-score lists and star rankings. (previously you could add teams and free-for-all games but the co-op section was a bit hard-wired)

First, a few little caveats:

At this time, adding co-op mods will disable your ability to play co-op tournaments (you’ll see an error at the score screen saying ‘please remove all game modifications and try again’). I’ll try to fix this in the next update or two. Pull your mods out and restart to get tournaments working again.

Currently you have to restart the game to pick up new or changed mods. This can be annoying to do repeatedly, so I’ll try to add auto-(re)loading in the future.

Anyway, let’s do this.

I feel that examples are the best way to learn, so lets just grab one and dive right in.

Download this script, drop it into your BombSquad mods folder (Settings->Advanced->Show Mods Folder), and launch the game. Under ‘co-op’ you should now see ‘Ninja Fight Custom’.

That’s it.

This mod is pretty much identical to the ‘Ninja Fight’ mini-game included with the game. It simply sets up a few timers to spawn ninjas and then measures the time it takes you to kill them all. The script is heavily commented so you should be able to see what’s going on, add more ninjas, or whatever else you want to do.

I’m happy to announce BombSquad’s third official platform: Amazon Fire TV.
The game runs quite nicely on this little guy; I was able to crank the quality to high and add anti-aliasing and a few other bells and whistles. It supports GameCircle leaderboards and achievements, and I even got the remote usable as a controller.
Enjoy!

It’s called ‘Meteor Shower’, and it’s pretty simple. You run around a platform as bombs fall from the sky at an ever increasing rate. The last team/player alive wins.

Here’s a video of me testing it:

To play, simply download the following file and stick it in BombSquad’s user-scripts dir. Poke the “Settings”->”Advanced”->”Show-Mods-Folder” button if you forgot where that is. You can then launch BombSquad, create a new teams or free-for-all playlist, and you should be able to add a ‘Meteor Shower’ game to it.

..And that’s it… To see what’s going on, just open the file and take a look at the code. I’ve commented it so you should be able to follow along. If you’re brave, take a stab at modifying it; see if you can change where or when the bombs fall, or change it to use a different map. Good luck!

This episode is just a brain-dump of basic scripting types and concepts, intended to be used as a reference guide. We’ll get back to writing code next episide. Anyway, let’s dive right in:

Classes to Be Familiar With:

bs.Session

Represents the entire set of games you are playing, and is in charge of swapping in activities for games, score-screens, etc. Current session types include Co-op, Teams, and Free-for-All.

bs.Activity

An activity represents a single sub-unit of a session, of which one is current at a time (though multiple can exist briefly during transitions). Examples of activities include mini-games and score-screens.

bs.Node
bs.Texture
bs.Model
bs.CollideModel
bs.Sound

These are BombSquad’s low level building blocks. At the most basic level, a BombSquad game script creates and manipulates these to construct a game experience.

bs.Timer

Timers are used to run code at some point in the future, either once or in a repeating fashion. If the timer object dies (due to its reference count falling to zero) the timer will be cancelled, so make sure to store it as a field on your game/actor/etc if you want to keep it running.

If you want to create a single-shot timer that can’t be cancelled, you can use the bs.gameTimer() or bs.realTimer() functions.

bs.Actor

Actors are a high-level building block implemented purely in Python. They generally encompass one or more nodes and handle message passing with other actors. Some example actors include bsSpaz.Spaz which is the standard character class and bsBomb.Bomb which is the standard explosive unit.

Concepts & Guidelines to Keep in Mind:

Reference counts, WeakRefs, and Activities

There are a few key concepts related to Python garbage collection to keep in mind when working in BombSquad. CPython, which BombSquad uses, has two methods for garbage-collection; in most cases objects are simply cleaned up when their reference-counts drop to zero, but there is also a fancier garbage-collector that runs periodically to clean up cases such as cyclical references. (Object A referencing object B which also references A). Be aware that BombSquad disables this second type of garbage collection to avoid hitches (though it does explicitly run it periodically at ‘safe’ times such as between games). Because of this, you should make sure to avoid dependency loops in your code, using weak-references or other methods as necessary.

A good way to debug references is to add a __del__() method to your objects containing a simple print statement. If you never see this print, your object is still alive because there’s a reference to it out there somewhere.

On a related note, be aware that BombSquad Activities are told to begin *only* after the previous Activity has been cleaned up, so you should be very careful about holding strong references to Activities. If you’re writing a Mini-Game and it gets ‘stuck’ after it ends, this is probably the problem. Familiarize yourself with weakref.ref and bs.WeakCall to help combat this.

bs.Call and bs.WeakCall

bs.Call is a convenient way to wrap up a Python callable along with arguments/keywords into a single callable object. This can be handy to pass to timers or other things that take callables as arguments. Example:

bs.gameTimer(1000,bs.Call(myFunction,myArg1,myArg2))

this will run myFunction(myArg1,myArg2) after 1 second of game time. Be sure to avoid this common mistake:

bs.gameTimer(1000,myFunction(myArg1,myArg2))

The above code is calling myFunction *immediately* and passing the result to bs.gameTimer, which is most likely not what you want.

Bound methods and references

One important concept to keep in mind is that a bound method of an instance is actually a little object containing a reference to the instance (“self”) as well as to the method to call, so if you pass a bound method as a callback you’re going to keep that object instance alive, which is something you may not want.
Example: avoid things like this:

bs.gameTimer(99000,bs.Call(myActivity.handleTimeExpired))

In this example the timer is going to hold onto the bound method (myActivity.handleTimeExpired) for 99 seconds, thus keeping a reference to myActivity, thus keeping it from being garbage collected and preventing another activity from starting for that 99 seconds. Doh.
The proper thing to do here would be to use bs.WeakCall. This is just like Call, except if given a bound-method it will only keep a weak-reference to the instance, allowing it to be garbage-collected if its ref-count hits zero. (in which case calling it results in a no-op).
So the correct code would be:

bs.gameTimer(99000,bs.WeakCall(myActivity.handleTimeExpired))

..in this new code we won’t inadvertently keep myActivity alive, but it’ll still get its handleTimeExpired method called in 99 seconds if its still around.

Internal functions/variables

Please keep in mind that functions, classes, and variables starting with an underscore (‘_’) should be considered ‘private’ to BombSquad and not used, as they are subject to change at any time. Actually this is a general coding convention in Python; not just with BombSquad. If you need functionally that is not available via a public class or function, please email me and we’ll arrange something.

Avoid globals

This restriction may be eased in the future, but currently all nodes/textures/materials/etc become invalidated between sessions, so make sure to create and store these as part of your game/actor/etc; not in a global fashion.

Tutorial 3 was pretty long-winded, so if you made it through that it’s time for something simpler. Today we’re gonna write our very first mini-game.

Make sure you’ve done Tutorial 1 so you know how to issue commands to the game and Tutorial 3 so you know where to put game scripts.

This mini-game we’ll be making doesn’t actually do anything; it just ends after 5 seconds and gives all teams a score of 0, so the game comes out a draw. That’s ok though; the point is to show what a bare-bones mini-game looks like; we’ll make it fancier in a later tutorial.

When BombSquad gathers its list of mini-games, it simply scans through all modules in its user and system scripts directories looking for ones that define a ‘getGames()’ function.. so to add a game we simply have to write a module that provides that function.

Create a file named HelloWorldGame.py (or whatever you want to call it), paste the following code in, and drop it into BombSquad’s user-scripts directory. You can use the ‘Show Mods Folder’ button in Settings->Advanced if you’ve forgotten where this is. (‘mods folder’ is just another term for the user scripts directory).

import bs
# scripts specify an API-version they were written against
# so the game knows to ignore out-of-date ones.
def bsGetAPIVersion():
return 3
# how BombSquad asks us what games we provide
def bsGetGames():
return [HelloWorldGame]
class HelloWorldGame(bs.TeamGameActivity):
@classmethod
def getName(cls):
return 'Hello World Game'
@classmethod
def getDescription(cls,sessionType):
return 'Just a test game.'
def onBegin(self):
bs.TeamGameActivity.onBegin(self)
# game's starting - let's just set a timer to end it in 5 seconds
bs.screenMessage("Hello World! Ending in 5 seconds...")
self._endGameTimer = bs.Timer(5000,bs.WeakCall(self.endGame))
def endGame(self):
# game's over - set a score for each team and tell our activity to finish
ourResults = bs.TeamGameResults()
for team in self.teams: ourResults.setTeamScore(team,0)
self.end(results=ourResults)

Now, to try out your shiny new mini-game, launch BombSquad, create a new game list, and add a game to it. You should see ‘Hello World Game’ in the list of available game types. When you run the game you should just see it print its message and end.

Well, that’s it for this tutorial.. next time we’ll start to add logic to our game to make it actually worth playing… stay tuned. (or if you’re impatient, you can look through BombSquad’s system scripts directory at all the built-in mini-games as reference)

Ok, I just completed the BombSquad 1.3.13 update, and now we can really start to have some fun.

In this update I added the ability to create your own scripts or override all of the game’s internal ones, so you can mod and tweak the game to your heart’s content without having to root your device or damage your install.

To get started, make sure you’ve run tutorial 1 so you know how to issue commands to the game. Also make sure that you’re running BombSquad version 1.3.22 or newer. You can look at the bottom right corner of the main menu screen for the version number.

First, a bit of context:

Conceptually, BombSquad is divided into two layers. The first, low-level layer, the engine, is written in high-performance c/c++ code and handles things like rendering, physics, and input. Changing to this requires re-compiling the game binary. On top of this there is a higher level scripting layer which drives the engine. All actual game logic happens in this layer, such as: ‘give team X a point when Y does Z’ …or ‘set player X’s hit points to Y’. This logic is all written into Python scripts stored with the game, so by adding our own or editing the internal ones we can completely change the game.

To get started, issue the following command in a BombSquad shell:

env = bs.getEnvironment()
print env['userScriptsDirectory']

The string you see printed where you can place python scripts to have the game pick them up. On OUYA this should be ‘/sdcard/BombSquad’, which you can easily get at via file browsers such as ‘Android File Transfer’ on Mac.*

Now let’s look at another path:

print env['systemScriptsDirectory']

This will show you where all of BombSquad’s built-in scripts live, including all existing mini-games and object types. Unfortunately you can’t modify anything in this directory without rooting your device or changing file permissions, but you don’t actually *need* to modify anything here. When BombSquad launches, if it finds a directory named ‘sys/1.3.23’ (or whatever version you are running) under its user-scripts directory, it will use that as its system-scripts directory in place of it’s internal one. ..So you just need to make a copy of BombSquad’s system scripts at that location to be able to modify them. As luck may have it, there’s a command to do just that:

import bsUtils
bsUtils.createUserSystemScripts()

ta-da!

Run that command, then quit BombSquad (via the UI or by running bs.quit()) and re-launch it. Now if you print bs.getEnvironment()[‘systemScriptsDirectory’] once more you should see that it’s now pointing to a path within your user-scripts dir (something like ‘/sdcard/BombSquad/sys/1.3.23/’).

Let’s be doubly sure by taking a look at one of BombSquad’s internal python modules. Run the following:

import bs
print bs.__file__

the ‘__file__’ attribute on any Python module shows where it came from, so if everything’s in order you should see that bs was loaded from that same new location.

One last note before we start making changes:
In the course of tinkering with BombSquad’s scripts it’s possible to break the game or leave it in a messed up state where it won’t even launch successfully (due to syntax errors, infinite loops, etc). Don’t panic when this happens. As a failsafe you can just force-kill the app (or restart the device if that’s easier), temporarily move or rename your custom copy of the system scripts, and then relaunch BombSquad to get back to a ‘vanilla’ version. There’s also a bsUtils.deleteUserSystemScripts() function that will clear out that directory for you.

Note that BombSquad will print all errors and other info to the log on android and to stdout on other platforms, so you may be able to debug problems that way. (‘adb logcat’ on android, launching via terminal on OSX, etc).

With that important safety-message out of the way, we’re ready to start messing around. Feel free to take a look around the system scripts to see how things are put together. Here are a few of BombSquad’s built-in modules and their uses:

bs.py: this pulls in bits of various modules to create BombSquad’s core API

bsUI.py: user-interface bits (windows, dialogs, etc) are found here

bsSpaz.py: the player character is defined here as well as variations of it (bots, etc)

bsDeathMatch.py: this is an example of a mini-game. More on these later.

To keep this tutorial from getting too long, for now we’re just going to change something simple; let’s change teams-mode from a best-of-7 series to a best-of-5.
To do this, make sure you’ve got your sys/1.x.x directory, and then dive in there and find the bsTeamGame.py script. That’s what we’ll need to edit. Note that on Android platforms you may need to copy this file off the device, edit it, and copy it back on using something like “Android File Transfer”. I’ll leave that as an exercise for the user.

Now look for the following line in bsTeamGame.py (currently its around line 711).

Save the file, copy it back to your android device if necessary, and re-launch the game.
Now when you start a Teams game you should see the above message and your series should go to 5 games instead of 7. Ta-da!

…Of course, if we wanted to make this a ‘proper’ option we could expose it via the GUI instead of hard-coding it like this, but that’s beyond the scope of this exercise.

Well, that’s all for this installment. Enjoy tinkering. Next time we’ll get into creating some new scripts from scratch.