Lunar Colonize!

Posted Nov 8th 2008 11:37pm by Alex Wein

Last spring I was in a class called Java Projects. It’s pretty much the best class at my high school because you get to sit around and make whatever you like with Java. And Lunar Colonize! was what two other students (Nick Clayton and Erik Krasner-Karpen) and I (Alex Wein) decided to make. (If that seemed grammatically stupid you should know that the exclamation mark is part of Lunar Colonize!‘s name…)

Real-Time Strategy

Anyway, Lunar Colonize! is an RTS (real-time strategy game), which basically means it’s a rip-off of games like Warcraft and Age of Empires… except seeing as it was made during class hours by 3 students in one semester, you can probably imagine that it’s somewhat worse. (When you see the graphics this will become painfully obvious.) However, we still think it’s fun to play and if you are a programmer you might find it interesting to see how we made it.

Multiplayer

The most distinctive thing about the game is its ability to connect multiple computers together so that anywhere from 2 to 10 players can play against each other on different computers in different places. (It was also really convenient for us to make the game multiplayer because programming computer AI for these kinds of games is mildly impossible.)

Instructions for Downloading and Running the Game

So, if you’re interested in playing Lunar Colonize! with a friend, here is the download link and instructions for how to run it. (If you’re more interested in learning how we made it or downloading the source code you might want to skip to the section called RMI.)

To run Lunar Colonize! on your computer…
1.) You need to have Java installed on your computer. If you don’t have it already you can click here for instruction on how to get it (make sure you download the JRE and then set the path correctly).
2.) Click here to download a zip file containing the Java class files.
3.) Open the zip file using a program such as WinZip and extract all the files to the directory C:\Lunar.
4.) Open the command prompt (on Windows XP that’s: Start > All Programs > Accessories > Command Prompt).
5.) Type “cd C:\Lunar” without quotes and press enter.
6.) At this point you need to decide which player is going to run the Server. (By now you should have realized that Lunar Colonize! can only be played with 2 or more players. If you’re trying to play it by yourself you’re going to have a hard time…) In order to start a game, only 1 of the people playing should run the Server on their computer. In order to do this, type (in the command prompt window) “java Server” without quotes. (If it doesn’t work, make sure you have done step 5.) The Server application will prompt you with a few questions. Type in each answer and then press enter. When you see “Waiting for players to connect…” continue to step 7.
7.) Now all the players (including the one running the Server) need to run the Client application. The Server player should open up a second command prompt window (Start > All Programs > Accessories > Command Prompt) and repeat step 5. (Do not close the old window that is running the Server.) Each player should now type into the command prompt “java Client” without quotes. (If it doesn’t work, make sure step 5 has been completed in that command prompt window.) At this point one player should have the Server running in one command prompt window and the Client running in another, and the other players should have only one command prompt window running the Client.
8.) The Client application will prompt each player with a few questions. One of these is the hostname of the Server computer. The player running the Server can find this here.
9.) Once everyone has entered the answers to all the questions posed by the Client application the game will start.

How to Play

Hopefully you will be able to figure out how to play on your own (especially if you have played an RTS before) but here are a few tips:


  • Destroy all other players’ bases to win.

  • Left-click to select units and buildings. Right-click to make them move, attack enemies, or gather resources.

  • When you select the base you will see buttons displayed at the bottom of the screen which you can use to train units and research technologies. Your resources are displayed in the bottom-left – if something doesn’t seem to be working it’s probably because you can’t afford it.

  • Villagers can gather gold (yellow circles) and helium (brown triangles), scientists can gather science (orange).

  • Villagers can also build buildings – when you select one you will see buttons at the bottom of the screen representing the buildings you can build. Click a building’s button and then click on the map somewhere to build it.

  • Scroll around the map by moving your mouse to the edge of the screen, or by using the arrow keys, or by clicking/dragging on the minimap in the bottom-right.

  • Press ‘i’ to find an idle villager/scientist.

  • Press ‘b’ to select your base.

  • You can drag a box or shift-click to select multiple units.

  • You can control-click a unit to select all nearby units of the same type.

  • You can create armies by selecting units and pressing Ctrl + a number 0-9. Press that number later to reselect the army. Double-press the number to scroll to the army’s location on the map.

  • Hold shift and right-click (while a unit is selected) to queue up multiple move-to points.

RMI

This is where I start talking about how we made the game, so if you’re the kind of person who doesn’t care about that you might want to stop reading right about now. Anyway, in order to do the networking aspect of the game we used RMI (Remote Method Invocation). RMI allows you to make remote objects, whose interface methods can be called remotely from other computers. This is a lot simpler than the alternative of using sockets and only being able to send strings over the server (which you then have to parse). After finishing the game we found a problem with RMI, however: it causes the game to have a memory leak, meaning that as you play, more and more Java objects are created, using up more and more RAM. This eventually causes the game to slow down significantly. At one point we were going to fix this by rewriting the entire game using sockets, but we never actually got around to it. RMI is an easy tool to use, especially for people who have had little or no experience with networking, but beware of performance problems if you use it in a particularly complex application.

LCG Files

In order to handle all the game graphics we created our own file type: .lcg (Lunar Colonize! graphics) files. These files contain simple instructions for drawing shapes on the screen in different colors. We then wrote a parser that translates .lcg files into instructions for the Java graphics handler. This way graphics could easily be modified and added without messing with the actual game code.

Servers, Clients, Unit Stubs, and other networking stuff

Here is the basic structure of how the game works: The server and client each have their own version of the game map (a set of all the objects (units, buildings, etc.) on the map). The server’s map contains Unit objects, which contain functionality for moving, gathering, fighting, etc. However, the client’s map contains only UnitStub objects, which contain only the data necessary for displaying a unit on the screen (location, health, etc.). Each UnitStub in the client’s map has an ID number that is the same as the ID number of its corresponding Unit in the server’s map. Since the Map class hashes units based on ID number, it is easy to locate corresponding units and update them appropriately. This is accomplished every frame (the game runs at 10 frames/second) when the client calls a method on the Server (an RMI remote object) that returns a MapUpdate object (which contains a list of everything that changed on the map that frame).

Commands, Queues, and other internal workings

I guess I still haven’t told you how the units actually work, so… when you select a villager and right-click a gold mine, this is what happens: First, the client calls Server.takeCommand with a Command parameter. This particular Command parameter is an instance of CommandGather (a subclass of Command), and it contains data such as the ID of the villager and the ID of the gold mine. When the server receives the command it uses this data to locate the villager and call its gatherFrom method with the gold mine as a parameter. This gatherFrom method makes the villager add two commands to its internal command queue. These commands are not instances of Command (which are sent across the network when the player performs an action) but rather instances of UCommand (which are contained within units’ internal command queues). The two UCommand instances added to the villager’s command queue are a UCommandMove (telling the unit to move to the resource) and a UCommandGather (telling the unit to gather from the resource). Every frame, every unit on the map processes the top UCommand on its queue. This means that the villager will continually process the UCommandMove command (which will move it a little bit closer to its destination every frame) until it reaches the destination, at which point the UCommandMove will remove itself from the villager’s queue. The following frame, the villager will process the UCommandGather which will make it gather a little bit of gold from the mine. The UCommandGather will never remove itself from the queue, so the villager will continue gathering every frame until interrupted by a new command from the player. I really hope all that made sense and wasn’t painfully boring.

Source Code

If you are interested, you can click here to download the source code of Lunar Colonize!

Copyright

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.