.: What's this? :.
This is intended for people who are already familiar with the basics of custom maps in MMF.
It is a method of generating maps without the use of an array.
Instead of arrays, the map information is stored in an image file.
The map is called upon at the beginning of the level and all evidence of the extrapolation is destroyed.
Example can be downloaded at the bottom of the page.
.: What's the point? :. Reason 1: Avoiding Redundancy
Most image editors already have well-developed features. Tools like circle, rectangle, line, and paint bucket. These tools are not only useful in making pictures, but also useful when painting maps. Not to mention, the ability to undo and redo or copy and paste is handy as hell. Yes, these are all features you could implement into a map editor of your own, sure, but why waste your time? The tools of an image editor have undergone the process of perfection since the 1980's. More than 30 years of time-tested tools versus the couple of days your map editor has been around? That's a very easy choice for me.
<
Reason 2: Avoiding Arrays
This method does not require arrays. Well, sort of. You don't have to bother with the Array Object, or anything similar. Image files ARE arrays, though. Each pixel of an image holds 3 values: Red, Green, and Blue. This can range from 0 to 255. You could theoretically have 256 different tiles, with 256 different attributes, and still have another 256 values to use, for say another layer of tiles with other stuff. This is more than enough information capacity to create most maps.
.: How's it done? :.
This is done in 6 simple steps.
PREPARATION PHASE
I. Make image in the image editor of choice.
The colors you use determine what the tile types will be. For this example, only pure white and pure black is used. But other colors could be used for specific things.
Be careful! Exact colors matter. There is a difference with the color 255, 255, 255 (white) and 255, 255, 254 (slightly dimmer white). The computer can tell the difference even though your eyes can't! If you have the wrong colors here, your map will fail to load later.
Also take caution! File formats matter. There is a difference between jpg and png. For the purpose of the example, use png or bmp because these will not interfere with the accuracy of your map. JPG will artifact to compress size, but will mess with the original colors you picked. Again, if you have the wrong colors on this step, your map will not load.
You may want to zoom in as well. Each pixel will represent a tile of your map.
II. Place objects into frame.
These are the required objects to make this engine go:
-Active Objects:
pixelcolor (finds coordinates to get pixel color)
paster (pastes into the background)
player (8 directional movement or w/e)
-Button to trigger map creation.
EVENT PHASE
III. Load the map image into the Active Picture Object.
Start of Frame
-(Active Picture): New picture:Apppath$+map.png
IV. Set the constants to counters.
This step is to allow more flexibility into the engine. There are many tile size preferences. We'll use 16x16 for this example, but could work with any size. The map size is then determined by the dimensions of the picture you loaded on step III.
Always
-(Map Width): Set Counter to (X Right(Active Picture - X Left(Active Picture))
-(Map Height): Set Counter to (Y Bottom(Active Picture - Y Top(Active Picture))
-(Tilesize): Set Counter to 16
V. Define the loops.
The loops examine the image and decide how to build the map accordingly.
On loop row
+GetRedAt(Pixel Object, x(pixelcolor), Y(pixelcolor)) = GetRed(GetRGB(0,0,0)
-(pixelcolor): Set X Position to (X(pixelcolor)+1)
-(paster):Add backdrop as obstacle
-(paster):Set X position to (X(paster)+value(tilesize))
If the pixel on the image is black, paste into background, move paster and pixelcolor to next spot.
On loop row
+GetRedAt(Pixel Object, x(pixelcolor), Y(pixelcolor)) <> GetRed(GetRGB(0,0,0)
-(pixelcolor): Set X Position to (X(pixelcolor)+1)
-(paster):Set X position to (X(paster)+value(tilesize))
If the pixel on image is white, don't paste background, and move to next spot.
LoopIndex(row=value(map width)
-(paster): Set Y position to (Y(paster)+value(tilesize))
-(pixelcolor): Set Y position to (Y(pixelcolor)+1)
-(paster): Set X position to 0
-(pixelcolor): Set X position to 0
-Set loop row index to 0
-Subtract 1 from Countdown
If the paster is at the end of the row, move down a space, move back to the left, reset the loop, subtract from countdown.
VI. Destroy the evidence.
After the map is constructed, destroy everything related to building the map so it won't take up space.
Countdown = 0
Destroy pixelcolor
Destroy paster
Destroy Pixel Object
Destroy Active Picture Object
Destroy Map Width counter
Destroy Map Height counter
Destroy Countdown counter
Set player position to x,y of whatever you want.
Set the button to start the countdown. Have the countdown start the row loop if it's greater than 0 and you're finished with the map maker.
.: What else? :. Internal vs. External Images
By using external image files, like the example, you provide a very simple way to allow players to build their own map. However, if you do not protect your original files, a clever hacker could build bridges and destroy obstacles of existing maps. Protecting external files is beyond the purpose of this article, though.
Internal image files provide much better protection. Simply replace the Active Picture Object with an Active Object. The trade off for protection is that you lose customization capacity.
A simple way to feature both custom levels and protected levels would be to us both internal and external methods. The extra coding will be worth the effort.
Barely Visible Color Differences and File Types
When designing the map, it makes sense for each tile to be incrementally associated with a number. For example, grass = 1, water = 2, rock = 3, and so on. However, incrementally increasing the RGB value in this fashion is difficult on the eyes. 0,0,1 and 0,0,2 look the same. The obvious solution here would be to only use visibly different colors when drawing out a map, however, this only moves the problem to coding side of things. A new event searching for each specific pixel color to assign it a tile will eventually become tedious. This is a problem to be further explored (the solution may rely on an array). However, you can use this conundrum to your advantage.
Instead of searching for specific pixel colors in Step IV, you could search for a range of colors. Such generalization would let you take advantage of features within image editors like blur and anti-aliasing. This is useful because the tiles placed during this color range could also be randomized, making for a more natural effect when making hills, mountains, trees, etc.
This can also be combined with the attributes of each file type. Each image file type (and there are lots) as special qualities. For example, JPG files compress images to reduce file size, and the resulting image becomes smudgy and artifacted with random pixels. These compression smudges and artifacts would in turn show up in your map. There are creative paths to explore here.
As someone who enjoys making a good level editor this was pretty interesting
how would you go about making a level with, say, a couple of background layers, a main layer, and a couple of foreground layers? The obvious workaround would be to import a layered image file, but I don't know whether or not that would be possible.
The using compressed images as a form of randomisation is an interesting concept, but I reckon it'd be a bit too computer-dependent and could lead to some unpredictable results. Still, interesting to think about!
You could make multiple layers, but you would need more picture files, as you would only get three layers from one image.
Some file formats support layers within the image itself, but the Pixel Object only detects the color of the pixels on screen, so if Active Picture Object could show only specific layers of as .psd or something like that, we'd be in business...
Nice article
The problem is that you can't store much more than just the tiles themselves - for example, you couldn't store text messages (eg. hints / dialogue), or if you had a lot of active objects you couldn't store all their properties.
I always thought it would be interesting to try and use .png as a level format, and write an extra binary chunk containing all the non-tile data.
It would be much like how Adobe Fireworks uses .png as its native format - so the files can contain features specific to Fireworks (vectors, layers, etc), but can still be opened in other image editors.
The existing .apng specification would be ideal for multi-layer maps.
There are 256 individual R,G,B values. Like you said, theoretically 256 different tiles with 256 different attributes with 256 more 'unused' values. Why not use these unused values to load text?
For example, here is an array of strings:
1. It's too dark to go back outside
2. He is a mere shadow of his former self.
3. Will you take the shotgun shells?
Now imagine a pixel with R,G,B value 255,1,2
Using your method, create tile 255, with attribute 1 and create another object (which the player will interact with to display text) and set an alterable value of this object to 2, as to later display message 2 from our array; 'He is a mere shadow of his former self'