Code clean up
This commit is contained in:
parent
6cff9d5968
commit
43f4ca68c6
15 changed files with 558 additions and 279 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,27 +74,51 @@ 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;
|
||||||
|
|
||||||
|
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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int clearComplete() {
|
|
||||||
// This will clear both complete rows and columns, all at once.
|
// This will clear both complete rows and columns, all at once.
|
||||||
// The reason why we can't check first rows and then columns
|
// The reason why we can't check first rows and then columns
|
||||||
// (or vice versa) is because the following case (* filled, _ empty):
|
// (or vice versa) is because the following case (* filled, _ empty):
|
||||||
|
@ -92,6 +131,7 @@ public class Board {
|
||||||
//
|
//
|
||||||
// If the piece is put on the top left corner, all the cells will be cleared.
|
// 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.
|
// If we first cleared the columns, then the rows wouldn't have been cleared.
|
||||||
|
public int clearComplete() {
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
if (shown) {
|
||||||
// Draw an overlay rectangle with not all the opacity
|
// Draw an overlay rectangle with not all the opacity
|
||||||
// This is the only place where ShapeRenderer is OK because the batch hasn't started
|
// This is the only place where ShapeRenderer is OK because the batch hasn't started
|
||||||
if (shown) {
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue