Phil Hassey - game dev blog
Phil Hassey as Syndrome
"Look, stores don't sell
costumes like this to just anyone."

Archive for the 'dynamitejack' Category

Experiment “The value of demos” … Results: confusing

Monday, March 11th, 2013

Okay, so about 6 or 7 weeks ago this article got posted somewhere (anyone remember where??) about how demos reduce sales. I figured I’d try that out with Dynamite Jack. First a graph showing the number of demo downloads on iOS:

Second, a graph showing $ earned via the full version on iOS.

Best I can tell, sales go down when I got rid of the demo. Then they went down a bit more when I re-enabled the demo version of Dynamite Jack. My hope is that eventually the demo-to-full conversion groove will pick back up to bump sales up a bit more again.

That said, though, the number changes aren’t terribly clear. I’m guessing it would take higher volume or better A/B style testing to really make any sort of decent claims about this stuff.

The only thing that I think is terribly clear is that when Dynamite Jack got launched in the Humble Bundle on March 6th, it doubled the number of demo downloads on iOS for a day.

-Phil

Dynamite Jack in Humble Bundle with Android!

Tuesday, March 5th, 2013

Hey! I’ve just completed porting Dynamite Jack to Android! You can get it right now in the Humble Bundle with Android!

If you’re new to the Humble Bundles, they offer several games in a bundle and you can pay what you want for a bunch of great indie games! Dynamite Jack is along side Dungeon Defenders, Super Hexagon, Beat Hazard Ultra, Solar 2, and NightSky HD. You can grab all these games on Android, Windows, Mac OS X, Linux and Android for just a few bucks!

Also, we’ll be announcing a new Dynamite Jack maps contest with Dynamite Maps very soon, so sharpen up your map making skills to win some sweet prizes! Check back in the forums or in the Community Maps section of the game for details in a day or so.

Cheers!
-Phil

P.S. Galcon 2 had it’s first multiplayer game this past Saturday! For now, the beta is closed to Kickstarter backers only, but you can read the progress so far on the Galcon blog .

Dynamite Jack: The Settings stats post-mortem

Wednesday, October 10th, 2012

Hey, a few months ago I read a post by Andy Moore about the value of music in games where he did some stats recording on games to discover how often audio was muted, etc. I decided to do something similar for Dynamite Jack.

The following are the results I got from the paid iOS version:

95% of players don’t change ANY settings.
2% of players quieted or silenced the audio.
2% of players change the controls to Virtual Stick only.
0.5% of players change the controls to Line Drawing only.
2% of players change the Touch Button Location / Virtual Joystick options.
1% of players change the HUD options.

1.7% of the users completed the campaign, which means they probably played the game for over 3 hours.

Of the users who completed the campaign:

34% of users changed options.
19% of users quieted or silenced the audio.
17% of users changed the controls to Virtual Stick only.
5% of users changed the controls to Line Drawing only.
10% of users changed the HUD options.
12% of users changed the Touch Button Location / Virtual Joystick options.

The piracy rate could be as high as 74%. Here are factors that make that number questionable:

– Each purchase can represent several devices
– Each purchase can represent several GameCenter accounts
– Each purchase can represent multiple IP addresses

Concluding interesting facts:

– Long term players are over 10x more likely to change options.
– I used royalty free music from shockwave-sound.com and only had 2% of users turn off the audio.
– I spent probably over 20 hours scouring through the tracks on that site to find the exact ones I wanted for my game.

Cheers!
-Phil

How I got Dynamite Jack from 62MB down to 46MB

Thursday, August 9th, 2012

Hey,

So – I went Universal with Dynamite Jack just today! Yay! This involved a lot of “blah blah” messing with resizing all the menus for iPhone users, which wasn’t very interesting, though it came out really well. The interesting bit was when I realized that “going Universal” meant that my retina iPad assets were going to be put on everyone’s phones. And that meant that the 50 MB OTA limit was going to hit me. Quite a few devs advised me against going over the limit, so I took their warning.

I was at 62 MB. I had to take the size down AT LEAST 12 MB to hit the 50MB limit. However, I also know that when distributing your game iTunesConnect pads things a bit, so adding 2MB to that is a good idea. So my target is 48MB.

What was taking up all that room??

– Video (IVF): 10 MB
– Sound effects (WAV): 7 MB
– Music (AAC): 24 MB
– Images (PNG): 20 MB
– Maps, etc: 1 MB

Okay, so I’m at a good place, I know exactly who is eating my space. But now what to do? Let’s check it out!

Video

So I decided not to do anything about the video. I include two IVF files, one for the retina iPad and one for everything else. They are as lossy as I want them to be, so further altering would start to eat up the quality. I could probably get away with re-encoding them a few % lighter and save 1 or 2 MB if I really had to.

Sound Effects

Stereo 16-bit WAV files sound great but they are huge. I took some advice and converted them to IMA4 files which are 25% as large as WAV files. This saved me about 5 MB. However, I found when testing the game out on my decent computer speakers that the IMA4 format really adds a lot of noise to the sound, this was not acceptable to me. I decided to re-encode them using the AAC encoder at 96k which resulted in perfect sounding sound effects and saved me 6MB!

iMac$ afconvert -d aac -f caff -b 98304 in.wav -o out.caf

I am using CocosDenshion for my audio engine, and it seems to handle this just fine.

Music

My music was already encoded as AAC files at 128k. I tried a variety lower bit rates to see if I could save a few bytes. I found at 64k it was really obvious that I was cutting corners. I found at 80k I couldn’t tell any difference, so I decided to go with 96k since that would give me a bit of a margin above that just so I could be sure the music sounded perfect. I used the same command line as converting the sound effects. Going from 128k to 96k saved me 5MB!

So far I had saved 11MB, but I was 14MB over and I knew I needed to trim a bit more fat to make this work.

Images

Previously I had tried a ton of variations on 16-bit “4444” dithered style images. These, unfortunately, looked horrible in Dynamite Jack. So I wasn’t able to use that trick.

I did find out about ImageOptim which takes forever to pack PNGs but it did manage to pull me back 2MB getting me down to 13MB total saved, which was really going to cut things close. I decided to investigate one other option.

I had heard that Amazing Breaker had used JPGs for the RGB component of images and a PNG file for the alpha component. I really require high-quality images in my game, so I found that at 98% quality and 1×1 sampling I was able to get really great looking images.

Ubuntu$ convert -quality 98 -sampling-factor 1x1 tmp-rgb.bmp tmp-rgb.jpg

I pre-blitted them (which gave me premultiplication) onto a black background to get the JPG. Then I made a grayscale PNG file of the alpha channel. I created my own mini format “.cuz” to combine these into single files and loaded them in my game. I found that the game looked perfect! This saved me 6MB!

Afterwards, I found that some of my pre-baked font images got larger using my format, so I left those as straight PNGs.

Finally …

So all said and done, I had saved 6 + 5 + 6 = 17MB! This got my IPA down to around 46MB, which is a nice distance below the 50MB limit 🙂 I’m quite pleased with the results. Some bonus tips:

– The AAC sound effect trick will only work iOS 3.0 and higher. Which shouldn’t be a problem now-a-days. I hear that this won’t work out-of-the-box with OpenAL, so maybe check out CocosDenshion.

– Definitely check your own music to find what bit rate starts to degrade the sounds. Playing on your iPhone or iPad speaker isn’t enough. Playing on earphones isn’t either (unless they are really nice). I recommend playing on your computer speakers so you can be sure the sound IS really good before deciding.

– The JPG+PNG image trick can get great results – but definitely keep the quality high. I found that I was able to go down to 98% and found no artifacts in my game. Be sure to experiment and find the sweet spot for your game images. Also be sure to test on all device resolutions you have to check for artifacts. I tested on all 4 iOS screen resolutions to be sure things were perfect.

Anyway, I hope you find this helpful in your quest for saving bytes! And don’t compromise on quality! Nobody wants to hear or see compression artifacts.

-Phil

P.S. If you need to cut your App in half after that, here’s what you could do:

– Change all SFX+music from stereo to mono
– Set JPG quality to 95% or something even less

That would probably cut mine back another 15MB or so, and very few people would notice. I would notice a tiny bit, and in my case, I don’t need to compromise any more, since I’m already under 50MB.


Bonus: a bit more detail on my image file format

First, I used a python script to figure out which was the best way to compress the image. I do a variety of conversions and see which one is the smallest:

– Using JPG-RGB + PNG-A
– Using PNG premultiplied Alpha
– Using original PNG

So, for example, fonts ended up working best as “original PNGs” and most everything else ended up being JPG-RGB + PNG-A. There should be a 4th option of just JPG-RGB with no alpha, but I didn’t bother, since I don’t have any fully opaque textures.

# -*- coding: utf-8 -*-
import glob
import os
import pygame
from pygame.locals import *
from PIL import Image
import numpy

SRC = "../data-ios"
DST = "../data-ios"

def do_cmd(cmd):
    print cmd
    os.system(cmd)

def png_fix(fname):
    img = pygame.image.load(fname)
    img = img.convert_alpha()
    pygame.image.save(img,fname)
    
def premult(finput, foutput):
    im = Image.open(finput)
    
    print "premultiplying matrix..."
    a = numpy.fromstring(im.tostring(), dtype=numpy.uint8)
    alphaLayer = a[3::4] / 255.0
    a[::4]  *= alphaLayer
    a[1::4] *= alphaLayer
    a[2::4] *= alphaLayer
    res = Image.fromstring("RGBA", im.size, a.tostring())

    res.save(foutput)
    png_fix(foutput)

def main():
    s = pygame.display.set_mode((256,256),0,32)
    for fname in glob.glob(SRC+"/*.png"):
        print fname
        img = pygame.image.load(fname).convert_alpha()
        
        img2 = img.convert_alpha()
        img2.fill((0,0,0,255))
        img2.blit(img,(0,0))
        pygame.image.save(img2,"tmp-rgb.bmp")
        
        cmd = "convert -quality 98 -sampling-factor 1x1 tmp-rgb.bmp tmp-rgb.jpg"
        do_cmd(cmd)
            
        img.fill((255,255,255),None,BLEND_RGB_MAX)
        img2 = img.convert_alpha()
        img2.fill((0,0,0,255))
        img2.blit(img,(0,0))
        pygame.image.save(img,"tmp-a.bmp")
        
        cmd = "convert tmp-a.bmp -define png:bit-depth=8 -define png:color-type=0 tmp-a.png"
        do_cmd(cmd)
        
        dst = fname 
        dst = dst.replace(".png",".cuz")
        f = open(dst,"wb")
        
        # 4 byte magic
        f.write("CZCO")
        # 4 byte version / whatever
        f.write("I\x00\x00\x01")
        
        s1 = open("tmp-rgb.jpg","rb").read()
        s2 = open("tmp-a.png","rb").read()
        t = 3 #JPG + PNG
        s3 = open(fname,"rb").read()
        
        # add a check for non-alpha images, store as JPGs.
        # wouldn't save much room since the full alpha PNG itself will only
        # be like 100 bytes.  not a high priority item!
        
        if (len(s3) < (len(s1)+len(s2))): 
            # we have failed, fall back to just wrapping a PNG
            # but first, premultiply it
            
            premult(fname,"tmp-pre.png")
            s4 = open("tmp-pre.png","rb").read()
            
            if len(s3) < len(s4):
                t = 1 # PNG - original
                s1 = s3
                s2 = ''
            else:
                t = 2 # PNG - premult
                s1 = s4
                s2 = ''
        
        s1 += "\x00"*(4-len(s1)%4)
        s2 += "\x00"*(4-len(s2)%4)
        
        # 24 byte info
        s = "%d %d %d"%(t,len(s1),len(s2))
        s += "\x00"*(24-len(s))
        f.write(s)
        
        # data
        f.write(s1)
        f.write(s2)
        
s = f = open("%s/data.json"%(SRC)).read()
s = s.replace(".png",".cuz")
f = open("%s/data.json"%(SRC),"wb")
f.write(s)
f.close()

main()

In my game, I use stb_image to load my images. But I used a little bit of C code to read my header and decide how to decode them.

        unsigned char cuz_head[256];
        FILE *f = fopen(fname,"rb");
        fread(cuz_head,1,256,f);
        int tp=0,s1=0,s2=0;
        sscanf((char*)cuz_head+8,"%d %d %d",&tp,&s1,&s2);
        fprintf(stderr,"is_cuz: %d %d %d\n",tp,s1,s2);
        fseek(f,32,SEEK_SET);
        
        // load our first image!
        data = stbi_load_from_file(f,&width,&height,&bpp,4);

        if (tp == 1) {
            // do nothing, it's like we loaded a normal image
        }
        
        if (tp == 2) {
            // this image is premultiplied
            is_premult = 1;
        }
        
        if (tp == 3) // separate ALPHA image
        if (data) {
            // this image is premultiplied
            is_premult = 1; 
        
            unsigned char *alpha;
            fseek(f,32+s1,SEEK_SET);
            int _width,_height,_bpp;
            alpha = stbi_load_from_file(f,&_width,&_height,&_bpp,1);
            
            if (!alpha) {
                fprintf(stderr,"(cuzi:alpha) stbi_load failed %s - %s\n",fname,stbi_failure_reason());
            }
            
            if (alpha) {
                fprintf(stderr,"(cuzi:alpha) OK\n");
            
                unsigned int *pix = (unsigned int *)data;
                unsigned char *pa = alpha;
                for (int i=0; i<width*height; i++) {
                    unsigned char *p = (unsigned char*)pix;
                    p[3] = *pa;
                    pa ++;
                    pix ++;
                }
                stbi_image_free(alpha);
            }
            
        }

Dynamite Jack – now Universal for iPhone – with special promotion

Wednesday, August 8th, 2012

Ahoy there! I’ve been working all month to get you Dynamite Jack for the iPhone, and it’s a Universal update to the iPad version! You can get it here.


“Like stealth? Like explosions? You’re going to love Dynamite Jack.” – 4.5 stars, TouchArcade

“It’s not often I come across I game that I believe should be on every iPad. Dynamite Jack is one of those games.” – 4.5 stars, 148Apps

“There are some games that you can instantly tell are going to be good, and Dynamite Jack is one of them.” – 4.5 stars, Apple’N’Apps


If that’s not enough to convince you, I’m also running special 48 hour promotion – buy the iOS version and you get the desktop version as a free download! This will also work for owners of the iPad version. If you already have the desktop version, give your bonus code to a friend!

iOS Promo

Anyway, check it out! I hope you enjoy it!

-Phil

P.S. I’m still considering the Android port of this game. If you are interested in an Android version, please post a message in this thread to show your support.

Dynamite Jack for iPad is live!

Thursday, June 28th, 2012

Hey y’all,

Dynamite Jack for iPad is now available on the iPad App Store :)

“Like stealth? Like explosions? You’re going to love Dynamite Jack.” – 4.5 stars, TouchArcade

The iPad edition includes retina support, Game Center features, virtual joystick, line-drawing controls, and it’s iCade compatible! The map editor, community sharing, and the full campaign are all included.

Have fun playing!

-Phil

Dynamite Jack – Mac App Store & Map Creator Contest!

Thursday, June 7th, 2012

Ahoy there,

Dynamite Jack has just arrived on the Mac App Store :)

And right now Dynamite Maps (a fan community site) is hosting a contest to create the best “SPACE” themed map!

Even if you aren’t into creating maps, you can help out by playing all the new maps that get created as part of the community judging :) Here’s all the info on the contest.

-Phil

P.S. I’m working hard on an iPad release of the game! Stay tuned for that!

Dynamite Jack on Steam and PC/Mac/Linux DRM-free

Thursday, May 10th, 2012

Hey there! Dynamite Jack is available now! The store on my website gets you a DRM-Free copy of the game for Windows / Mac / Linux AND a Steam code (Windows / Mac).

If you want to learn more about the development of Dynamite Jack, I’ve done dev blogs about it over the past month.

Enjoy!
-Phil

Dynamite Jack: Final Prototype post-post-mortem

Monday, May 7th, 2012

So in October of 2011, Ludum Dare hosted a second October Challenge. I had so much fun the last year, despite canceling my game, I decided to give it another go. I was really attached to the idea I felt I was approaching with Stealth Target, so I wanted to give it another try. Since I realized the aesthetics and UI were the biggest problems, I decided to take the game back to “Glorious 2-D” and use the aesthetic from my earlier Ludum Dare game Anathema Mines for the starting point of this game.

Here are cut-down versions of the blogs posts I made during the October Challenge 2011. Additional commentary included below the quotes.

Oct 13th – October Challenge, take 2

I’m doing brute-force ray casting here and it works great. It’s really nice to be targeting the desktop using C, so I can do stuff like that. (The older LD version was in python so I had to code it smart, and if I were targeting mobile I’d have to be more optimized.) Anyway, my goal is to have this game selling on the Mac App Store before the end of the month for a few bucks.

TECH: I’ve done a fair bit of optimization here, but really, the main gist is that I raycast from the center of the light until I hit something. I have a few optimizations and whatnot that help make this faster, but nothing super clever. A win for the component object system was that I’m able to change the size of the shadows each object has, which helps for the fine tuning of the look. If you look carefully you can see the size of the player’s shadow get larger when he dies and falls down.

BIZ: I changed my mind about the Mac App Store before the end of the month. I soon realized that this game was coming out really good and that it was going to be worth taking the extra time to really polish it up before releasing it for sale.

Oct 14th – More lighting stuff

I re-did my lighting systems in the game so now I can have various colored lights and I can add ambient light to corners of the caves.

TECH: Each tile on the map is given an RGBA “lighting” component. Each frame I color where light is on the map, and then I blur the coloring of the map. Then I draw the flooring and tiles using the lighting values. I use a different averaged color for each corner so that the shading is nice and smooth. When the player walks you can see the lighting jump ahead by tiles, it’s a technical shortcoming, but it “feels okay” because it feels like the light is flickering a little.

Oct 15th – Technology .. explosions!!

Some new goodies today. Well, the explosions I’ve had for a while, but I just added in the technology that you have to destroy in order to defeat the evil over-lords or whatever. The technology is RED that’s how you know it’s EVIL technology.

DESIGN: If you remember back to Dynamite the core game mechanic was exploding the load bearing pilars in the game so that the building would collapse. I decided that collapsing the cave like that didn’t make much sense, and that glowing alien technology would just look way cooler. I had to come up with a way for blowing up the tech to have a purpose, so requiring the user to explode all the tech of a single color to unlock some doors seemed like a straight forward design choice.

DESIGN: You can see the black “pit” below the explosion. In the prototype of the game, the explosions actually created holes in the floor that were impassable. I decided I wanted my game to never back the player into a corner, so I now have the explosions only break down walls and give the player more area to move in, instead of less.

Oct 18th – Level editor thing

So, here’s my level editor thing. Right now I’m trying to figure out how to set up the level entrances / exits / pathways throughout the level. Sort of some kind of cryptic code system. I’m not sure how complicated I want it to be. Depends on if I will have the level editing open to the general public or not.

DESIGN: I was thinking about some really bad ideas at that point …

That said, I think I want it to be editable by normal people. So I think I’ll probably pass on using those weird codes. But at least now I have those cool hex icons for no reason.

DESIGN: I quickly came to the conclusion that if the editor was going to be too hard for a “normal person” to use, I would also eventually get sick of it. So I made sure to only include things in the editor that I felt everyone could use, not just myself. This really helped me when creating the levels for the game. Since I’m not hugely into creating levels, having a super easy to use editor was what made it possible for me to create the 28 levels for the game.

Oct 22nd – Anathema Mines – now with animated characters

UPDATE: Using my cool-sauce edge generation script, with just a few minutes of graphics work I can get a totally different look to my game. This is going to be super helpful to giving my low-budget game the appearance that it has art in it (maybe).

TECH: This is the one place that I really used some fun python code. I created these interesting mini drawings of the walls in the gimp, one of the ones I use in the final game looks like this:

TECH: I then use a python script to use sub-sections of that image and face them in all different directions to generate the 200+ possible wall tiles for that style of wall. It took a fair bit of messing around to get this to work perfectly, and in fact the “red technology” has two separate layers to give it the look it has. I also save alpha data about each of these 200 sub-tiles which I use for the light ray-casting collision detection. I also use the same data for just plain collision detection.

Oct 27th – More shadows, levels, and editor tweaks

Not entirely sure if I’ll make the Oct.31 deadline, but I’m making quite a bit of progress. I’ll keep plodding along and see where I’m at in a few days!

BIZ: I missed the deadline, but I came pretty close … My new objective was to send Valve a pitch video of the gameplay footage to see if they would want the game.

Nov 1st – Anathema Mines: gameplay video footage

Here’s my gameplay demo video. I’m attempting to “monetize” the game as of Oct 31st, so I’ll report back on how well that goes.

BIZ: I didn’t report back, but I will now. I sent the video to Valve along with some of what I was planning. They were interested! Had they said no, I would not have spent more time working on the game. This was my way of attempting to “fail early” on this project by seeing if the game looked good enough to have mass market appeal.

DESIGN: You can see how the guards reacted to seeing your flashlight in the distance in this video. I changed this later on in development as it made the game too hard. Also the other “scientist” characters had that ability, so I decided it would give the game more variety if they behaved differently. You can also see how the guards turn around counter-clockwise in this video. This was somewhat random at one point, but now they always turn clockwise when going between two points. This makes tracking their paths much easier when playing.

It’s been a great month working on this. The game is coming along super-well, I imagine it’ll actually be released publicly in about a month now.

BIZ: I obviously have some rather poor time estimation skills. It is now six months later and the game is finally coming out this week! The amount of work and polish that went into this game were way beyond what I imagined, but it’s been totally worth it! I’m super pleased with how this game came together.

The game is coming out on Thursday, May 10th! Be sure to check it out then 🙂

-Phil

P.S. The prototype was named “Anathema Mines”. I almost named the final game “Escape from Anathema Mines” but enough people couldn’t pronounce or remember the name that I decided to change it. A TON of ideas were thrown around, but eventually Dynamite Jack stuck 🙂

Dynamite Jack: Game will launch with map editor

Wednesday, May 2nd, 2012

Hey there .. a bunch of my beta testers really wanted the map editor to be part of the game, so .. well .. I went ahead and just got it done. So Dynamite Jack will launch on May 10th with the Map Editor! I created a tutorial video that both demos the editor and turns you into a Master-Of-Maps in about 3 minutes. Check it out.

This was pretty much a last minute decision, and a bit of a hair raising experience, as the first build I created and sent to the beta testers that included the editor actually broke some of the game levels. Fortunately, the fix was pretty easy and I got that under control. It’s always a bit risky adding new features this late in the development cycle, but I felt that it would really add a lot of value to the game for people who enjoy creating levels.

It also includes a whole community section where levels will be shared, so people who just enjoy playing will get way more than just the 28 included levels 🙂

Disclaimer: this is coming to the desktop version of the game. I can’t guarantee that it will be included in the iPad version of Dynamite Jack. That will really depend on how well the editor interface transfers over. If it doesn’t work well, I will not include it.

-Phil