From cb64777012a916c22598793b6ad35af30d037493 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Thu, 4 Apr 2019 23:40:11 +0300 Subject: [PATCH 01/13] SongSelect: Add Settings - Resolution can be adjusted, as well as touch drum animation on mobile - A translation text file "songtitle.txt" can be imported - Titles and translated titles are each on their own line, if a line begins with a language code, it will translate the song title that is above - An example file can be found here: https://gist.github.com/LoveEevee/65fe66f0b54c0536f96fd2f4862984d4 - The page will fail to load if version on the page does not match /api/config - Disabled Tab key while playing, before hitting it would focus the version link - Fix forcing branches in debug not working - Fixed not being able to click on songs that do not have oni but have ura - Fix unexpected category being used as a fallback - Fix verticalText and layeredText not accepting anything except strings --- app.py | 3 +- public/assets/img/img.css | 15 --- public/src/css/main.css | 44 ++++++- public/src/css/songbg.css | 1 + public/src/js/assets.js | 10 +- public/src/js/canvascache.js | 3 + public/src/js/canvasdraw.js | 4 +- public/src/js/debug.js | 4 + public/src/js/game.js | 9 +- public/src/js/importsongs.js | 35 +++++- public/src/js/keyboard.js | 4 +- public/src/js/loader.js | 18 ++- public/src/js/loadsong.js | 77 +++++++----- public/src/js/main.js | 2 + public/src/js/settings.js | 210 +++++++++++++++++++++++++++++++++ public/src/js/songselect.js | 52 ++++++-- public/src/js/soundbuffer.js | 2 +- public/src/js/strings.js | 80 +++++++++++++ public/src/js/view.js | 33 ++++-- public/src/views/settings.html | 7 ++ 20 files changed, 527 insertions(+), 86 deletions(-) create mode 100644 public/src/js/settings.js create mode 100644 public/src/views/settings.html diff --git a/app.py b/app.py index 91f45b0..e03643d 100644 --- a/app.py +++ b/app.py @@ -111,7 +111,6 @@ def route_api_songs(): raw_categories = query_db('select * from categories') categories = {} - def_category = {'title': None, 'title_en': None} for cat in raw_categories: categories[cat[0]] = cat[1] @@ -126,7 +125,7 @@ def route_api_songs(): song_type = song[12] preview = song[15] - category_out = categories[song[11]] if song[11] in categories else def_category + category_out = categories[song[11]] if song[11] in categories else "" song_skin_out = song_skins[song[14]] if song[14] in song_skins else None songs_out.append({ diff --git a/public/assets/img/img.css b/public/assets/img/img.css index 7a9d682..9d4073a 100644 --- a/public/assets/img/img.css +++ b/public/assets/img/img.css @@ -10,24 +10,9 @@ #loading-don{ background-image: url("dancing-don.gif"); } -#touch-drum-img{ - background-image: url("touch_drum.png"); -} #touch-full-btn{ background-image: url("touch_fullscreen.png"); } #touch-pause-btn{ background-image: url("touch_pause.png"); } -.song-stage-1{ - background-image: url("bg_stage_1.png"); - background-size: calc(100vh / 720 * 66); -} -.song-stage-2{ - background-image: url("bg_stage_2.png"); - background-size: calc(100vh / 720 * 254); -} -.song-stage-3{ - background-image: url("bg_stage_3.png"); - background-size: calc(100vh / 720 * 458); -} diff --git a/public/src/css/main.css b/public/src/css/main.css index 2ec0cf7..c31abb0 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -92,7 +92,8 @@ kbd{ color: #000; } .taibtn:hover, -#tutorial-end-button:hover{ +#tutorial-end-button:hover, +#tutorial-end-button.selected{ position: relative; z-index: 1; color: #fff; @@ -147,6 +148,47 @@ kbd{ cursor: text; overflow: hidden; } +.setting-box{ + display: flex; + height: 2em; + margin-top: 1.2em; + border: 0.25em solid #000; + border-radius: 0.5em; + padding: 0.3em; + outline: none; + color: #000; + cursor: pointer; +} +.setting-box:first-child{ + margin-top: 0; +} +#tutorial-content:not(:hover) .setting-box.selected, +.setting-box:hover{ + background: #ffb547; + border-color: #21211a; +} +.setting-name{ + position: relative; + width: 50%; + padding: 0.3em; + font-size: 1.3em; + box-sizing: border-box; +} +#tutorial-content:not(:hover) .setting-box.selected .setting-name, +.setting-box:hover .setting-name{ + color: #fff; + z-index: 0; +} +.setting-name::before{ + padding-left: 0.3em; +} +.setting-value{ + background: #fff; + width: 50%; + border-radius: 0.2em; + padding: 0.5em; + box-sizing: border-box; +} @keyframes bgscroll{ from{ background-position: 0 top; diff --git a/public/src/css/songbg.css b/public/src/css/songbg.css index 9374f93..5f6f2ef 100644 --- a/public/src/css/songbg.css +++ b/public/src/css/songbg.css @@ -26,6 +26,7 @@ height: calc(44 / 720 * 100vh); background-position: center bottom; background-repeat-y: no-repeat; + background-size: auto 100%; bottom: 0; } .portrait #songbg{ diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 4f938a1..aaab4b5 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -27,7 +27,8 @@ var assets = { "debug.js", "session.js", "importsongs.js", - "logo.js" + "logo.js", + "settings.js" ], "css": [ "main.css", @@ -71,11 +72,7 @@ var assets = { "bg_score_p2.png", "bg_settings.png", "bg_pause.png", - "bg_stage_1.png", - "bg_stage_2.png", - "bg_stage_3.png", "badge_auto.png", - "touch_drum.png", "touch_pause.png", "touch_fullscreen.png", "mimizu.png", @@ -168,7 +165,8 @@ var assets = { "tutorial.html", "about.html", "debug.html", - "session.html" + "session.html", + "settings.html" ], "songs": [], diff --git a/public/src/js/canvascache.js b/public/src/js/canvascache.js index b8070a8..a731bcb 100644 --- a/public/src/js/canvascache.js +++ b/public/src/js/canvascache.js @@ -106,6 +106,9 @@ class CanvasCache{ this.ctx.clearRect(0, 0, this.w, this.h) } clean(){ + if(!this.canvas){ + return + } this.resize(1, 1, 1) delete this.map delete this.ctx diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 97d3afd..0e77fbb 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -277,7 +277,7 @@ verticalText(config){ var ctx = config.ctx - var inputText = config.text + var inputText = config.text.toString() var mul = config.fontSize / 40 var ura = false var r = this.regex @@ -601,7 +601,7 @@ layeredText(config, layers){ var ctx = config.ctx - var inputText = config.text + var inputText = config.text.toString() var mul = config.fontSize / 40 var ura = false var r = this.regex diff --git a/public/src/js/debug.js b/public/src/js/debug.js index beeede3..844e8d1 100644 --- a/public/src/js/debug.js +++ b/public/src/js/debug.js @@ -141,6 +141,7 @@ class Debug{ if(circles[i].endTime >= measureMS){ break } + game.skipNote(circles[i]) } if(game.mainMusicPlaying){ game.mainMusicPlaying = false @@ -215,6 +216,9 @@ class Debug{ var name = this.branchSelect.value game.branch = name === "auto" ? false : name game.branchSet = name === "auto" + if(noRestart){ + game.branchStatic = true + } var selectedOption = this.branchSelect.selectedOptions[0] this.branchSelect.style.background = selectedOption.style.background if(this.restartCheckbox.checked && !noRestart){ diff --git a/public/src/js/game.js b/public/src/js/game.js index 19609a4..3417209 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -150,10 +150,13 @@ class Game{ } } if(view.branch !== currentMeasure){ - view.branchAnimate = { - ms: ms, - fromBranch: view.branch + if(!this.branchStatic){ + view.branchAnimate = { + ms: ms, + fromBranch: view.branch + } } + this.branchStatic = false view.branch = currentMeasure } } diff --git a/public/src/js/importsongs.js b/public/src/js/importsongs.js index 93bd9ec..112b675 100644 --- a/public/src/js/importsongs.js +++ b/public/src/js/importsongs.js @@ -29,6 +29,8 @@ this.otherFiles = {} this.songs = [] this.stylesheet = [] + this.songTitle = {} + this.uraRegex = /\s*[\((]裏[\))]$/ this.courseTypes = { "easy": 0, "normal": 1, @@ -82,7 +84,7 @@ file: file, index: i }) - }else if(name === "genre.ini" || name === "box.def"){ + }else if(name === "genre.ini" || name === "box.def" || name === "songtitle.txt"){ var level = (file.webkitRelativePath.match(/\//g) || []).length metaFiles.push({ file: file, @@ -154,6 +156,20 @@ break } } + }else if(name === "songtitle.txt"){ + var lastTitle + for(var i = 0; i < data.length; i++){ + var line = data[i].trim() + if(line){ + var lang = line.slice(0, 2) + if(line.charAt(2) !== " " || !(lang in allStrings)){ + this.songTitle[line] = {} + lastTitle = line + }else if(lastTitle){ + this.songTitle[lastTitle][lang] = line.slice(3).trim() + } + } + } } if(category){ var metaPath = file.webkitRelativePath.toLowerCase().slice(0, file.name.length * -1) @@ -168,7 +184,11 @@ this.osuFiles.forEach(filesLoop) } }).catch(() => {}) - reader.readAsText(file, "sjis") + if(name === "songtitle.txt"){ + reader.readAsText(file) + }else{ + reader.readAsText(file, "sjis") + } return promise } @@ -212,8 +232,19 @@ songObj.song_skin = this.getSkin(dir, meta.taikowebskin) } for(var id in allStrings){ + var songTitle = songObj.title + var ura = "" + if(songTitle){ + var uraPos = songTitle.search(this.uraRegex) + if(uraPos !== -1){ + ura = songTitle.slice(uraPos) + songTitle = songTitle.slice(0, uraPos) + } + } if(meta["title" + id]){ titleLang[id] = meta["title" + id] + }else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){ + titleLang[id] = this.songTitle[songTitle][id] + ura } if(meta["subtitle" + id]){ subtitleLang[id] = meta["subtitle" + id] diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index cb9a2ac..0a5b32a 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -59,8 +59,8 @@ class Keyboard{ } pageEvents.keyAdd(this, "all", "both", event => { - if(event.keyCode === 8){ - // Disable back navigation when pressing backspace + if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ + // Escape, Backspace, Tab event.preventDefault() } var key = this.kbdSearch[event.keyCode] diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 47d1ecb..d7f45cd 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -38,7 +38,15 @@ class Loader{ document.head.appendChild(script) }) - this.addPromise(new Promise(resolve => { + this.addPromise(new Promise((resolve, reject) => { + if( + versionLink.href !== gameConfig._version.url && + gameConfig._version.commit && + versionLink.href.indexOf(gameConfig._version.commit) === -1 + ){ + // Version in the config does not match version on the page + reject() + } var cssCount = document.styleSheets.length + assets.css.length assets.css.forEach(name => { var stylesheet = document.createElement("link") @@ -195,6 +203,8 @@ class Loader{ p2.hash("") } + settings = new Settings() + Promise.all(this.promises).then(() => { this.canvasTest.drawAllImages().then(result => { perf.allImg = result @@ -212,7 +222,7 @@ class Loader{ } addPromise(promise){ this.promises.push(promise) - promise.then(this.assetLoaded.bind(this)) + promise.then(this.assetLoaded.bind(this), this.errorMsg.bind(this)) } loadSound(name, gain){ var id = this.getFilename(name) @@ -258,7 +268,9 @@ class Loader{ } clean(){ var fontDetectDiv = document.getElementById("fontdetectHelper") - fontDetectDiv.parentNode.removeChild(fontDetectDiv) + if(fontDetectDiv){ + fontDetectDiv.parentNode.removeChild(fontDetectDiv) + } delete this.loaderPercentage delete this.loaderProgress delete this.promises diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index 0c0b02f..d70b799 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -4,6 +4,15 @@ class LoadSong{ this.autoPlayEnabled = autoPlayEnabled this.multiplayer = multiplayer this.touchEnabled = touchEnabled + var resolution = settings.getItem("resolution") + this.imgScale = 1 + if(resolution === "medium"){ + this.imgScale = 0.75 + }else if(resolution === "low"){ + this.imgScale = 0.5 + }else if(resolution === "lowest"){ + this.imgScale = 0.25 + } loader.changePage("loadsong", true) var loadingText = document.getElementById("loading-text") @@ -57,9 +66,10 @@ class LoadSong{ } if(type === "don"){ song.donBg = null - } - if(type === "song"){ + }else if(type === "song"){ song.songBg = null + }else if(type === "stage"){ + song.songStage = null } } } @@ -71,19 +81,14 @@ class LoadSong{ continue } let img = document.createElement("img") - if(!songObj.music && this.touchEnabled && imgLoad[i].type === "song"){ + let force = imgLoad[i].type === "song" && this.touchEnabled + if(!songObj.music && (this.imgScale !== 1 || force)){ img.crossOrigin = "Anonymous" } let promise = pageEvents.load(img) - if(imgLoad[i].type === "song"){ - promises.push(promise.then(() => { - return this.scaleImg(img, filename, prefix) - })) - }else{ - promises.push(promise.then(() => { - assets.image[prefix + filename] = img - })) - } + promises.push(promise.then(() => { + return this.scaleImg(img, filename, prefix, force) + })) if(songObj.music){ img.src = URL.createObjectURL(song.songSkin[filename + ".png"]) }else{ @@ -126,6 +131,16 @@ class LoadSong{ this.songData = data.replace(/\0/g, "").split("\n") })) } + if(this.touchEnabled && !assets.image["touch_drum"]){ + let img = document.createElement("img") + if(this.imgScale !== 1){ + img.crossOrigin = "Anonymous" + } + promises.push(pageEvents.load(img).then(() => { + return this.scaleImg(img, "touch_drum", "") + })) + img.src = gameConfig.assets_baseurl + "img/touch_drum.png" + } Promise.all(promises).then(() => { this.setupMultiplayer() }, error => { @@ -151,23 +166,23 @@ class LoadSong{ filenames.push("bg_don2_" + this.selectedSong.donBg) } } + if(this.selectedSong.songStage !== null){ + filenames.push("bg_stage_" + this.selectedSong.songStage) + } for(var i = 0; i < filenames.length; i++){ - for(var letter = 0; letter < 2; letter++){ - let filenameAb = filenames[i] + (letter === 0 ? "a" : "b") + var filename = filenames[i] + var stage = filename.startsWith("bg_stage_") + for(var letter = 0; letter < (stage ? 1 : 2); letter++){ + let filenameAb = filenames[i] + (stage ? "" : (letter === 0 ? "a" : "b")) if(!(filenameAb in assets.image)){ let img = document.createElement("img") - if(filenameAb.startsWith("bg_song_")){ - if(this.touchEnabled){ - img.crossOrigin = "Anonymous" - } - promises.push(pageEvents.load(img).then(() => { - return this.scaleImg(img, filenameAb, "") - })) - }else{ - promises.push(pageEvents.load(img).then(() => { - assets.image[filenameAb] = img - })) + let force = filenameAb.startsWith("bg_song_") && this.touchEnabled + if(this.imgScale !== 1 || force){ + img.crossOrigin = "Anonymous" } + promises.push(pageEvents.load(img).then(() => { + return this.scaleImg(img, filenameAb, "", force) + })) img.src = gameConfig.assets_baseurl + "img/" + filenameAb + ".png" } } @@ -175,12 +190,16 @@ class LoadSong{ Promise.all(promises).then(resolve, reject) }) } - scaleImg(img, filename, prefix){ + scaleImg(img, filename, prefix, force){ return new Promise((resolve, reject) => { - if(this.touchEnabled){ + var scale = this.imgScale + if(force && scale > 0.5){ + scale = 0.5 + } + if(scale !== 1){ var canvas = document.createElement("canvas") - var w = Math.floor(img.width / 2) - var h = Math.floor(img.height / 2) + var w = Math.floor(img.width * scale) + var h = Math.floor(img.height * scale) canvas.width = w canvas.height = h var ctx = canvas.getContext("2d") diff --git a/public/src/js/main.js b/public/src/js/main.js index 1e632ca..e9067f1 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -82,6 +82,7 @@ var perf = { } var strings var vectors +var settings pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){ @@ -90,6 +91,7 @@ pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { }) var versionDiv = document.getElementById("version") var versionLink = document.getElementById("version-link") +versionLink.tabIndex = -1 pageEvents.add(versionDiv, ["click", "touchend"], event => { if(event.target === versionDiv){ versionLink.click() diff --git a/public/src/js/settings.js b/public/src/js/settings.js new file mode 100644 index 0000000..c09bebc --- /dev/null +++ b/public/src/js/settings.js @@ -0,0 +1,210 @@ +class Settings{ + constructor(){ + var ios = /iPhone|iPad/.test(navigator.userAgent) + var phone = /Android|iPhone|iPad/.test(navigator.userAgent) + + this.items = { + resolution: { + type: "select", + options: ["high", "medium", "low", "lowest"], + default: phone ? "medium" : "high" + }, + touchAnimation: { + type: "toggle", + default: !ios, + touch: true + } + } + + this.storage = {} + try{ + var storage = JSON.parse(localStorage.getItem("settings") || "{}") + for(var i in this.items){ + var current = this.items[i] + if(i in storage){ + if(current.type === "select" && current.options.indexOf(storage[i]) === -1){ + this.storage[i] = null + }else{ + this.storage[i] = storage[i] + } + }else{ + this.storage[i] = null + } + } + }catch(e){ + for(var i in this.items){ + this.storage[i] = null + } + } + } + getItem(name){ + var value = this.storage[name] + return value === null ? this.items[name].default : value + } + setItem(name, value){ + this.storage[name] = value + try{ + localStorage.setItem("settings", JSON.stringify(this.storage)) + }catch(e){} + } +} + +class SettingsView{ + constructor(touchEnabled){ + this.touchEnabled = touchEnabled + loader.changePage("settings", true) + this.endButton = document.getElementById("tutorial-end-button") + if(touchEnabled){ + document.getElementById("tutorial-outer").classList.add("touch-enabled") + } + + var tutorialTitle = document.getElementById("tutorial-title") + tutorialTitle.innerText = strings.gameSettings + tutorialTitle.setAttribute("alt", strings.gameSettings) + this.endButton.innerText = strings.settings.ok + this.endButton.setAttribute("alt", strings.settings.ok) + this.resolution = settings.getItem("resolution") + + var content = document.getElementById("tutorial-content") + this.items = [] + this.selected = 0 + for(let i in settings.items){ + if(!touchEnabled && settings.items[i].touch){ + continue + } + var settingBox = document.createElement("div") + settingBox.classList.add("setting-box") + var nameDiv = document.createElement("div") + nameDiv.classList.add("setting-name", "stroke-sub") + var name = strings.settings[i].name + nameDiv.innerText = name + nameDiv.setAttribute("alt", name) + settingBox.appendChild(nameDiv) + var valueDiv = document.createElement("div") + valueDiv.classList.add("setting-value") + valueDiv.innerText = this.getValue(i) + settingBox.appendChild(valueDiv) + content.appendChild(settingBox) + if(this.items.length === this.selected){ + settingBox.classList.add("selected") + } + pageEvents.add(settingBox, ["mousedown", "touchstart"], event => { + event.preventDefault() + this.setValue(i) + }) + this.items.push({ + id: i, + settingBox: settingBox, + valueDiv: valueDiv + }) + } + this.items.push({ + id: "back", + settingBox: this.endButton + }) + + this.kbd = { + "confirm": [13, 32, 70, 74], // Enter, Space, F, J + "previous": [37, 38, 68], // Left, Up, D + "next": [39, 40, 75], // Right, Down, K + "back": [8, 27] // Backspace, Esc + } + pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) + pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) + this.gamepad = new Gamepad({ + "confirm": ["b", "ls", "rs"], + "previous": ["u", "l", "lb", "lt", "lsu", "lsl"], + "next": ["d", "r", "rb", "rt", "lsd", "lsr"], + "back": ["start", "a"] + }, this.keyPressed.bind(this)) + + pageEvents.send("settings") + } + getValue(name){ + var current = settings.items[name] + var value = settings.getItem(name) + if(current.type === "select"){ + value = strings.settings[name][value] + }else if(current.type === "toggle"){ + value = value ? strings.settings.on : strings.settings.off + } + return value + } + setValue(name){ + var current = settings.items[name] + var value = settings.getItem(name) + if(current.type === "select"){ + value = current.options[this.mod(current.options.length, current.options.indexOf(value) + 1)] + }else if(current.type === "toggle"){ + value = !value + } + settings.setItem(name, value) + this.selected = this.items.findIndex(item => item.id === name) + this.items[this.selected].valueDiv.innerText = this.getValue(name) + } + keyEvent(event){ + if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ + // Escape, Backspace, Tab + event.preventDefault() + } + if(!event.repeat){ + for(var i in this.kbd){ + if(this.kbd[i].indexOf(event.keyCode) !== -1){ + this.keyPressed(true, i) + break + } + } + } + } + keyPressed(pressed, name){ + if(!pressed){ + return + } + var selected = this.items[this.selected] + if(name === "confirm"){ + if(selected.id === "back"){ + this.onEnd() + }else{ + this.setValue(selected.id) + } + }else if(name === "previous" || name === "next"){ + selected.settingBox.classList.remove("selected") + this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) + this.items[this.selected].settingBox.classList.add("selected") + }else if(name === "back"){ + this.onEnd() + } + } + onEnd(event){ + var touched = false + if(event && event.type === "touchstart"){ + event.preventDefault() + touched = true + } + this.clean() + assets.sounds["se_don"].play() + setTimeout(() => { + new SongSelect("settings", false, touched) + }, 500) + } + mod(length, index){ + return ((index % length) + length) % length + } + clean(){ + this.gamepad.clean() + pageEvents.keyRemove(this, "all") + for(var i in this.items){ + pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) + } + delete this.endButton + delete this.items + if(this.resolution !== settings.getItem("resolution")){ + for(var i in assets.image){ + if(i.startsWith("bg_song_") || i.startsWith("bg_stage_") || i.startsWith("bg_don_")){ + URL.revokeObjectURL(assets.image[i].src) + delete assets.image[i] + } + } + } + } +} diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index ed8d08b..530447e 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -25,21 +25,27 @@ class SongSelect{ }, "tutorial": { sort: 7, - background: "#9afbe1", - border: ["#d6ffff", "#6bae9c"], - outline: "#31ae94" + background: "#29e8aa", + border: ["#86ffbd", "#009a8c"], + outline: "#08a28c" }, "about": { sort: 7, - background: "#91cfff", - border: ["#dff0ff", "#6890b2"], - outline: "#217abb" + background: "#a2d0e7", + border: ["#c6dfff", "#4485d9"], + outline: "#2390d9" + }, + "settings": { + sort: 7, + background: "#ce93fa", + border: ["#dec4fd", "#a543ef"], + outline: "#a741ef" }, "browse": { sort: 7, - background: "#9791ff", - border: ["#e2dfff", "#6d68b2"], - outline: "#5350ba" + background: "#fab5d3", + border: ["#ffe7ef", "#d36aa2"], + outline: "#d36aa2" }, "J-POP": { sort: 0, @@ -149,6 +155,12 @@ class SongSelect{ action: "about", category: strings.random }) + this.songs.push({ + title: strings.gameSettings, + skin: this.songSkin.settings, + action: "settings", + category: strings.random + }) if("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))){ this.browse = document.getElementById("browse") pageEvents.add(this.browse, "change", this.browseChange.bind(this)) @@ -352,7 +364,8 @@ class SongSelect{ down: code == 40 // Down } - if(event && (code == 27 || code == 8)){ + if(event && (code == 27 || code == 8 || code == 9)){ + // Escape, Backspace, Tab event.preventDefault() } if(this.state.screen === "song"){ @@ -523,7 +536,7 @@ class SongSelect{ }else if(550 < x && x < 1050 && 95 < y && y < 524){ var moveBy = Math.floor((x - 550) / ((1050 - 550) / 5)) + this.diffOptions.length var currentSong = this.songs[this.selectedSong] - if(this.state.ura && moveBy === this.diffOptions + 3 || currentSong.stars[moveBy - this.diffOptions.length]){ + if(this.state.ura && moveBy === this.diffOptions.length + 3 || currentSong.stars[moveBy - this.diffOptions.length]){ return moveBy } } @@ -624,6 +637,8 @@ class SongSelect{ this.toTutorial() }else if(currentSong.action === "about"){ this.toAbout() + }else if(currentSong.action === "settings"){ + this.toSettings() }else if(currentSong.action === "browse"){ this.toBrowse() } @@ -722,6 +737,13 @@ class SongSelect{ new About(this.touchEnabled) }, 500) } + toSettings(){ + assets.sounds["se_don"].play() + this.clean() + setTimeout(() => { + new SettingsView(this.touchEnabled) + }, 500) + } toSession(){ if(p2.socket.readyState !== 1 || assets.customSongs){ return @@ -790,6 +812,14 @@ class SongSelect{ winW = winH / 9 * 32 } this.pixelRatio = window.devicePixelRatio || 1 + var resolution = settings.getItem("resolution") + if(resolution === "medium"){ + this.pixelRatio *= 0.75 + }else if(resolution === "low"){ + this.pixelRatio *= 0.5 + }else if(resolution === "lowest"){ + this.pixelRatio *= 0.25 + } winW *= this.pixelRatio winH *= this.pixelRatio var ratioX = winW / 1280 diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index cd179f5..3e6f45e 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -101,7 +101,7 @@ class SoundGain{ this.volume = amount } setVolumeMul(amount){ - this.setVolume(Math.sqrt(amount * amount * this.defaultVol)) + this.setVolume(amount * this.defaultVol) } setCrossfade(amount){ this.setVolume(Math.sqrt(Math.sin(Math.PI / 2 * amount))) diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 16ddaa8..8176d1e 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -24,6 +24,7 @@ this.randomSong = "ランダムに曲をえらぶ" this.howToPlay = "あそびかた説明" this.aboutSimulator = "このシミュレータについて" + this.gameSettings = "ゲーム設定" this.browse = "参照する…" this.defaultSongList = "デフォルト曲リスト" this.songOptions = "演奏オプション" @@ -98,6 +99,21 @@ linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", cancel: "キャンセル" } + this.settings = { + resolution: { + name: "ゲームの解像度", + high: "高", + medium: "中", + low: "低", + lowest: "最低" + }, + touchAnimation: { + name: "タッチアニメーション" + }, + on: "オン", + off: "オフ", + ok: "OK" + } this.browserSupport = { browserWarning: "サポートされていないブラウザを実行しています (%s)", details: "詳しく", @@ -131,6 +147,7 @@ function StringsEn(){ this.randomSong = "Random Song" this.howToPlay = "How to Play" this.aboutSimulator = "About Simulator" + this.gameSettings = "Game Settings" this.browse = "Browse…" this.defaultSongList = "Default Song List" this.songOptions = "Song Options" @@ -205,6 +222,21 @@ function StringsEn(){ linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", cancel: "Cancel" } + this.settings = { + resolution: { + name: "Game Resolution", + high: "High", + medium: "Medium", + low: "Low", + lowest: "Lowest" + }, + touchAnimation: { + name: "Touch Animation" + }, + on: "On", + off: "Off", + ok: "OK" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -238,6 +270,7 @@ function StringsCn(){ this.randomSong = "随机选曲" this.howToPlay = "操作说明" this.aboutSimulator = "关于模拟器" + this.gameSettings = "游戏设定" this.browse = "浏览…" this.defaultSongList = "默认歌曲列表" this.songOptions = "选项" @@ -312,6 +345,21 @@ function StringsCn(){ linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", cancel: "取消" } + this.settings = { + resolution: { + name: "游戏分辨率", + high: "高", + medium: "中", + low: "低", + lowest: "最低" + }, + touchAnimation: { + name: "触摸动画" + }, + on: "开", + off: "关", + ok: "确定" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -345,6 +393,7 @@ function StringsTw(){ this.randomSong = "隨機選曲" this.howToPlay = "操作說明" this.aboutSimulator = "關於模擬器" + this.gameSettings = "遊戲設定" this.browse = "開啟檔案…" this.defaultSongList = "默認歌曲列表" this.songOptions = "選項" @@ -419,6 +468,21 @@ function StringsTw(){ linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", cancel: "取消" } + this.settings = { + resolution: { + name: "遊戲分辨率", + high: "高", + medium: "中", + low: "低", + lowest: "最低" + }, + touchAnimation: { + name: "觸摸動畫" + }, + on: "開", + off: "關", + ok: "確定" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", @@ -452,6 +516,7 @@ function StringsKo(){ this.randomSong = "랜덤" this.howToPlay = "지도 시간" this.aboutSimulator = "게임 정보" + this.gameSettings = "게임 설정" this.browse = "찾아보기…" this.defaultSongList = "기본 노래 목록" this.songOptions = "옵션" @@ -526,6 +591,21 @@ function StringsKo(){ linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", cancel: "취소" } + this.settings = { + resolution: { + name: "게임 해상도", + high: "높은", + medium: "중간", + low: "저", + lowest: "최저" + }, + touchAnimation: { + name: "터치 애니메이션" + }, + on: "온", + off: "오프", + ok: "확인" + } this.browserSupport = { browserWarning: "You are running an unsupported browser (%s)", details: "Details...", diff --git a/public/src/js/view.js b/public/src/js/view.js index b81cd29..f045b09 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -118,6 +118,7 @@ this.touchEnabled = this.controller.touchEnabled this.touch = -Infinity + this.touchAnimation = settings.getItem("touchAnimation") if(this.multiplayer !== 2){ @@ -125,6 +126,8 @@ this.touchDrumDiv = document.getElementById("touch-drum") this.touchDrumImg = document.getElementById("touch-drum-img") + this.setBgImage(this.touchDrumImg, assets.image["touch_drum"].src) + if(this.controller.autoPlayEnabled){ this.touchDrumDiv.style.display = "none" } @@ -180,6 +183,14 @@ var touchMultiplayer = this.touchEnabled && this.multiplayer && !this.portrait this.pixelRatio = window.devicePixelRatio || 1 + var resolution = settings.getItem("resolution") + if(resolution === "medium"){ + this.pixelRatio *= 0.75 + }else if(resolution === "low"){ + this.pixelRatio *= 0.5 + }else if(resolution === "lowest"){ + this.pixelRatio *= 0.25 + } winW *= this.pixelRatio winH *= this.pixelRatio if(this.portrait){ @@ -1123,6 +1134,7 @@ if(!selectedSong.songSkin.stage){ this.songStage.classList.add("song-stage-" + selectedSong.songStage) + this.setBgImage(this.songStage, assets.image["bg_stage_" + selectedSong.songStage].src) }else if(selectedSong.songSkin.stage !== "none"){ var prefix = selectedSong.songSkin.prefix || "" this.setBgImage(this.songStage, assets.image[prefix + "bg_stage_" + songSkinName].src) @@ -1180,9 +1192,10 @@ } setDonBgHeight(){ this.donBg.style.setProperty("--h", getComputedStyle(this.donBg).height) - this.gameDiv.classList.add("fix-animations") + var gameDiv = this.gameDiv + gameDiv.classList.add("fix-animations") setTimeout(()=>{ - this.gameDiv.classList.remove("fix-animations") + gameDiv.classList.remove("fix-animations") }, 50) } setLayers(elements, file, ab){ @@ -1700,14 +1713,16 @@ this.touchDrumDiv.style.width = drumWidth + "px" this.touchDrumDiv.style.height = drumHeight + "px" } - if(this.touch > ms - 100){ - if(!this.drumPadding){ - this.drumPadding = true - this.touchDrumImg.style.backgroundPositionY = "7px" + if(this.touchAnimation){ + if(this.touch > ms - 100){ + if(!this.drumPadding){ + this.drumPadding = true + this.touchDrumImg.style.backgroundPositionY = "7px" + } + }else if(this.drumPadding){ + this.drumPadding = false + this.touchDrumImg.style.backgroundPositionY = "" } - }else if(this.drumPadding){ - this.drumPadding = false - this.touchDrumImg.style.backgroundPositionY = "" } } } diff --git a/public/src/views/settings.html b/public/src/views/settings.html new file mode 100644 index 0000000..983c90e --- /dev/null +++ b/public/src/views/settings.html @@ -0,0 +1,7 @@ +
+
+
+
+
+
+
From 78528b424c86c75cf1d20dbf6973b09344f8124c Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Fri, 5 Apr 2019 00:21:08 +0300 Subject: [PATCH 02/13] Fix results screen, clear drum asset --- public/src/js/scoresheet.js | 8 ++++++++ public/src/js/settings.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 037e7e4..9ea0240 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -193,6 +193,14 @@ class Scoresheet{ var winW = innerWidth var winH = lastHeight this.pixelRatio = window.devicePixelRatio || 1 + var resolution = settings.getItem("resolution") + if(resolution === "medium"){ + this.pixelRatio *= 0.75 + }else if(resolution === "low"){ + this.pixelRatio *= 0.5 + }else if(resolution === "lowest"){ + this.pixelRatio *= 0.25 + } winW *= this.pixelRatio winH *= this.pixelRatio var ratioX = winW / 1280 diff --git a/public/src/js/settings.js b/public/src/js/settings.js index c09bebc..b4e477e 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -200,7 +200,7 @@ class SettingsView{ delete this.items if(this.resolution !== settings.getItem("resolution")){ for(var i in assets.image){ - if(i.startsWith("bg_song_") || i.startsWith("bg_stage_") || i.startsWith("bg_don_")){ + if(i === "touch_drum" || i.startsWith("bg_song_") || i.startsWith("bg_stage_") || i.startsWith("bg_don_")){ URL.revokeObjectURL(assets.image[i].src) delete assets.image[i] } From 3f533a02555a4763adcdd03b5e4eb019d4851594 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Fri, 5 Apr 2019 12:36:14 +0300 Subject: [PATCH 03/13] Add background music --- public/assets/audio/bgm_settings.mp3 | Bin 0 -> 120017 bytes public/src/js/assets.js | 3 ++- public/src/js/settings.js | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 public/assets/audio/bgm_settings.mp3 diff --git a/public/assets/audio/bgm_settings.mp3 b/public/assets/audio/bgm_settings.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..e09d4922e742e09bd6aeb9cd2f219a6acd4b4dea GIT binary patch literal 120017 zcmeI$e`J+m0EXdjSxn3(k%(4C5wlq(5|tupDw>K&nq?vqNtB70#FB_4QlcUjQ4vv; zjFgdNDG^DGL`>G%A5UZJY$cB5nsN5a-tFCUF1L*gpYAB8c-h{ye{bna>WZTJSWz|b zyqGqK7cv**rVxOnOE)oV9y_T9RD=idDX4<9{#+W+juz{^*!-@JSO;p3;z zLtnmr8~$E8Z}Z00ZR=W_TAG`y@8&05+R#}2q^+oWJNk2+YijAsC;r>Vk>UD|qHd@t zx=O!dO;OY~6h&3(^-Ag8(wj@VOMjK07u8^jNR_L70 z3Z2tap>wWR=$!rvoio@w`L4%?RpzbV+?#X8-Jg5=rK96+Y2v%?&ApAT!Vc`f4$AiE zL^#KN#Pi4V$MeVYCoJ%Q2Rz^b4<`LTU#_R@BS$&PQH}-(9`Jw%Jm7(@$_9AAgKR+` z=mQ?`fCu^@8{h#CvITvh4|u=>9_WK?fCoIt7W9EW-~kVKpbxSE9`GPr&3OAY0G}`hW*K;DJ8K26(`OY(XFB10L{z2l^lz-~kV^1%03oc)$Z5=!0y4 z2Rz6Y^npI$0S|bf53&Is@E}{z2l{{qJm7&o$Od@8gKR+`=mQ?`fCu^@8{h#CvITvh z4|u=>9_WK?fCoIt7W9EW-~kVKpbxSE9`GPr&3OAY0G}`hW*K z;DJ8K26(`OY(XFB10L{z2l^lz-~kV^1%03oc)$Z5=!0y42Rz6Y^npI$0S|bf53&Is z@E}{z2l{{qJm7&o$Od@8gKR+`=mQ?`fCu^@8{h#CvITvh4|u=>9_WK?fCoIt7W9EW z-~kVKpbxSE9`GPr&3OAY0G}`hW*K;DJ8K26(`OY(XFB10L{z z2l^lz-~kV^1%03oc)$Z5=!0y42Rz6Y^npI$0S|bf53&Is@E}{z2l{{qJm7&o$Od@8 zgKR+`=mQ?`fCu^@8{h#CvITvh4|u=>9_WK?fCoIt7W9EW-~kVKpbxSE9`GPr& item.id === name) this.items[this.selected].valueDiv.innerText = this.getValue(name) + assets.sounds["se_ka"].play() } keyEvent(event){ if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ @@ -171,6 +174,7 @@ class SettingsView{ selected.settingBox.classList.remove("selected") this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) this.items[this.selected].settingBox.classList.add("selected") + assets.sounds["se_ka"].play() }else if(name === "back"){ this.onEnd() } @@ -192,6 +196,7 @@ class SettingsView{ } clean(){ this.gamepad.clean() + assets.sounds["bgm_settings"].stop() pageEvents.keyRemove(this, "all") for(var i in this.items){ pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) From 879186c313dd313b5f8f7577c5cd8c4355f00b24 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Fri, 5 Apr 2019 22:53:51 +0300 Subject: [PATCH 04/13] Add keyboard and gamepad settings --- public/assets/img/img.css | 3 + public/src/css/main.css | 29 ++++- public/src/js/about.js | 74 +++++++++++-- public/src/js/keyboard.js | 50 ++++++--- public/src/js/loader.js | 1 + public/src/js/pageevents.js | 12 +- public/src/js/scoresheet.js | 27 +++-- public/src/js/session.js | 3 + public/src/js/settings.js | 194 +++++++++++++++++++++++++++------ public/src/js/songselect.js | 83 +++++++------- public/src/js/strings.js | 65 +++++++++++ public/src/js/titlescreen.js | 26 +++-- public/src/js/tutorial.js | 30 +++-- public/src/views/about.html | 2 +- public/src/views/settings.html | 2 +- public/src/views/tutorial.html | 2 +- 16 files changed, 468 insertions(+), 135 deletions(-) diff --git a/public/assets/img/img.css b/public/assets/img/img.css index 9d4073a..7d339c6 100644 --- a/public/assets/img/img.css +++ b/public/assets/img/img.css @@ -16,3 +16,6 @@ #touch-pause-btn{ background-image: url("touch_pause.png"); } +.settings-outer{ + background-image: url("bg_settings.png"); +} diff --git a/public/src/css/main.css b/public/src/css/main.css index c31abb0..9b44bb3 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -92,6 +92,7 @@ kbd{ color: #000; } .taibtn:hover, +.taibtn.selected, #tutorial-end-button:hover, #tutorial-end-button.selected{ position: relative; @@ -148,6 +149,19 @@ kbd{ cursor: text; overflow: hidden; } +@keyframes border-pulse{ + 0%{border-color: #ff0} + 50%{border-color: rgba(255, 255, 0, 0)} + 100%{border-color: #ff0} +} +@keyframes border-pulse2{ + 0%{border-color: #e29e06} + 50%{border-color: rgba(226, 158, 6, 0)} + 100%{border-color: #e29e06} +} +.settings-outer{ + background-size: 50vh; +} .setting-box{ display: flex; height: 2em; @@ -165,7 +179,7 @@ kbd{ #tutorial-content:not(:hover) .setting-box.selected, .setting-box:hover{ background: #ffb547; - border-color: #21211a; + animation: 2s linear border-pulse infinite; } .setting-name{ position: relative; @@ -183,12 +197,25 @@ kbd{ padding-left: 0.3em; } .setting-value{ + display: flex; background: #fff; width: 50%; border-radius: 0.2em; padding: 0.5em; box-sizing: border-box; } +.setting-value.selected{ + width: calc(50% + 0.2em); + margin: -0.1em; + border: 0.2em solid #e29e06; + padding: 0.4em; + animation: 2s linear border-pulse2 infinite; +} +.setting-value>div{ + padding: 0 0.4em; + overflow: hidden; + text-overflow: ellipsis; +} @keyframes bgscroll{ from{ background-position: 0 top; diff --git a/public/src/js/about.js b/public/src/js/about.js index d01c66d..95575b7 100644 --- a/public/src/js/about.js +++ b/public/src/js/about.js @@ -32,22 +32,77 @@ var versionUrl = gameConfig._version.url this.getLink(this.linkIssues).href = versionUrl + "issues" + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = { + confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], + previous: ["arrowleft", "arrowup", kbdSettings.ka_l[0]], + next: ["arrowright", "arrowdown", kbdSettings.ka_r[0]], + back: ["backspace", "escape"] + } pageEvents.add(this.linkIssues, ["click", "touchend"], this.linkButton.bind(this)) pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this)) - pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) - pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this)) + pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) + pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) + this.items = [this.linkIssues, this.linkEmail, this.endButton] + this.selected = 2 this.gamepad = new Gamepad({ - "confirm": ["start", "b", "ls", "rs"] - }, this.onEnd.bind(this)) + "confirm": ["b", "ls", "rs"], + "previous": ["u", "l", "lb", "lt", "lsu", "lsl"], + "next": ["d", "r", "rb", "rt", "lsd", "lsr"], + "back": ["start", "a"] + }, this.keyPressed.bind(this)) pageEvents.send("about", this.addDiag()) } + keyEvent(event){ + if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ + // Escape, Backspace, Tab + event.preventDefault() + } + if(!event.repeat){ + for(var i in this.kbd){ + if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ + this.keyPressed(true, i) + break + } + } + } + } + keyPressed(pressed, name){ + if(!pressed){ + return + } + var selected = this.items[this.selected] + if(name === "confirm"){ + if(selected === this.endButton){ + this.onEnd() + }else{ + this.getLink(selected).click() + pageEvents.send("about-link", selected) + assets.sounds["se_don"].play() + } + }else if(name === "previous" || name === "next"){ + selected.classList.remove("selected") + this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) + this.items[this.selected].classList.add("selected") + assets.sounds["se_ka"].play() + }else if(name === "back"){ + this.onEnd() + } + } + mod(length, index){ + return ((index % length) + length) % length + } onEnd(event){ var touched = false - if(event && event.type === "touchstart"){ - event.preventDefault() - touched = true + if(event){ + if(event.type === "touchstart"){ + event.preventDefault() + touched = true + }else if(event.which !== 1){ + return + } } this.clean() assets.sounds["se_don"].play() @@ -154,7 +209,8 @@ linkButton(event){ if(event.target === event.currentTarget){ this.getLink(event.currentTarget).click() - pageEvents.send("about-link", event) + pageEvents.send("about-link", event.currentTarget) + assets.sounds["se_don"].play() } } clean(){ @@ -166,7 +222,7 @@ if(this.textarea){ pageEvents.remove(this.textarea, ["focus", "blur"]) } - pageEvents.keyRemove(this, 13) + pageEvents.keyRemove(this, "all") delete this.endButton delete this.diagTxt delete this.version diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index 0a5b32a..2960a97 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -3,22 +3,23 @@ class Keyboard{ this.controller = controller this.game = this.controller.game + var kbdSettings = settings.getItem("keyboardSettings") this.kbd = { - "don_l": 70, // F - "don_r": 74, // J - "ka_l": 68, // D - "ka_r": 75, // K - "pause": 81, // Q - "back": 8, // Backspace - "previous": 37, // Left - "next": 39, // Right - "confirm": 13 // Enter + "ka_l": kbdSettings.ka_l[0], + "don_l": kbdSettings.don_l[0], + "don_r": kbdSettings.don_r[0], + "ka_r": kbdSettings.ka_r[0], + "pause": "q", + "back": "backspace", + "previous": "arrowleft", + "next": "arrowright", + "confirm": "enter" } this.kbdAlias = { - "pause": [27], // Esc - "previous": [38], // Up - "next": [40], // Down - "confirm": [32] // Space + "pause": ["escape"], + "previous": ["arrowup"], + "next": ["arrowdown"], + "confirm": [" "] } this.keys = {} this.waitKeyupScore = {} @@ -30,11 +31,24 @@ class Keyboard{ } this.keyboardEvents = 0 + var layout = settings.getItem("gamepadLayout") var gameBtn = {} - gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] - gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] - gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] - gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] + if(layout === "b"){ + gameBtn[this.kbd["don_l"]] = ["d", "r", "ls"] + gameBtn[this.kbd["don_r"]] = ["a", "x", "rs"] + gameBtn[this.kbd["ka_l"]] = ["u", "l", "lb", "lt"] + gameBtn[this.kbd["ka_r"]] = ["b", "y", "rb", "rt"] + }else if(layout === "c"){ + gameBtn[this.kbd["don_l"]] = ["d", "l", "ls"] + gameBtn[this.kbd["don_r"]] = ["a", "b", "rs"] + gameBtn[this.kbd["ka_l"]] = ["u", "r", "lb", "lt"] + gameBtn[this.kbd["ka_r"]] = ["x", "y", "rb", "rt"] + }else{ + gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] + gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] + gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] + gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] + } this.gamepad = new Gamepad(gameBtn) this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2) @@ -63,7 +77,7 @@ class Keyboard{ // Escape, Backspace, Tab event.preventDefault() } - var key = this.kbdSearch[event.keyCode] + var key = this.kbdSearch[event.key.toLowerCase()] if(key && !event.repeat && this.buttonEnabled(key)){ var ms = this.game.getAccurateTime() this.setKey(key, event.type === "keydown", ms) diff --git a/public/src/js/loader.js b/public/src/js/loader.js index d7f45cd..a3ba450 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -204,6 +204,7 @@ class Loader{ } settings = new Settings() + pageEvents.setKbd() Promise.all(this.promises).then(() => { this.canvasTest.drawAllImages().then(result => { diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index 7ba8d68..a1bba1d 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -7,6 +7,7 @@ class PageEvents{ this.add(window, "keydown", this.keyEvent.bind(this)) this.add(window, "keyup", this.keyEvent.bind(this)) this.add(window, "mousemove", this.mouseEvent.bind(this)) + this.kbd = [] } add(target, type, callback){ if(Array.isArray(type)){ @@ -81,7 +82,7 @@ class PageEvents{ }) } keyEvent(event){ - if ([68, 70, 74, 75].indexOf(event.keyCode) > -1) { // D, F, J, K + if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){ this.lastKeyEvent = Date.now() } this.keyListeners.forEach(addedKeyCode => { @@ -146,4 +147,13 @@ class PageEvents{ send(name, detail){ dispatchEvent(new CustomEvent(name, {detail: detail})) } + setKbd(){ + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = [ + kbdSettings.ka_l[0], + kbdSettings.don_l[0], + kbdSettings.don_r[0], + kbdSettings.ka_r[0] + ] + } } diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 9ea0240..4d0360c 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -31,8 +31,12 @@ class Scoresheet{ this.draw = new CanvasDraw() this.canvasCache = new CanvasCache() + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = { + confirm: ["enter", " ", "escape", "backspace", kbdSettings.don_l[0], kbdSettings.don_r[0]] + } this.gamepad = new Gamepad({ - "13": ["a", "b", "start", "ls", "rs"] + confirm: ["a", "b", "start", "ls", "rs"] }) this.difficulty = { @@ -72,23 +76,22 @@ class Scoresheet{ touchEvents: controller.view.touchEvents }) } - keyDown(event, code){ - if(!code){ + keyDown(event, key){ + if(!key){ if(event.repeat){ return } - code = event.keyCode + for(var i in this.kbd){ + if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ + key = i + break + } + } } - var key = { - confirm: code == 13 || code == 32 || code == 70 || code == 74, - // Enter, Space, F, J - cancel: code == 27 || code == 8 - // Esc, Backspace - } - if(key.cancel && event){ + if(event && event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ event.preventDefault() } - if(key.confirm || key.cancel){ + if(key === "confirm"){ this.toNext() } } diff --git a/public/src/js/session.js b/public/src/js/session.js index 8dfe8e6..43efa9e 100644 --- a/public/src/js/session.js +++ b/public/src/js/session.js @@ -37,6 +37,9 @@ class Session{ pageEvents.send("session") } mouseDown(event){ + if(event.type === "mousedown" && event.which !== 1){ + return + } if(event.target === this.sessionInvite){ this.sessionInvite.focus() }else{ diff --git a/public/src/js/settings.js b/public/src/js/settings.js index 1f83c01..97b8a41 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -13,6 +13,22 @@ class Settings{ type: "toggle", default: !ios, touch: true + }, + keyboardSettings: { + type: "keyboard", + default: { + ka_l: ["d"], + don_l: ["f"], + don_r: ["j"], + ka_r: ["k"] + }, + touch: false + }, + gamepadLayout: { + type: "select", + options: ["a", "b", "c"], + default: "a", + gamepad: true } } @@ -24,6 +40,17 @@ class Settings{ if(i in storage){ if(current.type === "select" && current.options.indexOf(storage[i]) === -1){ this.storage[i] = null + }else if(current.type === "keyboard"){ + var obj = {} + for(var j in current.default){ + if(storage[i][j] && storage[i][j][0]){ + obj[j] = storage[i][j] + }else{ + obj = null + break + } + } + this.storage[i] = obj }else{ this.storage[i] = storage[i] } @@ -52,13 +79,24 @@ class Settings{ class SettingsView{ constructor(touchEnabled){ this.touchEnabled = touchEnabled - loader.changePage("settings", true) + loader.changePage("settings", false) assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) this.endButton = document.getElementById("tutorial-end-button") if(touchEnabled){ document.getElementById("tutorial-outer").classList.add("touch-enabled") } + var gamepadEnabled = false + if("getGamepads" in navigator){ + var gamepads = navigator.getGamepads() + for(var i = 0; i < gamepads.length; i++){ + if(gamepads[i]){ + gamepadEnabled = true + break + } + } + } + this.mode = "settings" var tutorialTitle = document.getElementById("tutorial-title") tutorialTitle.innerText = strings.gameSettings @@ -71,7 +109,12 @@ class SettingsView{ this.items = [] this.selected = 0 for(let i in settings.items){ - if(!touchEnabled && settings.items[i].touch){ + var current = settings.items[i] + if( + !touchEnabled && current.touch === true || + touchEnabled && current.touch === false || + !gamepadEnabled && current.gamepad === true + ){ continue } var settingBox = document.createElement("div") @@ -84,15 +127,17 @@ class SettingsView{ settingBox.appendChild(nameDiv) var valueDiv = document.createElement("div") valueDiv.classList.add("setting-value") - valueDiv.innerText = this.getValue(i) + this.getValue(i, valueDiv) settingBox.appendChild(valueDiv) content.appendChild(settingBox) if(this.items.length === this.selected){ settingBox.classList.add("selected") } pageEvents.add(settingBox, ["mousedown", "touchstart"], event => { - event.preventDefault() - this.setValue(i) + if(event.which === 1){ + event.preventDefault() + this.setValue(i) + } }) this.items.push({ id: i, @@ -105,13 +150,8 @@ class SettingsView{ settingBox: this.endButton }) - this.kbd = { - "confirm": [13, 32, 70, 74], // Enter, Space, F, J - "previous": [37, 38, 68], // Left, Up, D - "next": [39, 40, 75], // Right, Down, K - "back": [8, 27] // Backspace, Esc - } - pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) + this.setKbd() + pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) this.gamepad = new Gamepad({ "confirm": ["b", "ls", "rs"], @@ -122,27 +162,65 @@ class SettingsView{ pageEvents.send("settings") } - getValue(name){ + setKbd(){ + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = { + "confirm": ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], + "previous": ["arrowleft", "arrowup", kbdSettings.ka_l[0]], + "next": ["arrowright", "arrowdown", kbdSettings.ka_r[0]], + "back": ["backspace", "escape"] + } + } + getValue(name, valueDiv){ var current = settings.items[name] var value = settings.getItem(name) if(current.type === "select"){ value = strings.settings[name][value] }else if(current.type === "toggle"){ value = value ? strings.settings.on : strings.settings.off + }else if(current.type === "keyboard"){ + valueDiv.innerHTML = "" + for(var i in value){ + var key = document.createElement("div") + key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" + key.innerText = value[i][0].toUpperCase() + valueDiv.appendChild(key) + } + return } - return value + valueDiv.innerText = value } setValue(name){ var current = settings.items[name] var value = settings.getItem(name) + var selectedIndex = this.items.findIndex(item => item.id === name) + var selected = this.items[selectedIndex] + if(this.mode !== "settings"){ + if(this.selected === selectedIndex){ + this.keyboardBack(selected) + } + return + } + if(this.selected !== selectedIndex){ + this.items[this.selected].settingBox.classList.remove("selected") + this.selected = selectedIndex + selected.settingBox.classList.add("selected") + } if(current.type === "select"){ value = current.options[this.mod(current.options.length, current.options.indexOf(value) + 1)] }else if(current.type === "toggle"){ value = !value + }else if(current.type === "keyboard"){ + this.mode = "keyboard" + selected.settingBox.style.animation = "none" + selected.valueDiv.classList.add("selected") + this.keyboardKeys = {} + this.keyboardSet() + assets.sounds["se_don"].play() + return } settings.setItem(name, value) - this.selected = this.items.findIndex(item => item.id === name) - this.items[this.selected].valueDiv.innerText = this.getValue(name) + this.getValue(name, this.items[this.selected].valueDiv) assets.sounds["se_ka"].play() } keyEvent(event){ @@ -152,11 +230,23 @@ class SettingsView{ } if(!event.repeat){ for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.keyCode) !== -1){ - this.keyPressed(true, i) - break + if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ + if(this.mode !== "keyboard" || i === "back"){ + this.keyPressed(true, i) + return + } } } + if(this.mode === "keyboard"){ + var currentKey = event.key.toLowerCase() + for(var i in this.keyboardKeys){ + if(this.keyboardKeys[i][0] === currentKey || !currentKey){ + return + } + } + this.keyboardKeys[this.keyboardCurrent] = [currentKey] + this.keyboardSet() + } } } keyPressed(pressed, name){ @@ -164,26 +254,64 @@ class SettingsView{ return } var selected = this.items[this.selected] - if(name === "confirm"){ - if(selected.id === "back"){ + if(this.mode === "settings"){ + if(name === "confirm"){ + if(selected.id === "back"){ + this.onEnd() + }else{ + this.setValue(selected.id) + } + }else if(name === "previous" || name === "next"){ + selected.settingBox.classList.remove("selected") + this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) + this.items[this.selected].settingBox.classList.add("selected") + assets.sounds["se_ka"].play() + }else if(name === "back"){ this.onEnd() - }else{ - this.setValue(selected.id) } - }else if(name === "previous" || name === "next"){ - selected.settingBox.classList.remove("selected") - this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) - this.items[this.selected].settingBox.classList.add("selected") - assets.sounds["se_ka"].play() - }else if(name === "back"){ - this.onEnd() + }else if(this.mode === "keyboard"){ + if(name === "back"){ + this.keyboardBack(selected) + } } } + keyboardSet(){ + var selected = this.items[this.selected] + var current = settings.items[selected.id] + selected.valueDiv.innerHTML = "" + for(var i in current.default){ + var key = document.createElement("div") + key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" + if(this.keyboardKeys[i]){ + key.innerText = this.keyboardKeys[i][0].toUpperCase() + selected.valueDiv.appendChild(key) + }else{ + key.innerText = "[" + strings.settings[selected.id][i] + "]" + selected.valueDiv.appendChild(key) + this.keyboardCurrent = i + return + } + } + settings.setItem(selected.id, this.keyboardKeys) + this.keyboardBack(selected) + this.setKbd() + pageEvents.setKbd() + } + keyboardBack(selected){ + this.mode = "settings" + selected.settingBox.style.animation = "" + selected.valueDiv.classList.remove("selected") + this.getValue(selected.id, selected.valueDiv) + } onEnd(event){ var touched = false - if(event && event.type === "touchstart"){ - event.preventDefault() - touched = true + if(event){ + if(event.type === "touchstart"){ + event.preventDefault() + touched = true + }else if(event.which !== 1){ + return + } } this.clean() assets.sounds["se_don"].play() diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 530447e..ea7ba1b 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -289,16 +289,26 @@ class SongSelect{ this.startPreview(true) this.pressedKeys = {} + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = { + confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], + back: ["escape"], + left: ["arrowleft", kbdSettings.ka_l[0]], + right: ["arrowright", kbdSettings.ka_r[0]], + up: ["arrowup"], + down: ["arrowdown"], + session: ["backspace"] + } this.gamepad = new Gamepad({ - "13": ["b", "start", "ls", "rs"], - "27": ["a"], - "37": ["l", "lb", "lt", "lsl"], - "39": ["r", "rb", "rt", "lsr"], - "38": ["u", "lsu"], - "40": ["d", "lsd"], - "8": ["back"], - "ctrl": ["y"], - "shift": ["x"] + confirm: ["b", "start", "ls", "rs"], + back: ["a"], + left: ["l", "lb", "lt", "lsl"], + right: ["r", "rb", "rt", "lsr"], + up: ["u", "lsu"], + down: ["d", "lsd"], + session: ["back"], + ctrl: ["y"], + shift: ["x"] }) if(!assets.customSongs){ @@ -331,57 +341,46 @@ class SongSelect{ } } - keyDown(event, code){ - if(code){ + keyDown(event, key){ + if(key){ var modifiers = { shift: this.pressedKeys["shift"], ctrl: this.pressedKeys["ctrl"] } }else{ - code = event.keyCode var modifiers = { shift: event.shiftKey, ctrl: event.ctrlKey } + for(var i in this.kbd){ + if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ + key = i + break + } + } } - if(code === "ctrl" || code === "shift" || !this.redrawRunning){ + if(key === "ctrl" || key === "shift" || !this.redrawRunning){ return } - - var key = { - confirm: code == 13 || code == 32 || code == 70 || code == 74, - // Enter, Space, F, J - cancel: code == 27, - // Esc - session: code == 8, - // Backspace - left: code == 37 || code == 68, - // Left, D - right: code == 39 || code == 75, - // Right, K - up: code == 38, - // Up - down: code == 40 - // Down - } - if(event && (code == 27 || code == 8 || code == 9)){ + + if(event && (event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9)){ // Escape, Backspace, Tab event.preventDefault() } if(this.state.screen === "song"){ - if(key.confirm){ + if(key === "confirm"){ this.toSelectDifficulty() - }else if(key.cancel){ + }else if(key === "back"){ this.toTitleScreen() - }else if(key.session){ + }else if(key === "session"){ this.toSession() - }else if(key.left){ + }else if(key === "left"){ this.moveToSong(-1) - }else if(key.right){ + }else if(key === "right"){ this.moveToSong(1) } }else if(this.state.screen === "difficulty"){ - if(key.confirm){ + if(key === "confirm"){ if(this.selectedDiff === 0){ this.toSongSelect() }else if(this.selectedDiff === 1){ @@ -389,14 +388,14 @@ class SongSelect{ }else{ this.toLoadSong(this.selectedDiff - this.diffOptions.length, modifiers.shift, modifiers.ctrl) } - }else if(key.cancel || key.session){ + }else if(key === "back" || key === "session"){ this.toSongSelect() - }else if(key.left){ + }else if(key === "left"){ this.moveToDiff(-1) - }else if(key.right){ + }else if(key === "right"){ this.moveToDiff(1) - }else if(this.selectedDiff === 1 && (key.up || key.down)){ - this.toOptions(key.up ? -1 : 1) + }else if(this.selectedDiff === 1 && (key === "up" || key === "down")){ + this.toOptions(key === "up" ? -1 : 1) } } } diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 8176d1e..39a3bde 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -110,6 +110,19 @@ touchAnimation: { name: "タッチアニメーション" }, + keyboardSettings: { + name: "キーボード設定", + ka_l: "ふち(左)", + don_l: "面(左)", + don_r: "面(右)", + ka_r: "ふち(右)" + }, + gamepadLayout: { + name: "そうさタイプ設定", + a: "タイプA", + b: "タイプB", + c: "タイプC" + }, on: "オン", off: "オフ", ok: "OK" @@ -233,6 +246,19 @@ function StringsEn(){ touchAnimation: { name: "Touch Animation" }, + keyboardSettings: { + name: "Keyboard Settings", + ka_l: "Left Rim", + don_l: "Left Surface", + don_r: "Right Surface", + ka_r: "Right Rim" + }, + gamepadLayout: { + name: "Gamepad Layout", + a: "Type A", + b: "Type B", + c: "Type C" + }, on: "On", off: "Off", ok: "OK" @@ -356,6 +382,19 @@ function StringsCn(){ touchAnimation: { name: "触摸动画" }, + keyboardSettings: { + name: "Keyboard Settings", + ka_l: "Left Rim", + don_l: "Left Surface", + don_r: "Right Surface", + ka_r: "Right Rim" + }, + gamepadLayout: { + name: "操作类型设定", + a: "类型A", + b: "类型B", + c: "类型C" + }, on: "开", off: "关", ok: "确定" @@ -479,6 +518,19 @@ function StringsTw(){ touchAnimation: { name: "觸摸動畫" }, + keyboardSettings: { + name: "Keyboard Settings", + ka_l: "Left Rim", + don_l: "Left Surface", + don_r: "Right Surface", + ka_r: "Right Rim" + }, + gamepadLayout: { + name: "操作類型設定", + a: "類型A", + b: "類型B", + c: "類型C" + }, on: "開", off: "關", ok: "確定" @@ -602,6 +654,19 @@ function StringsKo(){ touchAnimation: { name: "터치 애니메이션" }, + keyboardSettings: { + name: "Keyboard Settings", + ka_l: "Left Rim", + don_l: "Left Surface", + don_r: "Right Surface", + ka_r: "Right Rim" + }, + gamepadLayout: { + name: "조작 타입 설정", + a: "타입 A", + b: "타입 B", + c: "타입 C" + }, on: "온", off: "오프", ok: "확인" diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index 9f95cdc..709de14 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -31,8 +31,12 @@ class Titlescreen{ pageEvents.add(this.langDropdown, "change", this.langChange.bind(this)) assets.sounds["v_title"].play() + var kbdSettings = settings.getItem("keyboardSettings") + this.kbd = { + confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]] + } this.gamepad = new Gamepad({ - "13": ["a", "b", "x", "y", "start", "ls", "rs"] + confirm: ["a", "b", "x", "y", "start", "ls", "rs"] }, pressed => { if(pressed){ this.onPressed() @@ -49,15 +53,19 @@ class Titlescreen{ } } - keyDown(event, code){ - if(event && event.target === this.langDropdown){ - return + keyDown(event, key){ + if(!key){ + if(event.repeat || event.target === this.langDropdown){ + return + } + for(var i in this.kbd){ + if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ + key = i + break + } + } } - if(!code){ - code = event.keyCode - } - if(code == 13 || code == 32 || code == 70 || code == 74){ - // Enter, Space, F, J + if(key === "confirm"){ this.onPressed() } } diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js index d2999cd..7a1f484 100644 --- a/public/src/js/tutorial.js +++ b/public/src/js/tutorial.js @@ -10,7 +10,14 @@ class Tutorial{ tutorialTitle.innerText = strings.howToPlay tutorialTitle.setAttribute("alt", strings.howToPlay) var tutorialContent = document.getElementById("tutorial-content") - var keys = ["F", "J", "D", "K", "Q", "SHIFT", "CTRL"] + var kbdSettings = settings.getItem("keyboardSettings") + var keys = [ + kbdSettings.don_l[0].toUpperCase(), + kbdSettings.don_r[0].toUpperCase(), + kbdSettings.ka_l[0].toUpperCase(), + kbdSettings.ka_r[0].toUpperCase(), + "Q", "SHIFT", "CTRL" + ] var keyIndex = 0 strings.tutorial.basics.forEach(string => { var par = document.createElement("p") @@ -42,8 +49,13 @@ class Tutorial{ this.endButton.innerText = strings.tutorial.ok this.endButton.setAttribute("alt", strings.tutorial.ok) - pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) - pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this)) + pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) + pageEvents.keyAdd(this, "all", "down", event => { + if(event.keyCode === 13 || event.keyCode === 27 || event.keyCode === 8){ + // Enter, Esc, Backspace + this.onEnd.bind(this) + } + }) this.gamepad = new Gamepad({ "confirm": ["start", "b", "ls", "rs"] @@ -60,9 +72,13 @@ class Tutorial{ } onEnd(event){ var touched = false - if(event && event.type === "touchstart"){ - event.preventDefault() - touched = true + if(event){ + if(event.type === "touchstart"){ + event.preventDefault() + touched = true + }else if(event.which !== 1){ + return + } } this.clean() assets.sounds["se_don"].play() @@ -75,7 +91,7 @@ class Tutorial{ this.gamepad.clean() assets.sounds["bgm_setsume"].stop() pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) - pageEvents.keyRemove(this, 13) + pageEvents.keyRemove(this, "all") delete this.endButton } } diff --git a/public/src/views/about.html b/public/src/views/about.html index 7ec8436..f6165c7 100644 --- a/public/src/views/about.html +++ b/public/src/views/about.html @@ -11,6 +11,6 @@ taiko@bui.pm -
+
diff --git a/public/src/views/settings.html b/public/src/views/settings.html index 983c90e..bfaa4ee 100644 --- a/public/src/views/settings.html +++ b/public/src/views/settings.html @@ -1,4 +1,4 @@ -
+
diff --git a/public/src/views/tutorial.html b/public/src/views/tutorial.html index 239daf2..ffd124a 100644 --- a/public/src/views/tutorial.html +++ b/public/src/views/tutorial.html @@ -2,6 +2,6 @@
-
+
From 59fc718a08fa583ed294f2ddb4ce437eea93bac3 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Fri, 5 Apr 2019 23:21:22 +0300 Subject: [PATCH 05/13] Fix touching settings --- public/src/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/js/settings.js b/public/src/js/settings.js index 97b8a41..0e38926 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -134,7 +134,7 @@ class SettingsView{ settingBox.classList.add("selected") } pageEvents.add(settingBox, ["mousedown", "touchstart"], event => { - if(event.which === 1){ + if(event.type !== "mousedown" || event.which === 1){ event.preventDefault() this.setValue(i) } From 8565a3cbba2d28fa908647cc1e3dc95dae28932a Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sat, 6 Apr 2019 00:10:15 +0300 Subject: [PATCH 06/13] Remove gamepad layout settings --- public/src/js/keyboard.js | 21 +++-------- public/src/js/settings.js | 65 ++++++++++++++++++++++------------ public/src/js/strings.js | 35 +++--------------- public/src/views/settings.html | 3 ++ 4 files changed, 54 insertions(+), 70 deletions(-) diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index 2960a97..f038a44 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -31,24 +31,11 @@ class Keyboard{ } this.keyboardEvents = 0 - var layout = settings.getItem("gamepadLayout") var gameBtn = {} - if(layout === "b"){ - gameBtn[this.kbd["don_l"]] = ["d", "r", "ls"] - gameBtn[this.kbd["don_r"]] = ["a", "x", "rs"] - gameBtn[this.kbd["ka_l"]] = ["u", "l", "lb", "lt"] - gameBtn[this.kbd["ka_r"]] = ["b", "y", "rb", "rt"] - }else if(layout === "c"){ - gameBtn[this.kbd["don_l"]] = ["d", "l", "ls"] - gameBtn[this.kbd["don_r"]] = ["a", "b", "rs"] - gameBtn[this.kbd["ka_l"]] = ["u", "r", "lb", "lt"] - gameBtn[this.kbd["ka_r"]] = ["x", "y", "rb", "rt"] - }else{ - gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] - gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] - gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] - gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] - } + gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] + gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] + gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] + gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] this.gamepad = new Gamepad(gameBtn) this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2) diff --git a/public/src/js/settings.js b/public/src/js/settings.js index 0e38926..b72c13b 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -23,12 +23,6 @@ class Settings{ ka_r: ["k"] }, touch: false - }, - gamepadLayout: { - type: "select", - options: ["a", "b", "c"], - default: "a", - gamepad: true } } @@ -82,25 +76,18 @@ class SettingsView{ loader.changePage("settings", false) assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) - this.endButton = document.getElementById("tutorial-end-button") if(touchEnabled){ document.getElementById("tutorial-outer").classList.add("touch-enabled") } - var gamepadEnabled = false - if("getGamepads" in navigator){ - var gamepads = navigator.getGamepads() - for(var i = 0; i < gamepads.length; i++){ - if(gamepads[i]){ - gamepadEnabled = true - break - } - } - } this.mode = "settings" var tutorialTitle = document.getElementById("tutorial-title") tutorialTitle.innerText = strings.gameSettings tutorialTitle.setAttribute("alt", strings.gameSettings) + this.defaultButton = document.getElementById("settings-default") + this.defaultButton.innerText = strings.settings.default + this.defaultButton.setAttribute("alt", strings.settings.default) + this.endButton = document.getElementById("tutorial-end-button") this.endButton.innerText = strings.settings.ok this.endButton.setAttribute("alt", strings.settings.ok) this.resolution = settings.getItem("resolution") @@ -112,8 +99,7 @@ class SettingsView{ var current = settings.items[i] if( !touchEnabled && current.touch === true || - touchEnabled && current.touch === false || - !gamepadEnabled && current.gamepad === true + touchEnabled && current.touch === false ){ continue } @@ -145,17 +131,23 @@ class SettingsView{ valueDiv: valueDiv }) } + this.items.push({ + id: "default", + settingBox: this.defaultButton + }) this.items.push({ id: "back", settingBox: this.endButton }) this.setKbd() + pageEvents.add(this.defaultButton, ["mousedown", "touchstart"], this.defaultSettings.bind(this)) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) this.gamepad = new Gamepad({ "confirm": ["b", "ls", "rs"], - "previous": ["u", "l", "lb", "lt", "lsu", "lsl"], + "up": ["u", "lsu"], + "previous": ["l", "lb", "lt", "lsl"], "next": ["d", "r", "rb", "rt", "lsd", "lsr"], "back": ["start", "a"] }, this.keyPressed.bind(this)) @@ -166,7 +158,8 @@ class SettingsView{ var kbdSettings = settings.getItem("keyboardSettings") this.kbd = { "confirm": ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], - "previous": ["arrowleft", "arrowup", kbdSettings.ka_l[0]], + "up": ["arrowup"], + "previous": ["arrowleft", kbdSettings.ka_l[0]], "next": ["arrowright", "arrowdown", kbdSettings.ka_r[0]], "back": ["backspace", "escape"] } @@ -258,12 +251,16 @@ class SettingsView{ if(name === "confirm"){ if(selected.id === "back"){ this.onEnd() + }else if(selected.id === "default"){ + this.defaultSettings() }else{ this.setValue(selected.id) } - }else if(name === "previous" || name === "next"){ + }else if(name === "up" || name === "previous" || name === "next"){ selected.settingBox.classList.remove("selected") - this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) + do{ + this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) + }while(this.items[this.selected].id === "default" && name !== "previous") this.items[this.selected].settingBox.classList.add("selected") assets.sounds["se_ka"].play() }else if(name === "back"){ @@ -303,6 +300,27 @@ class SettingsView{ selected.valueDiv.classList.remove("selected") this.getValue(selected.id, selected.valueDiv) } + defaultSettings(event){ + if(event && event.type === "touchstart"){ + event.preventDefault() + } + var selectedIndex = this.items.findIndex(item => item.id === "default") + if(this.selected !== selectedIndex){ + this.items[this.selected].settingBox.classList.remove("selected") + this.selected = selectedIndex + this.items[this.selected].settingBox.classList.add("selected") + } + for(var i in settings.items){ + settings.setItem(i, null) + } + for(var i in this.items){ + var item = this.items[i] + if(item.valueDiv){ + this.getValue(item.id, item.valueDiv) + } + } + assets.sounds["se_don"].play() + } onEnd(event){ var touched = false if(event){ @@ -329,6 +347,7 @@ class SettingsView{ for(var i in this.items){ pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) } + delete this.defaultButton delete this.endButton delete this.items if(this.resolution !== settings.getItem("resolution")){ diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 39a3bde..9d692ba 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -117,14 +117,9 @@ don_r: "面(右)", ka_r: "ふち(右)" }, - gamepadLayout: { - name: "そうさタイプ設定", - a: "タイプA", - b: "タイプB", - c: "タイプC" - }, on: "オン", off: "オフ", + default: "既定値にリセット", ok: "OK" } this.browserSupport = { @@ -253,14 +248,9 @@ function StringsEn(){ don_r: "Right Surface", ka_r: "Right Rim" }, - gamepadLayout: { - name: "Gamepad Layout", - a: "Type A", - b: "Type B", - c: "Type C" - }, on: "On", off: "Off", + default: "Reset to Defaults", ok: "OK" } this.browserSupport = { @@ -389,14 +379,9 @@ function StringsCn(){ don_r: "Right Surface", ka_r: "Right Rim" }, - gamepadLayout: { - name: "操作类型设定", - a: "类型A", - b: "类型B", - c: "类型C" - }, on: "开", off: "关", + default: "重置为默认值", ok: "确定" } this.browserSupport = { @@ -525,14 +510,9 @@ function StringsTw(){ don_r: "Right Surface", ka_r: "Right Rim" }, - gamepadLayout: { - name: "操作類型設定", - a: "類型A", - b: "類型B", - c: "類型C" - }, on: "開", off: "關", + default: "重置為默認值", ok: "確定" } this.browserSupport = { @@ -661,14 +641,9 @@ function StringsKo(){ don_r: "Right Surface", ka_r: "Right Rim" }, - gamepadLayout: { - name: "조작 타입 설정", - a: "타입 A", - b: "타입 B", - c: "타입 C" - }, on: "온", off: "오프", + default: "기본값으로 재설정", ok: "확인" } this.browserSupport = { diff --git a/public/src/views/settings.html b/public/src/views/settings.html index bfaa4ee..2333ff5 100644 --- a/public/src/views/settings.html +++ b/public/src/views/settings.html @@ -2,6 +2,9 @@
+
From b3c0f8cd73591116a0e85cad9f125a7a1691a779 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sat, 6 Apr 2019 13:19:10 +0300 Subject: [PATCH 07/13] Add language to settings --- public/src/css/main.css | 3 + public/src/js/pageevents.js | 1 + public/src/js/settings.js | 110 +++++++++++++++++++++++++++-------- public/src/js/strings.js | 21 ++++++- public/src/js/titlescreen.js | 35 ++--------- 5 files changed, 113 insertions(+), 57 deletions(-) diff --git a/public/src/css/main.css b/public/src/css/main.css index 9b44bb3..e312d72 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -181,6 +181,9 @@ kbd{ background: #ffb547; animation: 2s linear border-pulse infinite; } +.bold-fonts .setting-box{ + line-height: 1em; +} .setting-name{ position: relative; width: 50%; diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index a1bba1d..c180802 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -84,6 +84,7 @@ class PageEvents{ keyEvent(event){ if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){ this.lastKeyEvent = Date.now() + event.preventDefault() } this.keyListeners.forEach(addedKeyCode => { this.checkListener(addedKeyCode.get("all"), event) diff --git a/public/src/js/settings.js b/public/src/js/settings.js index b72c13b..1056fd9 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -4,6 +4,11 @@ class Settings{ var phone = /Android|iPhone|iPad/.test(navigator.userAgent) this.items = { + language: { + type: "language", + options: ["ja", "en", "cn", "tw", "ko"], + default: this.getLang() + }, resolution: { type: "select", options: ["high", "medium", "low", "lowest"], @@ -31,13 +36,18 @@ class Settings{ var storage = JSON.parse(localStorage.getItem("settings") || "{}") for(var i in this.items){ var current = this.items[i] - if(i in storage){ + if(current.type === "language"){ + this.storage[i] = localStorage.getItem("lang") + if(current.options.indexOf(this.storage[i]) === -1){ + this.storage[i] = null + } + }else if(i in storage){ if(current.type === "select" && current.options.indexOf(storage[i]) === -1){ this.storage[i] = null }else if(current.type === "keyboard"){ var obj = {} for(var j in current.default){ - if(storage[i][j] && storage[i][j][0]){ + if(storage[i] && storage[i][j] && storage[i][j][0]){ obj[j] = storage[i][j] }else{ obj = null @@ -65,9 +75,44 @@ class Settings{ setItem(name, value){ this.storage[name] = value try{ - localStorage.setItem("settings", JSON.stringify(this.storage)) + if(name === "language"){ + if(value){ + localStorage.setItem("lang", value) + }else{ + localStorage.removeItem("lang") + } + }else{ + var language = this.storage.language + delete this.storage.language + localStorage.setItem("settings", JSON.stringify(this.storage)) + this.storage.language = language + } }catch(e){} } + getLang(){ + if("languages" in navigator){ + var userLang = navigator.languages.slice() + userLang.unshift(navigator.language) + for(var i in userLang){ + for(var j in allStrings){ + if(allStrings[j].regex.test(userLang[i])){ + return j + } + } + } + } + return "ja" + } + setLang(lang, noEvent){ + strings = lang + var boldFonts = strings.font === "Microsoft YaHei, sans-serif" + loader.screen.style.fontFamily = strings.font + loader.screen.style.fontWeight = boldFonts ? "bold" : "" + loader.screen.classList[boldFonts ? "add" : "remove"]("bold-fonts") + if(!noEvent){ + pageEvents.send("language-change", lang.id) + } + } } class SettingsView{ @@ -81,15 +126,10 @@ class SettingsView{ } this.mode = "settings" - var tutorialTitle = document.getElementById("tutorial-title") - tutorialTitle.innerText = strings.gameSettings - tutorialTitle.setAttribute("alt", strings.gameSettings) + this.tutorialTitle = document.getElementById("tutorial-title") this.defaultButton = document.getElementById("settings-default") - this.defaultButton.innerText = strings.settings.default - this.defaultButton.setAttribute("alt", strings.settings.default) this.endButton = document.getElementById("tutorial-end-button") - this.endButton.innerText = strings.settings.ok - this.endButton.setAttribute("alt", strings.settings.ok) + this.setStrings() this.resolution = settings.getItem("resolution") var content = document.getElementById("tutorial-content") @@ -128,6 +168,7 @@ class SettingsView{ this.items.push({ id: i, settingBox: settingBox, + nameDiv: nameDiv, valueDiv: valueDiv }) } @@ -167,7 +208,9 @@ class SettingsView{ getValue(name, valueDiv){ var current = settings.items[name] var value = settings.getItem(name) - if(current.type === "select"){ + if(current.type === "language"){ + value = allStrings[value].name + " (" + value + ")" + }else if(current.type === "select"){ value = strings.settings[name][value] }else if(current.type === "toggle"){ value = value ? strings.settings.on : strings.settings.off @@ -199,7 +242,7 @@ class SettingsView{ this.selected = selectedIndex selected.settingBox.classList.add("selected") } - if(current.type === "select"){ + if(current.type === "language" || current.type === "select"){ value = current.options[this.mod(current.options.length, current.options.indexOf(value) + 1)] }else if(current.type === "toggle"){ value = !value @@ -215,6 +258,9 @@ class SettingsView{ settings.setItem(name, value) this.getValue(name, this.items[this.selected].valueDiv) assets.sounds["se_ka"].play() + if(current.type === "language"){ + this.setLang(allStrings[value]) + } } keyEvent(event){ if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ @@ -231,6 +277,7 @@ class SettingsView{ } } if(this.mode === "keyboard"){ + event.preventDefault() var currentKey = event.key.toLowerCase() for(var i in this.keyboardKeys){ if(this.keyboardKeys[i][0] === currentKey || !currentKey){ @@ -304,21 +351,13 @@ class SettingsView{ if(event && event.type === "touchstart"){ event.preventDefault() } - var selectedIndex = this.items.findIndex(item => item.id === "default") - if(this.selected !== selectedIndex){ - this.items[this.selected].settingBox.classList.remove("selected") - this.selected = selectedIndex - this.items[this.selected].settingBox.classList.add("selected") + if(this.mode === "keyboard"){ + this.keyboardBack(this.items[this.selected]) } for(var i in settings.items){ settings.setItem(i, null) } - for(var i in this.items){ - var item = this.items[i] - if(item.valueDiv){ - this.getValue(item.id, item.valueDiv) - } - } + this.setLang(allStrings[settings.getItem("language")]) assets.sounds["se_don"].play() } onEnd(event){ @@ -337,6 +376,30 @@ class SettingsView{ new SongSelect("settings", false, touched) }, 500) } + setLang(lang){ + settings.setLang(lang) + if(failedTests.length !== 0){ + showUnsupported(strings) + } + for(var i in this.items){ + var item = this.items[i] + if(item.valueDiv){ + var name = strings.settings[item.id].name + item.nameDiv.innerText = name + item.nameDiv.setAttribute("alt", name) + this.getValue(item.id, item.valueDiv) + } + } + this.setStrings() + } + setStrings(){ + this.tutorialTitle.innerText = strings.gameSettings + this.tutorialTitle.setAttribute("alt", strings.gameSettings) + this.defaultButton.innerText = strings.settings.default + this.defaultButton.setAttribute("alt", strings.settings.default) + this.endButton.innerText = strings.settings.ok + this.endButton.setAttribute("alt", strings.settings.ok) + } mod(length, index){ return ((index % length) + length) % length } @@ -347,6 +410,7 @@ class SettingsView{ for(var i in this.items){ pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) } + delete this.tutorialTitle delete this.defaultButton delete this.endButton delete this.items diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 9d692ba..57134ef 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -100,6 +100,9 @@ cancel: "キャンセル" } this.settings = { + language: { + name: "言語" + }, resolution: { name: "ゲームの解像度", high: "高", @@ -231,6 +234,9 @@ function StringsEn(){ cancel: "Cancel" } this.settings = { + language: { + name: "Language" + }, resolution: { name: "Game Resolution", high: "High", @@ -362,6 +368,9 @@ function StringsCn(){ cancel: "取消" } this.settings = { + language: { + name: "语言" + }, resolution: { name: "游戏分辨率", high: "高", @@ -373,7 +382,7 @@ function StringsCn(){ name: "触摸动画" }, keyboardSettings: { - name: "Keyboard Settings", + name: "键盘设置", ka_l: "Left Rim", don_l: "Left Surface", don_r: "Right Surface", @@ -493,6 +502,9 @@ function StringsTw(){ cancel: "取消" } this.settings = { + language: { + name: "語系" + }, resolution: { name: "遊戲分辨率", high: "高", @@ -504,7 +516,7 @@ function StringsTw(){ name: "觸摸動畫" }, keyboardSettings: { - name: "Keyboard Settings", + name: "鍵盤設置", ka_l: "Left Rim", don_l: "Left Surface", don_r: "Right Surface", @@ -624,6 +636,9 @@ function StringsKo(){ cancel: "취소" } this.settings = { + language: { + name: "언어" + }, resolution: { name: "게임 해상도", high: "높은", @@ -635,7 +650,7 @@ function StringsKo(){ name: "터치 애니메이션" }, keyboardSettings: { - name: "Keyboard Settings", + name: "키보드 설정", ka_l: "Left Rim", don_l: "Left Surface", don_r: "Right Surface", diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index 709de14..7e62525 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -14,7 +14,7 @@ class Titlescreen{ document.getElementById("globe-path").setAttribute("d", vectors.globe) this.logo = new Logo() } - this.lang = this.getLang() + this.lang = settings.getItem("language") this.setLang(allStrings[this.lang], true) if(songId){ @@ -101,32 +101,8 @@ class Titlescreen{ } } - getLang(){ - if(localStorage.lang && localStorage.lang in allStrings){ - return localStorage.lang - } - if("languages" in navigator){ - var userLang = navigator.languages.slice() - userLang.unshift(navigator.language) - for(var i in userLang){ - for(var j in allStrings){ - if(allStrings[j].regex.test(userLang[i])){ - return j - } - } - } - } - return "ja" - } - setLang(lang, initial){ - strings = lang - - loader.screen.style.fontFamily = strings.font - loader.screen.style.fontWeight = strings.font === "Microsoft YaHei, sans-serif" ? "bold" : "" - - if(failedTests.length !== 0){ - showUnsupported(strings) - } + setLang(lang, noEvent){ + settings.setLang(lang, noEvent || this.songId) if(this.songId){ return } @@ -141,9 +117,6 @@ class Titlescreen{ this.disclaimerCopyright.setAttribute("alt", strings.titleCopyright) this.logo.updateSubtitle() - if(!initial){ - pageEvents.send("language-change", lang.id) - } } addLangs(){ for(var i in allStrings){ @@ -158,7 +131,7 @@ class Titlescreen{ } langChange(){ this.lang = this.langDropdown.value - localStorage.lang = this.lang + settings.setItem("language", this.lang) this.setLang(allStrings[this.lang]) } From a33ff2a86808fcde4e6be9f725769dfafd42be85 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sat, 6 Apr 2019 13:26:06 +0300 Subject: [PATCH 08/13] Fix keys not resetting --- public/src/js/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/js/settings.js b/public/src/js/settings.js index 1056fd9..e57b2c1 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -358,6 +358,7 @@ class SettingsView{ settings.setItem(i, null) } this.setLang(allStrings[settings.getItem("language")]) + this.setKbd() assets.sounds["se_don"].play() } onEnd(event){ From a4d938e888d762cdba17b5e92d029c39656b3eca Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Sat, 6 Apr 2019 22:14:44 +0300 Subject: [PATCH 09/13] Move language settings from title screen --- public/assets/img/vectors.json | 3 - public/src/css/main.css | 4 +- public/src/css/titlescreen.css | 47 ---------- public/src/js/settings.js | 68 ++++++++++----- public/src/js/titlescreen.js | 37 +------- public/src/js/tutorial.js | 137 +++++++++++++++++------------- public/src/views/titlescreen.html | 5 -- 7 files changed, 131 insertions(+), 170 deletions(-) diff --git a/public/assets/img/vectors.json b/public/assets/img/vectors.json index 0e55a2a..536fb30 100644 --- a/public/assets/img/vectors.json +++ b/public/assets/img/vectors.json @@ -66,8 +66,5 @@ "", "logo5": -"", - -"globe": "" } diff --git a/public/src/css/main.css b/public/src/css/main.css index e312d72..11e4c64 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -176,7 +176,8 @@ kbd{ .setting-box:first-child{ margin-top: 0; } -#tutorial-content:not(:hover) .setting-box.selected, +.settings-outer #tutorial-content:not(:hover) .setting-box.selected, +#tutorial-outer:not(.settings-outer) .setting-box.selected, .setting-box:hover{ background: #ffb547; animation: 2s linear border-pulse infinite; @@ -192,6 +193,7 @@ kbd{ box-sizing: border-box; } #tutorial-content:not(:hover) .setting-box.selected .setting-name, +#tutorial-outer:not(.settings-outer) .setting-box.selected .setting-name, .setting-box:hover .setting-name{ color: #fff; z-index: 0; diff --git a/public/src/css/titlescreen.css b/public/src/css/titlescreen.css index 6a280a3..3ca80fc 100644 --- a/public/src/css/titlescreen.css +++ b/public/src/css/titlescreen.css @@ -38,53 +38,6 @@ -webkit-text-stroke: 0.25em #f00; filter: blur(0.3vmin); } -#lang{ - font-size: 3vmin; - position: absolute; - bottom: 0; - left: 0; - width: 7em; - height: 4em; - color: #000; - z-index: 5; -} -#lang:focus-within{ - outline: #4d90fe auto 5px; -} -#lang-dropdown{ - font-size: 1.7em; - font-family: Microsoft YaHei, sans-serif; - opacity: 0; - width: 100%; - height: 100%; - color: #000; - cursor: pointer; -} -#lang-id{ - position: absolute; - top: 0; - bottom: 0; - left: 2.6em; - font-family: TnT, Meiryo, sans-serif; - font-size: 1.5em; - font-weight: normal; - color: #fff; - line-height: 2.75em; - z-index: 0; -} -#lang-icon{ - position: absolute; - width: 2.8em; - height: 2.8em; - padding: 0.6em; - fill: currentColor; -} -#lang:hover #lang-icon{ - color: #f00; -} -#lang:hover #lang-id::before { - -webkit-text-stroke: 0.25em #f00; -} #title-disclaimer { text-align: center; position: absolute; diff --git a/public/src/js/settings.js b/public/src/js/settings.js index e57b2c1..d17c92b 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -116,30 +116,37 @@ class Settings{ } class SettingsView{ - constructor(touchEnabled){ + constructor(touchEnabled, tutorial){ this.touchEnabled = touchEnabled - loader.changePage("settings", false) - assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) - + this.tutorial = tutorial + if(!tutorial){ + loader.changePage("settings", tutorial) + assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) + this.defaultButton = document.getElementById("settings-default") + }else if(touchEnabled){ + document.getElementById("tutorial-outer").classList.add("settings-outer") + } if(touchEnabled){ document.getElementById("tutorial-outer").classList.add("touch-enabled") } this.mode = "settings" this.tutorialTitle = document.getElementById("tutorial-title") - this.defaultButton = document.getElementById("settings-default") this.endButton = document.getElementById("tutorial-end-button") - this.setStrings() + if(!tutorial){ + this.setStrings() + } this.resolution = settings.getItem("resolution") var content = document.getElementById("tutorial-content") this.items = [] - this.selected = 0 + this.selected = tutorial ? 1 : 0 for(let i in settings.items){ var current = settings.items[i] if( !touchEnabled && current.touch === true || - touchEnabled && current.touch === false + touchEnabled && current.touch === false || + tutorial && current.type !== "language" ){ continue } @@ -172,17 +179,19 @@ class SettingsView{ valueDiv: valueDiv }) } - this.items.push({ - id: "default", - settingBox: this.defaultButton - }) + if(!tutorial){ + this.items.push({ + id: "default", + settingBox: this.defaultButton + }) + pageEvents.add(this.defaultButton, ["mousedown", "touchstart"], this.defaultSettings.bind(this)) + } this.items.push({ id: "back", settingBox: this.endButton }) this.setKbd() - pageEvents.add(this.defaultButton, ["mousedown", "touchstart"], this.defaultSettings.bind(this)) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) this.gamepad = new Gamepad({ @@ -192,8 +201,9 @@ class SettingsView{ "next": ["d", "r", "rb", "rt", "lsd", "lsr"], "back": ["start", "a"] }, this.keyPressed.bind(this)) - - pageEvents.send("settings") + if(!tutorial){ + pageEvents.send("settings") + } } setKbd(){ var kbdSettings = settings.getItem("keyboardSettings") @@ -308,7 +318,9 @@ class SettingsView{ do{ this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1)) }while(this.items[this.selected].id === "default" && name !== "previous") - this.items[this.selected].settingBox.classList.add("selected") + selected = this.items[this.selected] + selected.settingBox.classList.add("selected") + selected.settingBox.scrollIntoView() assets.sounds["se_ka"].play() }else if(name === "back"){ this.onEnd() @@ -362,6 +374,10 @@ class SettingsView{ assets.sounds["se_don"].play() } onEnd(event){ + if(this.tutorial){ + this.clean() + return this.tutorial.onEnd(event) + } var touched = false if(event){ if(event.type === "touchstart"){ @@ -394,12 +410,16 @@ class SettingsView{ this.setStrings() } setStrings(){ - this.tutorialTitle.innerText = strings.gameSettings - this.tutorialTitle.setAttribute("alt", strings.gameSettings) - this.defaultButton.innerText = strings.settings.default - this.defaultButton.setAttribute("alt", strings.settings.default) - this.endButton.innerText = strings.settings.ok - this.endButton.setAttribute("alt", strings.settings.ok) + if(this.tutorial){ + this.tutorial.setStrings() + }else{ + this.tutorialTitle.innerText = strings.gameSettings + this.tutorialTitle.setAttribute("alt", strings.gameSettings) + this.defaultButton.innerText = strings.settings.default + this.defaultButton.setAttribute("alt", strings.settings.default) + this.endButton.innerText = strings.settings.ok + this.endButton.setAttribute("alt", strings.settings.ok) + } } mod(length, index){ return ((index % length) + length) % length @@ -411,8 +431,10 @@ class SettingsView{ for(var i in this.items){ pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) } + if(this.defaultButton){ + delete this.defaultButton + } delete this.tutorialTitle - delete this.defaultButton delete this.endButton delete this.items if(this.resolution !== settings.getItem("resolution")){ diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index 7e62525..a5ba7b6 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -7,15 +7,11 @@ class Titlescreen{ this.titleScreen = document.getElementById("title-screen") this.proceed = document.getElementById("title-proceed") - this.langDropdown = document.getElementById("lang-dropdown") - this.langId = document.getElementById("lang-id") this.disclaimerText = document.getElementById("title-disclaimer-text") this.disclaimerCopyright = document.getElementById("title-disclaimer-copyright") - document.getElementById("globe-path").setAttribute("d", vectors.globe) this.logo = new Logo() } - this.lang = settings.getItem("language") - this.setLang(allStrings[this.lang], true) + this.setLang(allStrings[settings.getItem("language")]) if(songId){ if(localStorage.getItem("tutorial") === "true"){ @@ -24,11 +20,8 @@ class Titlescreen{ new Tutorial(false, this.songId) } }else{ - this.addLangs() - pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], this.onPressed.bind(this)) - pageEvents.add(this.langDropdown, "change", this.langChange.bind(this)) assets.sounds["v_title"].play() var kbdSettings = settings.getItem("keyboardSettings") @@ -86,7 +79,7 @@ class Titlescreen{ goNext(fromP2){ if(p2.session && !fromP2){ p2.send("songsel") - }else if(fromP2 || this.touched || localStorage.getItem("tutorial") === "true"){ + }else if(fromP2 || localStorage.getItem("tutorial") === "true"){ if(this.touched){ localStorage.setItem("tutorial", "true") } @@ -96,20 +89,17 @@ class Titlescreen{ }, 500) }else{ setTimeout(() => { - new Tutorial(false, this.songId) + new Tutorial(false, this.songId, this.touched) }, 500) } } - setLang(lang, noEvent){ - settings.setLang(lang, noEvent || this.songId) + settings.setLang(lang, true) if(this.songId){ return } this.proceed.innerText = strings.titleProceed this.proceed.setAttribute("alt", strings.titleProceed) - this.langId.innerText = strings.id.toUpperCase() - this.langId.setAttribute("alt", strings.id.toUpperCase()) this.disclaimerText.innerText = strings.titleDisclaimer this.disclaimerText.setAttribute("alt", strings.titleDisclaimer) @@ -118,34 +108,15 @@ class Titlescreen{ this.logo.updateSubtitle() } - addLangs(){ - for(var i in allStrings){ - var option = document.createElement("option") - option.value = i - if(i === this.lang){ - option.selected = true - } - option.appendChild(document.createTextNode(allStrings[i].name)) - this.langDropdown.appendChild(option) - } - } - langChange(){ - this.lang = this.langDropdown.value - settings.setItem("language", this.lang) - this.setLang(allStrings[this.lang]) - } - clean(){ this.gamepad.clean() this.logo.clean() assets.sounds["v_title"].stop() pageEvents.keyRemove(this, "all") pageEvents.remove(this.titleScreen, ["mousedown", "touchstart"]) - pageEvents.remove(this.langDropdown, "change") delete this.titleScreen delete this.proceed delete this.titleDisclaimer delete this.titleCopyright - delete this.langDropdown } } diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js index 7a1f484..01a30a7 100644 --- a/public/src/js/tutorial.js +++ b/public/src/js/tutorial.js @@ -1,65 +1,32 @@ class Tutorial{ - constructor(fromSongSel, songId){ + constructor(fromSongSel, songId, touchEnabled){ this.fromSongSel = fromSongSel this.songId = songId - loader.changePage("tutorial", true) + this.touchEnabled = touchEnabled + loader.changePage("tutorial", fromSongSel || !touchEnabled) assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) this.endButton = document.getElementById("tutorial-end-button") - var tutorialTitle = document.getElementById("tutorial-title") - tutorialTitle.innerText = strings.howToPlay - tutorialTitle.setAttribute("alt", strings.howToPlay) - var tutorialContent = document.getElementById("tutorial-content") - var kbdSettings = settings.getItem("keyboardSettings") - var keys = [ - kbdSettings.don_l[0].toUpperCase(), - kbdSettings.don_r[0].toUpperCase(), - kbdSettings.ka_l[0].toUpperCase(), - kbdSettings.ka_r[0].toUpperCase(), - "Q", "SHIFT", "CTRL" - ] - var keyIndex = 0 - strings.tutorial.basics.forEach(string => { - var par = document.createElement("p") - var stringKeys = string.split("%s") - stringKeys.forEach((stringKey, i) => { - if(i !== 0){ - this.insertKey(keys[keyIndex++], par) - } - this.insertText(stringKey, par) - }) - tutorialContent.appendChild(par) - }) - var par = document.createElement("p") - var span = document.createElement("span") - span.style.fontWeight = "bold" - span.innerText = strings.tutorial.otherControls - par.appendChild(span) - strings.tutorial.otherTutorial.forEach(string => { - par.appendChild(document.createElement("br")) - var stringKeys = string.split("%s") - stringKeys.forEach((stringKey, i) => { - if(i !== 0){ - this.insertKey(keys[keyIndex++], par) - } - this.insertText(stringKey, par) - }) - }) - tutorialContent.appendChild(par) - this.endButton.innerText = strings.tutorial.ok - this.endButton.setAttribute("alt", strings.tutorial.ok) + this.tutorialTitle = document.getElementById("tutorial-title") + this.tutorialDiv = document.createElement("div") + document.getElementById("tutorial-content").appendChild(this.tutorialDiv) + this.setStrings() - pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) - pageEvents.keyAdd(this, "all", "down", event => { - if(event.keyCode === 13 || event.keyCode === 27 || event.keyCode === 8){ - // Enter, Esc, Backspace - this.onEnd.bind(this) - } - }) - - this.gamepad = new Gamepad({ - "confirm": ["start", "b", "ls", "rs"] - }, this.onEnd.bind(this)) + if(fromSongSel){ + pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) + pageEvents.keyAdd(this, "all", "down", event => { + if(event.keyCode === 13 || event.keyCode === 27 || event.keyCode === 8){ + // Enter, Esc, Backspace + this.onEnd.bind(this) + } + }) + + this.gamepad = new Gamepad({ + "confirm": ["start", "b", "ls", "rs"] + }, this.onEnd.bind(this)) + }else{ + new SettingsView(touchEnabled, this) + } pageEvents.send("tutorial") } insertText(text, parent){ @@ -87,11 +54,65 @@ class Tutorial{ new SongSelect(this.fromSongSel ? "tutorial" : false, false, touched, this.songId) }, 500) } + setStrings(){ + if(!this.fromSongSel && this.touchEnabled){ + this.tutorialTitle.innerText = strings.gameSettings + this.tutorialTitle.setAttribute("alt", strings.gameSettings) + this.endButton.innerText = strings.settings.ok + this.endButton.setAttribute("alt", strings.settings.ok) + return + } + this.tutorialTitle.innerText = strings.howToPlay + this.tutorialTitle.setAttribute("alt", strings.howToPlay) + this.endButton.innerText = strings.tutorial.ok + this.endButton.setAttribute("alt", strings.tutorial.ok) + this.tutorialDiv.innerHTML = "" + var kbdSettings = settings.getItem("keyboardSettings") + var keys = [ + kbdSettings.don_l[0].toUpperCase(), + kbdSettings.don_r[0].toUpperCase(), + kbdSettings.ka_l[0].toUpperCase(), + kbdSettings.ka_r[0].toUpperCase(), + "Q", "SHIFT", "CTRL" + ] + var keyIndex = 0 + strings.tutorial.basics.forEach(string => { + var par = document.createElement("p") + var stringKeys = string.split("%s") + stringKeys.forEach((stringKey, i) => { + if(i !== 0){ + this.insertKey(keys[keyIndex++], par) + } + this.insertText(stringKey, par) + }) + this.tutorialDiv.appendChild(par) + }) + var par = document.createElement("p") + var span = document.createElement("span") + span.style.fontWeight = "bold" + span.innerText = strings.tutorial.otherControls + par.appendChild(span) + strings.tutorial.otherTutorial.forEach(string => { + par.appendChild(document.createElement("br")) + var stringKeys = string.split("%s") + stringKeys.forEach((stringKey, i) => { + if(i !== 0){ + this.insertKey(keys[keyIndex++], par) + } + this.insertText(stringKey, par) + }) + }) + this.tutorialDiv.appendChild(par) + } clean(){ - this.gamepad.clean() + if(this.fromSongSel){ + this.gamepad.clean() + pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) + pageEvents.keyRemove(this, "all") + } assets.sounds["bgm_setsume"].stop() - pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) - pageEvents.keyRemove(this, "all") + delete this.tutorialTitle delete this.endButton + delete this.tutorialDiv } } diff --git a/public/src/views/titlescreen.html b/public/src/views/titlescreen.html index e660734..449427f 100644 --- a/public/src/views/titlescreen.html +++ b/public/src/views/titlescreen.html @@ -6,8 +6,3 @@
-
- -
- -
From f05b2518f35e2b6ffd37b28c9a72b6a5ce8f90f8 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Tue, 16 Apr 2019 21:06:41 +0300 Subject: [PATCH 10/13] Split language and tutorial, add gamepad settings --- public/assets/img/img.css | 4 + public/assets/img/settings_gamepad.png | Bin 0 -> 490 bytes public/src/css/main.css | 183 -------------- public/src/css/view.css | 235 ++++++++++++++++++ public/src/js/about.js | 38 +-- public/src/js/assets.js | 7 +- public/src/js/controller.js | 9 +- public/src/js/debug.js | 9 +- public/src/js/game.js | 21 +- public/src/js/gameinput.js | 247 +++++++++++++++++++ public/src/js/gamepad.js | 11 +- public/src/js/keyboard.js | 327 +++++++------------------ public/src/js/mekadon.js | 18 +- public/src/js/pageevents.js | 24 +- public/src/js/scoresheet.js | 37 +-- public/src/js/session.js | 32 ++- public/src/js/settings.js | 314 +++++++++++++++--------- public/src/js/songselect.js | 89 +++---- public/src/js/strings.js | 54 +++- public/src/js/titlescreen.js | 64 ++--- public/src/js/tutorial.js | 86 +++---- public/src/js/view.js | 8 +- public/src/views/about.html | 12 +- public/src/views/session.html | 10 +- public/src/views/settings.html | 22 +- public/src/views/tutorial.html | 10 +- 26 files changed, 1036 insertions(+), 835 deletions(-) create mode 100644 public/assets/img/settings_gamepad.png create mode 100644 public/src/css/view.css create mode 100644 public/src/js/gameinput.js diff --git a/public/assets/img/img.css b/public/assets/img/img.css index 7d339c6..2a79238 100644 --- a/public/assets/img/img.css +++ b/public/assets/img/img.css @@ -19,3 +19,7 @@ .settings-outer{ background-image: url("bg_settings.png"); } +#gamepad-bg, +#gamepad-buttons{ + background-image: url("settings_gamepad.png"); +} diff --git a/public/assets/img/settings_gamepad.png b/public/assets/img/settings_gamepad.png new file mode 100644 index 0000000000000000000000000000000000000000..c287f06cc505d9858d2bc4bfb04d759bd9a92330 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0y~yU{V9(lN`)Ik?l+p%0P-az$e5NNH4Fly#=HgOM?7@ z862M7NCUE`db&7{F_6 M)78&qol`;+0G}!ymjD0& literal 0 HcmV?d00001 diff --git a/public/src/css/main.css b/public/src/css/main.css index 11e4c64..6927ff1 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -23,117 +23,6 @@ left: 0; z-index: -1; } -#tutorial-outer{ - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - position: absolute; - width: 100%; - height: 100%; -} -#tutorial{ - background: rgb(246, 234, 212); - color: black; - border: 0.25em black solid; - border-radius: 0.5em; - width: 800px; - padding: 1em; - margin: 1em; - font-size: 21px; - position: relative; -} -.touch-enabled #tutorial{ - font-size: 3vmin; -} -#tutorial-title{ - z-index: 1; - position: absolute; - color: white; - top: -0.7em; - font-size: 1.65em; -} -#tutorial-content{ - margin: 0.7em 0; - overflow-y: auto; - max-height: calc(100vh - 14em); -} -kbd{ - font-family: inherit; - padding: 0.1em 0.6em; - border: 1px solid #ccc; - font-size: 0.6em; - background-color: #f7f7f7; - color: #333; - box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; - border-radius: 3px; - display: inline-block; - text-shadow: 0 1px 0 #fff; - line-height: 1.4; - white-space: nowrap; -} -.taibtn{ - display: inline-block; - background: #f6ead4; - padding: 0.4em 0.4em; - border-radius: 0.5em; - border: 0.1em rgba(218, 205, 178, 1) solid; - cursor: pointer; - font-size: 1.4em; - box-sizing: border-box; - color: #555; - text-align: center; -} -#tutorial-end-button{ - float: right; - padding: 0.4em 1.5em; - font-weight: bold; - border-color: #000; - color: #000; -} -.taibtn:hover, -.taibtn.selected, -#tutorial-end-button:hover, -#tutorial-end-button.selected{ - position: relative; - z-index: 1; - color: #fff; - background: #ffb547; - border-color: #fff; -} -.taibtn::before{ - padding-left: inherit; -} -#about-link-btns{ - float: left; - display: flex; -} -#about-link-btns .taibtn{ - margin-right: 0.4em; -} -#diag-txt textarea, -#diag-txt iframe{ - width: 100%; - height: 5em; - font-size: inherit; - resize: none; - word-break: break-all; - margin-bottom: 1em; - background: #fff; - border: 1px solid #a9a9a9; - user-select: all; -} -.text-warn{ - color: #d00; -} -.link-btn a{ - color: inherit; - text-decoration: none; - pointer-events: none; -} -.nowrap{ - white-space: nowrap; -} #session-invite{ width: 100%; height: 1.9em; @@ -149,78 +38,6 @@ kbd{ cursor: text; overflow: hidden; } -@keyframes border-pulse{ - 0%{border-color: #ff0} - 50%{border-color: rgba(255, 255, 0, 0)} - 100%{border-color: #ff0} -} -@keyframes border-pulse2{ - 0%{border-color: #e29e06} - 50%{border-color: rgba(226, 158, 6, 0)} - 100%{border-color: #e29e06} -} -.settings-outer{ - background-size: 50vh; -} -.setting-box{ - display: flex; - height: 2em; - margin-top: 1.2em; - border: 0.25em solid #000; - border-radius: 0.5em; - padding: 0.3em; - outline: none; - color: #000; - cursor: pointer; -} -.setting-box:first-child{ - margin-top: 0; -} -.settings-outer #tutorial-content:not(:hover) .setting-box.selected, -#tutorial-outer:not(.settings-outer) .setting-box.selected, -.setting-box:hover{ - background: #ffb547; - animation: 2s linear border-pulse infinite; -} -.bold-fonts .setting-box{ - line-height: 1em; -} -.setting-name{ - position: relative; - width: 50%; - padding: 0.3em; - font-size: 1.3em; - box-sizing: border-box; -} -#tutorial-content:not(:hover) .setting-box.selected .setting-name, -#tutorial-outer:not(.settings-outer) .setting-box.selected .setting-name, -.setting-box:hover .setting-name{ - color: #fff; - z-index: 0; -} -.setting-name::before{ - padding-left: 0.3em; -} -.setting-value{ - display: flex; - background: #fff; - width: 50%; - border-radius: 0.2em; - padding: 0.5em; - box-sizing: border-box; -} -.setting-value.selected{ - width: calc(50% + 0.2em); - margin: -0.1em; - border: 0.2em solid #e29e06; - padding: 0.4em; - animation: 2s linear border-pulse2 infinite; -} -.setting-value>div{ - padding: 0 0.4em; - overflow: hidden; - text-overflow: ellipsis; -} @keyframes bgscroll{ from{ background-position: 0 top; diff --git a/public/src/css/view.css b/public/src/css/view.css new file mode 100644 index 0000000..3b80242 --- /dev/null +++ b/public/src/css/view.css @@ -0,0 +1,235 @@ +.view-outer{ + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + position: absolute; + width: 100%; + height: 100%; +} +.view{ + background: rgb(246, 234, 212); + color: black; + border: 0.25em black solid; + border-radius: 0.5em; + width: 800px; + padding: 1em; + margin: 1em; + font-size: 21px; + position: relative; +} +.touch-enabled .view{ + font-size: 3vmin; +} +.view-title{ + z-index: 1; + position: absolute; + color: white; + top: -0.7em; + font-size: 1.65em; +} +.view-content{ + margin: 0.7em 0; + overflow-y: auto; + max-height: calc(100vh - 14em); +} +kbd{ + font-family: inherit; + padding: 0.1em 0.6em; + border: 1px solid #ccc; + font-size: 0.6em; + background-color: #f7f7f7; + color: #333; + box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + border-radius: 3px; + display: inline-block; + text-shadow: 0 1px 0 #fff; + line-height: 1.4; + white-space: nowrap; +} +.taibtn{ + display: inline-block; + background: #f6ead4; + padding: 0.4em 0.4em; + border-radius: 0.5em; + border: 0.1em rgba(218, 205, 178, 1) solid; + cursor: pointer; + font-size: 1.4em; + box-sizing: border-box; + color: #555; + text-align: center; +} +.view-end-button{ + float: right; + padding: 0.4em 1.5em; + font-weight: bold; + border-color: #000; + color: #000; + z-index: 1; +} +.taibtn:hover, +.taibtn.selected, +.view-end-button:hover, +.view-end-button.selected{ + position: relative; + color: #fff; + background: #ffb547; + border-color: #fff; +} +.taibtn::before, +.view-end-button::before{ + display: none; +} +.taibtn:hover::before, +.taibtn.selected::before, +.view-end-button:hover::before, +.view-end-button.selected::before{ + display: block +} +.taibtn::before{ + padding-left: inherit; +} +.left-buttons{ + float: left; + display: flex; +} +.left-buttons .taibtn{ + margin-right: 0.4em; +} +#diag-txt textarea, +#diag-txt iframe{ + width: 100%; + height: 5em; + font-size: inherit; + resize: none; + word-break: break-all; + margin-bottom: 1em; + background: #fff; + border: 1px solid #a9a9a9; + user-select: all; +} +.text-warn{ + color: #d00; +} +.link-btn a{ + color: inherit; + text-decoration: none; + pointer-events: none; +} +.nowrap{ + white-space: nowrap; +} +@keyframes border-pulse{ + 0%{border-color: #ff0} + 50%{border-color: rgba(255, 255, 0, 0)} + 100%{border-color: #ff0} +} +@keyframes border-pulse2{ + 0%{border-color: #e29e06} + 50%{border-color: rgba(226, 158, 6, 0)} + 100%{border-color: #e29e06} +} +.settings-outer{ + background-size: 50vh; +} +.setting-box{ + display: flex; + height: 2em; + margin-top: 1.2em; + border: 0.25em solid #000; + border-radius: 0.5em; + padding: 0.3em; + outline: none; + color: #000; + cursor: pointer; +} +.setting-box:first-child{ + margin-top: 0; +} +.settings-outer .view-content:not(:hover) .setting-box.selected, +.view-outer:not(.settings-outer) .setting-box.selected, +.setting-box:hover{ + background: #ffb547; + animation: 2s linear border-pulse infinite; +} +.bold-fonts .setting-box{ + line-height: 1em; +} +.setting-name{ + position: relative; + width: 50%; + padding: 0.3em; + font-size: 1.3em; + box-sizing: border-box; +} +.view-content:not(:hover) .setting-box.selected .setting-name, +.view-outer:not(.settings-outer) .setting-box.selected .setting-name, +.setting-box:hover .setting-name{ + color: #fff; + z-index: 0; +} +.setting-name::before{ + padding-left: 0.3em; +} +.setting-value{ + display: flex; + background: #fff; + width: 50%; + border-radius: 0.2em; + padding: 0.5em; + box-sizing: border-box; +} +.setting-value.selected{ + width: calc(50% + 0.2em); + margin: -0.1em; + border: 0.2em solid #e29e06; + padding: 0.4em; + animation: 2s linear border-pulse2 infinite; +} +.setting-value>div{ + padding: 0 0.4em; + overflow: hidden; + text-overflow: ellipsis; +} +.shadow-outer{ + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 1; +} +#settings-gamepad{ + display: none; +} +#settings-gamepad .view{ + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 550px; + height: 417px; +} +#gamepad-bg{ + position: relative; + width: 550px; + height: 317px; + max-height: none; + background-repeat: none; + text-align: center; + font-size: 1.4em; + cursor: pointer; +} +#gamepad-buttons{ + position: absolute; + left: 141px; + top: 120px; + width: 282px; + height: 131px; + background-position: 0 -318px; + background-repeat: none; + pointer-events: none; +} diff --git a/public/src/js/about.js b/public/src/js/about.js index 95575b7..104d8a1 100644 --- a/public/src/js/about.js +++ b/public/src/js/about.js @@ -4,20 +4,20 @@ loader.changePage("about", true) cancelTouch = false - this.endButton = document.getElementById("tutorial-end-button") + this.endButton = this.getElement("view-end-button") this.diagTxt = document.getElementById("diag-txt") this.version = document.getElementById("version-link").href - this.tutorialOuter = document.getElementById("tutorial-outer") + this.tutorialOuter = this.getElement("view-outer") if(touchEnabled){ this.tutorialOuter.classList.add("touch-enabled") } this.linkIssues = document.getElementById("link-issues") this.linkEmail = document.getElementById("link-email") - var tutorialTitle = document.getElementById("tutorial-title") + var tutorialTitle = this.getElement("view-title") tutorialTitle.innerText = strings.aboutSimulator tutorialTitle.setAttribute("alt", strings.aboutSimulator) - var tutorialContent = document.getElementById("tutorial-content") + var tutorialContent = this.getElement("view-content") strings.about.bugReporting.forEach(string => { tutorialContent.appendChild(document.createTextNode(string)) tutorialContent.appendChild(document.createElement("br")) @@ -32,20 +32,18 @@ var versionUrl = gameConfig._version.url this.getLink(this.linkIssues).href = versionUrl + "issues" - var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], - previous: ["arrowleft", "arrowup", kbdSettings.ka_l[0]], - next: ["arrowright", "arrowdown", kbdSettings.ka_r[0]], - back: ["backspace", "escape"] - } pageEvents.add(this.linkIssues, ["click", "touchend"], this.linkButton.bind(this)) pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this)) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) - pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) this.items = [this.linkIssues, this.linkEmail, this.endButton] this.selected = 2 + this.keyboard = new Keyboard({ + confirm: ["enter", "space", "don_l", "don_r"], + previous: ["left", "up", "ka_l"], + next: ["right", "down", "ka_r"], + back: ["escape"] + }, this.keyPressed.bind(this)) this.gamepad = new Gamepad({ "confirm": ["b", "ls", "rs"], "previous": ["u", "l", "lb", "lt", "lsu", "lsl"], @@ -55,19 +53,8 @@ pageEvents.send("about", this.addDiag()) } - keyEvent(event){ - if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ - // Escape, Backspace, Tab - event.preventDefault() - } - if(!event.repeat){ - for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ - this.keyPressed(true, i) - break - } - } - } + getElement(name){ + return loader.screen.getElementsByClassName(name)[0] } keyPressed(pressed, name){ if(!pressed){ @@ -215,6 +202,7 @@ } clean(){ cancelTouch = true + this.keyboard.clean() this.gamepad.clean() pageEvents.remove(this.linkIssues, ["click", "touchend"]) pageEvents.remove(this.linkEmail, ["click", "touchend"]) diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 80b46f3..e363842 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -7,6 +7,7 @@ var assets = { "scoresheet.js", "songselect.js", "keyboard.js", + "gameinput.js", "game.js", "controller.js", "circle.js", @@ -36,7 +37,8 @@ var assets = { "loadsong.css", "game.css", "debug.css", - "songbg.css" + "songbg.css", + "view.css" ], "assetsCss": [ "fonts/fonts.css", @@ -79,7 +81,8 @@ var assets = { "results_flowers.png", "results_mikoshi.png", "results_tetsuohana.png", - "results_tetsuohana2.png" + "results_tetsuohana2.png", + "settings_gamepad.png" ], "audioSfx": [ "se_cancel.wav", diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 6e2baae..cf253b4 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -28,7 +28,7 @@ class Controller{ this.game = new Game(this, this.selectedSong, this.parsedSongData) this.view = new View(this) this.mekadon = new Mekadon(this, this.game) - this.keyboard = new Keyboard(this) + this.keyboard = new GameInput(this) this.playedSounds = {} } @@ -210,11 +210,8 @@ class Controller{ getKeys(){ return this.keyboard.getKeys() } - setKey(keyCode, down, ms){ - return this.keyboard.setKey(keyCode, down, ms) - } - getBindings(){ - return this.keyboard.getBindings() + setKey(pressed, name, ms){ + return this.keyboard.setKey(pressed, name, ms) } getElapsedTime(){ return this.game.elapsedTime diff --git a/public/src/js/debug.js b/public/src/js/debug.js index 844e8d1..a6fa9a7 100644 --- a/public/src/js/debug.js +++ b/public/src/js/debug.js @@ -202,11 +202,10 @@ class Debug{ this.controller.autoPlayEnabled = this.autoplayCheckbox.checked if(!this.controller.autoPlayEnabled){ var keyboard = debugObj.controller.keyboard - var kbd = keyboard.getBindings() - keyboard.setKey(kbd.don_l, false) - keyboard.setKey(kbd.don_r, false) - keyboard.setKey(kbd.ka_l, false) - keyboard.setKey(kbd.ka_r, false) + keyboard.setKey(false, "don_l") + keyboard.setKey(false, "don_r") + keyboard.setKey(false, "ka_l") + keyboard.setKey(false, "ka_r") } } } diff --git a/public/src/js/game.js b/public/src/js/game.js index 3417209..63a92b7 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -254,29 +254,28 @@ class Game{ return } var keys = this.controller.getKeys() - var kbd = this.controller.getBindings() - var don_l = keys[kbd["don_l"]] && !this.controller.isWaiting(kbd["don_l"], "score") - var don_r = keys[kbd["don_r"]] && !this.controller.isWaiting(kbd["don_r"], "score") - var ka_l = keys[kbd["ka_l"]] && !this.controller.isWaiting(kbd["ka_l"], "score") - var ka_r = keys[kbd["ka_r"]] && !this.controller.isWaiting(kbd["ka_r"], "score") + var don_l = keys["don_l"] && !this.controller.isWaiting("don_l", "score") + var don_r = keys["don_r"] && !this.controller.isWaiting("don_r", "score") + var ka_l = keys["ka_l"] && !this.controller.isWaiting("ka_l", "score") + var ka_r = keys["ka_r"] && !this.controller.isWaiting("ka_r", "score") var checkDon = () => { if(don_l && don_r){ - this.checkKey([kbd["don_l"], kbd["don_r"]], circle, "daiDon") + this.checkKey(["don_l", "don_r"], circle, "daiDon") }else if(don_l){ - this.checkKey([kbd["don_l"]], circle, "don") + this.checkKey(["don_l"], circle, "don") }else if(don_r){ - this.checkKey([kbd["don_r"]], circle, "don") + this.checkKey(["don_r"], circle, "don") } } var checkKa = () => { if(ka_l && ka_r){ - this.checkKey([kbd["ka_l"], kbd["ka_r"]], circle, "daiKa") + this.checkKey(["ka_l", "ka_r"], circle, "daiKa") }else if(ka_l){ - this.checkKey([kbd["ka_l"]], circle, "ka") + this.checkKey(["ka_l"], circle, "ka") }else if(ka_r){ - this.checkKey([kbd["ka_r"]], circle, "ka") + this.checkKey(["ka_r"], circle, "ka") } } var keyTime = this.controller.getKeyTime() diff --git a/public/src/js/gameinput.js b/public/src/js/gameinput.js new file mode 100644 index 0000000..4707652 --- /dev/null +++ b/public/src/js/gameinput.js @@ -0,0 +1,247 @@ +class GameInput{ + constructor(controller){ + this.controller = controller + this.game = this.controller.game + + this.keyboard = new Keyboard({ + ka_l: ["ka_l"], + don_l: ["don_l"], + don_r: ["don_r"], + ka_r: ["ka_r"], + pause: ["q", "esc"], + back: ["backspace"], + previous: ["left", "up"], + next: ["right", "down"], + confirm: ["enter", "space"] + }, this.keyPress.bind(this)) + this.keys = {} + this.waitKeyupScore = {} + this.waitKeyupSound = {} + this.waitKeyupMenu = {} + this.keyTime = { + "don": -Infinity, + "ka": -Infinity + } + this.keyboardEvents = 0 + + var layout = settings.getItem("gamepadLayout") + if(layout === "b"){ + var gameBtn = { + don_l: ["d", "r", "ls"], + don_r: ["a", "x", "rs"], + ka_l: ["u", "l", "lb", "lt"], + ka_r: ["b", "y", "rb", "rt"] + } + }else if(layout === "c"){ + var gameBtn = { + don_l: ["d", "l", "ls"], + don_r: ["a", "b", "rs"], + ka_l: ["u", "r", "lb", "lt"], + ka_r: ["x", "y", "rb", "rt"] + } + }else{ + var gameBtn = { + don_l: ["u", "d", "l", "r", "ls"], + don_r: ["a", "b", "x", "y", "rs"], + ka_l: ["lb", "lt"], + ka_r: ["rb", "rt"] + } + } + this.gamepad = new Gamepad(gameBtn) + this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2) + + this.gamepadMenu = new Gamepad({ + cancel: ["a"], + confirm: ["b", "ls", "rs"], + previous: ["u", "l", "lb", "lt", "lsu", "lsl"], + next: ["d", "r", "rb", "rt", "lsd", "lsr"], + pause: ["start"] + }) + + if(controller.multiplayer === 1){ + pageEvents.add(window, "beforeunload", event => { + if(p2.otherConnected){ + pageEvents.send("p2-abandoned", event) + } + }) + } + } + keyPress(pressed, name){ + if(!this.controller.autoPlayEnabled || this.game.isPaused() || name !== "don_l" && name !== "don_r" && name !== "ka_l" && name !== "ka_r"){ + this.setKey(pressed, name, this.game.getAccurateTime()) + } + } + checkGameKeys(){ + if(this.controller.autoPlayEnabled){ + this.checkKeySound("don_l", "don") + this.checkKeySound("don_r", "don") + this.checkKeySound("ka_l", "ka") + this.checkKeySound("ka_r", "ka") + } + } + gamepadKeys(){ + if(!this.game.isPaused() && !this.controller.autoPlayEnabled){ + this.gamepad.play((pressed, name) => { + if(pressed){ + if(this.keys[name]){ + this.setKey(false, name) + } + this.setKey(true, name, this.game.getAccurateTime()) + }else{ + this.setKey(false, name) + } + }) + } + } + checkMenuKeys(){ + if(!this.controller.multiplayer && !this.locked){ + var moveMenu = 0 + var ms = this.game.getAccurateTime() + this.gamepadMenu.play((pressed, name) => { + if(pressed){ + if(this.game.isPaused()){ + if(name === "cancel"){ + this.locked = true + return setTimeout(() => { + this.controller.togglePause() + this.locked = false + }, 200) + } + } + if(this.keys[name]){ + this.setKey(false, name) + } + this.setKey(true, name, ms) + }else{ + this.setKey(false, name) + } + }) + this.checkKey("pause", "menu", () => { + this.controller.togglePause() + for(var key in this.keyTime){ + this.keys[key] = null + this.keyTime[key] = -Infinity + } + }) + var moveMenuMinus = () => { + moveMenu = -1 + } + var moveMenuPlus = () => { + moveMenu = 1 + } + var moveMenuConfirm = () => { + if(this.game.isPaused()){ + this.locked = true + setTimeout(() => { + this.controller.view.pauseConfirm() + this.locked = false + }, 200) + } + } + this.checkKey("previous", "menu", moveMenuMinus) + this.checkKey("ka_l", "menu", moveMenuMinus) + this.checkKey("next", "menu", moveMenuPlus) + this.checkKey("ka_r", "menu", moveMenuPlus) + this.checkKey("confirm", "menu", moveMenuConfirm) + this.checkKey("don_l", "menu", moveMenuConfirm) + this.checkKey("don_r", "menu", moveMenuConfirm) + if(moveMenu && this.game.isPaused()){ + assets.sounds["se_ka"].play() + this.controller.view.pauseMove(moveMenu) + } + } + if(this.controller.multiplayer !== 2){ + this.checkKey("back", "menu", () => { + if(this.controller.multiplayer === 1 && p2.otherConnected){ + p2.send("gameend") + pageEvents.send("p2-abandoned") + } + this.controller.togglePause() + this.controller.songSelection() + }) + } + } + checkKey(name, type, callback){ + if(this.keys[name] && !this.isWaiting(name, type)){ + this.waitForKeyup(name, type) + callback() + } + } + checkKeySound(name, sound){ + this.checkKey(name, "sound", () => { + var circles = this.controller.getCircles() + var circle = circles[this.controller.getCurrentCircle()] + var currentTime = this.keyTime[name] + this.keyTime[sound] = currentTime + if(circle && !circle.isPlayed){ + if(circle.type === "balloon"){ + if(sound === "don" && circle.requiredHits - circle.timesHit <= 1){ + this.controller.playSound("se_balloon") + return + } + } + } + this.controller.playSound("neiro_1_" + sound) + }) + } + getKeys(){ + return this.keys + } + setKey(pressed, name, ms){ + if(pressed){ + this.keys[name] = true + this.waitKeyupScore[name] = false + this.waitKeyupSound[name] = false + this.waitKeyupMenu[name] = false + if(this.game.isPaused()){ + return + } + this.keyTime[name] = ms + if(name == "don_l" || name == "don_r"){ + this.checkKeySound(name, "don") + this.keyboardEvents++ + }else if(name == "ka_l" || name == "ka_r"){ + this.checkKeySound(name, "ka") + this.keyboardEvents++ + } + }else{ + this.keys[name] = false + this.waitKeyupScore[name] = false + this.waitKeyupSound[name] = false + this.waitKeyupMenu[name] = false + } + } + isWaiting(name, type){ + if(type === "score"){ + return this.waitKeyupScore[name] + }else if(type === "sound"){ + return this.waitKeyupSound[name] + }else if(type === "menu"){ + return this.waitKeyupMenu[name] + } + } + waitForKeyup(name, type){ + if(!this.keys[name]){ + return + } + if(type === "score"){ + this.waitKeyupScore[name] = true + }else if(type === "sound"){ + this.waitKeyupSound[name] = true + }else if(type === "menu"){ + this.waitKeyupMenu[name] = true + } + } + getKeyTime(){ + return this.keyTime + } + clean(){ + this.keyboard.clean() + this.gamepad.clean() + this.gamepadMenu.clean() + clearInterval(this.gamepadInterval) + if(this.controller.multiplayer === 1){ + pageEvents.remove(window, "beforeunload") + } + } +} diff --git a/public/src/js/gamepad.js b/public/src/js/gamepad.js index 2956c1a..a4b3327 100644 --- a/public/src/js/gamepad.js +++ b/public/src/js/gamepad.js @@ -1,6 +1,7 @@ class Gamepad{ constructor(bindings, callback){ this.bindings = bindings + this.callback = !!callback this.b = { "a": 0, "b": 1, @@ -87,6 +88,9 @@ class Gamepad{ for(var name in bindings[bind]){ var bindName = bindings[bind][name] this.checkButton(gamepads, this.b[bindName], bind, callback, force[bindName]) + if(!this.b){ + return + } } } break @@ -136,6 +140,11 @@ class Gamepad{ } } clean(){ - clearInterval(this.interval) + if(this.callback){ + clearInterval(this.interval) + } + delete this.bindings + delete this.b + delete this.btn } } diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index f038a44..949673b 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -1,266 +1,105 @@ class Keyboard{ - constructor(controller){ - this.controller = controller - this.game = this.controller.game - + constructor(bindings, callback){ + this.bindings = bindings + this.callback = callback + this.wildcard = false + this.substitute = { + "up": "arrowup", + "right": "arrowright", + "down": "arrowdown", + "left": "arrowleft", + "space": " ", + "esc": "escape", + "ctrl": "control", + "altgr": "altgraph" + } + this.btn = {} + this.update() + pageEvents.keyAdd(this, "all", "both", this.keyEvent.bind(this)) + pageEvents.blurAdd(this, this.blurEvent.bind(this)) + } + update(){ var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - "ka_l": kbdSettings.ka_l[0], - "don_l": kbdSettings.don_l[0], - "don_r": kbdSettings.don_r[0], - "ka_r": kbdSettings.ka_r[0], - "pause": "q", - "back": "backspace", - "previous": "arrowleft", - "next": "arrowright", - "confirm": "enter" - } - this.kbdAlias = { - "pause": ["escape"], - "previous": ["arrowup"], - "next": ["arrowdown"], - "confirm": [" "] - } - this.keys = {} - this.waitKeyupScore = {} - this.waitKeyupSound = {} - this.waitKeyupMenu = {} - this.keyTime = { - "don": -Infinity, - "ka": -Infinity - } - this.keyboardEvents = 0 - - var gameBtn = {} - gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] - gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] - gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] - gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] - this.gamepad = new Gamepad(gameBtn) - this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2) - - var menuBtn = { - "cancel": ["a"], - } - menuBtn[this.kbd["confirm"]] = ["b", "ls", "rs"] - menuBtn[this.kbd["previous"]] = ["u", "l", "lb", "lt", "lsu", "lsl"], - menuBtn[this.kbd["next"]] = ["d", "r", "rb", "rt", "lsd", "lsr"] - menuBtn[this.kbd["pause"]] = ["start"] - this.gamepadMenu = new Gamepad(menuBtn) - - this.kbdSearch = {} - for(var name in this.kbdAlias){ - var list = this.kbdAlias[name] - for(var i in list){ - this.kbdSearch[list[i]] = this.kbd[name] + var drumKeys = {} + for(var name in kbdSettings){ + var keys = kbdSettings[name] + for(var i in keys){ + drumKeys[keys[i]] = name } } - for(var name in this.kbd){ - this.kbdSearch[this.kbd[name]] = this.kbd[name] - } - - pageEvents.keyAdd(this, "all", "both", event => { - if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ - // Escape, Backspace, Tab - event.preventDefault() - } - var key = this.kbdSearch[event.key.toLowerCase()] - if(key && !event.repeat && this.buttonEnabled(key)){ - var ms = this.game.getAccurateTime() - this.setKey(key, event.type === "keydown", ms) - if(event.type === "keydown"){ - this.keyboardEvents++ + this.kbd = {} + for(var name in this.bindings){ + var keys = this.bindings[name] + for(var i in keys){ + var key = keys[i] + if(key in drumKeys){ + continue } - } - }) - - if(controller.multiplayer === 1){ - pageEvents.add(window, "beforeunload", event => { - if(p2.otherConnected){ - pageEvents.send("p2-abandoned", event) - } - }) - } - } - getBindings(){ - return this.kbd - } - buttonEnabled(keyCode){ - if(this.controller.autoPlayEnabled){ - switch(keyCode){ - case this.kbd["don_l"]: - case this.kbd["don_r"]: - case this.kbd["ka_l"]: - case this.kbd["ka_r"]: - return false - } - } - return true - } - checkGameKeys(){ - if(this.controller.autoPlayEnabled){ - this.checkKeySound(this.kbd["don_l"], "don") - this.checkKeySound(this.kbd["don_r"], "don") - this.checkKeySound(this.kbd["ka_l"], "ka") - this.checkKeySound(this.kbd["ka_r"], "ka") - } - } - gamepadKeys(){ - if(!this.game.isPaused() && !this.controller.autoPlayEnabled){ - this.gamepad.play((pressed, keyCode) => { - if(pressed){ - if(this.keys[keyCode]){ - this.setKey(keyCode, false) - } - this.setKey(keyCode, true, this.game.getAccurateTime()) - }else{ - this.setKey(keyCode, false) - } - }) - } - } - checkMenuKeys(){ - if(!this.controller.multiplayer && !this.locked){ - var moveMenu = 0 - var ms = this.game.getAccurateTime() - this.gamepadMenu.play((pressed, keyCode) => { - if(pressed){ - if(this.game.isPaused()){ - if(keyCode === "cancel"){ - this.locked = true - return setTimeout(() => { - this.controller.togglePause() - this.locked = false - }, 200) + if(key in kbdSettings){ + var keyArray = kbdSettings[key] + for(var j in keyArray){ + key = keyArray[j] + if(!(key in this.kbd)){ + this.kbd[key] = name } } - if(this.keys[keyCode]){ - this.setKey(keyCode, false) - } - this.setKey(keyCode, true, ms) }else{ - this.setKey(keyCode, false) - } - }) - this.checkKey(this.kbd["pause"], "menu", () => { - this.controller.togglePause() - for(var key in this.keyTime){ - this.keys[key] = null - this.keyTime[key] = -Infinity - } - }) - var moveMenuMinus = () => { - moveMenu = -1 - } - var moveMenuPlus = () => { - moveMenu = 1 - } - var moveMenuConfirm = () => { - if(this.game.isPaused()){ - this.locked = true - setTimeout(() => { - this.controller.view.pauseConfirm() - this.locked = false - }, 200) - } - } - this.checkKey(this.kbd["previous"], "menu", moveMenuMinus) - this.checkKey(this.kbd["ka_l"], "menu", moveMenuMinus) - this.checkKey(this.kbd["next"], "menu", moveMenuPlus) - this.checkKey(this.kbd["ka_r"], "menu", moveMenuPlus) - this.checkKey(this.kbd["confirm"], "menu", moveMenuConfirm) - this.checkKey(this.kbd["don_l"], "menu", moveMenuConfirm) - this.checkKey(this.kbd["don_r"], "menu", moveMenuConfirm) - if(moveMenu && this.game.isPaused()){ - assets.sounds["se_ka"].play() - this.controller.view.pauseMove(moveMenu) - } - } - if(this.controller.multiplayer !== 2){ - this.checkKey(this.kbd["back"], "menu", () => { - if(this.controller.multiplayer === 1 && p2.otherConnected){ - p2.send("gameend") - pageEvents.send("p2-abandoned") - } - this.controller.togglePause() - this.controller.songSelection() - }) - } - } - 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.getCircles() - var circle = circles[this.controller.getCurrentCircle()] - var currentTime = this.keyTime[keyCode] - this.keyTime[sound] = currentTime - if(circle && !circle.isPlayed){ - if(circle.type === "balloon"){ - if(sound === "don" && circle.requiredHits - circle.timesHit <= 1){ - this.controller.playSound("se_balloon") - return + if(key in this.substitute){ + key = this.substitute[key] + } + if(!(key in this.kbd)){ + if(key === "wildcard"){ + this.wildcard = true + } + this.kbd[key] = name } } } - this.controller.playSound("neiro_1_" + sound) - }) + } } - getKeys(){ - return this.keys - } - setKey(keyCode, down, ms){ - if(down){ - this.keys[keyCode] = true - if(this.game.isPaused()){ - return + keyEvent(event){ + var key = event.key.toLowerCase() + if(key === "escape" || key === "backspace" || key === "tab"){ + event.preventDefault() + } + if(!event.repeat){ + var pressed = event.type === "keydown" + if(pressed){ + this.btn[key] = true + }else{ + delete this.btn[key] + if(key in this.kbd){ + for(var i in this.btn){ + if(this.kbd[i] === this.kbd[key]){ + return + } + } + } } - this.keyTime[keyCode] = ms - if(keyCode == this.kbd.don_l || keyCode == this.kbd.don_r){ - this.checkKeySound(keyCode, "don") - }else if(keyCode == this.kbd.ka_l || keyCode == this.kbd.ka_r){ - this.checkKeySound(keyCode, "ka") + if(key in this.kbd){ + this.callback(pressed, this.kbd[key], event) + }else if(this.wildcard){ + this.callback(pressed, this.kbd["wildcard"], event) } - }else{ - this.keys[keyCode] = false - this.waitKeyupScore[keyCode] = false - this.waitKeyupSound[keyCode] = false - this.waitKeyupMenu[keyCode] = false } } - isWaiting(keyCode, type){ - if(type === "score"){ - return this.waitKeyupScore[keyCode] - }else if(type === "sound"){ - return this.waitKeyupSound[keyCode] - }else if(type === "menu"){ - return this.waitKeyupMenu[keyCode] + blurEvent(){ + for(var key in this.btn){ + if(this.btn[key]){ + delete this.btn[key] + var name = this.kbd[key] || (this.wildcard ? "wildcard" : false) + if(name){ + this.callback(false, name) + } + } } } - waitForKeyup(keyCode, type){ - if(!this.keys[keyCode]){ - return - } - if(type === "score"){ - this.waitKeyupScore[keyCode] = true - }else if(type === "sound"){ - this.waitKeyupSound[keyCode] = true - }else if(type === "menu"){ - this.waitKeyupMenu[keyCode] = true - } - } - getKeyTime(){ - return this.keyTime - } clean(){ pageEvents.keyRemove(this, "all") - clearInterval(this.gamepadInterval) - if(this.controller.multiplayer === 1){ - pageEvents.remove(window, "beforeunload") - } + pageEvents.blurRemove(this) + delete this.bindings + delete this.callback + delete this.kbd + delete this.btn } } diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index eff1537..a58247e 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -50,7 +50,6 @@ class Mekadon{ } } playNow(circle, score, dai, reverse){ - var kbd = this.controller.getBindings() var type = circle.type var keyDai = false var playDai = !dai || dai === 2 @@ -70,20 +69,20 @@ class Mekadon{ } } if(type === "daiDon" && playDai){ - this.setKey(kbd["don_l"], ms) - this.setKey(kbd["don_r"], ms) + this.setKey("don_l", ms) + this.setKey("don_r", ms) this.lr = false keyDai = true }else if(type === "don" || type === "daiDon" || drumrollNotes && score !== 2){ - this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"], ms) + this.setKey(this.lr ? "don_l" : "don_r", ms) this.lr = !this.lr }else if(type === "daiKa" && playDai){ - this.setKey(kbd["ka_l"], ms) - this.setKey(kbd["ka_r"], ms) + this.setKey("ka_l", ms) + this.setKey("ka_r", ms) this.lr = false keyDai = true }else if(type === "ka" || type === "daiKa" || drumrollNotes){ - this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"], ms) + this.setKey(this.lr ? "ka_l" : "ka_r", ms) this.lr = !this.lr } if(type === "balloon"){ @@ -110,8 +109,7 @@ class Mekadon{ getMS(){ return this.controller.getElapsedTime() } - setKey(keyCode, ms){ - this.controller.setKey(keyCode, false) - this.controller.setKey(keyCode, true, ms) + setKey(name, ms){ + this.controller.setKey(true, name, ms) } } diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index c180802..c8c0af7 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -3,10 +3,12 @@ class PageEvents{ this.allEvents = new Map() this.keyListeners = new Map() this.mouseListeners = new Map() + this.blurListeners = new Map() this.lastKeyEvent = -Infinity this.add(window, "keydown", this.keyEvent.bind(this)) this.add(window, "keyup", this.keyEvent.bind(this)) this.add(window, "mousemove", this.mouseEvent.bind(this)) + this.add(window, "blur", this.blurEvent.bind(this)) this.kbd = [] } add(target, type, callback){ @@ -142,6 +144,15 @@ class PageEvents{ mouseRemove(target){ this.mouseListeners.delete(target) } + blurEvent(event){ + this.blurListeners.forEach(callback => callback(event)) + } + blurAdd(target, callback){ + this.blurListeners.set(target, callback) + } + blurRemove(target){ + this.blurListeners.delete(target) + } getMouse(){ return this.lastMouse } @@ -149,12 +160,13 @@ class PageEvents{ dispatchEvent(new CustomEvent(name, {detail: detail})) } setKbd(){ + this.kbd = [] var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = [ - kbdSettings.ka_l[0], - kbdSettings.don_l[0], - kbdSettings.don_r[0], - kbdSettings.ka_r[0] - ] + for(var name in kbdSettings){ + var keys = kbdSettings[name] + for(var i in keys){ + this.kbd.push(keys[i]) + } + } } } diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 4d0360c..24fde5d 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -31,13 +31,12 @@ class Scoresheet{ this.draw = new CanvasDraw() this.canvasCache = new CanvasCache() - var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - confirm: ["enter", " ", "escape", "backspace", kbdSettings.don_l[0], kbdSettings.don_r[0]] - } + this.keyboard = new Keyboard({ + confirm: ["enter", "space", "esc", "don_l", "don_r"] + }, this.keyDown.bind(this)) this.gamepad = new Gamepad({ confirm: ["a", "b", "start", "ls", "rs"] - }) + }, this.keyDown.bind(this)) this.difficulty = { "easy": 0, @@ -76,22 +75,8 @@ class Scoresheet{ touchEvents: controller.view.touchEvents }) } - keyDown(event, key){ - if(!key){ - if(event.repeat){ - return - } - for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ - key = i - break - } - } - } - if(event && event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ - event.preventDefault() - } - if(key === "confirm"){ + keyDown(pressed){ + if(pressed && this.redrawing){ this.toNext() } } @@ -140,7 +125,6 @@ class Scoresheet{ this.winW = null this.winH = null - pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this)) if(!this.multiplayer){ @@ -180,12 +164,6 @@ class Scoresheet{ } var ms = this.getMS() - this.gamepad.play((pressed, keyCode) => { - if(pressed){ - this.keyDown(false, keyCode) - } - }) - if(!this.redrawRunning){ return } @@ -864,12 +842,13 @@ class Scoresheet{ } clean(){ + this.keyboard.clean() + this.gamepad.clean() this.draw.clean() this.canvasCache.clean() assets.sounds["bgm_result"].stop() snd.buffer.loadSettings() this.redrawRunning = false - pageEvents.keyRemove(this, "all") pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) if(this.multiplayer !== 2 && this.touchEnabled){ pageEvents.remove(document.getElementById("touch-full-btn"), "touchend") diff --git a/public/src/js/session.js b/public/src/js/session.js index 43efa9e..0f08c67 100644 --- a/public/src/js/session.js +++ b/public/src/js/session.js @@ -2,13 +2,13 @@ class Session{ constructor(touchEnabled){ this.touchEnabled = touchEnabled loader.changePage("session", true) - this.endButton = document.getElementById("tutorial-end-button") + this.endButton = this.getElement("view-end-button") if(touchEnabled){ - document.getElementById("tutorial-outer").classList.add("touch-enabled") + this.getElement("view-outer").classList.add("touch-enabled") } this.sessionInvite = document.getElementById("session-invite") - var tutorialTitle = document.getElementById("tutorial-title") + var tutorialTitle = this.getElement("view-title") tutorialTitle.innerText = strings.session.multiplayerSession tutorialTitle.setAttribute("alt", strings.session.multiplayerSession) this.sessionInvite.parentNode.insertBefore(document.createTextNode(strings.session.linkTutorial), this.sessionInvite) @@ -16,11 +16,12 @@ class Session{ this.endButton.setAttribute("alt", strings.session.cancel) pageEvents.add(window, ["mousedown", "touchstart"], this.mouseDown.bind(this)) - pageEvents.keyOnce(this, 27, "down").then(this.onEnd.bind(this)) - + this.keyboard = new Keyboard({ + confirm: ["esc"] + }, this.keyPress.bind(this)) this.gamepad = new Gamepad({ - "confirm": ["start", "b", "ls", "rs"] - }, this.onEnd.bind(this)) + confirm: ["start", "b", "ls", "rs"] + }, this.keyPress.bind(this)) p2.hashLock = true pageEvents.add(p2, "message", response => { @@ -29,13 +30,16 @@ class Session{ p2.hash(response.value) }else if(response.type === "songsel"){ p2.clearMessage("users") - this.onEnd(false, true) + this.onEnd(true) pageEvents.send("session-start", "host") } }) p2.send("invite") pageEvents.send("session") } + getElement(name){ + return loader.screen.getElementsByClassName(name)[0] + } mouseDown(event){ if(event.type === "mousedown" && event.which !== 1){ return @@ -50,7 +54,12 @@ class Session{ this.onEnd() } } - onEnd(event, fromP2){ + keyPress(pressed){ + if(pressed){ + this.onEnd() + } + } + onEnd(fromP2){ if(!p2.session){ p2.send("leave") p2.hash("") @@ -59,9 +68,6 @@ class Session{ }else if(!fromP2){ return p2.send("songsel") } - if(event && event.type === "keydown"){ - event.preventDefault() - } this.clean() assets.sounds["se_don"].play() setTimeout(() => { @@ -69,9 +75,9 @@ class Session{ }, 500) } clean(){ + this.keyboard.clean() this.gamepad.clean() pageEvents.remove(window, ["mousedown", "touchstart"]) - pageEvents.keyRemove(this, 27) pageEvents.remove(p2, "message") delete this.endButton delete this.sessionInvite diff --git a/public/src/js/settings.js b/public/src/js/settings.js index d17c92b..572d1ae 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -28,6 +28,12 @@ class Settings{ ka_r: ["k"] }, touch: false + }, + gamepadLayout: { + type: "gamepad", + options: ["a", "b", "c"], + default: "a", + gamepad: true } } @@ -42,7 +48,7 @@ class Settings{ this.storage[i] = null } }else if(i in storage){ - if(current.type === "select" && current.options.indexOf(storage[i]) === -1){ + if((current.type === "select" || current.type === "gamepad") && current.options.indexOf(storage[i]) === -1){ this.storage[i] = null }else if(current.type === "keyboard"){ var obj = {} @@ -116,29 +122,50 @@ class Settings{ } class SettingsView{ - constructor(touchEnabled, tutorial){ + constructor(touchEnabled, tutorial, songId){ this.touchEnabled = touchEnabled this.tutorial = tutorial - if(!tutorial){ - loader.changePage("settings", tutorial) - assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) - this.defaultButton = document.getElementById("settings-default") - }else if(touchEnabled){ - document.getElementById("tutorial-outer").classList.add("settings-outer") - } + this.songId = songId + + loader.changePage("settings", tutorial) + assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992) + this.defaultButton = document.getElementById("settings-default") if(touchEnabled){ - document.getElementById("tutorial-outer").classList.add("touch-enabled") + this.getElement("view-outer").classList.add("touch-enabled") + } + var gamepadEnabled = false + if("getGamepads" in navigator){ + var gamepads = navigator.getGamepads() + for(var i = 0; i < gamepads.length; i++){ + if(gamepads[i]){ + gamepadEnabled = true + break + } + } } this.mode = "settings" - this.tutorialTitle = document.getElementById("tutorial-title") - this.endButton = document.getElementById("tutorial-end-button") - if(!tutorial){ - this.setStrings() - } + this.keyboard = new Keyboard({ + "confirm": ["enter", "space", "don_l", "don_r"], + "up": ["up"], + "previous": ["left", "ka_l"], + "next": ["right", "down", "ka_r"], + "back": ["esc"], + "other": ["wildcard"] + }, this.keyPressed.bind(this)) + this.gamepad = new Gamepad({ + "confirm": ["b", "ls", "rs"], + "up": ["u", "lsu"], + "previous": ["l", "lb", "lt", "lsl"], + "next": ["d", "r", "rb", "rt", "lsd", "lsr"], + "back": ["start", "a"] + }, this.keyPressed.bind(this)) + + this.viewTitle = this.getElement("view-title") + this.endButton = this.getElement("view-end-button") this.resolution = settings.getItem("resolution") - var content = document.getElementById("tutorial-content") + var content = this.getElement("view-content") this.items = [] this.selected = tutorial ? 1 : 0 for(let i in settings.items){ @@ -146,6 +173,7 @@ class SettingsView{ if( !touchEnabled && current.touch === true || touchEnabled && current.touch === false || + !gamepadEnabled && current.gamepad === true || tutorial && current.type !== "language" ){ continue @@ -166,12 +194,7 @@ class SettingsView{ if(this.items.length === this.selected){ settingBox.classList.add("selected") } - pageEvents.add(settingBox, ["mousedown", "touchstart"], event => { - if(event.type !== "mousedown" || event.which === 1){ - event.preventDefault() - this.setValue(i) - } - }) + this.addTouch(settingBox, event => this.setValue(i)) this.items.push({ id: i, settingBox: settingBox, @@ -179,58 +202,82 @@ class SettingsView{ valueDiv: valueDiv }) } - if(!tutorial){ + if(tutorial){ + this.defaultButton.style.display = "none" + this.endButton.classList.add("selected") + }else{ this.items.push({ id: "default", settingBox: this.defaultButton }) - pageEvents.add(this.defaultButton, ["mousedown", "touchstart"], this.defaultSettings.bind(this)) + this.addTouch(this.defaultButton, this.defaultSettings.bind(this)) } this.items.push({ id: "back", settingBox: this.endButton }) + this.addTouch(this.endButton, this.onEnd.bind(this)) - this.setKbd() - pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) - pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this)) - this.gamepad = new Gamepad({ - "confirm": ["b", "ls", "rs"], - "up": ["u", "lsu"], - "previous": ["l", "lb", "lt", "lsl"], - "next": ["d", "r", "rb", "rt", "lsd", "lsr"], - "back": ["start", "a"] - }, this.keyPressed.bind(this)) - if(!tutorial){ - pageEvents.send("settings") - } + this.gamepadSettings = document.getElementById("settings-gamepad") + this.addTouch(this.gamepadSettings, event => { + if(event.target === event.currentTarget){ + this.gamepadBack() + } + }) + this.gamepadTitle = this.gamepadSettings.getElementsByClassName("view-title")[0] + this.gamepadEndButton = this.gamepadSettings.getElementsByClassName("view-end-button")[0] + this.addTouch(this.gamepadEndButton, event => this.gamepadBack(true)) + this.gamepadBg = document.getElementById("gamepad-bg") + this.addTouch(this.gamepadBg, event => this.gamepadSet(1)) + this.gamepadButtons = document.getElementById("gamepad-buttons") + this.gamepadValue = document.getElementById("gamepad-value") + + this.setStrings() + + pageEvents.send("settings") } - setKbd(){ - var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - "confirm": ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], - "up": ["arrowup"], - "previous": ["arrowleft", kbdSettings.ka_l[0]], - "next": ["arrowright", "arrowdown", kbdSettings.ka_r[0]], - "back": ["backspace", "escape"] - } + getElement(name){ + return loader.screen.getElementsByClassName(name)[0] + } + addTouch(element, callback){ + pageEvents.add(element, ["mousedown", "touchstart"], event => { + if(event.type === "touchstart"){ + event.preventDefault() + this.touched = true + }else if(event.which !== 1){ + return + }else{ + this.touched = false + } + callback(event) + }) + } + removeTouch(element){ + pageEvents.remove(element, ["mousedown", "touchstart"]) } getValue(name, valueDiv){ var current = settings.items[name] var value = settings.getItem(name) if(current.type === "language"){ value = allStrings[value].name + " (" + value + ")" - }else if(current.type === "select"){ + }else if(current.type === "select" || current.type === "gamepad"){ value = strings.settings[name][value] }else if(current.type === "toggle"){ value = value ? strings.settings.on : strings.settings.off }else if(current.type === "keyboard"){ valueDiv.innerHTML = "" for(var i in value){ - var key = document.createElement("div") - key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" - key.innerText = value[i][0].toUpperCase() - valueDiv.appendChild(key) + var keyDiv = document.createElement("div") + keyDiv.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" + var key = value[i][0] + for(var j in this.keyboard.substitute){ + if(this.keyboard.substitute[j] === key){ + key = j + break + } + } + keyDiv.innerText = key.toUpperCase() + valueDiv.appendChild(keyDiv) } return } @@ -264,6 +311,12 @@ class SettingsView{ this.keyboardSet() assets.sounds["se_don"].play() return + }else if(current.type === "gamepad"){ + this.mode = "gamepad" + this.gamepadSelected = current.options.indexOf(value) + this.gamepadSet() + assets.sounds["se_don"].play() + return } settings.setItem(name, value) this.getValue(name, this.items[this.selected].valueDiv) @@ -272,37 +325,11 @@ class SettingsView{ this.setLang(allStrings[value]) } } - keyEvent(event){ - if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){ - // Escape, Backspace, Tab - event.preventDefault() - } - if(!event.repeat){ - for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ - if(this.mode !== "keyboard" || i === "back"){ - this.keyPressed(true, i) - return - } - } - } - if(this.mode === "keyboard"){ - event.preventDefault() - var currentKey = event.key.toLowerCase() - for(var i in this.keyboardKeys){ - if(this.keyboardKeys[i][0] === currentKey || !currentKey){ - return - } - } - this.keyboardKeys[this.keyboardCurrent] = [currentKey] - this.keyboardSet() - } - } - } - keyPressed(pressed, name){ + keyPressed(pressed, name, event){ if(!pressed){ return } + this.touched = false var selected = this.items[this.selected] if(this.mode === "settings"){ if(name === "confirm"){ @@ -325,9 +352,30 @@ class SettingsView{ }else if(name === "back"){ this.onEnd() } + }else if(this.mode === "gamepad"){ + if(name === "confirm"){ + this.gamepadBack(true) + }else if(name === "up" || name === "previous" || name === "next"){ + this.gamepadSet(name === "next" ? 1 : -1) + }else if(name === "back"){ + this.gamepadBack() + } }else if(this.mode === "keyboard"){ if(name === "back"){ this.keyboardBack(selected) + assets.sounds["se_cancel"].play() + }else{ + event.preventDefault() + var currentKey = event.key.toLowerCase() + for(var i in this.keyboardKeys){ + if(this.keyboardKeys[i][0] === currentKey || !currentKey){ + return + } + } + var current = this.keyboardCurrent + assets.sounds[current === "ka_l" || current === "ka_r" ? "se_ka" : "se_don"].play() + this.keyboardKeys[current] = [currentKey] + this.keyboardSet() } } } @@ -336,21 +384,28 @@ class SettingsView{ var current = settings.items[selected.id] selected.valueDiv.innerHTML = "" for(var i in current.default){ - var key = document.createElement("div") - key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" + var keyDiv = document.createElement("div") + keyDiv.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10" if(this.keyboardKeys[i]){ - key.innerText = this.keyboardKeys[i][0].toUpperCase() - selected.valueDiv.appendChild(key) + var key = this.keyboardKeys[i][0] + for(var j in this.keyboard.substitute){ + if(this.keyboard.substitute[j] === key){ + key = j + break + } + } + keyDiv.innerText = key.toUpperCase() + selected.valueDiv.appendChild(keyDiv) }else{ - key.innerText = "[" + strings.settings[selected.id][i] + "]" - selected.valueDiv.appendChild(key) + keyDiv.innerText = "[" + strings.settings[selected.id][i] + "]" + selected.valueDiv.appendChild(keyDiv) this.keyboardCurrent = i return } } settings.setItem(selected.id, this.keyboardKeys) this.keyboardBack(selected) - this.setKbd() + this.keyboard.update() pageEvents.setKbd() } keyboardBack(selected){ @@ -359,10 +414,38 @@ class SettingsView{ selected.valueDiv.classList.remove("selected") this.getValue(selected.id, selected.valueDiv) } - defaultSettings(event){ - if(event && event.type === "touchstart"){ - event.preventDefault() + gamepadSet(diff){ + if(this.mode !== "gamepad"){ + return } + var selected = this.items[this.selected] + var current = settings.items[selected.id] + if(diff){ + this.gamepadSelected = this.mod(current.options.length, this.gamepadSelected + diff) + assets.sounds["se_ka"].play() + } + var opt = current.options[this.gamepadSelected] + this.gamepadValue.innerText = strings.settings[selected.id][opt] + this.gamepadButtons.style.backgroundPosition = "0 " + (-318 - 132 * this.gamepadSelected) + "px" + this.gamepadSettings.style.display = "block" + } + gamepadBack(save){ + if(this.mode !== "gamepad"){ + return + } + if(save){ + var selected = this.items[this.selected] + var current = settings.items[selected.id] + settings.setItem(selected.id, current.options[this.gamepadSelected]) + this.getValue(selected.id, selected.valueDiv) + assets.sounds["se_don"].play() + }else{ + assets.sounds["se_cancel"].play() + } + this.gamepadSettings.style.display = "" + this.mode = "settings" + } + defaultSettings(){ if(this.mode === "keyboard"){ this.keyboardBack(this.items[this.selected]) } @@ -370,27 +453,19 @@ class SettingsView{ settings.setItem(i, null) } this.setLang(allStrings[settings.getItem("language")]) - this.setKbd() + this.keyboard.update() + pageEvents.setKbd() assets.sounds["se_don"].play() } - onEnd(event){ - if(this.tutorial){ - this.clean() - return this.tutorial.onEnd(event) - } - var touched = false - if(event){ - if(event.type === "touchstart"){ - event.preventDefault() - touched = true - }else if(event.which !== 1){ - return - } - } + onEnd(){ this.clean() assets.sounds["se_don"].play() setTimeout(() => { - new SongSelect("settings", false, touched) + if(this.tutorial && !this.touched){ + new Tutorial(false, this.songId) + }else{ + new SongSelect(this.tutorial ? false : "settings", false, this.touched, this.songId) + } }, 500) } setLang(lang){ @@ -410,33 +485,44 @@ class SettingsView{ this.setStrings() } setStrings(){ - if(this.tutorial){ - this.tutorial.setStrings() - }else{ - this.tutorialTitle.innerText = strings.gameSettings - this.tutorialTitle.setAttribute("alt", strings.gameSettings) + this.viewTitle.innerText = strings.gameSettings + this.viewTitle.setAttribute("alt", strings.gameSettings) + this.endButton.innerText = strings.settings.ok + this.endButton.setAttribute("alt", strings.settings.ok) + this.gamepadTitle.innerText = strings.settings.gamepadLayout.name + this.gamepadTitle.setAttribute("alt", strings.settings.gamepadLayout.name) + this.gamepadEndButton.innerText = strings.settings.ok + this.gamepadEndButton.setAttribute("alt", strings.settings.ok) + if(!this.tutorial){ this.defaultButton.innerText = strings.settings.default this.defaultButton.setAttribute("alt", strings.settings.default) - this.endButton.innerText = strings.settings.ok - this.endButton.setAttribute("alt", strings.settings.ok) } } mod(length, index){ return ((index % length) + length) % length } clean(){ + this.keyboard.clean() this.gamepad.clean() assets.sounds["bgm_settings"].stop() - pageEvents.keyRemove(this, "all") for(var i in this.items){ - pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"]) + this.removeTouch(this.items[i].settingBox) } if(this.defaultButton){ delete this.defaultButton } + this.removeTouch(this.gamepadSettings) + this.removeTouch(this.gamepadEndButton) + this.removeTouch(this.gamepadBg) delete this.tutorialTitle delete this.endButton delete this.items + delete this.gamepadSettings + delete this.gamepadTitle + delete this.gamepadEndButton + delete this.gamepadBg + delete this.gamepadButtons + delete this.gamepadValue if(this.resolution !== settings.getItem("resolution")){ for(var i in assets.image){ if(i === "touch_drum" || i.startsWith("bg_song_") || i.startsWith("bg_stage_") || i.startsWith("bg_don_")){ diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index ea7ba1b..f50dbc1 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -289,16 +289,17 @@ class SongSelect{ this.startPreview(true) this.pressedKeys = {} - var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]], + this.keyboard = new Keyboard({ + confirm: ["enter", "space", "don_l", "don_r"], back: ["escape"], - left: ["arrowleft", kbdSettings.ka_l[0]], - right: ["arrowright", kbdSettings.ka_r[0]], - up: ["arrowup"], - down: ["arrowdown"], - session: ["backspace"] - } + left: ["left", "ka_l"], + right: ["right", "ka_r"], + up: ["up"], + down: ["down"], + session: ["backspace"], + ctrl: ["ctrl"], + shift: ["shift"] + }, this.keyPress.bind(this)) this.gamepad = new Gamepad({ confirm: ["b", "start", "ls", "rs"], back: ["a"], @@ -309,13 +310,12 @@ class SongSelect{ session: ["back"], ctrl: ["y"], shift: ["x"] - }) + }, this.keyPress.bind(this)) if(!assets.customSongs){ this.startP2() } - pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.add(loader.screen, "mousemove", this.mouseMove.bind(this)) pageEvents.add(loader.screen, "mouseleave", () => { this.state.moveHover = null @@ -341,61 +341,47 @@ class SongSelect{ } } - keyDown(event, key){ - if(key){ - var modifiers = { - shift: this.pressedKeys["shift"], - ctrl: this.pressedKeys["ctrl"] + keyPress(pressed, name, event){ + if(pressed){ + if(!this.pressedKeys[name]){ + this.pressedKeys[name] = this.getMS() + 300 } }else{ - var modifiers = { - shift: event.shiftKey, - ctrl: event.ctrlKey - } - for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ - key = i - break - } - } - } - if(key === "ctrl" || key === "shift" || !this.redrawRunning){ + this.pressedKeys[name] = 0 return } - - if(event && (event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9)){ - // Escape, Backspace, Tab - event.preventDefault() + if(name === "ctrl" || name === "shift" || !this.redrawRunning){ + return } if(this.state.screen === "song"){ - if(key === "confirm"){ + if(name === "confirm"){ this.toSelectDifficulty() - }else if(key === "back"){ + }else if(name === "back"){ this.toTitleScreen() - }else if(key === "session"){ + }else if(name === "session"){ this.toSession() - }else if(key === "left"){ + }else if(name === "left"){ this.moveToSong(-1) - }else if(key === "right"){ + }else if(name === "right"){ this.moveToSong(1) } }else if(this.state.screen === "difficulty"){ - if(key === "confirm"){ + if(name === "confirm"){ if(this.selectedDiff === 0){ this.toSongSelect() }else if(this.selectedDiff === 1){ this.toOptions(1) }else{ - this.toLoadSong(this.selectedDiff - this.diffOptions.length, modifiers.shift, modifiers.ctrl) + this.toLoadSong(this.selectedDiff - this.diffOptions.length, this.pressedKeys["shift"], this.pressedKeys["ctrl"]) } - }else if(key === "back" || key === "session"){ + }else if(name === "back" || name === "session"){ this.toSongSelect() - }else if(key === "left"){ + }else if(name === "left"){ this.moveToDiff(-1) - }else if(key === "right"){ + }else if(name === "right"){ this.moveToDiff(1) - }else if(this.selectedDiff === 1 && (key === "up" || key === "down")){ - this.toOptions(key === "up" ? -1 : 1) + }else if(this.selectedDiff === 1 && (name === "up" || name === "down")){ + this.toOptions(name === "up" ? -1 : 1) } } } @@ -781,20 +767,10 @@ class SongSelect{ requestAnimationFrame(this.redrawBind) var ms = this.getMS() - this.gamepad.play((pressed, keyCode) => { - if(pressed){ - if(!this.pressedKeys[keyCode]){ - this.pressedKeys[keyCode] = ms + 300 - this.keyDown(false, keyCode) - } - }else{ - this.pressedKeys[keyCode] = 0 - } - }) for(var key in this.pressedKeys){ if(this.pressedKeys[key]){ if(ms >= this.pressedKeys[key] + 50){ - this.keyDown(false, key) + this.keyPress(true, key) this.pressedKeys[key] = ms } } @@ -1957,6 +1933,8 @@ class SongSelect{ } clean(){ + this.keyboard.clean() + this.gamepad.clean() this.clearHash() this.draw.clean() this.songTitleCache.clean() @@ -1979,7 +1957,6 @@ class SongSelect{ song.preview_sound.clean() } }) - pageEvents.keyRemove(this, "all") pageEvents.remove(loader.screen, ["mousemove", "mouseleave", "mousedown", "touchstart"]) pageEvents.remove(this.canvas, "touchend") pageEvents.remove(p2, "message") diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 57134ef..eb77015 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -120,6 +120,12 @@ don_r: "面(右)", ka_r: "ふち(右)" }, + gamepadLayout: { + name: "そうさタイプ設定", + a: "タイプA", + b: "タイプB", + c: "タイプC" + }, on: "オン", off: "オフ", default: "既定値にリセット", @@ -254,6 +260,12 @@ function StringsEn(){ don_r: "Right Surface", ka_r: "Right Rim" }, + gamepadLayout: { + name: "Gamepad Layout", + a: "Type A", + b: "Type B", + c: "Type C" + }, on: "On", off: "Off", default: "Reset to Defaults", @@ -383,10 +395,16 @@ function StringsCn(){ }, keyboardSettings: { name: "键盘设置", - ka_l: "Left Rim", - don_l: "Left Surface", - don_r: "Right Surface", - ka_r: "Right Rim" + ka_l: "边缘(左)", + don_l: "表面(左)", + don_r: "表面(右)", + ka_r: "边缘(右)" + }, + gamepadLayout: { + name: "操作类型设定", + a: "类型A", + b: "类型B", + c: "类型C" }, on: "开", off: "关", @@ -517,10 +535,16 @@ function StringsTw(){ }, keyboardSettings: { name: "鍵盤設置", - ka_l: "Left Rim", - don_l: "Left Surface", - don_r: "Right Surface", - ka_r: "Right Rim" + ka_l: "邊緣(左)", + don_l: "表面(左)", + don_r: "表面(右)", + ka_r: "邊緣(右)" + }, + gamepadLayout: { + name: "操作類型設定", + a: "類型A", + b: "類型B", + c: "類型C" }, on: "開", off: "關", @@ -651,10 +675,16 @@ function StringsKo(){ }, keyboardSettings: { name: "키보드 설정", - ka_l: "Left Rim", - don_l: "Left Surface", - don_r: "Right Surface", - ka_r: "Right Rim" + ka_l: "가장자리 (왼쪽)", + don_l: "표면 (왼쪽)", + don_r: "표면 (오른쪽)", + ka_r: "가장자리 (오른쪽)" + }, + gamepadLayout: { + name: "조작 타입 설정", + a: "타입 A", + b: "타입 B", + c: "타입 C" }, on: "온", off: "오프", diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index a5ba7b6..6068a93 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -17,24 +17,26 @@ class Titlescreen{ if(localStorage.getItem("tutorial") === "true"){ new SongSelect(false, false, this.touched, this.songId) }else{ - new Tutorial(false, this.songId) + new SettingsView(false, true, this.songId) } }else{ - pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) - pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], this.onPressed.bind(this)) + pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], event => { + if(event.type === "touchstart"){ + event.preventDefault() + this.touched = true + }else if(event.type === "mousedown" && event.which !== 1){ + return + } + this.onPressed(true) + }) assets.sounds["v_title"].play() - var kbdSettings = settings.getItem("keyboardSettings") - this.kbd = { - confirm: ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]] - } + this.keyboard = new Keyboard({ + confirm: ["enter", "space", "don_l", "don_r"] + }, this.onPressed.bind(this)) this.gamepad = new Gamepad({ confirm: ["a", "b", "x", "y", "start", "ls", "rs"] - }, pressed => { - if(pressed){ - this.onPressed() - } - }) + }, this.onPressed.bind(this)) if(p2.session){ pageEvents.add(p2, "message", response => { if(response.type === "songsel"){ @@ -46,35 +48,13 @@ class Titlescreen{ } } - keyDown(event, key){ - if(!key){ - if(event.repeat || event.target === this.langDropdown){ - return - } - for(var i in this.kbd){ - if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){ - key = i - break - } - } + onPressed(pressed, name){ + if(pressed){ + this.titleScreen.style.cursor = "auto" + this.clean() + assets.sounds["se_don"].play() + this.goNext() } - if(key === "confirm"){ - this.onPressed() - } - } - onPressed(event){ - if(event){ - if(event.type === "touchstart"){ - event.preventDefault() - this.touched = true - }else if(event.type === "mousedown" && event.which !== 1){ - return - } - } - this.titleScreen.style.cursor = "auto" - this.clean() - assets.sounds["se_don"].play() - this.goNext() } goNext(fromP2){ if(p2.session && !fromP2){ @@ -89,7 +69,7 @@ class Titlescreen{ }, 500) }else{ setTimeout(() => { - new Tutorial(false, this.songId, this.touched) + new SettingsView(this.touched, true, this.songId) }, 500) } } @@ -109,10 +89,10 @@ class Titlescreen{ this.logo.updateSubtitle() } clean(){ + this.keyboard.clean() this.gamepad.clean() this.logo.clean() assets.sounds["v_title"].stop() - pageEvents.keyRemove(this, "all") pageEvents.remove(this.titleScreen, ["mousedown", "touchstart"]) delete this.titleScreen delete this.proceed diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js index 01a30a7..711265c 100644 --- a/public/src/js/tutorial.js +++ b/public/src/js/tutorial.js @@ -1,34 +1,37 @@ class Tutorial{ - constructor(fromSongSel, songId, touchEnabled){ + constructor(fromSongSel, songId){ this.fromSongSel = fromSongSel this.songId = songId - this.touchEnabled = touchEnabled - loader.changePage("tutorial", fromSongSel || !touchEnabled) + loader.changePage("tutorial", true) assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) - this.endButton = document.getElementById("tutorial-end-button") + this.endButton = this.getElement("view-end-button") - this.tutorialTitle = document.getElementById("tutorial-title") + this.tutorialTitle = this.getElement("view-title") this.tutorialDiv = document.createElement("div") - document.getElementById("tutorial-content").appendChild(this.tutorialDiv) + this.getElement("view-content").appendChild(this.tutorialDiv) this.setStrings() - if(fromSongSel){ - pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) - pageEvents.keyAdd(this, "all", "down", event => { - if(event.keyCode === 13 || event.keyCode === 27 || event.keyCode === 8){ - // Enter, Esc, Backspace - this.onEnd.bind(this) - } - }) - - this.gamepad = new Gamepad({ - "confirm": ["start", "b", "ls", "rs"] - }, this.onEnd.bind(this)) - }else{ - new SettingsView(touchEnabled, this) - } + pageEvents.add(this.endButton, ["mousedown", "touchstart"], event => { + if(event.type === "touchstart"){ + event.preventDefault() + this.touched = true + }else if(event.type === "mousedown" && event.which !== 1){ + return + } + this.onEnd(true) + }) + this.keyboard = new Keyboard({ + confirm: ["enter", "space", "esc", "don_l", "don_r"] + }, this.onEnd.bind(this)) + this.gamepad = new Gamepad({ + confirm: ["start", "b", "ls", "rs"] + }, this.onEnd.bind(this)) + pageEvents.send("tutorial") } + getElement(name){ + return loader.screen.getElementsByClassName(name)[0] + } insertText(text, parent){ parent.appendChild(document.createTextNode(text)) } @@ -37,43 +40,30 @@ class Tutorial{ kbd.innerText = key parent.appendChild(kbd) } - onEnd(event){ - var touched = false - if(event){ - if(event.type === "touchstart"){ - event.preventDefault() - touched = true - }else if(event.which !== 1){ - return - } + onEnd(pressed, name){ + if(pressed){ + this.clean() + assets.sounds["se_don"].play() + localStorage.setItem("tutorial", "true") + setTimeout(() => { + new SongSelect(this.fromSongSel ? "tutorial" : false, false, this.touched, this.songId) + }, 500) } - this.clean() - assets.sounds["se_don"].play() - localStorage.setItem("tutorial", "true") - setTimeout(() => { - new SongSelect(this.fromSongSel ? "tutorial" : false, false, touched, this.songId) - }, 500) } setStrings(){ - if(!this.fromSongSel && this.touchEnabled){ - this.tutorialTitle.innerText = strings.gameSettings - this.tutorialTitle.setAttribute("alt", strings.gameSettings) - this.endButton.innerText = strings.settings.ok - this.endButton.setAttribute("alt", strings.settings.ok) - return - } this.tutorialTitle.innerText = strings.howToPlay this.tutorialTitle.setAttribute("alt", strings.howToPlay) this.endButton.innerText = strings.tutorial.ok this.endButton.setAttribute("alt", strings.tutorial.ok) this.tutorialDiv.innerHTML = "" var kbdSettings = settings.getItem("keyboardSettings") + var pauseKey = pageEvents.kbd.indexOf("q") === -1 ? "Q" : "ESC" var keys = [ kbdSettings.don_l[0].toUpperCase(), kbdSettings.don_r[0].toUpperCase(), kbdSettings.ka_l[0].toUpperCase(), kbdSettings.ka_r[0].toUpperCase(), - "Q", "SHIFT", "CTRL" + pauseKey, "SHIFT", "CTRL" ] var keyIndex = 0 strings.tutorial.basics.forEach(string => { @@ -105,11 +95,9 @@ class Tutorial{ this.tutorialDiv.appendChild(par) } clean(){ - if(this.fromSongSel){ - this.gamepad.clean() - pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) - pageEvents.keyRemove(this, "all") - } + this.keyboard.clean() + this.gamepad.clean() + pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) assets.sounds["bgm_setsume"].stop() delete this.tutorialTitle delete this.endButton diff --git a/public/src/js/view.js b/public/src/js/view.js index f045b09..06c30c7 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -830,11 +830,10 @@ ) // Taiko pressed keys - var kbd = this.controller.getBindings() var keys = ["ka_l", "ka_r", "don_l", "don_r"] for(var i = 0; i < keys.length; i++){ - var keyMS = ms - keyTime[kbd[keys[i]]] + var keyMS = ms - keyTime[keys[i]] if(keyMS < 130){ if(keyMS > 70 && !this.touchEnabled){ ctx.globalAlpha = this.draw.easeOut(1 - (keyMS - 70) / 60) @@ -1769,11 +1768,10 @@ } touchNote(note){ var keyboard = this.controller.keyboard - var kbd = keyboard.getBindings() var ms = this.controller.game.getAccurateTime() this.touch = ms - keyboard.setKey(kbd[note], false) - keyboard.setKey(kbd[note], true, ms) + keyboard.setKey(false, note) + keyboard.setKey(true, note, ms) } mod(length, index){ return ((index % length) + length) % length diff --git a/public/src/views/about.html b/public/src/views/about.html index f6165c7..3506eb3 100644 --- a/public/src/views/about.html +++ b/public/src/views/about.html @@ -1,9 +1,9 @@ -
-
-
-
+
+
+
+
- -
+
diff --git a/public/src/views/session.html b/public/src/views/session.html index 5e57005..f47ce54 100644 --- a/public/src/views/session.html +++ b/public/src/views/session.html @@ -1,9 +1,9 @@ -
-
-
-
+
+
+
+
-
+
diff --git a/public/src/views/settings.html b/public/src/views/settings.html index 2333ff5..6a35a91 100644 --- a/public/src/views/settings.html +++ b/public/src/views/settings.html @@ -1,10 +1,20 @@ -
-
-
-
-