Programming Tips #1 - If Statements
Programming Tips #2 - Making Progress
Programming Tips #3 - Design
Programming Tips #4 - Datums
When you first start programming, the problem you're trying to solve is "how do I write code that'll do ______?". Initially you're happy just to get something working, who cares what the code looks like. But when you try to develop a complete game this indifference can become a problem. As your code gets messier and messier, the project becomes harder to work on - you're more likely to write code that has bugs and they become harder to track down and fix. Eventually it'll get to the point where you're wasting a lot of time, don't feel productive, and are more likely to stop working on the project.
As a more experienced programmer, instead of asking "how do I do ______?", you should start asking "what's the best way to do ______?". In this post we'll look at why organization is important and some techniques you can use to keep your projects organized.
How many times have you done these things?
1. Searched through code files to find a proc's definition to see what order the arguments are in.
2. Looked through map files and counted z levels to find what z level a particular map is.
3. Switched back and forth from code files to icon files to verify icon state names before setting the icon_state var.
You've probably done these things a lot. You've probably also realized that skipping each of these tasks causes a corresponding bug:
1. The arguments are passed in the wrong order and the code doesn't work correctly.
2. Players get teleported to the wrong map.
3. Objects get the wrong icon state (and can appear invisible if the .dmi file doesn't have an unnamed icon state).
These examples aren't the only things you might have to look up. There are many things about a game you'll have to remember and any time you can't remember something you'll have to look it up. Here are some of the things you may have to remember about a game:
built-in variables, your own variables, library-defined variables, built-in procs, your own procs, library-defined procs, proc behavior, proc return values, parameters, parameter names, parameter order, object type paths, file names, folder structures, savefile layout, icon states, z levels, map locations, atom tags, level design, game modes, interface control IDs, window names, macros, verb names, sound effects, music, coordinate systems, IP addresses, user names, passwords, version numbers, and URLs.
It's a common mistake to rely on remembering these things. If you've ever had trouble getting back into a project after taking a few weeks off, this is the reason why - in the time off you forgot these details, and now that you can't remember them you have to look more things up and you have trouble making progress. A good developer isn't any better at remembering these details. A good developer is more organized so there are less details to remember and they're easier to look up.
This is the part of game development that's not fun. People ignore it because they'd rather focus on the fun parts but organization is very important. Most incomplete BYOND games aren't finished because the projects were disorganized. When you're not organized you'll spend a lot of time looking things up - this doesn't feel productive and it drains your motivation. Have you ever just lost interest in a project? That probably happened because the project became so disorganized that it was no longer fun to work on.
In this article we'll look at two ways to keep your projects organized.
Naming conventions are patterns you follow to make things easier to rememer. Want to see the power of patterns? Try to figure out where you were at 10:17 AM on February 7, 2002.
Unless that's a significant day for you (ex: your birthday), you probably don't remember where you were. But, you can probably figure it out. That day was a Thursday, so you were probably in school (or at work). If you were in school, what school did you go to that year? What period would you be in at 10:17 AM? Do you remember your schedule for that term?
Off the top of your head you don't remember where you were, but because you know what patterns your life followed you can probably figure it out. You can use this same idea in your games. Naming conventions can be applied to anything with a name: procs, variables, type paths, file, icon states - as long as it has a name, you can find a way to make the name useful to you.
Here are some different names you might use for the same variable:
When you defined the variable to store the player's maximum health you picked one of these names, but later on you might forget which name you picked. If you used a naming convention you don't have to remember what name you picked, you just have to remember what patterns you follow when naming variables. Here are the rules I tend to follow:
1. I'd call the value "health" instead of "hp".
2. I'd use the term "max" instead of "limit".
3. I'd keep "health" as the noun for all health-related vars.
4. I'd use underscores to separate words instead of capitalization (ex: var_name instead of varName).
Because I consistently follow these rules, I never have to go searching through code files to find the variable's definition and I don't have to remember that I called it max_health. The rules tell me that the variable would be called max_health.
Suppose you have three map files in your project (town.dmm, dungeon.dmm, and castle.dmm) each with multiple z levels, there's no easy way to know what number z level you would use to reference the second level of the dungeon map. You have to know what order the map files are processed in and how many z levels each map before dungeon.dmm has. You can split the maps up so each z level is its own .dmm file and name the files like this:
001-castle.dmm 002-castle-2nd-floor.dmm 003-castle-basement.dmm 004-town.dmm 005-town-upstairs.dmm 006-dungeon.dmm 007-dungeon-b2.dmm 008-dungeon-b3.dmm
The first part tells you the z level, the second part tells you what zone it is (castle, town, or dundeon), and the third part tells you what section it is (ex: upstairs, basement, etc.). You don't have to do any searching to figure out what the z levels are for each map, you just have to glance at the file names. If you want to teleport a player from the castle to the second level of the dungeon, you can easily see that they'll be moved to z = 7.
The first section of this article gives you ideas about how to name variables, but that's only part of it. No matter what you call the variable, you also have to decide what code file to put it in. How much code do you put in the same file? Which procs should go in the same file, which should go in different files? What should the file be named?
It's hard to tell people how to organize their files because it heavily depends on personal preferences. You might think that having 400 lines of DM code in one file is fine, but someone else might think that's too much and split it into two or three files. It's hard to have strict rules, but here are some things to keep in mind:
1. Think about what files you'll commonly have to switch between. Dream Maker lists files in alphabetical order. If all of your files are in the same folder, abilities.dm will be next to ambient-sounds.dm even though they're not related. You'll probably never switch directly from one of those files to the other, so you'll never find it convenient that they're next to each other. Group related files by putting them in the same folder or by giving them a common prefix (ex: put "combat-" on the front of all combat-related files.
2. Think about the granularity of each file. If you put a ton of code in each .dm file it'll be easy to remember what file a proc is in (ex: the attack() proc is in combat.dm because that file has all of the combat code), but once you're in that file it'll be hard to find things. Instead of spending time flipping between code files you'll spend time scrolling within the same file. Find a good balance.
3. Think about what vars and procs relate to each other. Put related things in the same file, but be careful. Every proc is related to some other proc, so if you put all related things in the same file you'll end up with one huge .dm file. It's not as simple as grouping any two things together because they have one common quality, you have to find logical groupings. For example, instead of defining all special abilities in one file and all enemies in another, you might make one file for each enemy that defines the enemy and the abilities it uses. You might have multiple interface menus but you wouldn't put all the code for them in the same file because the combat menu has nothing to do with the character creation menu. For each piece of code, think about what other pieces of code you'll need to refer to.
Organization plays a huge part in programming but it can be hard to realize it's importance. If you don't have any problems there's no indication of how organized you are - there's no message at the bottom of the screen saying "you could be 28% more organized." The only indication that you're disorganized is when you start running into problems, but even then it's not always clear - there's not a popup that says "if you were more organized, this wouldn't have happened!".
If you don't understand the importance of being organized you'll think that it's just a waste of time. The good news is that it doesn't really take any time at all. Every time you create a variable or proc is a chance to be organized. It might take time to get in the habit of following a naming convention, but once you're in the habit it doesn't take any extra time.
Look at your existing projects and think about ways they could be more organized. Think about some problems you've run into and see if they were caused by a lack of organization. When you scrap a project and start on a new one, think about what you can do to make the new project more organized than the old one.