diff --git a/public/index.html b/public/index.html index 44beb4f..b34e7a9 100644 --- a/public/index.html +++ b/public/index.html @@ -10,10 +10,11 @@ - + 太鼓の達人ウェブ - Taiko no Tatsujin Web + @@ -46,6 +47,7 @@ + diff --git a/public/src/js/circle.js b/public/src/js/circle.js index 84039d0..4ca8b9b 100644 --- a/public/src/js/circle.js +++ b/public/src/js/circle.js @@ -6,14 +6,13 @@ class Circle{ this.type = config.type this.text = config.txt this.speed = config.speed - this.endTime = config.endTime || this.ms + 150 + this.endTime = config.endTime || this.ms this.isPlayed = 0 this.animating = false this.animT = 0 this.score = 0 this.lastFrame = this.ms + 100 this.animationEnded = false - this.status = -1 this.timesHit = 0 this.requiredHits = config.requiredHits || 0 this.rendaPlayed = false @@ -47,12 +46,6 @@ class Circle{ incAnimT(){ this.animT += 0.05 } - updateStatus(status){ - this.status = status - } - getStatus(){ - return this.status - } getPlayed(){ return this.isPlayed } @@ -64,7 +57,7 @@ class Circle{ } played(score, big){ this.score = score - this.isPlayed = big ? 2 : 1 + this.isPlayed = score <= 0 ? score - 1 : (big ? 2 : 1) } hit(){ this.timesHit++ diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 43cb03a..e276f9d 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -80,7 +80,10 @@ class Controller{ }) } var ms = this.game.getElapsedTime().ms + if(!this.game.isPaused()){ + this.keyboard.checkGameKeys() + if(ms >= 0 && !this.mainLoopStarted){ this.mainLoopStarted = true } @@ -95,7 +98,6 @@ class Controller{ this.game.playMainMusic() } this.view.refresh() - this.keyboard.checkGameKeys() } this.keyboard.checkMenuKeys() } @@ -156,8 +158,8 @@ class Controller{ getKeys(){ return this.keyboard.getKeys() } - setKey(keyCode, down){ - return this.keyboard.setKey(keyCode, down) + setKey(keyCode, down, ms){ + return this.keyboard.setKey(keyCode, down, ms) } getBindings(){ return this.keyboard.getBindings() diff --git a/public/src/js/game.js b/public/src/js/game.js index 0be543e..d208b1e 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -28,6 +28,8 @@ class Game{ this.fadeOutStarted = false this.currentTimingPoint = 0 this.offsetTime = 0 + this.rules = new GameRules(this) + assets.songs.forEach(song => { if(song.id == selectedSong.folder){ this.mainAsset = song.sound @@ -64,45 +66,33 @@ class Game{ var circles = this.songData.circles circles.forEach(circle => { if(!circle.getPlayed()){ - var currentTime = this.getElapsedTime().ms - var startingTime = circle.getMS() - this.timeForDistanceCircle - // At circle.getMS(), the circle fits the slot - var hitTime = circle.getMS() - var endTime = circle.getEndTime() + var ms = this.getElapsedTime().ms var type = circle.getType() var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" + var endTime = circle.getEndTime() + (drumrollNotes ? 0 : this.rules.bad) - if(currentTime >= startingTime && currentTime <= endTime){ - - if(currentTime>= hitTime - 50 && currentTime < hitTime - 30){ - circle.updateStatus(0) - }else if(currentTime >= hitTime - 30 && currentTime < hitTime){ - circle.updateStatus(230) - }else if(currentTime >= hitTime && currentTime < endTime){ - circle.updateStatus(450) - if(drumrollNotes && !circle.rendaPlayed){ - circle.rendaPlayed = true - if(this.controller.selectedSong.difficulty === "easy"){ - assets.sounds["renda"].stop() - assets.sounds["renda"].play() - } + if(ms >= circle.getMS()){ + if(drumrollNotes && !circle.rendaPlayed){ + circle.rendaPlayed = true + if(this.rules.difficulty === "easy"){ + assets.sounds["renda"].stop() + assets.sounds["renda"].play() } } - }else if(currentTime > endTime){ + } + if(ms > endTime){ if(!this.controller.autoPlayEnabled){ if(drumrollNotes){ - circle.updateStatus(-1) - circle.played(0, false) + circle.played(-1, false) this.updateCurrentCircle() if(this.controller.multiplayer === 1){ p2.send("drumroll", { - pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit + pace: (ms - circle.getMS()) / circle.timesHit }) } }else{ - circle.updateStatus(-1) var currentScore = 0 - circle.played(currentScore, type === "daiDon" || type === "daiKa") + circle.played(-1, type === "daiDon" || type === "daiKa") this.controller.displayScore(currentScore, true) this.updateCurrentCircle() this.updateCombo(currentScore) @@ -152,7 +142,7 @@ class Game{ } } checkKey(keyCodes, circle, check){ - if(circle && !circle.getPlayed() && circle.getStatus() != -1){ + if(circle && !circle.getPlayed()){ if(!this.checkScore(circle, check)){ return } @@ -172,18 +162,33 @@ class Game{ var typeKa = type === "ka" || type === "daiKa" var typeDai = type === "daiDon" || type === "daiKa" + var keyTime = this.controller.getKeyTime() + var currentTime = keysDon ? keyTime["don"] : keyTime["ka"] + var relative = currentTime - circle.getMS() + if(typeDon || typeKa){ + if(-this.rules.bad >= relative || relative >= this.rules.bad){ + return true + } var score = 0 if(keysDon && typeDon || keysKa && typeKa){ if(typeDai && !keyDai){ if(!circle.daiFailed){ circle.daiFailed = ms return false - }else if(ms < circle.daiFailed + 2000 / 60){ + }else if(ms < circle.daiFailed + this.rules.daiLeniency){ return false } } - var circleStatus = circle.getStatus() + var circleStatus = -1 + relative = Math.abs(relative) + if(relative < this.rules.good){ + circleStatus = 450 + }else if(relative < this.rules.ok){ + circleStatus = 230 + }else if(relative < this.rules.bad){ + circleStatus = 0 + } if(circleStatus === 230 || circleStatus === 450){ score = circleStatus } @@ -198,19 +203,24 @@ class Game{ if(this.controller.multiplayer == 1){ p2.send("note", { score: score, - ms: circle.getMS() - ms, + ms: circle.getMS() - currentTime, dai: typeDai ? keyDai ? 2 : 1 : 0 }) } - }else if(keysDon && type == "balloon"){ - this.checkBalloon(circle) - if(check === "daiDon" && !circle.getPlayed()){ - this.checkBalloon(circle) + }else{ + if(circle.getMS() > currentTime || currentTime > circle.getEndTime()){ + return true } - }else if((keysDon || keysKa) && (type === "drumroll" || type === "daiDrumroll")){ - this.checkDrumroll(circle) - if(keyDai){ + if(keysDon && type === "balloon"){ + this.checkBalloon(circle) + if(check === "daiDon" && !circle.getPlayed()){ + this.checkBalloon(circle) + } + }else if((keysDon || keysKa) && (type === "drumroll" || type === "daiDrumroll")){ this.checkDrumroll(circle) + if(keyDai){ + this.checkDrumroll(circle) + } } } return true @@ -261,7 +271,7 @@ class Game{ var circles = this.songData.circles var lastCircle = circles[circles.length - 1] var ms = this.getElapsedTime().ms - if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 1900){ + if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 2000){ this.fadeOutStarted = ms } } @@ -329,17 +339,21 @@ class Game{ } updateTime(){ // Refreshed date - this.currentDate = new Date() + var currentDate = new Date() var ms = this.getElapsedTime().ms if(ms >= 0 && !this.started){ this.startDate = new Date() this.elapsedTimeSincePause = 0 - this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime()) + this.setElapsedTime(this.getAccurateTime()) this.started = true }else if(ms < 0 || ms >= 0 && this.started){ - this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime() - this.elapsedTimeSincePause) + this.setElapsedTime(this.getAccurateTime()) } } + getAccurateTime(){ + var currentDate = new Date() + return currentDate.getTime() - this.startDate.getTime() - this.elapsedTimeSincePause + } getCircles(){ return this.songData.circles } diff --git a/public/src/js/gamepad.js b/public/src/js/gamepad.js index 35b634b..ceb0a98 100644 --- a/public/src/js/gamepad.js +++ b/public/src/js/gamepad.js @@ -1,5 +1,8 @@ class Gamepad{ constructor(keyboard){ + this.keyboard = keyboard + this.game = this.keyboard.controller.game + var kbd = keyboard.getBindings() this.gameBtn = {} this.gameBtn[kbd["don_l"]] = ["u", "d", "l", "r"] @@ -28,9 +31,9 @@ class Gamepad{ "guide": 16 } this.btn = {} - this.keyboard = keyboard } play(menuPlay){ + var ms = this.game.getAccurateTime() if("getGamepads" in navigator){ var gamepads = navigator.getGamepads() }else{ @@ -48,7 +51,7 @@ class Gamepad{ for(var bind in bindings){ for(var name in bindings[bind]){ if(btnName === this.b[bindings[bind][name]]){ - this.checkButton(gamepads, btnName, bind) + this.checkButton(gamepads, btnName, bind, ms) break buttonSearch } } @@ -59,8 +62,9 @@ class Gamepad{ } } } - checkButton(gamepads, btnName, keyCode){ + checkButton(gamepads, btnName, keyCode, ms){ var button = false + for(var i = 0; i < gamepads.length; i++){ if(gamepads[i]){ var btn = gamepads[i].buttons[btnName] @@ -72,19 +76,24 @@ class Gamepad{ } } } + + var keys = this.keyboard.getKeys() var pressed = !this.btn[btnName] && button var released = this.btn[btnName] && !button + if(pressed){ this.btn[btnName] = true }else if(released){ delete this.btn[btnName] } + if(pressed){ - if(this.keyboard.getKeys()[keyCode]){ + if(keys[keyCode]){ this.keyboard.setKey(keyCode, false) } - this.keyboard.setKey(keyCode, true) - }else if(!button && this.keyboard.getKeys()[keyCode]){ + this.keyboard.setKey(keyCode, true, ms) + + }else if(!button && keys[keyCode]){ if(released){ this.toRelease[keyCode + "released"] = true } diff --git a/public/src/js/gamerules.js b/public/src/js/gamerules.js new file mode 100644 index 0000000..95dd6b3 --- /dev/null +++ b/public/src/js/gamerules.js @@ -0,0 +1,23 @@ +class GameRules{ + constructor(game){ + this.difficulty = game.controller.selectedSong.difficulty + var frame = 1000 / 60 + + switch(this.difficulty){ + case "easy": + case "normal": + this.good = 5 / 2 * frame + this.ok = 13 / 2 * frame + this.bad = 15 / 2 * frame + break + case "hard": + case "oni": + this.good = 3 / 2 * frame + this.ok = 9 / 2 * frame + this.bad = 13 / 2 * frame + break + } + + this.daiLeniency = 2 * frame + } +} diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index dc50d65..36d799a 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -1,6 +1,8 @@ class Keyboard{ constructor(controller){ this.controller = controller + this.game = this.controller.game + this.kbd = { "don_l": 86, // V "don_r": 66, // B @@ -19,12 +21,13 @@ class Keyboard{ } this.gamepad = new Gamepad(this) pageEvents.keyAdd(this, "all", "both", event => { - if (event.keyCode === 8){ + if(event.keyCode === 8){ // Disable back navigation when pressing backspace event.preventDefault() } - if(this.buttonEnabled(event.keyCode)){ - this.setKey(event.keyCode, event.type === "keydown") + if(!event.repeat && this.buttonEnabled(event.keyCode)){ + var ms = this.game.getAccurateTime() + this.setKey(event.keyCode, event.type === "keydown", ms) } }) } @@ -69,21 +72,20 @@ class Keyboard{ }) } } - checkKey(keyCode, keyup, callback){ - if(this.keys[keyCode] && !this.isWaiting(keyCode, keyup)){ - this.waitForKeyup(keyCode, keyup) + checkKey(keyCode, type, callback){ + if(this.keys[keyCode] && !this.isWaiting(keyCode, type)){ + this.waitForKeyup(keyCode, type) callback() } } checkKeySound(keyCode, sound){ this.checkKey(keyCode, "sound", () => { - var circles = this.controller.parsedSongData.circles - var circle = circles[this.controller.game.getCurrentCircle()] + var circles = this.controller.getCircles() + var circle = circles[this.controller.getCurrentCircle()] if( (keyCode === this.kbd["don_l"] || keyCode === this.kbd["don_r"]) && circle && !circle.getPlayed() - && circle.getStatus() !== -1 && circle.getType() === "balloon" && circle.requiredHits - circle.timesHit <= 1 ){ @@ -91,40 +93,39 @@ class Keyboard{ }else{ assets.sounds["note_" + sound].play() } - var ms = this.controller.getElapsedTime().ms - this.keyTime[keyCode] = ms - this.keyTime[sound] = ms + this.keyTime[sound] = this.keyTime[keyCode] }) } getKeys(){ return this.keys } - setKey(keyCode, down){ + setKey(keyCode, down, ms){ if(down){ this.keys[keyCode] = true + this.keyTime[keyCode] = ms }else{ - delete this.keys[keyCode] - delete this.waitKeyupScore[keyCode] - delete this.waitKeyupSound[keyCode] - delete this.waitKeyupMenu[keyCode] + this.keys[keyCode] = false + this.waitKeyupScore[keyCode] = false + this.waitKeyupSound[keyCode] = false + this.waitKeyupMenu[keyCode] = false } } - isWaiting(key, type){ + isWaiting(keyCode, type){ if(type === "score"){ - return this.waitKeyupScore[key] + return this.waitKeyupScore[keyCode] }else if(type === "sound"){ - return this.waitKeyupSound[key] + return this.waitKeyupSound[keyCode] }else if(type === "menu"){ - return this.waitKeyupMenu[key] + return this.waitKeyupMenu[keyCode] } } - waitForKeyup(key, type){ + waitForKeyup(keyCode, type){ if(type === "score"){ - this.waitKeyupScore[key] = true + this.waitKeyupScore[keyCode] = true }else if(type === "sound"){ - this.waitKeyupSound[key] = true + this.waitKeyupSound[keyCode] = true }else if(type === "menu"){ - this.waitKeyupMenu[key] = true + this.waitKeyupMenu[keyCode] = true } } getKeyTime(){ diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index 91b319f..2864a82 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -3,13 +3,11 @@ class Mekadon{ this.controller = controller this.game = game this.lr = false - this.keys = {} this.lastHit = -Infinity } play(circle){ var type = circle.getType() if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.getEndTime()){ - circle.updateStatus(-1) circle.played(0, false) this.game.updateCurrentCircle() } @@ -48,21 +46,29 @@ class Mekadon{ var type = circle.getType() var keyDai = false var playDai = !dai || dai === 2 + var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" + + if(drumrollNotes){ + var ms = this.getMS() + }else{ + var ms = circle.getMS() + } + if(type == "daiDon" && playDai){ - this.setKey(kbd["don_l"]) - this.setKey(kbd["don_r"]) + this.setKey(kbd["don_l"], ms) + this.setKey(kbd["don_r"], ms) this.lr = false keyDai = true - }else if(type == "don" || type == "daiDon" || type == "balloon" || type == "drumroll" || type == "daiDrumroll"){ - this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"]) + }else if(type == "don" || type == "daiDon" || drumrollNotes){ + this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"], ms) this.lr = !this.lr }else if(type == "daiKa" && playDai){ - this.setKey(kbd["ka_l"]) - this.setKey(kbd["ka_r"]) + this.setKey(kbd["ka_l"], ms) + this.setKey(kbd["ka_r"], ms) this.lr = false keyDai = true }else if(type == "ka" || type == "daiKa"){ - this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"]) + this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"], ms) this.lr = !this.lr } if(type === "balloon"){ @@ -73,36 +79,20 @@ class Mekadon{ }else if(type === "drumroll" || type === "daiDrumroll"){ this.game.checkDrumroll(circle) }else{ - if(typeof score == "undefined"){ - score = this.game.checkScore(circle) - }else{ - this.controller.displayScore(score) - this.game.updateCombo(score) - this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime) - this.game.updateCurrentCircle() - } - circle.updateStatus(score) + this.controller.displayScore(score) + this.game.updateCombo(score) + this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime) + this.game.updateCurrentCircle() circle.played(score, keyDai) } - this.lastHit = this.getMS() + this.lastHit = ms return true } getMS(){ return this.controller.getElapsedTime().ms } - setKey(keyCode){ - var self = this - if(this.keys[keyCode]){ - clearTimeout(this.keys[keyCode]) - self.clearKey(keyCode) - } - this.controller.setKey(keyCode, true) - this.keys[keyCode] = setTimeout(function(){ - self.clearKey(keyCode) - }, 100) - } - clearKey(keyCode){ + setKey(keyCode, ms){ this.controller.setKey(keyCode, false) - delete this.keys[keyCode] + this.controller.setKey(keyCode, true, ms) } } diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 03a3925..1f932be 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -116,7 +116,14 @@ class P2Connection{ play(circle, mekadon){ if(this.otherConnected || this.notes.length > 0){ var type = circle.getType() - if(type === "balloon"|| type === "drumroll" || type === "daiDrumroll"){ + var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" + + if(drumrollNotes && mekadon.getMS() > circle.getEndTime()){ + circle.played(-1, false) + mekadon.game.updateCurrentCircle() + } + + if(drumrollNotes){ mekadon.playDrumrollAt(circle, 0, this.drumrollPace) }else if(this.notes.length === 0){ mekadon.play(circle) diff --git a/public/src/js/view.js b/public/src/js/view.js index d744afb..ac32dec 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -420,8 +420,8 @@ class View{ var startingTime = circle.getMS() - timeForDistance var finishTime = circle.getEndTime() + this.posToMs(this.slotX - this.taikoSquareW + this.bigCircleSize * 3, speed) - if(!circle.getPlayed() || circle.getScore() === 0){ - if(ms >= startingTime && ms <= finishTime){ + if(circle.getPlayed() <= 0 || circle.getScore() === 0){ + if(ms >= startingTime && ms <= finishTime && circle.getPlayed() !== -1){ this.drawCircle(circle) } }else if(!circle.isAnimated()){ diff --git a/public/src/views/titlescreen.html b/public/src/views/titlescreen.html index 82dedc0..b582db7 100644 --- a/public/src/views/titlescreen.html +++ b/public/src/views/titlescreen.html @@ -1,4 +1,4 @@
太鼓の達人ウェブ -
Click or Press Enter! +
Click or Press Enter!