patternjavaMinor
Take These Buttons Back
Viewed 0 times
takethesebackbuttons
Problem
I created a side bar of buttons for my game, the idea being that if you click on the "main" button of the group, the rest of the buttons in the group would pop out from the side of the screen.
Later, I wanted to make it so that if you open one of the side menus the other ones would close. I thought about implementing some booleans and methods that would iterate through the tables that comprised the side bar, closing them if they were open and were not the table associated with the button that the player clicked. Instead I made something a little more object oriented.
One complication here was that I needed some special logic to be called when only one of these buttons was clicked, specifically the Overlay button. When closed, I wanted any open color overlays to be automatically switched off, so that the player doesn't need to open up the menu again to switch it off.
Here are the buttons in action:
SideButtonSlider.java
```
public class SideButtonSlider {
private Table table;
//private float stageWidth;
private float stageHeight;
private GameScreen screen;
private boolean isOpen;
public SideButtonSlider(ArrayListbuttons, GameScreen screen, Skin skin, String name, Color color, float stageWidth, float stageHeight) {
this.table = new Table(skin);
//this.stageWidth = stageWidth;
this.stageHeight = stageHeight;
this.screen = screen;
Table buttonTable = new Table();
buttonTable.defaults().pad(5).width(stageHeight/9).height(stageHeight/18).fill();
buttonTable.setFillParent(true);
for (Button button : buttons) {
buttonTable.add(button);
buttonTable.row();
}
this.table.add(buttonTable);
TextButton toggleButton = new TextButton(name, skin);
toggleButton.setColor(color);
toggleButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Later, I wanted to make it so that if you open one of the side menus the other ones would close. I thought about implementing some booleans and methods that would iterate through the tables that comprised the side bar, closing them if they were open and were not the table associated with the button that the player clicked. Instead I made something a little more object oriented.
One complication here was that I needed some special logic to be called when only one of these buttons was clicked, specifically the Overlay button. When closed, I wanted any open color overlays to be automatically switched off, so that the player doesn't need to open up the menu again to switch it off.
Here are the buttons in action:
SideButtonSlider.java
```
public class SideButtonSlider {
private Table table;
//private float stageWidth;
private float stageHeight;
private GameScreen screen;
private boolean isOpen;
public SideButtonSlider(ArrayListbuttons, GameScreen screen, Skin skin, String name, Color color, float stageWidth, float stageHeight) {
this.table = new Table(skin);
//this.stageWidth = stageWidth;
this.stageHeight = stageHeight;
this.screen = screen;
Table buttonTable = new Table();
buttonTable.defaults().pad(5).width(stageHeight/9).height(stageHeight/18).fill();
buttonTable.setFillParent(true);
for (Button button : buttons) {
buttonTable.add(button);
buttonTable.row();
}
this.table.add(buttonTable);
TextButton toggleButton = new TextButton(name, skin);
toggleButton.setColor(color);
toggleButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Solution
You can literally use the builder pattern for your Builder game here. :)
See, you have group of buttons that must be assigned a same color. These buttons have a corresponding pair of button label and a
In my opinion, the benefits of the builder pattern is that it lets you specify any common parameters once to minimize code repetition (and therefore bugs), and enforces the requirements for creating the necessary instances consistently too. In the long run, it also lets you introduce new features or fix bugs all in one go. Furthermore, builder classes tend to adopt the 'fluent' programming approach by using more descriptive sounding method names and
An example usage will be:
You can even opt to daisy-chain the entire thing, from
Just two more things to highlight from my code above:
My personal opinion is that
Declarations should be done with the interfaces, rather than the concrete implementation. This lets users of your variables simply use them as they are defined by the interface methods, rather than the exact type of implementing class. Therefore, I will suggest
See, you have group of buttons that must be assigned a same color. These buttons have a corresponding pair of button label and a
ClickListener implementation. Therefore, it's not hard to imagine a Builder implementation that lets you chain these operations:public final class SideButtonSliderBuilder {
private final GameScreen screen;
private final Skin skin;
private final String groupLabel;
private final Color color;
private final List labels = new ArrayList();
private final List listeners = new ArrayList();
private SideButtonSliderBuilder(GameScreen screen, Skin skin,
String groupLabel, Color color) {
this.screen = screen;
this.skin = skin;
this.groupLabel = groupLabel;
this.color = color;
}
public SideButtonSliderBuilder addButton(String label, ClickListener listener) {
// remember null checks too, just in case
labels.add(label);
listeners.add(listener);
return this;
}
private TextButton toButton(String label, ClickListener listener) {
// since this is a private method, null checks are probably optional
TextButton button = new TextButton(label, skin);
button.setColor(color);
button.addListener(listener);
return button;
}
private List toList() {
List list = new ArrayList(labels.size());
for (Iterator labelIterator = labels.iterator(),
Iterator listenerIterator = listeners.iterator();
labelIterator.hasNext() && listenerIterator().hasNext();) {
list.add(toButton(labelIterator.next(), listenrIterator.next()));
}
return list;
}
public SideButtonSlider build() {
// take note of List vs ArrayList, see below
return new SideButtonSlider(toList(), screen, skin, groupLabel, color,
LibGDXGame.STAGE_WIDTH, LibGDXGame.STAGE_HEIGHT);
}
public static SideButtonSliderBuilder of(GameScreen screen, Skin skin,
String groupLabel, Color color) {
return new SideButtonSliderBuilder(screen, skin, groupLabel, color);
}
}In my opinion, the benefits of the builder pattern is that it lets you specify any common parameters once to minimize code repetition (and therefore bugs), and enforces the requirements for creating the necessary instances consistently too. In the long run, it also lets you introduce new features or fix bugs all in one go. Furthermore, builder classes tend to adopt the 'fluent' programming approach by using more descriptive sounding method names and
return-ing itself, thereby allowing for daisy-chaining.An example usage will be:
// inside your GameScene class
SideButtonSliderBuilder cameraBuilder = SideButtonSliderBuilder.of(this, this.skin,
"Camera", Color.YELLOW);
cameraBuilder.addButton("Clip", /* clip listener */)
.addButton("Zoom", /* zoom listener */);
this.cameraSlider = cameraBuilder.build();You can even opt to daisy-chain the entire thing, from
of() to calling build().Just two more things to highlight from my code above:
// since this is a private method, null checks are probably optionalMy personal opinion is that
private methods can be less... particular about null inputs, as you should be trusting enough of yourself/your team that you aren't introducing them in the first place. This is more true, I hope, when the method calling the private method is right next to it, such that there is even lesser concern that nulls will be introduced.// take note of List vs ArrayList, see belowDeclarations should be done with the interfaces, rather than the concrete implementation. This lets users of your variables simply use them as they are defined by the interface methods, rather than the exact type of implementing class. Therefore, I will suggest
List list = new ArrayList().Code Snippets
public final class SideButtonSliderBuilder {
private final GameScreen screen;
private final Skin skin;
private final String groupLabel;
private final Color color;
private final List<String> labels = new ArrayList<String>();
private final List<ClickListener> listeners = new ArrayList<String>();
private SideButtonSliderBuilder(GameScreen screen, Skin skin,
String groupLabel, Color color) {
this.screen = screen;
this.skin = skin;
this.groupLabel = groupLabel;
this.color = color;
}
public SideButtonSliderBuilder addButton(String label, ClickListener listener) {
// remember null checks too, just in case
labels.add(label);
listeners.add(listener);
return this;
}
private TextButton toButton(String label, ClickListener listener) {
// since this is a private method, null checks are probably optional
TextButton button = new TextButton(label, skin);
button.setColor(color);
button.addListener(listener);
return button;
}
private List<TextButton> toList() {
List<TextButton> list = new ArrayList<TextButton>(labels.size());
for (Iterator<String> labelIterator = labels.iterator(),
Iterator<ClickListener> listenerIterator = listeners.iterator();
labelIterator.hasNext() && listenerIterator().hasNext();) {
list.add(toButton(labelIterator.next(), listenrIterator.next()));
}
return list;
}
public SideButtonSlider build() {
// take note of List vs ArrayList, see below
return new SideButtonSlider(toList(), screen, skin, groupLabel, color,
LibGDXGame.STAGE_WIDTH, LibGDXGame.STAGE_HEIGHT);
}
public static SideButtonSliderBuilder of(GameScreen screen, Skin skin,
String groupLabel, Color color) {
return new SideButtonSliderBuilder(screen, skin, groupLabel, color);
}
}// inside your GameScene class
SideButtonSliderBuilder cameraBuilder = SideButtonSliderBuilder.of(this, this.skin,
"Camera", Color.YELLOW);
cameraBuilder.addButton("Clip", /* clip listener */)
.addButton("Zoom", /* zoom listener */);
this.cameraSlider = cameraBuilder.build();Context
StackExchange Code Review Q#96495, answer score: 5
Revisions (0)
No revisions yet.