Gaming Your Way

May contain nuts.

Decision Style #4: Activity-Focused Design

I'm still awe and wonder about what shit comes up when you search for our post titles. This time it's a tech-talk-bullshit gem.

Anyway, it's time to get going with the prototype game and start piecing together all the little tools written so far. I mentioned it on g+ already, but I reached the point where I needed more than my usual ToDo list to keep track of what I want/need to do next.


Just a small part of my "map helper"

The first map I used for testing was quite big and complex and with some 20 rooms and even more doors a bit - shall we say - shit to keep track of. So I invested 2 hours to make a smaller map, then rendered it out and drew my notes on it (making revisions on paper is a bit messy after a while).

Color coded rooms help to maintain overview and layers in photoshop make it incredibly easy to keep track of items to place and doors to connect. Right now I'm placing these in Unity and wiring things up to be able to do a "play through" with the main objectives: find docs (USB drives), codes and key key cards and avoid being caught.

The next thing on my ToDo list however is the minimap, which wont show you the location but items, guards and cameras (and their "senses"). With that in place it's finally time to add security to the map.

Maybe I should add a trigger for the exit first so I can have a "well done" screen up and running (and make it feel more like a game than a pure game mechanics test bed).

-- Oliver / nGFX

The bad gains respect through imitation, the good loses it especially in art.

Friedrich Nietzsche.

I doubt good ol' Fritz had "kings" in mind when writing this, but such is life (though, respect for "kings" seem to fall apart lately...) .


Changing from MonoBehaviour to PanelSettings as base class ...

I've started a first refactoring pass today, one of many, as always. I like doing that every time I have a set of working functionalities that I can group together to make things easier to use / handle.

The code above is a part of the class that handles the tooltips in my current prototype game. The PanelSettings class is basically a wrapper for NGUI panels, adding a name and two methods: Show and Hide (which allow for no-brain fade in / fade out).

Together with the PanelManager singleton it makes things incredibly easy. Instead of creating connections via the Unity editor (read: linking panels to objects who might control them), Panels register themselves in the PanelManager to allow for easy access.

To fade in a panel it's simply:

PaneleManager.Show("mypanel");

// or, if you need a callback:
PanelManager.Show("mypanel", CallbackMethod);

As the tooltips need to be faded in out it was a good idea to use what the PanelSettings class has to offer and remove duplicated code from the ActionTooltip class.

... and with this I continue my refactoring saga and have some candy along the way.

-- Oliver / nGFX

Mack The Knife is back in town ...

... or checking a track for errors

 

Let's start with a screen shot and jump right into the fun stuff, without messing much with the underlying game (where users can create their own tracks).


[a very simple user (read: me) created track]

As always the problem is with teaching that damn computer to see if this is a valid track before it can be played. So what makes a valid track?

  • only one start tile is allowed
  • it must be a closed loop
  • the AI track must be valid and reach all tiles
 

Only one start tile is allowed

This is an easy one, loop over the map and count the number of start tiles. Another easy step to prevent 2 or more of these would be to disable the tile after it has been used one time.
I guess not.

What if you decide that the start you placed in the beginning might be better suited just before that bend you added a few minutes before, you could however just delete it, place it at the new location, then fill the gap ... yeah sure.

 

It must be a closed loop

Now that's a tough one and it took a few minutes to get the right idea. Basically it's using a node based pathfinder (again) and dungeon cells (stolen from Hellstrom.

A screenshot first.


[dungeon cells "applied"]

So each track gets a new property "exits", which is a four character string "0" (white) for a closed exit and "1" (orange) for an open one and as bonus "2" for start tile's start direction. A simple straight track becomes "0101" (N, E, S, W) a corner "0011".

Let's go over all the tiles connected, starting with the start tile ("0201") ... next one is a "0101" and a "0011" (which also change the direction to the next tile to "2" or "South"). While adding new cells to the map we also add a node for the pathfinder and connect it to the previous cell's center.

Blabla bla (new Screenshot)


[Cell'ed up and connected]

At last, we add another node to the start tile when we reach it (and we don't connect it to the first node), just run the pathfinder and see what happens (we should end up on the start tile ...).

 

We continue with the last check after this entertaining commercial about SEO scum that spams our mailbox with the promise to bring us into the top 5 positions on google - or, if you can't see the commercial, when I've written that check.

 

nGFX

Object Pooling, nice and simple

I promised to write an article for a mate over a year ago now about object pooling. As you can see, I'm a little late ( And with apologies to Michael, I don't mean to be shit, I just am ).

Ok, pooling. To sum it up it's a way of re-using objects. Creating new objects is costly, so rather than killing them off we just store them away until we need them again. Pooling is perfect for things like baddies, bullets, particles etc.

Let's get down to it.

In our baddie class we have the following,

public var type:String="Baddie1";

Just a simple identifier, obviously the number reflects it's ID.

We'll come back to that.

In our BaddieHandler class we have the following,

//---------------------------------------------------------------------------------------
		private function createBaddie1(data:Array):void{
			var baddie:Baddie;
			if(baddie1Pool.length!=0){
				baddie=baddie1Pool[0];
				baddie1Pool.shift();
			} else {
				baddie=new Baddie1();
			}
			baddie.init(data[1],data[2]);
			activeBaddies.push(baddie);
		}

That's straight forward ? Ignore the data:Array and the init, that's just passing the x,y positions to it.
So we check baddie1Pool ( In this case its a Vector, an array does the same job ). If there's a baddie object in there we grab it and use it. If not we create a new instance.

Let's go back to the baddie class, when we declare it dead we simply do this,

return "dead";

Back again to our BaddieHandler class ( I've structured this well haven't I ), in our mainloop we have,

//---------------------------------------------------------------------------------------
		private function mainloop_normal():void {
			var baddie:Baddie;
			var cnt:int=0;
			
			for each (baddie in activeBaddies){
				if(baddie.mainloop()=="dead"){
					activeBaddies.splice(cnt,1);
//We can live with defining vars in a loop, as it should only be needed once per loop
					var type:String=baddie["type"];
					if(type!="DontPool"){
						var functionCall:Function=this["returnToPool_"+type];
						functionCall(baddie);
					}
				}
				cnt++;
			}	
		}

So we loop through the active baddies array, running the mainloop for each baddie. If we get returned "dead" as a string we know we've got to put him back in the pool. This is where that identifier from the start of the post comes back into it.

Finally we have a simple method for putting it back into the pool itself, eg

//---------------------------------------------------------------------------------------
		private function returnToPool_Baddie1(baddie:Baddie):void{
			baddie1Pool.unshift(baddie);
		}

The nice part is the use of identifier and the dynamic function in the mainloop, see how we create this["returnToPool_"+type] and then just call it, no messing around with any conditionals to see which pool we should
put the object back into.

And that's how simple pooling is. If you want you can pre-populate your pool ( ie create 30 baddies right at the start of the game, so there's no slow down as you slowly fill the pool to its maximum level ), I just find it easier on my brain to create the instances as I go.

Squize.