Merge pull request #55 from LoveEevee/songselect-add-ura

SongSelect: Add ura difficulty
This commit is contained in:
Bui 2018-10-13 01:22:04 +01:00 committed by GitHub
commit 5fbea99d06
20 changed files with 225 additions and 98 deletions

View File

@ -10,7 +10,7 @@ Still in developement. Works best with Chrome.
Create a SQLite databse named `taiko.db` with the following schema: Create a SQLite databse named `taiko.db` with the following schema:
CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL ) CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `ura` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL )
CREATE TABLE "categories" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT NOT NULL ) CREATE TABLE "categories" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT NOT NULL )
When inserting song rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them. When inserting song rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them.

23
app.py
View File

@ -105,33 +105,34 @@ def route_api_songs():
categories[cat[0]] = {'title': cat[1], 'title_en': cat[2]} categories[cat[0]] = {'title': cat[1], 'title_en': cat[2]}
songs_out = [] songs_out = []
for song in songs: for song in songs:
type = song[9] song_id = song[0]
if type == "tja": song_type = song[10]
if os.path.isfile('public/songs/%s/main.tja' % song[0]): if song_type == "tja":
preview = get_tja_preview('public/songs/%s/main.tja' % song[0]) if os.path.isfile('public/songs/%s/main.tja' % song_id):
preview = get_tja_preview('public/songs/%s/main.tja' % song_id)
else: else:
preview = 0 preview = 0
else: else:
osus = [osu for osu in os.listdir('public/songs/%s' % song[0]) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']] osus = [osu for osu in os.listdir('public/songs/%s' % song_id) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
if osus: if osus:
osud = parse_osu('public/songs/%s/%s' % (song[0], osus[0])) osud = parse_osu('public/songs/%s/%s' % (song_id, osus[0]))
preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0)) preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
else: else:
preview = 0 preview = 0
category_out = categories[song[8]] if song[8] in categories else def_category category_out = categories[song[9]] if song[9] in categories else def_category
songs_out.append({ songs_out.append({
'id': song[0], 'id': song_id,
'title': song[1], 'title': song[1],
'title_en': song[2], 'title_en': song[2],
'stars': [ 'stars': [
song[3], song[4], song[5], song[6] song[3], song[4], song[5], song[6], song[7]
], ],
'preview': preview, 'preview': preview,
'category': category_out['title'], 'category': category_out['title'],
'category_en': category_out['title_en'], 'category_en': category_out['title_en'],
'type': type, 'type': song_type,
'offset': song[10] 'offset': song[11]
}) })
return jsonify(songs_out) return jsonify(songs_out)

View File

@ -1,6 +1,7 @@
#game{ #game{
width: 100%; width: 100%;
height: 100%; height: 100%;
position: asbolute;
overflow: hidden; overflow: hidden;
background-size: cover; background-size: cover;
} }
@ -32,7 +33,7 @@
border:.5vmin solid #ae7a26; border:.5vmin solid #ae7a26;
background: #fff; background: #fff;
color: #000; color: #000;
font-family: TnT; font-family: TnT, Meiryo, sans-serif;
font-size: 3.5vmin; font-size: 3.5vmin;
border-radius: 1.5vmin; border-radius: 1.5vmin;
outline: none; outline: none;
@ -61,6 +62,7 @@
height: 50%; height: 50%;
text-align: center; text-align: center;
margin: auto; margin: auto;
overflow: hidden;
} }
#touch-drum-img{ #touch-drum-img{
width: 100%; width: 100%;

View File

@ -13,6 +13,7 @@ body{
height: 100%; height: 100%;
background: #fe7839; background: #fe7839;
user-select: none; user-select: none;
touch-action: none;
} }
#screen{ #screen{
width: 100%; width: 100%;
@ -20,7 +21,7 @@ body{
margin: 0; margin: 0;
padding: 0; padding: 0;
background: #fe7839 url("/assets/img/bg-pattern-1.png") top center; background: #fe7839 url("/assets/img/bg-pattern-1.png") top center;
font-family: TnT; font-family: TnT, Meiryo, sans-serif;
} }
#assets{ #assets{
display: none; display: none;
@ -233,13 +234,16 @@ kbd{
bottom: 1vh; bottom: 1vh;
right: 1vh; right: 1vh;
opacity: 0.7; opacity: 0.7;
font-family: TnT; font-family: TnT, Meiryo, sans-serif;
}
#version:hover{
opacity: 1;
} }
#version a { #version-link{
color: #FFFFFF; color: #FFFFFF;
text-decoration: none; text-decoration: none;
cursor: default; pointer-events: none;
} }
.version-hide{ .version-hide{

View File

@ -22,6 +22,7 @@ var assets = {
"muzu_normal.png", "muzu_normal.png",
"muzu_hard.png", "muzu_hard.png",
"muzu_oni.png", "muzu_oni.png",
"muzu_ura.png",
"don_anim_normal.png", "don_anim_normal.png",
"don_anim_10combo.png", "don_anim_10combo.png",
"don_anim_gogo.png", "don_anim_gogo.png",

View File

@ -229,6 +229,12 @@
easeIn(pos){ easeIn(pos){
return 1 - Math.cos(Math.PI / 2 * pos) return 1 - Math.cos(Math.PI / 2 * pos)
} }
easeOut(pos){
return Math.sin(Math.PI / 2 * pos)
}
easeInOut(pos){
return (Math.cos(Math.PI * pos) - 1) / -2
}
verticalText(config){ verticalText(config){
var ctx = config.ctx var ctx = config.ctx
@ -508,7 +514,7 @@
ctx.save() ctx.save()
ctx.lineWidth = config.border ctx.lineWidth = config.border
ctx.strokeStyle = "#000" ctx.strokeStyle = "#000"
var icon = this.diffIconPath[config.diff] var icon = this.diffIconPath[config.diff === 4 ? 3 : config.diff]
ctx.translate(config.x - icon[0].w * scale / 2, config.y - icon[0].h * scale / 2) ctx.translate(config.x - icon[0].w * scale / 2, config.y - icon[0].h * scale / 2)
ctx.scale(scale, scale) ctx.scale(scale, scale)
for(var i = 1; i < icon.length; i++){ for(var i = 1; i < icon.length; i++){
@ -518,7 +524,11 @@
} }
if(!config.noFill){ if(!config.noFill){
for(var i = 1; i < icon.length; i++){ for(var i = 1; i < icon.length; i++){
ctx.fillStyle = icon[i].fill if(config.diff === 4 && icon[i].fill === "#db1885"){
ctx.fillStyle = "#7135db"
}else{
ctx.fillStyle = icon[i].fill
}
ctx.fill(icon[i].d) ctx.fill(icon[i].d)
} }
} }
@ -619,18 +629,19 @@
diffStar(config){ diffStar(config){
var ctx = config.ctx var ctx = config.ctx
ctx.save() ctx.save()
if(config.songSel){ if(config.songSel || config.ura){
if(this.diffStarCache.scale !== config.ratio){ if(this.diffStarCache.scale !== config.ratio){
this.diffStarCache.resize(30, 30, config.ratio) this.diffStarCache.resize(62, 31, config.ratio)
} }
var offset = 30 / 2 - 18 / 2 var offset = 30 / 2 - 18 / 2
var big = config.ura && !config.songSel
this.diffStarCache.get({ this.diffStarCache.get({
ctx: ctx, ctx: ctx,
x: config.x - 9 - offset, x: config.x - 9 - offset,
y: config.y - 9 - offset, y: config.y - 9 - offset,
w: 30, w: 30,
h: 30, h: 30,
id: "star" id: big ? "big" : "small"
}, ctx => { }, ctx => {
ctx.fillStyle = "#fff" ctx.fillStyle = "#fff"
this.shadow({ this.shadow({
@ -639,7 +650,12 @@
blur: 10, blur: 10,
force: true force: true
}) })
ctx.translate(offset, offset) if(big){
ctx.translate(30 / 2 - 21 / 2, 30 / 2 - 19 / 2)
ctx.scale(1.1, 1.1)
}else{
ctx.translate(offset, offset)
}
ctx.fill(this.diffStarPath) ctx.fill(this.diffStarPath)
}) })
}else{ }else{

View File

@ -103,7 +103,7 @@ class CanvasTest{
var comboX = 100 var comboX = 100
var comboY = 100 var comboY = 100
var fontSize = 120 var fontSize = 120
this.ctx.font = "normal " + fontSize + "px TnT" this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
this.ctx.strokeStyle = "#000" this.ctx.strokeStyle = "#000"
this.ctx.lineWidth = fontSize / 10 this.ctx.lineWidth = fontSize / 10

View File

@ -40,17 +40,17 @@ class Controller{
} }
} }
loadUIEvents(){ loadUIEvents(){
this.pauseMenu = document.getElementById("pause-menu")
this.continueBtn = document.getElementById("continue-butt") this.continueBtn = document.getElementById("continue-butt")
this.restartBtn = document.getElementById("restart-butt") this.restartBtn = document.getElementById("restart-butt")
this.songSelBtn = document.getElementById("song-selection-butt") this.songSelBtn = document.getElementById("song-selection-butt")
pageEvents.add(this.continueBtn, "click", () => { pageEvents.add(this.pauseMenu, "touchstart", event => event.preventDefault())
this.togglePauseMenu() pageEvents.add(this.continueBtn, ["click", "touchend"], this.togglePauseMenu.bind(this))
}) pageEvents.add(this.restartBtn, ["click", "touchend"], () => {
pageEvents.add(this.restartBtn, "click", () => {
assets.sounds["don"].play() assets.sounds["don"].play()
this.restartSong() this.restartSong()
}) })
pageEvents.add(this.songSelBtn, "click", () => { pageEvents.add(this.songSelBtn, ["click", "touchend"], () => {
assets.sounds["don"].play() assets.sounds["don"].play()
this.songSelection() this.songSelection()
}) })
@ -63,9 +63,6 @@ class Controller{
stopMainLoop(){ stopMainLoop(){
this.mainLoopRunning = false this.mainLoopRunning = false
this.mainAsset.stop() this.mainAsset.stop()
if(this.syncWith){
this.syncWith.stopMainLoop()
}
} }
mainLoop(){ mainLoop(){
if(this.mainLoopRunning){ if(this.mainLoopRunning){
@ -212,11 +209,13 @@ class Controller{
this.keyboard.clean() this.keyboard.clean()
this.view.clean() this.view.clean()
pageEvents.remove(this.continueBtn, "click") pageEvents.remove(this.pauseMenu, "touchstart")
delete this.pauseMenu
pageEvents.remove(this.continueBtn, ["click", "touchend"])
delete this.continueBtn delete this.continueBtn
pageEvents.remove(this.restartBtn, "click") pageEvents.remove(this.restartBtn, ["click", "touchend"])
delete this.restartBtn delete this.restartBtn
pageEvents.remove(this.songSelBtn, "click") pageEvents.remove(this.songSelBtn, ["click", "touchend"])
delete this.songSelBtn delete this.songSelBtn
} }
} }

View File

@ -12,6 +12,7 @@ class GameRules{
break break
case "hard": case "hard":
case "oni": case "oni":
case "ura":
this.good = 3 / 2 * frame this.good = 3 / 2 * frame
this.ok = 9 / 2 * frame this.ok = 9 / 2 * frame
this.bad = 13 / 2 * frame this.bad = 13 / 2 * frame

View File

@ -6,6 +6,15 @@ class Loader{
this.canvasTest = new CanvasTest() this.canvasTest = new CanvasTest()
p2 = new P2Connection() p2 = new P2Connection()
this.ajax("src/views/loader.html").then(this.run.bind(this)) this.ajax("src/views/loader.html").then(this.run.bind(this))
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
event.preventDefault()
})
var versionDiv = document.getElementById("version")
var versionLink = document.getElementById("version-link")
pageEvents.add(versionDiv, ["click", "touchend"], () => {
versionLink.click()
})
} }
run(page){ run(page){
this.promises = [] this.promises = []
@ -152,5 +161,6 @@ class Loader{
delete this.loaderPercentage delete this.loaderPercentage
delete this.loaderProgress delete this.loaderProgress
delete this.promises delete this.promises
pageEvents.remove(root, "touchstart")
} }
} }

View File

@ -1,5 +1,4 @@
function toggleFullscreen(){ function toggleFullscreen(){
var root = document.documentElement
if("requestFullscreen" in root){ if("requestFullscreen" in root){
if(document.fullscreenElement){ if(document.fullscreenElement){
document.exitFullscreen() document.exitFullscreen()
@ -20,6 +19,8 @@ function toggleFullscreen(){
} }
} }
} }
var root = document.documentElement
var fullScreenSupported = "requestFullscreen" in root || "webkitRequestFullscreen" in root || "mozRequestFullScreen" in root
var pageEvents = new PageEvents() var pageEvents = new PageEvents()
var snd = {} var snd = {}

View File

@ -8,6 +8,10 @@ class PageEvents{
this.add(window, "mousemove", this.mouseEvent.bind(this)) this.add(window, "mousemove", this.mouseEvent.bind(this))
} }
add(target, type, callback){ add(target, type, callback){
if(Array.isArray(type)){
type.forEach(type => this.add(target, type, callback))
return
}
this.remove(target, type) this.remove(target, type)
var addedEvent = this.allEvents.get(target) var addedEvent = this.allEvents.get(target)
if(!addedEvent){ if(!addedEvent){
@ -18,6 +22,10 @@ class PageEvents{
return target.addEventListener(type, callback) return target.addEventListener(type, callback)
} }
remove(target, type){ remove(target, type){
if(Array.isArray(type)){
type.forEach(type => this.remove(target, type))
return
}
var addedEvent = this.allEvents.get(target) var addedEvent = this.allEvents.get(target)
if(addedEvent){ if(addedEvent){
var callback = addedEvent.get(type) var callback = addedEvent.get(type)

View File

@ -22,7 +22,14 @@
{name: false, txt: false}, {name: false, txt: false},
{name: "balloon", txt: "ふうせん"} {name: "balloon", txt: "ふうせん"}
] ]
this.courseTypes = ["easy", "normal", "hard", "oni"] this.courseTypes = {
"0": "easy",
"1": "normal",
"2": "hard",
"3": "oni",
"4": "ura",
"edit": "ura"
}
this.metadata = this.parseMetadata() this.metadata = this.parseMetadata()
this.measures = [] this.measures = []
@ -67,10 +74,11 @@
value = value.trim() value = value.trim()
if(name === "course"){ if(name === "course"){
value = value.toLowerCase()
if(value in this.courseTypes){ if(value in this.courseTypes){
courseName = this.courseTypes[value] courseName = this.courseTypes[value]
}else{ }else{
courseName = value.toLowerCase() courseName = value
} }
}else if(name === "balloon"){ }else if(name === "balloon"){
value = value ? value.split(",").map(digit => parseInt(digit)) : [] value = value ? value.split(",").map(digit => parseInt(digit)) : []

View File

@ -10,7 +10,7 @@ class Scoresheet{
this.canvas = document.getElementById("canvas") this.canvas = document.getElementById("canvas")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
this.font = "TnT" this.font = "TnT, Meiryo, sans-serif"
this.state = { this.state = {
screen: "fadeIn", screen: "fadeIn",
screenMS: this.getMS(), screenMS: this.getMS(),
@ -89,8 +89,7 @@ class Scoresheet{
this.winH = null this.winH = null
pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this))
pageEvents.add(this.canvas, "mousedown", this.mouseDown.bind(this)) pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this))
pageEvents.add(this.canvas, "touchstart", this.mouseDown.bind(this))
} }
redraw(){ redraw(){
@ -670,8 +669,7 @@ class Scoresheet{
snd.musicGain.fadeIn() snd.musicGain.fadeIn()
this.redrawRunning = false this.redrawRunning = false
pageEvents.keyRemove(this, "all") pageEvents.keyRemove(this, "all")
pageEvents.remove(this.canvas, "mousedown") pageEvents.remove(this.canvas, ["mousedown", "touchstart"])
pageEvents.remove(this.canvas, "touchstart")
delete this.ctx delete this.ctx
delete this.canvas delete this.canvas
} }

View File

@ -78,7 +78,7 @@ class SongSelect{
outline: "#656565" outline: "#656565"
} }
} }
this.font = "TnT" this.font = "TnT, Meiryo, sans-serif"
this.songs = [] this.songs = []
for(let song of assets.songs){ for(let song of assets.songs){
@ -149,7 +149,7 @@ class SongSelect{
this.difficultyCache = new CanvasCache() this.difficultyCache = new CanvasCache()
this.difficulty = ["かんたん", "ふつう", "むずかしい", "おに"] this.difficulty = ["かんたん", "ふつう", "むずかしい", "おに"]
this.difficultyId = ["easy", "normal", "hard", "oni"] this.difficultyId = ["easy", "normal", "hard", "oni", "ura"]
this.selectedSong = 0 this.selectedSong = 0
this.selectedDiff = 0 this.selectedDiff = 0
@ -181,6 +181,7 @@ class SongSelect{
screenMS: this.getMS(), screenMS: this.getMS(),
move: 0, move: 0,
moveMS: 0, moveMS: 0,
ura: 0,
moveHover: null, moveHover: null,
locked: true, locked: true,
hasPointer: false hasPointer: false
@ -210,12 +211,11 @@ class SongSelect{
this.redraw() this.redraw()
pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this))
pageEvents.add(this.canvas, "mousemove", this.mouseMove.bind(this)) pageEvents.add(this.canvas, "mousemove", this.mouseMove.bind(this))
pageEvents.add(this.canvas, "mousedown", this.mouseDown.bind(this)) pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this))
pageEvents.add(this.canvas, "touchstart", this.mouseDown.bind(this)) if(touchEnabled && fullScreenSupported){
if(touchEnabled){
this.touchFullBtn = document.getElementById("touch-full-btn") this.touchFullBtn = document.getElementById("touch-full-btn")
this.touchFullBtn.style.display = "block" this.touchFullBtn.style.display = "block"
pageEvents.add(this.touchFullBtn, "click", toggleFullscreen) pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen)
} }
} }
@ -306,6 +306,12 @@ class SongSelect{
|| mouse.y < 40 || mouse.y > 540 || mouse.y < 40 || mouse.y > 540
){ ){
this.toSongSelect() this.toSongSelect()
}else if(moveBy === 5){
this.state.ura = !this.state.ura
assets.sounds["ka"].play()
if(this.selectedDiff === 5 && !this.state.ura){
this.state.move = -1
}
}else if(moveBy !== null){ }else if(moveBy !== null){
this.toLoadSong(moveBy - 1, shift, ctrl, touch) this.toLoadSong(moveBy - 1, shift, ctrl, touch)
} }
@ -370,10 +376,10 @@ class SongSelect{
if(this.state.locked === 0){ if(this.state.locked === 0){
if(100 < x && x < 160 && 120 < y && y < 420){ if(100 < x && x < 160 && 120 < y && y < 420){
return 0 return 0
}else if(434 < x && x < 810 && 95 < y && y < 524){ }else if(422 < x && x < 922 && 95 < y && y < 524){
var moveBy = Math.floor((x - 434) / ((810 - 434) / 4)) + 1 var moveBy = Math.floor((x - 422) / ((922 - 422) / 5)) + 1
var currentSong = this.songs[this.selectedSong] var currentSong = this.songs[this.selectedSong]
if(currentSong.stars[moveBy - 1]){ if(this.state.ura && moveBy === 4 || currentSong.stars[moveBy - 1]){
return moveBy return moveBy
} }
} }
@ -425,6 +431,10 @@ class SongSelect{
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
this.state.locked = true this.state.locked = true
this.state.moveHover = null this.state.moveHover = null
this.state.ura = 0
if(this.selectedDiff === 5){
this.selectedDiff = 4
}
assets.sounds["don"].play() assets.sounds["don"].play()
assets.sounds["song-select"].stop() assets.sounds["song-select"].stop()
@ -468,6 +478,10 @@ class SongSelect{
localStorage["selectedSong"] = this.selectedSong localStorage["selectedSong"] = this.selectedSong
localStorage["selectedDiff"] = difficulty + 1 localStorage["selectedDiff"] = difficulty + 1
if(difficulty === 3 && this.state.ura){
difficulty = 4
}
new loadSong({ new loadSong({
"title": selectedSong.title, "title": selectedSong.title,
"folder": selectedSong.id, "folder": selectedSong.id,
@ -557,7 +571,7 @@ class SongSelect{
}) })
this.categoryCache.resize(280, (this.songAsset.marginTop + 1) * categories , ratio + 0.5) this.categoryCache.resize(280, (this.songAsset.marginTop + 1) * categories , ratio + 0.5)
this.difficultyCache.resize((44 + 56 + 2) * 4, 135 + 10, ratio + 0.5) this.difficultyCache.resize((44 + 56 + 2) * 5, 135 + 10, ratio + 0.5)
}else if(!document.hasFocus()){ }else if(!document.hasFocus()){
this.pointer(false) this.pointer(false)
return return
@ -698,9 +712,28 @@ class SongSelect{
this.state.locked = 0 this.state.locked = 0
} }
if(this.state.move){ if(this.state.move){
var hasUra = currentSong.stars[4]
var previousSelection = this.selectedDiff
do{ do{
this.selectedDiff = this.mod(5, this.selectedDiff + this.state.move) if(hasUra && this.state.move > 0){
}while(this.selectedDiff !== 0 && !currentSong.stars[this.selectedDiff - 1]) this.selectedDiff += this.state.move
if(this.selectedDiff > 5){
this.state.ura = !this.state.ura
if(this.state.ura){
this.selectedDiff = previousSelection === 4 ? 5 : previousSelection
break
}else{
this.state.move = -1
}
}
}else{
this.selectedDiff = this.mod(6, this.selectedDiff + this.state.move)
}
}while(
this.selectedDiff !== 0 && !currentSong.stars[this.selectedDiff - 1]
|| this.selectedDiff === 4 && this.state.ura
|| this.selectedDiff === 5 && !this.state.ura
)
this.state.move = 0 this.state.move = 0
}else if(!currentSong.stars[this.selectedDiff - 1]){ }else if(!currentSong.stars[this.selectedDiff - 1]){
this.selectedDiff = 0 this.selectedDiff = 0
@ -903,19 +936,19 @@ class SongSelect{
} }
} }
} }
for(var i = 0; currentSong.stars && i < 4; i++){ var drawDifficulty = (ctx, i, currentUra) => {
if(currentSong.stars[i]){ if(currentSong.stars[i] || currentUra){
if(songSel){ if(songSel){
var _x = x + 33 + i * 60 var _x = x + 33 + i * 60
var _y = y + 120 var _y = y + 120
ctx.fillStyle = "#ff9f18" ctx.fillStyle = currentUra ? "#006279" : "#ff9f18"
ctx.beginPath() ctx.beginPath()
ctx.arc(_x, _y + 22, 22, -Math.PI, 0) ctx.arc(_x, _y + 22, 22, -Math.PI, 0)
ctx.arc(_x, _y + 266, 22, 0, Math.PI) ctx.arc(_x, _y + 266, 22, 0, Math.PI)
ctx.fill() ctx.fill()
this.draw.diffIcon({ this.draw.diffIcon({
ctx: ctx, ctx: ctx,
diff: i, diff: currentUra ? 4 : i,
x: _x, x: _x,
y: _y - 8, y: _y - 8,
scale: 1, scale: 1,
@ -937,13 +970,13 @@ class SongSelect{
ctx.lineWidth = 4.5 ctx.lineWidth = 4.5
ctx.fillRect(_x - 35.5, _y + 2, 71, 380) ctx.fillRect(_x - 35.5, _y + 2, 71, 380)
ctx.strokeRect(_x - 35.5, _y + 2, 71, 380) ctx.strokeRect(_x - 35.5, _y + 2, 71, 380)
ctx.fillStyle = "#fff" ctx.fillStyle = currentUra ? "#006279" : "#fff"
ctx.lineWidth = 2.5 ctx.lineWidth = 2.5
ctx.fillRect(_x - 28, _y + 19, 56, 351) ctx.fillRect(_x - 28, _y + 19, 56, 351)
ctx.strokeRect(_x - 28, _y + 19, 56, 351) ctx.strokeRect(_x - 28, _y + 19, 56, 351)
this.draw.diffIcon({ this.draw.diffIcon({
ctx: ctx, ctx: ctx,
diff: i, diff: currentUra ? 4 : i,
x: _x, x: _x,
y: _y - 12, y: _y - 12,
scale: 1.4, scale: 1.4,
@ -957,7 +990,7 @@ class SongSelect{
y: songSel ? _y + 10 : _y + 23, y: songSel ? _y + 10 : _y + 23,
w: songSel ? 44 : 56, w: songSel ? 44 : 56,
h: (songSel ? 88 : 135) + 10, h: (songSel ? 88 : 135) + 10,
id: this.difficulty[i] + (songSel ? "1" : "0") id: this.difficulty[currentUra ? 4 : i] + (songSel ? "1" : "0")
}, ctx => { }, ctx => {
this.draw.verticalText({ this.draw.verticalText({
ctx: ctx, ctx: ctx,
@ -966,19 +999,22 @@ class SongSelect{
y: 0, y: 0,
width: songSel ? 44 : 56, width: songSel ? 44 : 56,
height: songSel ? (i === 1 ? 66 : 88) : (i === 0 ? 130 : (i === 1 ? 110 : 135)), height: songSel ? (i === 1 ? 66 : 88) : (i === 0 ? 130 : (i === 1 ? 110 : 135)),
fill: "#000", fill: currentUra ? "#fff" : "#000",
fontSize: songSel ? 25 : (i === 2 ? 45 : 40), fontSize: songSel ? 25 : (i === 2 ? 45 : 40),
fontFamily: this.font fontFamily: this.font,
outline: currentUra ? "#003C52" : false,
outlineSize: currentUra ? this.songAsset.letterBorder : 0
}) })
}) })
var songStars = currentUra ? currentSong.stars[4] : currentSong.stars[i]
for(var j = 0; j < 10; j++){ for(var j = 0; j < 10; j++){
if(songSel){ if(songSel){
var yPos = _y + 113 + j * 17 var yPos = _y + 113 + j * 17
}else{ }else{
var yPos = _y + 178 + j * 19.5 var yPos = _y + 178 + j * 19.5
} }
if(10 - j > currentSong.stars[i]){ if(10 - j > songStars){
ctx.fillStyle = songSel ? "#e97526" : "#e7e7e7" ctx.fillStyle = currentUra ? "#187085" : (songSel ? "#e97526" : "#e7e7e7")
ctx.beginPath() ctx.beginPath()
ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2) ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2)
ctx.fill() ctx.fill()
@ -986,12 +1022,17 @@ class SongSelect{
this.draw.diffStar({ this.draw.diffStar({
ctx: ctx, ctx: ctx,
songSel: songSel, songSel: songSel,
ura: currentUra,
x: _x, x: _x,
y: yPos, y: yPos,
ratio: ratio ratio: ratio
}) })
} }
} }
var currentDiff = this.selectedDiff - 1
if(this.selectedDiff === 5){
currentDiff = 3
}
if(i === currentSong.p2Cursor){ if(i === currentSong.p2Cursor){
this.draw.diffCursor({ this.draw.diffCursor({
ctx: ctx, ctx: ctx,
@ -999,13 +1040,12 @@ class SongSelect{
x: _x, x: _x,
y: _y - (songSel ? 45 : 65), y: _y - (songSel ? 45 : 65),
two: true, two: true,
side: songSel ? false : (currentSong.p2Cursor === this.selectedDiff - 1), side: songSel ? false : (currentSong.p2Cursor === currentDiff),
scale: songSel ? 0.7 : 1 scale: songSel ? 0.7 : 1
}) })
} }
if(!songSel){ if(!songSel){
var highlight = 0 var highlight = 0
var currentDiff = this.selectedDiff - 1
if(this.state.moveHover - 1 === i){ if(this.state.moveHover - 1 === i){
highlight = 2 highlight = 2
}else if(currentDiff === i){ }else if(currentDiff === i){
@ -1035,6 +1075,42 @@ class SongSelect{
} }
} }
} }
for(var i = 0; currentSong.stars && i < 4; i++){
var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.stars[4] && songSel)
if(songSel && currentUra){
drawDifficulty(ctx, i, false)
var elapsedMS = this.state.screenMS > this.state.moveMS ? this.state.screenMS : this.state.moveMS
var fade = ((ms - elapsedMS) % 4000) / 4000
var alphaFade = 0
if(fade > 0.95){
alphaFade = this.draw.easeOut(1 - (fade - 0.95) * 20)
}else if(fade > 0.5){
alphaFade = 1
}else if(fade > 0.45){
alphaFade = this.draw.easeIn((fade - 0.45) * 20)
}
this.draw.alpha(alphaFade, ctx, ctx => {
drawDifficulty(ctx, i, true)
})
}else{
drawDifficulty(ctx, i, currentUra)
}
}
if(!songSel && currentSong.stars[4]){
var fade = ((ms - this.state.screenMS) % 1200) / 1200
var _x = x + 402 + 4 * 100 + fade * 25
var _y = y + 258
ctx.save()
ctx.globalAlpha = this.draw.easeInOut(1 - fade)
ctx.fillStyle = "#e0be28"
ctx.beginPath()
ctx.moveTo(_x - 35, _y - 25)
ctx.lineTo(_x - 10, _y)
ctx.lineTo(_x - 35, _y + 25)
ctx.fill()
ctx.restore()
}
ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2 ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2
ctx.fillStyle = selectedSkin.background ctx.fillStyle = selectedSkin.background
ctx.fillRect(x, y, w, h) ctx.fillRect(x, y, w, h)
@ -1066,8 +1142,6 @@ class SongSelect{
fontFamily: this.font fontFamily: this.font
}) })
}) })
//ctx.fillStyle="#f00"
//ctx.fillRect(textX,textY,textW,textH)
} }
}) })
@ -1212,6 +1286,9 @@ class SongSelect{
var id = idDiff.id |0 var id = idDiff.id |0
var diff = idDiff.diff var diff = idDiff.diff
var diffId = this.difficultyId.indexOf(diff) var diffId = this.difficultyId.indexOf(diff)
if(diffId > 3){
diffId = 3
}
if(diffId >= 0){ if(diffId >= 0){
var currentSong = this.songs.find(song => song.id === id) var currentSong = this.songs.find(song => song.id === id)
currentSong.p2Cursor = diffId currentSong.p2Cursor = diffId
@ -1255,10 +1332,8 @@ class SongSelect{
this.redrawRunning = false this.redrawRunning = false
this.endPreview() this.endPreview()
pageEvents.keyRemove(this, "all") pageEvents.keyRemove(this, "all")
pageEvents.remove(this.canvas, "mousemove") pageEvents.remove(this.canvas, ["mousemove", "mousedown", "touchstart"])
pageEvents.remove(this.canvas, "mousedown") if(this.touchEnabled && fullScreenSupported){
pageEvents.remove(this.canvas, "touchstart")
if(this.touchEnabled){
pageEvents.remove(this.touchFullBtn, "click") pageEvents.remove(this.touchFullBtn, "click")
delete this.touchFullBtn delete this.touchFullBtn
} }

View File

@ -2,11 +2,7 @@
constructor(){ constructor(){
var AudioContext = window.AudioContext || window.webkitAudioContext var AudioContext = window.AudioContext || window.webkitAudioContext
this.context = new AudioContext() this.context = new AudioContext()
pageEvents.once(window, "click").then(() => { pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this))
if(this.context.state === "suspended"){
this.context.resume()
}
})
} }
load(url, gain){ load(url, gain){
return loader.ajax(url, request => { return loader.ajax(url, request => {
@ -48,6 +44,11 @@
source.connect(sound.gain.gainNode || this.context.destination) source.connect(sound.gain.gainNode || this.context.destination)
return source return source
} }
pageClicked(){
if(this.context.state === "suspended"){
this.context.resume()
}
}
} }
class SoundGain{ class SoundGain{
constructor(soundBuffer, channel){ constructor(soundBuffer, channel){
@ -178,7 +179,9 @@ class Sound{
stop(time, absolute){ stop(time, absolute){
time = this.convertTime(time, absolute) time = this.convertTime(time, absolute)
this.sources.forEach(source => { this.sources.forEach(source => {
source.stop(Math.max(source.startTime, time)) try{
source.stop(Math.max(source.startTime, time))
}catch(e){}
}) })
this.setTimeouts(time).then(() => { this.setTimeouts(time).then(() => {
if(this.loop){ if(this.loop){

View File

@ -3,8 +3,7 @@ class Titlescreen{
loader.changePage("titlescreen") loader.changePage("titlescreen")
this.titleScreen = document.getElementById("title-screen") this.titleScreen = document.getElementById("title-screen")
pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this))
pageEvents.add(this.titleScreen, "mousedown", this.onPressed.bind(this)) pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], this.onPressed.bind(this))
pageEvents.once(this.titleScreen, "touchstart").then(this.onPressed.bind(this))
assets.sounds["title"].play() assets.sounds["title"].play()
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
"13": ["a", "b", "x", "y", "start", "ls", "rs"] "13": ["a", "b", "x", "y", "start", "ls", "rs"]
@ -48,8 +47,7 @@ class Titlescreen{
this.gamepad.clean() this.gamepad.clean()
assets.sounds["title"].stop() assets.sounds["title"].stop()
pageEvents.keyRemove(this, "all") pageEvents.keyRemove(this, "all")
pageEvents.remove(this.titleScreen, "mousedown") pageEvents.remove(this.titleScreen, ["mousedown", "touchstart"])
pageEvents.remove(this.titleScreen, "touchstart")
delete this.titleScreen delete this.titleScreen
} }
} }

View File

@ -5,8 +5,7 @@ class Tutorial{
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")
pageEvents.once(this.endButton, "mousedown").then(this.onEnd.bind(this)) pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this))
pageEvents.once(this.endButton, "touchstart").then(this.onEnd.bind(this))
pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this)) pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this))
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
@ -29,7 +28,7 @@ class Tutorial{
clean(){ clean(){
this.gamepad.clean() this.gamepad.clean()
assets.sounds["bgm_setsume"].stop() assets.sounds["bgm_setsume"].stop()
pageEvents.remove(this.endButton, "click") pageEvents.remove(this.endButton, ["mousedown", "touchstart"])
pageEvents.keyRemove(this, 13) pageEvents.keyRemove(this, 13)
delete this.endButton delete this.endButton
} }

View File

@ -64,16 +64,19 @@ class View{
pageEvents.add(this.canvas.canvas, "touchstart", this.ontouch.bind(this)) pageEvents.add(this.canvas.canvas, "touchstart", this.ontouch.bind(this))
this.touchFullBtn = document.getElementById("touch-full-btn") this.touchFullBtn = document.getElementById("touch-full-btn")
pageEvents.add(this.touchFullBtn, "click", toggleFullscreen) pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen)
if(!fullScreenSupported){
this.touchFullBtn.style.display = "none"
}
this.touchPauseBtn = document.getElementById("touch-pause-btn") this.touchPauseBtn = document.getElementById("touch-pause-btn")
pageEvents.add(this.touchPauseBtn, "click", () => { pageEvents.add(this.touchPauseBtn, "touchend", () => {
this.controller.togglePauseMenu() this.controller.togglePauseMenu()
}) })
} }
} }
run(){ run(){
this.ctx.font = "normal 14pt TnT" this.ctx.font = "normal 14pt TnT, Meiryo, sans-serif"
this.setBackground() this.setBackground()
if(this.controller.multiplayer !== 2){ if(this.controller.multiplayer !== 2){
@ -318,7 +321,7 @@ class View{
var comboX = this.taikoX + this.taikoW / 2 var comboX = this.taikoX + this.taikoW / 2
var comboY = this.barY + this.barH / 2 var comboY = this.barY + this.barH / 2
var fontSize = this.taikoH * 0.4 var fontSize = this.taikoH * 0.4
this.ctx.font = "normal " + fontSize + "px TnT" this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
this.ctx.strokeStyle = "#000" this.ctx.strokeStyle = "#000"
this.ctx.lineWidth = fontSize / 10 this.ctx.lineWidth = fontSize / 10
@ -354,7 +357,7 @@ class View{
}else{ }else{
this.ctx.fillStyle = "#fff" this.ctx.fillStyle = "#fff"
} }
this.ctx.font = "normal " + fontSize + "px TnT" this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif"
this.ctx.lineWidth = fontSize / 5 this.ctx.lineWidth = fontSize / 5
this.strokeFillText("コンボ", this.strokeFillText("コンボ",
comboX, comboX,
@ -386,7 +389,7 @@ class View{
var fontSize = 0.7 * this.scoreSquareH var fontSize = 0.7 * this.scoreSquareH
// Draw score text // Draw score text
this.ctx.font = "normal " + fontSize + "px TnT" this.ctx.font = "normal " + fontSize + "px TnT, Meiryo, sans-serif"
this.ctx.fillStyle = "#fff" this.ctx.fillStyle = "#fff"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
var glyph = this.ctx.measureText("0").width var glyph = this.ctx.measureText("0").width
@ -946,15 +949,15 @@ class View{
} }
clean(){ clean(){
pageEvents.mouseRemove(this) pageEvents.mouseRemove(this)
if(this.controller.multiplayer === 2){ if(this.controller.multiplayer === 2 && this.canvas){
this.canvas.canvas.parentNode.removeChild(this.canvas.canvas) this.canvas.canvas.parentNode.removeChild(this.canvas.canvas)
}else{ }else{
this.cursor.parentNode.removeChild(this.cursor) this.cursor.parentNode.removeChild(this.cursor)
} }
if(this.touchEnabled){ if(this.touchEnabled){
pageEvents.remove(this.canvas.canvas, "touchstart") pageEvents.remove(this.canvas.canvas, "touchstart")
pageEvents.remove(this.touchFullBtn, "click") pageEvents.remove(this.touchFullBtn, "touchend")
pageEvents.remove(this.touchPauseBtn, "click") pageEvents.remove(this.touchPauseBtn, "touchend")
this.gameDiv.classList.remove("touch-visible") this.gameDiv.classList.remove("touch-visible")
document.getElementById("version").classList.remove("version-hide") document.getElementById("version").classList.remove("version-hide")
delete this.touchDrumDiv delete this.touchDrumDiv

View File

@ -59,9 +59,9 @@
<div id="screen"></div> <div id="screen"></div>
<div id="version"> <div id="version">
{% if version %} {% if version %}
<a href="https://github.com/bui/taiko-web/commit/{{version.commit}}" target="_blank" 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>
{% else %} {% else %}
<a href="https://github.com/bui/taiko-web" target="_blank" class="stroke-sub" alt="taiko-web (unknown version)">taiko-web (unknown version)</a> <a href="https://github.com/bui/taiko-web" target="_blank" id="version-link" class="stroke-sub" alt="taiko-web (unknown version)">taiko-web (unknown version)</a>
{% endif %} {% endif %}
</div> </div>
<script src="/src/js/main.js?{{version.commit_short}}"></script> <script src="/src/js/main.js?{{version.commit_short}}"></script>