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 {
|
||||
|
||||
//region Members
|
||||
|
||||
// TODO Not sure whether the theme should be static or not since it might load textures
|
||||
public static Theme theme;
|
||||
public Skin skin;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Creation
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
prefs = Gdx.app.getPreferences("io.github.lonamiwebs.klooni.game");
|
||||
|
@ -51,11 +57,19 @@ public class Klooni extends Game {
|
|||
setScreen(new MainMenuScreen(this));
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Screen
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Disposing
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
@ -63,6 +77,8 @@ public class Klooni extends Game {
|
|||
theme.dispose();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Settings
|
||||
|
||||
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.JsonValue;
|
||||
|
||||
// Represents a Theme for the current game.
|
||||
// These are loaded from external files, so more
|
||||
// can be easily added
|
||||
public class Theme {
|
||||
|
||||
//region Members
|
||||
|
||||
private String displayName;
|
||||
private String name;
|
||||
private int price;
|
||||
|
@ -23,19 +28,28 @@ public class Theme {
|
|||
|
||||
public NinePatch cellPatch;
|
||||
|
||||
// Save the button styles so the changes here get reflected
|
||||
private ImageButton.ImageButtonStyle[] buttonStyles;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
private Theme() {
|
||||
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() {
|
||||
FileHandle[] handles = Gdx.files.internal("themes").list();
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -48,6 +62,11 @@ public class Theme {
|
|||
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) {
|
||||
return update(Gdx.files.internal("themes/"+name+".theme"));
|
||||
}
|
||||
|
@ -93,6 +112,14 @@ public class Theme {
|
|||
return this;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Applying the theme
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ImageButton.ImageButtonStyle getStyle(int button) {
|
||||
return buttonStyles[button];
|
||||
}
|
||||
|
@ -101,20 +128,22 @@ public class Theme {
|
|||
return cells[colorIndex];
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
|
||||
}
|
||||
|
||||
public void glClearBackground() {
|
||||
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void updateStyle(ImageButton.ImageButtonStyle style, int styleIndex) {
|
||||
style.imageUp = buttonStyles[styleIndex].imageUp;
|
||||
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.Scorer;
|
||||
|
||||
// Score and pause menu band actually
|
||||
// Horizontal band, used to show the score on the pause menu
|
||||
public class Band extends Actor {
|
||||
|
||||
//region Members
|
||||
|
||||
private final Scorer scorer;
|
||||
private final Texture bandTexture;
|
||||
|
||||
public final Rectangle scoreBounds;
|
||||
public final Rectangle infoBounds;
|
||||
|
||||
public final Label infoLabel;
|
||||
public final Label scoreLabel;
|
||||
private final Label infoLabel;
|
||||
private final Label scoreLabel;
|
||||
|
||||
public Band(final GameLayout layout, final Scorer aScorer, final Color bandColor) {
|
||||
scorer = aScorer;
|
||||
//endregion
|
||||
|
||||
//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.setColor(bandColor);
|
||||
pixmap.fill();
|
||||
|
@ -49,9 +56,9 @@ public class Band extends Actor {
|
|||
layout.update(this);
|
||||
}
|
||||
|
||||
public void setGameOver() {
|
||||
infoLabel.setText("no moves left");
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Public methods
|
||||
|
||||
@Override
|
||||
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.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.Theme;
|
||||
|
||||
// Small wrapper to use themed image buttons more easily
|
||||
public class SoftButton extends ImageButton {
|
||||
|
||||
//region Members
|
||||
|
||||
private int styleIndex;
|
||||
private Drawable image;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
public SoftButton(int styleIndex, String imageName) {
|
||||
super(Klooni.theme.getStyle(styleIndex));
|
||||
|
||||
|
@ -19,13 +26,22 @@ public class SoftButton extends ImageButton {
|
|||
image = Theme.skin.getDrawable(imageName);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Public methods
|
||||
|
||||
@Override
|
||||
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();
|
||||
Klooni.theme.updateStyle(style, styleIndex);
|
||||
style.imageUp = image;
|
||||
|
||||
super.draw(batch, parentAlpha);
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.github.lonamiwebs.klooni.actors;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
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.GameLayout;
|
||||
|
||||
// Card-like actor used to display information about a given theme
|
||||
public class ThemeCard extends Actor {
|
||||
|
||||
//region Members
|
||||
|
||||
public final Theme theme;
|
||||
private final Texture background;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
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)
|
||||
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
|
||||
pixmap.setColor(theme.background);
|
||||
|
@ -26,11 +33,12 @@ public class ThemeCard extends Actor {
|
|||
|
||||
this.theme = theme;
|
||||
layout.update(this);
|
||||
|
||||
setWidth(Gdx.graphics.getWidth());
|
||||
setScaleX(200);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Public methods
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float parentAlpha) {
|
||||
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(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;
|
||||
|
||||
// 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 {
|
||||
|
||||
Cell[][] cells;
|
||||
//region Members
|
||||
|
||||
public final int cellCount;
|
||||
public float cellSize;
|
||||
|
||||
private final Vector2 lastPutPiecePos; // Used to animate cleared cells vanishing
|
||||
private Cell[][] cells;
|
||||
|
||||
final Vector2 pos;
|
||||
|
||||
private final Sound stripClearSound;
|
||||
|
||||
// Used to animate cleared cells vanishing
|
||||
private final Vector2 lastPutPiecePos;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
public Board(final GameLayout layout, int cellCount) {
|
||||
this.cellCount = cellCount;
|
||||
|
||||
|
@ -27,9 +35,9 @@ public class Board {
|
|||
|
||||
lastPutPiecePos = 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];
|
||||
for (int i = 0; i < this.cellCount; i++) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
if (!inBounds(piece, x, y))
|
||||
return false;
|
||||
|
@ -59,39 +74,64 @@ public class Board {
|
|||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
// Returns true iff the piece was put on the board
|
||||
private boolean putPiece(Piece piece, int x, int y) {
|
||||
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;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
public boolean putScreenPiece(Piece piece) {
|
||||
// Get the local piece coordinates
|
||||
// TODO Works weird, it puts the piece like one too low…
|
||||
boolean putScreenPiece(Piece piece) {
|
||||
// Convert the on screen coordinates of the piece to the local-board-space coordinates
|
||||
// This is done by subtracting the piece coordinates from the board coordinates
|
||||
Vector2 local = piece.pos.cpy().sub(pos);
|
||||
int x = MathUtils.round(local.x / piece.cellSize);
|
||||
int y = MathUtils.round(local.y / piece.cellSize);
|
||||
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() {
|
||||
// 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;
|
||||
boolean[] clearedRows = new boolean[cellCount];
|
||||
boolean[] clearedCols = new boolean[cellCount];
|
||||
|
@ -123,13 +163,11 @@ public class Board {
|
|||
float pan = 0;
|
||||
|
||||
// Do clear those rows and columns
|
||||
for (int i = 0; i < cellCount; i++) {
|
||||
if (clearedRows[i]) {
|
||||
for (int j = 0; j < cellCount; j++) {
|
||||
for (int i = 0; i < cellCount; i++)
|
||||
if (clearedRows[i])
|
||||
for (int j = 0; j < cellCount; j++)
|
||||
cells[i][j].vanish(lastPutPiecePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < cellCount; j++) {
|
||||
if (clearedCols[j]) {
|
||||
pan += 2f * (j - cellCount / 2) / (float)cellCount;
|
||||
|
@ -150,27 +188,5 @@ public class Board {
|
|||
return clearCount;
|
||||
}
|
||||
|
||||
public boolean putPiece(Piece piece, int x, int y) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
|
|
|
@ -9,19 +9,27 @@ import com.badlogic.gdx.math.Vector2;
|
|||
|
||||
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 {
|
||||
|
||||
//region Members
|
||||
|
||||
private boolean empty;
|
||||
private Color color;
|
||||
|
||||
Vector2 pos;
|
||||
float size;
|
||||
private Vector2 pos;
|
||||
private float size;
|
||||
|
||||
private Color vanishColor;
|
||||
private float vanishSize;
|
||||
private float vanishElapsed;
|
||||
private float vanishLifetime;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
Cell(float x, float y, float cellSize) {
|
||||
pos = new Vector2(x, y);
|
||||
size = cellSize;
|
||||
|
@ -31,6 +39,11 @@ public class Cell {
|
|||
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) {
|
||||
empty = false;
|
||||
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,
|
||||
// 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) {
|
||||
if (empty) // We cannot vanish twice
|
||||
return;
|
||||
|
@ -90,4 +92,21 @@ public class Cell {
|
|||
|
||||
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
|
||||
public class GameLayout {
|
||||
|
||||
// Widths
|
||||
private float screenWidth, marginWidth, availableWidth;
|
||||
//region Members
|
||||
|
||||
// Heights
|
||||
private float screenHeight, logoHeight, scoreHeight, boardHeight, pieceHolderHeight;
|
||||
private float screenWidth, marginWidth, availableWidth;
|
||||
private float scoreHeight, boardHeight, pieceHolderHeight;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
public GameLayout() {
|
||||
calculate();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Private methods
|
||||
|
||||
private void calculate() {
|
||||
screenWidth = Gdx.graphics.getWidth();
|
||||
screenHeight = Gdx.graphics.getHeight();
|
||||
float screenHeight = Gdx.graphics.getHeight();
|
||||
|
||||
// Widths
|
||||
marginWidth = screenWidth * 0.05f;
|
||||
availableWidth = screenWidth - marginWidth * 2f;
|
||||
|
||||
// Heights
|
||||
logoHeight = screenHeight * 0.10f;
|
||||
// logoHeight = screenHeight * 0.10f; // Unused
|
||||
scoreHeight = screenHeight * 0.15f;
|
||||
boardHeight = screenHeight * 0.50f;
|
||||
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) {
|
||||
float cupSize = Math.min(scoreHeight, scorer.cupTexture.getHeight());
|
||||
final Rectangle area = new Rectangle(
|
||||
|
@ -94,4 +109,6 @@ public class GameLayout {
|
|||
public void update(ThemeCard card) {
|
||||
card.setSize(availableWidth - marginWidth, scoreHeight);
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
|
|
@ -8,18 +8,31 @@ import com.badlogic.gdx.math.Vector2;
|
|||
|
||||
import io.github.lonamiwebs.klooni.Klooni;
|
||||
|
||||
// Pieces can be L shaped and be rotated 0 to 3 times to make it random
|
||||
// Maximum cellSize = 4
|
||||
// Represents a piece with an arbitrary shape, which
|
||||
// can be either rectangles (squares too) or L shaped
|
||||
// with any rotation.
|
||||
public class Piece {
|
||||
|
||||
//region Members
|
||||
|
||||
final Vector2 pos;
|
||||
float cellSize = 10f; // Default
|
||||
final Color color;
|
||||
|
||||
final int cellCols, cellRows;
|
||||
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) {
|
||||
color = Klooni.theme.getCellColor(colorIndex);
|
||||
|
||||
|
@ -34,6 +47,7 @@ public class Piece {
|
|||
}
|
||||
}
|
||||
|
||||
// L-shaped constructor
|
||||
private Piece(int lSize, int rotateCount, int colorIndex) {
|
||||
color = Klooni.theme.getCellColor(colorIndex);
|
||||
|
||||
|
@ -68,11 +82,12 @@ public class Piece {
|
|||
}
|
||||
}
|
||||
|
||||
boolean filled(int i, int j) {
|
||||
return shape[i][j];
|
||||
}
|
||||
//endregion
|
||||
|
||||
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
|
||||
switch (color) {
|
||||
// Squares
|
||||
|
@ -93,10 +108,28 @@ public class Piece {
|
|||
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() {
|
||||
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 area = 0;
|
||||
for (int i = 0; i < cellRows; i++) {
|
||||
|
@ -109,6 +142,7 @@ public class Piece {
|
|||
return area;
|
||||
}
|
||||
|
||||
// Calculates the gravity center of the piece shape
|
||||
Vector2 calculateGravityCenter() {
|
||||
int filledCount = 0;
|
||||
Vector2 result = new Vector2();
|
||||
|
@ -125,14 +159,5 @@ public class Piece {
|
|||
return result.scl(1f / filledCount);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
|
|
|
@ -11,28 +11,43 @@ import com.badlogic.gdx.utils.Array;
|
|||
|
||||
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 {
|
||||
|
||||
//region Members
|
||||
|
||||
final Rectangle area;
|
||||
private final Piece[] pieces;
|
||||
private final Rectangle[] originalPositions; // Needed after a piece is dropped
|
||||
|
||||
private final Sound pieceDropSound;
|
||||
private final Sound invalidPieceDropSound;
|
||||
private final Sound takePiecesSound;
|
||||
|
||||
// Count of pieces to be shown
|
||||
private final int count;
|
||||
|
||||
// Currently held piece index (picked by the user)
|
||||
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
|
||||
private final float pickedCellSize;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Static members
|
||||
|
||||
public static final int NO_DROP = 0;
|
||||
public static final int NORMAL_DROP = 1;
|
||||
public static final int ON_BOARD_DROP = 2;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
public PieceHolder(final GameLayout layout, final int pieceCount, final float pickedCellSize) {
|
||||
count = pieceCount;
|
||||
pieces = new Piece[count];
|
||||
|
@ -53,7 +68,21 @@ public class PieceHolder {
|
|||
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;
|
||||
for (int i = 0; i < count; i++) {
|
||||
pieces[i] = Piece.random();
|
||||
|
@ -85,15 +114,11 @@ public class PieceHolder {
|
|||
}
|
||||
}
|
||||
|
||||
boolean handFinished() {
|
||||
for (int i = 0; i < count; i++)
|
||||
if (pieces[i] != null)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
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() {
|
||||
Vector2 mouse = new Vector2(
|
||||
Gdx.input.getX(),
|
||||
|
@ -112,23 +137,20 @@ public class PieceHolder {
|
|||
|
||||
public Array<Piece> getAvailablePieces() {
|
||||
Array<Piece> result = new Array<Piece>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (pieces[i] != null) {
|
||||
for (int i = 0; i < count; i++)
|
||||
if (pieces[i] != null)
|
||||
result.add(pieces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// If no piece is currently being held, the area will be 0
|
||||
public int calculateHeldPieceArea() {
|
||||
if (heldPiece > -1) {
|
||||
return pieces[heldPiece].calculateArea();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return heldPiece > -1 ? pieces[heldPiece].calculateArea() : 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) {
|
||||
if (heldPiece > -1) {
|
||||
boolean put = board.putScreenPiece(pieces[heldPiece]);
|
||||
|
@ -154,6 +176,7 @@ public class PieceHolder {
|
|||
return NO_DROP;
|
||||
}
|
||||
|
||||
// Updates the state of the piece holder (and the held piece)
|
||||
public void update() {
|
||||
Piece piece;
|
||||
if (heldPiece > -1) {
|
||||
|
@ -163,7 +186,7 @@ public class PieceHolder {
|
|||
Gdx.input.getX(),
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
// 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 {
|
||||
|
||||
private int currentScore, maxScore;
|
||||
private boolean newRecord;
|
||||
//region Members
|
||||
|
||||
private float shownScore; // To interpolate between shown score -> real score
|
||||
private final int boardSize;
|
||||
private int currentScore, maxScore;
|
||||
|
||||
final Label currentScoreLabel;
|
||||
final Label maxScoreLabel;
|
||||
|
@ -27,10 +28,20 @@ public class Scorer {
|
|||
final Texture cupTexture;
|
||||
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;
|
||||
maxScore = Klooni.getMaxScore();
|
||||
this.boardSize = boardSize;
|
||||
|
||||
cupTexture = new Texture(Gdx.files.internal("ui/cup.png"));
|
||||
cupArea = new Rectangle();
|
||||
|
@ -48,19 +59,39 @@ public class Scorer {
|
|||
layout.update(this);
|
||||
}
|
||||
|
||||
public void addPieceScore(int areaPut) {
|
||||
addScore(areaPut);
|
||||
}
|
||||
//endregion
|
||||
|
||||
public void addBoardScore(int stripsCleared) {
|
||||
addScore(calculateClearScore(stripsCleared));
|
||||
}
|
||||
//region Private methods
|
||||
|
||||
private void addScore(int score) {
|
||||
currentScore += score;
|
||||
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() {
|
||||
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) {
|
||||
int roundShown = MathUtils.round(shownScore);
|
||||
if (roundShown != currentScore) {
|
||||
|
@ -93,4 +114,6 @@ public class Scorer {
|
|||
currentScoreLabel.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.game.GameLayout;
|
||||
|
||||
public class CustomizeScreen implements Screen {
|
||||
private Klooni game;
|
||||
// Screen where the user can customize the look and feel of the game
|
||||
class CustomizeScreen implements Screen {
|
||||
|
||||
//region Members
|
||||
|
||||
private Klooni game;
|
||||
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();
|
||||
|
||||
game = aGame;
|
||||
this.game = game;
|
||||
stage = new Stage();
|
||||
|
||||
Table table = new Table();
|
||||
|
@ -45,7 +59,7 @@ public class CustomizeScreen implements Screen {
|
|||
backButton.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
game.setScreen(lastScreen);
|
||||
CustomizeScreen.this.game.setScreen(lastScreen);
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
@ -59,7 +73,7 @@ public class CustomizeScreen implements Screen {
|
|||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
Klooni.toggleSound();
|
||||
soundButton.getStyle().imageUp = game.skin.getDrawable(
|
||||
soundButton.getStyle().imageUp = CustomizeScreen.this.game.skin.getDrawable(
|
||||
Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture");
|
||||
}
|
||||
});
|
||||
|
@ -86,8 +100,9 @@ public class CustomizeScreen implements Screen {
|
|||
optionsGroup.addActor(webButton);
|
||||
|
||||
table.add(new ScrollPane(optionsGroup)).pad(20, 4, 12, 4);
|
||||
table.row();
|
||||
|
||||
// Load all the available themes
|
||||
table.row();
|
||||
VerticalGroup themesGroup = new VerticalGroup();
|
||||
for (Theme theme : Theme.getThemes()) {
|
||||
final ThemeCard card = new ThemeCard(layout, theme);
|
||||
|
@ -105,13 +120,15 @@ public class CustomizeScreen implements Screen {
|
|||
table.add(new ScrollPane(themesGroup)).expand().fill();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Public methods
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
Gdx.input.setInputProcessor(stage);
|
||||
}
|
||||
|
||||
private static final float minDelta = 1/30f;
|
||||
|
||||
@Override
|
||||
public void render(float delta) {
|
||||
Klooni.theme.glClearBackground();
|
||||
|
@ -130,23 +147,23 @@ public class CustomizeScreen implements Screen {
|
|||
stage.getViewport().update(width, height, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 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.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 Board board;
|
||||
private PieceHolder holder;
|
||||
private final Board board;
|
||||
private final PieceHolder holder;
|
||||
|
||||
private final GameLayout layout;
|
||||
private final SpriteBatch batch;
|
||||
private final Sound gameOverSound;
|
||||
|
||||
private SpriteBatch batch;
|
||||
|
||||
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) {
|
||||
batch = new SpriteBatch();
|
||||
|
||||
layout = new GameLayout();
|
||||
|
||||
scorer = new Scorer(layout, 10);
|
||||
board = new Board(layout, 10);
|
||||
holder = new PieceHolder(layout, 3, board.cellSize);
|
||||
final GameLayout layout = new GameLayout();
|
||||
scorer = new Scorer(layout);
|
||||
board = new Board(layout, BOARD_SIZE);
|
||||
holder = new PieceHolder(layout, HOLDER_PIECE_COUNT, board.cellSize);
|
||||
pauseMenu = new PauseMenuStage(layout, game, scorer);
|
||||
|
||||
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() {
|
||||
for (Piece piece : holder.getAvailablePieces()) {
|
||||
if (board.canPutPiece(piece)) {
|
||||
for (Piece piece : holder.getAvailablePieces())
|
||||
if (board.canPutPiece(piece))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Screen
|
||||
|
||||
@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
|
||||
public void dispose() {
|
||||
pauseMenu.dispose();
|
||||
|
@ -109,11 +106,6 @@ public class GameScreen implements Screen, InputProcessor {
|
|||
|
||||
//region Input
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keycode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyUp(int keycode) {
|
||||
if (keycode == Input.Keys.P || keycode == Input.Keys.BACK) // Pause
|
||||
|
@ -122,11 +114,6 @@ public class GameScreen implements Screen, InputProcessor {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(char character) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
|
||||
return holder.pickPiece();
|
||||
|
@ -141,7 +128,7 @@ public class GameScreen implements Screen, InputProcessor {
|
|||
|
||||
if (action == PieceHolder.ON_BOARD_DROP) {
|
||||
scorer.addPieceScore(area);
|
||||
scorer.addBoardScore(board.clearComplete());
|
||||
scorer.addBoardScore(board.clearComplete(), board.cellCount);
|
||||
|
||||
// After the piece was put, check if it's game over
|
||||
if (isGameOver()) {
|
||||
|
@ -153,6 +140,32 @@ public class GameScreen implements Screen, InputProcessor {
|
|||
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
|
||||
public boolean touchDragged(int screenX, int screenY, int pointer) {
|
||||
return false;
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx;
|
|||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.Screen;
|
||||
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.InputListener;
|
||||
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.actors.SoftButton;
|
||||
|
||||
// Main menu screen, presenting some options (play, customize…)
|
||||
public class MainMenuScreen extends InputListener implements Screen {
|
||||
private Klooni game;
|
||||
|
||||
Stage stage;
|
||||
SpriteBatch batch;
|
||||
//region Members
|
||||
|
||||
public MainMenuScreen(Klooni aGame) {
|
||||
game = aGame;
|
||||
private final Klooni game;
|
||||
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();
|
||||
|
||||
Table table = new Table();
|
||||
|
@ -35,7 +46,7 @@ public class MainMenuScreen extends InputListener implements Screen {
|
|||
final ImageButton playButton = new SoftButton(0, "play_texture");
|
||||
playButton.addListener(new ChangeListener() {
|
||||
public void changed (ChangeEvent event, Actor actor) {
|
||||
game.setScreen(new GameScreen(game));
|
||||
MainMenuScreen.this.game.setScreen(new GameScreen(MainMenuScreen.this.game));
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
@ -55,20 +66,22 @@ public class MainMenuScreen extends InputListener implements Screen {
|
|||
final ImageButton paletteButton = new SoftButton(3, "palette_texture");
|
||||
paletteButton.addListener(new ChangeListener() {
|
||||
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
|
||||
}
|
||||
});
|
||||
table.add(paletteButton).space(16);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Screen
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
Gdx.input.setInputProcessor(stage);
|
||||
}
|
||||
|
||||
private static final float minDelta = 1/30f;
|
||||
|
||||
@Override
|
||||
public void render(float delta) {
|
||||
Klooni.theme.glClearBackground();
|
||||
|
@ -86,23 +99,23 @@ public class MainMenuScreen extends InputListener implements Screen {
|
|||
stage.getViewport().update(width, height, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 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.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 boolean shown;
|
||||
|
@ -32,8 +36,13 @@ public class PauseMenuStage extends Stage {
|
|||
private final Band band;
|
||||
private final Scorer scorer;
|
||||
|
||||
public PauseMenuStage(final GameLayout layout, final Klooni game, final Scorer aScorer) {
|
||||
scorer = aScorer;
|
||||
//endregion
|
||||
|
||||
//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
|
||||
|
||||
|
@ -43,7 +52,7 @@ public class PauseMenuStage extends Stage {
|
|||
|
||||
// Current and maximum score band.
|
||||
// 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);
|
||||
|
||||
// Home screen button
|
||||
|
@ -84,7 +93,7 @@ public class PauseMenuStage extends Stage {
|
|||
});
|
||||
|
||||
// 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");
|
||||
table.add(playButton).space(16);
|
||||
|
||||
|
@ -95,22 +104,12 @@ public class PauseMenuStage extends Stage {
|
|||
});
|
||||
}
|
||||
|
||||
void show(final boolean gameOver) {
|
||||
scorer.saveScore();
|
||||
//endregion
|
||||
|
||||
lastInputProcessor = Gdx.input.getInputProcessor();
|
||||
Gdx.input.setInputProcessor(this);
|
||||
shown = true;
|
||||
hiding = false;
|
||||
//region Private methods
|
||||
|
||||
if (gameOver)
|
||||
band.setGameOver();
|
||||
|
||||
addAction(Actions.moveTo(0, Gdx.graphics.getHeight()));
|
||||
addAction(Actions.moveTo(0, 0, 0.75f, Interpolation.swingOut));
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
// Hides the pause menu, setting back the previous input processor
|
||||
private void hide() {
|
||||
shown = false;
|
||||
hiding = true;
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isHiding() {
|
||||
boolean isHiding() {
|
||||
return hiding;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Public methods
|
||||
|
||||
@Override
|
||||
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) {
|
||||
// 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);
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
|
||||
shapeRenderer.setColor(1f, 1f, 1f, 0.3f);
|
||||
|
@ -156,4 +180,6 @@ public class PauseMenuStage extends Stage {
|
|||
|
||||
return super.keyUp(keyCode);
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue