From 03b9326733c3a9e0dfaf99e6c555ccc7c62e5c11 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sun, 17 Feb 2019 19:26:46 +0300 Subject: [PATCH 1/6] PraseTja: Add branches - Needs the following changes to the database: change `easy`, `normal`, `hard`, and `oni` to `TEXT` type - When adding songs to the database and if, for example, a song's 7-star difficulty has a branch, instead of `7` input `7 B`, this is to display song's branch support on the song selection - Branch can be forced in debug --- public/src/css/debug.css | 20 +++- public/src/js/canvasdraw.js | 1 + public/src/js/circle.js | 42 +------- public/src/js/debug.js | 64 ++++++++++-- public/src/js/game.js | 124 +++++++++++++++++----- public/src/js/importsongs.js | 2 +- public/src/js/keyboard.js | 4 +- public/src/js/mekadon.js | 16 +-- public/src/js/p2.js | 11 +- public/src/js/parsetja.js | 195 ++++++++++++++++++++++++----------- public/src/js/songselect.js | 64 ++++++++---- public/src/js/soundbuffer.js | 2 +- public/src/js/strings.js | 5 + public/src/js/titlescreen.js | 6 +- public/src/js/view.js | 70 +++++++++---- public/src/views/debug.html | 11 ++ server.py | 1 + 17 files changed, 445 insertions(+), 193 deletions(-) diff --git a/public/src/css/debug.css b/public/src/css/debug.css index 7c838f0..f9e1478 100644 --- a/public/src/css/debug.css +++ b/public/src/css/debug.css @@ -44,7 +44,8 @@ box-sizing: border-box; } -#debug .input-slider{ +#debug .input-slider, +#debug .select{ display: flex; width: 100%; height: 30px; @@ -59,7 +60,8 @@ padding: 2px 4px; text-align: center; } -#debug .input-slider>span{ +#debug .input-slider>span, +#debug .select>span{ display: block; width: 10%; height: 100%; @@ -70,10 +72,19 @@ line-height: 2em; cursor: pointer; } -#debug .input-slider>span:hover{ +#debug .input-slider>span:hover, +#debug .select>span:hover{ opacity: 1; background: #333; } +#debug .select select{ + width: 90%; + height: 100%; + box-sizing: border-box; + font-size: 18px; + font-family: sans-serif; + padding: 2px 4px; +} #debug label{ display: block; @@ -111,6 +122,7 @@ margin-left: 3px; } -#debug .autoplay-label{ +#debug .autoplay-label, +#debug .branch-hide{ display: none; } diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 472730c..8a072a4 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -1167,6 +1167,7 @@ var firstTop = config.multiplayer ? 0 : 30 var secondTop = config.multiplayer ? 0 : 8 + config.percentage = Math.max(0, Math.min(1, config.percentage)) var cleared = config.percentage - 1 / 50 >= config.clear var gaugeW = 14 * 50 diff --git a/public/src/js/circle.js b/public/src/js/circle.js index 6d3c650..261629e 100644 --- a/public/src/js/circle.js +++ b/public/src/js/circle.js @@ -1,6 +1,5 @@ class Circle{ constructor(config){ - // id, ms, type, text, speed, endTime, requiredHits this.id = config.id this.ms = config.start this.originalMS = this.ms @@ -23,38 +22,13 @@ class Circle{ this.gogoChecked = false this.beatMS = config.beatMS this.fixedPos = config.fixedPos - } - getMS(){ - return this.ms - } - getEndTime(){ - return this.endTime - } - getType(){ - return this.type - } - getLastFrame(){ - return this.lastFrame + this.branch = config.branch + this.section = config.section } animate(ms){ this.animating = true this.animT = ms } - isAnimated(){ - return this.animating - } - getAnimT(){ - return this.animT - } - getPlayed(){ - return this.isPlayed - } - isAnimationFinished(){ - return this.animationEnded - } - endAnimation(){ - this.animationEnded = true - } played(score, big){ this.score = score this.isPlayed = score <= 0 ? score - 1 : (big ? 2 : 1) @@ -65,16 +39,4 @@ class Circle{ this.timesKa++ } } - getScore(){ - return this.score - } - getID(){ - return this.id - } - getText(){ - return this.text - } - getSpeed(){ - return this.speed - } } \ No newline at end of file diff --git a/public/src/js/debug.js b/public/src/js/debug.js index 6b03534..607002d 100644 --- a/public/src/js/debug.js +++ b/public/src/js/debug.js @@ -8,15 +8,19 @@ class Debug{ this.debugDiv.innerHTML = assets.pages["debug"] document.body.appendChild(this.debugDiv) - this.titleDiv = this.debugDiv.getElementsByClassName("title")[0] - this.minimiseDiv = this.debugDiv.getElementsByClassName("minimise")[0] - this.offsetDiv = this.debugDiv.getElementsByClassName("offset")[0] - this.measureNumDiv = this.debugDiv.getElementsByClassName("measure-num")[0] - this.restartCheckbox = this.debugDiv.getElementsByClassName("change-restart")[0] - this.autoplayLabel = this.debugDiv.getElementsByClassName("autoplay-label")[0] - this.autoplayCheckbox = this.debugDiv.getElementsByClassName("autoplay")[0] - this.restartBtn = this.debugDiv.getElementsByClassName("restart-btn")[0] - this.exitBtn = this.debugDiv.getElementsByClassName("exit-btn")[0] + this.titleDiv = this.byClass("title") + this.minimiseDiv = this.byClass("minimise") + this.offsetDiv = this.byClass("offset") + this.measureNumDiv = this.byClass("measure-num") + this.branchHideDiv = this.byClass("branch-hide") + this.branchSelectDiv = this.byClass("branch-select") + this.branchSelect = this.branchSelectDiv.getElementsByTagName("select")[0] + this.branchResetBtn = this.branchSelectDiv.getElementsByClassName("reset")[0] + this.restartCheckbox = this.byClass("change-restart") + this.autoplayLabel = this.byClass("autoplay-label") + this.autoplayCheckbox = this.byClass("autoplay") + this.restartBtn = this.byClass("restart-btn") + this.exitBtn = this.byClass("exit-btn") this.moving = false pageEvents.add(window, ["mousedown", "mouseup", "blur"], this.stopMove.bind(this)) @@ -26,6 +30,8 @@ class Debug{ pageEvents.add(this.restartBtn, "click", this.restartSong.bind(this)) pageEvents.add(this.exitBtn, "click", this.clean.bind(this)) pageEvents.add(this.autoplayCheckbox, "change", this.toggleAutoplay.bind(this)) + pageEvents.add(this.branchSelect, "change", this.branchChange.bind(this)) + pageEvents.add(this.branchResetBtn, "click", this.branchReset.bind(this)) this.offsetSlider = new InputSlider(this.offsetDiv, -60, 60, 3) this.offsetSlider.onchange(this.offsetChange.bind(this)) @@ -39,6 +45,9 @@ class Debug{ this.updateStatus() pageEvents.send("debug") } + byClass(name){ + return this.debugDiv.getElementsByClassName(name)[0] + } startMove(event){ if(event.which === 1){ event.stopPropagation() @@ -88,17 +97,23 @@ class Debug{ } updateStatus(){ if(debugObj.controller && !this.controller){ + this.controller = debugObj.controller + this.restartBtn.style.display = "block" this.autoplayLabel.style.display = "block" + if(this.controller.parsedSongData.branches){ + this.branchHideDiv.style.display = "block" + } - this.controller = debugObj.controller var selectedSong = this.controller.selectedSong this.defaultOffset = selectedSong.offset || 0 if(this.songFolder === selectedSong.folder){ this.offsetChange(this.offsetSlider.get(), true) + this.branchChange(null, true) }else{ this.songFolder = selectedSong.folder this.offsetSlider.set(this.defaultOffset) + this.branchReset(null, true) } var measures = this.controller.parsedSongData.measures @@ -128,6 +143,7 @@ class Debug{ if(this.controller && !debugObj.controller){ this.restartBtn.style.display = "" this.autoplayLabel.style.display = "" + this.branchHideDiv.style.display = "" this.controller = null } } @@ -142,6 +158,11 @@ class Debug{ songData.measures.forEach(measure => { measure.ms = measure.originalMS + offset }) + if(songData.branches){ + songData.branches.forEach(branch => { + branch.ms = branch.originalMS + offset + }) + } if(this.restartCheckbox.checked && !noRestart){ this.restartSong() } @@ -171,21 +192,44 @@ class Debug{ } } } + branchChange(event, noRestart){ + if(this.controller){ + var game = this.controller.game + var name = this.branchSelect.value + game.branch = name === "auto" ? false : name + game.branchSet = false + if(this.restartCheckbox.checked && !noRestart){ + this.restartSong() + } + } + } + branchReset(event, noRestart){ + this.branchSelect.value = "auto" + this.branchChange(null, noRestart) + } clean(){ this.offsetSlider.clean() + this.measureNumSlider.clean() pageEvents.remove(window, ["mousedown", "mouseup", "blur"]) pageEvents.mouseRemove(this) + pageEvents.remove(this.titleDiv, "mousedown") pageEvents.remove(this.title, "mousedown") pageEvents.remove(this.minimiseDiv, "click") pageEvents.remove(this.restartBtn, "click") pageEvents.remove(this.exitBtn, "click") pageEvents.remove(this.autoplayCheckbox, "change") + pageEvents.remove(this.branchSelect, "change") + pageEvents.remove(this.branchResetBtn, "click") delete this.titleDiv delete this.minimiseDiv delete this.offsetDiv delete this.measureNumDiv + delete this.branchHideDiv + delete this.branchSelectDiv + delete this.branchSelect + delete this.branchResetBtn delete this.restartCheckbox delete this.autoplayLabel delete this.autoplayCheckbox diff --git a/public/src/js/game.js b/public/src/js/game.js index 76f7006..865b905 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -19,8 +19,8 @@ class Game{ difficulty: this.rules.difficulty } this.HPGain = 100 / this.songData.circles.filter(circle => { - var type = circle.getType() - return type === "don" || type === "ka" || type === "daiDon" || type === "daiKa" + var type = circle.type + return (type === "don" || type === "ka" || type === "daiDon" || type === "daiKa") && (!circle.branch || circle.branch.active) }).length this.paused = false this.started = false @@ -28,6 +28,8 @@ class Game{ this.musicFadeOut = 0 this.fadeOutStarted = false this.currentTimingPoint = 0 + this.sectionNotes = [] + this.sectionDrumroll = 0 assets.songs.forEach(song => { if(song.id == selectedSong.folder){ @@ -69,17 +71,18 @@ class Game{ } updateCirclesStatus(){ var nextSet = false + var ms = this.elapsedTime var circles = this.songData.circles var startIndex = this.currentCircle === 0 ? 0 : this.currentCircle - 1 - for(var i = startIndex; i < circles.length && i < this.currentCircle + 2; i++){ + var index = 0 + for(var i = startIndex; i < circles.length; i++){ var circle = circles[i] - if(!circle.getPlayed()){ - var ms = this.elapsedTime - var type = circle.getType() + if((!circle.branch || circle.branch.active) && !circle.isPlayed){ + var type = circle.type var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" - var endTime = circle.getEndTime() + (drumrollNotes ? 0 : this.rules.bad) + var endTime = circle.endTime + (drumrollNotes ? 0 : this.rules.bad) - if(ms >= circle.getMS()){ + if(ms >= circle.ms){ if(drumrollNotes && !circle.rendaPlayed && ms < endTime){ circle.rendaPlayed = true if(this.rules.difficulty === "easy"){ @@ -101,7 +104,7 @@ class Game{ this.updateCurrentCircle() if(this.controller.multiplayer === 1){ var value = { - pace: (ms - circle.getMS()) / circle.timesHit + pace: (ms - circle.ms) / circle.timesHit } if(type === "drumroll" || type === "daiDrumroll"){ value.kaAmount = circle.timesKa / circle.timesHit @@ -111,6 +114,7 @@ class Game{ }else{ var currentScore = 0 circle.played(-1, type === "daiDon" || type === "daiKa") + this.sectionNotes.push(0) this.controller.displayScore(currentScore, true) this.updateCurrentCircle() this.updateCombo(currentScore) @@ -126,6 +130,56 @@ class Game{ nextSet = true this.currentCircle = i } + if(index++ > 1){ + break + } + } + } + var branches = this.songData.branches + if(branches){ + if(this.controller.multiplayer === 2 || this.branch){ + var parent = this.controller.multiplayer === 2 ? p2 : this + var view = this.controller.view + if(view.branch !== parent.branch){ + view.branchAnimate = { + ms: ms, + fromBranch: view.branch + } + view.branch = parent.branch + } + if(!parent.branchSet){ + parent.branchSet = true + for(var i = 0; i < branches.length; i++){ + this.setBranch(branches[i], parent.branch) + } + } + }else{ + var measures = this.songData.measures + for(var i = 0; i < measures.length; i++){ + var measure = measures[i] + if(measure.ms > ms){ + break + }else if(measure.nextBranch && !measure.gameChecked){ + measure.gameChecked = true + var branch = measure.nextBranch + if(branch.type){ + if(branch.type === "drumroll"){ + var accuracy = this.sectionDrumroll + }else{ + var accuracy = this.sectionNotes.reduce((a, b) => a + b) / this.sectionNotes.length * 100 + } + if(accuracy >= branch.requirement[1]){ + this.setBranch(branch, "master") + }else if(accuracy >= branch.requirement[0]){ + this.setBranch(branch, "advanced") + }else{ + this.setBranch(branch, "normal") + } + }else if(this.controller.multiplayer === 1){ + p2.send("branch", "normal") + } + } + } } } } @@ -160,7 +214,7 @@ class Game{ } } checkKey(keyCodes, circle, check){ - if(circle && !circle.getPlayed()){ + if(circle && !circle.isPlayed){ if(!this.checkScore(circle, check)){ return } @@ -171,7 +225,7 @@ class Game{ } checkScore(circle, check){ var ms = this.elapsedTime - var type = circle.getType() + var type = circle.type var keysDon = check === "don" || check === "daiDon" var keysKa = check === "ka" || check === "daiKa" @@ -182,7 +236,7 @@ class Game{ var keyTime = this.controller.getKeyTime() var currentTime = keysDon ? keyTime["don"] : keyTime["ka"] - var relative = currentTime - circle.getMS() + var relative = currentTime - circle.ms if(typeDon || typeKa){ if(-this.rules.bad >= relative || relative >= this.rules.bad){ @@ -219,10 +273,11 @@ class Game{ this.updateCombo(score) this.updateGlobalScore(score, typeDai && keyDai ? 2 : 1, circle.gogoTime) this.updateCurrentCircle() - if(this.controller.multiplayer == 1){ + this.sectionNotes.push(score === 450 ? 1 : (score === 230 ? 0.5 : 0)) + if(this.controller.multiplayer === 1){ var value = { score: score, - ms: circle.getMS() - currentTime, + ms: circle.ms - currentTime, dai: typeDai ? keyDai ? 2 : 1 : 0 } if((!keysDon || !typeDon) && (!keysKa || !typeKa)){ @@ -231,12 +286,12 @@ class Game{ p2.send("note", value) } }else{ - if(circle.getMS() > currentTime || currentTime > circle.getEndTime()){ + if(circle.ms > currentTime || currentTime > circle.endTime){ return true } if(keysDon && type === "balloon"){ this.checkBalloon(circle) - if(check === "daiDon" && !circle.getPlayed()){ + if(check === "daiDon" && !circle.isPlayed){ this.checkBalloon(circle) } }else if((keysDon || keysKa) && (type === "drumroll" || type === "daiDrumroll")){ @@ -256,24 +311,25 @@ class Game{ circle.played(score) if(this.controller.multiplayer == 1){ p2.send("drumroll", { - pace: (this.elapsedTime - circle.getMS()) / circle.timesHit + pace: (this.elapsedTime - circle.ms) / circle.timesHit }) } }else{ var score = 300 circle.hit() } - this.globalScore.drumroll ++ + this.globalScore.drumroll++ + this.sectionDrumroll++ this.globalScore.points += score this.view.setDarkBg(false) } checkDrumroll(circle, keysKa){ var ms = this.elapsedTime - var dai = circle.getType() === "daiDrumroll" + var dai = circle.type === "daiDrumroll" var score = 100 circle.hit(keysKa) var keyTime = this.controller.getKeyTime() - if(circle.getType() === "drumroll"){ + if(circle.type === "drumroll"){ var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka" }else{ var sound = keyTime["don"] > keyTime["ka"] ? "daiDon" : "daiKa" @@ -291,6 +347,9 @@ class Game{ circleAnim.animate(ms) this.view.drumroll.push(circleAnim) this.globalScore.drumroll++ + if(this.controller.multiplayer !== 2){ + this.sectionDrumroll++ + } this.globalScore.points += score * (dai ? 2 : 1) this.view.setDarkBg(false) } @@ -298,11 +357,11 @@ class Game{ var ms = this.elapsedTime if(!this.lastCircle){ var circles = this.songData.circles - this.lastCircle = circles[circles.length - 1].getEndTime() + this.lastCircle = circles[circles.length - 1].endTime if(this.controller.multiplayer){ var syncWith = this.controller.syncWith var syncCircles = syncWith.game.songData.circles - var syncLastCircle = syncCircles[syncCircles.length - 1].getEndTime() + var syncLastCircle = syncCircles[syncCircles.length - 1].endTime if(syncLastCircle > this.lastCircle){ this.lastCircle = syncLastCircle } @@ -410,7 +469,14 @@ class Game{ return this.songData.circles } updateCurrentCircle(){ - this.currentCircle++ + var circles = this.songData.circles + do{ + var circle = circles[++this.currentCircle] + }while(circle && circle.branch && !circle.branch.active) + if(circle && circle.section){ + this.sectionNotes = [] + this.sectionDrumroll = 0 + } } getCurrentCircle(){ return this.currentCircle @@ -464,4 +530,16 @@ class Game{ } this.globalScore.points += Math.floor(score * multiplier / 10) * 10 } + setBranch(branch, name){ + var names = ["normal", "advanced", "master"] + for(var i in names){ + if(names[i] in branch){ + branch[names[i]].active = names[i] === name + } + } + branch.active = name + if(this.controller.multiplayer === 1){ + p2.send("branch", name) + } + } } diff --git a/public/src/js/importsongs.js b/public/src/js/importsongs.js index 400f443..cb907f5 100644 --- a/public/src/js/importsongs.js +++ b/public/src/js/importsongs.js @@ -199,7 +199,7 @@ songObj.subtitle = songObj.subtitle_en = subtitle songObj.preview = meta.demostart ? Math.floor(meta.demostart * 1000) : 0 if(meta.level){ - songObj.stars[this.courseTypes[diff]] = meta.level + songObj.stars[this.courseTypes[diff]] = meta.level + (meta.branch ? " B" : "") } if(meta.wave){ songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index 186c651..5925658 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -199,8 +199,8 @@ class Keyboard{ if( sound === "don" && circle - && !circle.getPlayed() - && circle.getType() === "balloon" + && !circle.isPlayed + && circle.type === "balloon" && circle.requiredHits - circle.timesHit <= 1 ){ this.controller.playSound("se_balloon") diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index cca80e2..22f7d73 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -6,12 +6,12 @@ class Mekadon{ this.lastHit = -Infinity } play(circle){ - var type = circle.getType() - if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.getEndTime()){ + var type = circle.type + if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.endTime){ circle.played(-1, false) this.game.updateCurrentCircle() } - type = circle.getType() + type = circle.type if(type === "balloon"){ this.playDrumrollAt(circle, 0, 30) }else if(type === "drumroll" || type === "daiDrumroll"){ @@ -21,7 +21,7 @@ class Mekadon{ } } playAt(circle, ms, score, dai, reverse){ - var currentMs = circle.getMS() - this.getMS() + var currentMs = circle.ms - this.getMS() if(ms > currentMs - 10){ return this.playNow(circle, score, dai, reverse) } @@ -36,18 +36,19 @@ class Mekadon{ } } miss(circle){ - var currentMs = circle.getMS() - this.getMS() + var currentMs = circle.ms - this.getMS() if(0 >= currentMs - 10){ this.controller.displayScore(0, true) this.game.updateCurrentCircle() this.game.updateCombo(0) this.game.updateGlobalScore(0, 1, circle.gogoTime) + this.game.sectionNotes.push(0) return true } } playNow(circle, score, dai, reverse){ var kbd = this.controller.getBindings() - var type = circle.getType() + var type = circle.type var keyDai = false var playDai = !dai || dai === 2 var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" @@ -55,7 +56,7 @@ class Mekadon{ if(drumrollNotes){ var ms = this.getMS() }else{ - var ms = circle.getMS() + var ms = circle.ms } if(reverse){ @@ -95,6 +96,7 @@ class Mekadon{ this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime) this.game.updateCurrentCircle() circle.played(score, keyDai) + this.game.sectionNotes.push(score === 450 ? 1 : (score === 230 ? 0.5 : 0)) } this.lastHit = ms return true diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 1f6f97e..a0c266d 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -109,6 +109,7 @@ class P2Connection{ this.dai = 2 this.kaAmount = 0 this.results = false + this.branch = "normal" break case "gameend": this.otherConnected = false @@ -141,6 +142,10 @@ class P2Connection{ this.kaAmount = response.value.kaAmount } break + case "branch": + this.branch = response.value + this.branchSet = false + break case "session": this.clearMessage("users") this.otherConnected = true @@ -161,10 +166,10 @@ class P2Connection{ } play(circle, mekadon){ if(this.otherConnected || this.notes.length > 0){ - var type = circle.getType() + var type = circle.type var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" - if(drumrollNotes && mekadon.getMS() > circle.getEndTime()){ + if(drumrollNotes && mekadon.getMS() > circle.endTime){ circle.played(-1, false) mekadon.game.updateCurrentCircle() } @@ -177,7 +182,7 @@ class P2Connection{ var note = this.notes[0] if(note.score >= 0){ var dai = 1 - if(circle.getType() === "daiDon" || circle.getType() === "daiKa"){ + if(circle.type === "daiDon" || circle.type === "daiKa"){ dai = this.dai } if(mekadon.playAt(circle, note.ms, note.score, dai, note.reverse)){ diff --git a/public/src/js/parsetja.js b/public/src/js/parsetja.js index 0055b99..262c0b9 100644 --- a/public/src/js/parsetja.js +++ b/public/src/js/parsetja.js @@ -59,7 +59,9 @@ if(!(courseName in courses)){ courses[courseName] = {} } - courses[courseName][name] = currentCourse[name] + if(name !== "branch"){ + courses[courseName][name] = currentCourse[name] + } } courses[courseName].start = lineNum + 1 courses[courseName].end = this.data.length @@ -70,6 +72,8 @@ hasSong = true courses[courseName].end = lineNum } + }else if(name.startsWith("branchstart") && inSong){ + courses[courseName].branch = true } }else if(!inSong){ @@ -128,9 +132,13 @@ var balloons = meta.balloon || [] var lastDrumroll = false + var branch = false - var branchType - var branchPreference = "m" + var branchObj = {} + var currentBranch = false + var branchSettings = {} + var branchPushed = false + var sectionBegin = true var currentMeasure = [] var firstNote = true @@ -138,19 +146,19 @@ var circleID = 0 var pushMeasure = () => { - if(barLine){ - var note = currentMeasure[0] - if(note){ - var speed = note.bpm * note.scroll / 60 - }else{ - var speed = bpm * scroll / 60 - } - this.measures.push({ - ms: ms, - originalMS: ms, - speed: speed - }) + var note = currentMeasure[0] + if(note){ + var speed = note.bpm * note.scroll / 60 + }else{ + var speed = bpm * scroll / 60 } + this.measures.push({ + ms: ms, + originalMS: ms, + speed: speed, + visible: barLine, + branch: currentBranch + }) if(currentMeasure.length){ for(var i = 0; i < currentMeasure.length; i++){ var note = currentMeasure[i] @@ -182,7 +190,9 @@ gogoTime: note.gogo, endTime: note.endTime, requiredHits: note.requiredHits, - beatMS: 60000 / note.bpm + beatMS: 60000 / note.bpm, + branch: currentBranch, + section: note.section }) if(lastDrumroll === note){ lastDrumroll = circleObj @@ -204,59 +214,112 @@ var line = line.slice(1).toLowerCase() var [name, value] = this.split(line, " ") - if(!branch || branch && branchType === branchPreference){ - switch(name){ - case "gogostart": - gogo = true - break - case "gogoend": - gogo = false - break - case "bpmchange": - bpm = parseFloat(value) - break - case "scroll": - scroll = parseFloat(value) - break - case "measure": - var [numerator, denominator] = value.split("/") - measure = numerator / denominator * 4 - break - case "delay": - ms += (parseFloat(value) || 0) * 1000 - break - case "barlineon": - barLine = true - break - case "barlineoff": - barLine = false - break - } - } switch(name){ + case "gogostart": + gogo = true + break + case "gogoend": + gogo = false + break + case "bpmchange": + bpm = parseFloat(value) + break + case "scroll": + scroll = parseFloat(value) + break + case "measure": + var [numerator, denominator] = value.split("/") + measure = numerator / denominator * 4 + break + case "delay": + ms += (parseFloat(value) || 0) * 1000 + break + case "barlineon": + barLine = true + break + case "barlineoff": + barLine = false + break case "branchstart": branch = true - branchType = "" + currentBranch = false + branchPushed = false + branchSettings = { + ms: ms, + gogo: gogo, + bpm: bpm, + scroll: scroll, + sectionBegin: sectionBegin + } value = value.split(",") - var forkType = value[0].toLowerCase() - if(forkType === "r" || parseFloat(value[2]) <= 100){ - branchPreference = "m" - }else if(parseFloat(value[1]) <= 100){ - branchPreference = "e" - }else{ - branchPreference = "n" + if(!this.branches){ + this.branches = [] + } + branchObj = { + ms: ms, + originalMS: ms, + type: value[0].toLowerCase() === "r" ? "drumroll" : "perfect", + requirement: [ + parseFloat(value[1]), + parseFloat(value[2]) + ] } break case "branchend": - case "section": branch = false + currentBranch = false + if(this.measures.length !== 0){ + this.measures[this.measures.length - 1].nextBranch = { + ms: ms, + originalMS: ms, + active: "normal" + } + } + break + case "section": + sectionBegin = true + if(branch && !currentBranch){ + branchSettings.sectionBegin = true + } break case "n": case "e": case "m": - branchType = name + if(!branchPushed){ + branchPushed = true + this.branches.push(branchObj) + if(this.measures.length === 1 && branchObj.type === "drumroll"){ + for(var i = circles.length; i--;){ + var circle = circles[i] + if(circle.endTime && circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon"){ + this.measures.push({ + ms: circle.endTime, + originalMS: circle.endTime, + speed: circle.bpm * circle.scroll / 60, + visible: false, + branch: circle.branch + }) + break + } + } + } + if(this.measures.length !== 0){ + this.measures[this.measures.length - 1].nextBranch = branchObj + } + } + ms = branchSettings.ms + gogo = branchSettings.gogo + bpm = branchSettings.bpm + scroll = branchSettings.scroll + sectionBegin = branchSettings.sectionBegin + var branchName = name === "m" ? "master" : (name === "e" ? "advanced" : "normal") + currentBranch = { + name: branchName, + active: branchName === "normal" + } + branchObj[branchName] = currentBranch break } - }else if(!branch || branch && branchType === branchPreference){ + }else{ var string = line.split("") @@ -278,8 +341,10 @@ txt: type.txt, gogo: gogo, bpm: bpm, - scroll: scroll + scroll: scroll, + section: sectionBegin } + sectionBegin = false if(lastDrumroll){ circleObj.endDrumroll = lastDrumroll lastDrumroll = false @@ -293,15 +358,19 @@ txt: type.txt, gogo: gogo, bpm: bpm, - scroll: scroll + scroll: scroll, + section: sectionBegin } + sectionBegin = false if(lastDrumroll){ if(symbol === "9"){ currentMeasure.push({ endDrumroll: lastDrumroll, bpm: bpm, - scroll: scroll + scroll: scroll, + section: sectionBegin }) + sectionBegin = false lastDrumroll = false }else{ currentMeasure.push({ @@ -327,8 +396,10 @@ currentMeasure.push({ endDrumroll: lastDrumroll, bpm: bpm, - scroll: scroll + scroll: scroll, + section: sectionBegin }) + sectionBegin = false lastDrumroll = false }else{ currentMeasure.push({ @@ -359,6 +430,10 @@ lastDrumroll.originalEndTime = ms } + if(this.branches){ + circles.sort((a, b) => a.ms > b.ms ? 1 : -1) + circles.forEach((circle, i) => circle.id = i + 1) + } return circles } } diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 6dbe579..114a276 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -351,7 +351,7 @@ class SongSelect{ down: code == 40 // Down } - if(key.cancel && event){ + if(event && (code == 27 || code == 8)){ event.preventDefault() } if(this.state.screen === "song"){ @@ -1322,27 +1322,47 @@ class SongSelect{ outlineSize: currentUra ? this.songAsset.letterBorder : 0 }) }) - var songStars = currentUra ? currentSong.stars[4] : currentSong.stars[i] - for(var j = 0; j < 10; j++){ - if(songSel){ - var yPos = _y + 113 + j * 17 - }else{ - var yPos = _y + 178 + j * 19.5 - } - if(10 - j > songStars){ - ctx.fillStyle = currentUra ? "#187085" : (songSel ? "#e97526" : "#e7e7e7") - ctx.beginPath() - ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2) - ctx.fill() - }else{ - this.draw.diffStar({ - ctx: ctx, - songSel: songSel, - ura: currentUra, - x: _x, - y: yPos, - ratio: ratio - }) + var songStarsArray = (currentUra ? currentSong.stars[4] : currentSong.stars[i]).toString().split(" ") + var songStars = songStarsArray[0] + var songBranch = songStarsArray[1] === "B" + var elapsedMS = this.state.screenMS > this.state.moveMS ? this.state.screenMS : this.state.moveMS + var fade = ((ms - elapsedMS) % 2000) / 2000 + if(songBranch && fade > 0.25 && fade < 0.75){ + this.draw.verticalText({ + ctx: ctx, + text: strings.songBranch, + x: _x, + y: _y + (songSel ? 110 : 185), + width: songSel ? 44 : 56, + height: songSel ? 160 : 170, + fill: songSel && !currentUra ? "#c85200" : "#fff", + fontSize: songSel ? 25 : 27, + fontFamily: songSel ? "Meiryo, Microsoft YaHei, sans-serif" : this.font, + outline: songSel ? false : "#f22666", + outlineSize: songSel ? 0 : this.songAsset.letterBorder + }) + }else{ + for(var j = 0; j < 10; j++){ + if(songSel){ + var yPos = _y + 113 + j * 17 + }else{ + var yPos = _y + 178 + j * 19.5 + } + if(10 - j > songStars){ + ctx.fillStyle = currentUra ? "#187085" : (songSel ? "#e97526" : "#e7e7e7") + ctx.beginPath() + ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2) + ctx.fill() + }else{ + this.draw.diffStar({ + ctx: ctx, + songSel: songSel, + ura: currentUra, + x: _x, + y: yPos, + ratio: ratio + }) + } } } var currentDiff = this.selectedDiff - this.diffOptions.length diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index 0262a6b..f220863 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -86,7 +86,7 @@ class SoundGain{ this.volume = amount } setCrossfade(amount){ - this.setVolume(Math.pow(Math.sin(Math.PI / 2 * amount), 1 / 4)) + this.setVolume(Math.sqrt(Math.sin(Math.PI / 2 * amount))) } fadeIn(duration, time, absolute){ this.fadeVolume(0, this.volume * this.volume, duration, time, absolute) diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 967d0a1..7c6b029 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -34,6 +34,7 @@ this.normal = "ふつう" this.hard = "むずかしい" this.oni = "おに" + this.songBranch = "譜面分岐あり" this.sessionStart = "オンラインセッションを開始する!" this.sessionEnd = "オンラインセッションを終了する" this.loading = "ロード中..." @@ -135,6 +136,7 @@ function StringsEn(){ this.normal = "Normal" this.hard = "Hard" this.oni = "Extreme" + this.songBranch = "Forked Paths" this.sessionStart = "Begin an Online Session!" this.sessionEnd = "End Online Session" this.loading = "Loading..." @@ -236,6 +238,7 @@ function StringsCn(){ this.normal = "普通" this.hard = "困难" this.oni = "魔王" + this.songBranch = "有分数分支" this.sessionStart = "开始在线会话!" this.sessionEnd = "结束在线会话" this.loading = "加载中..." @@ -337,6 +340,7 @@ function StringsTw(){ this.normal = "普通" this.hard = "困難" this.oni = "魔王" + this.songBranch = "有分數分支" this.sessionStart = "開始多人模式!" this.sessionEnd = "結束多人模式" this.loading = "讀取中..." @@ -438,6 +442,7 @@ function StringsKo(){ this.normal = "보통" this.hard = "어려움" this.oni = "귀신" + this.songBranch = "악보 분기 있습니다" this.sessionStart = "온라인 세션 시작!" this.sessionEnd = "온라인 세션 끝내기" this.loading = "로딩 중..." diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index 642aab9..9f95cdc 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -18,7 +18,11 @@ class Titlescreen{ this.setLang(allStrings[this.lang], true) if(songId){ - this.goNext() + if(localStorage.getItem("tutorial") === "true"){ + new SongSelect(false, false, this.touched, this.songId) + }else{ + new Tutorial(false, this.songId) + } }else{ this.addLangs() diff --git a/public/src/js/view.js b/public/src/js/view.js index fa0c534..f3f8383 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -75,6 +75,18 @@ this.gogoTime = 0 this.drumroll = [] this.touchEvents = 0 + if(this.controller.parsedSongData.branches){ + this.branch = "normal" + this.branchAnimate = { + ms: -Infinity, + fromBranch: "normal" + } + this.branchMap = { + "normal": "rgba(0, 0, 0, 0)", + "advanced": "rgba(29, 129, 189, 0.4)", + "master": "rgba(230, 29, 189, 0.4)" + } + } this.beatInterval = this.controller.parsedSongData.beatInfo.beatInterval this.font = strings.font @@ -693,6 +705,18 @@ } ctx.fillRect(padding, barY, winW - padding, barH) } + if(this.branchAnimate && ms <= this.branchAnimate.ms + 300){ + var alpha = Math.max(0, (ms - this.branchAnimate.ms) / 300) + ctx.globalAlpha = 1 - alpha + ctx.fillStyle = this.branchMap[this.branchAnimate.fromBranch] + ctx.fillRect(padding, barY, winW - padding, barH) + ctx.globalAlpha = alpha + } + if(this.branch){ + ctx.fillStyle = this.branchMap[this.branch] + ctx.fillRect(padding, barY, winW - padding, barH) + ctx.globalAlpha = 1 + } if(keyTime[sound] > ms - 130){ var gradients = { "don": "255, 0, 0", @@ -1102,7 +1126,7 @@ var timeForDistance = this.posToMs(distanceForCircle, measure.speed) var startingTime = measure.ms - timeForDistance var finishTime = measure.ms + this.posToMs(this.slotPos.x - this.slotPos.paddingLeft + 3, measure.speed) - if(ms >= startingTime && ms <= finishTime){ + if(measure.visible && (!measure.branch || measure.branch.active) && ms >= startingTime && ms <= finishTime){ var measureX = this.slotPos.x + this.msToPos(measure.ms - ms, measure.speed) this.ctx.strokeStyle = "#bdbdbd" this.ctx.lineWidth = 3 @@ -1111,6 +1135,14 @@ this.ctx.lineTo(measureX, measureY + measureH) this.ctx.stroke() } + if(this.multiplayer !== 2 && ms >= measure.ms && measure.nextBranch && !measure.viewChecked && measure.gameChecked){ + measure.viewChecked = true + this.branchAnimate = { + ms: ms, + fromBranch: this.branch + } + this.branch = measure.nextBranch.active + } }) } updateNoteFaces(){ @@ -1137,17 +1169,17 @@ for(var i = circles.length; i--;){ var circle = circles[i] - var speed = circle.getSpeed() + var speed = circle.speed var timeForDistance = this.posToMs(distanceForCircle + this.slotPos.size / 2, speed) - var startingTime = circle.getMS() - timeForDistance - var finishTime = circle.getEndTime() + this.posToMs(this.slotPos.x - this.slotPos.paddingLeft + this.slotPos.size * 2, speed) + var startingTime = circle.ms - timeForDistance + var finishTime = circle.endTime + this.posToMs(this.slotPos.x - this.slotPos.paddingLeft + this.slotPos.size * 2, speed) - if(circle.getPlayed() <= 0 || circle.getScore() === 0){ - if(ms >= startingTime && ms <= finishTime && circle.getPlayed() !== -1){ + if(circle.isPlayed <= 0 || circle.score === 0){ + if((!circle.branch || circle.branch.active) && ms >= startingTime && ms <= finishTime && circle.isPlayed !== -1){ this.drawCircle(circle) } - }else if(!circle.isAnimated()){ + }else if(!circle.animating){ // Start animation to gauge circle.animate(ms) } @@ -1165,9 +1197,9 @@ for(var i = 0; i < circles.length; i++){ var circle = circles[i] - if(circle.isAnimated()){ + if(circle.animating){ - var animT = circle.getAnimT() + var animT = circle.animT if(ms < animT + 490){ if(circle.fixedPos){ @@ -1183,7 +1215,7 @@ var pos = this.animateBezier[3] this.drawCircle(circle, pos, (ms - animT - 490) / 160) }else{ - circle.endAnimation() + circle.animationEnded = true } } } @@ -1211,13 +1243,13 @@ var lyricsSize = 20 * mul var fill, size, faceID - var type = circle.getType() + var type = circle.type var ms = this.getMS() - var circleMs = circle.getMS() - var endTime = circle.getEndTime() - var animated = circle.isAnimated() - var speed = circle.getSpeed() - var played = circle.getPlayed() + var circleMs = circle.ms + var endTime = circle.endTime + var animated = circle.animating + var speed = circle.speed + var played = circle.isPlayed var drumroll = 0 var endX = 0 @@ -1323,9 +1355,9 @@ ctx.fill() ctx.globalAlpha = 1 } - if(!circle.isAnimated()){ + if(!circle.animating){ // Text - var text = circle.getText() + var text = circle.text var textX = circlePos.x var textY = circlePos.y + 83 * mul ctx.font = lyricsSize + "px Kozuka, Microsoft YaHei, sans-serif" @@ -1466,7 +1498,7 @@ if(this.gogoTime){ var circles = this.controller.parsedSongData.circles var lastCircle = circles[circles.length - 1] - var endTime = lastCircle.getEndTime() + 3000 + var endTime = lastCircle.endTime + 3000 if(ms >= endTime){ this.toggleGogoTime({ gogoTime: 0, diff --git a/public/src/views/debug.html b/public/src/views/debug.html index eba64ac..b681717 100644 --- a/public/src/views/debug.html +++ b/public/src/views/debug.html @@ -9,6 +9,17 @@
x-+
+
+
Branch:
+
+ x +
+
diff --git a/server.py b/server.py index b4b65ca..aafcad4 100644 --- a/server.py +++ b/server.py @@ -185,6 +185,7 @@ async def connection(ws, path): if "other_user" in user and "ws" in user["other_user"]: if type == "note"\ or type == "drumroll"\ + or type == "branch"\ or type == "gameresults": await user["other_user"]["ws"].send(msgobj(type, value)) elif type == "songsel" and user["session"]: From 4e9bf237a1a66ef54aa5b69cb49f8c408004b9b5 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sun, 17 Feb 2019 20:17:07 +0300 Subject: [PATCH 2/6] Fix go go time --- public/src/js/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/js/view.js b/public/src/js/view.js index f3f8383..43975cb 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -1183,7 +1183,7 @@ // Start animation to gauge circle.animate(ms) } - if(ms >= circle.ms && !circle.gogoChecked){ + if(ms >= circle.ms && !circle.gogoChecked && (!circle.branch || circle.branch.active)){ if(this.gogoTime != circle.gogoTime){ this.toggleGogoTime(circle) } From 76e56736f72f2f87125ff3d3fe8287b9bc9e538d Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Mon, 18 Feb 2019 01:29:18 +0300 Subject: [PATCH 3/6] Do not restart animation with d-pad --- public/src/js/songselect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 114a276..c6271f4 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -1325,7 +1325,7 @@ class SongSelect{ var songStarsArray = (currentUra ? currentSong.stars[4] : currentSong.stars[i]).toString().split(" ") var songStars = songStarsArray[0] var songBranch = songStarsArray[1] === "B" - var elapsedMS = this.state.screenMS > this.state.moveMS ? this.state.screenMS : this.state.moveMS + var elapsedMS = this.state.screenMS > this.state.moveMS || !songSel ? this.state.screenMS : this.state.moveMS var fade = ((ms - elapsedMS) % 2000) / 2000 if(songBranch && fade > 0.25 && fade < 0.75){ this.draw.verticalText({ From c72b5a742c4f8bafd5b5fcbd400724bb3ea2120a Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Wed, 20 Feb 2019 23:48:21 +0300 Subject: [PATCH 4/6] Add animations and fix behaviour --- public/src/js/canvascache.js | 1 + public/src/js/canvasdraw.js | 9 +- public/src/js/debug.js | 8 +- public/src/js/game.js | 164 ++++++++++++++++++++++++----------- public/src/js/main.js | 4 +- public/src/js/mekadon.js | 6 ++ public/src/js/parsetja.js | 84 +++++++++--------- public/src/js/strings.js | 31 ++++++- public/src/js/view.js | 157 +++++++++++++++++++++++++++------ public/src/views/debug.html | 8 +- 10 files changed, 344 insertions(+), 128 deletions(-) diff --git a/public/src/js/canvascache.js b/public/src/js/canvascache.js index 56a1f7d..1b4c121 100644 --- a/public/src/js/canvascache.js +++ b/public/src/js/canvascache.js @@ -11,6 +11,7 @@ class CanvasCache{ this.map = new Map() this.canvas = document.createElement("canvas") this.ctx = this.canvas.getContext("2d") + document.body.appendChild(this.canvas) } this.scale = scale this.x = 0 diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 8a072a4..4431774 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -268,6 +268,9 @@ easeOut(pos){ return Math.sin(Math.PI / 2 * pos) } + easeOutBack(pos){ + return Math.sin(Math.PI / 1.74 * pos) * 1.03 + } easeInOut(pos){ return (Math.cos(Math.PI * pos) - 1) / -2 } @@ -572,7 +575,7 @@ } if(symbol.ura){ ctx.font = (30 * mul) + "px Meiryo, sans-serif" - ctx.textBaseline = "center" + ctx.textBaseline = "middle" ctx.beginPath() ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2) if(action === "stroke"){ @@ -581,7 +584,7 @@ }else if(action === "fill"){ ctx.strokeStyle = config.fill ctx.lineWidth = 2.5 * mul - ctx.fillText(symbol.text, currentX, currentY) + ctx.fillText(symbol.text, currentX, currentY + (17 * mul)) } ctx.stroke() }else{ @@ -788,7 +791,7 @@ } if(symbol.ura){ ctx.font = (30 * mul) + "px Meiryo, sans-serif" - ctx.textBaseline = "center" + ctx.textBaseline = "middle" ctx.beginPath() ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2) if(action === "strokeText"){ diff --git a/public/src/js/debug.js b/public/src/js/debug.js index 607002d..9f2836c 100644 --- a/public/src/js/debug.js +++ b/public/src/js/debug.js @@ -116,7 +116,9 @@ class Debug{ this.branchReset(null, true) } - var measures = this.controller.parsedSongData.measures + var measures = this.controller.parsedSongData.measures.filter((measure, i, array) => { + return i === 0 || Math.abs(measure.ms - array[i - 1].ms) > 0.01 + }) this.measureNumSlider.setMinMax(0, measures.length - 1) if(this.measureNum && measures.length > this.measureNum){ var measureMS = measures[this.measureNum].ms @@ -197,7 +199,9 @@ class Debug{ var game = this.controller.game var name = this.branchSelect.value game.branch = name === "auto" ? false : name - game.branchSet = false + game.branchSet = name === "auto" + var selectedOption = this.branchSelect.selectedOptions[0] + this.branchSelect.style.background = selectedOption.style.background if(this.restartCheckbox.checked && !noRestart){ this.restartSong() } diff --git a/public/src/js/game.js b/public/src/js/game.js index 865b905..3f0845b 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -28,8 +28,8 @@ class Game{ this.musicFadeOut = 0 this.fadeOutStarted = false this.currentTimingPoint = 0 - this.sectionNotes = [] - this.sectionDrumroll = 0 + this.branchNames = ["normal", "advanced", "master"] + this.resetSection() assets.songs.forEach(song => { if(song.id == selectedSong.folder){ @@ -77,7 +77,7 @@ class Game{ var index = 0 for(var i = startIndex; i < circles.length; i++){ var circle = circles[i] - if((!circle.branch || circle.branch.active) && !circle.isPlayed){ + if(circle && (!circle.branch || circle.branch.active) && !circle.isPlayed){ var type = circle.type var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" var endTime = circle.endTime + (drumrollNotes ? 0 : this.rules.bad) @@ -100,6 +100,9 @@ class Game{ if(ms > endTime){ if(!this.controller.autoPlayEnabled){ if(drumrollNotes){ + if(circle.section && circle.timesHit === 0){ + this.resetSection() + } circle.played(-1, false) this.updateCurrentCircle() if(this.controller.multiplayer === 1){ @@ -112,6 +115,9 @@ class Game{ p2.send("drumroll", value) } }else{ + if(circle.section){ + this.resetSection() + } var currentScore = 0 circle.played(-1, type === "daiDon" || type === "daiKa") this.sectionNotes.push(0) @@ -137,47 +143,62 @@ class Game{ } var branches = this.songData.branches if(branches){ - if(this.controller.multiplayer === 2 || this.branch){ - var parent = this.controller.multiplayer === 2 ? p2 : this - var view = this.controller.view - if(view.branch !== parent.branch){ - view.branchAnimate = { - ms: ms, - fromBranch: view.branch + var force = this.controller.multiplayer === 2 ? p2 : this + var measures = this.songData.measures + if(this.controller.multiplayer === 2 || force.branch){ + if(!force.branchSet){ + force.branchSet = true + if(branches.length){ + this.setBranch(branches[0], force.branch) } - view.branch = parent.branch - } - if(!parent.branchSet){ - parent.branchSet = true - for(var i = 0; i < branches.length; i++){ - this.setBranch(branches[i], parent.branch) + var view = this.controller.view + var currentMeasure = view.branch + for(var i = measures.length; i--;){ + var measure = measures[i] + if(measure.nextBranch && measure.ms <= ms){ + currentMeasure = measure.nextBranch.active + } + } + if(view.branch !== currentMeasure){ + view.branchAnimate = { + ms: ms, + fromBranch: view.branch + } + view.branch = currentMeasure } } - }else{ - var measures = this.songData.measures - for(var i = 0; i < measures.length; i++){ - var measure = measures[i] - if(measure.ms > ms){ - break - }else if(measure.nextBranch && !measure.gameChecked){ - measure.gameChecked = true - var branch = measure.nextBranch - if(branch.type){ - if(branch.type === "drumroll"){ + } + for(var i = 0; i < measures.length; i++){ + var measure = measures[i] + if(measure.ms > ms){ + break + }else if(measure.nextBranch && !measure.gameChecked){ + measure.gameChecked = true + var branch = measure.nextBranch + if(branch.type){ + var accuracy = 0 + if(branch.type === "drumroll"){ + if(force.branch){ + var accuracy = Math.max(0, branch.requirement[force.branch]) + }else{ var accuracy = this.sectionDrumroll + } + }else if(this.sectionNotes.length !== 0){ + if(force.branch){ + var accuracy = Math.max(0, Math.min(100, branch.requirement[force.branch])) }else{ var accuracy = this.sectionNotes.reduce((a, b) => a + b) / this.sectionNotes.length * 100 } - if(accuracy >= branch.requirement[1]){ - this.setBranch(branch, "master") - }else if(accuracy >= branch.requirement[0]){ - this.setBranch(branch, "advanced") - }else{ - this.setBranch(branch, "normal") - } - }else if(this.controller.multiplayer === 1){ - p2.send("branch", "normal") } + if(accuracy >= branch.requirement.master){ + this.setBranch(branch, "master") + }else if(accuracy >= branch.requirement.advanced){ + this.setBranch(branch, "advanced") + }else{ + this.setBranch(branch, "normal") + } + }else if(this.controller.multiplayer === 1){ + p2.send("branch", "normal") } } } @@ -273,6 +294,9 @@ class Game{ this.updateCombo(score) this.updateGlobalScore(score, typeDai && keyDai ? 2 : 1, circle.gogoTime) this.updateCurrentCircle() + if(circle.section){ + this.resetSection() + } this.sectionNotes.push(score === 450 ? 1 : (score === 230 ? 0.5 : 0)) if(this.controller.multiplayer === 1){ var value = { @@ -327,6 +351,9 @@ class Game{ var ms = this.elapsedTime var dai = circle.type === "daiDrumroll" var score = 100 + if(circle.section && circle.timesHit === 0){ + this.resetSection() + } circle.hit(keysKa) var keyTime = this.controller.getKeyTime() if(circle.type === "drumroll"){ @@ -347,9 +374,7 @@ class Game{ circleAnim.animate(ms) this.view.drumroll.push(circleAnim) this.globalScore.drumroll++ - if(this.controller.multiplayer !== 2){ - this.sectionDrumroll++ - } + this.sectionDrumroll++ this.globalScore.points += score * (dai ? 2 : 1) this.view.setDarkBg(false) } @@ -473,10 +498,6 @@ class Game{ do{ var circle = circles[++this.currentCircle] }while(circle && circle.branch && !circle.branch.active) - if(circle && circle.section){ - this.sectionNotes = [] - this.sectionDrumroll = 0 - } } getCurrentCircle(){ return this.currentCircle @@ -530,16 +551,59 @@ class Game{ } this.globalScore.points += Math.floor(score * multiplier / 10) * 10 } - setBranch(branch, name){ - var names = ["normal", "advanced", "master"] - for(var i in names){ - if(names[i] in branch){ - branch[names[i]].active = names[i] === name + setBranch(currentBranch, activeName){ + var pastActive = currentBranch.active + var ms = currentBranch.ms + for(var i = 0; i < this.songData.branches.length; i++){ + var branch = this.songData.branches[i] + if(branch.ms >= ms){ + var relevantName = activeName + var req = branch.requirement + var noNormal = req.advanced <= 0 + var noAdvanced = req.master <= 0 || req.advanced >= req.master || branch.type === "accuracy" && req.advanced > 100 + var noMaster = branch.type === "accuracy" && req.master > 100 + if(relevantName === "normal" && noNormal){ + relevantName = noAdvanced ? "master" : "advanced" + } + if(relevantName === "advanced" && noAdvanced){ + relevantName = noMaster ? "normal" : "master" + } + if(relevantName === "master" && noMaster){ + relevantName = noAdvanced ? "normal" : "advanced" + } + for(var j in this.branchNames){ + var name = this.branchNames[j] + if(name in branch){ + branch[name].active = name === relevantName + } + } + if(branch === currentBranch){ + activeName = relevantName + } + branch.active = relevantName } } - branch.active = name + var circles = this.songData.circles + var circle = circles[this.currentCircle] + if(!circle || circle.branch === currentBranch[pastActive]){ + var ms = this.elapsedTime + var closestCircle = circles.findIndex(circle => { + return (!circle.branch || circle.branch.active) && circle.endTime >= ms + }) + if(closestCircle !== -1){ + this.currentCircle = closestCircle + } + } + this.HPGain = 100 / this.songData.circles.filter(circle => { + var type = circle.type + return (type === "don" || type === "ka" || type === "daiDon" || type === "daiKa") && (!circle.branch || circle.branch.active) + }).length if(this.controller.multiplayer === 1){ - p2.send("branch", name) + p2.send("branch", activeName) } } + resetSection(){ + this.sectionNotes = [] + this.sectionDrumroll = 0 + } } diff --git a/public/src/js/main.js b/public/src/js/main.js index a63691e..1e632ca 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -106,7 +106,9 @@ pageEvents.keyAdd(debugObj, "all", "down", event => { }else if(debugObj.state === "minimised"){ debugObj.debug.restore() }else{ - debugObj.debug = new Debug() + try{ + debugObj.debug = new Debug() + }catch(e){} } } if(event.keyCode === 82 && debugObj.debug && debugObj.controller){ diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index 22f7d73..962b9ff 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -8,6 +8,9 @@ class Mekadon{ play(circle){ var type = circle.type if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.endTime){ + if(circle.section && circle.timesHit === 0){ + this.game.resetSection() + } circle.played(-1, false) this.game.updateCurrentCircle() } @@ -96,6 +99,9 @@ class Mekadon{ this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime) this.game.updateCurrentCircle() circle.played(score, keyDai) + if(circle.section){ + this.game.resetSection() + } this.game.sectionNotes.push(score === 450 ? 1 : (score === 230 ? 0.5 : 0)) } this.lastHit = ms diff --git a/public/src/js/parsetja.js b/public/src/js/parsetja.js index 262c0b9..22e2e9f 100644 --- a/public/src/js/parsetja.js +++ b/public/src/js/parsetja.js @@ -137,7 +137,7 @@ var branchObj = {} var currentBranch = false var branchSettings = {} - var branchPushed = false + var branchFirstMeasure = false var sectionBegin = true var currentMeasure = [] @@ -157,8 +157,10 @@ originalMS: ms, speed: speed, visible: barLine, - branch: currentBranch + branch: currentBranch, + branchFirst: branchFirstMeasure }) + branchFirstMeasure = false if(currentMeasure.length){ for(var i = 0; i < currentMeasure.length; i++){ var note = currentMeasure[i] @@ -222,14 +224,14 @@ gogo = false break case "bpmchange": - bpm = parseFloat(value) + bpm = parseFloat(value) || bpm break case "scroll": - scroll = parseFloat(value) + scroll = parseFloat(value) || scroll break case "measure": var [numerator, denominator] = value.split("/") - measure = numerator / denominator * 4 + measure = numerator / denominator * 4 || measure break case "delay": ms += (parseFloat(value) || 0) * 1000 @@ -243,7 +245,7 @@ case "branchstart": branch = true currentBranch = false - branchPushed = false + branchFirstMeasure = true branchSettings = { ms: ms, gogo: gogo, @@ -255,26 +257,45 @@ if(!this.branches){ this.branches = [] } + var req = { + advanced: parseFloat(value[1]) || 0, + master: parseFloat(value[2]) || 0 + } + if(req.advanced > 0){ + var active = req.master > 0 ? "normal" : "master" + }else{ + var active = req.master > 0 ? "advanced" : "master" + } branchObj = { ms: ms, originalMS: ms, - type: value[0].toLowerCase() === "r" ? "drumroll" : "perfect", - requirement: [ - parseFloat(value[1]), - parseFloat(value[2]) - ] + active: active, + type: value[0].trim().toLowerCase() === "r" ? "drumroll" : "accuracy", + requirement: req + } + this.branches.push(branchObj) + if(this.measures.length === 1 && branchObj.type === "drumroll"){ + for(var i = circles.length; i--;){ + var circle = circles[i] + if(circle.endTime && circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon"){ + this.measures.push({ + ms: circle.endTime, + originalMS: circle.endTime, + speed: circle.bpm * circle.scroll / 60, + visible: false, + branch: circle.branch + }) + break + } + } + } + if(this.measures.length !== 0){ + this.measures[this.measures.length - 1].nextBranch = branchObj } break case "branchend": branch = false currentBranch = false - if(this.measures.length !== 0){ - this.measures[this.measures.length - 1].nextBranch = { - ms: ms, - originalMS: ms, - active: "normal" - } - } break case "section": sectionBegin = true @@ -283,37 +304,19 @@ } break case "n": case "e": case "m": - if(!branchPushed){ - branchPushed = true - this.branches.push(branchObj) - if(this.measures.length === 1 && branchObj.type === "drumroll"){ - for(var i = circles.length; i--;){ - var circle = circles[i] - if(circle.endTime && circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon"){ - this.measures.push({ - ms: circle.endTime, - originalMS: circle.endTime, - speed: circle.bpm * circle.scroll / 60, - visible: false, - branch: circle.branch - }) - break - } - } - } - if(this.measures.length !== 0){ - this.measures[this.measures.length - 1].nextBranch = branchObj - } + if(!branch){ + break } ms = branchSettings.ms gogo = branchSettings.gogo bpm = branchSettings.bpm scroll = branchSettings.scroll sectionBegin = branchSettings.sectionBegin + branchFirstMeasure = true var branchName = name === "m" ? "master" : (name === "e" ? "advanced" : "normal") currentBranch = { name: branchName, - active: branchName === "normal" + active: branchName === branchObj.active } branchObj[branchName] = currentBranch break @@ -432,6 +435,7 @@ if(this.branches){ circles.sort((a, b) => a.ms > b.ms ? 1 : -1) + this.measures.sort((a, b) => a.ms > b.ms ? 1 : -1) circles.forEach((circle, i) => circle.id = i + 1) } return circles diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 7c6b029..7d13389 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -54,6 +54,11 @@ this.good = "良" this.ok = "可" this.bad = "不可" + this.branch = { + "normal": "普通譜面", + "advanced": "玄人譜面", + "master": "達人譜面" + } this.pauseOptions = [ "演奏をつづける", "はじめからやりなおす", @@ -136,7 +141,7 @@ function StringsEn(){ this.normal = "Normal" this.hard = "Hard" this.oni = "Extreme" - this.songBranch = "Forked Paths" + this.songBranch = "Diverge Notes" this.sessionStart = "Begin an Online Session!" this.sessionEnd = "End Online Session" this.loading = "Loading..." @@ -156,6 +161,11 @@ function StringsEn(){ this.good = "GOOD" this.ok = "OK" this.bad = "BAD" + this.branch = { + "normal": "Normal", + "advanced": "Professional", + "master": "Master" + } this.pauseOptions = [ "Continue", "Retry", @@ -238,7 +248,7 @@ function StringsCn(){ this.normal = "普通" this.hard = "困难" this.oni = "魔王" - this.songBranch = "有分数分支" + this.songBranch = "有谱面分歧" this.sessionStart = "开始在线会话!" this.sessionEnd = "结束在线会话" this.loading = "加载中..." @@ -258,6 +268,11 @@ function StringsCn(){ this.good = "良" this.ok = "可" this.bad = "不可" + this.branch = { + "normal": "一般谱面", + "advanced": "进阶谱面", + "master": "达人谱面" + } this.pauseOptions = [ "继续演奏", "从头开始", @@ -340,7 +355,7 @@ function StringsTw(){ this.normal = "普通" this.hard = "困難" this.oni = "魔王" - this.songBranch = "有分數分支" + this.songBranch = "有譜面分歧" this.sessionStart = "開始多人模式!" this.sessionEnd = "結束多人模式" this.loading = "讀取中..." @@ -360,6 +375,11 @@ function StringsTw(){ this.good = "良" this.ok = "可" this.bad = "不可" + this.branch = { + "normal": "一般譜面", + "advanced": "進階譜面", + "master": "達人譜面" + } this.pauseOptions = [ "繼續演奏", "從頭開始", @@ -462,6 +482,11 @@ function StringsKo(){ this.good = "얼쑤" this.ok = "좋다" this.bad = "에구" + this.branch = { + "normal": "보통 악보", + "advanced": "현인 악보", + "master": "달인 악보" + } this.pauseOptions = [ "연주 계속하기", "처음부터 다시", diff --git a/public/src/js/view.js b/public/src/js/view.js index 43975cb..a50bf13 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -82,9 +82,24 @@ fromBranch: "normal" } this.branchMap = { - "normal": "rgba(0, 0, 0, 0)", - "advanced": "rgba(29, 129, 189, 0.4)", - "master": "rgba(230, 29, 189, 0.4)" + "normal": { + "bg": "rgba(0, 0, 0, 0)", + "text": "#d3d3d3", + "stroke": "#393939", + "shadow": "#000" + }, + "advanced": { + "bg": "rgba(29, 129, 189, 0.4)", + "text": "#94d7e7", + "stroke": "#315973", + "shadow": "#082031" + }, + "master": { + "bg": "rgba(230, 29, 189, 0.4)", + "text": "#f796ef", + "stroke": "#7e2e6e", + "shadow": "#3e0836" + } } } @@ -97,6 +112,7 @@ this.titleCache = new CanvasCache() this.comboCache = new CanvasCache() this.pauseCache = new CanvasCache() + this.branchCache = new CanvasCache() this.multiplayer = this.controller.multiplayer @@ -144,7 +160,8 @@ } this.setDonBg() - this.lastMousemove = this.controller.game.getAccurateTime() + this.startTime = this.controller.game.getAccurateTime() + this.lastMousemove = this.startTime pageEvents.mouseAdd(this, this.onmousemove.bind(this)) this.refresh() @@ -174,6 +191,7 @@ } var ratio = (ratioX < ratioY ? ratioX : ratioY) + var resized = false if(this.winW !== winW || this.winH !== winH){ this.winW = winW this.winH = winH @@ -193,6 +211,7 @@ } this.fillComboCache() this.setDonBgHeight() + resized = true }else if(this.controller.game.paused && !document.hasFocus()){ return }else if(this.multiplayer !== 2){ @@ -681,7 +700,7 @@ } ctx.restore() - // Bar pressed keys + // Branch background var keyTime = this.controller.getKeyTime() var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka" var padding = this.slotPos.paddingLeft @@ -689,12 +708,78 @@ var barY = this.slotPos.y - 65 * mul var barH = 130 * mul + if(this.branchAnimate && ms <= this.branchAnimate.ms + 300){ + var alpha = Math.max(0, (ms - this.branchAnimate.ms) / 300) + ctx.globalAlpha = 1 - alpha + ctx.fillStyle = this.branchMap[this.branchAnimate.fromBranch].bg + ctx.fillRect(padding, barY, winW - padding, barH) + ctx.globalAlpha = alpha + } + if(this.branch){ + ctx.fillStyle = this.branchMap[this.branch].bg + ctx.fillRect(padding, barY, winW - padding, barH) + ctx.globalAlpha = 1 + } + + // Current branch text + if(this.branch){ + if(resized){ + this.fillBranchCache() + } + var textW = Math.floor(260 * mul) + var textH = Math.floor(barH) + var textX = winW - textW + var oldOffset = 0 + var newOffset = 0 + var elapsed = ms - this.startTime + if(elapsed < 250){ + textX = winW + }else if(elapsed < 500){ + textX += (1 - this.draw.easeOutBack((elapsed - 250) / 250)) * textW + } + if(this.branchAnimate && ms - this.branchAnimate.ms < 310 && ms >= this.branchAnimate.ms){ + var fromBranch = this.branchAnimate.fromBranch + var elapsed = ms - this.branchAnimate.ms + var reverse = fromBranch === "master" || fromBranch === "advanced" && this.branch === "normal" ? -1 : 1 + if(elapsed < 65){ + oldOffset = elapsed / 65 * 12 * mul * reverse + ctx.globalAlpha = 1 + var newAlpha = 0 + }else if(elapsed < 215){ + var animPoint = (elapsed - 65) / 150 + oldOffset = (12 - animPoint * 48) * mul * reverse + newOffset = (36 - animPoint * 48) * mul * reverse + ctx.globalAlpha = this.draw.easeIn(1 - animPoint) + var newAlpha = this.draw.easeIn(animPoint) + }else{ + newOffset = (1 - (elapsed - 215) / 95) * -12 * mul * reverse + ctx.globalAlpha = 0 + var newAlpha = 1 + } + this.branchCache.get({ + ctx: ctx, + x: textX, y: barY + oldOffset, + w: textW, h: textH, + id: fromBranch + }) + ctx.globalAlpha = newAlpha + } + this.branchCache.get({ + ctx: ctx, + x: textX, y: barY + newOffset, + w: textW, h: textH, + id: this.branch + }) + ctx.globalAlpha = 1 + } + + // Go go time background if(this.gogoTime || ms <= this.gogoTimeStarted + 100){ var grd = ctx.createLinearGradient(padding, 0, winW, 0) - grd.addColorStop(0, "#512a2c") - grd.addColorStop(0.46, "#6f2a2d") - grd.addColorStop(0.76, "#8a4763") - grd.addColorStop(1, "#2c2a2c") + grd.addColorStop(0, "rgba(255, 0, 0, 0.16)") + grd.addColorStop(0.45, "rgba(255, 0, 0, 0.28)") + grd.addColorStop(0.77, "rgba(255, 83, 157, 0.4)") + grd.addColorStop(1, "rgba(255, 83, 157, 0)") ctx.fillStyle = grd if(!this.touchEnabled){ var alpha = Math.min(100, ms - this.gogoTimeStarted) / 100 @@ -705,18 +790,8 @@ } ctx.fillRect(padding, barY, winW - padding, barH) } - if(this.branchAnimate && ms <= this.branchAnimate.ms + 300){ - var alpha = Math.max(0, (ms - this.branchAnimate.ms) / 300) - ctx.globalAlpha = 1 - alpha - ctx.fillStyle = this.branchMap[this.branchAnimate.fromBranch] - ctx.fillRect(padding, barY, winW - padding, barH) - ctx.globalAlpha = alpha - } - if(this.branch){ - ctx.fillStyle = this.branchMap[this.branch] - ctx.fillRect(padding, barY, winW - padding, barH) - ctx.globalAlpha = 1 - } + + // Bar pressed keys if(keyTime[sound] > ms - 130){ var gradients = { "don": "255, 0, 0", @@ -814,6 +889,7 @@ ctx.lineWidth = 7 * mul ctx.textAlign = "center" ctx.miterLimit = 1 + ctx.strokeStyle = "#000" ctx.strokeText(strings.combo, comboX, comboTextY) ctx.miterLimit = 10 ctx.fillText(strings.combo, comboX, comboTextY) @@ -1128,7 +1204,7 @@ var finishTime = measure.ms + this.posToMs(this.slotPos.x - this.slotPos.paddingLeft + 3, measure.speed) if(measure.visible && (!measure.branch || measure.branch.active) && ms >= startingTime && ms <= finishTime){ var measureX = this.slotPos.x + this.msToPos(measure.ms - ms, measure.speed) - this.ctx.strokeStyle = "#bdbdbd" + this.ctx.strokeStyle = measure.branchFirst ? "#ff0" : "#bdbdbd" this.ctx.lineWidth = 3 this.ctx.beginPath() this.ctx.moveTo(measureX, measureY) @@ -1137,9 +1213,9 @@ } if(this.multiplayer !== 2 && ms >= measure.ms && measure.nextBranch && !measure.viewChecked && measure.gameChecked){ measure.viewChecked = true - this.branchAnimate = { - ms: ms, - fromBranch: this.branch + if(measure.nextBranch.active !== this.branch){ + this.branchAnimate.ms = ms + this.branchAnimate.fromBranch = this.branch } this.branch = measure.nextBranch.active } @@ -1468,6 +1544,37 @@ }) this.globalAlpha = 1 } + fillBranchCache(){ + var mul = this.slotPos.size / 106 + var textW = Math.floor(260 * mul) + var barH = Math.floor(130 * mul) + var branchNames = this.controller.game.branchNames + var textX = textW - 33 * mul + var textY = 63 * mul + var fontSize = (strings.id === "en" ? 33 : (strings.id === "ko" ? 38 : 43)) * mul + this.branchCache.resize((textW + 1), (barH + 1) * 3, this.ratio) + for(var i in branchNames){ + this.branchCache.set({ + w: textW, + h: barH, + id: branchNames[i] + }, ctx => { + var currentMap = this.branchMap[branchNames[i]] + ctx.font = this.draw.bold(this.font) + fontSize + "px " + this.font + ctx.lineJoin = "round" + ctx.miterLimit = 1 + ctx.textAlign = "right" + ctx.textBaseline = "middle" + ctx.lineWidth = 8 * mul + ctx.strokeStyle = currentMap.shadow + ctx.strokeText(strings.branch[branchNames[i]], textX, textY + 4 * mul) + ctx.strokeStyle = currentMap.stroke + ctx.strokeText(strings.branch[branchNames[i]], textX, textY) + ctx.fillStyle = currentMap.text + ctx.fillText(strings.branch[branchNames[i]], textX, textY) + }) + } + } toggleGogoTime(circle){ this.gogoTime = circle.gogoTime this.gogoTimeStarted = circle.ms diff --git a/public/src/views/debug.html b/public/src/views/debug.html index b681717..dd37b44 100644 --- a/public/src/views/debug.html +++ b/public/src/views/debug.html @@ -13,10 +13,10 @@
Branch:
x
From a09709843d35851a6fc4a1b45d89d9b2ea13701f Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Wed, 20 Feb 2019 23:51:45 +0300 Subject: [PATCH 5/6] Fix ura symbol --- public/src/js/canvasdraw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 4431774..7733c3d 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -800,7 +800,7 @@ }else if(action === "fillText"){ ctx.strokeStyle = layer.fill ctx.lineWidth = 2.5 * mul - ctx.fillText(symbol.text, currentX, currentY) + ctx.fillText(symbol.text, currentX, currentY + (17 * mul)) } ctx.stroke() }else{ From 92510c302101798019e61c0e7ff4243024c49938 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Thu, 21 Feb 2019 00:06:16 +0300 Subject: [PATCH 6/6] Do not add canvascache to body --- public/src/js/canvascache.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/src/js/canvascache.js b/public/src/js/canvascache.js index 1b4c121..56a1f7d 100644 --- a/public/src/js/canvascache.js +++ b/public/src/js/canvascache.js @@ -11,7 +11,6 @@ class CanvasCache{ this.map = new Map() this.canvas = document.createElement("canvas") this.ctx = this.canvas.getContext("2d") - document.body.appendChild(this.canvas) } this.scale = scale this.x = 0