Time for some worldbuilding! Not the history/back-story kind, but the let-us-make-the-terrain-on-which-we-will-be-standing kind. But Adam, you may be saying, should this not be called level building? And I will say, my game doesn't have levels! It has a world! In response you will only look at me askance, one eyebrow raised, as if to say: well okay, have it your way, go ahead and CONFUSE EVERYONE.
PART 1: Building the world
Fig 1. An area of the game being designed in my worldbuilder program
This is my worldbuilding program, which I've made in java. As you can see, there's a 9 by 6 grid of square buttons, matching the 9 * 6 tile format I'm using in my game. On the right we have a scrolling window with different types tiles. Select the tile you want, and click on the button representing the location you want, and BAM the image on the button changes. When you're happy with the design you click export level and you can save the resulting map as a text file.
Fig 2. the text file representing a single screen of the game
Basically, it's just a list of tile types with their x and y locations. Each object is contained within the curly braces. Anything outside of that doesn't count - so we can use that for comments (as we'll see momentarily).
What's cool is that I use the same sort of file to determine what types of tiles are available in the world builder.
Fig 3. Tile type index (remember that the text outside the curly braces has no effect, it's just for my own reference)
If I want to have more than just two tile types, all I have to do is draw a new one, name it, and put its name into the text file.
So this is all pretty cool, but how does this translate into actual stuff in the game?
PART 2: Loading the world
So now we need to get these maps into the game somehow. This was actually the trickiest part to accomplish, only because I'm not an expert with the Android filesystem. Basically, there are multiple ways to store files in android apps:
In resources: Files stored in resources are very easy to get to since they have a special built in way to refer to them in the code (R.fileType.fileName). However, you can't change files in resources, and you can't use text files. So that's out.
In a local file: You can make files that can only be read and edited by the app that makes them. However, these have to be made by the program after it starts, so that's no good for these files, which I'm making in advance. Might be useful for save games later on, though.
Use a SQL database: This might actually be a good way to do this (if you have thoughts on this, say so in the comments), but I don't know anything about SQL and I don't want to spend too much time trying to learn it right now.
In the SD Card: Files in external memory can be read and edited, but they can also be easily found by the user (which would be a problem if the delete or edit the world files and now suddenly the game can't play). Another problem is you'd have to remember a system address for your files. No go.
In assets: This is what I used. You can store any file you want in the assets folder, you can read and edit them, and ONLY your app can modify them. Great! There is one downside though, which is that you have to read each file in byte by byte.
So here's how I organized my data. Every android app comes with an "assets" folder. Inside assets I made a "world" folder. And inside world I made a "zone" folder.
In the world folder I have a text file called "argil.wld" (Argil is the current name of the setting, but that's another post). This serves as a directory for all the zones of the world (the individual screens which I made in the level builder). It tells the game engine how big the world is, what zones are in it, and at what location (in relation to each other) each zone is.
Fig 5. The world file. Once again, only the information inside the curly braces is used by the computer. Also, notice my "IMPORTANT NOTES" to myself at the bottom. This is how much I trust my future self to have any idea of what my past self intended.
When the game starts up, it reads the world file. For each zone mentioned in the world file it creates a new Zone object. For each Zone object, it reads in the appropriately named .zne file (stored in "assets->world->zones"), which is the file made by the worldbuilder program. Reading through the .zne file it makes Tile objects for every tile in the file, and stores those inside the Zone object. Got all that?
Here's some code from the actual file-loading section:
InputStream file = context.getAssets().open(fileName);
boolean readingData = false; //true when it's reading relevant data
String data = ""; //the string of the data being read
int curByte = file.read(); //start with the first byte
char curChar = ((char)curByte);
So, you can see that context.getAssets().open(fileName) is how you actually open a file from assets - note that fileName is a String and that you need a reference the "context" of the app.
More important is how you can tell when there's still data in the file - basically, if file.read() returns -1 then that means you've run out of bytes. This seems simple, but at first I was trying to use an ill-documented method called isAvailable() which I thought was telling me how many bites are available in the file, but NOPE, actually it was telling me something else and cutting off the file at about four letters in. So, this is me telling you DON'T DO THAT.
So, in conclusion, we start with a world builder
which saves as a .zne file
which goes through some code, and becomes
part of the game! I'm super excited about this.
(Note to self. How to take screenshots of game: Under Eclipse, go to DDMS, click on the camera icon.)
PART 3: Stuff you can download
The source code for the level builder
The current build of the game (for the morbidly curious)