July Treasure Tomb Development Diary

27 June 2007

I have decided to keep a diary of the Treasure Tomb development for posterity, like the Alien Flux one before it somewhere on the javagaming.org forums. It might be an amusing read for you, or enlightening. Mostly though, it’s my public trail of shame. Can’t quit on this game if you have to see a daily progress, eh?

So: where are we with development for starters?

With the guts of Monster Mash ripped out and a quick package name refactor, I’ve got a basic game framework set up in Eclipse that launches and has a title screen, register screen, nag screen, hiscores screen, options screen, help screen, and credits screen. Of course all of the graphics and layouts are from Monster Mash (I just scribble over the top of the title with “TREASURE TOMB” using the Gimp) and it’s for Chaz to sort out later. But there we have it – the cradle in which a game sits.

Currently tapping M on the title screen brings us to the Map Editor. I’ve decided to do the editor completely before I do any game development, as it’s by far and away the most work involved in this project.

The map in this game is rather big. 1024×1024 tiles, to be precise, which is a lot to fit in memory at any one time when you also consider that each tile may also have an item on it (like a munchable dot, or a jewel, or monster spawner). Not only that but some of the map squares have special actions associated with them: teleports have a destination; script tiles fire off a “script”; and switches fire off a sequence of changes to the map. Furthermore, in the editor, we want to be able to turn switches on and off and see which tiles have been affected on the screen with some sort of indicator.

Were I to implement that naively and have each coordinate on the map represented by, say, some TileInfo class which contained the floor tile, item tile, any special action, and a flag, I’d need to create an array of 1,048,576 of them, and each one would take up 8 bytes overhead and 16 bytes of object data. That’s 24 megs! Not to mention the 4mb just for the array pointing at them. I don’t really fancy using half of my entire heap just to store the ingame map – not to mention the fact it’d make serialization slow and probably very bulky – so I’ve already decided to optimise this data structure.

The map now consists of two short[] arrays which point at indexed Tile instances; that’s the floor and item layers. Now it only takes 4 megs for the entire tile storage. There’s another 4 megs that points at optional ExtendedInfo instances – so mostly null. An ExtendedInfo, when present, is where I can bung everything else when necessary, like tile actions, flags, etc. So that’s more or less got map storage down to just over 8 megs, much better. And serialization will be lightning fast.

The editor is proving extremely difficult to write because I’m doing it properly – one of the most important things I’ve implemented is a multiple undo feature. This is quite tricky to implement especially when drawing one tile can affect its four neighbours (the wall tiles automatically adjust to get the edges right). But it works! Hurrah.

Also implemented is setting Teleports and destinations – just to test that part was working ok.

Tomorrow comes the much more extremely difficult design and implementation of the switch editor. Why so difficult, you ask? Well, firstly, because I want to be able to undo switch edits. And secondly because I want to be able to flip switches in the editor – both on and off. In the game, they cannot be flipped off. However, they can be flipped in any order, and the bit which recalculates walls has to be able to cope. And Undo. Gah. It’s making my brain hurt just thinking about it.

28 June 2007

All right, I wussed out on doing the horribly difficult switch editor coding and instead implemented cut, copy, and paste functions with some delightfully poorly drawn icons. And it all works properly with Undo as well which is nice. Nice use of glLineStipple here to draw the animated selection rectangle.

Also in is scrolling if the mouse is attempted to move beyond the edges of the screen. I think the last two things I’ll bother putting in today are wiring up Ctrl-X/C/V for the cut, copy and paste functions, and scrolling the minimap. The game map is so big it won’t even fit on the screen when in minimap mode! In fact the minimap is still 7×7 big – blimey. Hopefully should be able to fit in a lot of adventurin’ in there 🙂

Chaz is working on the new website at the mo so he hasn’t done any new graphics yet for the game.

29 June 2007

So all the Ctrl-X/C/V stuff is wired in now (and Ctrl-Z for undo). I don’t know why I didn’t put it in before, but it’s now in my base class library, and I can now wire up any key combination to any GUI element, like in a more traditional sort of GUI framework.

Did some more tweakage in the editor.

30 June 2007

Nursing a bastard between the eyes today from a colossal lager binge last night out in Durham with my pseudocousin Amy, I decided to avoid doing anything especially difficult and instead work on the “adventure scripting” part of the game.

Every now and again you will have to solve some sort of adventure style puzzle in the game – this will usually involve doing some sort of little mini-quest to find some item and take it somewhere, or perhaps discover the letters to a secret code to unlock something, or whatever. To this end, I’ve got a Script class which contains a number of States. Each State has a block of text which I’ll display on the screen and a number of Choices, and each Choice will do one thing such as set some state variable, give or take an item from the player’s inventory, or allow the player to input some text.

When a Script gets “executed”, I’ll scan through the States to find the first one that matches the player’s inventory and start there. Then every time they make a choice I’ll do the same thing again against their inventory and any internal state set (just a Map of key-value string pairs basically). I think that’ll be complicated enough for my needs.

In more classical hard-work-avoidance I knocked up a screen to let me type in a script ID when a script tile is placed. Tweaked my screen handling system so that I can now designate a screen as a “dialog”, which just draws it on top of any existing screen but disables all its buttons etc. Don’t know why I didn’t do that a long time ago.

2 July 2007

Continuing along with the theme of avoiding hard things to do, I put minimap scrolling in this morning. You can drag the minimap around with the right mouse button, and also you can scroll the aperture around with the cursor keys and if you try to go off the edge of the screen it scrolls the minimap instead. Nice and easy, but still took me an hour to do for some reason. I think I am just horribly slow.

Chaz has just finished updating the website with a new super-retro look as we further consolidate our image and brand of pixelly goodness. Gone is the Puppyinvaders applet, which we suspect caused a lot more trouble for people than it was worth (slow page loading, crashes, etc). This means he’s free to start doing game graphics, so he’s started on doing the little icons for the toolbar in the editor.

Oh by the way, Tomas Andrle of Catnap Games has just released an updated version of Devastro, a LWJGL+Java game reminiscent of Cannon Fodder. We’ll be putting a front page link to Devastro on our front page shortly, because we like it! In fact I think it might be the third only studio to have released a LWJGL game other than Puppygames and Oddlabs.

Added information into extended tile info to show that a tile is a teleport destination. I store a List of Points which are the locations of the teleport tiles that can take you to a particular tile. Now the editor draws red lines between teleports and their destinations.

Started on the switch editing part of the map editor now finally, the Really Hard Bit. First stop is to make tiles that are currently “transient” – ie. changes made by switches being toggled on – visible with a glowing border around them so you can see they’re not actually part of the base map.

3 July 2007

Found this morning that Chaz has completely done all the GUI widgets for the editor, and it looks really slick and nice now. Hey, I might even show you a screenshot!

Put in compression to the MapStorage class when it’s serialized. A saved map on disk was 5MB; now it’s 5KB. Of course that’ll grow somewhat as we actually design some real maps. In case you want to know how that’s done:

/** * Override standard object writing so we can gzip the stream for MapStorage * @param stream * @throws IOException */ private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); GZIPOutputStream gzos = new GZIPOutputStream(stream); ObjectOutputStream oos = new ObjectOutputStream(gzos); oos.writeObject(map); oos.flush(); gzos.finish(); } /** * Override standard objecr reading to read the zipped MapStorage * @param stream * @throws IOException * @throws ClassNotFoundException */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); GZIPInputStream gzis = new GZIPInputStream(stream); ObjectInputStream ois = new ObjectInputStream(gzis); map = (MapStorage) ois.readObject(); }Those two methods are in the GameMap class, which implements all the required functionality to edit the map and play the game. The actual map data is held in a class called MapStorage in a transient member variable called map. You have to make it transient otherwise stream.defaultWriteObject() will write it as normal. MapStorage extends another class called MapClip which only contains the tile layers – MapStorage contains all the aforementioned ExtendedInfo stuff.

Massive refactoring operation today. All the code was piled in ever more fiddly nested inner classes inside the editor screen. Now I’ve broken it all out. It’s a little tider and easier to navigate. Technically totally unnecessary, but I just felt like doing it. I’m not entirely happy with the code design even now but this is an operation in making money rather than making elegant code. The only reason I refactored it in the first place is because we know we’re going to be using this map editing tool again and I want it to be easy to rip out and fiddle with.

Did a few other tweaks at Chaz’s behest. All in all quite a good day.

4 July 2007

Finally took the bull by the horns tackled switch editing. Why does everyone else find this stuff so easy? Not much to report, except it works! I am so l33t etc etc. The switch changes are highlighted by glowing red boxes round the affected tiles. You can toggle switches on and off in normal draw mode at any time and in any order. This will make it easy for me to create some fiendish tile logic puzzles.

I’ll spend the rest of the day tidying things up and then make meself dinner. In particular a few things need attending to such as:

  • Set the map start point, where the player beams in at the start of a brand new game
  • Yes/No/Cancel “Would you like to save changes?” dialog when quitting the editor if dirtied or attempting to load a map
  • I think I need to have the ability to create “permanent entities” on the map – ie. a gidrah that lies dormant until made visible, then which doesn’t go away until destroyed. I can’t be bothered to do it yet, because Chaz hasn’t drawn me any gidrah sprites so far, but it won’t be hard to put in.

The new Eclipse 3.3 I’m using misbehaved twice today, crashing after a couple of 100% CPU stints and exiting without warning. Grr.

5 July 2007

Done:

  • Confirmation dialog on attempting to quit dirty editor. Created a new DialogScreen general screen sort of class with variably visible OK, CANCEL, YES and NO buttons on it and a title and message box. Might well come in handy elsewhere.
  • Fixed a pair of crash bugs in the editor when trying to edit switches
  • Start point now set when you place the Start tile. Previous Start tile is automatically removed. I did this by adding an onDraw(map, x, y) method to the Tile class, called whenever a Tile is drawn on the map. The only Tile to override this method is the Start tile. I can’t tell really whether it would be better design to “hack” it or whether this nice neat object-orientated method is nicer.
  • You can no longer draw on a two-tile border around the entire map, which prevents a small glitch with wall calculation from occurring.

We can now start doing the exciting stuff and actually writing the game! Chaz has sent me a little test gidrah that can animate movement in four directions, and I’ll just use that to test the player with, along with a bullet from Ultratron.

So: the player spawns, flashes for a couple of seconds invulnerability, and… jerks around the screen like it’s got electrodes stuck to its feet. But only… sometimes. How curious. I move the little guy around and sometimes it does it, sometimes it doesn’t. Eventually I notice it only seems to do it for a little bit just after he spawns. Then I notice that it comes back again after a while. Most perplexing.

A few System.out.printlns() reveal this bit of code in the MapRenderer (which draws the tiles) to be the culprit:

// Determine the offset in pixels int ox = x & 31; int oy = y & 31;

This works fine in the editor, and indeed, for all positive values of x and y, but in the very bottom left corner of the map, where I’m spawning the player right now, the bottom left corner of what’s being rendered falls into negative coordinates and the & operator doesn’t quite work as expected! Easily fixed:

// Determine the offset in pixels int ox = x % 32; int oy = y % 32;

Yay! A game is born! I put player bullets in too, so you can run around shooting. I tried to add a particle trail to the bullets – just for the hell of it, it looks awful because I’ve got no particle sprites and Chaz is the particle monkey – but discovered a horrible problem. When the map scrolls, the particles stay where they are on the screen! Curses!

The thing is, the map doesn’t actually scroll as such, it’s just told to render from a different origin. All the entities on the map just position their sprites relative to that origin like this:

screenX = mapX - TreasureTomb.getGameState().getPlayer().getMapX() + SCREEN_OFFSET + offsetX; screenY = mapY - TreasureTomb.getGameState().getPlayer().getMapY() + SCREEN_OFFSET + offsetY;where SCREEN_OFFSET accounts for the fact that there’s 10 tiles fits on a screen so I offset everything by 16 pixels so there’s an actual middle tile where the player is. The player is always the first entity to get ticked, so all the other entities choose screen locations relative to the player.

Except of course, the particles don’t, because they’re generic particles from my other games. Bugger. I’ll have to sleep on the problem. It can’t be hard to fix, but I don’t want to hack it if I can help it.

6 July 2007

All the player movement is in now, and absolutely perfect it is too. I’ve also nipped out and finally bought a gamepad and wired that in – much better! Must get round to putting it into Titan Attacks and Ultratron too.

I’ve put in a little shower of sparks when the player’s bullets strikes a wall, and ripped a couple of sound effects out of Ultratron for now (might even keep them – I like ’em). I’ve also fixed the particle problem (and all of the special effects) by adding a setOffset() method to the Effect base class. This takes a ReadablePoint which every frame I update with the offset required to get things to display on the screen in the right place. One last niggle remains, that everything lags behind the scrolling by one frame.

Chaz has discovered that old problem with premultiplied alpha in PNGs coming to haunt us again – around the edges of some of his more subtly glowing sprites there’s a nasty fringe. We’re trying to figure out how to get rid of it as I type. He’s done a few more proper tiles too. Nearly ready for a screenshot! Maybe tomorrow.

Oh, and another thing: Chaz was complaining that all his sprites looked crap in the game. He showed me a screenshot and sure enough they did indeed look crap. Fortunately I recognised the symptoms – texture compression! I don’t use texture compression in my games because it generally looks a bit wrong for most of our smoothly drawn 2D stuff, but Chaz had accidentally overridden the settings in his control panel to use “Maximum Performance”. So: beware! If you think our graphics look a bit naff, maybe you’ve set this too.

Also done:

  • Eating dots!
  • Eating jewels! Except there’s no gidrahs to pause yet (when you eat a jewel, the gidrahs stop moving for a few seconds)
  • Picking up keys and using them in locks
  • Teleporting
  • Flicking switches
  • Arrows – stand on these and you get whisked off in the direction they’re pointing

7 July 2007

Chaz has produced a player sprite which is pretty cute, but a little dark. Might have to brighten it up a bit.

At last, the gidrahs live! The spawner tiles now churn out a regular stream of particulary stupid and cute little robots for the player to blast. It feels like a complete game now. Right now they have absolutely no brains whatsoever but I have been researching Pac-Man ghost AI and there are four brains to choose from. My “research”* led me here. Seeing as I’m on a bit of a roll tonight I sat up until the wee hours coding three brains for the gidrahs. The HomingBrain is like Blinky, and attempts to home in vertically first, then horizontally on the player. The AmbushBrain is like Pinky, and is essentially a HomingBrain that attempts to home in on the location four squares in front of the player. Chaz will be surprised when he syncs tomorrow!

As the game progresses, I want it to get a bit more frantic and challenging. To this end, there’s the notion of the game’s current “level”. The game itself is played on one enormous map so there aren’t actually any levels like in Ultratron or Titan for me to get this value from. Instead, I’m going to tune it to being the number of treasures that the player has collected, and one or two other variables.

Little things done:

  • Wired in a bunch of sound effects for little events like eating dots, etc. Game feels more “complete” with sound.
  • Put little bonus labels in when you score points
  • Put the “bravery” meter in. When you move, you get more bravery points, which in turn leads to more points when you shoot a gidrah – up to 50 points each kill. If you sit still, your bravery drops to zero, at which point you earn nothing for shooting the gidrahs.
  • Started attempting to fix the particle lag by giving all the tickable things a tick() method and then calling another method, update(), to update their sprite locations separately

* Everyone knows that “research” these days means Googling

8 July 2007

Played a bit of Time Bandit again today on STeeM, the Atari ST emulator. I noticed that the player is not always fixed in the centre of the screen as it is in my game. You move up to two spaces in the direction you’re heading. Unfortunately this means you can see even less of what’s coming up! I think I’m going to try some experiments with the view position so that the player can see more of what’s coming up rather than less.

I tuned joypad axis control as well so that it’s a little less sensitive to diagonals. Here’s the code:

float yAxis = controller.getAxisValue(1); float xAxis = controller.getAxisValue(0); upDown |= yAxis < = -0.5f; downDown |= yAxis >= 0.5f; rightDown |= xAxis >= 0.5f; leftDown |= xAxis < = -0.5f; // Tune diagonals if ((upDown || downDown) && (leftDown || rightDown)) { float dist = xAxis * xAxis + yAxis * yAxis; if (dist < 1.0f) { // Don't allow diagonal. if (Math.abs(xAxis) > Math.abs(yAxis)) { upDown = false; downDown = false; } else { leftDown = false; rightDown = false; } } }

It can be tuned by tweaking that 1.0f value in there. Seems to have made it slightly better to control. However, the controls still feel rather sensitive. I think I shall implement a small delay in starting moving from a standstill – really small, like 2 frames, and see how that feels.

Screenshots are imminent. Just got to get Chaz to do the HUD.

Charlotte tried to add me as a “friend” on Facebook. LOL. As if.

  • Fixed a bug in the map renderer which caused strange tiles to appear out of nowhere.
  • Added teleport beam out and beam in sounds. Also give the player 2 seconds of immunity when teleporting.

9 July 2007

Finally settled on 4 frames before initiating movement from a standstill. Tuned that diagonal joypad axis detection variable to 2.0f. I tried having it so the player viewpoint shifts slightly over time to show you up to two squares further in the direction you are moving, but it feels a little unnatural, so I’ve commented it out.

The big issue facing us today is the amount of screen that’s visible. With 32×32 pixel tiles, the map visible on the screen is only 10×10 tiles, which makes the game feel rather claustrophobic. It’s only a square smaller than the original Time Bandit but having played that again yesterday… well, that game feels claustrophobic as well. Plus Time Bandit doesn’t have nearly so many puzzles in it, and the complexity of our puzzles is largely limited by what we can fit on the screen.

So I tried changing the game to 480×480 resolution so we could have 15×15 tiles onscreen. Better, but now all the GUIs are out of whack and it doesn’t quite fit the feel of Ultratron or Titan Attacks. The only other option is to make the sprites and tiles all 24×24 pixels wide which would give us a viewable map area of 13×13 or so but I don’t think Chaz can be arsed to redo all the work he’s done all ready so that’s probably out of the question. So sod it, 320×320 it stays.

Anyway: I want some opinions about the “feel” of the game so far… so whack this Webstart link to launch the game! I’ll keep the Webstart updated daily (well, nightly) so you can check out the progress until we get to “beta” stage at which point it goes into closed testing with the Select Few. TODO tomorrow

  • Confirm delete switch/teleport/script
  • When editing switches don’t record unnecessary events
  • Death (got something special planned for this)
  • Game Over
  • Particles when hurt
  • Powerups

10 July 2007

Took my mum to the seaside today (Whitby) – on the bike, haha! It’s so big she can’t get off it without assistance. So anyway, a good time was had by all, but rather less work done than usual.

Chaz has done the HUD, which looks nice. Doesn’t need too much more tweaking, but I’m going to adjust the font size a bit. Surprise surprise, he is none too enamoured of my gidrah death “animation” so I will be twiddling with that for him.

Did crappy programmer art for the powerups, wired in the code (mostly don’t actually do anything yet), pinched sound effects from Super Dudester for now.

Found a bug in switch change code that meant after fiddling with the tiles.xml file, sometimes the stuff the switches drew got corrupted. Unfortunately the fix broke serialization so the test map is buggered and I’ll have to do another one. Still, I’m glad I found it now, and not after 2 months of map-wrangling.

11 July 2007

Found yet another switch change bug that meant my saved map was buggered once again. Most annoying – still, glad I found it now.

Chaz has done half of the “rating” animations in the HUD (pathetic, cowardly, timid, etc). and I’ve got a preliminary angel for the death sequence. When youy die, a little angel flies out of your body, leaving you as a ghost. You’ve got 30 seconds to earn an extra health dit (by scoring 1,000 points) to resurrect yourself.

At this point the ghost player is just a white alpha’d version of the real sprite and it doesn’t look too interesting, so we’ll probably have that redone at some point. Also, I’m not sure whether to make it so you can just float through gidrahs or not when you’re a ghost. It makes resurrection somewhat easier, which is important for our market. Nobody likes really hard games any more! The original Time Bandit is absolutely unforgiving in this regard. That’s probably why it’s got a multiple slot save game feature. I wonder if I’ll have to implement the same thing in this game.

Game Over is now in as well so fortunately the game finishes when you die properly (ie. when you fail to resurrect yourself in time).

Done:

  • Psychotic powerup, which turns you psychotic and gives you ultra zappy lasers for 15 seconds
  • Invulnerability powerup, which does what it says on the tin, for 15 seconds
  • Extra Health powerup, just gives you a free health dit
  • Ghost powerup, turns you into a ghost temporarily
  • Freeze powerup, freezes all the monsters for 15 seconds

Haven’t done the gobbler powerup – this one turns all the monsters into edible treats so you can just run around eating them for points. Think I need to do some more monster AIs, or tweak the existing ones. Question: do I prevent monsters from walking over each other or just leave it the way it is?

While Chaz slumbers I will do more odds and sods. There is a new build up for playing with. Not much in the map this time since I lost the last one. Er, might need to clear your caches.

12 July 2007

Chaz has redone the sprites for the psychotic powerup (now distinguished from the maximum bravery rating, which is now called “BEZERK”), and also the sprites for the angel which now flap, and the ghost sprite too. Still need a “death” and “resurrection” animation.

I’ve added a little animation for when you earn an extra health dit – it flies from the screen where you earned it and lands on the health dit-o-meter on the left. Lovely but pointless.

Had a bit of an amusing bug once the player had died. What we’ve done, is when the player dies, he becomes a ghost and has to run around as outlined yesterday. Now we’ve decided that to resurrect you don’t have to score 1000 points, you simply need to collect a jewel. When you resurrect now, the screen flips back to where your body lies and the angel drops back into you. This is quite a cool mechanism – I can create puzzles which involve you having to actually die so that you can walk through an otherwise impassable obstacle tile to step on a switch and then collect a jewel to return to your body! Anyway – if you stepped on a teleport, when you rematerialised it unfortunately always rematerialises you in PHASE_ALIVE state – not so handy when you’re meant to be in PHASE_GHOST state. Easily fixed.

Also, prevented the player from moving onto an arrow tile that would immediately move you back again – it was just annoying to do that.

I’ve just realised that we’ve done over 50% of the coding on this game already, in about 4 weeks flat. Another 4 weeks at this rate and all the coding will be done, it’ll just be the long, hard slog drawing the giant world map and inventing puzzles and scripty adventure bits…

Latest build is up. See what you think of “death” in game now. You can practise dying by tapping Z repeatedly to kill yourself.

13 July 2007

Eclipse 3.3 crashes fairly regularly on me these days. Bah. I hope they get a patched one out soon, as it’s beginning to get annoying. At least I assume it’s Eclipse. I’m using JDK6.0.1 with the server VM to run it.

Death and resurrection animation is in, and look nice. There’s a little gravestone pops up!

Spent the afternoon coding in gun turrets. These are destructible gun turrets that face in one direction and fire at a rate determined by the difficulty level. The way they’re wired into the game is similar to spawning tiles; that is, the game state has a listener in the tile renderer that watches out for turrets that come into view. Turret tiles themselves are blank; the listener spawns a Turret entity at that spot and remembers it. The turret entity takes care of removing itself if it’s too far away from the player. Sorted.

This also means I had to code in enemy bullets finally. The code looks uncannily like the player bullet code, haha. Pinched another bullet sprite from Ultratron.

I am toying with the idea of adding laser turrets, and mirrors. You know, the sort of puzzles that involve flipping mirrors to turn lasers around and blow things up etc. That might be fun. It’d probably only be applicable in the hi-tech worlds though. Mind you, so will the turrets I expect. I’ll have to think of some other stuff to go in the low-tech worlds.

Chaz has done the powerup tiles, which look lovely. They will be in different colour schemes for the other tilesets. I made them wobble with a bit of XML trickery.

There was a strange problem with gidrahs – and, it seems, turrets – being destroyed but then springing back to life as phantoms. They moved around as normal and look otherwise perfectly healthy… they just won’t collide with anything or die. Turns out this was due to a concurrent modification to an ArrayList. Being paranoid as I am about producing garbage I tend not to use Iterators, and this is the price I pay 🙁 Anyway, fixed it and all is well with the world.

Right, knocking off early tonight after only 7 hours coding. Thank Crunchie it’s Friday. Going to a Japanese restaurant in Durham. The chef there does this crazy thing with knives and condiments in front of you which make you retract your fingers for fear of losing them. He also throws a lot of eggs in the air. A great spectacle and delicious food for all, I should hope.

Latest build is up as ever. Whether the mysteries of the Webstart cache allow you to just hit that link to try it is another matter.

16 July 2007

Today I decided that I want to implement pushable crates. One laughably poor programmer-drawn sprite later, I wire it into the game and realise that a Big Refactor is needed.

The thing about crates is they’re actually entities, not tiles – rather like turrets. Then I realised that I might want to place gidrahs on the map too. So I changed all the mechanism for doing that; now they are effectively “blank items”. When first drawn on the screen by the map renderer when the game is running, they spawn the appropriate entity at that location and then perform the Kevorkian operation of removing themselves, so that tile will never spawn an entity again.

However, buried within my entity code was a bit of code to automatically remove entities when they got too far offscreen – otherwise we’d have thousands upon thousands of them left lying all over the place and as the collision detection algorithm slows down with the square of the number of entities, that’d be bad. So I’ve got another flag in the Entity class, “permanent”, which says that this entity should not be removed when it’s too far off the screen. Instead what happens to permanent entities is they are removed as normal, but placed into a “dormant” list of entities using a HashMap of Points to ArrayLists. Each Point corresponds to the entity’s tile coordinates divided by some rough divisor (15 in this case), and each array list contains all the dormant entities in that sector of the map. Every 15 frames or so I check the sectors all around the player (9 of them) and revive any dormant entities I find (and clear that bit of the hashmap out to recover RAM). Neat.

The next big thing I’ve done today was try to implement “crates” that you can push around to solve Sokoban-style puzzles. This was surprisingly complicated and took about 3 hours to do, and involved another big refactor but the code is quite nifty now. The main issues were that because crates don’t exist on the map, the code that let the player move or the gidrahs move around wasn’t actually able to see them, so I had to implement a check through all the active entities to see if said player or gidrah was attempting to move into the grid square where a crate was. Anyway, to cut a long story short, it works, and the gidrahs can’t push the crates but the player can. The crates also propel themselves along on arrows which is fun, and activate switches when they’re moved onto them.

Pushable crates pose a game design problem which was on the back of my mind and which I didn’t really think too hard about (because crates are a “cool feature” so I was determined to implement them). That is the problem that the player can irretrievably fuck up the map by pushing a crate somewhere it won’t come out of. For example, they block access to a key, or a corridor. Or even onto a switch which they might need to toggle back. I’m really not sure how to fix this problem yet. Currently as a ghost the player can walk right through crates but that sort of relies on your ability to be a ghost on a whimsy. Maybe I’ll just have to be bloody careful with level design. I suppose I can mitigate it by keeping crate usage to a minimum, and having special tiles that crates can’t be pushed over.

Eclipse annoying me frequently now. Also there is a strange bug in SWT that allows it to grab the mouse from behind a LWJGL window which has itself grabbed the mouse. Occasionally I randomly select chunks of code in Eclipse when drawing in the map editor. Most irritating.

17 July 2007

Chaz has gone and redone all of the graphics! I keep on telling him to put in less effort but he never listens.

You might have noticed, if you’ve played the Webstart alpha, that the gidrahs keep on spontaneously combusting. This is something to do with the “squish detection” – that is, when a gidrah suddenly finds a wall has been dropped on it by a switch. Unfortunately it’s gone a bit haywire and they just sort of… explode randomly. No idea why yet.

Also, for some unknown reason, the game starts on some computers but without a player. Again, this is bafflingly non-deterministic.

Didn’t do much today otherwise. Fiddled with the turrets so they shoot in the right direction now. Will spend the evening finding out why the gidrahs are exploding and what might make the player fail to materialise.

Have thought of a solution to the crate problem: crate reset switches. Might work. Will think about that some more.

18 July 2007

Ok, discovered what was going on. It’s a little obscure. It’s buried in a bit of SPGL code, in an Interpolator. To move my gidrahs, they have a start coordinate and an end coordinate, and a move duration and tick. They smoothly interpolate between the start and end based on the tick using a LinearInterpolator, thusly:

if (moveTick > 0) { moveTick --; float ratio = moveTick / (float) moveDuration; setLocation ( (int) LinearInterpolator.instance.interpolate(tx, sx, ratio), (int) LinearInterpolator.instance.interpolate(ty, sy, ratio) ); }

How, you wonder, could this possibly go wrong? Well, let’s take a look at the LinearInterpolator code:

public float interpolate(float a, float b, float ratio) { if (ratio < 0.0f) { ratio = 0.0f; } else if (ratio > 1.0f) { ratio = 1.0f; } return a * (1f - ratio) + b * ratio; }

Looks like it couldn’t possibly go wrong, could it? And indeed, it probably wouldn’t if I were using doubles but I’m possibly foolishly using floats, and floating point numbers behave in all kinds of peculiar ways. The problem was occuring when a == b, for example, when the gidrah was walking south and the x coordinate was not changing, so we were interpolating effectively between two identical numbers.

Except, of course, when the curiousities of floating point maths says that a * (1f – ratio) + b * ratio != a, which it does occasionally now and again due to odd rounding errors. The resulting value, instead of say, 100, would be 99.999999, truncated to 99. The gidrah would think it was one space to the left, in the middle of a wall, and squish itself.

Fixed it like this:

public float interpolate(float a, float b, float ratio) { if (a == b) { return a; } if (ratio < 0.0f) { ratio = 0.0f; } else if (ratio > 1.0f) { ratio = 1.0f; } return a * (1f - ratio) + b * ratio; }

One of the gidrahs now shoots at you on sight. Makes the game very slightly harder!

Instead of doing any game coding today I've instead been working on tools! Our GUIs are defined in XML like this: (well, have a look through TreasureTomb.jar and see for yourself)

...Poor old Chaz has had to fiddle around with the XML for the last 3 or 4 games manually, tweaking a coordinate here, adjusting a size there, getting his GUIs to line up properly once he's drawn all the sprite for them. (I set up most of the initial XML manually). It takes him ages and ages and I've been very mean by not giving him a tool to do it with... until now!You can see the tool in action for yourself now by tapping F11 on any screen. You can drag the areas around (or use cursor keys), resize them (using left-shift and the cursor keys), reset the area's bounds to the sprite image size ('R' key), or finally and most usefully, tap X to write out the XML to the console ready to cut and paste back into the source code file. Neat. Tap F11 again to exit. This tool will probably save Chaz hours and hours and eventually days as we reuse this particular application framework a few more times.

Hopefully this will convince him to do the new title screen 🙂

I also fixed one or two bugs in the map editor. If you haven't yet tried the map editor, it's the 'M' key on the title screen that opens it up. I'm afraid right now you won't be able to play your maps, but it will save and load them. It writes a file called 'map.dat' to the current working directory though I'm not entirely sure where that will be on Webstart right now. I'll get a better interface on loading and saving at some point.

No new build up tonight, will put one up tomorrow most likely. Must tackle "script tiles" tomorrow. Bah.

19 July 2007

Did some more tool programming last night. I've now written Chaz an Animation Diddler to go along with the GUI Monkeyer and Particle Diddler. The Animation Diddler lets him tweak the XML in realtime and test out animations. That'll save him a ton of time too. In the process of doing that I more or less made the whole of SPGL's Resources stuff write itself as XML which could be handy in the future. One of these days I'd like to change the loading mechanism to SAX instead of DOM too so I can use a lightweight parser. Chaz has done a whole load of new tiles for the moonbase levels. There are a bewildering array of them. I think I'll just have to concentrate on the map layout and then maybe he can go around the floors putting nice little finishing touches down everywhere. We still need some decent ladders and holes to fall down, and the crate reset switch needs doing. Also we need some generic "obstacle scenery" - stuff that you can't move through unless you're a ghost. But other than that the moon base tiles are very much done. Chaz also did the "scared ghost sprites" for the gobbler powerup, which I wired in today. You can run around chasing the gidrahs and eat them for loads of points for about 8 seconds. He's provided 3 different colours but I think I'll stick to one colour per tileset for consistency. Someone moaned at me yesterday that movement was tilebased and not pixel based. I'm not quite sure what to do about that really. I liked it just fine in the original game which was tilebased. It's a pretty major undertaking to go changing it now of course. Also it would require diagonal movement to be put in the game. I'm not so sure it's a good idea. What do you think? Completely avoided doing any work on script tiles. Sun came out - which is a miracle it seems these days in the UK - so I took the opportunity to take Teazle for a long walk and then I went for a burn in the Dales up to a bleak farming community known as Rook Hope. Whereupon it started to rain again so I can hooning back as fast as I could. Lovely new gidrah explosions look good. See them for yourself.

20 July 2007

Well... what a day. The game has changed completely. But for the best. Before it was a Time Bandit rip off with all the flaws of the original Time Bandit. Now it's our own original game, Puppystyle. Yesterday as I said someone moaned bout me about the tilebased movement ('twas Michael of Rock Solid Games, coders of Darwin the Monkey and Inca Quest). Well, I fobbed him off for a bit but deep down I knew fundamentally he was right - tilebased movement is really a hangover from ancient limitations of older games. We can provide proper pixel freedom these days. So I ummed and ahhed over it in my sleep (which now seems to consist of dreaming about code) and in the morning I realised that I couldn't let it lie.

Making this game work with pixel based movement is hard. Actually it must be hard for anyone that does it. Hats off to everyone who's made it work, because it's taken me all day, and it's still not even half finished.

I've got most of the movement working ok. You can move without getting embedded in walls and you can step on things and pick them up and arrow tiles sort of work. You can slide along walls by trying to do a diagonal move. It keeps you facing in the first direction you moved in if you add a diagonal move. There are some things that still need to be fixed though, which are quite hard and I've drunk too much wine to get my tiny brain around them.

The first and most important thing is "slippery corners". If you attempt to walk north, say, into a corridor but you're a few pixels left of the entrance, you just stop dead unless you also do a bit of diagonal. Unfortunately to the player it just feels like the walls are sticky. So I need to detect this situation and slip the player in the right direction.
The second thing is if you step on an arrow, I think you need to be "sucked onto" the arrow tile before it starts moving you, that is, it must first align you with the grid parallel to its direction of movement. Right now, you get halfway onto an arrow tile and suddenly it shoots you along, and it doesn't quite feel right.

Oh and I haven't even started looking at crate pushing or turret collision yet. All that's got to change to cope. Bah.

The other big change I've put in today which does work perfectly and which I'm very happy with is the new auto-aiming. No longer do you have to line up with gidrahs to shoot them! You have an auto-aiming crosshair which tracks the nearest visible gidrah in your field-of-view and you fire directly at it. This does make the game rather easier but that was the whole point - it is a feature which makes the game so much more accessible to everyone. It does mean we need to spawn a few more gidrahs and I think some of them will develop hit points as well otherwise they really do just become cannon fodder of no importance. It also gives us a bit of scope to give the player more powerful guns as the game progresses. Probably the result of completing one of the little "quests".

There won't be a build for a few days until I get all the movement stuff working again...

21 July 2007

Went to bed, couldn't sleep, so got up and coded until 8am before exhaustion forced me to retire. What I managed to achieve though is:

  • Perfected the crosshair and aiming system. Added a field-of-view enhancement so that you can see gidrahs in a 90 degree arc in front of you plus a certain number of degrees either side. Crosshair now fades out and in when it has a target. When it's got no target it invisibly returns back to the player. I'm really happy with the system. Just need to make the gidrahs have a few hitpoints now because it's a little too easy. But then again, I'm testing "easiest" difficulty mode so perhaps I'm jumping the gun.
  • Slippery corners are in. If you're just over halfway by 1 pixel over a junction you'll be shimmied in the right direction to get through the corner. You should see the code for this! Horribly fiddly but ultimately not a particularly complex algorithm.
  • Arrow suction is in. Step on an arrow and it first sucks you into the middle of the arrow's direction of flow. Feels much better.
  • Diagonal player movement slowed down to 75% speed (3 pixels / frame instead of 4)
  • The gidrahs now shoot back again, and from any angle too. They use the same code the player uses to determine whether they can see the player: public boolean isFacingToward(int x, int y, int facing, double fov) { double xd = x - getMapX(); double yd = y - getMapY(); // Check quadrant with angle calc double angle = Math.toDegrees(Math.atan2(yd, xd)); if (angle < 0) { angle += 360; } switch (facing) { case Facing.NORTH: if (angle < 45.0 - fov || angle > 135.0 + fov) { return false; } break; case Facing.SOUTH: if (angle < 225.0 - fov || angle > 315.0 + fov) { return false; } break; case Facing.WEST: if (angle < 135.0 - fov || angle > 225.0 + fov) { return false; } break; case Facing.EAST: if (angle > 45.0 + fov && angle < 315.0 - fov) { return false; } break; default: break; } return true; }and we use Bresenham's line scanning algorithm to scan the map to see if there are any solid tiles in the way (ie. wall) (to save big garbage I use a single static Bresenham's instance for all entities. The joys of single-threaded programming :))

public boolean canSee(Entity e) { final int offset = MapRenderer.TILE_SIZE / 2; // Gets us to the middle of the tile GameMap map = TreasureTomb.getGameState().getMap(); BRESENHAM.plot(getMapX() + offset, getMapY() + offset, e.getMapX() + offset, e.getMapY() + offset); while (BRESENHAM.next()) { // Jump in several pixels at a time if (!BRESENHAM.next()) { return true; } if (!BRESENHAM.next()) { return true; } int x = BRESENHAM.getX() / MapRenderer.TILE_SIZE; int y = BRESENHAM.getY() / MapRenderer.TILE_SIZE; for (int z = 0; z < GameMap.LAYERS; z ++) { Tile tile = map.getTile(x, y, z); if (tile== null || tile.isSolid()) { return false; } } } return true; }

It has occurred to me that the shenanigans and hoops I've had to jump through in order to make pixel-based movement work on a tiled map are probably exactly the same shenanigans and hoops every other developer has had to jump through to make it work - you know, like sliding along walls when doing diagonal movement, unstickied corners, arrow tiles, etc. I expect my solution is convoluted and difficult to understand. I didn't really appreciate just how complex it all was to get it perfect. I mean, I could have just not bothered to get it perfect and left out unstickied corners and arrow suction but you'd just know it wasn't right and it would annoy you enough to dislike the game. So there we go, two whole days coding and I've still yet to get crate pushing working again. It looks horribly like I'm going to have to refactor crate and player code into a common base class because I think crates are going to need to move in exactly the same way as the player.

Some more features I want to add in to the game:

  • Ice. Like arrow tiles, except you simply carry on moving in the direction you started in and can't change it. Can create a few more puzzles with it.
  • Secrets. We're going to have a switch tile that is very difficult to spot, likely just be a single intermittently flashing pixel. What fun :)
  • Traps. Stand next to a trap tile and you'll get an indicator there's something scary next to you (they otherwise look like blank floor tiles). I expect they'll just be explosion traps that cause a point of damage.

Oh, and there's a new build up to play with. You'll find it's quite different to the last one...

22 July 2007

"Agile programming" seems to be all about periodically refactoring everything in order to move ahead to the next stage and get something working in a matter of weeks.

Of course, being a hardcore hacker, I refactor everything and expect it to work in a matter of days :) Today is a refactoring sort of day, nursing as I am another hangover from a drinking competition between myself and my pseudocoisin Amy last night. Neither of us lost but poor auntie Mel is terribly sick today. Worse luck, it's Bob Burroughs' 33rd birthday bash tonight in Newcastle and he's already booked Monday off work in anticipation of incredible sickness. Bob went to school with Chaz and me back in the 80's. Chaz went on to do arty stuff; Bob does musicy stuff. Bob might be doing some of the music and sound effects for Treasure Tomb.

Anyway, refactoring.

Not very exciting to read about unfortunately. But the gist of it is this: I realise that if the player is going to be pushing crates around, then the crates are going to need pixel based movement too. So all that code I put into the Player class is now going into an abstract base class called PixelBasedEntity and both Crate and Player will extend it. Thrilling stuff I know.

23 July 2007

The refactoring continues. I've perhaps unwisely made the gidrahs pixelbased too now. Many headaches. Player can't now walk through turrets which is good. Still no crate pushing or collision. Gidrahs keep getting stuck on each other. Bah. And this is after a night out with Bob. I don't feel too good.

Chaz has done me ladders and a hole, which are "teleports" except they are instantaneous (no beamout / beamin). Not many more tiles needed now for the moonbase tileset.

I've been thinking about the map, which is huge. I might have to outsource bits of it to the community.

24 July 2007

After what feels like the biggest refactoring operation ever, I've finally gotten crates to move correctly when pushed, and gidrahs to wander around without bumping into each other. Gidrahs no longer walk over each other and get stuck. One problem was that when they spawned on top of each other they couldn't move, so now I check that the spawner has no gidrah within a square of it.

I'm in two minds as to whether to make gidrahs obey floor arrows. Might be amusing. What do you think?

I've tweaked the way the player aims. Now, if you hold the fire button down and you get a lock on the nearest gidrah, that gidrah will remain locked on until it is destroyed or you release the fire button. The player can no longer shoot when a ghost either. Only fair.

Oh, and we've got exploding crates now! Yay! Always good for some chain reaction fun. The gidrahs have gained hitpoints as well and will take several hits to kill. This makes up for the poor things being rather easier to shoot than before. Exploding crates are not replaced by the tile reset switch.

Chaz has done me an ice tile but I haven't put it in the game yet. Also he's monkeying with the gamma correction - I can hardly see some of the tiles and it all seems rather dark to me. It turns out Chaz's gamma is turned up considerably more than my default Nvidia settings. We'll see the results tomorrow.

Please test away and check out the lovely new pixel movement and crate pushing fun and gidrah pwning.

25 July 2007

Removed player pivoting, which is now no longer relevant with the auto-aiming feature. Changed start moving delay to 35ms (2 frames). I've noticed something very slightly annoying when stepping on arrows - if just one pixel of your bounding box steps on an arrow you are effectively hooked onto it but unless your dead centre is on the arrow the arrow itself doesn't have any effect. I expect that will require a bunch of hackery and bodgery to fix but I'm leaving all that alone today to make improvements to the map editor.

Stuff done to the editor:

  • Page Up and Page Down on the tile selector screen now flip the pages as expected
  • Holding Ctrl down and clicking in draw mode on any tile other than an action tile will instead pick up that tile to draw with.
  • Asynchronous load and save and exception handling (also for New Game - can take a few seconds on older computers and laptops to load the map!)
  • You can now type in the name of the map you want to save and load! The maps are stored in the your user home folder unless you give them a full path. This means you can finally experiment with your own maps. The last map saved or loaded is the one that is used in the game. Don't forget to toggle all your switches to the correct state before you save (Ctrl-click).

Had fun writing all sorts of crazy asynchronous stuff and dialog boxes and message boxes and so on. Once again it just makes you appreciate how good Swing is at this sort of stuff.

26 July 2007

Things done:

  • Added "sentries" and "gargoyles" this afternoon. Sentries are turrets that turn to face the player (configurable speed in the XML, natch). Gargoyles fire directly at the player and don't turn. Right now there's no rotating turret graphic so it looks absolutely stupid. As does the gargoyle.
  • Chaz has done a "secret switch" tile. See if you can spot it :) We'll be peppering the game with secrets.
  • Added tooltips to the editor tile chooser.
  • Did a bunch of stuff in the UI code, such as rendering text with Areas and suchlike.

Ideas we had today:

  • Dangerous floortiles. What game would be complete without lava and toxic waste? Obviously lava would be rather out of place on the moonbase tileset but toxic waste is a possibility. Step on a tile and lose a point of health every second. Or every third of a second if it's really nasty.
  • Moving floortiles. Well, you need a device to cross dangerous floortiles don't you? These will just be EntityTiles and spawn entities on first view. Not sure about the implications for switches. Mind you, there are already implications for switches that create entities which I've not investigated.
  • Rescuing scientists. It might be fun to have a sub-mission in the moonbase levels to rescue some scientists and guide them to the exit without getting them killed for bonus points. They could shoot for you as well, but be killed by enemy fire and gidrahs. Get them to an exit and you are awarded 1,000 point bonus. We can have lost souls in the Hell levels and intrepid explorers in the Aztec levels.
  • Mines. Nearly invisible - maybe a single flashing dot that's quite intermittent.

Remains to be seen what goes into the game. Probably all of it :)

Very tired after another night of insomnia. Going to take it easy for a few days and not do any work until Tuesday.

29 July 2007

Fixed last movement glitch - if you just partially stood on an arrow tile but not enough for the arrow to actually start moving you, you couldn't step back off of it. Nice simple fix after all, I'd feared it was going to be a bugger to do.

You may or may not be interested to know we've made 58 sales this month. This is both good (yay! 58 sales!) and bad (we need realistically about 500 sales a month). I had formerly set this goal for end of 2007 but even with this new game on the way it's very unlikely. End of 2008 might be realistic, if we can get another 4 games out there and put some money into advertising. Somehow.

One thought on 'July Treasure Tomb Development Diary'

Comments are closed.