diff --git a/README.md b/README.md index 01874aa..afea7ec 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Still in developement. Works best with Chrome. Create a SQLite databse named `taiko.db` with the following schema: - CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL ) + CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `ura` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL ) CREATE TABLE "categories" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT NOT NULL ) When inserting song rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them. diff --git a/app.py b/app.py index 216b357..2235372 100644 --- a/app.py +++ b/app.py @@ -105,33 +105,34 @@ def route_api_songs(): categories[cat[0]] = {'title': cat[1], 'title_en': cat[2]} songs_out = [] for song in songs: - type = song[9] - if type == "tja": - if os.path.isfile('public/songs/%s/main.tja' % song[0]): - preview = get_tja_preview('public/songs/%s/main.tja' % song[0]) + song_id = song[0] + song_type = song[10] + if song_type == "tja": + if os.path.isfile('public/songs/%s/main.tja' % song_id): + preview = get_tja_preview('public/songs/%s/main.tja' % song_id) else: preview = 0 else: - osus = [osu for osu in os.listdir('public/songs/%s' % song[0]) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']] + osus = [osu for osu in os.listdir('public/songs/%s' % song_id) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']] if osus: - osud = parse_osu('public/songs/%s/%s' % (song[0], osus[0])) + osud = parse_osu('public/songs/%s/%s' % (song_id, osus[0])) preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0)) else: preview = 0 - category_out = categories[song[8]] if song[8] in categories else def_category + category_out = categories[song[9]] if song[9] in categories else def_category songs_out.append({ - 'id': song[0], + 'id': song_id, 'title': song[1], 'title_en': song[2], 'stars': [ - song[3], song[4], song[5], song[6] + song[3], song[4], song[5], song[6], song[7] ], 'preview': preview, 'category': category_out['title'], 'category_en': category_out['title_en'], - 'type': type, - 'offset': song[10] + 'type': song_type, + 'offset': song[11] }) return jsonify(songs_out) diff --git a/public/src/css/game.css b/public/src/css/game.css index 776983a..848c24a 100644 --- a/public/src/css/game.css +++ b/public/src/css/game.css @@ -1,6 +1,7 @@ #game{ width: 100%; height: 100%; + position: asbolute; overflow: hidden; background-size: cover; } @@ -32,7 +33,7 @@ border:.5vmin solid #ae7a26; background: #fff; color: #000; - font-family: TnT; + font-family: TnT, Meiryo, sans-serif; font-size: 3.5vmin; border-radius: 1.5vmin; outline: none; @@ -61,6 +62,7 @@ height: 50%; text-align: center; margin: auto; + overflow: hidden; } #touch-drum-img{ width: 100%; diff --git a/public/src/css/main.css b/public/src/css/main.css index 8f81bdf..b91867a 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -13,6 +13,7 @@ body{ height: 100%; background: #fe7839; user-select: none; + touch-action: none; } #screen{ width: 100%; @@ -20,7 +21,7 @@ body{ margin: 0; padding: 0; background: #fe7839 url("/assets/img/bg-pattern-1.png") top center; - font-family: TnT; + font-family: TnT, Meiryo, sans-serif; } #assets{ display: none; @@ -233,13 +234,16 @@ kbd{ bottom: 1vh; right: 1vh; opacity: 0.7; - font-family: TnT; + font-family: TnT, Meiryo, sans-serif; +} +#version:hover{ + opacity: 1; } -#version a { +#version-link{ color: #FFFFFF; text-decoration: none; - cursor: default; + pointer-events: none; } .version-hide{ diff --git a/public/src/js/assets.js b/public/src/js/assets.js index fb5fded..e289e16 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -22,6 +22,7 @@ var assets = { "muzu_normal.png", "muzu_hard.png", "muzu_oni.png", + "muzu_ura.png", "don_anim_normal.png", "don_anim_10combo.png", "don_anim_gogo.png", diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index d899003..429b59b 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -229,6 +229,12 @@ easeIn(pos){ return 1 - Math.cos(Math.PI / 2 * pos) } + easeOut(pos){ + return Math.sin(Math.PI / 2 * pos) + } + easeInOut(pos){ + return (Math.cos(Math.PI * pos) - 1) / -2 + } verticalText(config){ var ctx = config.ctx @@ -508,7 +514,7 @@ ctx.save() ctx.lineWidth = config.border ctx.strokeStyle = "#000" - var icon = this.diffIconPath[config.diff] + var icon = this.diffIconPath[config.diff === 4 ? 3 : config.diff] ctx.translate(config.x - icon[0].w * scale / 2, config.y - icon[0].h * scale / 2) ctx.scale(scale, scale) for(var i = 1; i < icon.length; i++){ @@ -518,7 +524,11 @@ } if(!config.noFill){ for(var i = 1; i < icon.length; i++){ - ctx.fillStyle = icon[i].fill + if(config.diff === 4 && icon[i].fill === "#db1885"){ + ctx.fillStyle = "#7135db" + }else{ + ctx.fillStyle = icon[i].fill + } ctx.fill(icon[i].d) } } @@ -619,18 +629,19 @@ diffStar(config){ var ctx = config.ctx ctx.save() - if(config.songSel){ + if(config.songSel || config.ura){ if(this.diffStarCache.scale !== config.ratio){ - this.diffStarCache.resize(30, 30, config.ratio) + this.diffStarCache.resize(62, 31, config.ratio) } var offset = 30 / 2 - 18 / 2 + var big = config.ura && !config.songSel this.diffStarCache.get({ ctx: ctx, x: config.x - 9 - offset, y: config.y - 9 - offset, w: 30, h: 30, - id: "star" + id: big ? "big" : "small" }, ctx => { ctx.fillStyle = "#fff" this.shadow({ @@ -639,7 +650,12 @@ blur: 10, force: true }) - ctx.translate(offset, offset) + if(big){ + ctx.translate(30 / 2 - 21 / 2, 30 / 2 - 19 / 2) + ctx.scale(1.1, 1.1) + }else{ + ctx.translate(offset, offset) + } ctx.fill(this.diffStarPath) }) }else{ diff --git a/public/src/js/canvastest.js b/public/src/js/canvastest.js index 5a5e92b..b952981 100644 --- a/public/src/js/canvastest.js +++ b/public/src/js/canvastest.js @@ -103,7 +103,7 @@ class CanvasTest{ var comboX = 100 var comboY = 100 var fontSize = 120 - this.ctx.font = "normal " + fontSize + "px TnT" + this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif" this.ctx.textAlign = "center" this.ctx.strokeStyle = "#000" this.ctx.lineWidth = fontSize / 10 diff --git a/public/src/js/controller.js b/public/src/js/controller.js index a497129..9ef9608 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -40,17 +40,17 @@ class Controller{ } } loadUIEvents(){ + this.pauseMenu = document.getElementById("pause-menu") this.continueBtn = document.getElementById("continue-butt") this.restartBtn = document.getElementById("restart-butt") this.songSelBtn = document.getElementById("song-selection-butt") - pageEvents.add(this.continueBtn, "click", () => { - this.togglePauseMenu() - }) - pageEvents.add(this.restartBtn, "click", () => { + pageEvents.add(this.pauseMenu, "touchstart", event => event.preventDefault()) + pageEvents.add(this.continueBtn, ["click", "touchend"], this.togglePauseMenu.bind(this)) + pageEvents.add(this.restartBtn, ["click", "touchend"], () => { assets.sounds["don"].play() this.restartSong() }) - pageEvents.add(this.songSelBtn, "click", () => { + pageEvents.add(this.songSelBtn, ["click", "touchend"], () => { assets.sounds["don"].play() this.songSelection() }) @@ -63,9 +63,6 @@ class Controller{ stopMainLoop(){ this.mainLoopRunning = false this.mainAsset.stop() - if(this.syncWith){ - this.syncWith.stopMainLoop() - } } mainLoop(){ if(this.mainLoopRunning){ @@ -212,11 +209,13 @@ class Controller{ this.keyboard.clean() this.view.clean() - pageEvents.remove(this.continueBtn, "click") + pageEvents.remove(this.pauseMenu, "touchstart") + delete this.pauseMenu + pageEvents.remove(this.continueBtn, ["click", "touchend"]) delete this.continueBtn - pageEvents.remove(this.restartBtn, "click") + pageEvents.remove(this.restartBtn, ["click", "touchend"]) delete this.restartBtn - pageEvents.remove(this.songSelBtn, "click") + pageEvents.remove(this.songSelBtn, ["click", "touchend"]) delete this.songSelBtn } } diff --git a/public/src/js/gamerules.js b/public/src/js/gamerules.js index 95dd6b3..35818bd 100644 --- a/public/src/js/gamerules.js +++ b/public/src/js/gamerules.js @@ -12,6 +12,7 @@ class GameRules{ break case "hard": case "oni": + case "ura": this.good = 3 / 2 * frame this.ok = 9 / 2 * frame this.bad = 13 / 2 * frame diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 62dce66..e8bda9d 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -6,6 +6,15 @@ class Loader{ this.canvasTest = new CanvasTest() p2 = new P2Connection() this.ajax("src/views/loader.html").then(this.run.bind(this)) + + pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { + event.preventDefault() + }) + var versionDiv = document.getElementById("version") + var versionLink = document.getElementById("version-link") + pageEvents.add(versionDiv, ["click", "touchend"], () => { + versionLink.click() + }) } run(page){ this.promises = [] @@ -152,5 +161,6 @@ class Loader{ delete this.loaderPercentage delete this.loaderProgress delete this.promises + pageEvents.remove(root, "touchstart") } } diff --git a/public/src/js/main.js b/public/src/js/main.js index b78130e..98f6121 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -1,5 +1,4 @@ function toggleFullscreen(){ - var root = document.documentElement if("requestFullscreen" in root){ if(document.fullscreenElement){ document.exitFullscreen() @@ -20,6 +19,8 @@ function toggleFullscreen(){ } } } +var root = document.documentElement +var fullScreenSupported = "requestFullscreen" in root || "webkitRequestFullscreen" in root || "mozRequestFullScreen" in root var pageEvents = new PageEvents() var snd = {} diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index 7b1fef7..aa16104 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -8,6 +8,10 @@ class PageEvents{ this.add(window, "mousemove", this.mouseEvent.bind(this)) } add(target, type, callback){ + if(Array.isArray(type)){ + type.forEach(type => this.add(target, type, callback)) + return + } this.remove(target, type) var addedEvent = this.allEvents.get(target) if(!addedEvent){ @@ -18,6 +22,10 @@ class PageEvents{ return target.addEventListener(type, callback) } remove(target, type){ + if(Array.isArray(type)){ + type.forEach(type => this.remove(target, type)) + return + } var addedEvent = this.allEvents.get(target) if(addedEvent){ var callback = addedEvent.get(type) diff --git a/public/src/js/parsetja.js b/public/src/js/parsetja.js index d995462..52d56f0 100644 --- a/public/src/js/parsetja.js +++ b/public/src/js/parsetja.js @@ -22,7 +22,14 @@ {name: false, txt: false}, {name: "balloon", txt: "ふうせん"} ] - this.courseTypes = ["easy", "normal", "hard", "oni"] + this.courseTypes = { + "0": "easy", + "1": "normal", + "2": "hard", + "3": "oni", + "4": "ura", + "edit": "ura" + } this.metadata = this.parseMetadata() this.measures = [] @@ -67,10 +74,11 @@ value = value.trim() if(name === "course"){ + value = value.toLowerCase() if(value in this.courseTypes){ courseName = this.courseTypes[value] }else{ - courseName = value.toLowerCase() + courseName = value } }else if(name === "balloon"){ value = value ? value.split(",").map(digit => parseInt(digit)) : [] diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 3556cfe..c309bd9 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -10,7 +10,7 @@ class Scoresheet{ this.canvas = document.getElementById("canvas") this.ctx = this.canvas.getContext("2d") - this.font = "TnT" + this.font = "TnT, Meiryo, sans-serif" this.state = { screen: "fadeIn", screenMS: this.getMS(), @@ -89,8 +89,7 @@ class Scoresheet{ this.winH = null pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) - pageEvents.add(this.canvas, "mousedown", this.mouseDown.bind(this)) - pageEvents.add(this.canvas, "touchstart", this.mouseDown.bind(this)) + pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this)) } redraw(){ @@ -670,8 +669,7 @@ class Scoresheet{ snd.musicGain.fadeIn() this.redrawRunning = false pageEvents.keyRemove(this, "all") - pageEvents.remove(this.canvas, "mousedown") - pageEvents.remove(this.canvas, "touchstart") + pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) delete this.ctx delete this.canvas } diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index d894a9a..53248e9 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -78,7 +78,7 @@ class SongSelect{ outline: "#656565" } } - this.font = "TnT" + this.font = "TnT, Meiryo, sans-serif" this.songs = [] for(let song of assets.songs){ @@ -149,7 +149,7 @@ class SongSelect{ this.difficultyCache = new CanvasCache() this.difficulty = ["かんたん", "ふつう", "むずかしい", "おに"] - this.difficultyId = ["easy", "normal", "hard", "oni"] + this.difficultyId = ["easy", "normal", "hard", "oni", "ura"] this.selectedSong = 0 this.selectedDiff = 0 @@ -181,6 +181,7 @@ class SongSelect{ screenMS: this.getMS(), move: 0, moveMS: 0, + ura: 0, moveHover: null, locked: true, hasPointer: false @@ -210,12 +211,11 @@ class SongSelect{ this.redraw() pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.add(this.canvas, "mousemove", this.mouseMove.bind(this)) - pageEvents.add(this.canvas, "mousedown", this.mouseDown.bind(this)) - pageEvents.add(this.canvas, "touchstart", this.mouseDown.bind(this)) - if(touchEnabled){ + pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this)) + if(touchEnabled && fullScreenSupported){ this.touchFullBtn = document.getElementById("touch-full-btn") this.touchFullBtn.style.display = "block" - pageEvents.add(this.touchFullBtn, "click", toggleFullscreen) + pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen) } } @@ -306,6 +306,12 @@ class SongSelect{ || mouse.y < 40 || mouse.y > 540 ){ this.toSongSelect() + }else if(moveBy === 5){ + this.state.ura = !this.state.ura + assets.sounds["ka"].play() + if(this.selectedDiff === 5 && !this.state.ura){ + this.state.move = -1 + } }else if(moveBy !== null){ this.toLoadSong(moveBy - 1, shift, ctrl, touch) } @@ -370,10 +376,10 @@ class SongSelect{ if(this.state.locked === 0){ if(100 < x && x < 160 && 120 < y && y < 420){ return 0 - }else if(434 < x && x < 810 && 95 < y && y < 524){ - var moveBy = Math.floor((x - 434) / ((810 - 434) / 4)) + 1 + }else if(422 < x && x < 922 && 95 < y && y < 524){ + var moveBy = Math.floor((x - 422) / ((922 - 422) / 5)) + 1 var currentSong = this.songs[this.selectedSong] - if(currentSong.stars[moveBy - 1]){ + if(this.state.ura && moveBy === 4 || currentSong.stars[moveBy - 1]){ return moveBy } } @@ -425,6 +431,10 @@ class SongSelect{ this.state.screenMS = this.getMS() this.state.locked = true this.state.moveHover = null + this.state.ura = 0 + if(this.selectedDiff === 5){ + this.selectedDiff = 4 + } assets.sounds["don"].play() assets.sounds["song-select"].stop() @@ -468,6 +478,10 @@ class SongSelect{ localStorage["selectedSong"] = this.selectedSong localStorage["selectedDiff"] = difficulty + 1 + if(difficulty === 3 && this.state.ura){ + difficulty = 4 + } + new loadSong({ "title": selectedSong.title, "folder": selectedSong.id, @@ -557,7 +571,7 @@ class SongSelect{ }) this.categoryCache.resize(280, (this.songAsset.marginTop + 1) * categories , ratio + 0.5) - this.difficultyCache.resize((44 + 56 + 2) * 4, 135 + 10, ratio + 0.5) + this.difficultyCache.resize((44 + 56 + 2) * 5, 135 + 10, ratio + 0.5) }else if(!document.hasFocus()){ this.pointer(false) return @@ -698,9 +712,28 @@ class SongSelect{ this.state.locked = 0 } if(this.state.move){ + var hasUra = currentSong.stars[4] + var previousSelection = this.selectedDiff do{ - this.selectedDiff = this.mod(5, this.selectedDiff + this.state.move) - }while(this.selectedDiff !== 0 && !currentSong.stars[this.selectedDiff - 1]) + if(hasUra && this.state.move > 0){ + this.selectedDiff += this.state.move + if(this.selectedDiff > 5){ + this.state.ura = !this.state.ura + if(this.state.ura){ + this.selectedDiff = previousSelection === 4 ? 5 : previousSelection + break + }else{ + this.state.move = -1 + } + } + }else{ + this.selectedDiff = this.mod(6, this.selectedDiff + this.state.move) + } + }while( + this.selectedDiff !== 0 && !currentSong.stars[this.selectedDiff - 1] + || this.selectedDiff === 4 && this.state.ura + || this.selectedDiff === 5 && !this.state.ura + ) this.state.move = 0 }else if(!currentSong.stars[this.selectedDiff - 1]){ this.selectedDiff = 0 @@ -903,19 +936,19 @@ class SongSelect{ } } } - for(var i = 0; currentSong.stars && i < 4; i++){ - if(currentSong.stars[i]){ + var drawDifficulty = (ctx, i, currentUra) => { + if(currentSong.stars[i] || currentUra){ if(songSel){ var _x = x + 33 + i * 60 var _y = y + 120 - ctx.fillStyle = "#ff9f18" + ctx.fillStyle = currentUra ? "#006279" : "#ff9f18" ctx.beginPath() ctx.arc(_x, _y + 22, 22, -Math.PI, 0) ctx.arc(_x, _y + 266, 22, 0, Math.PI) ctx.fill() this.draw.diffIcon({ ctx: ctx, - diff: i, + diff: currentUra ? 4 : i, x: _x, y: _y - 8, scale: 1, @@ -937,13 +970,13 @@ class SongSelect{ ctx.lineWidth = 4.5 ctx.fillRect(_x - 35.5, _y + 2, 71, 380) ctx.strokeRect(_x - 35.5, _y + 2, 71, 380) - ctx.fillStyle = "#fff" + ctx.fillStyle = currentUra ? "#006279" : "#fff" ctx.lineWidth = 2.5 ctx.fillRect(_x - 28, _y + 19, 56, 351) ctx.strokeRect(_x - 28, _y + 19, 56, 351) this.draw.diffIcon({ ctx: ctx, - diff: i, + diff: currentUra ? 4 : i, x: _x, y: _y - 12, scale: 1.4, @@ -957,7 +990,7 @@ class SongSelect{ y: songSel ? _y + 10 : _y + 23, w: songSel ? 44 : 56, h: (songSel ? 88 : 135) + 10, - id: this.difficulty[i] + (songSel ? "1" : "0") + id: this.difficulty[currentUra ? 4 : i] + (songSel ? "1" : "0") }, ctx => { this.draw.verticalText({ ctx: ctx, @@ -966,19 +999,22 @@ class SongSelect{ y: 0, width: songSel ? 44 : 56, height: songSel ? (i === 1 ? 66 : 88) : (i === 0 ? 130 : (i === 1 ? 110 : 135)), - fill: "#000", + fill: currentUra ? "#fff" : "#000", fontSize: songSel ? 25 : (i === 2 ? 45 : 40), - fontFamily: this.font + fontFamily: this.font, + outline: currentUra ? "#003C52" : false, + 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 > currentSong.stars[i]){ - ctx.fillStyle = songSel ? "#e97526" : "#e7e7e7" + 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() @@ -986,12 +1022,17 @@ class SongSelect{ this.draw.diffStar({ ctx: ctx, songSel: songSel, + ura: currentUra, x: _x, y: yPos, ratio: ratio }) } } + var currentDiff = this.selectedDiff - 1 + if(this.selectedDiff === 5){ + currentDiff = 3 + } if(i === currentSong.p2Cursor){ this.draw.diffCursor({ ctx: ctx, @@ -999,13 +1040,12 @@ class SongSelect{ x: _x, y: _y - (songSel ? 45 : 65), two: true, - side: songSel ? false : (currentSong.p2Cursor === this.selectedDiff - 1), + side: songSel ? false : (currentSong.p2Cursor === currentDiff), scale: songSel ? 0.7 : 1 }) } if(!songSel){ var highlight = 0 - var currentDiff = this.selectedDiff - 1 if(this.state.moveHover - 1 === i){ highlight = 2 }else if(currentDiff === i){ @@ -1035,6 +1075,42 @@ class SongSelect{ } } } + for(var i = 0; currentSong.stars && i < 4; i++){ + var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.stars[4] && songSel) + if(songSel && currentUra){ + drawDifficulty(ctx, i, false) + var elapsedMS = this.state.screenMS > this.state.moveMS ? this.state.screenMS : this.state.moveMS + var fade = ((ms - elapsedMS) % 4000) / 4000 + var alphaFade = 0 + if(fade > 0.95){ + alphaFade = this.draw.easeOut(1 - (fade - 0.95) * 20) + }else if(fade > 0.5){ + alphaFade = 1 + }else if(fade > 0.45){ + alphaFade = this.draw.easeIn((fade - 0.45) * 20) + } + this.draw.alpha(alphaFade, ctx, ctx => { + drawDifficulty(ctx, i, true) + }) + }else{ + drawDifficulty(ctx, i, currentUra) + } + } + if(!songSel && currentSong.stars[4]){ + var fade = ((ms - this.state.screenMS) % 1200) / 1200 + var _x = x + 402 + 4 * 100 + fade * 25 + var _y = y + 258 + ctx.save() + ctx.globalAlpha = this.draw.easeInOut(1 - fade) + ctx.fillStyle = "#e0be28" + ctx.beginPath() + ctx.moveTo(_x - 35, _y - 25) + ctx.lineTo(_x - 10, _y) + ctx.lineTo(_x - 35, _y + 25) + ctx.fill() + ctx.restore() + } + ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2 ctx.fillStyle = selectedSkin.background ctx.fillRect(x, y, w, h) @@ -1066,8 +1142,6 @@ class SongSelect{ fontFamily: this.font }) }) - //ctx.fillStyle="#f00" - //ctx.fillRect(textX,textY,textW,textH) } }) @@ -1212,6 +1286,9 @@ class SongSelect{ var id = idDiff.id |0 var diff = idDiff.diff var diffId = this.difficultyId.indexOf(diff) + if(diffId > 3){ + diffId = 3 + } if(diffId >= 0){ var currentSong = this.songs.find(song => song.id === id) currentSong.p2Cursor = diffId @@ -1255,10 +1332,8 @@ class SongSelect{ this.redrawRunning = false this.endPreview() pageEvents.keyRemove(this, "all") - pageEvents.remove(this.canvas, "mousemove") - pageEvents.remove(this.canvas, "mousedown") - pageEvents.remove(this.canvas, "touchstart") - if(this.touchEnabled){ + pageEvents.remove(this.canvas, ["mousemove", "mousedown", "touchstart"]) + if(this.touchEnabled && fullScreenSupported){ pageEvents.remove(this.touchFullBtn, "click") delete this.touchFullBtn } diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index 34186bc..9a8c1c2 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -2,11 +2,7 @@ constructor(){ var AudioContext = window.AudioContext || window.webkitAudioContext this.context = new AudioContext() - pageEvents.once(window, "click").then(() => { - if(this.context.state === "suspended"){ - this.context.resume() - } - }) + pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this)) } load(url, gain){ return loader.ajax(url, request => { @@ -48,6 +44,11 @@ source.connect(sound.gain.gainNode || this.context.destination) return source } + pageClicked(){ + if(this.context.state === "suspended"){ + this.context.resume() + } + } } class SoundGain{ constructor(soundBuffer, channel){ @@ -178,7 +179,9 @@ class Sound{ stop(time, absolute){ time = this.convertTime(time, absolute) this.sources.forEach(source => { - source.stop(Math.max(source.startTime, time)) + try{ + source.stop(Math.max(source.startTime, time)) + }catch(e){} }) this.setTimeouts(time).then(() => { if(this.loop){ diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index f2ad090..28c45d7 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -3,8 +3,7 @@ class Titlescreen{ loader.changePage("titlescreen") this.titleScreen = document.getElementById("title-screen") pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) - pageEvents.add(this.titleScreen, "mousedown", this.onPressed.bind(this)) - pageEvents.once(this.titleScreen, "touchstart").then(this.onPressed.bind(this)) + pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], this.onPressed.bind(this)) assets.sounds["title"].play() this.gamepad = new Gamepad({ "13": ["a", "b", "x", "y", "start", "ls", "rs"] @@ -48,8 +47,7 @@ class Titlescreen{ this.gamepad.clean() assets.sounds["title"].stop() pageEvents.keyRemove(this, "all") - pageEvents.remove(this.titleScreen, "mousedown") - pageEvents.remove(this.titleScreen, "touchstart") + pageEvents.remove(this.titleScreen, ["mousedown", "touchstart"]) delete this.titleScreen } } diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js index 4059a0e..3f9e1e3 100644 --- a/public/src/js/tutorial.js +++ b/public/src/js/tutorial.js @@ -5,8 +5,7 @@ class Tutorial{ assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) this.endButton = document.getElementById("tutorial-end-button") - pageEvents.once(this.endButton, "mousedown").then(this.onEnd.bind(this)) - pageEvents.once(this.endButton, "touchstart").then(this.onEnd.bind(this)) + pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this)) this.gamepad = new Gamepad({ @@ -29,7 +28,7 @@ class Tutorial{ clean(){ this.gamepad.clean() assets.sounds["bgm_setsume"].stop() - pageEvents.remove(this.endButton, "click") + pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) pageEvents.keyRemove(this, 13) delete this.endButton } diff --git a/public/src/js/view.js b/public/src/js/view.js index c19af9e..99d37ae 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -64,16 +64,19 @@ class View{ pageEvents.add(this.canvas.canvas, "touchstart", this.ontouch.bind(this)) this.touchFullBtn = document.getElementById("touch-full-btn") - pageEvents.add(this.touchFullBtn, "click", toggleFullscreen) + pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen) + if(!fullScreenSupported){ + this.touchFullBtn.style.display = "none" + } this.touchPauseBtn = document.getElementById("touch-pause-btn") - pageEvents.add(this.touchPauseBtn, "click", () => { + pageEvents.add(this.touchPauseBtn, "touchend", () => { this.controller.togglePauseMenu() }) } } run(){ - this.ctx.font = "normal 14pt TnT" + this.ctx.font = "normal 14pt TnT, Meiryo, sans-serif" this.setBackground() if(this.controller.multiplayer !== 2){ @@ -318,7 +321,7 @@ class View{ var comboX = this.taikoX + this.taikoW / 2 var comboY = this.barY + this.barH / 2 var fontSize = this.taikoH * 0.4 - this.ctx.font = "normal " + fontSize + "px TnT" + this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif" this.ctx.textAlign = "center" this.ctx.strokeStyle = "#000" this.ctx.lineWidth = fontSize / 10 @@ -354,7 +357,7 @@ class View{ }else{ this.ctx.fillStyle = "#fff" } - this.ctx.font = "normal " + fontSize + "px TnT" + this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif" this.ctx.lineWidth = fontSize / 5 this.strokeFillText("コンボ", comboX, @@ -386,7 +389,7 @@ class View{ var fontSize = 0.7 * this.scoreSquareH // Draw score text - this.ctx.font = "normal " + fontSize + "px TnT" + this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif" this.ctx.fillStyle = "#fff" this.ctx.textAlign = "center" var glyph = this.ctx.measureText("0").width @@ -946,15 +949,15 @@ class View{ } clean(){ pageEvents.mouseRemove(this) - if(this.controller.multiplayer === 2){ + if(this.controller.multiplayer === 2 && this.canvas){ this.canvas.canvas.parentNode.removeChild(this.canvas.canvas) }else{ this.cursor.parentNode.removeChild(this.cursor) } if(this.touchEnabled){ pageEvents.remove(this.canvas.canvas, "touchstart") - pageEvents.remove(this.touchFullBtn, "click") - pageEvents.remove(this.touchPauseBtn, "click") + pageEvents.remove(this.touchFullBtn, "touchend") + pageEvents.remove(this.touchPauseBtn, "touchend") this.gameDiv.classList.remove("touch-visible") document.getElementById("version").classList.remove("version-hide") delete this.touchDrumDiv diff --git a/templates/index.html b/templates/index.html index ddb810d..d813baf 100644 --- a/templates/index.html +++ b/templates/index.html @@ -59,9 +59,9 @@
{% if version %} - taiko-web ver.{{version.version}} ({{version.commit_short}}) + taiko-web ver.{{version.version}} ({{version.commit_short}}) {% else %} - taiko-web (unknown version) + taiko-web (unknown version) {% endif %}