Add time mode scorer
This commit is contained in:
parent
cafe83ad80
commit
47301864eb
5 changed files with 168 additions and 8 deletions
|
@ -75,6 +75,25 @@ public class GameLayout {
|
|||
area.width * 0.5f - cupSize * 0.5f, area.height);
|
||||
}
|
||||
|
||||
void update(TimeScorer scorer) {
|
||||
float cupSize = Math.min(scoreHeight, scorer.cupTexture.getHeight());
|
||||
final Rectangle area = new Rectangle(
|
||||
marginWidth, pieceHolderHeight + boardHeight,
|
||||
availableWidth, scoreHeight);
|
||||
|
||||
scorer.cupArea.set(
|
||||
area.x + area.width * 0.5f - cupSize * 0.5f, area.y,
|
||||
cupSize, cupSize);
|
||||
|
||||
scorer.timeLeftLabel.setBounds(
|
||||
area.x, area.y,
|
||||
area.width * 0.5f - cupSize * 0.5f, area.height);
|
||||
|
||||
scorer.highTimeLabel.setBounds(
|
||||
area.x + area.width * 0.5f + cupSize * 0.5f, area.y,
|
||||
area.width * 0.5f - cupSize * 0.5f, area.height);
|
||||
}
|
||||
|
||||
void update(Board board) {
|
||||
// We can't leave our area, so pick the minimum between available
|
||||
// height and width to determine an appropriated cell size
|
||||
|
|
119
core/src/io/github/lonamiwebs/klooni/game/TimeScorer.java
Normal file
119
core/src/io/github/lonamiwebs/klooni/game/TimeScorer.java
Normal file
|
@ -0,0 +1,119 @@
|
|||
package io.github.lonamiwebs.klooni.game;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
|
||||
import io.github.lonamiwebs.klooni.Klooni;
|
||||
|
||||
public class TimeScorer {
|
||||
|
||||
//region Members
|
||||
|
||||
private final long startTime;
|
||||
|
||||
// Maximum time alive, in seconds
|
||||
private int maxTimeScore;
|
||||
|
||||
// Indicates where we would die in time. Score adds to this, so we take
|
||||
// longer to die. To get the "score" we simply calculate `deadTime - startTime`
|
||||
private long deadTime;
|
||||
|
||||
final Label timeLeftLabel;
|
||||
final Label highTimeLabel;
|
||||
|
||||
final Texture cupTexture;
|
||||
final Rectangle cupArea;
|
||||
|
||||
private final Color cupColor;
|
||||
|
||||
private static final long START_TIME = 20 * 1000000000L;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
// The board size is required when calculating the score
|
||||
public TimeScorer(final Klooni game, GameLayout layout) {
|
||||
startTime = TimeUtils.nanoTime();
|
||||
deadTime = startTime + START_TIME;
|
||||
|
||||
cupTexture = new Texture(Gdx.files.internal("ui/cup.png"));
|
||||
cupColor = Klooni.theme.currentScore.cpy();
|
||||
cupArea = new Rectangle();
|
||||
|
||||
Label.LabelStyle labelStyle = new Label.LabelStyle();
|
||||
labelStyle.font = game.skin.getFont("font");
|
||||
|
||||
timeLeftLabel = new Label("0", labelStyle);
|
||||
timeLeftLabel.setColor(Klooni.theme.currentScore);
|
||||
timeLeftLabel.setAlignment(Align.right);
|
||||
|
||||
highTimeLabel = new Label(Integer.toString(nanosToSeconds(maxTimeScore)), labelStyle);
|
||||
highTimeLabel.setColor(Klooni.theme.highScore);
|
||||
|
||||
layout.update(this);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region Private methods
|
||||
|
||||
private void addScore(int score) {
|
||||
deadTime += scoreToNanos(score);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private int nanosToSeconds(long nano) {
|
||||
return MathUtils.ceil((float)(nano * 1e-09));
|
||||
}
|
||||
|
||||
private long scoreToNanos(int score) {
|
||||
// 1s/4p seems fair enough
|
||||
return (long)((score / 4.0) * 1e+09);
|
||||
}
|
||||
|
||||
public boolean isGameOver() {
|
||||
return TimeUtils.nanoTime() > deadTime;
|
||||
}
|
||||
|
||||
//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 void draw(SpriteBatch batch) {
|
||||
int timeLeft = Math.max(nanosToSeconds(deadTime - TimeUtils.nanoTime()), 0);
|
||||
timeLeftLabel.setText(Integer.toString(timeLeft));
|
||||
|
||||
// If we beat a new record, the cup color will linear interpolate to the high score color
|
||||
//cupColor.lerp(newRecord ? Klooni.theme.highScore : Klooni.theme.currentScore, 0.05f);
|
||||
batch.setColor(cupColor);
|
||||
batch.draw(cupTexture, cupArea.x, cupArea.y, cupArea.width, cupArea.height);
|
||||
|
||||
timeLeftLabel.draw(batch, 1f);
|
||||
highTimeLabel.draw(batch, 1f);
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
|
@ -14,6 +14,7 @@ import io.github.lonamiwebs.klooni.game.GameLayout;
|
|||
import io.github.lonamiwebs.klooni.game.Piece;
|
||||
import io.github.lonamiwebs.klooni.game.PieceHolder;
|
||||
import io.github.lonamiwebs.klooni.game.Scorer;
|
||||
import io.github.lonamiwebs.klooni.game.TimeScorer;
|
||||
|
||||
// Main game screen. Here the board, piece holder and score are shown
|
||||
class GameScreen implements Screen, InputProcessor {
|
||||
|
@ -21,6 +22,8 @@ class GameScreen implements Screen, InputProcessor {
|
|||
//region Members
|
||||
|
||||
private final Scorer scorer;
|
||||
private final TimeScorer timeScorer;
|
||||
|
||||
private final Board board;
|
||||
private final PieceHolder holder;
|
||||
|
||||
|
@ -29,6 +32,10 @@ class GameScreen implements Screen, InputProcessor {
|
|||
|
||||
private final PauseMenuStage pauseMenu;
|
||||
|
||||
// TODO Perhaps make an abstract base class for the game screen and game modes
|
||||
// by implementing different "isGameOver" etc. logic instead using an integer?
|
||||
private final int gameMode;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Static members
|
||||
|
@ -36,15 +43,21 @@ class GameScreen implements Screen, InputProcessor {
|
|||
private final static int BOARD_SIZE = 10;
|
||||
private final static int HOLDER_PIECE_COUNT = 3;
|
||||
|
||||
final static int GAME_MODE_SCORE = 0;
|
||||
final static int GAME_MODE_TIME = 1;
|
||||
|
||||
//endregion
|
||||
|
||||
//region Constructor
|
||||
|
||||
GameScreen(final Klooni game) {
|
||||
GameScreen(final Klooni game, final int gameMode) {
|
||||
batch = new SpriteBatch();
|
||||
this.gameMode = gameMode;
|
||||
|
||||
final GameLayout layout = new GameLayout();
|
||||
scorer = new Scorer(game, layout);
|
||||
timeScorer = new TimeScorer(game, layout);
|
||||
|
||||
board = new Board(layout, BOARD_SIZE);
|
||||
holder = new PieceHolder(layout, HOLDER_PIECE_COUNT, board.cellSize);
|
||||
pauseMenu = new PauseMenuStage(layout, game, scorer);
|
||||
|
@ -82,9 +95,17 @@ class GameScreen implements Screen, InputProcessor {
|
|||
Klooni.theme.glClearBackground();
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// With the time mode, we always need to check whether it's game over or not
|
||||
if (timeScorer.isGameOver() && !pauseMenu.isShown()) {
|
||||
pauseMenu.show(true);
|
||||
if (Klooni.soundsEnabled())
|
||||
gameOverSound.play();
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
|
||||
scorer.draw(batch);
|
||||
//scorer.draw(batch);
|
||||
timeScorer.draw(batch);
|
||||
board.draw(batch);
|
||||
holder.update();
|
||||
holder.draw(batch);
|
||||
|
@ -127,8 +148,10 @@ class GameScreen implements Screen, InputProcessor {
|
|||
return false;
|
||||
|
||||
if (action == PieceHolder.ON_BOARD_DROP) {
|
||||
scorer.addPieceScore(area);
|
||||
scorer.addBoardScore(board.clearComplete(), board.cellCount);
|
||||
//scorer.addPieceScore(area);
|
||||
//scorer.addBoardScore(board.clearComplete(), board.cellCount);
|
||||
timeScorer.addPieceScore(area);
|
||||
timeScorer.addBoardScore(board.clearComplete(), board.cellCount);
|
||||
|
||||
// After the piece was put, check if it's game over
|
||||
if (isGameOver()) {
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.badlogic.gdx.graphics.GL20;
|
|||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||
|
||||
|
@ -46,7 +45,8 @@ public class MainMenuScreen extends InputListener implements Screen {
|
|||
final SoftButton playButton = new SoftButton(0, "play_texture");
|
||||
playButton.addListener(new ChangeListener() {
|
||||
public void changed (ChangeEvent event, Actor actor) {
|
||||
MainMenuScreen.this.game.setScreen(new GameScreen(MainMenuScreen.this.game));
|
||||
MainMenuScreen.this.game.setScreen(
|
||||
new GameScreen(MainMenuScreen.this.game, GameScreen.GAME_MODE_SCORE));
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
|
|||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.RunnableAction;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||
|
||||
|
@ -73,7 +72,7 @@ class PauseMenuStage extends Stage {
|
|||
replayButton.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
game.setScreen(new GameScreen(game));
|
||||
game.setScreen(new GameScreen(game, GameScreen.GAME_MODE_SCORE));
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue