The Dink Network

Reply to Re: Windemere Fonts

If you don't have an account, just leave the password field blank.
Username:
Password:
Subject:
Antispam: Enter Dink Smallwood's last name (surname) below.
Formatting: :) :( ;( :P ;) :D >( : :s :O evil cat blood
Bold font Italic font hyperlink Code tags
Message:
 
 
December 23rd 2004, 03:07 AM
wizardb.gif
merlin
Peasant He/Him
 
Windemere Map Format: A Primer
==============================

HISTORY

When I sat down to begin coding the Windemere map format it quickly became apparent that I would need something to organize my thoughts, especially considering the greater complexity with freescrolling. There are an infinite ways to do this, but very few sane ways. With that in mind it would have been a mistake to build off of Seth's map format.

I write this article not to explain how the map format works to the reader, but how the format works to myself before actually coding it. I publish it with hope that something useful can be gained for the reader as well.

There were two approaches to the map format, as with any format, that were...

...to be considered: plain text or binary. I chose plain text because it is simpler. Binary formats are a mess to work with but are fairly compact; ASCII formats are exactly the opposite. I wanted both so I chose ASCII plain text that would later be compressed with my favorite compressor: Bzip2. While compression is beyond the scope of this document, its capabilities are amazing in comparison to its speed. There are better compression algorithms out there, yes, but the Burrow Wheelers algorithm is speedy for its yielding results.

There were still many ways to do this with ASCII but I chose one of the most widely-used methods of organization in existence: the tree method (as used by SGML, XML, HTML, etc.).

LIMITATIONS

Now, freescrolling relieves many limits of the previous tile-based implementation, but I had to further impose restrictions that I was not willing to code for, namely the map size. My plan was to allow an unlimited map size (up to 2^32 – 1 on 32-bit macines) and an unlimited number of maps. Since there were no longer tiles I made the terrain tiles sprites. Yes, tiles are now sprites! Which makes no difference whatsoever since there is no limit on the number of sprites that can be used.

I was not willing to code code that would draw only a portion of a sprite for the map. That would be not only cause more memory usage (new's, calls to glTexSubImage2D, and delete's every frame), but it would be slower and more work for me. Not something I want to do. So, the map size would have to be a multiple of the tile size. So, if the tile was 50 x 50 pixels, the map size would have to be divisible by 50.

The map would not have to be square either. A (bad) size could be 64 x 32. But then the tile size could not be 50 x 50 – it would have to be either 64 x 32, 32 x 16, 16 x 8, 8 x 4, 4 x 2, or 2 x 1. A better size would be 1000 x 500, meaning the width is twice as much as the height. This means that, at a tile size of 50 x 50, there would be 50 tiles across and 25 tiles up.

COORDINATES

But enough of the talk about tiles. That's just for reference for the OpenGL code in the engine. You, as a developer, only have to worry about one thing: pixels. I chose pixels not only because they were very simple but also so the engine could run at different resolutions without (too) adverse effects.

Here's the run-down:

We have a 2D plane on which to map. To plot a point, we need two things: the point and the point in relation (the point and origin). Like lattitude and longitute, we need some place to call 0. In Windemere, that place is the bottom-left corner of the map. Why the bottom left? Well, so the map can be added on to without it screwing up the rest of the coordinates. There are other ways to add onto a map, usually used for “indoor” areas, but those come later.

So, we know we need two things so far – the x and y pixel coordinates of our point, and the x and y pixel coordinates of the origin (0, 0), the bottom-left corner of the map. Bottom-left is the key here. Bottom-left everything. So, when you specify the coordinates for a sprite, you are specifying the point where the bottom-left of the sprite image will go.

In Seth's game we have areas called “indoor” areas. These areas are warped to and from using a warp. Areas like these are houses or shops or anything not connected to the outside world. Since I did not wish to force the author to put hardness around all areas that were indoor like one had to in Dink, I came up with a new idea: submaps. Instead of boxing off an area that would be warped to it would instead be created on an entirely separate map (in the same file, mind you). How do we know what part of the map is a submap? This is where a third coordinate comes in: the map number.

The number 0 is reserved for the overall main map, but the rest are yours to create and use.

1-1210,1350

That warps to the first submap, 1210 pixels over and 1350 pixels up.

0-0,0

That one warps to the main map at the very bottom-left corner. Probably not the most practical example but a proper one nonetheless.

Note that coordinates can get huge (ex: 196840,16783) which is another reason why I've created the submap system. If you're allergic to large numbers (like I'm allergic to Java) then you can create a hardness border around the map, force the user to use a path to change screens, and move him or her onto another submap. Very nice concept.

HARDNESS

Note that hardness methods can change as this is still under development.

Hardness is declared right inside of the map file using one of two methods: point hardness or rectangular hardness. Point hardness is where you want only a certain point to be hard (that didn't sound right) and rectangular hardness is used mainly for a box or line.

The first thing the engine does when the submap is loaded is create an array of all the hard coordinates for that plane. Each frame these will be referenced and dink will stop if he reaches one of them. This is why you must not warp inside one – you'll be stuck. You cheating fellow.

Point Hardness is defined like this:

[x, y]

And Rectangular Hardness is like this:

[x, y, w, h]

But that's pretty much useless unless it's in context. Let's look at the actual file.

THE MAP FILE

The first thing there will be are 4 characters: WMF\n. WMF means Windemere Map File and is checked to see if the file is really a map file (it's really used to see if the file is compressed or not).

Next:

<Map: 0>
{
Sprite(1, 340, 218);
Sprite(4, 4892, 3844);
Hard(5, 5);
Hard(27893, 1982, 280, 14);
}
<Map: 1>
...

Let's look at that line by line.

<Map: 0>
{

This designates the submap level. 0 is the main map. Everything after the { applies to that level.

Sprite(n, CoordX, CoordY);

This says display the bottom-left corner of sprite n at CoordX, CoordY. So, in this case, display sprite 1 at 340, 218.

The second sprite says display sprite 4 at 4892, 3844.

Hard(PointX, PointY);

This says create a point hardness at PointX, PointY. In this case, make sure the bottom part of the character cannot pass (5, 5).

The second Hard command says create a box of hardness from (27893, 1982) to (28173, 1996).

}

Close up Map 0.

<Map: 1>

Make everything apply to submap 1 now.

Overall it's a relatively simple map format. Simple enough to be written in a text editor, anyway.