Gaming Your Way

May contain nuts.

So, whats the plan, Stan ?

Firstly, hello blog, it's been a while. A very long while.

There is a valid reason behind that, I just couldn't be arsed. It takes two seconds to write a tweet, a blog post with true depth and insight takes a lot longer. Even a rushed crap post like this still takes a while.

Ok, so I've been working on Rot:Purge forever now. Getting a full time job a couple of months into its development didn't really speed things up.

To try and get some light at the end of this very long tunnel the current plan for the game is to release a Swarm ( / Horde ) mode version, just to get it out there. That way I get some vital feedback and people actually get to play the game, which is crazy talk I know.


A picture with no real context, because, blogs.

The other benefits of this approach, aside the main one of me keeping my sanity, is that it's achievable. It's viable to push out a one level Swarm demo with reduced UI and game mechanics.

It's either go with Rot Swarm, or the game doesn't see the light of day for a long long while, and by then any issues will be too firmly entrenched. Basically I think it's a win all round, and obviously the Swarm mode will be free, with the aim to update it constantly ( It's just going to launch with the town square level, but there are three other levels already waiting in the wings, they just need some improvements retro fitting to them )

So that Stan, is a very quick update of the plan going forward. I'm hoping to make more time for posting here again, where we can get down and dirty about the game a lot more, gameplay choices, the voxel tech etc.

Squize.


9 years, and counting

Nine years ago today GYW burst into life, redefining what it meant to play online games.

Well, that was the plan. In reality we've done some good stuff, some average stuff and some stuff that was purely for the money that we take no pride in.

Yep even after all these years we still know how to really sell gamingyourway as a brand.

Anyway this was just a brief blog, I'm trying to get back in the swing of it, rather than a post every two years.

More soon...

Squize.

Object pooling without all the ins and outs

I've been meaning to write this up for a while now, so before we start it's going to be a long one ( And I'm not going to make it even longer with a "That's what she said..." comment.. damn it, already ) and could end up being a little dry in places ( "That's..." )


Ok, we all get object pooling, any mention of optimisation includes the term like some sort of crazed mantra, so I know what it is, you know what it is, let's actually start from there.


Until recently I did it like this:

//Fill our pools    
    this.activeParticles=new Array();
    this.particlesPool=new Array();
    var particle;
    var cnt=-1;
    var len=numberOfParticlesWeWant;
    while(++cnt!=len){
        particle=new ParticleInstance();
        this.particlesPool.push(particle);
    }

The pool would be pre-filled to it's max length, I don't understand all this growing pools thing in a game, when you're getting an object from the pool it's because your game is doing tons of stuff anyway, why make it run even slower.
The main loop would then be:
  var particle;
  var cnt=-1;
  var len=this.activeParticles.length;
  while(++cnt<len){
    particle=this.activeParticles[cnt];
    if(particle.mainloop()=="dead"){
      this.activeParticles.splice(cnt,1);
      this.particlesPool.push(particle);
      len--;
      cnt--;
    };
  }

I'm just showing this for the general gist of things, two arrays, an active particle array and the pool array, when a particle stops being active you remove it from the active one and put it back into the pool.

The thing I've changed recently, which I've seen really improve performance, is the whole array access part. Every time you use pretty much any Array method, such as splice, it returns the new array. That's handy, but if you're not doing anything with it's just floating around waiting for the GC to spot it and kill it off for us. This is happening 60 times a second and when the GC kicks in is anyones guess, 1 second, 5 seconds ? Either way it's a lot of junk data just sitting around ready to be cleaned up.
Also you're no longer working with fixed length arrays, which is another strain as they shrink and grow.

The new way I've moved over to is having both a pool of objects as normal, and an offset table.
    var len=48;
    this.bloodParticle_poolOffsetTablelength=len;  
    this.bloodParticle_poolOffsetTablelength4=len/4;
    var buffer=new ArrayBuffer(len);
    this.bloodParticle_poolOffsetTable=new Int8Array(buffer);
    this.bloodParticlePool=new Array(len);
    var cnt=-1;
    while(++cnt!=len){
        this.bloodParticle_poolOffsetTable[cnt]=cnt;
        this.bloodParticlePool[cnt]=new BloodParticle(cnt);
    }

That's code directly lifted from Rot, I may love you but not enough to write new example code for you.
So there we use the len/4 for loop unrolling later on ( So all our pool lengths have to be divisible by 4, but you can go with 2 or 8 or whatever you can face ).
The one "What's that now?" thing may be the Int8Array. Basically it is what is says, an array which can only hold 8bit ints. It's much quicker than a normal array and all we're doing is storing numbers in it anyway, the table is just a list of offsets to our pool array.

When we request an object from the pool we loop through out table offsets, looking for a valid number:
ParticleHandler.prototype._getBloodFromPool = function() {
    var offset=-1;
    var cnt=-1;
    var len=this.bloodParticle_poolOffsetTablelength4;
    var table=this.bloodParticle_poolOffsetTable;
    var pool=this.bloodParticlePool;
    
    while(++cnt!=len){
        offset=table[cnt];
        if(offset!=-1){
            table[cnt]=-1;
            return pool[offset];
        }
        offset=table[cnt+12];
        if(offset!=-1){
            table[cnt+12]=-1;
            return pool[offset];
        }
        offset=table[cnt+24];
        if(offset!=-1){
            table[cnt+24]=-1;
            return pool[offset];
        }
        offset=table[cnt+36];
        if(offset!=-1){
            table[cnt+36]=-1;
            return pool[offset];
        }
    }
    return false;
};

If the offset isn't -1 then it's valid and we can claim it, so then set it to -1 and return the object. That's it, we've got our object ready to init() and no arrays were slapped around for it.
( Also you can see where our loop unrolling comes in to it )

Right, we've created our pools, got an object from them, how to do we run each object ?
    var len=this.bloodParticle_poolOffsetTablelength4;
    var table=this.bloodParticle_poolOffsetTable;
    var pool=this.bloodParticlePool;
//Sorry about the broken indenting here, it bugs me too        
        cnt=-1;
        while(++cnt!=len){
            if(table[cnt]==-1){
                if(pool[cnt].mainloop()=="dead"){
                    table[cnt]=cnt;
                }
            }
            if(table[cnt+12]==-1){
                if(pool[cnt+12].mainloop()=="dead"){
                    table[cnt+12]=cnt+12;
                }
            }
            if(table[cnt+24]==-1){
                if(pool[cnt+24].mainloop()=="dead"){
                    table[cnt+24]=cnt+24;
                }
            }
            if(table[cnt+36]==-1){
                if(pool[cnt+36].mainloop()=="dead"){
                    table[cnt+36]=cnt+36;
                }
            }
        }

Pretty much the same as requests the object from out pool, if the object is dead we just put it's value back in the offset table again.

Break the bad news to me gently doc.

You may have noticed the downside, which is in our main loop. In our original way we took the active particles array length and worked through that, so if there were only 5 objects running then it only looped 5 times. It doesn't really allow for loop unrolling, but it's always just doing the correct number.
In our table offset approach we have to check every object every time. That's less than optimal.

But...

Say your game needs up to 20 explosions running at once. Firstly, cool game. Secondly, that's the worst case scenario and because we're already checking all our objects every frame we pretty much know the game can cope with that worst case.
Also you can set flags to see if certain loops even need testing ( I removed those checks from my pasted code just for ease of reading ). Your explosions aren't going to be happening every frame ( If so, again, cool game ) so you can do a simple test to see if any are running, if not skip the loop entirely, if so run the loop and keep a running total of how many objects are actually running, if it drops back to zero clear your test flag again.

I'm sure all of you reading this have your own ways of pooling, everyone does, and I'm sure some of you will be able to pick holes in this, good, please do so in the comments so that information is shared, but I've found not altering the arrays has had a large performance boost on mobile which more than cancels out the overheads involved.

K, I've got a freeze gun to finish adding to Rot, so that's me spent.

Squize.

Rot: PixiJS Depth sorting and performance

I thought I'd do a techy post for a change, it's been a while hasn't it ?

If you've played the demo or even just seen screenshots you'll know Rot is an isometric game.

God damn that tilt shift filter is good

Because the game was always destined for mobile performance is a key issue.

Depth sorting is always painful to do, to do it correctly you're looking at doing a topological sort ( See this excellent blog post for more details: https://mazebert.com/2013/04/18/isometric-depth-sorting/ ) which is fine if you're not running too many sprites, but less than great if you're looking at a silly number of particles, and Rot is all about a silly number of particles.

Let's backtrack a little. The display is made up of various play fields ( Layers ), the background is burned into one large sprite, on top of that we have the sprites play field ( i.e. all the zombies, particles, pretty much everything moving ) and then a fore ground play field ( There are more, but let's not make this any more complicated than it needs to be ).

Because of having the background / foreground laid out like that we don't have to depth sort them at all, we only have to worry about the sprites themselves.

I added an extra property to each sprite, isoZ. This is just a simple old school depth sorting formula I'm sure you're familiar with, based on the sprites x/y position ( For more details see the link above, or pretty much any tutorial about iso ) and gives us something to sort by.

Along with that property we also added a new method to the DisplayObjectContainer class, zSort(). This method loops through all the children in our sprite play field and tests if they're visible or not, if they are they get shoved into a new visibleChildren array. This is because we only want to sort sprites we actually care about, visible ones.
We learned a lot about performance working on DN8 for iPad, and one thing was to not add / remove children when they were needed, there's a large overhead for that, so when we start a level we add nearly all the sprites at once so they're there ready and waiting for when we need them ( Things like explosions are added as needed because in the overall scheme of things they're pretty rare, but zombies and blood are always in use ).


So we have over a 1000 sprites just sitting there waiting to do their thing, but by setting the visible property to false our zSort ignores them ( This is why we check for visible rather than just looping through all the children of the sprite play field ).

This improved performance a lot, the max number of sprites we sort is 512 but in testing even with multiple explosions going off it never hits over 350, well within out limits.

The actual sort code is simple as it's possible to be,

    this.visibleChildren.sort(function(a,b) {
        if (a.isoZ > b.isoZ){
            return -1;
        }
       return 1;
    });

That's it, we don't even really care if two sprites have the same z depth, we're using large numbers for the isoZ value so it's a little unlikely and even if it does happen, it'll be for a 60th of a second. I can live with that.

Now if you've played with doing iso games before you'll know this way can lead to clipping, where the depth sort is a fairly cheap and therefore not as good as doing a topological sort.
Yep.
The objective was to make the depth sorting good enough, not perfect. We lose a little accuracy, which hopefully you don't notice when playing ( You will now though ) in return for performance.

So cool, we've pulled out all the visible sprites and sorted them, job done...
( This is my Colombo moment )
... but there's one more thing.

When you look at any sort of display graph, the containers ( Be it a DisplayObjectContainer in pixiJS or the Stage in Flash ) are pretty much just a list of the children. To display them the plotter simply loops through the list plotting one at a time, much like a painter would ( Ah, that's why it's called the painters algorithm, it finally makes sense ).
But we've got a sorted list of only visible sprites, with a little re-writing we can remove some of the checks in pixiJS's plotter loop, we already know all these sprites should be plotted. Further more we can also check to see if the sprite has any children itself, the way the game is set up they usually don't, and if not avoid some extra looping too.

To recap, by doing a simple visibility test before sorting and then using that data we can really improve performance. The zSort method was around the 3rd most expensive function call when profiling the game, that's dropped right down now.

Squize.

I want it painted black

Firstly, thanks to everyone who played the demo over the weekend, the feedback has been excellent.

To celebrate the game finally going out into the wild I had a couple of lazy couple of days, just adding love here and there.

I think the title of this post gives away where I spent that time.


The fire effect was in the demo, but I wasn't quite happy with it, so I've exported all the frames with -60% brightness and now as the fire burns on we slowly reveal the darker frame ( Just by increasing it's alpha ).
It's a little change but it makes a big difference, it's good to show direct feedback to a players actions.

Now because re-exporting a ton of frames is just boring donkey work I treated myself to adding some ember particles rising up off the burning zombie.
Zombies are only going to catch fire when caught up in an explosion, which already triggers a ton of particles ( Maybe too many at the moment, I think I may be showing off a little with those and could perhaps cut them back ) so there's actually a delay before we trigger them embers to try and keep the performance high.
Also I think the embers will be dropped entirely if the game is running on mobile, on my iPhone 5 I'm getting a fairly good 30fps, my iPad3 is less and more variable, so eye candy like this can be optional depending on the platform.

Squize.

That's rotten

So it's been like a 100 years hasn't it ( Well, nearly a year ).

Time to pimp our new game then,


I've been working on this for just over 3 months now, my first big HTML5 game, and we're finally able to show off the demo:

http://www.gywgames.com/rotdemotwitter/

We're about half way through content wise, there's a more weapons and outfits to go in there, mainly this build is to see if people find it fun or not.

Hopefully over the next few weeks I'll actually flesh out what goes into making a monster of a game like this.

Squize.

PS. It's good to be back.

It's Friday, again ? So soon ?

As a quick follow up to the last post where I was trying to fix the tiny slow down in the game I had a bit of a break through. Reducing the size of my pooled objects made a really large difference ( I was just pre-pooling too many items, mainly as a safety net ).

With those pools reduced it's a lot smoother now, which I'm pleased about.

Set up a twitter account for the game ( @DN8Pulse ) , as I think it's going to be an easy way to get quick feedback from players.

And to hopefully finish off the twitter / social stuff I've added a "Tweet your score" option to the game over screen. I thought rather than just a bland text tweet a custom image may be cool, and that's what you can see above there.
( It's all done using Movieclips and Sprites in Flash, so didn't take a fraction of the time to have done it in Starling, and it's just so nice being able to layer and position things in an IDE ).

I've just finished the Orbs power-ups, these are two droids that spin around your ship blocking baddie bullets. If a bullet hits one rather than just being destroyed, it's rebounded back at the baddies, which should hopefully be slightly more than a nice touch.

A bit of a slow week really, more focused on the fluff rather than getting levels and baddies in there. There's still more to do than I'd hoped for, it should be coming to a close now.

Squize. 

(no subject)

On the weekend if I'm working I like to count it as "Treat days", where I get to dick around with things I don't really have time for.

This weekend I updated the skybox to a much nicer collection of 1024x1024 textures and to celebrate I added some parallax stars.

The stars had to be away3D sprites as they needed to go behind the planets ( That took ages, 3D positioning isn't my strong suit ).

It looks lovely with a 100 stars, really nice and subtle, but as ever the iPad isn't going to cope with that. When I was testing though I did notice a one frame hold up when a baddie was killed ( The new stars actually really helped with the testing of this, I could see them jitter, which is something which I was missing with just the planets / skybox in there ).
Today has been spent trying to optimise things to avoid that judder. It was a case of removing every element of the explosion until I found the bottle neck, which it turned out are the particles.

So I've removed one of the explosions ( Down to 3 from 4 ), capped their max size as they grow in size depending on the beat of the music, reduced the number of particles which are belched out and done some loop unrolling in Starling itself.

A couple of things I noticed, with the particles I could pre-calc pretty much everything, their speed / rotation / speed and store all those values in Vectors in the constructor so their actual movement / scaling is just a case of getting values from a Vector, which helped. The code per particle is really cut down now.

Also with my alteration in Starling to keep the visible / invisible display objects in their own Vectors ( More here ) I found that there could be really large loops due to the number of children in the game, so I've unrolled some loops there. I think I need to do some more work though, as triggering 34 particles at once means a lot of looping to move the sprite from the hidden to visible Vector. There's got to be a smarter way to do that.

All these amends still haven't got rid of the tiny judder, I don't think it's going to be possible and I'm not that gutted about it, I'm developing on the slowest on the market iPad ( 3 ), and I added an additional check that if there are more than 20 particles running at once then I hide these new sexy parallax stars. It may sound nasty, but they're really tiny and it gives the impression that they're blinking ( Also if there are explosions kicking off on screen you're not going to notice anyway ).

Have I go time to mention retro mode ? No, ok, let's save that for now then.

Squize.

Sociable, for a change.

At present with the game I'm trying to do as many of the boring things as possible, they're going to need doing so let's kill them off in one painful hit.

So yesterday was the pause mode. Now user acquisition is a thing I need to think about as this is a mobile game, rather than a Flash one that will get traffic almost in spite of itself, and the cheapest way to do that is to leverage social networks ( Shit, I'm starting to sound like all the blogs I've been reading recently. Just don't get me started on Customer Lifetime Value calculations ).

Rather than shoehorn a "More games" link or banner ad to the pause mode, I've added the ability to tweet a screenshot.

My never used personal account, a victim of my own spam.

I'm quite pleased with it, it has a nice taking a photo effect along with a picture frame, it looks pretty good. Ideally I'd like to be able to let the player mess around with the image like the screen grab feature in AAA games, but I don't know if only one person in the whole world will use this, so it's best to focus on what will be used rather than what could be.

And that's the Game Over and pause mode done. Hopefully next week will see more levels ( I've got to drop the bosses in yet, which I'm looking forward to ) and the final player power-ups.

Squize.