Gaming Your Way

May contain nuts.

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

Unity Flash export test

Grabbed the preview build of Unity 3.5 yesterday just to have an ultra quick play. I wrote a simple plasma cube way back ( You'll see how long ago when you see the source below ) so that was the obvious choice to try and export, as I'm stilling suffering the Christmas lazy hangover and don't really have much work in me.

Here's the flash version ( 2.2 meg ) Plasma effect ( Usual Stage3D stuff applies, you'll need a compatible card etc. )

And just for comparison, the native Unity one ( 64k ! ) Unity Plasma effect

You'll see some corruption on the Flash version, which I guess is to be almost expected as it's a preview build ( And also Stage3D in itself is still very new ). I still find it mental impressive that it works at all.

If you fancy playing with it yourself, drag a cube onto the stage and attach this script.

/*-----------------------------------------------------------------------------
@method: Plasma
@author: Squize / www.gamingyourway.com
@version: 4/4/09
-----------------------------------------------------------------------------*/
#pragma strict
public var width:int=128;
public var height:int=128;
	
private var texture:Texture2D;
private var colourTable:Array;
private var activePixelsStorage:Array;
private var sinOffset:Number;
private var paletteShiftX:Number;
private var paletteShiftY:Number;
private var colourTableResolution:int=2048;

//---------------------------------------------------------------------------------------
// Start method
//---------------------------------------------------------------------------------------
function Start(){
	texture=new Texture2D(width,height);
	renderer.material.mainTexture = texture;
	renderer.material.mainTexture.filterMode = FilterMode.Bilinear;
	renderer.material.mainTexture.anisoLevel = 3;
	renderer.material.shader=Shader.Find("Particles/Additive (Soft)");

	createColourTable();

//Create our pixel instances
	activePixelsStorage=new Array();
	var pixelObj:PlasmaPixel;
	
	var j:int=-1;
	var k:int;
	while(++j!=width){
		k=-1;
		while(++k!=height){
			pixelObj=new PlasmaPixel();
			pixelObj.cX=pixelObj.xPos=j;
			pixelObj.cY=pixelObj.yPos=k;

			var xDist:int=width-pixelObj.cX;
			var yDist:int=height-pixelObj.cY;

			var distance:Number=Mathf.Round((Mathf.Sqrt((xDist*xDist)+(yDist*yDist))/2));
			var distX:Number=256 * Mathf.Sin(distance/8);
			var distY:Number=256 * Mathf.Cos(distance/8);

			pixelObj.jointDist=distX+distY;
			activePixelsStorage.push(pixelObj);
		}
	}	

	sinOffset=0;
}

//---------------------------------------------------------------------------------------
// Update method
//---------------------------------------------------------------------------------------
function Update(){
	sinOffset++;
	paletteShiftX = sinOffset;
	paletteShiftY = sinOffset*(transform.position.z)*2;
	
	var pixelObj:PlasmaPixel;
	var cnt:int=-1;
	var length:int=activePixelsStorage.length;

	while(++cnt!=length){
		pixelObj=activePixelsStorage[cnt];
		pixelObj.cX=pixelObj.xPos+paletteShiftX;
		pixelObj.cY=pixelObj.yPos+paletteShiftY;
		
		pixelObj.offset=(Mathf.Cos(pixelObj.cX/16) + Mathf.Sin(pixelObj.cY/32))*256 + pixelObj.jointDist;

		if(pixelObj.offset<0){			
			pixelObj.offset+=colourTableResolution;
		}

		texture.SetPixel (pixelObj.xPos, pixelObj.yPos,colourTable[pixelObj.offset]);
	}
	
// Apply all SetPixel calls
	texture.Apply(false);
	
	transform.Rotate(Vector3.right * (Time.deltaTime*30));
	transform.Rotate(Vector3.up * (-Time.deltaTime*23));
	transform.Rotate(Vector3.forward * (-Time.deltaTime*3));
	
}

//---------------------------------------------------------------------------------------
// Private
//---------------------------------------------------------------------------------------
private function createColourTable(){
	colourTable=new Array();
	var cnt:int=-1;
	var col:Color;
	var offset:float=3.1415;

	while(++cnt!=256*4){
		col=new Color();
		col.a=1;
		col.r = (128 + 128 * Mathf.Sin(offset * cnt / 32))/255;
		col.g = (128 + 128 * Mathf.Sin(offset * cnt / 64))/255;
		col.b = (128 + 128 * Mathf.Sin(offset * cnt / 128))/255;
		colourTable.push(col);
		colourTable.push(col);
		colourTable.push(col);
		colourTable.push(col);
	}
}

//---------------------------------------------------------------------------------------
// Pixel class
//---------------------------------------------------------------------------------------
class PlasmaPixel{
	var xPos:int;
	var yPos:int;

	var cX:Number;
	var cY:Number;
	
	var jointDist:Number;	
	var offset:Number;
};

And that's all there is to it. It could be optimised a lot, but look how old that code is, I think I'm allowed a pass for that.

If you do anything nice with it please drop a link in the comments.

Squize.

Unhappy meals - and that's OK

If you come here often you might have seen the screenshots of the "random mine" game, well this one won't make it to a full game.
There's a good reason of course (actually there are a good number of reasons).
I still like the appeal of random created levels, but this one didn't quite work as well as I thought. The early alpha version showed that a jump & run game needs carefully designed levels in order to be fun and you can't fake that by adding elements from other genres.
That was something I discovered pretty early in development and changed the idea from "really random" to "random pieces" or blocks.
This created levels that were playable, but in worst case quite repetitive. The obvious thing to do was to create more variations of the basic tiles (or parts). 

 
These are the basic blocks the generator used.

 
A version of the 0101 block.

I create a set of variations for the blocks (each one uses 30*20 ingame tiles) which worked well at a first glance.  But due to the random nature could appear multiple times in a large map. That drained the fun more than I expected. In the end it proved as much work to create varied and fun blocks as to create a whole level.
Tough decission, but I didn't want to design a jump & run game, I wanted to write code that does that for me.

Zipped and stored away for later use.

 

So while Squize works on an AAA title I'm back at the beginning of a new project.

 

You've seen Knuckles (I think he might change a bit in the end), the main character in the Unity game I decided to do (that mine game should have been done in Unity in the first place, too - but flash seemed to be make a faster development possible).

The Idea for Nuckle's game evolved from a 2d sidescroller into a 3d game, so using Unity seems the better choice - even though there's the promissing stage3d api around.

Right now I'm focussing on the controls, aiming at a mouse only controlable game, but adding optional keys for movement. I think point 'n' click controls are what I'll use in the end.
But first there's a lot of stuff to code for the first level and I need to find ways to wire things in the game (like alarms and lights) to create an working environment.
If that proves to be "fun", more things can be added for the later levels (guards, cameras, more types of alarms and security).

nGFX

More Nuckles

[forcezoom]

Pretty much where I want it to be now. Not textured yet and only using plain colours.
I guess I'll add bones now and do a simple walk cycle. With that in place it's time to do some environments (and props) for walking around in.

 


nGFX

[In desperate need for a catchy title]

So what am I going to write about today?

I guess my last post is so long ago you must believe I left GYW and let Squize do all the posting. Well, no. I just had nothing to write about, nothing even mildly related to games anyway.

And while Squize wrote all this posts (and awesome games), I wrote … an online picture database. This 'small' project took way, and I really mean WAY longer than I thought. My first guess was 'ok, maybe three month, max four' - lesson learned there. In the end it took a year and changed from a very basic database driven website to schow (and sell) some 40 years worth of black and white press fotos to an ajax driven catalog monster. There is a quite complex backend to handle the images' keywords and background informations, import and upload methods, a product and discount editor and a whole lot more, that makes up a good third of the all-in-all 54,000 lines of code - ok this includes some 9k lines of javascript and a lot of css.

By the way, if you happen to speak German, go have a look at it (otherwise you've just have to click on "Fotosuche":
http://www.krefelder-fotoarchiv.de/

And if you like a hairy leg on a woman, have a look at these "swimsuit models", (And while you're at it consider buying a few prints :) )

Now that I got this out of the system, I can as well add something about why it took so damn long (about 10 month):

1. style and code revisions. As I mentioned earlier this one got bigger than the first idea, this wasn't such a big problem as it was an inhouse project.
2. oh and it was an inhouse project. So adding things, tweaking design and layout caused some rewrites and with no fixed schedule … do I have to say  more?
3. Ajax. Ajax eats time, and imho javascript sucks (even when using  jquery). Until I started to use Aptana Studio each fucking line was a chore (and honestly still is).
4. customers :-), just when I really was deep into the c# code of the backend there was scheduled client work ahead.

Although looking back now I'm quite proud of it.

And now - finally - games.

Right after (and when I really couldn't face serverside anymore) I started working on two games. One's nearly finished: a flash puzzler based on two cute (and cute normally isn't a word I like to use in this context) robots called Nuts and Bolts. The other one is an Unity based gamed re-using an old game idea of mine where you collect items and solve small switch based puzzles to reach the level's exit. It's got quite an unusual control scheme which I hope will bring some mobile/gyro feel to the mouse using gamer (and later be ported to Android without much trouble).

Right, enough text for me, here's a big lot of screenies:
2011_crystalis_00.jpg

2011_crystalis_01.jpg

2011_nb_00.jpg

2011_nb_01.jpg

I'll let these stay uncommented.

And now ... levels for Nuts & Botls

nGFX

GPS? Not down here, but we've got magic!

Screenie post I fear ...

thp_chrome_screenie_path.jpg
Current Hellstrom built in Chrome with the debug pathfinder being a little show-off.

What's new? Just a lot of code atm. There's a second pathfinder in it now (after I discovered that the one I wrote for flash a good while (ok, years) ago didn't quite work as expected.

I really like the old one as it only needed a boolean map to work, though with the dynamic dungeons in hellstrom that proved to be a bit tricky anyway as I had to render my cell structure used for the maps into the boolean map:

+---+    #####
! ! # #
! D >> #
! ! # #
+---+ #####

While the cell stores just if there is a wall, say for north, the boolean map needed to have a wall made of "false". (see : here (scroll down a bit) for some more detailed explanation about the structure I use).

Anyway the new pathfinder (codename: Magellan :) ) uses linked nodes instead of a boolean map, this is not only incredibly usefull (as it can adapt any "scale"), it also works in 3d / multiple levels and can use "one way nodes". The code isn't as clean as I wanted it to be, but it's working and abstract enough to be easy to use...

_Magellan = myDungeonCreator.createMagellanMap(_Dungeon, new Magellan(), false, false); 
// dungeon, pathfinder ref, use locked doors, move diagonal


it uses 3d Points as internal ref system so to find a path you's simply:

string Result = _Magellan.FindPath(_Dungeon.Rooms[iStart].offset, _Dungeon.Rooms[iEnd].offset);

With Result being some handy string to be parsed, like "noLink", "pathFound". The found path is internally stored as array of index ponters to the nodes, so we need to "parse" it to be used:

PointInt3D[] path = _Magellan.path3D;

enough code now.
If I feel luck I'm going to post it, though first I need to get alive through the much dreaded holidays (way too much food and family - and way to much drinking in order to forget the two) ...

nGFX


It's all about chosing the right door.

Just another picture post...

hellstrom_temp_00.jpg

Screengrab of the current test version of The Hellstrom Project showing a few of the corridor tiles I've set up.
The mappings aren't final, nor the lights (will render the lightmaps later) - and it's only one of the visual styles that will be used in the game (and dungeon) - but that's another post (I don't want to give away the story yet).

Right now you can only run around the generated dungeon, though new things are added daily when updating placeholders with new models and refine/add methods.

nGFX

Say "Hi" everybody ...

Small picture post this time.

hellstrom_danielle_00.jpg
This is "Danielle" (or what she looks like atm) for the RPG'ish game I'm working on in Unity. The project isn't quite showable atm, but I promise to upload something when there is more to see (like having Danielle walking around).

She'll def get a visual overhaul for the game (and this model will be used as "Generic Femal Player") as the "real" Danielle will get a lot more "pirate" to her outfit. (The other two playable characters will be quite different, but more on that ... later)

She's modeled from a foto reference with a good set of idealizing the model and she'll need some optimizing as the whole model is using 3.6k triangles atm, though she can be reduced safely to about 2k polys.

So long and back to Unity, nGFX

Let's start all over again - or "how to handle all that weight"

Ok, the last bit of the headline was a cleverly placed quote from someone who took Mass Effect 2 way to serious, but hey it still fits.

Our little toy based Unity game has made some nice progress over the last few weeks (with just a few scattered coding session inbetween all the other  stuff that needed to be done). I'd go as far and say it is just a few 100 lines away from becoming gold (yep, in more than one way hopefully).

toygame_00.jpg

So the the release date is coming closer - at least that is what I thought till Friday...

And now the pretty headline kicks in. Why on earth do I want to start all over? The reason (and once I learned to handle all that weight) is quite simple:
It's a grown game, it started off easy, but then lingered it's way through some fails (talk Unity animation system and events) and a "second" floor and ended in the tab system that should showed informations as well as the ingame help.

There was quite a loud "damn fucking shit" from my side when it finally dawned on me that Unity's UI system (which, honestly is dog shit) does only handle click events and is missing the "over, out, down and up" states I've came to expect from flash. So my idea of using a rollover event on the tabs to focus the camera on an object failed badly. Before I even started to code it (the idea was to show each moving toy as a tab, then if you move the mouse over it's tab the camera would zoom in on the toy to show it in closeup - pointless but neat), plus from time to time help tabs should be added that can be ignored or read. Oh, and while I'm at it, hints to be shown on rollover for the built in level editor became quite impossible too.

Next point on the list of "things not easy to add" was "scaleability", read new decorational elements, backdrops and styles that could be bought by players so that we can earn a quid (to pay the servers for instance).

A few hours later, with a few sheets of paper used as external memory, I swallowed the bitter pill and decided to start all over again. Starting with a new map system, new "landscape" features, a more flexible decoration system, the level editor (and a way to save these levels on our severs), deciding an a service for micro transactions and, and, and ...
The tiny little game grew up, causing a lot more thought and work then I ... thought ...

Either I start again, or drop it, but I do believe that (oh did I mention I'm doing an overhaul of the visuals?) it might get some fans playing it on Facebook or through our website ...

And now: Day 1 of the development diary (oh come on, I doubt I'll ever be able to write about it every time I code on it. Just that much: next time I think I'll have a quick look at MT systems for Unity right now I'm looking into UnityTokens and Dimerocker (and if you know some else don't hesitate to post a comment).

nGFX