Tuesday 23 July 2013

...forget everything I just said.

Objects no longer work like that. The current system is similar to the one described but the previous post's version had too many limitations that were not obvious until I started trying to do unobvious things.

Welcome to rapid application development!

Ok, in fairness, it's mostly the same. The six-phase collision is out and a new three part behavior system is in. Collisions now happen in two phases and automated behavior in another separate phase allowing complex behaviors to be coded, combined and then triggered for different reasons.

I'll post about the changes before too long and hopefully I'll have some video to share.

Thanks to the people who helped test Asciilands recently! Also, if you want to help test the alpha / beta versions or just see it in action, let me know by any means available to you.

Saturday 6 July 2013

Behind the Curtain

I thought I'd make a slightly more technical post about some of the behind-the-scenes goings-on with Asciilands. After all, most of the people invited onto this blog are fellow developers or coders of one sort or another. First up, a look at how the map is rendered and how we keep the lightweight stuff lightweight and the heavyweight stuff to a minimum. After that we'll touch on the interactions between objects and why they are so crucial to pretty much everything.

Asciilands is like...onions.

First up, a bit of nomenclature:
Map - The entire cached area (e.g., all of testIsland). When the player moves from testIsland into bluffCave, they are in a different map. A map can be any size. TestIsland is 139 * 71.
View- This is the 21 * 21 grid shown to the player in the panel. The view is just the visible part of the map. The view is [at this point] always 21*21.
Tile - A tile is an arrangement of six characters which form a [almost] square. The only player interaction it is capable of is either allowing or disallowing a player to move onto its square in the grid.
Scenery - A sprite which appears on a tile. It is merely decorative and, like the tile, can only permit or deny entry to its square in the grid.
Objects - Objects are representations of interactive items. I'll come back to this.

I'm a visual learner so I came here armed with diagrams. First is a screenshot of a view with indications of which parts of the grid are occupied by elements from which layers. Babble.


The red markers are from the tile layer, the yellow markers are from the scenery layer and the purple markers are from the object layer. The lowest yellow marker is highlighting the cracking on the wall; this is subtle so I thought I'd better mention it.

The two purple markers are on a sign (which can be read) and a block (which can be pushed). These are interactions too complex for scenery.

Tile objects are the most basic; all they have is a background colour, a foreground colour and a bunch of characters used to make them up (either static [like the bricks] or randomly allocated [like the grass, sand and water]).

The view is composed like this:


The view is like a cookie-cutter that cuts down through all layers; objects on top, scenery below that and tiles on the bottom. Objects from lower layers show through in the gaps of the layers above and tiles set the default characters and colours to be shown in the spots for characters which aren't occupied by the sprites above them.

Now why did I say that thing about objects being a representation of an interactive item? Well it's sort of complicated. Basically, the object only exists within the context of the map. For example, the player cannot collect an object. Previously seen coin and weapon objects which can be collected work like this:

The coin object has a sprite, a location and an item. It also has instructions on what to do if various things interact with it.
Confused? I'll keep explaining and maybe it'll make sense. Maybe it won't. Not sure.
The player collides with the money object (this happens when the player attempts to move into the same grid-location as the object) the object then disappears and places the money item it was storing into the player's wallet. If say, a push block collides with the money object, it crushes it so the money object, along with the item it was holding, just disappears.

Wait, this is moving into explanation-of-collisions territory, time for a change of sub-heading.

When objects collide!

A collision takes place when one objects attempts to occupy the grid-location of another.

There are two important things which come out of a collision. The first is the behaviors and interactions between the two objects and the other is whether or not the object attempting to move will indeed be able to enter that grid-location.
The collision itself is made of of six parts; the pre collision, the collision, the post collision, the pre reaction, the reaction and the post reaction. Each different object type has a different combination and range of behaviors that are triggered in the various parts of the collision.

First I'll show a diagram of which of these behaviors are triggered and in what order. That way you can picture what's going on as I explain it:


The diagram shows two objects; the instigator is the object attempting to move to a new location in the grid and the receiver is the object which is already occupying that location.

For the sake of demonstration, let's look at the interactions taking place when a player attempts to push a block into a sign.
There are two collisions taking place here; one between the player and the block and another between the block and the sign.
Firstly, the player's collision behaviors would be imposed on the block then the block would react.
In this instance, at this time the player has no collision behaviors; the player only makes requests to move and other objects react so let's look at the block's reaction:
The block recognises that the player is trying to enter its location so it attempts to move along one tile in the same direction as the player. In the absence of the sign (or any other obstructing entity), the block would make this move and then return true. Why? Because it is now true that the player is allowed to enter the space into which it attempted to move.
The block's calculation of direction, attempt to move and response as to whether or not it DID move are all done inside the reaction phase. This is because the block reacted to the player's collision with it.
The plot thickens, however, because as port of the block's reaction, it attempted a move of its own into another occupied grid-location.
The sign has a reaction behavior which tells it to display text to the player when the player collides with it however since it is a block, this behavior is ignored and instead it simply returns false. False meaning "you can't come in here, I was here first" and so the block's attempt to move is unsuccessful and it stays where it is. Since it hasn't been able to move out of the way of the  player, it too sends the "false" message back to the player so that the player is, similarly, blocked (no pun intended) from entering that location.

In this example, the final order of operations is this:

  1. Player pre collision (nothing)
  2. Player collision (nothing)
  3. Player post collision (nothing)
  4. Block pre reaction (nothing)
  5. Block reaction (See what's trying to move it, attempt to move on account of instigator being a "player")
    1. Block pre collision (nothing)
    2. Block collision (See what I'm being pushed into and update thought  panel with hint as to why I am or am not moving)
    3. Block post collision (nothing)
    4. Sign pre reaction (nothing)
    5. Sign reaction (See what's instigating this collision, do nothing since it's not a player, return "false" to forbid entry)
    6. Sign post reaction (nothing)
  6. Since the block was unable to move, the false bubbles upward to the collision with the player.
  7. Block post reaction (nothing)
And so nobody moves!

It's a difficult thing to explain and I'm sure an even harder thing to understand but hopefully you have at least some insight into what's going on when you're moving around in Asciilands eventually!

One thing some of you might have noticed is that there seems to be a lot of waste. The pre and post behaviors all did nothing. This is because those interactions happened between vanilla objects. The pre and post behaviors will be utilised by custom objects with special behaviors.
Take the light wand for example:


The light wand is a custom object based on the collectObject code. It has a special post reaction behavior which makes it light up the room when it is picked up.
I recently did another test of custom object capability and created a zombie. The zombie code is exactly the same as the human code except that the zombie has a pre collision behavior which makes it turn the receiver into a clone of itself if the receiver is a moving object. This means that a single zombie can infect every person in the map and they can infect each other and the only change required to create this whole dynamic was the addition of one behavior.

It's all about leaving room to fill with custom behaviors to create exciting and diverse custom objects.

I think that's enough from me today. I'm experimenting with some screen capture stuff to record some videos but Blogger doesn't like the size of my files so I might try to make them shorter. Feel free to shoot me any questions or ask me to better explain anything I may have just glossed over.

Until next time!

Tuesday 2 July 2013

Adventures in Nostalgia

With a baby imminent, my wife and I have been sorting through some old stuff to make room for the impending flood of fluffy, pink and / or squeaky baby things. One of the oldest boxes - packed in 2008, lugged to our first apartment and then, still sealed, our current townhouse - contained this:

 Note the unique spelling of the word 'Vengenance'


This game was the defining game of my childhood. My sister and I spent hours and hours playing and replaying it. Certain poorly documented features (like the ability to move diagonally by using the WASD keys instead of the arrow keys) just stretched out the enjoyment even further; we would use and reuse a random teleport spell until we ended up on the other side of the diagonal passageway.

The interface looked like this:

Good job, legless midriff-showing avatar!

I don't think I've ever enjoyed a game more, either before or since.

You can't see it in this picture, but many of Castle of the Wind's sprites were a little... difficult to interpret. Some high level enemies would leave behind these yellows mounds with some stuff - like swords and helmets - sticking out of it. It was only on replaying the game many years later that it occurred to me that these yellowish puddles might, in fact, be piles of gold coins and loot rather than a semi-viscous pile of melted yellow monster puss with some items embedded in it.

The message, I guess, is that things don't have to look like the things that they are meant to look like for a game to work. Which is reassuring, given some of the sprites I've worked on:


Moo!