Treasure Tomb Development Diary

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.

Music: Led Zepellin IV, DJ Food - Solid Steel, Chemical Brothers - Push the Button

Damn… webstart really sucks. It really does.

I’m desperately trying to get the console-output either on screen after the crash, or in some file.

But whatever I try, the console-window is disposed immediately, and nothing is written to stdout.

Some uber-webstart-hero help me out here…

So… in short: the game crashes a few seconds after the javaws dialogs show up, and before anything GUI-wise gets loaded.

[quote]You can practise dying by tapping Z repeatedly
[/quote]
This forum needs a Quotes Top 10.

Sorry :slight_smile: Fixed it - was a ClassNotFound, we’ve got a ParticleDiddler AWT tool that Chaz uses to monkey with the particle effects but I didn’t upload that. Reference removed, re-uploaded. Clear your cache again and try once more :slight_smile:

I must make the map editor load and save files properly at some point so you can play with it (tap M to play with the map editor. Some useful keys are M for minimap, Space for tile chooser, scrollwheel, RMB to delete, cursor keys/ shift cursor keys for scrolling navigation, hold down ALT, SHIFT, or CTRL for special stuff, cut n paste all works as expected, so does undo)

Cas :slight_smile:

But how long did it take you to come up the idea? I know people say ideas are a dime a dozen, but I find it hard to come up with a good idea that is fun. Do you have some sort of process that you can describe when coming up with/fleshing out the idea? Or is too hard to put into words?

About 5 minutes to come up with the idea coz we basically pinched the concept from Time Bandit. Then we throw out all the bits we don’t like, put in a bunch of stuff that we know we like, and then just let it evolve randomly as we code it. Then we tune the hell out of it when it’s finished to ensure it’s easy and fun to play.

Not all my ideas are pinched directly from somewhere else but this is definitely a homage.

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 :frowning: 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.

Music: Chemical Brothers - Come with Us, Smashing Pumpkins - Siamese Dream, Cypress Hill - Los Grandes Exidos En Espanol

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.

Music: The Good, the Bad, and The Queen; Prefuse 73 - Security Screenings; Lee Perry & The Upsetters

Movable crates! I could block a robot spawn spot! And they get shoved by the “arrow” squares!

It’s interesting to watch this development as gameplay is (by far ;)) not finalized and there are surprises in each “release”… It’s hard to say how things are going to work on a limited map though.

How about adding shooting in 4 directions a la Puppy/Ultratron? I’m not familiar with the games that inspired this one, but coming from Puppytron is for sure frustrating!

Update: Blocked spawn spots still release bots… and some cannons shoot sideways? Can’t seem to be able to destroy cannons now.

Perhaps enough shots (5 or so?) destroy a crate, which re-spawns in its original position. Anyway, you’ll figure out the gameplay, there are lots of possibilities here. I’m enjoying the read.

Bill

I’m enjoying the day-by-day read as well, and I wanted to throw in another suggestion.

As a replacement for the laser cannons, in your “pyramid” tile-set, the sphinxes are said to have a deadly gaze. 8)

Noted :slight_smile:

Don’t think I’m going to change the movement and shooting now, as it’s just right the way it is. However, you are going to need some enemies that shoot back and which have brains at some point. Oh, and this is difficulty level 0. I shall put a tester in so we can see what difficulty level 10 feels like.

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.

Music: Didn’t listen to any!

When I ran Software Update for currently installed features in my Mac based Eclipse 3.3 today, patch 1 for the RCP (Rich Client Platform) was found. Perhaps worth trying.

Also you can try the very latest Java 6u2 - I guess you’re on Windows (Mac doesn’t have final Java 6 yet… >:()

(Mod: please don’t change the thread subject :slight_smile: )

I’ll wait for an official 3.3.1 release I think… I don’t trust those patches. Already got update 2. Wonder when the Mac will get it… they drag their heels a bit in Apple-land.

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)


<!-- Title screen -->
<instance
	name="title.screen"
	class="tomb.TitleScreen"
	autocreated="true"
	mousevisible="true"
	registrationbounds="0,6,220,32"
	colour="255,255,255,255"
	versionbounds="300,305,20,15"
	keyboardnavigation="true"
	music="title.buffer"
>

	<area id="titlescreen" position="0,0" mouseoff="spriteimage.titlescreen.01" layer="-1" noclick="true"/>	

	<area id="buy" position="0,170" mouseoff="spriteimage.buy.off.01" mouseon="spriteimage.buy.on.01" disabled="spriteimage.buy.disabled.01"
		nextfocus="moregames"
		prevfocus="credits"
		rightfocus="moregames"
		upfocus="help"
	/>

	<area id="play" position="197,72" mouseoff="spriteimage.play.off.01" mouseon="play.button.on.animation" disabled="spriteimage.play.disabled.01"
		prevfocus="moregames"
		nextfocus="help"
		upfocus="credits"
		leftfocus="moregames"
	/>
...

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 :slight_smile:

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.

Music: Dandy Warhols - Thirteen Tales from Urban Bohemia, DJ Vadim, Primus - Frizzlefry, Primus - Sailing the Seas of Cheese

Kinda offtopic: about the lerp… isn’t this guaranteed to work?

c = a + t * (b - a)

it’s slightly faster too. :slight_smile:

Hm… I can’t modify my posts in this thread (and can modify posts by others in another thread…) so let me add a bit to my last message:

your code: (1-(1-a)) != a
my code: a==b -> b-a == 0

I think that’s why my code is stable?

What a strange coincidence, but I found exactly that algorithm about half an hour after I posted in Ken Perlin’s improved noise generator in Java.

I suppose I will adjust mine to suit :slight_smile:

Cas :slight_smile:

Isn’t the lerp implementation a red herring? Surely you should be comparing floats with an epsilon all the time anyway?

Crivens no, not when I’m dealing with whole numbers ultimately!

Cas :slight_smile:

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.

Music: Kruder & Dorfmeister, Square Pusher

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…

Music; K & D, Square Pusher, 2 Many DJs, Jason Holmes, The Dandy Warhols

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 :slight_smile:
[*] 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…

Music: none, was the early hours of the morning :wink: