I'm in the middle of creating a game-simulator for a project. The game consist of two armies fighting each other. Each army consists of multiple soldiers. Soldiers are executing instructions (read from text).
Each instruction is a command like move, turn, etc. I have come to the part where I need to create a method that will check what is the next instruction and execute it. The instructions aren't much similar, meaning they don't开发者_Go百科 have the same methods.
The class running this method stores the game field (2d array) and an array of all soldiers, looping through it and executing the next instruction each soldier has. So at this point I have a really long list with if-else describing what happens with each instruction. I'm trying to find a better way to write this but can't figure out how. I have knowledge of few design patterns but I cant figure a way to do this with interface or inheritance (not sure if it's even possible).
How do I get around the problem of too many if-else statements and long code?
I know that there might not be enough information here but any advice is appreciated.
The instructions aren't much similar, meaning they don't have the same methods [...] How do I get around the problem of too many if-else statements and long code?
In general, if you have "if this type, then do this", then you have a case for polymorphism (a virtual function). In this case, what each entity has in common is that you're trying to update your game simulation, and each part of your game (each soldier) has a different concept of what it means to update the simulation.
I have come to the part where I need to create a method that will check what is the next instruction and execute it.
I recommend splitting this into multiple levels of abstraction:
- Representation of the simulation itself
- Getting input from the user (reading the file)
- Translating input into actions in your simulation
The reason you want this sort of independence is that you don't have to re-structure your whole game if you decide to change how you accept simulation input.
Game simulations
Every game must set up some sort of initial state, so they know what the world should look like, and how each action should change the world.
After that state it set up, the simulation will iterate through a global loop, commonly called a "game loop", and will keep looping until the simulation is finished (you quit, the game ends, or there is no more input).
How most games handle their input:
At the beginning of each game loop, they look for user input since the last time through the loop. They might look for key presses, mouse input, input on the console, network packets, etc. They take this input and translate it into actions for their simulation to process.
How most games handle their simulation:
Most games make an abstract base class for each game entity, and keep a global collection of all entities. The entity base class will provide a virtual Update
method. This method will take whatever state is necessary to perform the update.
An example, using C# syntax (sorry, I don't know Java)
public abstract class GameEntity
{
public abstract void Update(TimeSpan timeElapsedSinceLastUpdate, World theWorld);
}
Each iteration through the game loop, the game will make a sub loop through all the entities, calling Update
on each of them. Each game entity will have its own implementation of Update
.
A specific entity might react to input, or update some internal state. It might update its position based on its velocity. It might check for user-induced actions since the last update, to see whether it should change its acceleration/position. It might check whether enough time has elapsed to transition between game states (e.g. from a counting-down
state to an exploding
state). It might do intersection/collision tests vs other entities in the world.
The point is that time marches forward, and each game entity can have its own independent concept of what it changes vs time.
If your game is turn based (and therefore has no need for a concept of clock-time), or each entity already has a reference to the world, you can remove them from the base Update
method's signature. You might also consider adding a int updateNumber
or int currentTurn
parameter, if this becomes useful.
How to handle your simulation:
You might have soldiers as your only entity type. Actions will be passed to soldiers independently from the update command. Then the actions will be performed when update is called.
How to handle initial state for your simulation:
You have to figure out how many soldiers you have to start with, and their attributes (type, rank, health, etc). You might also need information on the world, such as grid size, or possibly terrain data.
How to handle input:
- You could feed the actions in when you create the soldiers, keeping track of the action and which turn it should be executed
- You could feed the actions to be executed to each entity before each turn/update
Either way is up to you, but feeding in before each update will let your game be more flexible to change in the future. In most interactive game, users tend to input moves one turn at a time.
This also won't limit you from creating queues of commands to be executed each turn, since the entity itself doesn't have to process the queue, and so it doesn't have to know such a queue exists.
You might to want to look at the State Pattern.
if you think about it, what you are really trying to do, is creating a new language, specialized for your game. It is called a DSL (Domain Specific Language).
This is a really common thing in computer science.
If you think your language will stay really simple, something like that :
command1 arg1 ... argn
..
commandN argN1 ... argNn
then, you can use the pattern command and find the right command by it name. This is what other response are about.
But this is really BASIC. How do you manage errors ? Too many, not enough arguments ? Eventually conditional expressions or loops? How about sending complex structures or arguments to yours commands ? How about defining a 'macro' or a list of commands ?
If you want more depending of what you really want to do you can go for several routes :
- Using an XML formaat with an XSD instead of free text would allow for validation time checking of your list of orders and their parameter. It would also permit use or advenced data struscture, macro or simple expression. Better, but not so easy on the eyes to read.
- Using an existing scripting language (like Groovy, Jython, clojure...) that can embbed nicely in java, so that your commands are in fact source code. So they can do everything the language permit (so you have loop, functions, anything the scripting language can do), and you expose the API that allow to control your soldiers in it.
- You really want something specific. A special language, likely more advenced than the one in my example, but don't want to include a regular scripting language. You have a range set of tools like XText from Eclipse Modeling framework that is designed just for that. Helping making a DSL. Or you can define a grammar and use parsers like ANTR to help you.
This is a very wide topic, if your needs are basic, a big switch case, or the command pattern is enough. If you want something more professional but still effective, I would try one of the other solutions I pointed there and spending time to see what each can really offer, what is possible or not, and how it could serve you... or not.
Of course it's possible :) You'd use polymorphism. Here's an excellent example.
精彩评论