From caa8723afebfa1e9cef5247e801d7b0358af6924 Mon Sep 17 00:00:00 2001 From: mae Date: Fri, 12 Jan 2024 02:02:14 +0000 Subject: [PATCH] highscores --- debug.js | 6 +++ highscore.js | 37 +++++++++++++ main.js | 46 ++++++++++------ screenGame.js | 2 +- screenHighscoreInput.js | 114 ++++++++++++++++++++++++++++++++++++++++ screenSongSelect.js | 30 +++++++++++ ui.js | 6 ++- 7 files changed, 222 insertions(+), 19 deletions(-) create mode 100644 debug.js create mode 100644 highscore.js create mode 100644 screenHighscoreInput.js diff --git a/debug.js b/debug.js new file mode 100644 index 0000000..5777f0f --- /dev/null +++ b/debug.js @@ -0,0 +1,6 @@ +export function debugMsg(msg) { + fill(255); + stroke(0); + textSize(12); + text(msg, 24, 24); +} \ No newline at end of file diff --git a/highscore.js b/highscore.js new file mode 100644 index 0000000..1a21998 --- /dev/null +++ b/highscore.js @@ -0,0 +1,37 @@ +class HighscoreManager { + constructor() { + this._deserialize(); + } + + _deserialize() { + let raw = localStorage.getItem('rhythm.hst'); + if(!raw) { + this._highscores = {}; + this._serialize(); + } else { + this._highscores = JSON.parse(atob(raw)); + } + } + + _serialize() { + localStorage.setItem('rhythm.hst', btoa(JSON.stringify(this._highscores))); + } + + getHighscore(songId) { + return this._highscores[songId] + } + + setHighscore(songId, name, score) { + let existing = this.getHighscore(songId); + if(existing != undefined && existing.score <= score) + return; + + this._highscores[songId] = { + name, + score + } + this._serialize(); + } +} + +export default new HighscoreManager(); \ No newline at end of file diff --git a/main.js b/main.js index fc78b2c..d712411 100644 --- a/main.js +++ b/main.js @@ -1,25 +1,21 @@ -import { - Entity, - Sprite -} from './entity.js'; -import { GameScreen } from './screenGame.js'; import { SongSelectScreen } from './screenSongSelect.js'; -import { - KeyHint -} from './ui.js' import chartmgr from './chartmgr.js'; import state from './state.js'; +import { HighscoreInputScreen } from './screenHighscoreInput.js' +import { debugMsg } from './debug.js'; +import highscore from './highscore.js'; const charts = [ "bozo", "dashstar", "golddust", - "pixelpalace" + "pixelpalace", // "test" ] // STUFF let songSelectScreen; +export let highscoreInputScreen; // ASSETS let sndBoop; @@ -32,13 +28,6 @@ function blur(col, blurFactor) { drawingContext.shadowBlur = blurFactor; } -function debugMsg(msg) { - fill(255); - stroke(0); - textSize(12); - text(msg, 24, 24); -} - function drawFps() { let fps = frameRate(); fill(255); @@ -105,6 +94,18 @@ function draw() { break; } + + if(window.gameScreen.song.duration() - 0.01 < window.gameScreen.song.currentTime()) { + if( + highscore.getHighscore(window.gameScreen.chart.id) == undefined + || window.gameScreen.score.score > highscore.getHighscore(this.chart.id) + ) { + highscoreInputScreen = new HighscoreInputScreen(window.gameScreen.chart.id, window.gameScreen.score.score); + state.setState("highscoreInput") + } else { + state.setState("songselect") + } + } window.gameScreen.calcBeat(); window.gameScreen.draw(); @@ -117,6 +118,15 @@ function draw() { } songSelectScreen.draw() break; + + case "highscoreInput": + if(!highscoreInputScreen) { + debugMsg(`ERROR: HSI BUT NO SETUP`) + break; + } + + highscoreInputScreen.draw(); + break; } drawFps(); @@ -131,6 +141,10 @@ function keyPressed() { case "songselect": songSelectScreen.keyPressed() break; + + case "highscoreInput": + highscoreInputScreen.keyPressed(); + break; } } diff --git a/screenGame.js b/screenGame.js index 5ba051b..d249d8f 100644 --- a/screenGame.js +++ b/screenGame.js @@ -8,6 +8,7 @@ import { PressIndicator, Highway } from './highway.js'; import { Note } from './note.js'; import { ScoreManager } from './score.js' import chartmgr from './chartmgr.js'; +import { debugMsg } from './debug.js'; export class GameScreen { constructor(chart) { @@ -109,7 +110,6 @@ export class GameScreen { if(targetNotes[0].beat + GRACE_BEAT > pressBeat && targetNotes[0].beat - GRACE_BEAT < pressBeat && keyIsDown(KEYS[k.lane])){ - // console.log("HIT", k.lane) // hit note! this.notes.find(n=> n.symbol == k.symbol).pressed = true; diff --git a/screenHighscoreInput.js b/screenHighscoreInput.js new file mode 100644 index 0000000..4931be8 --- /dev/null +++ b/screenHighscoreInput.js @@ -0,0 +1,114 @@ +import chartmgr from "./chartmgr.js" +import { Sprite } from './entity.js'; +import highscore from "./highscore.js"; +import state from "./state.js"; +import { KeyHint } from "./ui.js"; +import { sndBoop } from "./main.js"; + +class HighscoreSong extends Sprite { + static draw(img, name, artist, x, y) { + fill(255); + noStroke(); + + let wth = 0; + textSize(18); + let artistTextWidth = textWidth(artist); + textSize(24); + let songTextWidth = textWidth(artist); + + wth += Math.max(artistTextWidth, songTextWidth) + wth += 128 + + fill(50) + rect(x - (wth / 2) - 16, y - 16, wth + 32, 64 + 32, 8) + + fill(255) + textSize(18); + text(artist, x + 64 + 16 - (wth / 2), y + 56) + + textSize(24); + text(name, x + 64 + 16 - (wth / 2), y + 32) + + image(img, x - (wth / 2), y, 64, 64); + } +} + +export class HighscoreInputScreen { + constructor(...args) { + this._init(...args); + + this.name = ""; + } + + async _init(songId, score) { + this.song = await chartmgr.get(songId); + this.cover = chartmgr.covers.get(songId); + this.score = score; + } + + draw() { + if(!this.song) + return; + + let bigTitle = "NEW HIGHSCORE!"; + fill(255); + textSize(64); + let bigTitleW = (width - textWidth(bigTitle)); + text(bigTitle, bigTitleW / 2, 128); + + HighscoreSong.draw(this.cover, this.song.name, this.song.artist, + width / 2, + (height / 2) - 128 + ) + + fill(255); + textSize(48); + text(this.score, (bigTitleW / 2) + 128 + 32, 256 + 128 + 32 + 4); + + fill(255); + textSize(24); + text("NAME:", bigTitleW / 2, 256 + 128); + + for(let i = 0; i < 3; i++) { + fill(255); + if(i == this.name.length && (frameCount % 32) > 16) { + console.log(i) + fill(255,255,255,0) + } + text((this.name.length > i) ? this.name[i] : "_", (bigTitleW / 2) + (i*20), 256 + 128 + 36); + } + + if(this.name.length > 2) + KeyHint.draw("Enter", (bigTitleW / 2) + 8 + 64, 256 + 128 + 36 - 4) + } + + keyPressed() { + switch(keyCode) { + case 8: // backspace + this.name = this.name.slice(0, this.name.length - 1) + return; + + case 13: //enter + if(this.name.length > 2) { + sndBoop.play(); + highscore.setHighscore(this.song.id, this.name, this.score) + state.setState("songselect") + } + return; + } + + if(this.name.length > 2) + return + + // special characters are > 1 letter (eg. SHIFT) + if(key.length > 1) + return; + + // regex to check if letter + if(!key.match(/[a-z]/i)) + return + + sndBoop.play(); + this.name += key.toUpperCase(); + } +} \ No newline at end of file diff --git a/screenSongSelect.js b/screenSongSelect.js index 4af3a96..4bfdc6c 100644 --- a/screenSongSelect.js +++ b/screenSongSelect.js @@ -2,6 +2,7 @@ import state from './state.js'; import chartmgr from './chartmgr.js'; import { KeyHint } from './ui.js' import { sndBoop, sndSongselect } from './main.js'; +import highscore from './highscore.js'; export class SongSelectScreen { constructor() { @@ -25,16 +26,19 @@ export class SongSelectScreen { // current song image(this.covers[this.curSelection], (width-256)/2, (height-256)/2, 256, 256) + // song name textSize(48); text(this.songs[this.curSelection].name, (width / 2) - (textWidth(this.songs[this.curSelection].name) / 2), height - 128 - 36); + // song artist textSize(24); text(this.songs[this.curSelection].artist, (width / 2) - (textWidth(this.songs[this.curSelection].artist) / 2), height - 128); + // song meta let etcmeta = this.songs[this.curSelection].difficulty + " - " + this.songs[this.curSelection].len textSize(18); @@ -42,6 +46,8 @@ export class SongSelectScreen { (width - textWidth(etcmeta) ) / 2, height - 128 + 32); + + // cover art side let nextSelection = (this.curSelection + 1 > this.songs.length - 1) ? 0 : this.curSelection + 1 @@ -55,6 +61,30 @@ export class SongSelectScreen { image(this.covers[nextSelection], (width - 128) - 32, (height - 128) / 2, 128, 128); + + noStroke() + textSize(24); + + if(highscore.getHighscore(this.songs[this.curSelection].id) != undefined) { + let hsw = textWidth("HIGH SCORE") + text("HIGH SCORE", + ((width - hsw) / 2) - 48, + height - 512 - 64 + ); + + textSize(16); + text(highscore.getHighscore(this.songs[this.curSelection].id).name, + ((width - hsw) / 2) - 48, + height - 512 - 32 + ); + + textAlign(RIGHT); + text(highscore.getHighscore(this.songs[this.curSelection].id).score, + (((width + 256) / 2)), + height - 512 - 32 + ); + textAlign(LEFT); + } } async keyPressed() { diff --git a/ui.js b/ui.js index f61c198..d454829 100644 --- a/ui.js +++ b/ui.js @@ -38,11 +38,13 @@ export class CurrentSongUi extends Sprite { static draw(img, name, artist) { fill(255); + image(img, (width / 2) + 175, 40 - 32 + 6, 64, 64 + 4); + textSize(18); - text(artist, (width / 2) + 175 + 40, 40 + 24) + text(artist, (width / 2) + 175 + 40 + 32 + 4, 40 + 24 + 4) textSize(24); - text(name, (width / 2) + 175 + 40, 40) + text(name, (width / 2) + 175 + 40 + 32 + 4, 40 + 4) } }