You would use a “layout” of some kind, even just a simple one, to lay out an arbitrary number of items centered on screen. And you would have a Button type of class that handles mouse click, using a contains(int, int) method to check if the mouse is inside the point.
Using a bunch of if-else statements works, but it leads to messy code that is (a) error-prone, (b) difficult to debug and © difficult to adapt. For example; say you want to add a new button later down the road, you might need to copy and paste huge chunks of code in many parts of your program. Or, if you want to change the way the button looks or acts, you would again need to change a lot of code. Ideally it would be better if everything was “modular” and well separated – that way, if you decide to add/remove buttons, or change them around, it should take minimal code changes.
This would be a good candidate for the Enum pattern. For a larger application, enums might not always be the best choice, but for small games and generally increased productivity they can lead to very clean code.
In this example, we only need to define a new Enum constant when we want to add, remove, or change a button from the menu screen.
public interface ButtonListener {
public void clicked(GameContext context);
}
protected enum MenuActions implements ButtonListener {
// All buttons are defined here
PLAY("Play") {
public void clicked(GameContext context) {
context.enterGame();
}
},
EXIT("Exit") {
public void clicked(GameContext context) {
context.exit();
}
};
// MenuActions class definitions...
public final String text;
MenuActions(String text) {
this.text = text;
}
}
Assuming you have some sort of GameContext class, which handles game states and so forth:
public interface GameContext {
public void exit();
//you could apply further abstraction here... i.e. enterState(State)
public void enterGame();
public void enterMenu();
}
During our GUI setup, we don’t actually know anything about what buttons exist or how large they are. This “abstraction” means that we won’t need to change the following code if, say, we want to add, change or remove a button:
//let's say your game implements GameContext
final GameContext context = this;
for (final ButtonActions action : ButtonActions.values()) {
MyButton btn = new MyButton(action.text) {
public void onClick(int x, int y, int mouseButton) {
//optionally you could also pass x,y,etc to ButtonListener
action.clicked(context);
}
};
buttonGroup.add(btn);
}
If your button click logic is complex, you might want to move it to new classes (using a command design pattern or something similar). Perhaps it would be implemented by passing the listener to the enum constructor, rather than overriding the enum.
For an entire example of how it might look in LibGDX, see below:
(As you can see, you don’t need to make your own input handler, or button, or layout classes… very easy!)
The result looks something like this: