From a9e99a363cb2b9433bda5f01fe15524d332774f7 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Thu, 16 Jan 2020 03:54:38 +0400 Subject: [PATCH] Plumb in high scores --- android/assets/high_scores_background.png | Bin 0 -> 2308 bytes core/src/com/me/pacman/Assets.java | 5 + core/src/com/me/pacman/FontRenderer.java | 4 +- core/src/com/me/pacman/HighScores.java | 67 ++++++++++ core/src/com/me/pacman/PacDude.java | 29 +++- core/src/com/me/pacman/Score.java | 22 ++++ .../me/pacman/state/HighScoreEntryState.java | 124 ++++++++++++++++++ .../com/me/pacman/state/HighScoresState.java | 67 ++++++++++ core/src/com/me/pacman/state/MenuState.java | 14 +- core/src/com/me/pacman/state/State.java | 1 - 10 files changed, 322 insertions(+), 11 deletions(-) create mode 100644 android/assets/high_scores_background.png create mode 100644 core/src/com/me/pacman/HighScores.java create mode 100644 core/src/com/me/pacman/Score.java create mode 100644 core/src/com/me/pacman/state/HighScoreEntryState.java create mode 100644 core/src/com/me/pacman/state/HighScoresState.java diff --git a/android/assets/high_scores_background.png b/android/assets/high_scores_background.png new file mode 100644 index 0000000000000000000000000000000000000000..646d514ba44b617effecebbf4f00cb4f14c03acd GIT binary patch literal 2308 zcmZ{mc{rQt8padLphY>Rt(HhyYE&6iwHlMeR?9e4RJUPJTd87bt?^0PqdQHl(T=U9 zC?c&T6p^l&Dr%`%8lfpdglaaGL{6$Rb5757oj>09{pb7M>wcc+zJK3$&C|nKZNv5r zAP`8+)y2_Ec23IHit=}|onJY>Rd%TS=5q2J2&Dev%L3=_QP%;1l*z7+cHW5v9D0Au zxV6T20mjTL5e^St?DE}x{8er&q)ZF*?oiQtOqWsJ?qBX1*tVWXWgIaq$h4EAx|~uB zJJ7QrG+W|I<;M~MNxRQa4;j?9jZj`=zU9+@b;5%e=ib@He*Ux^;v}7J7{PLT2a=MA zb2<_NEpQmQR?*wNX-9)=ji! z>j(0imOm(KpUhI#RX1C-QPyhliipn0OnR3o4t(SNVb+H%a8;aG%Ik#9r zs~2%@mNvIfmriCb{?YjoS^f3yoY9f_;c><&-=iJ5F3U zGO#4y!ks2G7GosH0B#?SvS_Y}$u%$P?_fA#p|{35wqbQ7fbAKb(_%HQ2Y9p9rT_t8 z_aL%inRZ`2AMp3=@Qx8j#`}Ao(Fqkth9d&_-0G5K=*dmW*OXyjbQ-Mt;7z$eG30DN zv$MU#GXoC0?Y*QQXY1nlw?Sm?LMr~o%fJtTBXlTO!WKRfVxM4r%PQ@8&CvpS*A+7z%|W&>7~~tKE^oPK%Z)hjIapc!~fOq zVA54+$Zl=!HDV@f`;1owRP)XS3jIz%vKhmx))M_n=fkzawa7d1)bia}*x-^%y$lzp zqxDC1pA&$EoI8q_`eoBJ-u&cx+|HZEg6IdJXJKL_?0Mw~b@9J*E*s;|iVp(|uYOf# zzCF(NGWrpg4*m-SUn!EiA>buk(|NO~$s2TP-#kvWG*H?izfOuD@Fk=B_x7}t^phy< zsf-Y4A670gtP*^9*JuYfu(yul_8NhbhSgn46>x)XP`$BX%=ac?WUa(+IvAS5D=43~ z5btB4uxS$BR91S>N)UOi%{3*ZqHCqL-|MSOd${GQ;6JhUb)u{)kl!!(T#0qi4Lua1 zqu2)K=%r+kJr9(re`{#ZL3lvJ0*8ql6$$eMapQRp`R8Lh_`iOzdcDF%D=nbAM_(ON z^!XC3;8HipL)!J#nsL=z-C<19ph3DEDpMA$!tE`hx3h7lGGaOy=1bpuqPd{e8YinO zKsY9a+*YO9kMZxo9DdVY(%3l9i0BOM1HxP1f}>Tk5w3HlbnR}k-bY`Z#Yq3lTxMGl zP;ggDR7!J{L7KRxYAwxra82F%Plho*_KJz;6U#84Vk~e3@+lv#b4eA3+t0HM;I$Wy z(r&~Qvz7;$OTVXGuyxhTEnh@zJpirNvm^MqtV}jx zK0R91^q!oIXqtI$unr{NZX9Lnpc5^|WJ@n+!0Rq+`5fs!*XFaTc4NK(on}r#cf8q0 zCpUyIi|aUwcL2oJ$B002LrP(2F_?aGiD@Usru$IqUC&*i#be%i9+=MZ+hDcU}D>P8pC1uf0>*}b%KEPzq35S@snz#|$>-g|VmJa5Am3(O1t=rE#qfa`F zL@w}*9D>_$+l(C2tDX0^Gq4tuSHbs&Co(Z;BW%kCG{*T26Qf3DKX~cV!(@39!LTOl)9SsNiM%Zj2{ryGX x8x~Vf1tLO10+JO`RG)2As9}%dR&-0jhCmd)vTKj;D{|3`xaMu6; literal 0 HcmV?d00001 diff --git a/core/src/com/me/pacman/Assets.java b/core/src/com/me/pacman/Assets.java index ce9f425..fc0b6e8 100644 --- a/core/src/com/me/pacman/Assets.java +++ b/core/src/com/me/pacman/Assets.java @@ -18,6 +18,7 @@ public class Assets { private Texture levelBackground; private Texture levelWinBackground; private Texture menuBackground; + private Texture highScoresBackground; public TextureRegion[][] font; public TextureRegion[][] level; @@ -44,6 +45,7 @@ public class Assets { manager.load("level_background.png", Texture.class); manager.load("level_background_win.png", Texture.class); manager.load("menu_background.png", Texture.class); + manager.load("high_scores_background.png", Texture.class); manager.load("logo.png", Texture.class); manager.load("sprites/font.png", Texture.class); @@ -75,6 +77,7 @@ public class Assets { levelBackground = manager.get("level_background.png", Texture.class); levelWinBackground = manager.get("level_background_win.png", Texture.class); menuBackground = manager.get("menu_background.png", Texture.class); + highScoresBackground = manager.get("high_scores_background.png", Texture.class); // cache our texture regions font = TextureRegion.split(manager.get("sprites/font.png", Texture.class), 8, 8); @@ -114,6 +117,8 @@ public class Assets { return menuBackground; } + public Texture getHighScoresBackground() { return highScoresBackground; } + public Texture getLogo() { return manager.get("logo.png", Texture.class); } diff --git a/core/src/com/me/pacman/FontRenderer.java b/core/src/com/me/pacman/FontRenderer.java index 75f1e94..0ec9a11 100644 --- a/core/src/com/me/pacman/FontRenderer.java +++ b/core/src/com/me/pacman/FontRenderer.java @@ -7,8 +7,8 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; public class FontRenderer { - private static final char[] CHARS = "abcdefghijklmnopqrstuvwxyz0123456789!?()[]<>$&*:#^~-_/\\".toCharArray(); - private static final int[] CHAR_TO_INDEX = new int[256]; + public static final char[] CHARS = "abcdefghijklmnopqrstuvwxyz0123456789!?()[]<>$&*:#^~-_/\\".toCharArray(); + public static final int[] CHAR_TO_INDEX = new int[256]; private Color color = Color.WHITE; private TextureRegion[][] sprites; diff --git a/core/src/com/me/pacman/HighScores.java b/core/src/com/me/pacman/HighScores.java new file mode 100644 index 0000000..192113a --- /dev/null +++ b/core/src/com/me/pacman/HighScores.java @@ -0,0 +1,67 @@ +package com.me.pacman; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; + +/** + * A simple class for retrieving and saving high scores to persistent storage. + * + * Scores are saved in a simple text file + */ +public class HighScores { + + public static final String FILE = "scores.dat"; + + private FileHandle file; + + private Array scores = new Array<>(10); + + public HighScores() { + file = Gdx.files.local(FILE); + loadScores(); + } + + private void loadScores() { + if (!file.exists()) { + return; + } + + String data = file.readString(); + String[] lines = data.split("\n"); + + for (String line : lines) { + String[] parts = line.split("\t"); + scores.add(new Score(parts[0], Integer.parseInt(parts[1]))); + } + } + + private void saveScores() { + for (int i = 0; i < scores.size; i++) { + Score score = scores.get(i); + boolean append = i > 0; + file.writeString(String.format("%s\t%d\n", score.scorer, score.score), append); + } + } + + private void sortScores() { + scores.sort(Score.SCORE_SORTER); + } + + public Score getCurrentHighScore() { + return scores.size > 0 ? scores.get(0) : null; + } + + public Score[] getHighScores(int count) { + Score[] ret = new Score[Math.min(count, scores.size)]; + System.arraycopy(scores.items, 0, ret, 0, ret.length); + return ret; + } + + public void addScore(Score score) { + scores.add(score); + sortScores(); + saveScores(); + } + +} diff --git a/core/src/com/me/pacman/PacDude.java b/core/src/com/me/pacman/PacDude.java index 89bec36..052cce2 100644 --- a/core/src/com/me/pacman/PacDude.java +++ b/core/src/com/me/pacman/PacDude.java @@ -2,12 +2,15 @@ package com.me.pacman; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.viewport.FitViewport; import com.badlogic.gdx.utils.viewport.Viewport; +import com.me.pacman.state.HighScoresState; import com.me.pacman.state.MenuState; +import com.me.pacman.state.State; public class PacDude extends Game { @@ -19,6 +22,8 @@ public class PacDude extends Game { public static final int LEVEL_WIDTH = 224; public static final int LEVEL_HEIGHT = 288; + public HighScores highScores; + public Assets assets; public Sound sound; @@ -28,12 +33,16 @@ public class PacDude extends Game { public OrthographicCamera cam; public Viewport viewport; + private State nextState; + @Override public void create () { cam = new OrthographicCamera(); viewport = new FitViewport(LEVEL_WIDTH, LEVEL_HEIGHT, cam); viewport.apply(true); + highScores = new HighScores(); + assets = new Assets(); assets.loadAssets(); sound = new Sound(this); @@ -42,13 +51,21 @@ public class PacDude extends Game { fontRenderer = new FontRenderer(assets.font); Gdx.gl.glClearColor(0, 0, 0, 1); - setScreen(new MenuState(this)); + setNextState(new MenuState(this)); } @Override public void render () { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + if (nextState != null) { + Screen currScreen = getScreen(); + if (currScreen != null) currScreen.dispose(); + nextState.setup(); + super.setScreen(nextState); + nextState = null; + } + batch.begin(); if (DEBUG) { fontRenderer.draw(batch, "fps:" + Gdx.graphics.getFramesPerSecond(), 19 * 8, 34 * 8); @@ -71,4 +88,14 @@ public class PacDude extends Game { batch.dispose(); assets.dispose(); } + + @Override + public void setScreen(Screen screen) { + throw new IllegalStateException("Use setNextState instead."); + } + + public void setNextState(State state) { + this.nextState = state; + } + } diff --git a/core/src/com/me/pacman/Score.java b/core/src/com/me/pacman/Score.java new file mode 100644 index 0000000..05f3662 --- /dev/null +++ b/core/src/com/me/pacman/Score.java @@ -0,0 +1,22 @@ +package com.me.pacman; + +import java.util.Comparator; + +public final class Score { + + public String scorer; + public int score; + + public static final Comparator SCORE_SORTER = new Comparator() { + @Override + public int compare(Score a, Score b) { + return a.score < b.score? 1 : (a.score == b.score ? 0 : -1); + } + }; + + public Score(String scorer, int score) { + this.scorer = scorer; + this.score = score; + } + +} diff --git a/core/src/com/me/pacman/state/HighScoreEntryState.java b/core/src/com/me/pacman/state/HighScoreEntryState.java new file mode 100644 index 0000000..456b835 --- /dev/null +++ b/core/src/com/me/pacman/state/HighScoreEntryState.java @@ -0,0 +1,124 @@ +package com.me.pacman.state; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.me.pacman.FontRenderer; +import com.me.pacman.Score; +import com.me.pacman.PacDude; + +public class HighScoreEntryState extends State { + + private Texture background; + private Score score; + + private int currLetter; + private char[] name; + + private boolean flash; + private float elapsed; + + public HighScoreEntryState(PacDude game, Score score) { + super(game); + this.score = score; + this.currLetter = 0; + this.flash = false; + this.elapsed = 0f; + this.name = score.scorer.toCharArray(); + } + + @Override + public void setup() { + this.background = game.assets.getHighScoresBackground(); + Gdx.input.setInputProcessor(this.new Controller()); + } + + @Override + public void render() { + game.batch.draw(background, 0, 16); + + game.fontRenderer.setColor(Color.YELLOW); + game.fontRenderer.draw(game.batch, "high scores", (8 * 8) + 4, 25 * 8); + + game.fontRenderer.setColor(Color.CHARTREUSE); + game.fontRenderer.draw(game.batch, "score name", (8 * 8) + 4, 23 * 8); + + + game.fontRenderer.setColor(Color.BLUE); + game.fontRenderer.draw(game.batch, "" + score.score, (8 * 8) + 4, 18 * 9); + for (int i = 0; i < 3; i++) { + game.fontRenderer.draw(game.batch, String.valueOf((i == currLetter && flash)? '_' : name[i]), (16 + i) * 8 + 4, 18 * 9); + } + + game.fontRenderer.setColor(Color.WHITE); + Score[] scores = game.highScores.getHighScores(9); + for (int i = 0; i < scores.length; i++) { + Score score = scores[i]; + game.fontRenderer.draw(game.batch, String.format("%-8d%s", score.score, score.scorer), (8 * 8) + 4, (16 - i) * 9); + } + } + + @Override + public void update(float dt) { + elapsed += dt; + if (elapsed >= 1/3f) { + elapsed = 0f; + flash = !flash; + } + } + + @Override + public void dispose() { + Gdx.input.setInputProcessor(null); + } + + private final class Controller extends InputAdapter { + + @Override + public boolean keyDown(int keycode) { + switch(keycode) { + case Input.Keys.DOWN: + int nextIndex = FontRenderer.CHAR_TO_INDEX[name[currLetter]] - 1; + if (nextIndex < 0) { + nextIndex = 25; + } + flash = false; + name[currLetter] = FontRenderer.CHARS[nextIndex]; + break; + case Input.Keys.UP: + nextIndex = FontRenderer.CHAR_TO_INDEX[name[currLetter]] + 1; + if (nextIndex > 25) { + nextIndex = 0; + } + flash = false; + name[currLetter] = FontRenderer.CHARS[nextIndex]; + break; + case Input.Keys.RIGHT: + currLetter++; + if (currLetter > 2) { + currLetter = 0; + } + flash = true; + break; + case Input.Keys.LEFT: + currLetter--; + if (currLetter < 0) { + currLetter = 2; + } + flash = true; + break; + case Input.Keys.ENTER: + score.scorer = String.valueOf(name); + game.highScores.addScore(score); + game.setNextState(new HighScoresState(game)); + break; + } + elapsed = 0f; + return super.keyDown(keycode); + } + + } + +} diff --git a/core/src/com/me/pacman/state/HighScoresState.java b/core/src/com/me/pacman/state/HighScoresState.java new file mode 100644 index 0000000..d61087a --- /dev/null +++ b/core/src/com/me/pacman/state/HighScoresState.java @@ -0,0 +1,67 @@ +package com.me.pacman.state; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.me.pacman.PacDude; +import com.me.pacman.Score; + +public class HighScoresState extends State { + + + private Texture background; + + public HighScoresState(PacDude game) { + super(game); + } + + @Override + public void setup() { + this.background = game.assets.getHighScoresBackground(); + Gdx.input.setInputProcessor(this.new Controller()); + } + + @Override + public void render() { + game.batch.draw(background, 0, 16); + + game.fontRenderer.setColor(Color.YELLOW); + game.fontRenderer.draw(game.batch, "high scores", (8 * 8) + 4, 25 * 8); + + game.fontRenderer.setColor(Color.CHARTREUSE); + game.fontRenderer.draw(game.batch, "score name", (8 * 8) + 4, 23 * 8); + + game.fontRenderer.setColor(Color.WHITE); + Score[] scores = game.highScores.getHighScores(10); + for (int i = 0; i < scores.length; i++) { + Score score = scores[i]; + game.fontRenderer.draw(game.batch, String.format("%-8d%s", score.score, score.scorer), (8 * 8) + 4, (17 - i) * 9); + } + } + + @Override + public void dispose() { + Gdx.input.setInputProcessor(null); + } + + @Override + public void update(float dt) {} + + private final class Controller extends InputAdapter { + + @Override + public boolean keyDown(int keycode) { + switch(keycode) { + case Input.Keys.ENTER: + case Input.Keys.ESCAPE: + game.setNextState(new MenuState(game)); + break; + } + return super.keyDown(keycode); + } + + } + +} diff --git a/core/src/com/me/pacman/state/MenuState.java b/core/src/com/me/pacman/state/MenuState.java index 2e42adb..a2087b2 100644 --- a/core/src/com/me/pacman/state/MenuState.java +++ b/core/src/com/me/pacman/state/MenuState.java @@ -11,7 +11,7 @@ import com.me.pacman.Sound; public class MenuState extends LevelState { - private Texture levelBackground; + private Texture background; private Texture logo; @@ -29,7 +29,7 @@ public class MenuState extends LevelState { @Override public void setup() { - levelBackground = game.assets.getMenuBackground(); + background = game.assets.getMenuBackground(); logo = game.assets.getLogo(); logo.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); @@ -48,7 +48,7 @@ public class MenuState extends LevelState { @Override public void render() { - game.batch.draw(levelBackground, 0, 16); + game.batch.draw(background, 0, 16); game.batch.draw(logo, 0, 140, 224, 120); @@ -80,10 +80,10 @@ public class MenuState extends LevelState { case Input.Keys.ENTER: switch (selectedOption) { case NEW_GAME: - game.setScreen(new PlayState(game)); + game.setNextState(new PlayState(game)); break; case HIGH_SCORES: -// game.setScreen(new HighScores(game)); + game.setNextState(new HighScoresState(game)); break; } break; @@ -106,9 +106,9 @@ public class MenuState extends LevelState { public boolean touchUp(int screenX, int screenY, int pointer, int button) { Vector2 coords = game.viewport.unproject(new Vector2(screenX, screenY)); if (selectedOption == 0 && NEW_GAME_BOX.contains(coords)) { - game.setScreen(new PlayState(game)); + game.setNextState(new PlayState(game)); } else if (selectedOption == 1 && HIGH_SCORE_BOX.contains(coords)) { - selectedOption = -1; + game.setNextState(new HighScoresState(game)); } else { selectedOption = -1; } diff --git a/core/src/com/me/pacman/state/State.java b/core/src/com/me/pacman/state/State.java index 30087a9..5d28e44 100644 --- a/core/src/com/me/pacman/state/State.java +++ b/core/src/com/me/pacman/state/State.java @@ -10,7 +10,6 @@ public abstract class State extends ScreenAdapter { public State(PacDude game) { this.game = game; - this.setup(); } @Override