Code clean up

This commit is contained in:
Lonami Exo 2017-01-30 21:36:45 +01:00
parent 6cff9d5968
commit 43f4ca68c6
15 changed files with 558 additions and 279 deletions

View file

@ -11,10 +11,16 @@ import io.github.lonamiwebs.klooni.screens.MainMenuScreen;
public class Klooni extends Game { public class Klooni extends Game {
//region Members
// TODO Not sure whether the theme should be static or not since it might load textures // TODO Not sure whether the theme should be static or not since it might load textures
public static Theme theme; public static Theme theme;
public Skin skin; public Skin skin;
//endregion
//region Creation
@Override @Override
public void create() { public void create() {
prefs = Gdx.app.getPreferences("io.github.lonamiwebs.klooni.game"); prefs = Gdx.app.getPreferences("io.github.lonamiwebs.klooni.game");
@ -51,11 +57,19 @@ public class Klooni extends Game {
setScreen(new MainMenuScreen(this)); setScreen(new MainMenuScreen(this));
} }
//endregion
//region Screen
@Override @Override
public void render() { public void render() {
super.render(); super.render();
} }
//endregion
//region Disposing
@Override @Override
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
@ -63,6 +77,8 @@ public class Klooni extends Game {
theme.dispose(); theme.dispose();
} }
//endregion
//region Settings //region Settings
private static Preferences prefs; private static Preferences prefs;

View file

@ -10,8 +10,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.JsonReader; import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue; import com.badlogic.gdx.utils.JsonValue;
// Represents a Theme for the current game.
// These are loaded from external files, so more
// can be easily added
public class Theme { public class Theme {
//region Members
private String displayName; private String displayName;
private String name; private String name;
private int price; private int price;
@ -23,19 +28,28 @@ public class Theme {
public NinePatch cellPatch; public NinePatch cellPatch;
// Save the button styles so the changes here get reflected
private ImageButton.ImageButtonStyle[] buttonStyles; private ImageButton.ImageButtonStyle[] buttonStyles;
//endregion
//region Constructor
private Theme() { private Theme() {
buttonStyles = new ImageButton.ImageButtonStyle[4]; buttonStyles = new ImageButton.ImageButtonStyle[4];
} }
//endregion
//region Static methods
// Gets all the available themes on the available on the internal game storage
public static Theme[] getThemes() { public static Theme[] getThemes() {
FileHandle[] handles = Gdx.files.internal("themes").list(); FileHandle[] handles = Gdx.files.internal("themes").list();
Theme[] result = new Theme[handles.length]; Theme[] result = new Theme[handles.length];
for (int i = 0; i < handles.length; i++) { for (int i = 0; i < handles.length; i++)
result[i] = Theme.fromFile(handles[i]); result[i] = Theme.fromFile(handles[i]);
}
return result; return result;
} }
@ -48,6 +62,11 @@ public class Theme {
return new Theme().update(handle); return new Theme().update(handle);
} }
//endregion
//region Theme updating
// Updates the theme with all the values from the specified file or name
public Theme update(final String name) { public Theme update(final String name) {
return update(Gdx.files.internal("themes/"+name+".theme")); return update(Gdx.files.internal("themes/"+name+".theme"));
} }
@ -93,6 +112,14 @@ public class Theme {
return this; return this;
} }
//endregion
//region Applying the theme
public String getName() {
return name;
}
public ImageButton.ImageButtonStyle getStyle(int button) { public ImageButton.ImageButtonStyle getStyle(int button) {
return buttonStyles[button]; return buttonStyles[button];
} }
@ -101,20 +128,22 @@ public class Theme {
return cells[colorIndex]; return cells[colorIndex];
} }
void dispose() {
}
public void glClearBackground() { public void glClearBackground() {
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a); Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
} }
public String getName() {
return name;
}
public void updateStyle(ImageButton.ImageButtonStyle style, int styleIndex) { public void updateStyle(ImageButton.ImageButtonStyle style, int styleIndex) {
style.imageUp = buttonStyles[styleIndex].imageUp; style.imageUp = buttonStyles[styleIndex].imageUp;
style.imageDown = buttonStyles[styleIndex].imageDown; style.imageDown = buttonStyles[styleIndex].imageDown;
} }
//endregion
//region Disposal
void dispose() {
}
//endregion
} }

View file

@ -15,21 +15,28 @@ import com.badlogic.gdx.utils.Align;
import io.github.lonamiwebs.klooni.game.GameLayout; import io.github.lonamiwebs.klooni.game.GameLayout;
import io.github.lonamiwebs.klooni.game.Scorer; import io.github.lonamiwebs.klooni.game.Scorer;
// Score and pause menu band actually // Horizontal band, used to show the score on the pause menu
public class Band extends Actor { public class Band extends Actor {
//region Members
private final Scorer scorer; private final Scorer scorer;
private final Texture bandTexture; private final Texture bandTexture;
public final Rectangle scoreBounds; public final Rectangle scoreBounds;
public final Rectangle infoBounds; public final Rectangle infoBounds;
public final Label infoLabel; private final Label infoLabel;
public final Label scoreLabel; private final Label scoreLabel;
public Band(final GameLayout layout, final Scorer aScorer, final Color bandColor) { //endregion
scorer = aScorer;
//region Constructor
public Band(final GameLayout layout, final Scorer scorer, final Color bandColor) {
this.scorer = scorer;
// A 1x1 pixel map will be enough since the band texture will then be expanded
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(bandColor); pixmap.setColor(bandColor);
pixmap.fill(); pixmap.fill();
@ -49,9 +56,9 @@ public class Band extends Actor {
layout.update(this); layout.update(this);
} }
public void setGameOver() { //endregion
infoLabel.setText("no moves left");
} //region Public methods
@Override @Override
public void draw(Batch batch, float parentAlpha) { public void draw(Batch batch, float parentAlpha) {
@ -70,4 +77,11 @@ public class Band extends Actor {
infoLabel.setBounds(x + infoBounds.x, y + infoBounds.y, infoBounds.width, infoBounds.height); infoLabel.setBounds(x + infoBounds.x, y + infoBounds.y, infoBounds.width, infoBounds.height);
infoLabel.draw(batch, parentAlpha); infoLabel.draw(batch, parentAlpha);
} }
// Once game over is set on the menu, it cannot be reverted
public void setGameOver() {
infoLabel.setText("no moves left");
}
//endregion
} }

View file

@ -7,11 +7,18 @@ import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
import io.github.lonamiwebs.klooni.Theme; import io.github.lonamiwebs.klooni.Theme;
// Small wrapper to use themed image buttons more easily
public class SoftButton extends ImageButton { public class SoftButton extends ImageButton {
//region Members
private int styleIndex; private int styleIndex;
private Drawable image; private Drawable image;
//endregion
//region Constructor
public SoftButton(int styleIndex, String imageName) { public SoftButton(int styleIndex, String imageName) {
super(Klooni.theme.getStyle(styleIndex)); super(Klooni.theme.getStyle(styleIndex));
@ -19,13 +26,22 @@ public class SoftButton extends ImageButton {
image = Theme.skin.getDrawable(imageName); image = Theme.skin.getDrawable(imageName);
} }
//endregion
//region Public methods
@Override @Override
public void draw(Batch batch, float parentAlpha) { public void draw(Batch batch, float parentAlpha) {
// Always update the style to make sure we're using the right colors // Always update the style to make sure we're using the right image.
// This might not always be the case since two buttons can be using
// the "same" style (except for the image up, i.e. after coming from
// the customize menu), so make sure to update it always.
ImageButtonStyle style = getStyle(); ImageButtonStyle style = getStyle();
Klooni.theme.updateStyle(style, styleIndex); Klooni.theme.updateStyle(style, styleIndex);
style.imageUp = image; style.imageUp = image;
super.draw(batch, parentAlpha); super.draw(batch, parentAlpha);
} }
//endregion
} }

View file

@ -1,6 +1,5 @@
package io.github.lonamiwebs.klooni.actors; package io.github.lonamiwebs.klooni.actors;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
@ -11,12 +10,20 @@ import io.github.lonamiwebs.klooni.Theme;
import io.github.lonamiwebs.klooni.game.Cell; import io.github.lonamiwebs.klooni.game.Cell;
import io.github.lonamiwebs.klooni.game.GameLayout; import io.github.lonamiwebs.klooni.game.GameLayout;
// Card-like actor used to display information about a given theme
public class ThemeCard extends Actor { public class ThemeCard extends Actor {
//region Members
public final Theme theme; public final Theme theme;
private final Texture background; private final Texture background;
//endregion
//region Constructor
public ThemeCard(final GameLayout layout, final Theme theme) { public ThemeCard(final GameLayout layout, final Theme theme) {
// A 1x1 pixel map will be enough, the background texture will then be stretched accordingly
// TODO We could also use white color and then batch.setColor(theme.background) // TODO We could also use white color and then batch.setColor(theme.background)
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(theme.background); pixmap.setColor(theme.background);
@ -26,11 +33,12 @@ public class ThemeCard extends Actor {
this.theme = theme; this.theme = theme;
layout.update(this); layout.update(this);
setWidth(Gdx.graphics.getWidth());
setScaleX(200);
} }
//endregion
//region Public methods
@Override @Override
public void draw(Batch batch, float parentAlpha) { public void draw(Batch batch, float parentAlpha) {
final float x = getX(), y = getY(); final float x = getX(), y = getY();
@ -55,4 +63,6 @@ public class ThemeCard extends Actor {
Cell.draw(theme.getCellColor(8), batch, x + cellSize * 2, y + cellSize * 3, cellSize); Cell.draw(theme.getCellColor(8), batch, x + cellSize * 2, y + cellSize * 3, cellSize);
Cell.draw(theme.getCellColor(3), batch, x + cellSize * 3, y + cellSize * 3, cellSize); Cell.draw(theme.getCellColor(3), batch, x + cellSize * 3, y + cellSize * 3, cellSize);
} }
//endregion
} }

View file

@ -8,18 +8,26 @@ import com.badlogic.gdx.math.Vector2;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
// Represents the on screen board, with all the put cells
// and functions to determine when it is game over given a PieceHolder
public class Board { public class Board {
Cell[][] cells; //region Members
public final int cellCount; public final int cellCount;
public float cellSize; public float cellSize;
private Cell[][] cells;
private final Vector2 lastPutPiecePos; // Used to animate cleared cells vanishing
final Vector2 pos; final Vector2 pos;
private final Sound stripClearSound; private final Sound stripClearSound;
// Used to animate cleared cells vanishing
private final Vector2 lastPutPiecePos;
//endregion
//region Constructor
public Board(final GameLayout layout, int cellCount) { public Board(final GameLayout layout, int cellCount) {
this.cellCount = cellCount; this.cellCount = cellCount;
@ -27,9 +35,9 @@ public class Board {
lastPutPiecePos = new Vector2(); lastPutPiecePos = new Vector2();
pos = new Vector2(); pos = new Vector2();
layout.update(this);
// Cell size depends on the layout to be updated // Cell size depends on the layout to be updated first
layout.update(this);
cells = new Cell[this.cellCount][this.cellCount]; cells = new Cell[this.cellCount][this.cellCount];
for (int i = 0; i < this.cellCount; i++) { for (int i = 0; i < this.cellCount; i++) {
for (int j = 0; j < this.cellCount; j++) { for (int j = 0; j < this.cellCount; j++) {
@ -39,14 +47,21 @@ public class Board {
} }
} }
//endregion
//region Private methods
// True if the given cell coordinates are inside the bounds of the board
private boolean inBounds(int x, int y) { private boolean inBounds(int x, int y) {
return x >= 0 && x < cellCount && y >= 0 && y < cellCount; return x >= 0 && x < cellCount && y >= 0 && y < cellCount;
} }
// True if the given piece at the given coordinates is not outside the bounds of the board
private boolean inBounds(Piece piece, int x, int y) { private boolean inBounds(Piece piece, int x, int y) {
return inBounds(x, y) && inBounds(x + piece.cellCols - 1, y + piece.cellRows - 1); return inBounds(x, y) && inBounds(x + piece.cellCols - 1, y + piece.cellRows - 1);
} }
// This only tests for the piece on the given coordinates, not the whole board
private boolean canPutPiece(Piece piece, int x, int y) { private boolean canPutPiece(Piece piece, int x, int y) {
if (!inBounds(piece, x, y)) if (!inBounds(piece, x, y))
return false; return false;
@ -59,39 +74,64 @@ public class Board {
return true; return true;
} }
public boolean canPutPiece(Piece piece) { // Returns true iff the piece was put on the board
for (int i = 0; i < cellCount; i++) { private boolean putPiece(Piece piece, int x, int y) {
for (int j = 0; j < cellCount; j++) { if (!canPutPiece(piece, x, y))
if (canPutPiece(piece, j, i)) { return false;
return true;
lastPutPiecePos.set(piece.calculateGravityCenter());
for (int i = 0; i < piece.cellRows; i++) {
for (int j = 0; j < piece.cellCols; j++) {
if (piece.filled(i, j)) {
cells[y+i][x+j].set(piece.color);
} }
} }
} }
return true;
}
//endregion
//region Public methods
public void draw(SpriteBatch batch) {
for (int i = 0; i < cellCount; i++)
for (int j = 0; j < cellCount; j++)
cells[i][j].draw(batch);
}
public boolean canPutPiece(Piece piece) {
for (int i = 0; i < cellCount; i++)
for (int j = 0; j < cellCount; j++)
if (canPutPiece(piece, j, i))
return true;
return false; return false;
} }
public boolean putScreenPiece(Piece piece) { boolean putScreenPiece(Piece piece) {
// Get the local piece coordinates // Convert the on screen coordinates of the piece to the local-board-space coordinates
// TODO Works weird, it puts the piece like one too low // This is done by subtracting the piece coordinates from the board coordinates
Vector2 local = piece.pos.cpy().sub(pos); Vector2 local = piece.pos.cpy().sub(pos);
int x = MathUtils.round(local.x / piece.cellSize); int x = MathUtils.round(local.x / piece.cellSize);
int y = MathUtils.round(local.y / piece.cellSize); int y = MathUtils.round(local.y / piece.cellSize);
return putPiece(piece, x, y); return putPiece(piece, x, y);
} }
// This will clear both complete rows and columns, all at once.
// The reason why we can't check first rows and then columns
// (or vice versa) is because the following case (* filled, _ empty):
//
// 4x4 boardHeight piece
// _ _ * * * *
// _ * * * *
// * * _ _
// * * _ _
//
// If the piece is put on the top left corner, all the cells will be cleared.
// If we first cleared the columns, then the rows wouldn't have been cleared.
public int clearComplete() { public int clearComplete() {
// This will clear both complete rows and columns, all at once.
// The reason why we can't check first rows and then columns
// (or vice versa) is because the following case (* filled, _ empty):
//
// 4x4 boardHeight piece
// _ _ * * * *
// _ * * * *
// * * _ _
// * * _ _
//
// If the piece is put on the top left corner, all the cells will be cleared.
// If we first cleared the columns, then the rows wouldn't have been cleared.
int clearCount = 0; int clearCount = 0;
boolean[] clearedRows = new boolean[cellCount]; boolean[] clearedRows = new boolean[cellCount];
boolean[] clearedCols = new boolean[cellCount]; boolean[] clearedCols = new boolean[cellCount];
@ -123,13 +163,11 @@ public class Board {
float pan = 0; float pan = 0;
// Do clear those rows and columns // Do clear those rows and columns
for (int i = 0; i < cellCount; i++) { for (int i = 0; i < cellCount; i++)
if (clearedRows[i]) { if (clearedRows[i])
for (int j = 0; j < cellCount; j++) { for (int j = 0; j < cellCount; j++)
cells[i][j].vanish(lastPutPiecePos); cells[i][j].vanish(lastPutPiecePos);
}
}
}
for (int j = 0; j < cellCount; j++) { for (int j = 0; j < cellCount; j++) {
if (clearedCols[j]) { if (clearedCols[j]) {
pan += 2f * (j - cellCount / 2) / (float)cellCount; pan += 2f * (j - cellCount / 2) / (float)cellCount;
@ -150,27 +188,5 @@ public class Board {
return clearCount; return clearCount;
} }
public boolean putPiece(Piece piece, int x, int y) { //endregion
if (!canPutPiece(piece, x, y))
return false;
lastPutPiecePos.set(piece.calculateGravityCenter());
for (int i = 0; i < piece.cellRows; i++) {
for (int j = 0; j < piece.cellCols; j++) {
if (piece.filled(i, j)) {
cells[y+i][x+j].set(piece.color);
}
}
}
return true;
}
public void draw(SpriteBatch batch) {
for (int i = 0; i < cellCount; i++) {
for (int j = 0; j < cellCount; j++) {
cells[i][j].draw(batch);
}
}
}
} }

View file

@ -9,19 +9,27 @@ import com.badlogic.gdx.math.Vector2;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
// Represents a single cell, with a position, size and color.
// Instances will use the cell texture provided by the currently used skin.
public class Cell { public class Cell {
//region Members
private boolean empty; private boolean empty;
private Color color; private Color color;
Vector2 pos; private Vector2 pos;
float size; private float size;
private Color vanishColor; private Color vanishColor;
private float vanishSize; private float vanishSize;
private float vanishElapsed; private float vanishElapsed;
private float vanishLifetime; private float vanishLifetime;
//endregion
//region Constructor
Cell(float x, float y, float cellSize) { Cell(float x, float y, float cellSize) {
pos = new Vector2(x, y); pos = new Vector2(x, y);
size = cellSize; size = cellSize;
@ -31,6 +39,11 @@ public class Cell {
vanishElapsed = Float.POSITIVE_INFINITY; vanishElapsed = Float.POSITIVE_INFINITY;
} }
//endregion
//region Package local methods
// Sets the cell to be non-empty and of the specified color
void set(Color c) { void set(Color c) {
empty = false; empty = false;
color = c; color = c;
@ -54,20 +67,9 @@ public class Cell {
} }
} }
// TODO Use skin atlas
public static void draw(Color color, Batch batch,
float x, float y, float size) {
batch.setColor(color);
Klooni.theme.cellPatch.draw(batch, x, y, size, size);
}
boolean isEmpty() {
return empty;
}
// Vanish from indicates the point which caused the vanishing to happen, // Vanish from indicates the point which caused the vanishing to happen,
// in this case, a piece was put. The closer it was put, the faster // in this case, a piece was put. The closer it was put, the faster
// this piece will vanish. // this piece will vanish. This immediately marks the piece as empty.
void vanish(Vector2 vanishFrom) { void vanish(Vector2 vanishFrom) {
if (empty) // We cannot vanish twice if (empty) // We cannot vanish twice
return; return;
@ -90,4 +92,21 @@ public class Cell {
color = Color.WHITE; color = Color.WHITE;
} }
boolean isEmpty() {
return empty;
}
//endregion
//region Static methods
// TODO Use skin atlas
public static void draw(Color color, Batch batch,
float x, float y, float size) {
batch.setColor(color);
Klooni.theme.cellPatch.draw(batch, x, y, size, size);
}
//endregion
} }

View file

@ -13,32 +13,47 @@ import io.github.lonamiwebs.klooni.actors.ThemeCard;
// For example, the boardHeight on the left and the piece holder on the right // For example, the boardHeight on the left and the piece holder on the right
public class GameLayout { public class GameLayout {
// Widths //region Members
private float screenWidth, marginWidth, availableWidth;
// Heights private float screenWidth, marginWidth, availableWidth;
private float screenHeight, logoHeight, scoreHeight, boardHeight, pieceHolderHeight; private float scoreHeight, boardHeight, pieceHolderHeight;
//endregion
//region Constructor
public GameLayout() { public GameLayout() {
calculate(); calculate();
} }
//endregion
//region Private methods
private void calculate() { private void calculate() {
screenWidth = Gdx.graphics.getWidth(); screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight(); float screenHeight = Gdx.graphics.getHeight();
// Widths // Widths
marginWidth = screenWidth * 0.05f; marginWidth = screenWidth * 0.05f;
availableWidth = screenWidth - marginWidth * 2f; availableWidth = screenWidth - marginWidth * 2f;
// Heights // Heights
logoHeight = screenHeight * 0.10f; // logoHeight = screenHeight * 0.10f; // Unused
scoreHeight = screenHeight * 0.15f; scoreHeight = screenHeight * 0.15f;
boardHeight = screenHeight * 0.50f; boardHeight = screenHeight * 0.50f;
pieceHolderHeight = screenHeight * 0.25f; pieceHolderHeight = screenHeight * 0.25f;
} }
// Note that we're now using Y-up coordinates //endregion
//region Update layout methods
// These methods take any of the custom objects used in the game
// and positions them accordingly on the screen, by using relative
// coordinates. Since these objects are not actors and we cannot
// add them to a table (and would probably be harder), this approach
// was used. Note that all these are using Y-up coordinates.
void update(Scorer scorer) { void update(Scorer scorer) {
float cupSize = Math.min(scoreHeight, scorer.cupTexture.getHeight()); float cupSize = Math.min(scoreHeight, scorer.cupTexture.getHeight());
final Rectangle area = new Rectangle( final Rectangle area = new Rectangle(
@ -94,4 +109,6 @@ public class GameLayout {
public void update(ThemeCard card) { public void update(ThemeCard card) {
card.setSize(availableWidth - marginWidth, scoreHeight); card.setSize(availableWidth - marginWidth, scoreHeight);
} }
//endregion
} }

View file

@ -8,18 +8,31 @@ import com.badlogic.gdx.math.Vector2;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
// Pieces can be L shaped and be rotated 0 to 3 times to make it random // Represents a piece with an arbitrary shape, which
// Maximum cellSize = 4 // can be either rectangles (squares too) or L shaped
// with any rotation.
public class Piece { public class Piece {
//region Members
final Vector2 pos; final Vector2 pos;
float cellSize = 10f; // Default final Color color;
final int cellCols, cellRows; final int cellCols, cellRows;
private boolean shape[][]; private boolean shape[][];
final Color color; // Default arbitrary value
float cellSize = 10f;
//endregion
//region Constructors
// Rectangle-shaped constructor
//
// If swapSize is true, the rows and columns will be swapped.
// colorIndex represents a random index that will be used
// to determine the color of this piece when drawn on the screen.
private Piece(int cols, int rows, boolean swapSize, int colorIndex) { private Piece(int cols, int rows, boolean swapSize, int colorIndex) {
color = Klooni.theme.getCellColor(colorIndex); color = Klooni.theme.getCellColor(colorIndex);
@ -34,6 +47,7 @@ public class Piece {
} }
} }
// L-shaped constructor
private Piece(int lSize, int rotateCount, int colorIndex) { private Piece(int lSize, int rotateCount, int colorIndex) {
color = Klooni.theme.getCellColor(colorIndex); color = Klooni.theme.getCellColor(colorIndex);
@ -68,11 +82,12 @@ public class Piece {
} }
} }
boolean filled(int i, int j) { //endregion
return shape[i][j];
}
public static Piece random() { //region Static methods
// Generates a random piece with always the same color for the generated shape
static Piece random() {
int color = MathUtils.random(8); // 9 pieces int color = MathUtils.random(8); // 9 pieces
switch (color) { switch (color) {
// Squares // Squares
@ -93,10 +108,28 @@ public class Piece {
throw new RuntimeException("Random function is broken."); throw new RuntimeException("Random function is broken.");
} }
//endregion
//region Package local methods
void draw(SpriteBatch batch) {
for (int i = 0; i < cellRows; i++)
for (int j = 0; j < cellCols; j++)
if (shape[i][j])
Cell.draw(color, batch, pos.x + j * cellSize, pos.y + i * cellSize, cellSize);
}
// Calculates the rectangle of the piece with screen coordinates
Rectangle getRectangle() { Rectangle getRectangle() {
return new Rectangle(pos.x, pos.y, cellCols * cellSize, cellRows * cellSize); return new Rectangle(pos.x, pos.y, cellCols * cellSize, cellRows * cellSize);
} }
// Determines whether the shape is filled on the given row and column
boolean filled(int i, int j) {
return shape[i][j];
}
// Calculates the area occupied by the shape
int calculateArea() { int calculateArea() {
int area = 0; int area = 0;
for (int i = 0; i < cellRows; i++) { for (int i = 0; i < cellRows; i++) {
@ -109,6 +142,7 @@ public class Piece {
return area; return area;
} }
// Calculates the gravity center of the piece shape
Vector2 calculateGravityCenter() { Vector2 calculateGravityCenter() {
int filledCount = 0; int filledCount = 0;
Vector2 result = new Vector2(); Vector2 result = new Vector2();
@ -125,14 +159,5 @@ public class Piece {
return result.scl(1f / filledCount); return result.scl(1f / filledCount);
} }
void draw(SpriteBatch batch) { //endregion
for (int i = 0; i < cellRows; i++) {
for (int j = 0; j < cellCols; j++) {
if (shape[i][j]) {
Cell.draw(color, batch,
pos.x + j * cellSize, pos.y + i * cellSize, cellSize);
}
}
}
}
} }

View file

@ -11,28 +11,43 @@ import com.badlogic.gdx.utils.Array;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
// A holder of pieces that can be drawn on screen.
// Pieces can be picked up from it and dropped on a board.
public class PieceHolder { public class PieceHolder {
//region Members
final Rectangle area;
private final Piece[] pieces; private final Piece[] pieces;
private final Rectangle[] originalPositions; // Needed after a piece is dropped
private final Sound pieceDropSound; private final Sound pieceDropSound;
private final Sound invalidPieceDropSound; private final Sound invalidPieceDropSound;
private final Sound takePiecesSound; private final Sound takePiecesSound;
// Count of pieces to be shown
private final int count; private final int count;
// Currently held piece index (picked by the user)
private int heldPiece; private int heldPiece;
final Rectangle area; // Needed after a piece is dropped, so it can go back
private final Rectangle[] originalPositions;
// The size the cells will adopt once picked // The size the cells will adopt once picked
private final float pickedCellSize; private final float pickedCellSize;
//endregion
//region Static members
public static final int NO_DROP = 0; public static final int NO_DROP = 0;
public static final int NORMAL_DROP = 1; public static final int NORMAL_DROP = 1;
public static final int ON_BOARD_DROP = 2; public static final int ON_BOARD_DROP = 2;
//endregion
//region Constructor
public PieceHolder(final GameLayout layout, final int pieceCount, final float pickedCellSize) { public PieceHolder(final GameLayout layout, final int pieceCount, final float pickedCellSize) {
count = pieceCount; count = pieceCount;
pieces = new Piece[count]; pieces = new Piece[count];
@ -53,7 +68,21 @@ public class PieceHolder {
takeMore(); takeMore();
} }
void takeMore() { //endregion
//region Private methods
// Determines whether all the pieces have been put (and the "hand" is finished)
private boolean handFinished() {
for (int i = 0; i < count; i++)
if (pieces[i] != null)
return false;
return true;
}
// Takes a new set of pieces. Should be called when there are no more piece left
private void takeMore() {
float perPieceWidth = area.width / count; float perPieceWidth = area.width / count;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
pieces[i] = Piece.random(); pieces[i] = Piece.random();
@ -85,15 +114,11 @@ public class PieceHolder {
} }
} }
boolean handFinished() { //endregion
for (int i = 0; i < count; i++)
if (pieces[i] != null)
return false;
return true; //region Public methods
}
// Pick the piece below the finger/mouse // Picks the piece below the finger/mouse, returning true if any was picked
public boolean pickPiece() { public boolean pickPiece() {
Vector2 mouse = new Vector2( Vector2 mouse = new Vector2(
Gdx.input.getX(), Gdx.input.getX(),
@ -112,23 +137,20 @@ public class PieceHolder {
public Array<Piece> getAvailablePieces() { public Array<Piece> getAvailablePieces() {
Array<Piece> result = new Array<Piece>(count); Array<Piece> result = new Array<Piece>(count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++)
if (pieces[i] != null) { if (pieces[i] != null)
result.add(pieces[i]); result.add(pieces[i]);
}
}
return result; return result;
} }
// If no piece is currently being held, the area will be 0
public int calculateHeldPieceArea() { public int calculateHeldPieceArea() {
if (heldPiece > -1) { return heldPiece > -1 ? pieces[heldPiece].calculateArea() : 0;
return pieces[heldPiece].calculateArea();
} else {
return 0;
}
} }
// Returns one of the following: NO_DROP, NORMAL_DROP, ON_BOARD_DROP // Tries to drop the piece on the given board. As a result, it
// returns one of the following: NO_DROP, NORMAL_DROP, ON_BOARD_DROP
public int dropPiece(Board board) { public int dropPiece(Board board) {
if (heldPiece > -1) { if (heldPiece > -1) {
boolean put = board.putScreenPiece(pieces[heldPiece]); boolean put = board.putScreenPiece(pieces[heldPiece]);
@ -154,6 +176,7 @@ public class PieceHolder {
return NO_DROP; return NO_DROP;
} }
// Updates the state of the piece holder (and the held piece)
public void update() { public void update() {
Piece piece; Piece piece;
if (heldPiece > -1) { if (heldPiece > -1) {
@ -163,7 +186,7 @@ public class PieceHolder {
Gdx.input.getX(), Gdx.input.getX(),
Gdx.graphics.getHeight() - Gdx.input.getY()); // Y axis is inverted Gdx.graphics.getHeight() - Gdx.input.getY()); // Y axis is inverted
// Center the piece // Center the new piece position
mouse.sub(piece.getRectangle().width / 2, piece.getRectangle().height / 2); mouse.sub(piece.getRectangle().width / 2, piece.getRectangle().height / 2);
piece.pos.lerp(mouse, 0.4f); piece.pos.lerp(mouse, 0.4f);
@ -194,4 +217,6 @@ public class PieceHolder {
} }
} }
} }
//endregion
} }

View file

@ -13,13 +13,14 @@ import com.badlogic.gdx.utils.Align;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
// Used to keep track of the current and maximum
// score, and to also display it on the screen.
// The maximum score is NOT saved automatically.
public class Scorer { public class Scorer {
private int currentScore, maxScore; //region Members
private boolean newRecord;
private float shownScore; // To interpolate between shown score -> real score private int currentScore, maxScore;
private final int boardSize;
final Label currentScoreLabel; final Label currentScoreLabel;
final Label maxScoreLabel; final Label maxScoreLabel;
@ -27,10 +28,20 @@ public class Scorer {
final Texture cupTexture; final Texture cupTexture;
final Rectangle cupArea; final Rectangle cupArea;
public Scorer(GameLayout layout, int boardSize) { // If the currentScore beat the maxScore, then we have a new record
private boolean newRecord;
// To interpolate between shown score -> real score
private float shownScore;
//endregion
//region Constructor
// The board size is required when calculating the score
public Scorer(GameLayout layout) {
currentScore = 0; currentScore = 0;
maxScore = Klooni.getMaxScore(); maxScore = Klooni.getMaxScore();
this.boardSize = boardSize;
cupTexture = new Texture(Gdx.files.internal("ui/cup.png")); cupTexture = new Texture(Gdx.files.internal("ui/cup.png"));
cupArea = new Rectangle(); cupArea = new Rectangle();
@ -48,19 +59,39 @@ public class Scorer {
layout.update(this); layout.update(this);
} }
public void addPieceScore(int areaPut) { //endregion
addScore(areaPut);
}
public void addBoardScore(int stripsCleared) { //region Private methods
addScore(calculateClearScore(stripsCleared));
}
private void addScore(int score) { private void addScore(int score) {
currentScore += score; currentScore += score;
newRecord = currentScore > maxScore; newRecord = currentScore > maxScore;
} }
// The original game seems to work as follows:
// If < 1 were cleared, score = 0
// If = 1 was cleared, score = cells cleared
// If > 1 were cleared, score = cells cleared + score(cleared - 1)
private int calculateClearScore(int stripsCleared, int boardSize) {
if (stripsCleared < 1) return 0;
if (stripsCleared == 1) return boardSize;
else return boardSize * stripsCleared + calculateClearScore(stripsCleared - 1, boardSize);
}
//endregion
//region Public methods
// Adds the score a given piece would give
public void addPieceScore(int areaPut) {
addScore(areaPut);
}
// Adds the score given by the board, this is, the count of cleared strips
public void addBoardScore(int stripsCleared, int boardSize) {
addScore(calculateClearScore(stripsCleared, boardSize));
}
public int getCurrentScore() { public int getCurrentScore() {
return currentScore; return currentScore;
} }
@ -71,16 +102,6 @@ public class Scorer {
} }
} }
int calculateClearScore(int stripsCleared) {
// The original game seems to work as follows:
// If < 1 were cleared, score = 0
// If = 1 was cleared, score = cells cleared
// If > 1 were cleared, score = cells cleared + score(cleared - 1)
if (stripsCleared < 1) return 0;
if (stripsCleared == 1) return boardSize;
else return boardSize * stripsCleared + calculateClearScore(stripsCleared - 1);
}
public void draw(SpriteBatch batch) { public void draw(SpriteBatch batch) {
int roundShown = MathUtils.round(shownScore); int roundShown = MathUtils.round(shownScore);
if (roundShown != currentScore) { if (roundShown != currentScore) {
@ -93,4 +114,6 @@ public class Scorer {
currentScoreLabel.draw(batch, 1f); currentScoreLabel.draw(batch, 1f);
maxScoreLabel.draw(batch, 1f); maxScoreLabel.draw(batch, 1f);
} }
//endregion
} }

View file

@ -22,15 +22,29 @@ import io.github.lonamiwebs.klooni.actors.SoftButton;
import io.github.lonamiwebs.klooni.actors.ThemeCard; import io.github.lonamiwebs.klooni.actors.ThemeCard;
import io.github.lonamiwebs.klooni.game.GameLayout; import io.github.lonamiwebs.klooni.game.GameLayout;
public class CustomizeScreen implements Screen { // Screen where the user can customize the look and feel of the game
private Klooni game; class CustomizeScreen implements Screen {
//region Members
private Klooni game;
private Stage stage; private Stage stage;
public CustomizeScreen(Klooni aGame, final Screen lastScreen) { //endregion
//region Static members
// As the examples show on the LibGdx wiki
private static final float minDelta = 1/30f;
//endregion
//region Constructor
CustomizeScreen(Klooni game, final Screen lastScreen) {
final GameLayout layout = new GameLayout(); final GameLayout layout = new GameLayout();
game = aGame; this.game = game;
stage = new Stage(); stage = new Stage();
Table table = new Table(); Table table = new Table();
@ -45,7 +59,7 @@ public class CustomizeScreen implements Screen {
backButton.addListener(new ChangeListener() { backButton.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
game.setScreen(lastScreen); CustomizeScreen.this.game.setScreen(lastScreen);
dispose(); dispose();
} }
}); });
@ -59,7 +73,7 @@ public class CustomizeScreen implements Screen {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
Klooni.toggleSound(); Klooni.toggleSound();
soundButton.getStyle().imageUp = game.skin.getDrawable( soundButton.getStyle().imageUp = CustomizeScreen.this.game.skin.getDrawable(
Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture"); Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture");
} }
}); });
@ -86,8 +100,9 @@ public class CustomizeScreen implements Screen {
optionsGroup.addActor(webButton); optionsGroup.addActor(webButton);
table.add(new ScrollPane(optionsGroup)).pad(20, 4, 12, 4); table.add(new ScrollPane(optionsGroup)).pad(20, 4, 12, 4);
table.row();
// Load all the available themes
table.row();
VerticalGroup themesGroup = new VerticalGroup(); VerticalGroup themesGroup = new VerticalGroup();
for (Theme theme : Theme.getThemes()) { for (Theme theme : Theme.getThemes()) {
final ThemeCard card = new ThemeCard(layout, theme); final ThemeCard card = new ThemeCard(layout, theme);
@ -105,13 +120,15 @@ public class CustomizeScreen implements Screen {
table.add(new ScrollPane(themesGroup)).expand().fill(); table.add(new ScrollPane(themesGroup)).expand().fill();
} }
//endregion
//region Public methods
@Override @Override
public void show() { public void show() {
Gdx.input.setInputProcessor(stage); Gdx.input.setInputProcessor(stage);
} }
private static final float minDelta = 1/30f;
@Override @Override
public void render(float delta) { public void render(float delta) {
Klooni.theme.glClearBackground(); Klooni.theme.glClearBackground();
@ -130,23 +147,23 @@ public class CustomizeScreen implements Screen {
stage.getViewport().update(width, height, true); stage.getViewport().update(width, height, true);
} }
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
}
@Override @Override
public void dispose() { public void dispose() {
stage.dispose(); stage.dispose();
} }
//endregion
//region Empty methods
@Override
public void pause() { }
@Override
public void resume() { }
@Override
public void hide() { }
//endregion
} }

View file

@ -15,41 +15,58 @@ import io.github.lonamiwebs.klooni.game.Piece;
import io.github.lonamiwebs.klooni.game.PieceHolder; import io.github.lonamiwebs.klooni.game.PieceHolder;
import io.github.lonamiwebs.klooni.game.Scorer; import io.github.lonamiwebs.klooni.game.Scorer;
public class GameScreen implements Screen, InputProcessor { // Main game screen. Here the board, piece holder and score are shown
class GameScreen implements Screen, InputProcessor {
//region Members
private final Scorer scorer; private final Scorer scorer;
private Board board; private final Board board;
private PieceHolder holder; private final PieceHolder holder;
private final GameLayout layout; private final SpriteBatch batch;
private final Sound gameOverSound; private final Sound gameOverSound;
private SpriteBatch batch;
private final PauseMenuStage pauseMenu; private final PauseMenuStage pauseMenu;
//endregion
//region Static members
private final static int BOARD_SIZE = 10;
private final static int HOLDER_PIECE_COUNT = 3;
//endregion
//region Constructor
GameScreen(final Klooni game) { GameScreen(final Klooni game) {
batch = new SpriteBatch(); batch = new SpriteBatch();
layout = new GameLayout(); final GameLayout layout = new GameLayout();
scorer = new Scorer(layout);
scorer = new Scorer(layout, 10); board = new Board(layout, BOARD_SIZE);
board = new Board(layout, 10); holder = new PieceHolder(layout, HOLDER_PIECE_COUNT, board.cellSize);
holder = new PieceHolder(layout, 3, board.cellSize);
pauseMenu = new PauseMenuStage(layout, game, scorer); pauseMenu = new PauseMenuStage(layout, game, scorer);
gameOverSound = Gdx.audio.newSound(Gdx.files.internal("sound/game_over.mp3")); gameOverSound = Gdx.audio.newSound(Gdx.files.internal("sound/game_over.mp3"));
} }
//endregion
//region Private methods
// If no piece can be put, then it is considered to be game over
private boolean isGameOver() { private boolean isGameOver() {
for (Piece piece : holder.getAvailablePieces()) { for (Piece piece : holder.getAvailablePieces())
if (board.canPutPiece(piece)) { if (board.canPutPiece(piece))
return false; return false;
}
}
return true; return true;
} }
//endregion
//region Screen //region Screen
@Override @Override
@ -80,26 +97,6 @@ public class GameScreen implements Screen, InputProcessor {
} }
} }
@Override
public void resize(int width, int height) {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
}
@Override @Override
public void dispose() { public void dispose() {
pauseMenu.dispose(); pauseMenu.dispose();
@ -109,11 +106,6 @@ public class GameScreen implements Screen, InputProcessor {
//region Input //region Input
@Override
public boolean keyDown(int keycode) {
return false;
}
@Override @Override
public boolean keyUp(int keycode) { public boolean keyUp(int keycode) {
if (keycode == Input.Keys.P || keycode == Input.Keys.BACK) // Pause if (keycode == Input.Keys.P || keycode == Input.Keys.BACK) // Pause
@ -122,11 +114,6 @@ public class GameScreen implements Screen, InputProcessor {
return false; return false;
} }
@Override
public boolean keyTyped(char character) {
return false;
}
@Override @Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) { public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return holder.pickPiece(); return holder.pickPiece();
@ -141,7 +128,7 @@ public class GameScreen implements Screen, InputProcessor {
if (action == PieceHolder.ON_BOARD_DROP) { if (action == PieceHolder.ON_BOARD_DROP) {
scorer.addPieceScore(area); scorer.addPieceScore(area);
scorer.addBoardScore(board.clearComplete()); scorer.addBoardScore(board.clearComplete(), board.cellCount);
// After the piece was put, check if it's game over // After the piece was put, check if it's game over
if (isGameOver()) { if (isGameOver()) {
@ -153,6 +140,32 @@ public class GameScreen implements Screen, InputProcessor {
return true; return true;
} }
//endregion
//region Unused methods
@Override
public void resize(int width, int height) { }
@Override
public void pause() { }
@Override
public void resume() { }
@Override
public void hide() { }
@Override
public boolean keyDown(int keycode) {
return false;
}
@Override
public boolean keyTyped(char character) {
return false;
}
@Override @Override
public boolean touchDragged(int screenX, int screenY, int pointer) { public boolean touchDragged(int screenX, int screenY, int pointer) {
return false; return false;

View file

@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.Stage;
@ -15,16 +14,28 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
import io.github.lonamiwebs.klooni.actors.SoftButton; import io.github.lonamiwebs.klooni.actors.SoftButton;
// Main menu screen, presenting some options (play, customize)
public class MainMenuScreen extends InputListener implements Screen { public class MainMenuScreen extends InputListener implements Screen {
private Klooni game;
Stage stage; //region Members
SpriteBatch batch;
public MainMenuScreen(Klooni aGame) { private final Klooni game;
game = aGame; private final Stage stage;
//endregion
//region Static members
// As the examples show on the LibGdx wiki
private static final float minDelta = 1/30f;
//endregion
//region Constructor
public MainMenuScreen(Klooni game) {
this.game = game;
batch = new SpriteBatch();
stage = new Stage(); stage = new Stage();
Table table = new Table(); Table table = new Table();
@ -35,7 +46,7 @@ public class MainMenuScreen extends InputListener implements Screen {
final ImageButton playButton = new SoftButton(0, "play_texture"); final ImageButton playButton = new SoftButton(0, "play_texture");
playButton.addListener(new ChangeListener() { playButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
game.setScreen(new GameScreen(game)); MainMenuScreen.this.game.setScreen(new GameScreen(MainMenuScreen.this.game));
dispose(); dispose();
} }
}); });
@ -55,20 +66,22 @@ public class MainMenuScreen extends InputListener implements Screen {
final ImageButton paletteButton = new SoftButton(3, "palette_texture"); final ImageButton paletteButton = new SoftButton(3, "palette_texture");
paletteButton.addListener(new ChangeListener() { paletteButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
game.setScreen(new CustomizeScreen(game, game.getScreen())); MainMenuScreen.this.game.setScreen(new CustomizeScreen(MainMenuScreen.this.game, MainMenuScreen.this.game.getScreen()));
// Don't dispose because then it needs to take us to the previous screen // Don't dispose because then it needs to take us to the previous screen
} }
}); });
table.add(paletteButton).space(16); table.add(paletteButton).space(16);
} }
//endregion
//region Screen
@Override @Override
public void show() { public void show() {
Gdx.input.setInputProcessor(stage); Gdx.input.setInputProcessor(stage);
} }
private static final float minDelta = 1/30f;
@Override @Override
public void render(float delta) { public void render(float delta) {
Klooni.theme.glClearBackground(); Klooni.theme.glClearBackground();
@ -86,23 +99,23 @@ public class MainMenuScreen extends InputListener implements Screen {
stage.getViewport().update(width, height, true); stage.getViewport().update(width, height, true);
} }
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
}
@Override @Override
public void dispose() { public void dispose() {
stage.dispose(); stage.dispose();
} }
//endregion
//region Unused methods
@Override
public void pause() { }
@Override
public void resume() { }
@Override
public void hide() { }
//endregion
} }

View file

@ -21,7 +21,11 @@ import io.github.lonamiwebs.klooni.actors.SoftButton;
import io.github.lonamiwebs.klooni.game.GameLayout; import io.github.lonamiwebs.klooni.game.GameLayout;
import io.github.lonamiwebs.klooni.game.Scorer; import io.github.lonamiwebs.klooni.game.Scorer;
public class PauseMenuStage extends Stage { // The pause stage is not a whole screen but rather a menu
// which can be overlaid on top of another screen
class PauseMenuStage extends Stage {
//region Members
private InputProcessor lastInputProcessor; private InputProcessor lastInputProcessor;
private boolean shown; private boolean shown;
@ -32,8 +36,13 @@ public class PauseMenuStage extends Stage {
private final Band band; private final Band band;
private final Scorer scorer; private final Scorer scorer;
public PauseMenuStage(final GameLayout layout, final Klooni game, final Scorer aScorer) { //endregion
scorer = aScorer;
//region Constructor
// We need the score to save the maximum score if a new record was beaten
PauseMenuStage(final GameLayout layout, final Klooni game, final Scorer scorer) {
this.scorer = scorer;
shapeRenderer = new ShapeRenderer(20); // 20 vertex seems to be enough for a rectangle shapeRenderer = new ShapeRenderer(20); // 20 vertex seems to be enough for a rectangle
@ -43,7 +52,7 @@ public class PauseMenuStage extends Stage {
// Current and maximum score band. // Current and maximum score band.
// Do not add it to the table not to over-complicate things. // Do not add it to the table not to over-complicate things.
band = new Band(layout, scorer, Color.SKY); band = new Band(layout, this.scorer, Color.SKY);
addActor(band); addActor(band);
// Home screen button // Home screen button
@ -84,7 +93,7 @@ public class PauseMenuStage extends Stage {
}); });
// Continue playing OR share (if game over) button // Continue playing OR share (if game over) button
// TODO Enable both actions for this button // TODO Enable both actions for this button? Or leave play?
final ImageButton playButton = new SoftButton(2, "play_texture"); final ImageButton playButton = new SoftButton(2, "play_texture");
table.add(playButton).space(16); table.add(playButton).space(16);
@ -95,22 +104,12 @@ public class PauseMenuStage extends Stage {
}); });
} }
void show(final boolean gameOver) { //endregion
scorer.saveScore();
lastInputProcessor = Gdx.input.getInputProcessor(); //region Private methods
Gdx.input.setInputProcessor(this);
shown = true;
hiding = false;
if (gameOver) // Hides the pause menu, setting back the previous input processor
band.setGameOver(); private void hide() {
addAction(Actions.moveTo(0, Gdx.graphics.getHeight()));
addAction(Actions.moveTo(0, 0, 0.75f, Interpolation.swingOut));
}
public void hide() {
shown = false; shown = false;
hiding = true; hiding = true;
Gdx.input.setInputProcessor(lastInputProcessor); Gdx.input.setInputProcessor(lastInputProcessor);
@ -126,19 +125,44 @@ public class PauseMenuStage extends Stage {
)); ));
} }
public boolean isShown() { //endregion
//region Package local methods
// Shows the pause menu, indicating whether it's game over or not
void show(final boolean gameOver) {
scorer.saveScore();
// Save the last input processor so then we can return the handle to it
lastInputProcessor = Gdx.input.getInputProcessor();
Gdx.input.setInputProcessor(this);
shown = true;
hiding = false;
if (gameOver)
band.setGameOver();
addAction(Actions.moveTo(0, Gdx.graphics.getHeight()));
addAction(Actions.moveTo(0, 0, 0.75f, Interpolation.swingOut));
}
boolean isShown() {
return shown; return shown;
} }
public boolean isHiding() { boolean isHiding() {
return hiding; return hiding;
} }
//endregion
//region Public methods
@Override @Override
public void draw() { public void draw() {
// Draw an overlay rectangle with not all the opacity
// This is the only place where ShapeRenderer is OK because the batch hasn't started
if (shown) { if (shown) {
// Draw an overlay rectangle with not all the opacity
// This is the only place where ShapeRenderer is OK because the batch hasn't started
Gdx.gl.glEnable(GL20.GL_BLEND); Gdx.gl.glEnable(GL20.GL_BLEND);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(1f, 1f, 1f, 0.3f); shapeRenderer.setColor(1f, 1f, 1f, 0.3f);
@ -156,4 +180,6 @@ public class PauseMenuStage extends Stage {
return super.keyUp(keyCode); return super.keyUp(keyCode);
} }
//endregion
} }