From d6350a900c84309c0e8479b2af52ab3c411ef509 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Wed, 3 Oct 2018 12:48:18 +0300 Subject: [PATCH 1/2] Scoresheet: Add counting up animation --- public/src/js/assets.js | 52 ++++++----- public/src/js/canvasasset.js | 2 +- public/src/js/canvasdraw.js | 2 + public/src/js/controller.js | 24 +++-- public/src/js/game.js | 60 +++++------- public/src/js/keyboard.js | 4 +- public/src/js/loader.js | 16 +++- public/src/js/mekadon.js | 2 +- public/src/js/p2.js | 5 +- public/src/js/scoresheet.js | 171 +++++++++++++++++++++++++++++------ public/src/js/soundbuffer.js | 30 ++++-- public/src/js/view.js | 41 +++++---- public/src/js/viewassets.js | 2 +- 13 files changed, 277 insertions(+), 134 deletions(-) diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 04414dd..24df5e7 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -41,26 +41,9 @@ var assets = { "bg_score_p2.png" ], "audioSfx": [ - "start.wav", "don.wav", "ka.wav", - - "combo-50.wav", - "combo-100.wav", - "combo-200.wav", - "combo-300.wav", - "combo-400.wav", - "combo-500.wav", - "combo-600.wav", - "combo-700.wav", - "combo-800.wav", - "combo-900.wav", - "combo-1000.wav", - "combo-1100.wav", - "combo-1200.wav", - "combo-1300.wav", - "combo-1400.wav", - "fullcombo.wav", + "start.wav", "combo-50-meka.wav", "combo-100-meka.wav", @@ -84,16 +67,39 @@ var assets = { "pause.wav", "cancel.wav", "results.ogg", - "diffsel.wav", + "diffsel.wav" + ], + "audioSfxLR": [ + "note_don.ogg", + "note_ka.ogg", + "balloon.ogg", + "renda.ogg", + "combo-50.wav", + "combo-100.wav", + "combo-200.wav", + "combo-300.wav", + "combo-400.wav", + "combo-500.wav", + "combo-600.wav", + "combo-700.wav", + "combo-800.wav", + "combo-900.wav", + "combo-1000.wav", + "combo-1100.wav", + "combo-1200.wav", + "combo-1300.wav", + "combo-1400.wav", + + "fullcombo.wav", "gamefullcombo.wav", "gameclear.wav", "gamefail.wav", - "note_don.ogg", - "note_ka.ogg", - "balloon.ogg", - "renda.ogg" + "results_fullcombo.ogg", + "results_fullcombo2.ogg", + "results_crown.ogg", + "results_countup.wav" ], "audioMusic": [ "bgm_songsel.ogg", diff --git a/public/src/js/canvasasset.js b/public/src/js/canvasasset.js index d3d37d0..07f17b3 100644 --- a/public/src/js/canvasasset.js +++ b/public/src/js/canvasasset.js @@ -12,7 +12,7 @@ class CanvasAsset{ if(this.animation){ var u = (a, b) => typeof a === "undefined" ? b : a var frame = 0 - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() if(this.animationEnd){ if(ms > this.animationEnd.ms){ this.animationEnd.callback() diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index a625af8..41c0cc3 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -390,6 +390,8 @@ drawn.push({text: symbol, x: -2, y: 0, w: 20, scale: [0.6, 0.5]}) }else if(symbol === " "){ drawn.push({text: symbol, x: 0, y: 0, w: 10}) + }else if(symbol === "'"){ + drawn.push({text: ",", x: 0, y: -15, w: 7, scale: [1, 0.7]}) }else if(r.en.test(symbol)){ // n-width drawn.push({text: symbol, x: 0, y: 0, w: 28, scale: [1, 0.95]}) diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 2ddf853..da8ec3c 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -4,6 +4,7 @@ class Controller{ this.songData = songData this.autoPlayEnabled = autoPlayEnabled this.multiplayer = multiplayer + this.snd = this.multiplayer ? "_p" + this.multiplayer : "" var backgroundURL = "/songs/" + this.selectedSong.folder + "/bg.png" var songParser = new ParseSong(songData) @@ -26,15 +27,9 @@ class Controller{ this.view.run() this.startMainLoop() if(syncWith){ - syncWith.game.getElapsedTime = () => { - return this.game.elapsedTime - } - this.game.setElapsedTime = - syncWith.game.setElapsedTime = time => { - this.game.elapsedTime.ms = time - syncWith.game.elapsedTime.ms = time - } syncWith.run() + syncWith.elapsedTime = this.game.elapsedTime + syncWith.startDate = this.game.startDate this.syncWith = syncWith } } @@ -71,7 +66,7 @@ class Controller{ if(this.multiplayer !== 2){ requestAnimationFrame(() => { if(this.syncWith){ - this.syncWith.game.elapsedTime.ms = this.game.elapsedTime.ms + this.syncWith.game.elapsedTime = this.game.elapsedTime } this.mainLoop() if(this.syncWith){ @@ -79,7 +74,7 @@ class Controller{ } }) } - var ms = this.game.getElapsedTime().ms + var ms = this.game.elapsedTime if(!this.game.isPaused()){ this.keyboard.checkGameKeys() @@ -121,7 +116,7 @@ class Controller{ }else{ vp = "fail" } - assets.sounds["game" + vp].play() + this.playSound("game" + vp) } displayResults(){ if(this.multiplayer !== 2){ @@ -147,12 +142,15 @@ class Controller{ taikoGame.run() } } + playSound(id, time){ + assets.sounds[id + this.snd].play(time) + } playSoundMeka(soundID, time){ var meka = "" if(this.autoPlayEnabled && !this.multiplayer){ meka = "-meka" } - assets.sounds[soundID + meka].play(time) + this.playSound(soundID + meka, time) } togglePause(){ if(this.syncWith){ @@ -173,7 +171,7 @@ class Controller{ return this.game.getSongData() } getElapsedTime(){ - return this.game.getElapsedTime() + return this.game.elapsedTime } getCircles(){ return this.game.getCircles() diff --git a/public/src/js/game.js b/public/src/js/game.js index 6a9714c..d8685b4 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -29,7 +29,6 @@ class Game{ this.musicFadeOut = 0 this.fadeOutStarted = false this.currentTimingPoint = 0 - this.offsetTime = 0 assets.songs.forEach(song => { if(song.id == selectedSong.folder){ @@ -43,12 +42,10 @@ class Game{ } initTiming(){ // Date when the chrono is started (before the game begins) - this.offsetDate = new Date() - this.offsetTime = Math.max(0, this.timeForDistanceCircle - this.songData.circles[0].ms) |0 - this.setElapsedTime(-this.offsetTime) + var offsetTime = Math.max(0, this.timeForDistanceCircle - this.songData.circles[0].ms) |0 + this.elapsedTime = -offsetTime // The real start for the game will start when chrono will reach 0 - this.startDate = new Date() - this.startDate.setMilliseconds(this.startDate.getMilliseconds() + this.offsetTime) + this.startDate = snd.buffer.getTime() * 1000 + offsetTime } update(){ // Main operations @@ -67,7 +64,7 @@ class Game{ var circles = this.songData.circles circles.forEach(circle => { if(!circle.getPlayed()){ - var ms = this.getElapsedTime().ms + var ms = this.elapsedTime var type = circle.getType() var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" var endTime = circle.getEndTime() + (drumrollNotes ? 0 : this.rules.bad) @@ -76,8 +73,8 @@ class Game{ if(drumrollNotes && !circle.rendaPlayed){ circle.rendaPlayed = true if(this.rules.difficulty === "easy"){ - assets.sounds["renda"].stop() - assets.sounds["renda"].play() + assets.sounds["renda" + this.controller.snd].stop() + this.controller.playSound("renda") } } } @@ -153,7 +150,7 @@ class Game{ }) } checkScore(circle, check){ - var ms = this.getElapsedTime().ms + var ms = this.elapsedTime var type = circle.getType() var keysDon = check === "don" || check === "daiDon" @@ -234,7 +231,7 @@ class Game{ circle.played(score) if(this.controller.multiplayer == 1){ p2.send("drumroll", { - pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit + pace: (this.elapsedTime - circle.getMS()) / circle.timesHit }) } }else{ @@ -256,7 +253,7 @@ class Game{ } var circleAnim = new Circle({ id: 0, - start: this.getElapsedTime().ms, + start: this.elapsedTime, type: sound, txt: "", speed: circle.speed, @@ -271,7 +268,7 @@ class Game{ whenLastCirclePlayed(){ var circles = this.songData.circles var lastCircle = circles[circles.length - 1] - var ms = this.getElapsedTime().ms + var ms = this.elapsedTime if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 2000){ this.fadeOutStarted = ms } @@ -279,7 +276,7 @@ class Game{ whenFadeoutMusic(){ var started = this.fadeOutStarted if(started){ - var ms = this.getElapsedTime().ms + var ms = this.elapsedTime if(this.musicFadeOut === 0){ if(this.controller.multiplayer === 1){ p2.send("gameresults", this.getGlobalScore()) @@ -302,13 +299,13 @@ class Game{ } checkTiming(){ if(this.songData.timingPoints[this.currentTimingPoint + 1]){ - if(this.getElapsedTime().ms >= this.songData.timingPoints[this.currentTimingPoint + 1].start){ + if(this.elapsedTime >= this.songData.timingPoints[this.currentTimingPoint + 1].start){ this.currentTimingPoint++ } } } playMainMusic(){ - var ms = this.getElapsedTime().ms + var ms = this.elapsedTime if(!this.mainMusicPlaying && (!this.fadeOutStarted || ms= 0 && !this.started){ - this.startDate = new Date() + this.startDate = snd.buffer.getTime() * 1000 this.elapsedTimeSincePause = 0 - this.setElapsedTime(this.getAccurateTime()) + this.elapsedTime = this.getAccurateTime() this.started = true }else if(ms < 0 || ms >= 0 && this.started){ - this.setElapsedTime(this.getAccurateTime()) + this.elapsedTime = this.getAccurateTime() } } getAccurateTime(){ if(this.isPaused()){ - return this.getElapsedTime().ms + return this.elapsedTime }else{ - var currentDate = new Date() - return currentDate.getTime() - this.startDate.getTime() - this.elapsedTimeSincePause + var currentDate = snd.buffer.getTime() * 1000 + return currentDate - this.startDate - this.elapsedTimeSincePause } } getCircles(){ diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index 0189390..67f6494 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -177,9 +177,9 @@ class Keyboard{ && circle.getType() === "balloon" && circle.requiredHits - circle.timesHit <= 1 ){ - assets.sounds["balloon"].play() + this.controller.playSound("balloon") }else{ - assets.sounds["note_" + sound].play() + this.controller.playSound("note_" + sound) } this.keyTime[sound] = this.keyTime[keyCode] }) diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 4633fe9..6deb0ab 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -36,9 +36,14 @@ class Loader{ snd.buffer = new SoundBuffer() snd.musicGain = snd.buffer.createGain() snd.sfxGain = snd.buffer.createGain() - snd.buffer.setCrossfade(snd.musicGain, snd.sfxGain, 0.5) snd.previewGain = snd.buffer.createGain() - snd.previewGain.setVolume(0.5) + snd.sfxGainL = snd.buffer.createGain("left") + snd.sfxGainR = snd.buffer.createGain("right") + snd.buffer.setCrossfade( + [snd.musicGain, snd.previewGain], + [snd.sfxGain, snd.sfxGainL, snd.sfxGainR], + 0.5 + ) assets.audioSfx.forEach(name => { this.promises.push(this.loadSound(name, snd.sfxGain)) @@ -46,6 +51,13 @@ class Loader{ assets.audioMusic.forEach(name => { this.promises.push(this.loadSound(name, snd.musicGain)) }) + assets.audioSfxLR.forEach(name => { + this.promises.push(this.loadSound(name, snd.sfxGain).then(sound => { + var id = this.getFilename(name) + assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL) + assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR) + })) + }) p2 = new P2Connection() diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index 2de0163..8dce1f9 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -89,7 +89,7 @@ class Mekadon{ return true } getMS(){ - return this.controller.getElapsedTime().ms + return this.controller.getElapsedTime() } setKey(keyCode, ms){ this.controller.setKey(keyCode, false) diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 1f932be..1874da8 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -100,7 +100,10 @@ class P2Connection{ this.otherConnected = false break case "gameresults": - this.results = response.value + this.results = {} + for(var i in response.value){ + this.results[i] = response.value[i].toString() + } break case "note": this.notes.push(response.value) diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index cf7e216..45d0de0 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -1,7 +1,10 @@ class Scoresheet{ constructor(controller, results, multiplayer){ this.controller = controller - this.results = results + this.results = {} + for(var i in results){ + this.results[i] = results[i].toString() + } this.multiplayer = multiplayer this.canvas = document.getElementById("canvas") @@ -14,6 +17,9 @@ class Scoresheet{ startDelay: 3300, hasPointer: 0 } + this.frame = 1000 / 60 + this.numbers = "001122334455667788900112233445".split("") + this.draw = new CanvasDraw() this.gamepad = new Gamepad({ @@ -57,17 +63,16 @@ class Scoresheet{ } toNext(){ var ms = this.getMS() - var elapsed = ms - this.state.screenMS - this.state.startDelay - if(this.state.screen === "fadeIn"){ - if(elapsed >= 3400){ - snd.musicGain.fadeOut(0.5) - this.state.screen = "fadeOut" - this.state.screenMS = ms - assets.sounds["don"].play() - }else if(elapsed >= 0 && elapsed <= 2400){ - this.state.screenMS = ms - 2400 - this.state.startDelay - assets.sounds["don"].play() - } + var elapsed = ms - this.state.screenMS + if(this.state.screen === "fadeIn" && elapsed >= this.state.startDelay){ + this.state.screen = "scoresShown" + this.state.screenMS = ms + assets.sounds["note_don"].play() + }else if(this.state.screen === "scoresShown" && elapsed >= 1000){ + snd.musicGain.fadeOut(0.5) + this.state.screen = "fadeOut" + this.state.screenMS = ms + assets.sounds["note_don"].play() } } @@ -116,7 +121,7 @@ class Scoresheet{ ctx.scale(ratio, ratio) this.canvas.style.width = (winW / this.pixelRatio) + "px" this.canvas.style.height = (winH / this.pixelRatio) + "px" - }else if(!document.hasFocus() && ms - this.state.screenMS - this.state.startDelay > 2400){ + }else if(!document.hasFocus() && this.state.screen === "scoresShown"){ return }else{ ctx.clearRect(0, 0, winW / ratio, winH / ratio) @@ -158,8 +163,12 @@ class Scoresheet{ }) ctx.fillStyle = "rgba(127, 28, 12, 0.5)" ctx.fillRect(0, winH / 2 - 12, winW, 12) - ctx.fillStyle = "#000" - ctx.fillRect(0, winH / 2 - 2, winW, 3) + ctx.fillStyle = "rgba(0, 0, 0, 0.25)" + ctx.fillRect(0, winH / 2, winW, 20) + if(bgOffset !== 0){ + ctx.fillStyle = "#000" + ctx.fillRect(0, winH / 2 - 2, winW, 2) + } ctx.fillStyle = "#fa4529" ctx.fillRect(0, 0, winW, frameTop + 64) ctx.fillStyle = "#bf2900" @@ -184,7 +193,11 @@ class Scoresheet{ ctx.fillStyle = this.multiplayer ? "rgba(138, 245, 247, 0.5)" : "rgba(249, 163, 149, 0.5)" ctx.fillRect(0, winH / 2, winW, 12) ctx.fillStyle = "#000" - ctx.fillRect(0, winH / 2 - 1, winW, 3) + if(bgOffset === 0){ + ctx.fillRect(0, winH / 2 - 2, winW, 4) + }else{ + ctx.fillRect(0, winH / 2, winW, 2) + } ctx.fillStyle = this.multiplayer ? "#6bbec0" : "#fa4529" ctx.fillRect(0, winH - frameTop - 64, winW, frameTop + 64) ctx.fillStyle = this.multiplayer ? "rgba(160, 228, 229, 0.8)" : "rgba(255, 144, 116, 0.8)" @@ -196,8 +209,8 @@ class Scoresheet{ ctx.restore() } - if(this.state.screen === "fadeOut"){ - var elapsed = 2400 + if(this.state.screen === "scoresShown" || this.state.screen === "fadeOut"){ + var elapsed = Infinity }else{ var elapsed = ms - this.state.screenMS - this.state.startDelay } @@ -331,12 +344,12 @@ class Scoresheet{ this.draw.layeredText({ ctx: ctx, text: "最大コンボ数", - x: 1150, + x: 1149, y: 193, fontSize: 29, fontFamily: this.font, align: "right", - width: 216, + width: 215, letterSpacing: 1 }, [ {outline: "#000", letterBorder: 8}, @@ -397,7 +410,7 @@ class Scoresheet{ results = p2.results } var crownType = null - if(results.bad === 0){ + if(results.bad === "0"){ crownType = "gold" }else if(results.gauge >= 50){ crownType = "silver" @@ -424,6 +437,16 @@ class Scoresheet{ shine = 2 - shine } } + if(this.state.screen === "fadeIn" && elapsed >= 1200 && !this.state["fullcomboPlayed" + p]){ + this.state["fullcomboPlayed" + p] = true + if(crownType === "gold" && !this.controller.autoPlayEnabled){ + this.playSound("results_fullcombo" + (p === 1 ? "2" : ""), p) + } + } + if(this.state.screen === "fadeIn" && elapsed >= 1650 && !this.state["crownPlayed" + p]){ + this.state["crownPlayed" + p] = true + this.playSound("results_crown", p) + } this.draw.crown({ ctx: ctx, type: crownType, @@ -444,6 +467,35 @@ class Scoresheet{ ctx.save() ctx.translate(frameLeft, frameTop) + var printNumbers = ["good", "ok", "bad", "maxCombo", "drumroll"] + if(!this.state["countupTime0"]){ + var times = {} + var lastTime = 0 + for(var p = 0; p < players; p++){ + var results = p === 0 ? this.results : p2.results + var currentTime = 3100 + results.points.length * 30 * this.frame + 1000 + if(currentTime > lastTime){ + lastTime = currentTime + } + } + for(var i in printNumbers){ + var largestTime = 0 + for(var p = 0; p < players; p++){ + var results = p === 0 ? this.results : p2.results + times[printNumbers[i]] = lastTime + 500 + var currentTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame + if(currentTime > largestTime){ + largestTime = currentTime + } + } + lastTime = largestTime + } + this.state.fadeInEnd = lastTime + for(var p = 0; p < players; p++){ + this.state["countupTime" + p] = times + } + } + for(var p = 0; p < players; p++){ var results = this.results if(p === 1){ @@ -451,9 +503,12 @@ class Scoresheet{ ctx.translate(0, p2Offset) } ctx.save() - var points = results.points.toString() + + this.state.countupShown = false + + var points = this.getNumber(results.points, 3100, elapsed) var scale = 1.3 - ctx.font = "36px " + this.font + ctx.font = "35px " + this.font ctx.translate(760, 286) ctx.scale(1 / scale, 1 * 1.1) ctx.textAlign = "center" @@ -461,28 +516,56 @@ class Scoresheet{ ctx.strokeStyle = "#fff" ctx.lineWidth = 0.5 for(var i = 0; i < points.length; i++){ - ctx.translate(-23 * scale, 0) + ctx.translate(-23.3 * scale, 0) ctx.fillText(points[points.length - i - 1], 0, 0) ctx.strokeText(points[points.length - i - 1], 0, 0) } ctx.restore() - var printNumbers = ["good", "ok", "bad", "maxCombo", "drumroll"] + if(!this.state["countupTime" + p]){ + var times = {} + var lastTime = 3100 + results.points.length * 30 * this.frame + 1000 + for(var i in printNumbers){ + times[printNumbers[i]] = lastTime + 500 + lastTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame + } + this.state["countupTime" + p] = times + } + for(var i in printNumbers){ + var start = this.state["countupTime" + p][printNumbers[i]] this.draw.layeredText({ ctx: ctx, - text: results[printNumbers[i]].toString(), + text: this.getNumber(results[printNumbers[i]], start, elapsed), x: 971 + 270 * Math.floor(i / 3), - y: 194 + (40 * (i % 3)), - fontSize: 27, + y: 196 + (40 * (i % 3)), + fontSize: 26, fontFamily: this.font, - letterSpacing: 4, + letterSpacing: 1, align: "right" }, [ {outline: "#000", letterBorder: 9}, {fill: "#fff"} ]) } + + if(this.state.countupShown){ + if(!this.state["countup" + p]){ + this.state["countup" + p] = true + this.loopSound("results_countup", p, [0.1, false, 0, 0, 0.07]) + } + }else if(this.state["countup" + p]){ + this.state["countup" + p] = false + this.stopSound("results_countup", p) + if(this.state.screen === "fadeIn"){ + this.playSound("note_don", p) + } + } + + if(this.state.screen === "fadeIn" && elapsed >= this.state.fadeInEnd){ + this.state.screen = "scoresShown" + this.state.screenMS = this.getMS() + } } ctx.restore() } @@ -510,6 +593,36 @@ class Scoresheet{ ctx.restore() } + getNumber(score, start, elapsed){ + var numberPos = Math.floor((elapsed - start) / this.frame) + if(numberPos < 0){ + return "" + } + var output = "" + for(var i = 0; i < score.length; i++){ + if(numberPos < 30 * (i + 1)){ + this.state.countupShown = true + return this.numbers[numberPos % 30] + output + }else{ + output = score[score.length - i - 1] + output + } + } + return output + } + + getSound(id, p){ + return assets.sounds[id + (this.multiplayer ? "_p" + (p + 1) : "")] + } + playSound(id, p){ + this.getSound(id, p).play() + } + loopSound(id, p, args){ + this.getSound(id, p).playLoop(...args) + } + stopSound(id, p){ + this.getSound(id, p).stop() + } + mod(length, index){ return ((index % length) + length) % length } diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index d185f6d..b9b97d4 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -16,12 +16,18 @@ return new Sound(gain || {soundBuffer: this}, buffer) }) } - createGain(){ - return new SoundGain(this) + createGain(channel){ + return new SoundGain(this, channel) } setCrossfade(gain1, gain2, median){ - gain1.setCrossfade(1 - median) - gain2.setCrossfade(median) + if(!Array.isArray(gain1)){ + gain1 = [gain1] + } + if(!Array.isArray(gain2)){ + gain2 = [gain2] + } + gain1.forEach(gain => gain.setCrossfade(1 - median)) + gain2.forEach(gain => gain.setCrossfade(median)) } getTime(){ return this.context.currentTime @@ -41,10 +47,17 @@ } } class SoundGain{ - constructor(soundBuffer){ + constructor(soundBuffer, channel){ this.soundBuffer = soundBuffer this.gainNode = soundBuffer.context.createGain() - this.gainNode.connect(soundBuffer.context.destination) + if(channel){ + var index = channel === "left" ? 0 : 1 + this.merger = soundBuffer.context.createChannelMerger(2) + this.merger.connect(soundBuffer.context.destination) + this.gainNode.connect(this.merger, 0, index) + }else{ + this.gainNode.connect(soundBuffer.context.destination) + } this.setVolume(1) } load(url){ @@ -87,6 +100,9 @@ class Sound{ this.timeouts = new Set() this.sources = new Set() } + copy(gain){ + return new Sound(gain, this.buffer) + } getTime(){ return this.soundBuffer.getTime() } @@ -132,7 +148,7 @@ class Sound{ }, 100) } addLoop(){ - if(this.getTime() > this.loop.started - 1){ + while(this.getTime() > this.loop.started - 1){ this.play(this.loop.started, true, this.loop.seek, this.loop.until) this.loop.started += this.loop.until - this.loop.seek } diff --git a/public/src/js/view.js b/public/src/js/view.js index 8e93dfe..8eb5ad6 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -59,7 +59,7 @@ class View{ gameSong.appendChild(document.createTextNode(this.songTitle)) gameSong.setAttribute("alt", this.songTitle) } - this.lastMousemove = this.controller.getElapsedTime().ms + this.lastMousemove = this.controller.getElapsedTime() pageEvents.mouseAdd(this, this.onmousemove.bind(this)) this.refresh() @@ -162,7 +162,7 @@ class View{ //this.drawTime() } updateDonFaces(){ - if(this.controller.getElapsedTime().ms >= this.nextBeat){ + if(this.controller.getElapsedTime() >= this.nextBeat){ this.nextBeat += this.beatInterval if(this.controller.getCombo() >= 50){ this.currentBigDonFace = (this.currentBigDonFace + 1) % 2 @@ -236,7 +236,7 @@ class View{ } drawMeasures(){ var measures = this.controller.getSongData().measures - var currentTime = this.controller.getElapsedTime().ms + var currentTime = this.controller.getElapsedTime() measures.forEach((measure, index)=>{ var timeForDistance = this.posToMs(this.distanceForCircle, measure.speed) @@ -251,7 +251,7 @@ class View{ } drawMeasure(measure){ var z = this.canvas.scale - var currentTime = this.controller.getElapsedTime().ms + var currentTime = this.controller.getElapsedTime() var measureX = this.slotX + this.msToPos(measure.ms - currentTime, measure.speed) this.ctx.strokeStyle = "#bab8b8" this.ctx.lineWidth = 2 @@ -348,7 +348,7 @@ class View{ } } drawPressedKeys(){ - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() var keyTime = this.controller.getKeyTime() var kbd = this.controller.getBindings() @@ -432,7 +432,7 @@ class View{ drawCircles(circles){ for(var i = circles.length; i--;){ var circle = circles[i] - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() var speed = circle.getSpeed() var timeForDistance = this.posToMs(this.distanceForCircle + this.bigCircleSize / 2, speed) @@ -499,7 +499,7 @@ class View{ var z = this.canvas.scale var fill, size, faceID var type = circle.getType() - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() var circleMs = circle.getMS() var endTime = circle.getEndTime() var animated = circle.isAnimated() @@ -607,7 +607,7 @@ class View{ togglePauseMenu(){ if(this.controller.game.isPaused()){ this.pauseMenu.style.display = "block" - this.lastMousemove = this.controller.getElapsedTime().ms + this.lastMousemove = this.controller.getElapsedTime() this.cursorHidden = false this.mouseIdle() }else{ @@ -626,7 +626,14 @@ class View{ } drawTime(){ var z = this.canvas.scale - var time = this.controller.getElapsedTime() + var ms = this.controller.getElapsedTime() + var sign = Math.sign(ms) < 0 ? "-" : "" + ms = Math.abs(ms) + (sign === "-" ? 1000 : 0) + var time = { + sec: Math.floor(ms / 1000) % 60, + min: Math.floor(ms / 1000 / 60) % 60, + hour: Math.floor(ms / 1000 / 60 / 60) % 60 + } this.ctx.globalAlpha = 0.7 this.ctx.fillStyle = "#000" @@ -641,10 +648,10 @@ class View{ this.ctx.font = "normal " + (this.barH / 12) + "px Kozuka" this.ctx.textAlign = "right" - this.ctx.fillText(formatedH + ":" + formatedM + ":" + formatedS, + this.ctx.fillText(sign + formatedH + ":" + formatedM + ":" + formatedS, this.winW - 10 * z, this.winH - 30 * z ) - this.ctx.fillText(time.ms, this.winW - 10 * z, this.winH - 10 * z) + this.ctx.fillText(sign + Math.floor(ms), this.winW - 10 * z, this.winH - 10 * z) } drawBar(){ this.ctx.strokeStyle = "#000" @@ -655,7 +662,7 @@ class View{ this.ctx.closePath() this.ctx.fill() - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() var keyTime = this.controller.getKeyTime() var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka" if(this.gogoTime || ms <= this.gogoTimeStarted + 100){ @@ -666,7 +673,7 @@ class View{ grd.addColorStop(1, "#2c2a2c") this.ctx.fillStyle = grd this.ctx.rect(0, this.barY, this.winW, this.barH) - var alpha = Math.min(100, this.controller.getElapsedTime().ms - this.gogoTimeStarted) / 100 + var alpha = Math.min(100, this.controller.getElapsedTime() - this.gogoTimeStarted) / 100 if(!this.gogoTime){ alpha = 1 - alpha } @@ -755,7 +762,7 @@ class View{ } } drawGogoTime(){ - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() if(this.gogoTime){ var circles = this.controller.parsedSongData.circles @@ -788,7 +795,7 @@ class View{ && animation !== "gogo" ){ don.setAnimation("10combo") - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() don.setAnimationStart(ms) var length = don.getAnimationLength("normal") don.setUpdateSpeed(this.beatInterval / (length / 4)) @@ -797,13 +804,13 @@ class View{ } } onmousemove(event){ - this.lastMousemove = this.controller.getElapsedTime().ms + this.lastMousemove = this.controller.getElapsedTime() this.cursorHidden = false } mouseIdle(){ var lastMouse = pageEvents.getMouse() if(lastMouse && !this.cursorHidden){ - if(this.controller.getElapsedTime().ms >= this.lastMousemove + 2000){ + if(this.controller.getElapsedTime() >= this.lastMousemove + 2000){ this.cursor.style.top = lastMouse.clientY + "px" this.cursor.style.left = lastMouse.clientX + "px" this.cursor.style.pointerEvents = "auto" diff --git a/public/src/js/viewassets.js b/public/src/js/viewassets.js index 0e8592a..f6222c5 100644 --- a/public/src/js/viewassets.js +++ b/public/src/js/viewassets.js @@ -60,7 +60,7 @@ class ViewAssets{ var imgw = 360 var imgh = 370 var scale = 175 - var ms = this.controller.getElapsedTime().ms + var ms = this.controller.getElapsedTime() var elapsed = ms - this.view.gogoTimeStarted if(this.view.gogoTime){ var grow = 3 - Math.min(200, elapsed) / 100 From 3e84c4018405141254d01ea7bc640945050b3060 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Wed, 3 Oct 2018 17:22:40 +0300 Subject: [PATCH 2/2] Add autoplay badge, change game timing to new Date with fallback --- public/src/js/assets.js | 9 ++++++--- public/src/js/game.js | 26 ++++++++++++++++---------- public/src/js/loader.js | 5 +++++ public/src/js/scoresheet.js | 10 ++++++++-- public/src/js/view.js | 6 ++++++ 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 24df5e7..6f1c873 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -38,7 +38,8 @@ var assets = { "bg_genre_6.png", "bg_genre_7.png", "bg_score_p1.png", - "bg_score_p2.png" + "bg_score_p2.png", + "badge_auto.png" ], "audioSfx": [ "don.wav", @@ -66,8 +67,7 @@ var assets = { "title.ogg", "pause.wav", "cancel.wav", - "results.ogg", - "diffsel.wav" + "results.ogg" ], "audioSfxLR": [ "note_don.ogg", @@ -101,6 +101,9 @@ var assets = { "results_crown.ogg", "results_countup.wav" ], + "audioSfxLoud": [ + "diffsel.wav" + ], "audioMusic": [ "bgm_songsel.ogg", "bgm_result.ogg", diff --git a/public/src/js/game.js b/public/src/js/game.js index d8685b4..5498ac9 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -25,7 +25,6 @@ class Game{ this.paused = false this.started = false this.mainMusicPlaying = false - this.elapsedTimeSincePause = 0 this.musicFadeOut = 0 this.fadeOutStarted = false this.currentTimingPoint = 0 @@ -45,7 +44,7 @@ class Game{ var offsetTime = Math.max(0, this.timeForDistanceCircle - this.songData.circles[0].ms) |0 this.elapsedTime = -offsetTime // The real start for the game will start when chrono will reach 0 - this.startDate = snd.buffer.getTime() * 1000 + offsetTime + this.startDate = +(new Date) + offsetTime } update(){ // Main operations @@ -317,14 +316,15 @@ class Game{ if(!this.paused){ assets.sounds["pause"].play() this.paused = true - this.latestDate = snd.buffer.getTime() * 1000 + this.latestDate = +new Date this.mainAsset.stop() this.mainMusicPlaying = false }else{ assets.sounds["cancel"].play() this.paused = false - var currentDate = snd.buffer.getTime() * 1000 - this.elapsedTimeSincePause = this.elapsedTimeSincePause + currentDate - this.latestDate + var currentDate = +new Date + this.startDate += currentDate - this.latestDate + this.sndTime = currentDate - snd.buffer.getTime() * 1000 } } isPaused(){ @@ -334,20 +334,26 @@ class Game{ // Refreshed date var ms = this.elapsedTime if(ms >= 0 && !this.started){ - this.startDate = snd.buffer.getTime() * 1000 - this.elapsedTimeSincePause = 0 + this.startDate = +new Date this.elapsedTime = this.getAccurateTime() this.started = true + this.sndTime = this.startDate - snd.buffer.getTime() * 1000 }else if(ms < 0 || ms >= 0 && this.started){ - this.elapsedTime = this.getAccurateTime() + this.elapsedTime = this.getAccurateTime(ms >= 0) } } getAccurateTime(){ if(this.isPaused()){ return this.elapsedTime }else{ - var currentDate = snd.buffer.getTime() * 1000 - return currentDate - this.startDate - this.elapsedTimeSincePause + var currentDate = +new Date + var sndTime = currentDate - snd.buffer.getTime() * 1000 + var lag = sndTime - this.sndTime + if(Math.abs(lag) >= 50){ + this.startDate += lag + this.sndTime = sndTime + } + return currentDate - this.startDate } } getCircles(){ diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 6deb0ab..ce99d0e 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -39,11 +39,13 @@ class Loader{ snd.previewGain = snd.buffer.createGain() snd.sfxGainL = snd.buffer.createGain("left") snd.sfxGainR = snd.buffer.createGain("right") + snd.sfxLoudGain = snd.buffer.createGain() snd.buffer.setCrossfade( [snd.musicGain, snd.previewGain], [snd.sfxGain, snd.sfxGainL, snd.sfxGainR], 0.5 ) + snd.sfxLoudGain.setVolume(1.2) assets.audioSfx.forEach(name => { this.promises.push(this.loadSound(name, snd.sfxGain)) @@ -58,6 +60,9 @@ class Loader{ assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR) })) }) + assets.audioSfxLoud.forEach(name => { + this.promises.push(this.loadSound(name, snd.sfxLoudGain)) + }) p2 = new P2Connection() diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 45d0de0..8acd94c 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -270,6 +270,12 @@ class Scoresheet{ 276, 150, imgScale * 176, imgScale * 120 ) + if(this.controller.autoPlayEnabled){ + ctx.drawImage(assets.image["badge_auto"], + 431, 311, 34, 34 + ) + } + this.draw.roundedRect({ ctx: ctx, x: 532, @@ -439,7 +445,7 @@ class Scoresheet{ } if(this.state.screen === "fadeIn" && elapsed >= 1200 && !this.state["fullcomboPlayed" + p]){ this.state["fullcomboPlayed" + p] = true - if(crownType === "gold" && !this.controller.autoPlayEnabled){ + if(crownType === "gold"){ this.playSound("results_fullcombo" + (p === 1 ? "2" : ""), p) } } @@ -473,7 +479,7 @@ class Scoresheet{ var lastTime = 0 for(var p = 0; p < players; p++){ var results = p === 0 ? this.results : p2.results - var currentTime = 3100 + results.points.length * 30 * this.frame + 1000 + var currentTime = 3100 + results.points.length * 30 * this.frame if(currentTime > lastTime){ lastTime = currentTime } diff --git a/public/src/js/view.js b/public/src/js/view.js index 8eb5ad6..cdba97b 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -619,6 +619,12 @@ class View{ this.diffX, this.diffY, this.diffW, this.diffH ) + if(this.controller.autoPlayEnabled){ + this.ctx.drawImage(assets.image["badge_auto"], + this.diffX + this.diffW * 0.71, this.diffY + this.diffH * 0.01, + this.diffH * 0.3, this.diffH * 0.3 + ) + } this.ctx.drawImage(assets.image.taiko, this.taikoX, this.taikoY, this.taikoW, this.taikoH