Controller: Separate game and view loops

This commit is contained in:
LoveEevee 2019-01-16 15:33:42 +03:00
parent 926b163460
commit 3398791afe
20 changed files with 275 additions and 275 deletions

View File

@ -1,3 +1,31 @@
html,
body{
margin: 0;
width: 100%;
height: 100%;
background: #fe7839;
position: absolute;
user-select: none;
touch-action: none;
overflow: hidden;
}
#screen{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #000;
background-position: top center;
background-size: 30vh;
font-family: TnT, Meiryo, sans-serif;
}
#screen.pattern-bg{
background-color: #fe7839;
}
#assets,
#browse{
display: none;
}
#loader{ #loader{
width:90%; width:90%;
height:10%; height:10%;

View File

@ -1,28 +1,3 @@
html,
body{
margin: 0;
width: 100%;
height: 100%;
background: #fe7839;
position: absolute;
user-select: none;
touch-action: none;
overflow: hidden;
}
#screen{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #fe7839;
background-position: top center;
background-size: 30vh;
font-family: TnT, Meiryo, sans-serif;
}
#assets,
#browse{
display: none;
}
.window{ .window{
width: 60vmin; width: 60vmin;
height: 23vmin; height: 23vmin;
@ -40,40 +15,6 @@ body{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
}
.stroke-main{
font-weight: 300;
}
.result-title{
margin-top: 9px !important;
margin-left: 5px !important;
z-index: 1;
}
.result-song,
.game-song{
position: absolute;
right: 0;
font-size: 5vmin;
margin: 3vmin 3vmin 0px 0px;
color: white;
float: right;
z-index: 1;
font-weight: 300;
}
.stroke-main::before{
content: attr(alt);
left: 0;
z-index: -1;
position: absolute;
-webkit-text-stroke: 0.3em #fb3c0c;
}
.stroke-main::after{
content: attr(alt);
left: 0;
z-index: -2;
position: absolute;
-webkit-text-stroke: 0.5em #000;
} }
.stroke-sub::before{ .stroke-sub::before{
content: attr(alt); content: attr(alt);
@ -82,44 +23,6 @@ body{
left: 0; left: 0;
z-index: -1; z-index: -1;
} }
.don{
background-position-y: 0;
position: absolute;
top: 0px;
}
.alpha-title .song-title-char{
transform: scale(1.3, 1);
font-size: 80%;
line-height: 22px;
}
.song-title-apos{
padding-left: 4px;
}
.song-title-char[alt="ぁ"],
.song-title-char[alt="ぃ"],
.song-title-char[alt="ぅ"],
.song-title-char[alt="ぇ"],
.song-title-char[alt="ぉ"],
.song-title-char[alt="ゃ"],
.song-title-char[alt="ゅ"],
.song-title-char[alt="ょ"],
.song-title-char[alt="っ"],
.song-title-char[alt="ァ"],
.song-title-char[alt="ィ"],
.song-title-char[alt="ゥ"],
.song-title-char[alt="ェ"],
.song-title-char[alt="ォ"],
.song-title-char[alt="ャ"],
.song-title-char[alt="ュ"],
.song-title-char[alt="ョ"],
.song-title-char[alt="ッ"]{
margin-top: -6px;
}
.song-title-char[alt="ー"],
.song-title-char[alt="-"]{
transform: rotate(95deg);
font-size: 90%;
}
#tutorial-outer{ #tutorial-outer{
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -6,7 +6,7 @@
] ]
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("about") loader.changePage("about", true)
cancelTouch = false cancelTouch = false
this.endButton = document.getElementById("tutorial-end-button") this.endButton = document.getElementById("tutorial-end-button")

View File

@ -1,4 +1,42 @@
var assets = { var assets = {
"js": [
"lib/fontdetect.min.js",
"loadsong.js",
"parseosu.js",
"titlescreen.js",
"scoresheet.js",
"songselect.js",
"keyboard.js",
"game.js",
"controller.js",
"circle.js",
"view.js",
"mekadon.js",
"gamepad.js",
"tutorial.js",
"soundbuffer.js",
"p2.js",
"canvasasset.js",
"viewassets.js",
"gamerules.js",
"canvasdraw.js",
"canvastest.js",
"canvascache.js",
"parsetja.js",
"about.js",
"debug.js",
"session.js",
"strings.js",
"importsongs.js"
],
"css": [
"main.css",
"titlescreen.css",
"loadsong.css",
"game.css",
"debug.css",
"songbg.css"
],
"img": [ "img": [
"title-screen.png", "title-screen.png",
"logo-big.png", "logo-big.png",

View File

@ -1,7 +1,7 @@
class CanvasAsset{ class CanvasAsset{
constructor(view, layer, position){ constructor(view, layer, position){
this.ctx = view.ctx this.ctx = view.ctx
this.controller = view.controller this.view = view
this.position = position this.position = position
this.animationFrames = {} this.animationFrames = {}
this.speed = 1000 / 60 this.speed = 1000 / 60
@ -13,7 +13,7 @@ class CanvasAsset{
if(this.animation){ if(this.animation){
var u = (a, b) => typeof a === "undefined" ? b : a var u = (a, b) => typeof a === "undefined" ? b : a
var frame = 0 var frame = 0
var ms = this.controller.getElapsedTime() var ms = this.view.getMS()
var beatInterval = this.frameSpeed ? 1000 / 60 : this.beatInterval var beatInterval = this.frameSpeed ? 1000 / 60 : this.beatInterval
if(this.animationEnd){ if(this.animationEnd){
@ -95,7 +95,7 @@ class CanvasAsset{
} }
changeBeatInterval(beatMS, initial){ changeBeatInterval(beatMS, initial){
if(!initial && !this.frameSpeed){ if(!initial && !this.frameSpeed){
var ms = this.controller.getElapsedTime() var ms = this.view.getMS()
this.animationStart = ms - (ms - this.animationStart) / this.beatInterval * beatMS this.animationStart = ms - (ms - this.animationStart) / this.beatInterval * beatMS
} }
this.beatInterval = beatMS this.beatInterval = beatMS

View File

@ -7,6 +7,10 @@ class Controller{
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
this.snd = this.multiplayer ? "_p" + this.multiplayer : "" this.snd = this.multiplayer ? "_p" + this.multiplayer : ""
if(this.multiplayer !== 2){
loader.changePage("game", false)
}
if(selectedSong.type === "tja"){ if(selectedSong.type === "tja"){
this.parsedSongData = new ParseTja(songData, selectedSong.difficulty, selectedSong.offset) this.parsedSongData = new ParseTja(songData, selectedSong.difficulty, selectedSong.offset)
}else{ }else{
@ -47,27 +51,48 @@ class Controller{
}) })
} }
startMainLoop(){ startMainLoop(){
this.mainLoopStarted = false
this.mainLoopRunning = true this.mainLoopRunning = true
this.mainLoop() this.gameLoop()
this.viewLoop()
this.gameInterval = setInterval(this.gameLoop.bind(this), 1000 / 60)
} }
stopMainLoop(){ stopMainLoop(){
this.mainLoopRunning = false this.mainLoopRunning = false
this.mainAsset.stop() this.mainAsset.stop()
clearInterval(this.gameInterval)
} }
mainLoop(){ gameLoop(){
if(this.mainLoopRunning){
if(this.syncWith){
this.syncWith.game.elapsedTime = this.game.elapsedTime
this.syncWith.game.startDate = this.game.startDate
}
var ms = this.game.elapsedTime
this.keyboard.checkMenuKeys()
if(!this.game.isPaused()){
this.keyboard.checkGameKeys()
if(ms < 0){
this.game.updateTime()
}else{
this.game.update()
if(!this.mainLoopRunning){
return
}
this.game.playMainMusic()
}
}
}
}
viewLoop(){
if(this.mainLoopRunning){ if(this.mainLoopRunning){
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.viewLoop()
if(this.syncWith){ if(this.syncWith){
this.syncWith.game.elapsedTime = this.game.elapsedTime this.syncWith.viewLoop()
this.syncWith.game.startDate = this.game.startDate
} }
this.mainLoop()
if(this.syncWith){
this.syncWith.mainLoop()
}
if(this.scoresheet){ if(this.scoresheet){
if(this.view.ctx){ if(this.view.ctx){
this.view.ctx.save() this.view.ctx.save()
@ -80,27 +105,7 @@ class Controller{
} }
}) })
} }
var ms = this.game.elapsedTime
if(!this.game.isPaused()){
this.keyboard.checkGameKeys()
if(ms >= 0 && !this.mainLoopStarted){
this.mainLoopStarted = true
}
if(ms < 0){
this.game.updateTime()
}
if(this.mainLoopStarted){
this.game.update()
if(!this.mainLoopRunning){
return
}
this.game.playMainMusic()
}
}
this.view.refresh() this.view.refresh()
this.keyboard.checkMenuKeys()
} }
} }
gameEnded(){ gameEnded(){
@ -130,7 +135,6 @@ class Controller{
if(!fadeIn){ if(!fadeIn){
this.clean() this.clean()
} }
loader.screen.classList.remove("view")
new SongSelect(false, fadeIn, this.touchEnabled) new SongSelect(false, fadeIn, this.touchEnabled)
} }
restartSong(){ restartSong(){
@ -138,7 +142,6 @@ class Controller{
if(this.multiplayer){ if(this.multiplayer){
new LoadSong(this.selectedSong, false, true, this.touchEnabled) new LoadSong(this.selectedSong, false, true, this.touchEnabled)
}else{ }else{
loader.changePage("game")
var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled) var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled)
taikoGame.run() taikoGame.run()
} }

View File

@ -64,7 +64,8 @@ class Game{
updateCirclesStatus(){ updateCirclesStatus(){
var nextSet = false var nextSet = false
var circles = this.songData.circles var circles = this.songData.circles
for(var i in circles){ var startIndex = this.currentCircle === 0 ? 0 : this.currentCircle - 1
for(var i = startIndex; i < circles.length && i < this.currentCircle + 2; i++){
var circle = circles[i] var circle = circles[i]
if(!circle.getPlayed()){ if(!circle.getPlayed()){
var ms = this.elapsedTime var ms = this.elapsedTime

View File

@ -28,21 +28,23 @@ class Gamepad{
if(callback){ if(callback){
this.interval = setInterval(() => { this.interval = setInterval(() => {
this.play(callback) this.play(callback)
}, 100) }, 1000 / 60)
} }
} }
play(callback){ play(callback){
if(pageEvents.lastKeyEvent + 5000 > Date.now()){
return
}
if("getGamepads" in navigator){ if("getGamepads" in navigator){
var gamepads = navigator.getGamepads() var gamepads = navigator.getGamepads()
if(gamepads.length === 0){
return
}
}else{ }else{
return return
} }
if(pageEvents.lastKeyEvent + 5000 > Date.now()){
return
}
var bindings = this.bindings var bindings = this.bindings
var force = { var force = {
lsu: false, lsu: false,
lsr: false, lsr: false,

View File

@ -35,6 +35,7 @@ class Keyboard{
gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] gameBtn[this.kbd["ka_l"]] = ["lb", "lt"]
gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] gameBtn[this.kbd["ka_r"]] = ["rb", "rt"]
this.gamepad = new Gamepad(gameBtn) this.gamepad = new Gamepad(gameBtn)
this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2)
var menuBtn = { var menuBtn = {
"cancel": ["a"], "cancel": ["a"],
@ -84,23 +85,25 @@ class Keyboard{
return true return true
} }
checkGameKeys(){ checkGameKeys(){
if(!this.controller.autoPlayEnabled){ if(this.controller.autoPlayEnabled){
var ms = this.game.getAccurateTime() 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) => { this.gamepad.play((pressed, keyCode) => {
if(pressed){ if(pressed){
if(this.keys[keyCode]){ if(this.keys[keyCode]){
this.setKey(keyCode, false) this.setKey(keyCode, false)
} }
this.setKey(keyCode, true, ms) this.setKey(keyCode, true, this.game.getAccurateTime())
}else{ }else{
this.setKey(keyCode, false) this.setKey(keyCode, false)
} }
}) })
}else{
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")
} }
} }
checkMenuKeys(){ checkMenuKeys(){
@ -239,5 +242,6 @@ class Keyboard{
} }
clean(){ clean(){
pageEvents.keyRemove(this, "all") pageEvents.keyRemove(this, "all")
clearInterval(this.gamepadInterval)
} }
} }

View File

@ -3,92 +3,141 @@ class Loader{
this.callback = callback this.callback = callback
this.loadedAssets = 0 this.loadedAssets = 0
this.assetsDiv = document.getElementById("assets") this.assetsDiv = document.getElementById("assets")
this.canvasTest = new CanvasTest() this.screen = document.getElementById("screen")
this.startTime = Date.now() this.startTime = Date.now()
this.ajax("/src/views/loader.html").then(this.run.bind(this)) var promises = []
promises.push(this.ajax("/src/views/loader.html").then(page => {
this.screen.innerHTML = page
}))
promises.push(this.ajax("/api/config").then(conf => {
gameConfig = JSON.parse(conf)
}))
Promise.all(promises).then(this.run.bind(this))
} }
run(page){ run(){
this.promises = [] this.promises = []
this.screen = document.getElementById("screen")
this.screen.innerHTML = page
this.loaderPercentage = document.querySelector("#loader .percentage") this.loaderPercentage = document.querySelector("#loader .percentage")
this.loaderProgress = document.querySelector("#loader .progress") this.loaderProgress = document.querySelector("#loader .progress")
snd.buffer = new SoundBuffer() var queryString = gameConfig._version ? "?" + gameConfig._version.commit_short : ""
snd.musicGain = snd.buffer.createGain()
snd.sfxGain = snd.buffer.createGain() assets.js.forEach(name => {
snd.previewGain = snd.buffer.createGain() var script = document.createElement("script")
snd.sfxGainL = snd.buffer.createGain("left") this.addPromise(pageEvents.load(script))
snd.sfxGainR = snd.buffer.createGain("right") script.src = "/src/js/" + name + queryString
snd.sfxLoudGain = snd.buffer.createGain() document.head.appendChild(script)
snd.buffer.setCrossfade( })
[snd.musicGain, snd.previewGain],
[snd.sfxGain, snd.sfxGainL, snd.sfxGainR], this.addPromise(new Promise(resolve => {
0.5 var cssCount = document.styleSheets.length + assets.css.length
) assets.css.forEach(name => {
snd.sfxLoudGain.setVolume(1.2) var stylesheet = document.createElement("link")
stylesheet.rel = "stylesheet"
this.promises.push(this.ajax("/api/config").then(conf => { stylesheet.href = "/src/css/" + name + queryString
gameConfig = JSON.parse(conf) document.head.appendChild(stylesheet)
})
snd.buffer.load(gameConfig.assets_baseurl + "audio/" + assets.audioOgg).then(() => { var checkStyles = () => {
if(document.styleSheets.length >= cssCount){
resolve()
clearInterval(interval)
}
}
var interval = setInterval(checkStyles, 100)
checkStyles()
}))
assets.fonts.forEach(name => {
var font = document.createElement("h1")
font.style.fontFamily = name
font.appendChild(document.createTextNode("I am a font"))
this.assetsDiv.appendChild(font)
})
assets.img.forEach(name => {
var id = this.getFilename(name)
var image = document.createElement("img")
this.addPromise(pageEvents.load(image))
image.id = name
image.src = gameConfig.assets_baseurl + "img/" + name
this.assetsDiv.appendChild(image)
assets.image[id] = image
})
assets.views.forEach(name => {
var id = this.getFilename(name)
this.addPromise(this.ajax("/src/views/" + name + queryString).then(page => {
assets.pages[id] = page
}))
})
this.addPromise(this.ajax("/api/songs").then(songs => {
assets.songsDefault = JSON.parse(songs)
assets.songs = assets.songsDefault
}))
this.afterJSCount =
[assets.audioOgg, "blurPerformance", "P2Connection"].length +
assets.fonts.length +
assets.audioSfx.length +
assets.audioMusic.length +
assets.audioSfxLR.length +
assets.audioSfxLoud.length
Promise.all(this.promises).then(() => {
snd.buffer = new SoundBuffer()
snd.musicGain = snd.buffer.createGain()
snd.sfxGain = snd.buffer.createGain()
snd.previewGain = snd.buffer.createGain()
snd.sfxGainL = snd.buffer.createGain("left")
snd.sfxGainR = snd.buffer.createGain("right")
snd.sfxLoudGain = snd.buffer.createGain()
snd.buffer.setCrossfade(
[snd.musicGain, snd.previewGain],
[snd.sfxGain, snd.sfxGainL, snd.sfxGainR],
0.5
)
snd.sfxLoudGain.setVolume(1.2)
this.afterJSCount--
this.addPromise(snd.buffer.load(gameConfig.assets_baseurl + "audio/" + assets.audioOgg).then(() => {
this.oggNotSupported = false this.oggNotSupported = false
}, () => { }, () => {
this.oggNotSupported = true this.oggNotSupported = true
}).then(() => { }).then(() => {
this.afterJSCount = 0
assets.fonts.forEach(name => { assets.fonts.forEach(name => {
var font = document.createElement("h1") this.addPromise(new Promise(resolve => {
font.style.fontFamily = name FontDetect.onFontLoaded(name, resolve, resolve, {msTimeout: Infinity})
font.appendChild(document.createTextNode("I am a font"))
this.assetsDiv.appendChild(font)
this.promises.push(new Promise((resolve, reject) => {
FontDetect.onFontLoaded(name, resolve, reject, {msTimeout: 90000})
})) }))
}) })
assets.img.forEach(name => {
var id = this.getFilename(name)
var image = document.createElement("img")
this.promises.push(pageEvents.load(image))
image.id = name
image.src = gameConfig.assets_baseurl + "img/" + name
this.assetsDiv.appendChild(image)
assets.image[id] = image
})
assets.audioSfx.forEach(name => { assets.audioSfx.forEach(name => {
this.promises.push(this.loadSound(name, snd.sfxGain)) this.addPromise(this.loadSound(name, snd.sfxGain))
}) })
assets.audioMusic.forEach(name => { assets.audioMusic.forEach(name => {
this.promises.push(this.loadSound(name, snd.musicGain)) this.addPromise(this.loadSound(name, snd.musicGain))
}) })
assets.audioSfxLR.forEach(name => { assets.audioSfxLR.forEach(name => {
this.promises.push(this.loadSound(name, snd.sfxGain).then(sound => { this.addPromise(this.loadSound(name, snd.sfxGain).then(sound => {
var id = this.getFilename(name) var id = this.getFilename(name)
assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL) assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL)
assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR) assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR)
})) }))
}) })
assets.audioSfxLoud.forEach(name => { assets.audioSfxLoud.forEach(name => {
this.promises.push(this.loadSound(name, snd.sfxLoudGain)) this.addPromise(this.loadSound(name, snd.sfxLoudGain))
}) })
this.promises.push(this.ajax("/api/songs").then(songs => { this.canvasTest = new CanvasTest()
assets.songsDefault = JSON.parse(songs) this.addPromise(this.canvasTest.blurPerformance().then(result => {
assets.songs = assets.songsDefault
}))
assets.views.forEach(name => {
var id = this.getFilename(name)
var qs = gameConfig._version ? '?' + gameConfig._version.commit_short : '?'
this.promises.push(this.ajax("/src/views/" + name + qs).then(page => {
assets.pages[id] = page
}))
})
this.promises.push(this.canvasTest.blurPerformance().then(result => {
perf.blur = result perf.blur = result
if(result > 1000 / 50){ if(result > 1000 / 50){
// Less than 50 fps with blur enabled // Less than 50 fps with blur enabled
@ -96,8 +145,10 @@ class Loader{
} }
})) }))
p2 = new P2Connection()
if(location.hash.length === 6){ if(location.hash.length === 6){
this.promises.push(new Promise(resolve => { p2.hashLock = true
this.addPromise(new Promise(resolve => {
p2.open() p2.open()
pageEvents.add(p2, "message", response => { pageEvents.add(p2, "message", response => {
if(response.type === "session"){ if(response.type === "session"){
@ -119,12 +170,10 @@ class Loader{
}).then(() => { }).then(() => {
pageEvents.remove(p2, "message") pageEvents.remove(p2, "message")
})) }))
}else{
p2.hash("")
} }
this.promises.forEach(promise => {
promise.then(this.assetLoaded.bind(this))
})
Promise.all(this.promises).then(() => { Promise.all(this.promises).then(() => {
this.canvasTest.drawAllImages().then(result => { this.canvasTest.drawAllImages().then(result => {
perf.allImg = result perf.allImg = result
@ -135,9 +184,13 @@ class Loader{
}) })
}, this.errorMsg.bind(this)) }, this.errorMsg.bind(this))
}) }))
})) })
}
addPromise(promise){
this.promises.push(promise)
promise.then(this.assetLoaded.bind(this))
} }
loadSound(name, gain){ loadSound(name, gain){
if(this.oggNotSupported && name.endsWith(".ogg")){ if(this.oggNotSupported && name.endsWith(".ogg")){
@ -161,13 +214,14 @@ class Loader{
assetLoaded(){ assetLoaded(){
if(!this.error){ if(!this.error){
this.loadedAssets++ this.loadedAssets++
var percentage = Math.floor(this.loadedAssets * 100 / this.promises.length) var percentage = Math.floor(this.loadedAssets * 100 / (this.promises.length + this.afterJSCount))
this.loaderProgress.style.width = percentage + "%" this.loaderProgress.style.width = percentage + "%"
this.loaderPercentage.firstChild.data = percentage + "%" this.loaderPercentage.firstChild.data = percentage + "%"
} }
} }
changePage(name){ changePage(name, patternBg){
this.screen.innerHTML = assets.pages[name] this.screen.innerHTML = assets.pages[name]
this.screen.classList[patternBg ? "add" : "remove"]("pattern-bg")
} }
ajax(url, customRequest){ ajax(url, customRequest){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -5,7 +5,7 @@ class LoadSong{
this.multiplayer = multiplayer this.multiplayer = multiplayer
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("loadsong") loader.changePage("loadsong", true)
var loadingText = document.getElementById("loading-text") var loadingText = document.getElementById("loading-text")
loadingText.appendChild(document.createTextNode(strings.loading)) loadingText.appendChild(document.createTextNode(strings.loading))
loadingText.setAttribute("alt", strings.loading) loadingText.setAttribute("alt", strings.loading)
@ -233,7 +233,6 @@ class LoadSong{
}else if(event.type === "gamestart"){ }else if(event.type === "gamestart"){
this.clean() this.clean()
p2.clearMessage("songsel") p2.clearMessage("songsel")
loader.changePage("game")
var taikoGame1 = new Controller(song, this.songData, false, 1, this.touchEnabled) var taikoGame1 = new Controller(song, this.songData, false, 1, this.touchEnabled)
var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2, this.touchEnabled) var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2, this.touchEnabled)
taikoGame1.run(taikoGame2) taikoGame1.run(taikoGame2)
@ -248,7 +247,6 @@ class LoadSong{
}) })
}else{ }else{
this.clean() this.clean()
loader.changePage("game")
var taikoGame = new Controller(song, this.songData, this.autoPlayEnabled, false, this.touchEnabled) var taikoGame = new Controller(song, this.songData, this.autoPlayEnabled, false, this.touchEnabled)
taikoGame.run() taikoGame.run()
} }

View File

@ -58,11 +58,16 @@ function debug(){
} }
var root = document.documentElement var root = document.documentElement
var fullScreenSupported = "requestFullscreen" in root || "webkitRequestFullscreen" in root || "mozRequestFullScreen" in root
if(/iPhone|iPad/.test(navigator.userAgent)){
var fullScreenSupported = false
}else{
var fullScreenSupported = "requestFullscreen" in root || "webkitRequestFullscreen" in root || "mozRequestFullScreen" in root
}
var pageEvents = new PageEvents() var pageEvents = new PageEvents()
var snd = {} var snd = {}
var p2 = new P2Connection() var p2
var disableBlur = false var disableBlur = false
var cancelTouch = true var cancelTouch = true
var lastHeight var lastHeight
@ -104,11 +109,6 @@ pageEvents.keyAdd(debugObj, "all", "down", event => {
debugObj.controller.restartSong() debugObj.controller.restartSong()
} }
}) })
if(location.hash.length === 6){
p2.hashLock = true
}else{
p2.hash("")
}
var loader = new Loader(() => { var loader = new Loader(() => {
new Titlescreen() new Titlescreen()

View File

@ -290,7 +290,7 @@ class ParseOsu{
var extras = values.slice(this.osu.EXTRAS) var extras = values.slice(this.osu.EXTRAS)
var distance = parseFloat(extras[this.osu.PIXELLENGTH]) var distance = parseFloat(extras[this.osu.PIXELLENGTH]) * parseFloat(extras[this.osu.REPEAT])
var velocity = this.difficulty.sliderMultiplier * speed / 10 var velocity = this.difficulty.sliderMultiplier * speed / 10
var endTime = start + distance / velocity var endTime = start + distance / velocity

View File

@ -493,7 +493,7 @@ class Scoresheet{
fontSize: 29, fontSize: 29,
fontFamily: this.font, fontFamily: this.font,
align: "right", align: "right",
width: 215, width: 154,
letterSpacing: 1 letterSpacing: 1
}, [ }, [
{outline: "#000", letterBorder: 8}, {outline: "#000", letterBorder: 8},

View File

@ -1,7 +1,7 @@
class Session{ class Session{
constructor(touchEnabled){ constructor(touchEnabled){
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("session") loader.changePage("session", true)
this.endButton = document.getElementById("tutorial-end-button") this.endButton = document.getElementById("tutorial-end-button")
if(touchEnabled){ if(touchEnabled){
document.getElementById("tutorial-outer").classList.add("touch-enabled") document.getElementById("tutorial-outer").classList.add("touch-enabled")

View File

@ -1,11 +1,11 @@
class SongSelect{ class SongSelect{
constructor(fromTutorial, fadeIn, touchEnabled){ constructor(fromTutorial, fadeIn, touchEnabled){
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("songselect") loader.changePage("songselect", false)
this.canvas = document.getElementById("song-sel-canvas") this.canvas = document.getElementById("song-sel-canvas")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
this.songSkin = { this.songSkin = {
"selected": { "selected": {
background: "#ffdb2c", background: "#ffdb2c",

View File

@ -1,6 +1,6 @@
class Titlescreen{ class Titlescreen{
constructor(){ constructor(){
loader.changePage("titlescreen") loader.changePage("titlescreen", false)
this.titleScreen = document.getElementById("title-screen") this.titleScreen = document.getElementById("title-screen")
var proceed = document.getElementById("title-proceed") var proceed = document.getElementById("title-proceed")
proceed.appendChild(document.createTextNode(strings.titleProceed)) proceed.appendChild(document.createTextNode(strings.titleProceed))

View File

@ -1,7 +1,7 @@
class Tutorial{ class Tutorial{
constructor(fromSongSel){ constructor(fromSongSel){
this.fromSongSel = fromSongSel this.fromSongSel = fromSongSel
loader.changePage("tutorial") loader.changePage("tutorial", true)
assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054)
this.endButton = document.getElementById("tutorial-end-button") this.endButton = document.getElementById("tutorial-end-button")

View File

@ -124,7 +124,7 @@
} }
this.setDonBg() this.setDonBg()
this.lastMousemove = this.controller.getElapsedTime() this.lastMousemove = this.controller.game.getAccurateTime()
pageEvents.mouseAdd(this, this.onmousemove.bind(this)) pageEvents.mouseAdd(this, this.onmousemove.bind(this))
this.refresh() this.refresh()
@ -180,7 +180,10 @@
} }
winW /= ratio winW /= ratio
winH /= ratio winH /= ratio
var ms = this.getMS() if(!this.controller.game.paused){
this.ms = this.controller.game.getAccurateTime()
}
var ms = this.ms
if(this.portrait){ if(this.portrait){
var frameTop = winH / 2 - 1280 / 2 var frameTop = winH / 2 - 1280 / 2
@ -978,7 +981,6 @@
}else{ }else{
var catId = this.categories.default.sort var catId = this.categories.default.sort
} }
loader.screen.classList.add("view")
if(!selectedSong.songSkin.song){ if(!selectedSong.songSkin.song){
var id = selectedSong.songBg var id = selectedSong.songBg
@ -1100,7 +1102,7 @@
} }
drawCircles(circles){ drawCircles(circles){
var distanceForCircle = this.winW / this.ratio - this.slotPos.x var distanceForCircle = this.winW / this.ratio - this.slotPos.x
var ms = this.controller.getElapsedTime() var ms = this.getMS()
for(var i = circles.length; i--;){ for(var i = circles.length; i--;){
var circle = circles[i] var circle = circles[i]
@ -1127,7 +1129,7 @@
} }
} }
drawAnimatedCircles(circles){ drawAnimatedCircles(circles){
var ms = this.controller.getElapsedTime() var ms = this.getMS()
for(var i = 0; i < circles.length; i++){ for(var i = 0; i < circles.length; i++){
var circle = circles[i] var circle = circles[i]
@ -1174,7 +1176,7 @@
var fill, size, faceID var fill, size, faceID
var type = circle.getType() var type = circle.getType()
var ms = this.controller.getElapsedTime() var ms = this.getMS()
var circleMs = circle.getMS() var circleMs = circle.getMS()
var endTime = circle.getEndTime() var endTime = circle.getEndTime()
var animated = circle.isAnimated() var animated = circle.isAnimated()
@ -1458,7 +1460,7 @@
&& animation !== "gogo" && animation !== "gogo"
){ ){
don.setAnimation("10combo") don.setAnimation("10combo")
var ms = this.controller.getElapsedTime() var ms = this.getMS()
don.setAnimationStart(ms) don.setAnimationStart(ms)
var length = don.getAnimationLength("normal") var length = don.getAnimationLength("normal")
don.setUpdateSpeed(4 / length) don.setUpdateSpeed(4 / length)
@ -1677,7 +1679,7 @@
this.assets.changeBeatInterval(beatMS) this.assets.changeBeatInterval(beatMS)
} }
getMS(){ getMS(){
return this.controller.getElapsedTime() return this.ms
} }
clean(){ clean(){
this.draw.clean() this.draw.clean()

View File

@ -7,53 +7,20 @@
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<meta name="description" content="パソコンとスマホのブラウザ向けの太鼓の達人シミュレータ 🥁 Taiko no Tatsujin rhythm game simulator for desktop and mobile browsers"> <meta name="description" content="パソコンとスマホのブラウザ向けの太鼓の達人シミュレータ 🥁 Taiko no Tatsujin rhythm game simulator for desktop and mobile browsers">
<link rel="stylesheet" href="/src/css/main.css?{{version.commit_short}}"/>
<link rel="stylesheet" href="/src/css/loader.css?{{version.commit_short}}"> <link rel="stylesheet" href="/src/css/loader.css?{{version.commit_short}}">
<link rel="stylesheet" href="/src/css/titlescreen.css?{{version.commit_short}}">
<link rel="stylesheet" href="/src/css/loadsong.css?{{version.commit_short}}">
<link rel="stylesheet" href="/src/css/game.css?{{version.commit_short}}">
<link rel="stylesheet" href="/src/css/debug.css?{{version.commit_short}}">
<link rel="stylesheet" href="/src/css/songbg.css?{{version.commit_short}}">
<link rel="stylesheet" href="{{config.assets_baseurl}}fonts/fonts.css?{{version.commit_short}}"> <link rel="stylesheet" href="{{config.assets_baseurl}}fonts/fonts.css?{{version.commit_short}}">
<link rel="stylesheet" href="{{config.assets_baseurl}}img/img.css?{{version.commit_short}}"> <link rel="stylesheet" href="{{config.assets_baseurl}}img/img.css?{{version.commit_short}}">
<script src="/src/js/lib/fontdetect.min.js?{{version.commit_short}}"></script> <script src="/src/js/lib/fontdetect.min.js?{{version.commit_short}}"></script>
<script src="/src/js/assets.js?{{version.commit_short}}"></script> <script src="/src/js/assets.js?{{version.commit_short}}"></script>
<script src="/src/js/loadsong.js?{{version.commit_short}}"></script>
<script src="/src/js/parseosu.js?{{version.commit_short}}"></script>
<script src="/src/js/titlescreen.js?{{version.commit_short}}"></script>
<script src="/src/js/scoresheet.js?{{version.commit_short}}"></script>
<script src="/src/js/songselect.js?{{version.commit_short}}"></script>
<script src="/src/js/keyboard.js?{{version.commit_short}}"></script>
<script src="/src/js/game.js?{{version.commit_short}}"></script>
<script src="/src/js/controller.js?{{version.commit_short}}"></script>
<script src="/src/js/circle.js?{{version.commit_short}}"></script>
<script src="/src/js/view.js?{{version.commit_short}}"></script>
<script src="/src/js/mekadon.js?{{version.commit_short}}"></script>
<script src="/src/js/gamepad.js?{{version.commit_short}}"></script>
<script src="/src/js/tutorial.js?{{version.commit_short}}"></script>
<script src="/src/js/soundbuffer.js?{{version.commit_short}}"></script>
<script src="/src/js/p2.js?{{version.commit_short}}"></script>
<script src="/src/js/canvasasset.js?{{version.commit_short}}"></script>
<script src="/src/js/pageevents.js?{{version.commit_short}}"></script> <script src="/src/js/pageevents.js?{{version.commit_short}}"></script>
<script src="/src/js/viewassets.js?{{version.commit_short}}"></script>
<script src="/src/js/gamerules.js?{{version.commit_short}}"></script>
<script src="/src/js/canvasdraw.js?{{version.commit_short}}"></script>
<script src="/src/js/loader.js?{{version.commit_short}}"></script> <script src="/src/js/loader.js?{{version.commit_short}}"></script>
<script src="/src/js/canvastest.js?{{version.commit_short}}"></script>
<script src="/src/js/canvascache.js?{{version.commit_short}}"></script>
<script src="/src/js/parsetja.js?{{version.commit_short}}"></script>
<script src="/src/js/about.js?{{version.commit_short}}"></script>
<script src="/src/js/debug.js?{{version.commit_short}}"></script>
<script src="/src/js/session.js?{{version.commit_short}}"></script>
<script src="/src/js/strings.js?{{version.commit_short}}"></script>
<script src="/src/js/importsongs.js?{{version.commit_short}}"></script>
</head> </head>
<body> <body>
<div id="assets"></div> <div id="assets"></div>
<div id="screen"></div> <div id="screen" class="orange-bg"></div>
<div id="version"> <div id="version">
{% if version %} {% if version %}
<a href="https://github.com/bui/taiko-web/commit/{{version.commit}}" target="_blank" id="version-link" class="stroke-sub" alt="taiko-web ver.{{version.version}} ({{version.commit_short}})">taiko-web ver.{{version.version}} ({{version.commit_short}})</a> <a href="https://github.com/bui/taiko-web/commit/{{version.commit}}" target="_blank" id="version-link" class="stroke-sub" alt="taiko-web ver.{{version.version}} ({{version.commit_short}})">taiko-web ver.{{version.version}} ({{version.commit_short}})</a>