diff --git a/android/assets/font/geosans-light.fnt b/android/assets/font/geosans-light.fnt new file mode 100644 index 0000000..6c10dd3 --- /dev/null +++ b/android/assets/font/geosans-light.fnt @@ -0,0 +1,90 @@ +info face="GeosansLight" size=64 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=77 base=58 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="geosans-light.png" +chars count=12 +char id=10 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=0 page=0 chnl=0 +char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=57 xadvance=16 page=0 chnl=0 +char id=48 x=0 y=0 width=36 height=51 xoffset=0 yoffset=9 xadvance=35 page=0 chnl=0 +char id=49 x=297 y=0 width=13 height=48 xoffset=10 yoffset=11 xadvance=35 page=0 chnl=0 +char id=50 x=94 y=0 width=31 height=49 xoffset=2 yoffset=10 xadvance=35 page=0 chnl=0 +char id=51 x=36 y=0 width=29 height=50 xoffset=3 yoffset=10 xadvance=35 page=0 chnl=0 +char id=52 x=125 y=0 width=34 height=49 xoffset=1 yoffset=10 xadvance=35 page=0 chnl=0 +char id=53 x=159 y=0 width=34 height=49 xoffset=0 yoffset=11 xadvance=35 page=0 chnl=0 +char id=54 x=193 y=0 width=34 height=49 xoffset=1 yoffset=11 xadvance=35 page=0 chnl=0 +char id=55 x=227 y=0 width=36 height=49 xoffset=0 yoffset=11 xadvance=35 page=0 chnl=0 +char id=56 x=65 y=0 width=29 height=50 xoffset=3 yoffset=10 xadvance=35 page=0 chnl=0 +char id=57 x=263 y=0 width=34 height=49 xoffset=1 yoffset=11 xadvance=35 page=0 chnl=0 +kernings count=73 +kerning first=49 second=48 amount=-7 +kerning first=48 second=49 amount=-11 +kerning first=56 second=52 amount=-2 +kerning first=57 second=53 amount=-3 +kerning first=55 second=57 amount=-4 +kerning first=57 second=50 amount=-2 +kerning first=48 second=52 amount=-4 +kerning first=51 second=49 amount=-12 +kerning first=57 second=56 amount=-3 +kerning first=56 second=50 amount=-4 +kerning first=54 second=49 amount=-13 +kerning first=55 second=51 amount=-6 +kerning first=48 second=55 amount=-3 +kerning first=54 second=50 amount=-6 +kerning first=52 second=51 amount=-4 +kerning first=52 second=50 amount=-3 +kerning first=51 second=50 amount=-4 +kerning first=50 second=50 amount=-2 +kerning first=57 second=49 amount=-11 +kerning first=54 second=52 amount=-4 +kerning first=55 second=50 amount=-6 +kerning first=49 second=56 amount=-10 +kerning first=57 second=52 amount=-6 +kerning first=50 second=54 amount=-3 +kerning first=51 second=53 amount=-4 +kerning first=49 second=49 amount=-17 +kerning first=57 second=51 amount=-2 +kerning first=55 second=56 amount=-4 +kerning first=50 second=55 amount=-3 +kerning first=55 second=48 amount=-3 +kerning first=56 second=53 amount=-4 +kerning first=53 second=55 amount=-2 +kerning first=52 second=57 amount=-4 +kerning first=51 second=52 amount=-3 +kerning first=50 second=53 amount=-4 +kerning first=49 second=55 amount=-9 +kerning first=53 second=50 amount=-7 +kerning first=55 second=52 amount=-20 +kerning first=55 second=49 amount=-9 +kerning first=53 second=52 amount=-2 +kerning first=54 second=51 amount=-2 +kerning first=49 second=54 amount=-8 +kerning first=50 second=56 amount=-2 +kerning first=53 second=53 amount=-3 +kerning first=51 second=51 amount=-4 +kerning first=48 second=51 amount=-2 +kerning first=51 second=57 amount=-3 +kerning first=49 second=52 amount=-11 +kerning first=52 second=55 amount=-4 +kerning first=50 second=49 amount=-12 +kerning first=49 second=57 amount=-8 +kerning first=54 second=57 amount=-4 +kerning first=56 second=55 amount=-3 +kerning first=51 second=55 amount=-4 +kerning first=56 second=56 amount=-4 +kerning first=56 second=51 amount=-3 +kerning first=49 second=50 amount=-11 +kerning first=55 second=53 amount=-8 +kerning first=49 second=51 amount=-12 +kerning first=53 second=49 amount=-10 +kerning first=48 second=50 amount=-2 +kerning first=52 second=49 amount=-10 +kerning first=53 second=57 amount=-3 +kerning first=50 second=52 amount=-13 +kerning first=53 second=51 amount=-3 +kerning first=56 second=49 amount=-12 +kerning first=49 second=53 amount=-9 +kerning first=55 second=54 amount=-9 +kerning first=57 second=55 amount=-3 +kerning first=54 second=55 amount=-3 +kerning first=56 second=57 amount=-4 +kerning first=51 second=56 amount=-1 +kerning first=50 second=51 amount=-4 diff --git a/android/assets/font/geosans-light.png b/android/assets/font/geosans-light.png new file mode 100644 index 0000000..03cec39 Binary files /dev/null and b/android/assets/font/geosans-light.png differ diff --git a/android/assets/ui/cup.png b/android/assets/ui/cup.png new file mode 100644 index 0000000..606cf64 Binary files /dev/null and b/android/assets/ui/cup.png differ diff --git a/core/src/io/github/lonamiwebs/klooni/game/Cell.java b/core/src/io/github/lonamiwebs/klooni/game/Cell.java index 1a571ee..3d09f74 100644 --- a/core/src/io/github/lonamiwebs/klooni/game/Cell.java +++ b/core/src/io/github/lonamiwebs/klooni/game/Cell.java @@ -39,6 +39,8 @@ class Cell { } // TODO Use vanish with a pretty animation instead .setEmpty() + // It would be AWESOME if the delay from vanishing (bounce -> big -> small -> gone) + // was delayed by how far this cell is from the cleared piece, I mean cool!! public void vanish() { empty = true; } diff --git a/core/src/io/github/lonamiwebs/klooni/game/GameLayout.java b/core/src/io/github/lonamiwebs/klooni/game/GameLayout.java index 071ae36..e3b5d16 100644 --- a/core/src/io/github/lonamiwebs/klooni/game/GameLayout.java +++ b/core/src/io/github/lonamiwebs/klooni/game/GameLayout.java @@ -2,6 +2,7 @@ package io.github.lonamiwebs.klooni.game; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.math.Rectangle; // Helper class to calculate the size of each element // @@ -10,7 +11,7 @@ import com.badlogic.gdx.Gdx; public class GameLayout { // Widths - private float screenWidth, marginWidth; + private float screenWidth, marginWidth, availableWidth; // Heights private float screenHeight, logoHeight, scoreHeight, boardHeight, pieceHolderHeight; @@ -25,6 +26,7 @@ public class GameLayout { // Widths marginWidth = screenWidth * 0.05f; + availableWidth = screenWidth - marginWidth * 2f; // Heights logoHeight = screenHeight * 0.10f; @@ -34,19 +36,37 @@ public class GameLayout { } // Note that we're now using Y-up coordinates + void update(Scorer 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.currentScoreLabel.setBounds( + area.x, area.y, + area.width * 0.5f - cupSize * 0.5f, area.height); + + scorer.maxScoreLabel.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 - float availableWidth = screenWidth - marginWidth * 2f; float boardSize = Math.min(availableWidth, boardHeight); board.cellSize = boardSize / board.cellCount; // Now that we know the board size, we can center the board on the screen - board.pos.set(screenWidth * 0.5f - boardSize * 0.5f, pieceHolderHeight); + board.pos.set( + screenWidth * 0.5f - boardSize * 0.5f, pieceHolderHeight); } void update(PieceHolder holder) { - float availableWidth = screenWidth - marginWidth * 2f; holder.area.set( marginWidth, 0f, availableWidth, pieceHolderHeight); diff --git a/core/src/io/github/lonamiwebs/klooni/game/PieceHolder.java b/core/src/io/github/lonamiwebs/klooni/game/PieceHolder.java index f613fba..d394cb4 100644 --- a/core/src/io/github/lonamiwebs/klooni/game/PieceHolder.java +++ b/core/src/io/github/lonamiwebs/klooni/game/PieceHolder.java @@ -87,17 +87,17 @@ public class PieceHolder { } public boolean dropPiece(Board board) { + boolean put = false; if (heldPiece > -1) { if (board.putScreenPiece(pieces[heldPiece])) { pieces[heldPiece] = null; + put = true; } heldPiece = -1; if (handFinished()) takeMore(); - - return true; } - return false; + return put; } public void update(float cellSizeOnBoard) { diff --git a/core/src/io/github/lonamiwebs/klooni/game/Scorer.java b/core/src/io/github/lonamiwebs/klooni/game/Scorer.java new file mode 100644 index 0000000..649ded4 --- /dev/null +++ b/core/src/io/github/lonamiwebs/klooni/game/Scorer.java @@ -0,0 +1,73 @@ +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.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Interpolation; +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; + +public class Scorer { + + private int currentScore; + private float shownScore; // To interpolate between shown score -> real score + private final int boardSize; + + final Label currentScoreLabel; + final Label maxScoreLabel; + + final Texture cupTexture; + final Rectangle cupArea; + + public Scorer(GameLayout layout, int boardSize) { + currentScore = 0; + this.boardSize = boardSize; + + cupTexture = new Texture(Gdx.files.internal("ui/cup.png")); + cupArea = new Rectangle(); + + Label.LabelStyle scoreStyle = new Label.LabelStyle(); + scoreStyle.font = new BitmapFont(Gdx.files.internal("font/geosans-light.fnt")); + + currentScoreLabel = new Label("0", scoreStyle); + currentScoreLabel.setAlignment(Align.right); + maxScoreLabel = new Label("0", scoreStyle); + + layout.update(this); + } + + public void addPieceScore(int areaPut) { + currentScore += areaPut; + } + + public void addBoardScore(int stripsCleared) { + currentScore += calculateClearScore(stripsCleared); + } + + 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) { + shownScore = Interpolation.linear.apply(shownScore, currentScore, 0.1f); + currentScoreLabel.setText(Integer.toString(MathUtils.round(shownScore))); + } + + batch.setColor(Color.WHITE); + batch.draw(cupTexture, cupArea.x, cupArea.y, cupArea.width, cupArea.height); + currentScoreLabel.draw(batch, 1f); + maxScoreLabel.draw(batch, 1f); + } +} diff --git a/core/src/io/github/lonamiwebs/klooni/screens/GameScreen.java b/core/src/io/github/lonamiwebs/klooni/screens/GameScreen.java index faf54dc..2ab327c 100644 --- a/core/src/io/github/lonamiwebs/klooni/screens/GameScreen.java +++ b/core/src/io/github/lonamiwebs/klooni/screens/GameScreen.java @@ -13,10 +13,13 @@ import io.github.lonamiwebs.klooni.game.Board; 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; public class GameScreen implements Screen, InputProcessor { private Klooni game; + + private Scorer scorer; private Board board; private PieceHolder holder; @@ -35,6 +38,7 @@ public class GameScreen implements Screen, InputProcessor { layout = new GameLayout(); + scorer = new Scorer(layout, 10); board = new Board(layout, 10); holder = new PieceHolder(layout, 3); @@ -44,16 +48,6 @@ public class GameScreen implements Screen, InputProcessor { } } - int calculateClearScore(int cleared) { - // 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 (cleared < 1) return 0; - if (cleared == 1) return board.cellCount; - else return board.cellCount * cleared + calculateClearScore(cleared - 1); - } - boolean isGameOver() { for (Piece piece : holder.getAvailablePieces()) { if (board.canPutPiece(piece)) { @@ -76,8 +70,9 @@ public class GameScreen implements Screen, InputProcessor { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); - board.draw(batch); + scorer.draw(batch); + board.draw(batch); holder.update(board.cellSize); holder.draw(batch, board.cellPatch); @@ -137,13 +132,13 @@ public class GameScreen implements Screen, InputProcessor { public boolean touchUp(int screenX, int screenY, int pointer, int button) { int area = holder.calculateHeldPieceArea(); if (holder.dropPiece(board)) { - int cleared = board.clearComplete(); - score += area + calculateClearScore(cleared); + scorer.addPieceScore(area); + scorer.addBoardScore(board.clearComplete()); + // After the piece was put, check if it's game over if (isGameOver()) { clearColor.set(0.4f, 0.1f, 0.1f, 1f); } - return true; } else { return false;