Gaming Your Way

May contain nuts.

Dungeons: Explained better

A bit of a repeat post. Nothing from us for ages, and then when it arrives it's just a rehash. Ages back I did try and explain how we make the dungeons in Knight'sQuest ( FB link ), but using test data images along with poor writing didn't explain it too well I don't think.

Ok, so we have at the basis Olli's dungeon generator code. This creates an array of objects describing a room / corridor. Each room is made up of blocks and blocks are made up of 4x4 tiles. The rooms are made up of a variable number of blocks, so we can have small tight rooms or bigger expansive areas.

When plotting a dungeon ( A generic term, it covers the caves and the new forest ) we look through each room which starts its life as just a collection of 4 digit numbers which are stored in a clock wise fashion ( North, East, South and West ) and each tell us if there's a wall / door / nothing.
For example, if we get the code 0111 that means there are walls to the north, and nothing in any of the other directions ( Little weird 1 meaning an empty space, to be honest I couldn't face refactoring Olli's code ).

Due to the large number of combinations, using a switch / if statement was a non starter, I'd still be typing it now, so we used this cheeky bit of code,

            var directionsAsString:String;             if(location=="caves"){                 directionsAsString="caves_"+northWallValue+eastWallValue+
southWallValue+westWallValue;             } else {                 if(location=="dungeon"){                     directionsAsString="dung_"+northWallValue+eastWallValue+
southWallValue+westWallValue;                 } else {                     if(location=="forest"){                         directionsAsString="forest_"+northWallValue+eastWallValue
+southWallValue+westWallValue;                     }                 }                     }                          try {                 var functionCall:Function=this[directionsAsString];                 functionCall();             }             catch (e:Error){ Debug.trace(directionsAsString,2);                 if(location=="caves"){                     caves_1111();                 } else {                     if(location=="dungeon"){                         dung_1111();                     } else {                         if(location=="forest"){                             forest_1111();                         }                     }                 }             }

Basically we just turn the value into a function call. The try / catch is there in case I've missed one of the possible combinations ( And the trace is so I can find out which and fix it ). Using our current example value from above, and we're in the forest this time, we'd call the function

private function forest_0111():void{

Which is a million times easier than any sort of conditional.

Right we now know what block we need to plot ( Take it as read we know the x/y position of it, this isn't the most fun post in the world as it is without me going into that depth ), how do we store the blocks themselves ?

KQ_darkForest.jpg


In the IDE we have block movieclips, like you can see above. Inside those blocks we have a floorMC and then the tiles. For the floor we just use bitmap draw() to grab it and turn it into a bitmap, and then burn that into the master ground bitmap ( All the floors in the game are just one huge bitmap, so no depth sorting or messing around, it's just a flat bitmap we scroll ).
The beauty of this approach is that the floors are in effect art style, we can drop any image on any pixel position, use blendmodes / alpha / scaling / anything really and because we're just burning it into the ground bitmap all this extra stuff is basically free.

That's the floor covered, next the tiles. Each tile in a block is just a movieclip, with an instance name. See that campfire on the top left block ? That's got the instance name "forest_088", and we just store that in an array with a reference to the bitmap of that image ( We're using the blitter for everything, which means bitmaps ). When plotting a block we loop through all the tile mc's in the block, find out the reference to it's bitmap and create a Bob ( Blitter OBject, ie a sprite ) for it.
In terms of layout, we don't have to be really anal, none of these tiles are pixel perfect aligned, that would be soul destroying, so the plotter rounds things down and most of the time gets it right.
One other slight bit of weirdness before we move on, each instance of a certain tile has to have the same name. Going back to the top left block, notice all the trees are the same ? They are all called "forest_008". Normally we'd never use the same instance name, as that's mental and wrong, but all we're doing is looping through each mc in the block, getting it's x,y position relative to the blocks origin, and then it's .name so we can look up the bitmap reference.

Not easy going I know, sorry. We're nearly there.

Notice we've got 4 blocks all with a north facing wall. To try and make the dungeons look as good as possible we make as many variations of each block as we can face. Before we actually plot them, we pick one at random ( Again, another array, just listing each possible block for each possible combination ).

If you've got this far then well done. Hopefully it explains things better than before.

Squize.

Knight's Quest, get your mana on.

Finally finally finally, we've soft launched KQ. With it being a soft launch it means we know there are things we need to tweak and change and there are more features planned over the next couple of weeks ( Today is a day of resting ).

Rather than me write reams of boring text, here are some pictures to give you a taste before clicking ( Or not ) the link.

KQ_village.jpg

KQ_fireballs.jpg

Now it's finally out for everyone to play I'll be able to do some more techy posts about how it does what it does, I was kind of loathe to do it sooner as explaining how the spiders AI works in a game you can't play is a bit abstract.

Please, any and all feedback in the comments is more than welcome. We can't make the game better if we don't know what's important to you guys.

Here's the link, ( Facebook only I'm afraid, it's the nature of the beast ) go and hurt some big spiders ( They so deserve it ).

Cheers,

Squize.

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

Knight's Quest, the story so far...

Sorry we've been a bit quiet here recently, both Olli and I have been beavering away like a couple of mentals on projects which hasn't given us any free time to devote to the blog ( Also we didn't have that much of interest to say ).

Knight's Quest, our first Facebook and our first RPG, has been my main focus for weeks. It's finally starting to come together after weeks of just working on the techy side, so I thought it may be of some interest to go over some bits and bobs from it.

The game is iso, which is a pain at the best of times. Z-sorting is murder. How I've gone about it is to split the map into sectors. Each sector is 16x16 tiles, and we only z-sort on those visible areas ( Also we turn off any plotting in sectors which aren't visible ).
This really reduces the sorting to just what is needed, also the floor tiles are burned into their own bitmap ( See this old post ) so we're only having to sort tiles and sprites, which helps.
Also as we're using the blitter we don't have to worry about sequential indexes, it's like as2 all over again, where you could give a sprite any old depth and not care about it.

Next up, the dungeons. I've used Olli's generator ( He's written tons about it previously ) and it works a treat. Basically it creates "cells" which are in this case 4x4 tiles. The cells tell us which walls or doors are present. Rather than just randomly plot tiles I've set up a lot of mc blocks, eg.

KQ_tiles.png
This may be tricky to explain well so stick with me. As we read each cell we know what's there, let's say for example a north and east wall. From there we look up the array which contains all the blocks with a north and east wall and pick one at random.
The floor is burnt into the background bitmap and the wall tiles ( Or cauldron placeholders ) are converted into blitter sprites ( Bobs ) which can then be plotted / sorted etc.
The reason for this is that we can then hand design a lot of different wall blocks and use them randomly ( Rather than just picking one random tile at a time ). It should make the dungeons look more hand designed, which is what we want.
It's important that we create the impression that someone has slaved over each dungeon to make it look as non-random as possible.


I think that's about it for now, there will be more to share real soon.

Squize.

first post in ages - and a jolly short one too.

I guess you won't remember me (nGFX) as for ages only Squize has done all the posting. Not that I have been lazy, but there hasn't been a single line of interesting code on my side, nor something mildly game related.

I've been coding some large scale foto archive software. To sell our really vast collection of black/white press fotos (180 000 of the 1.5 million negatives should be available in the end) and coding the backend and the frontend (with lots of ajax). Right now last bits and bobs of the user handling needs to be done and there are still a good number of negatives to be scanned (alas, thank fuck I'm not in charge there).

fotoarchiv_00.jpg

Ok, back to something game related at last ...

While Squize is churning out flash games like mad, I've jumped on the Unity train (of course) and been tinkering with it for a while now. I've started with porting the dungeon creation code over to C# and played with dynamic maps, which proved to be working just nicely. In order to get more out of this project I thought it might be helpfull to get deeper into Unity with smaller game.

A remake of one of my games seemed a good idea, I've got the AS2 code to look at and knew how the game should work (and added some minor additions). So here's something I've learned besides the usual "oh damnit" ...

Unity's animation editor is good enough to make things easier, but don't trust it on time critical problems.

The game involves things moving along tracks - so my first idea was to save some code and use animations for that. I wanted to use a container that I can just move from tile to tile and let the "car" move inside it from the start of the tile to the end of it, then an animation event should be fired, telling the engin to move the "car" to the next tile and start the correct animation.

I did a few tests (of course) and it seemed to work, so I did all the animations (straight tracks, junctions, ramps and so on) which roughly saved some 500 lines of code (compared to the flash version) - oh lovely - same game, less code, I was on fire.

Of course it didn't work.

I tested it locally, online in a browser and all went well until I noticed that the timing can get off the track and cause visual glitches. These showed themself as "jumping" car, where the car jumped ahead one tile for a single frame and then continued as intended. This happened every time I started a level - but not always at the same time (hence I didn't see it in my tests).
After a good night of debugging, tracing (or Debug.Log()) I found out what happend.

Unlike flash the "timeline" in Unity doesn't sync visuals and code - and in fact Unity has no "timeline" - point taken, lesson learned :| .
So this happened (and caused the glitch)
1. [engine] sendMessage -> [car] "goto next tile"
2. [car] move to next tile, rewind animation, play it
3. (glitch might occur)
4. [car] sendMessage -> [engine] "done, give me next tile"
...

Because the code isn't tied to the visuals, the code in 2 can be executed, but the visuals from the animation might start on the next frame, hence the container is moved to the next tile, but the animation is still on the last frame (at the and of the track) ...

... I ended up coding the movement in the end ...

Editor scripts can do a lot of damage (or just be utterly helpfull)

In order to get the levels into the game I needed an level editor, but was too lazy to write one - so I decided to dig into editor scripts in Unity, which allow you to do all kind of dangerous things.
I wanted to be able to drag my level into the Unity editor window, grab it and save it to a file (which works just wonderfull). the first big "shit" came when I added a function to clear the level from screen (so I could do a new level) and carelessly allowed "DestroyImmediate" to delete from the asset window (and not checking if the GameObject I want to destroy is a child of my Playground) - oh well.

Anyway, you can easily add you own menu entries, access files or manipulate your current scenes with editor scripts.

And now some screenies ...

Project Hellstrom

hellstrom_00.jpg
The ponytailed lady is just my scaler model, in the end I guess it'll be 1st person.
Right now you can walk around a dynamic generated map (with temp mapping) - A LOT of work left to do.


ToyGame - the game without a name yet

toygame_00.jpg
Inside Unity's editor, the first level in progress ...

toygame_01.jpg
Playing level 1, just crashed 2 toys ...

And with this I descent back into the hell that is js/css and html ...

nGFX





The good things in life aren't for free ...

Let's start with a little rant.

So there are all these shiny things you can do with css, alas they might not work in all the browsers, knowing what works (or to know how to fake/correct it) is for me some sort of art form. I'm not even talking about the possibilites of JS and DOM based development.
But I do believe that there is something utterly wrong with css in parts if there are people out there (thanks guys) who devote a damn good deal of time to write bloody FRAMEWORKS so that you can do something as trivial as a 3 colum layout. It gets worse if you want a header and a footer - alas not a footer that is always BELOW each of the 3 columns and not just the main column).

I needed to get that out.

What else? Ah the redesign - yet again - what first seemed a good idea, wasn't that good when done. Back to start then. (Meanwhile we just continue here.)

Speaking of things that seemed to be a good idea ...

Last time I wrote about the map format used for the current game (or that I'm thinking about it) the last one I had seemed to be a good idea too. I guess I can say that I was wrong :) .

My first idea was to a tilebased map and to create it from the dungeon data I've got out of the dungeon creation code. Basically I wanted to convert each cell into an 6x6 piece of tiles, so there could have been a wall 1 tile wide and so on.
This worked quite well until I had the idea that I don't need a tile based map at all and just could plot the floor of a cell in one go (as for the new idea I don't needed walls in the tiles) - this worked also quite well.

I could reduce the code needed to convert the dungeon by some 75% - and was quite please with the outcome as it was also quite fast, the scroller needed to plot less tiles and everybody was happy, I used simple vector math for wall/door/trigger collision tests. Untill ...

While recoding the converter there was a nagging feeling that I forgot something, that I *needed* the tile information for something and right just as I finished the converter I dwaned on my why I wanted to use them in the first place - pathfinding.

Darn.

I know I could use nodebased pathfinding or some other utterly clever method (I've got heaps of books about that) but honestly there is nothing as simple as a tilebased pathfinding ... so I'm adding a simple tile map info back in (using a bool map). Joy.

Well, good thzat I haven't just deleted the old code ...

nGFX

Dial Z for Zombie - dev diary

So after the set of articles about random level generation I wanted to put that into use (alas not in the scale I planed it out - mind you) - so I came up with a nice little 3 week project - that was 5 weeks ago.

The basic idea is a simple top/down shooter blended with a good portion of Gauntlet added (hordes of enemies, maybe). And while it's fun to watch levels being created by code it involves a good deal of additional work, like changing the tilesets, adding dirt and stains.

The X entries seemed to be a good idea, so I'm going to publish a few wip builds soon, too (alas not as many as Squize).

In order to see something at all (except the test visuals from the article tests) I needed to convert the cell based dungeons into someting tile based, and write a simple scroller to display the created maps. I decided that each cell should consist of 6 by 6 tiles, so I could use a one tile wide border for the walls (if any) and still have 4 tiles walking space. Next point on the list was the question about how to store the data generated - as I didn't wanted to convert cells/tiles at runtime before they're being displayed. Storing them in an array seemed a good idea, but I wanted to try something new...

Not to mention that converting 50x50 cell dungeon would result in an 300x300 array.

After a few minutes I thought that using BitmapData would be a nice try to store the map, as it'll give me a quite quick direct access 3 dim array (x,y, R,G,B,A) which I could use multiple times. so I used the alpha chanel for the tileset, the red one for the actual tile, blue for pathfinding and green for effects/2nd layer.

Right, why storing a tileset?

In my idea each room has basically the same tiles (ie. walls, doors, corners and floor) and the conversion would be much easier if I would use the same tiles over and over. So I came up with storing tiles in tilesets, which offsets the tiles on the tilesheet.
The creation process is quite easy this way:

First I have to create a tileset and give it a name, say "Corridor".

myTileset = new Tileset("Corridor");

Then add tiles to that tileset, giving it a name and and x/y offset in the tilesheet (I wrote data class for that):

myTileset.addTile(new Tile("empty", 0, 0));
myTileset.addTile(new Tile("Floor00", 1, 0));
myTileset.addTile(new Tile("WallN", 0, 1));
myTileset.addTile(new Tile("CornerInN", 1, 1));


Internally I use the tile's index, but the cell/tile converter just uses the name:

if (!myCell.isUnused) {
                        
    iTile = myTileset.index(strFloor);
    iPath = 0
    iSpecial = 0;
    bmpdMap.fillRect(new Rectangle(xx, yy, iTilesPerCell, iTilesPerCell), this.rgba(iTile, iSpecial, iPath, iTileset));
    
    // walls
    for (i = 0; i < Dir.NUM_BASEDIR; i++) {
        
        if (!myCell.isOpen(i)) {
            cx = xx + aWall[i].x;
            cy = yy + aWall[i].y;
            
            iTile = myTileset.index("Wall" + Dir.shortName(i));
            iPath = 255;    // so you can't walk there (for the bool map pathfinding)
            iSpecial = 0;
            bmpdMap.fillRect(new Rectangle(cx, cy, aWall[i].width, aWall[i].height), this.rgba(iTile, iSpecial, iPath, iTileset));
            
            // door
            if (myCell.hasDoor(i)) {
                
                // door frames are painted "above" the floor, so I use the special layer for that
                iTile = myTileset.index(strFloor);
                iPath = 127;
                iSpecial = myTileset.index("Door" + Dir.shortName(i) + "0");
                bmpdMap.setPixel(cx + aDoor[i][0].x, cy + aDoor[i][0].y, this.rgba(iTile, iSpecial, iPath, iTileset));
                
                iSpecial = myTileset.index("Door" + Dir.shortName(i) + "1");
                bmpdMap.setPixel(cx + aDoor[i][1].x, cy + aDoor[i][1].y, this.rgba(iTile, iSpecial, iPath, iTileset));
                
            } // ToDo: add windows if possible ...
            
        }
        
    }
    
    // ... draw corner and outer coners [skipped]
}

Ah. Nice and easy :)

So by using a different tileset you can easily control the visuals of a room.

Next thing on the list: the scroller - more thinking here ...

I wrote the Scroller class as extension to Sprite so I could add my own sprites and use the Sprites scrollrect for clipping. Adding a Scoller to the stage became easy as 123:

this._Scroller = new Scroller(620, 460, 20, 20); // width, height, tilewidth and tileheight
this._Scroller.name = "scroller";
this._Scroller.x = 10;
this._Scroller.y = 10;

this.addChild(this._Scroller);

this._Scroller.setTileset(this._bmpdTileset, this._TilesetCollection);
this._Scroller.setMap(this._bmpdMap); // the freshly generated map
this._Scroller.setCenter(310, 230);   // alows offsettin the origin, so 0,0 can be at the center of the scroller

this._Scroller.xPos = 0;
this._Scroller.yPos = 0;
this._Scroller.draw();
// updates the visuals of the scroller

the way the scroller is set up (I still need to optimize redrawing, though) makes it possible to use it with tween utils like TweenLite:
TweenLite.to(this._Scroller, 1, [xPos: 100, yPos: 100, onUpdate: this._Scroller.draw});

So after a few days of coding it looks like this:
DialZ_pre_00_small.jpg
(scaled version)

The visibilty test is in place (you can only see the room you're currently in and vector boundaries are created (the green rect in the room, door triggers (blue rect)). The map in the left corner is shwoing the pathfinding bounds (helpfull for testing, too) and will be replaced by a minimap later (circular, hopefully).

Right now I'm writing the vector intersection methods (I'm using math instead of the tiledate for collisions) - so I thing the next entry will feature that.

nGFX