Merge pull request #17 from LoveEevee/balloons-drumrolls

Add balloon and drumroll notes
This commit is contained in:
Bui 2018-09-15 18:44:40 +01:00 committed by GitHub
commit 938931d7af
13 changed files with 1224 additions and 1218 deletions

View File

@ -1,32 +1,29 @@
#scoresheet{ .scoresheet{
width:100%; width:100%;
height:100%; height:100%;
background: #e84019;
color:black; color:black;
font-family: TnT; font-family: TnT;
background: url('/assets/img/bg-pattern-2.png'); background: url("/assets/img/bg-pattern-2.png");
position: absolute;
} }
#scoresheet h2{ .scoresheet h2{
position:absolute; position:absolute;
top:1%; top:1%;
left:1%; left:1%;
font-size: 7vmin; font-size: 7vmin;
margin:0; margin:0;
color: white; color: white;
} }
#result-window{ .result-window{
width:70%; width:70%;
margin:auto; margin:auto;
} }
#scoresheet button{ .scoresheet button{
height: 50%;
height: 15%; min-width:20%;
width:20%;
position: absolute; position: absolute;
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
@ -38,45 +35,50 @@
border-radius: 10px; border-radius: 10px;
outline: none; outline: none;
top:10%; top:10%;
white-space: nowrap;
} }
#replay{ .scoresheet .replay{
left:1%; left:1%;
} }
#song-select{ .scoresheet .song-select{
left:23%; left:23%;
} }
#scoresheet button:hover{ .scoresheet button:hover{
border-color:#fa5d3a; border-color:#fa5d3a;
color:white; color:white;
background:#0c6577; background:#0c6577;
} }
#result-bar{ .scoresheet .result-bar{
width: 100%; max-width: 120vh;
height:40%; height: 71vh;
position:absolute;
top:10%;
left:0;
border-bottom:10px inset #b6361d;
border-top:5px solid #b23111;
min-height: 200px; min-height: 200px;
display:flex;
flex-direction: column;
justify-content: center;
align-items: flex-end;
position: absolute;
left: 0;
right: 0;
margin: auto;
} }
#score-cont{ .scoresheet .score-cont{
position:absolute; position:relative;
right:1%; right:1%;
width:60%; width:60%;
height:80%; height:80%;
background:rgba(255,255,255,0.7); background:rgba(255,255,255,0.7);
border-radius:15px; border-radius:15px;
margin: 10px;
max-height: 33vh;
} }
#score-hp-bar-bg{ .scoresheet .score-hp-bar-bg{
position: absolute; position: relative;
margin-top:2%; margin-top:2%;
margin-left:5%; margin-left:5%;
background: url("/assets/img/hp-bar-bg.png"); background: url("/assets/img/hp-bar-bg.png");
@ -85,12 +87,12 @@
} }
#score-hp-bar-colour{ .scoresheet .score-hp-bar-colour{
position:absolute; position:absolute;
padding: 0; padding: 0;
} }
#score-hp-bar-colour img{ .scoresheet .score-hp-bar-colour img{
position:absolute; position:absolute;
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -98,8 +100,8 @@
padding:0; padding:0;
} }
#score-points{ .scoresheet .score-points{
width:30%; min-width:30%;
height:18%; height:18%;
background:black; background:black;
border:5px solid #ae7a26; border:5px solid #ae7a26;
@ -110,61 +112,95 @@
color: white; color: white;
font-size: 5vmin; font-size: 5vmin;
text-align: right; text-align: right;
padding-right:2%; padding: .3% 1%;
white-space: nowrap;
} }
#score-details{ .scoresheet .score-details{
position: absolute; position: absolute;
right:5%; right:5%;
width:50%; width:70%;
height:50%; height:50%;
color:white; color:white;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: black;
} }
#score-details td{ .scoresheet .score-details th,
.scoresheet .score-details td{
font-size: 3vmin; font-size: 3vmin;
font-weight: normal;
white-space: nowrap;
}
.scoresheet .score-details td{
text-align: right; text-align: right;
} }
.floatLeft{ .scoresheet .value{
text-align: left !important; width: 25%;
} }
.value{ .scoresheet .bottom-part{
width:25%; position: fixed;
}
#bottom-part{
width:100%; width:100%;
position: absolute; height:19vh;
bottom:0;
-webkit-box-shadow: inset 0px 10px 20px -5px #ee6d46; -webkit-box-shadow: inset 0px 10px 20px -5px #ee6d46;
-moz-box-shadow: inset 0px 10px 20px -5px #ee6d46; -moz-box-shadow: inset 0px 10px 20px -5px #ee6d46;
box-shadow: inset 0px 10px 20px -5px #ee6d46; box-shadow: inset 0px 10px 20px -5px #ee6d46;
border-top:10px outset #b6361d;
box-sizing: border-box;
} }
#score-mark{ .scoresheet .score-mark{
position: absolute; position: absolute;
top: 0;
bottom: 0;
right: 105%;
height: 40%;
margin: auto;
} }
.gradient-overlay{ .scoresheet .gradient-overlay{
position:absolute; position:absolute;
width:100%; width:100%;
height:100%; height:100%;
background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,165,100,0.64) 62%, rgba(255,165,100,0.65) 63%); /* FF3.6+ */ background: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(255,165,100,0.64) 62%, rgba(255,165,100,0.65) 63%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(62%,rgba(255,165,100,0.64)), color-stop(63%,rgba(255,165,100,0.65))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(255,165,100,0.64) 62%,rgba(255,165,100,0.65) 63%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(255,165,100,0.64) 62%,rgba(255,165,100,0.65) 63%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(255,165,100,0.64) 62%,rgba(255,165,100,0.65) 63%); /* IE10+ */
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(255,165,100,0.64) 62%,rgba(255,165,100,0.65) 63%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#a6ffa564',GradientType=0 ); /* IE6-9 */
} }
#top-part{ .scoresheet .top-part{
width:100%; width:100%;
height:10%; height:10vh;
background:#e84019; background:#e84019;
border-bottom:5px solid #b23111;
box-sizing: border-box;
}
.header-great,
.header-fail{
color: transparent;
}
.header-great::after,
.header-fail::after{
content: attr(alt);
color: transparent;
-webkit-background-clip: text;
background-clip: text;
position: absolute;
width: 100%;
left: 0;
}
.header-great::after{
background-image: linear-gradient(0deg, #f00 10%, #fe0 70%);
}
.header-fail::after{
background-image: linear-gradient(0deg, #00b3df 30%, #6a62f9 90%);
}
.scoresheet .stroke-sub{
position:relative;
z-index:1;
}
.scoresheet .stroke-sub::before{
left:auto;
} }

View File

@ -28,7 +28,8 @@ var assets = {
'muzu_hard.png', 'muzu_hard.png',
'muzu_oni.png', 'muzu_oni.png',
'don_anim_normal.png', 'don_anim_normal.png',
'don_anim_10combo.png' 'don_anim_10combo.png',
'balloon.png'
], ],
audioSfx: [ audioSfx: [
@ -83,6 +84,7 @@ var assets = {
'note_don.ogg', 'note_don.ogg',
'note_ka.ogg', 'note_ka.ogg',
'balloon.ogg'
], ],
audioMusic:[ audioMusic:[

View File

@ -1,94 +1,80 @@
function Circle(id, ms, type, text, speed){ class Circle{
constructor(id, ms, type, text, speed, endTime, requiredHits){
var _id=id; this.id = id
var _ms = ms; this.ms = ms
var _type = type; this.type = type
var _played = false; this.text = text
var _pos={x:0, y:0}; this.speed = speed
var _animating = false; this.endTime = endTime ? endTime : ms + 150
var _animT = 0; this.isPlayed = false
var _score=0; this.animating = false
var _lastFrame = ms+100; this.animT = 0
var _animationEnded = false; this.score = 0
this.lastFrame = ms + 100
var played=false; //if cirlce has been played this.animationEnded = false
var _status=-1; //check if circle is playable this.status = -1
this.timesHit = 0
// -1 : Not playable this.requiredHits = requiredHits ? requiredHits : 0
// 0 : Playable, giving 0 points if played at current time (fail)
// 50 : Playable, giving 50 points if played at current time (pass)
// 100 : Playable, giving 100 points if played at current time (good)
this.getMS = function(){
return _ms;
}
this.getType = function(){
return _type;
}
this.getLastFrame = function(){
return _lastFrame;
} }
getMS(){
this.incFrame = function(){ return this.ms
_lastFrame+=20;
} }
getEndTime(){
this.animate = function(){ return this.endTime
_animating=true;
} }
getType(){
this.isAnimated = function(){ return this.type
return _animating;
} }
getLastFrame(){
this.getAnimT = function(){ return this.lastFrame
return _animT;
} }
incFrame(){
this.incAnimT = function(){ this.lastFrame += 20
_animT+=0.05;
} }
animate(){
this.updateStatus = function(status){ this.animating = true
_status=status;
}
this.getStatus = function(){
return _status;
}
this.getPlayed = function(){
return _played;
}
this.isAnimationFinished = function(){
return _animationEnded;
} }
isAnimated(){
this.endAnimation = function(){ return this.animating
_animationEnded = true;
} }
getAnimT(){
this.played = function(score){ return this.animT
_score=score; }
_played=true; incAnimT(){
} this.animT += 0.05
}
this.getScore = function(){ updateStatus(status){
return _score; this.status = status
}
getStatus(){
return this.status
}
getPlayed(){
return this.isPlayed
}
isAnimationFinished(){
return this.animationEnded
}
endAnimation(){
this.animationEnded = true
}
played(score){
this.score = score
this.isPlayed = true
}
hit(){
this.timesHit++
}
getScore(){
return this.score
}
getID(){
return this.id
}
getText(){
return this.text
}
getSpeed(){
return this.speed
} }
this.getID = function(){
return _id;
}
this.getText = function(){
return text;
}
this.getSpeed = function(){
return speed;
}
} }

View File

@ -57,6 +57,13 @@ class Controller{
this.mainLoopRunning = true this.mainLoopRunning = true
this.mainLoop() this.mainLoop()
} }
stopMainLoop(){
this.mainLoopRunning = false
this.mainAsset.stop()
if(this.syncWith){
this.syncWith.stopMainLoop()
}
}
mainLoop(){ mainLoop(){
if(this.mainLoopRunning){ if(this.mainLoopRunning){
if(this.multiplayer != 2){ if(this.multiplayer != 2){
@ -88,9 +95,6 @@ class Controller{
this.keyboard.checkMenuKeys() this.keyboard.checkMenuKeys()
} }
} }
getDistanceForCircle(){
return this.view.getDistanceForCircle()
}
togglePauseMenu(){ togglePauseMenu(){
this.togglePause() this.togglePause()
this.view.togglePauseMenu() this.view.togglePauseMenu()
@ -98,43 +102,41 @@ class Controller{
displayResults(){ displayResults(){
var score = this.getGlobalScore() var score = this.getGlobalScore()
var vp var vp
if (score.fail == 0) { if(score.fail == 0){
vp = "fullcombo" vp = "fullcombo"
this.playSoundMeka("fullcombo", 1.350) this.playSoundMeka("fullcombo", 1.350)
} else if (score.hp >= 50) { }else if(score.hp >= 50){
vp = "clear" vp = "clear"
} else { }else{
vp = "fail" vp = "fail"
} }
assets.sounds["game" + vp].play() assets.sounds["game" + vp].play()
setTimeout(() => { setTimeout(() => {
this.mainLoopRunning = false if(this.mainLoopRunning){
if(this.multiplayer != 2){ this.stopMainLoop()
new Scoresheet(this, this.getGlobalScore()) if(this.multiplayer != 2){
new Scoresheet(this, this.getGlobalScore(), this.multiplayer)
}
} }
}, 7000) }, 7000)
} }
displayScore(score, notPlayed){ displayScore(score, notPlayed){
this.view.displayScore(score, notPlayed) this.view.displayScore(score, notPlayed)
} }
fadeOutOver(){
this.game.fadeOutOver()
this.displayResults()
}
getCurrentTimingPoint(){
return this.game.getCurrentTimingPoint()
}
songSelection(){ songSelection(){
$("#music-bg").remove() $("#music-bg").remove()
this.mainLoopRunning = false this.stopMainLoop()
new SongSelect() new SongSelect()
} }
restartSong(){ restartSong(){
this.mainAsset.stop() this.stopMainLoop()
this.mainLoopRunning = false
$("#screen").load("/src/views/game.html", () => { $("#screen").load("/src/views/game.html", () => {
var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) if(this.multiplayer){
taikoGame.run() new loadSong(this.selectedSong, false, true)
}else{
var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled)
taikoGame.run()
}
}) })
} }
playSoundMeka(soundID, time){ playSoundMeka(soundID, time){
@ -144,27 +146,12 @@ class Controller{
} }
assets.sounds[soundID + meka].play(time) assets.sounds[soundID + meka].play(time)
} }
initTiming(){
this.game.initTiming()
}
setHitcircleSpeed(speed){
this.view.setHitcircleSpeed(speed)
}
getHitcircleSpeed(){
return this.game.getHitcircleSpeed()
}
toggleMainMusic(){
this.game.toggleMainMusic()
}
togglePause(){ togglePause(){
if(this.syncWith){ if(this.syncWith){
this.syncWith.game.togglePause() this.syncWith.game.togglePause()
} }
this.game.togglePause() this.game.togglePause()
} }
isPaused(){
return this.game.isPaused()
}
getKeys(){ getKeys(){
return this.keyboard.getKeys() return this.keyboard.getKeys()
} }
@ -186,9 +173,6 @@ class Controller{
getCurrentCircle(){ getCurrentCircle(){
return this.game.getCurrentCircle() return this.game.getCurrentCircle()
} }
updateCurrentCircle(){
this.game.updateCurrentCircle()
}
isWaitingForKeyup(key, type){ isWaitingForKeyup(key, type){
return this.keyboard.isWaitingForKeyup(key, type) return this.keyboard.isWaitingForKeyup(key, type)
} }
@ -198,18 +182,12 @@ class Controller{
getKeyTime(){ getKeyTime(){
return this.keyboard.getKeyTime() return this.keyboard.getKeyTime()
} }
updateCombo(score){
this.game.updateCombo(score)
}
getCombo(){ getCombo(){
return this.game.getCombo() return this.game.getCombo()
} }
getGlobalScore(){ getGlobalScore(){
return this.game.getGlobalScore() return this.game.getGlobalScore()
} }
updateGlobalScore(score){
this.game.updateGlobalScore(score)
}
autoPlay(circle){ autoPlay(circle){
if(this.multiplayer){ if(this.multiplayer){
p2.play(circle, this.mekadon) p2.play(circle, this.mekadon)

View File

@ -1,446 +1,361 @@
function Game(controller, selectedSong, songData){ class Game{
constructor(controller, selectedSong, songData){
var _this = this; this.controller = controller
var _selectedSong = selectedSong; this.selectedSong = selectedSong
this.elapsedTime = {} //current time in ms from the beginning of the song this.songData = songData
var _offsetDate; //date when the chrono is started (before the game begins) this.elapsedTime = {}
var _startDate; //real start date (when the chrono will be 0) this.currentCircle = 0
var _currentDate; // refreshed date this.combo = 0
var _songData=songData; this.globalScore = {
var _currentCircle=0; points: 0,
var _currentScore=0; great: 0,
var _combo=0; good: 0,
var _globalScore={points:0, great:0, good:0, fail:0, maxCombo:0, hp:0, song:selectedSong.title}; fail: 0,
var _HPGain= 100/_songData.circles.length; maxCombo: 0,
var _paused=false; drumroll: 0,
var _started=false; hp: 0,
var _mainMusicPlaying=false; song: selectedSong.title
var _latestDate; }
var _elapsedTimeSincePause=0; this.HPGain = 100 / this.songData.circles.filter(circle => {
var _musicFadeOut=0; var type = circle.getType()
var _fadeOutStarted=false; return type == "don" || type == "ka" || type == "daiDon" || type == "daiKa"
var _currentTimingPoint=0; }).length
var _offsetTime=0; this.paused = false
var _hitcircleSpeed=_songData.difficulty.sliderMultiplier*8; this.started = false
var _timeForDistanceCircle; this.mainMusicPlaying = false
var _mainAsset this.elapsedTimeSincePause = 0
assets.songs.forEach(song => { this.musicFadeOut = 0
if(song.id == selectedSong.folder){ this.fadeOutStarted = false
_mainAsset = song.sound this.currentTimingPoint = 0
} this.offsetTime = 0
}) assets.songs.forEach(song => {
if(song.id == selectedSong.folder){
this.run = function(){ this.mainAsset = song.sound
_timeForDistanceCircle=2500 }
_this.initTiming(); })
} }
run(){
this.initTiming = function(){ this.timeForDistanceCircle = 2500
_offsetDate = new Date(); this.initTiming()
_this.setElapsedTime(-_timeForDistanceCircle |0) }
_offsetTime = _timeForDistanceCircle |0 initTiming(){
_startDate = new Date(); // Date when the chrono is started (before the game begins)
// The real start for the game will start when chrono will reach 0 this.offsetDate = new Date()
_startDate.setMilliseconds(_startDate.getMilliseconds()+_offsetTime); this.offsetTime = this.timeForDistanceCircle |0
} this.setElapsedTime(-this.offsetTime)
// The real start for the game will start when chrono will reach 0
this.update = function(){ this.startDate = new Date()
this.startDate.setMilliseconds(this.startDate.getMilliseconds() + this.offsetTime)
// Main operations }
_this.updateTime(); update(){
_this.checkTiming(); // Main operations
_this.updateCirclesStatus(); this.updateTime()
_this.checkPlays(); this.checkTiming()
this.updateCirclesStatus()
// Event operations this.checkPlays()
_this.whenFadeoutMusic(); // Event operations
_this.whenLastCirclePlayed(); this.whenFadeoutMusic()
this.whenLastCirclePlayed()
} }
getCircles(){
this.getCircles = function(){ return this.songData.circles
return _songData.circles; }
} updateCirclesStatus(){
var circles = this.songData.circles
this.updateCirclesStatus = function(){ circles.forEach(circle => {
if(!circle.getPlayed()){
var circles = _songData.circles; var currentTime = this.getElapsedTime().ms
var startingTime = circle.getMS() - this.timeForDistanceCircle
circles.forEach(function(circle){ // At circle.getMS(), the circle fits the slot
var hitTime = circle.getMS()
if(!circle.getPlayed()){ var endTime = circle.getEndTime()
var type = circle.getType()
var currentTime = _this.getElapsedTime().ms; var normalNotes = type == "don" || type == "daiDon" || type == "ka" || type == "daiKa"
var startingTime = circle.getMS()-_timeForDistanceCircle;
// At circle.getMS(), the circle fits the slot if(currentTime >= startingTime && currentTime <= endTime){
var finishTime = circle.getMS();
if(currentTime>= hitTime - 50 && currentTime < hitTime - 30){
if( currentTime >= startingTime && currentTime <= finishTime+200){ circle.updateStatus(0)
}else if(currentTime>= hitTime - 30 && currentTime < hitTime){
if(currentTime>= finishTime-50 && currentTime < finishTime-30){ circle.updateStatus(230)
circle.updateStatus(0); }else if(currentTime >= hitTime && currentTime < endTime){
} circle.updateStatus(450)
else if(currentTime>= finishTime-30 && currentTime < finishTime){ }
circle.updateStatus(230);
} }else if(currentTime>endTime){
else if(currentTime >= finishTime && currentTime < finishTime+200){ if(type == "balloon" || type == "drumroll" || type == "daiDrumroll"){
circle.updateStatus(450); circle.updateStatus(-1)
} circle.played(0)
this.updateCurrentCircle()
} if(this.controller.multiplayer == 1){
else if(currentTime>finishTime+200 && currentTime<=finishTime+300){ p2.send("drumroll", {
if(controller.multiplayer != 2){ pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit
circle.updateStatus(-1); })
_currentScore=0; }
circle.played(_currentScore); }else{
controller.displayScore(_currentScore, true); if(!this.controller.autoPlayEnabled){
_this.updateCurrentCircle(); circle.updateStatus(-1)
_this.updateCombo(_currentScore); var currentScore = 0
_this.updateGlobalScore(_currentScore); circle.played(currentScore)
} this.controller.displayScore(currentScore, true)
if(controller.multiplayer == 1){ this.updateCurrentCircle()
p2.send("note", { this.updateCombo(currentScore)
score: -1 this.updateGlobalScore(currentScore)
}) }
} if(this.controller.multiplayer == 1){
p2.send("note", {
} score: -1
})
} }
}
}); }
}
} })
}
this.setHPGain = function(gain){ setHPGain(gain){
_HPGain=gain; this.HPGain = gain
} }
checkPlays(){
this.checkPlays = function(){ var circles = this.songData.circles
var circle = circles[this.currentCircle]
var circles = _songData.circles;
var circle = circles[_currentCircle]; if(circle && this.controller.autoPlayEnabled){
return this.controller.autoPlay(circle)
if(circle){ }
if(controller.autoPlayEnabled){ var keys = this.controller.getKeys()
return controller.autoPlay(circle) var kbd = this.controller.getBindings()
} if(keys[kbd["don_l"]]){
var keys = controller.getKeys() this.checkKey(kbd["don_l"], circle)
var kbd = controller.getBindings() }
if(keys[kbd["don_l"]]){ if(keys[kbd["don_r"]]){
_this.checkKey(kbd["don_l"], circle) this.checkKey(kbd["don_r"], circle)
} }
if(keys[kbd["don_r"]]){ if(keys[kbd["ka_l"]]){
_this.checkKey(kbd["don_r"], circle) this.checkKey(kbd["ka_l"], circle)
} }
if(keys[kbd["ka_l"]]){ if(keys[kbd["ka_r"]]){
_this.checkKey(kbd["ka_l"], circle) this.checkKey(kbd["ka_r"], circle)
} }
if(keys[kbd["ka_r"]]){ }
_this.checkKey(kbd["ka_r"], circle) checkKey(keyCode, circle){
} if(!this.controller.isWaitingForKeyup(keyCode, "score")){
} if(circle && !circle.getPlayed() && circle.getStatus() != -1){
this.checkScore(circle)
} }
this.controller.waitForKeyup(keyCode, "score")
this.checkKey = function(keyCode, circle){ }
if(!circle.getPlayed() && !controller.isWaitingForKeyup(keyCode, "score") && circle.getStatus()!=-1){ }
var score = _this.checkScore(circle); checkScore(circle){
circle.played(score); var keys = this.controller.getKeys()
_this.updateCurrentCircle(); var kbd = this.controller.getBindings()
controller.waitForKeyup(keyCode, "score"); var keysDon = keys[kbd["don_l"]] || keys[kbd["don_r"]]
if(controller.multiplayer == 1){ var keysKa = keys[kbd["ka_l"]] || keys[kbd["ka_r"]]
p2.send("note", {
score: score, var type = circle.getType()
ms: circle.getMS() - _this.getElapsedTime().ms var typeDon = type == "don" || type == "daiDon"
}) var typeKa = type == "ka" || type == "daiKa"
}
} if(typeDon || typeKa){
} var score = 0
if(keysDon && typeDon || keysKa && typeKa){
this.checkScore = function(circle){ var circleStatus = circle.getStatus()
if(circleStatus == 230 || circleStatus == 450){
var keys = controller.getKeys() score = circleStatus
var kbd = controller.getBindings() }
this.controller.displayScore(score)
if( }else{
((keys[kbd["don_l"]] || keys[kbd["don_r"]]) && (circle.getType()=="don" || circle.getType()=="daiDon")) || this.controller.displayScore(score, true)
((keys[kbd["ka_l"]] || keys[kbd["ka_r"]]) && (circle.getType()=="ka" || circle.getType()=="daiKa")) }
){ this.updateCombo(score)
this.updateGlobalScore(score)
switch(circle.getStatus()){ this.updateCurrentCircle()
circle.played(score)
case 230: if(this.controller.multiplayer == 1){
_currentScore=230; p2.send("note", {
break; score: score,
ms: circle.getMS() - this.getElapsedTime().ms
case 450: })
_currentScore=450; }
break; }else if(keysDon && type == "balloon"){
this.checkBalloon(circle)
} }else if((keysDon || keysKa) && (type == "drumroll" || type == "daiDrumroll")){
controller.displayScore(_currentScore); this.checkDrumroll(circle)
}
} }
else{ checkBalloon(circle){
_currentScore=0; if(circle.timesHit >= circle.requiredHits - 1){
controller.displayScore(_currentScore, true); var score = 5000
} this.updateCurrentCircle()
circle.hit()
circle.played(score)
_this.updateCombo(_currentScore); if(this.controller.multiplayer == 1){
_this.updateGlobalScore(_currentScore); p2.send("drumroll", {
return _currentScore; pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit
} })
}
this.whenLastCirclePlayed = function(){ }else{
var circles = _songData.circles; var score = 300
var lastCircle = circles[_songData.circles.length-1]; circle.hit()
if(!_fadeOutStarted && _this.getElapsedTime().ms>=lastCircle.getMS()+2000){ }
_fadeOutStarted=_this.getElapsedTime().ms this.globalScore.drumroll ++
} this.globalScore.points += score
} }
checkDrumroll(circle){
this.whenFadeoutMusic = function(){ var score = 100
if(_fadeOutStarted){ circle.hit()
if(_musicFadeOut==0){ var keyTime = this.controller.getKeyTime()
snd.musicGain.fadeOut(1.6) if(circle.getType() == "drumroll"){
_musicFadeOut++ var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka"
if(controller.multiplayer == 1){ }else{
p2.send("gameend") var sound = keyTime["don"] > keyTime["ka"] ? "daiDon" : "daiKa"
} }
} var circleAnim = new Circle(0, this.getElapsedTime().ms, sound, "", circle.speed)
if(_musicFadeOut==1 && _this.getElapsedTime().ms>=_fadeOutStarted+1600){ circleAnim.played(score)
controller.fadeOutOver() circleAnim.animate()
_mainAsset.stop() this.controller.view.drumroll.push(circleAnim)
_musicFadeOut++ this.globalScore.drumroll ++
setTimeout(() => { this.globalScore.points += score
snd.musicGain.fadeIn() }
snd.musicGain.unmute() whenLastCirclePlayed(){
}, 1000) var circles = this.songData.circles
} var lastCircle = circles[this.songData.circles.length - 1]
} if(!this.fadeOutStarted && this.getElapsedTime().ms >= lastCircle.getEndTime() + 1900){
} this.fadeOutStarted=this.getElapsedTime().ms
}
this.checkTiming = function(){ }
whenFadeoutMusic(){
if(_songData.timingPoints[_currentTimingPoint+1]){ if(this.fadeOutStarted){
if(_this.getElapsedTime().ms>=_songData.timingPoints[_currentTimingPoint+1].start){ if(this.musicFadeOut==0){
_currentTimingPoint++; snd.musicGain.fadeOut(1.6)
} if(this.controller.multiplayer == 1){
} p2.send("gameresults", this.controller.getGlobalScore())
} }
this.musicFadeOut++
this.getCurrentTimingPoint = function(){ }
return _songData.timingPoints[_currentTimingPoint]; if(this.musicFadeOut == 1 && this.getElapsedTime().ms >= this.fadeOutStarted + 1600){
} this.controller.displayResults()
this.mainAsset.stop()
this.playMainMusic = function(){ p2.send("gameend")
var ms = _this.getElapsedTime().ms setTimeout(() => {
if(!_mainMusicPlaying && (!_fadeOutStarted || ms<_fadeOutStarted+1600)){ snd.musicGain.fadeIn()
if(controller.multiplayer != 2){ snd.musicGain.unmute()
_mainAsset.play((ms < 0 ? -ms : 0) / 1000, false, Math.max(0, ms / 1000)); }, 1000)
} this.musicFadeOut++
_mainMusicPlaying=true; }
} }
} }
checkTiming(){
this.fadeOutOver = function(){ if(this.songData.timingPoints[this.currentTimingPoint + 1]){
if(this.getElapsedTime().ms >= this.songData.timingPoints[this.currentTimingPoint + 1].start){
} this.currentTimingPoint++
}
this.getHitcircleSpeed = function(){ }
return _hitcircleSpeed; }
} playMainMusic(){
var ms = this.getElapsedTime().ms
this.togglePause = function(){ if(!this.mainMusicPlaying && (!this.fadeOutStarted || ms<this.fadeOutStarted + 1600)){
if(!_paused){ if(this.controller.multiplayer != 2){
assets.sounds["pause"].play(); this.mainAsset.play((ms < 0 ? -ms : 0) / 1000, false, Math.max(0, ms / 1000))
_paused=true; }
_latestDate = new Date(); this.mainMusicPlaying = true
_mainAsset.stop(); }
_mainMusicPlaying=false; }
togglePause(){
} if(!this.paused){
else{ assets.sounds["pause"].play()
assets.sounds["cancel"].play(); this.paused = true
_paused=false; this.latestDate = new Date()
var currentDate = new Date(); this.mainAsset.stop()
_elapsedTimeSincePause = _elapsedTimeSincePause + currentDate.getTime() - _latestDate.getTime(); this.mainMusicPlaying = false
} }else{
} assets.sounds["cancel"].play()
this.paused = false
this.isPaused = function(){ var currentDate = new Date()
return _paused; this.elapsedTimeSincePause = this.elapsedTimeSincePause + currentDate.getTime() - this.latestDate.getTime()
} }
}
this.getElapsedTime = function(){ isPaused(){
return this.elapsedTime; return this.paused
} }
getElapsedTime(){
this.setElapsedTime = function(time){ // Current time in ms from the beginning of the song
this.elapsedTime.ms = time return this.elapsedTime
this.elapsedTime.sec = (this.elapsedTime.ms / 1000 |0) % 60 }
this.elapsedTime.min = (this.elapsedTime.ms / 1000 / 60 |0) % 60 setElapsedTime(time){
this.elapsedTime.hour = (this.elapsedTime.ms / 1000 / 60 / 60 |0) % 60 this.elapsedTime.ms = time
} this.elapsedTime.sec = (this.elapsedTime.ms / 1000 |0) % 60
this.elapsedTime.min = (this.elapsedTime.ms / 1000 / 60 |0) % 60
this.updateTime = function(){ this.elapsedTime.hour = (this.elapsedTime.ms / 1000 / 60 / 60 |0) % 60
_currentDate = new Date(); }
var time = _this.getElapsedTime() updateTime(){
// Refreshed date
if(time.ms<0){ this.currentDate = new Date()
_this.setElapsedTime(_currentDate.getTime() - _startDate.getTime() - _elapsedTimeSincePause) var ms = this.getElapsedTime().ms
} if(ms >= 0 && !this.started){
else if(time.ms>=0 && !_started){ this.startDate = new Date()
_startDate = new Date(); this.elapsedTimeSincePause = 0
_elapsedTimeSincePause = 0; this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime())
_this.setElapsedTime(_currentDate.getTime() - _startDate.getTime()) this.started = true
_started=true; }else if(ms < 0 || ms >= 0 && this.started){
} this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime() - this.elapsedTimeSincePause)
else if(time.ms>=0 && _started){ }
_this.setElapsedTime(_currentDate.getTime() - _startDate.getTime() - _elapsedTimeSincePause) }
} getCircles(){
} return this.songData.circles
}
this.getCircles = function(){ getSongData(){
return _songData.circles; return this.songData
} }
updateCurrentCircle(){
this.getSongData = function(){ this.currentCircle++
return _songData; }
} getCurrentCircle(){
return this.currentCircle
this.updateCurrentCircle = function(){ }
_currentCircle++; updateCombo(score){
} if(score != 0){
this.combo++
this.getCurrentCircle = function(){ }else{
return _currentCircle; this.combo = 0
} }
if(this.combo > this.globalScore.maxCombo){
this.updateCombo = function(score){ this.globalScore.maxCombo = this.combo
}
(score!=0) ? _combo++ : _combo=0; if(this.combo == 50 || this.combo > 0 && this.combo % 100 == 0 && this.combo <= 1400){
this.controller.playSoundMeka("combo-" + this.combo)
if(_combo>_globalScore.maxCombo) _globalScore.maxCombo = _combo; }
this.controller.view.updateCombo(this.combo)
switch(_combo){ }
case 50: getCombo(){
controller.playSoundMeka("combo-50"); return this.combo
break; }
case 100: getGlobalScore(){
controller.playSoundMeka("combo-100"); return this.globalScore
break; }
case 200: updateGlobalScore(score){
controller.playSoundMeka("combo-200"); // Circle score
break; switch(score){
case 300: case 450:
controller.playSoundMeka("combo-300"); this.globalScore.great++
break; break
case 400: case 230:
controller.playSoundMeka("combo-400"); this.globalScore.good++
break; break
case 500: case 0:
controller.playSoundMeka("combo-500"); this.globalScore.fail++
break; break
case 600: }
controller.playSoundMeka("combo-600"); // HP Update
break; if(score != 0){
case 700: this.globalScore.hp += this.HPGain
controller.playSoundMeka("combo-700"); }else if(this.globalScore.hp - this.HPGain > 0){
break; this.globalScore.hp -= this.HPGain
case 800: }else{
controller.playSoundMeka("combo-800"); this.globalScore.hp = 0
break; }
case 900: // Points update
controller.playSoundMeka("combo-900"); score += Math.max(0, Math.floor((Math.min(this.combo, 100) - 1) / 10) * 100)
break;
case 1000: this.globalScore.points+=score
controller.playSoundMeka("combo-1000"); }
break; }
case 1100:
controller.playSoundMeka("combo-1100");
break;
case 1200:
controller.playSoundMeka("combo-1200");
break;
case 1300:
controller.playSoundMeka("combo-1300");
break;
case 1400:
controller.playSoundMeka("combo-1400");
break;
}
controller.view.updateCombo(_combo)
}
this.getCombo = function(){
return _combo;
}
this.getGlobalScore = function(){
return _globalScore;
}
this.updateGlobalScore = function(score){
/* Circle score */
switch(score){
case 450:
_globalScore.great++;
break;
case 230:
_globalScore.good++;
break;
case 0:
_globalScore.fail++;
break;
}
/* HP Update */
if(score!=0){
_globalScore.hp+=_HPGain;
}
else{
if(_globalScore.hp-_HPGain>0)
_globalScore.hp-=_HPGain;
else
_globalScore.hp=0;
}
/* Points update */
if(_combo>=11 && _combo<=20){
score+=100;
}
else if(_combo>=21 && _combo<=30){
score+=200;
}
else if(_combo>=31 && _combo<=40){
score+=300;
}
else if(_combo>=41 && _combo<=50){
score+=400;
}
else if(_combo>=51 && _combo<=60){
score+=500;
}
else if(_combo>=61 && _combo<=70){
score+=500;
}
else if(_combo>=71 && _combo<=80){
score+=600;
}
else if(_combo>=81 && _combo<=90){
score+=700;
}
else if(_combo>=91 && _combo<=100){
score+=800;
}
_globalScore.points+=score;
}
}

View File

@ -91,7 +91,20 @@ function Keyboard(controller){
this.checkKeySound = function(keyCode, sound){ this.checkKeySound = function(keyCode, sound){
_this.checkKey(keyCode, "sound", function(){ _this.checkKey(keyCode, "sound", function(){
assets.sounds["note_"+sound].play() var circles = controller.parsedSongData.circles
var circle = circles[controller.game.getCurrentCircle()]
if(
(keyCode == _kbd["don_l"] || keyCode == _kbd["don_r"])
&& circle
&& !circle.getPlayed()
&& circle.getStatus() != -1
&& circle.getType() == "balloon"
&& circle.requiredHits - circle.timesHit <= 1
){
assets.sounds["balloon"].play()
}else{
assets.sounds["note_"+sound].play()
}
_keyTime[sound] = controller.getElapsedTime().ms _keyTime[sound] = controller.getElapsedTime().ms
}) })
} }

View File

@ -1,73 +1,98 @@
class Mekadon{ class Mekadon{
constructor(controller, game){ constructor(controller, game){
this.controller = controller this.controller = controller
this.game = game this.game = game
this.lr = false this.lr = false
this.keys = {} this.keys = {}
} this.lastHit = -Infinity
play(circle){ }
if(circle.getStatus() == 450){ play(circle){
return this.playNow(circle) var type = circle.getType()
} if(type == "balloon"){
} this.playDrumrollAt(circle, 0, 30)
playAt(circle, ms, score){ }else if(type == "drumroll" || type == "daiDrumroll"){
var currentMs = circle.getMS() - this.controller.getElapsedTime().ms this.playDrumrollAt(circle, 0, 60)
if(ms > currentMs - 10){ }else{
return this.playNow(circle, score) this.playAt(circle, 0, 450)
} }
} }
miss(circle){ playAt(circle, ms, score){
var currentMs = circle.getMS() - this.controller.getElapsedTime().ms var currentMs = circle.getMS() - this.getMS()
if(0 > currentMs - 10){ if(ms > currentMs - 10){
this.controller.displayScore(0, true) return this.playNow(circle, score)
this.game.updateCurrentCircle() }
this.game.updateCombo(0) }
this.game.updateGlobalScore(0) playDrumrollAt(circle, ms, pace){
return true if(pace && this.getMS() >= this.lastHit + pace){
} this.playAt(circle, ms)
} }
playNow(circle, score){ }
var kbd = this.controller.getBindings() miss(circle){
if(circle.getType() == "don"){ var currentMs = circle.getMS() - this.getMS()
this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"]) if(0 >= currentMs - 10){
this.lr = !this.lr this.controller.displayScore(0, true)
}else if(circle.getType() == "daiDon"){ this.game.updateCurrentCircle()
this.setKey(kbd["don_l"]) this.game.updateCombo(0)
this.setKey(kbd["don_r"]) this.game.updateGlobalScore(0)
this.lr = false return true
}else if(circle.getType() == "ka"){ }
this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"]) }
this.lr = !this.lr playNow(circle, score){
}else if(circle.getType() == "daiKa"){ var kbd = this.controller.getBindings()
this.setKey(kbd["ka_l"]) var type = circle.getType()
this.setKey(kbd["ka_r"]) if(type == "don" || type == "balloon" || type == "drumroll" || type == "daiDrumroll"){
this.lr = false this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"])
} this.lr = !this.lr
if(typeof score == "undefined"){ }else if(type == "daiDon"){
score = this.game.checkScore(circle) this.setKey(kbd["don_l"])
}else{ this.setKey(kbd["don_r"])
this.controller.displayScore(score) this.lr = false
this.game.updateCombo(score) }else if(type == "ka"){
this.game.updateGlobalScore(score) this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"])
} this.lr = !this.lr
circle.updateStatus(score) }else if(type == "daiKa"){
circle.played(score) this.setKey(kbd["ka_l"])
this.game.updateCurrentCircle() this.setKey(kbd["ka_r"])
return true this.lr = false
} }
setKey(keyCode){ if(type == "balloon"){
var self = this if(circle.requiredHits == 1){
if(this.keys[keyCode]){ assets.sounds["balloon"].play()
clearTimeout(this.keys[keyCode]) }
self.clearKey(keyCode) this.game.checkBalloon(circle)
} }else if(type == "drumroll" || type == "daiDrumroll"){
this.controller.setKey(keyCode, true) this.game.checkDrumroll(circle)
this.keys[keyCode] = setTimeout(function(){ }else{
self.clearKey(keyCode) if(typeof score == "undefined"){
},100) score = this.game.checkScore(circle)
} }else{
clearKey(keyCode){ this.controller.displayScore(score)
this.controller.setKey(keyCode, false) this.game.updateCombo(score)
delete this.keys[keyCode] this.game.updateGlobalScore(score)
} this.game.updateCurrentCircle()
}
circle.updateStatus(score)
circle.played(score)
}
this.lastHit = this.getMS()
return true
}
getMS(){
return this.controller.getElapsedTime().ms
}
setKey(keyCode){
var self = this
if(this.keys[keyCode]){
clearTimeout(this.keys[keyCode])
self.clearKey(keyCode)
}
this.controller.setKey(keyCode, true)
this.keys[keyCode] = setTimeout(function(){
self.clearKey(keyCode)
}, 100)
}
clearKey(keyCode){
this.controller.setKey(keyCode, false)
delete this.keys[keyCode]
}
} }

View File

@ -5,18 +5,25 @@ class P2Connection{
this.msgCallbacks = {} this.msgCallbacks = {}
this.closeCallbacks = new Set() this.closeCallbacks = new Set()
this.openCallbacks = new Set() this.openCallbacks = new Set()
this.notes = []
this.otherConnected = false this.otherConnected = false
this.onmessage("gamestart", () => { this.onmessage("gamestart", () => {
this.otherConnected = true this.otherConnected = true
this.notes = [] this.notes = []
this.drumrollPace = 45
this.results = false
}) })
this.onmessage("gameend", () => { this.onmessage("gameend", () => {
this.otherConnected = false this.otherConnected = false
}) })
this.onmessage("gameresults", response => {
this.results = response
})
this.onmessage("note", response => { this.onmessage("note", response => {
this.notes.push(response) this.notes.push(response)
}) })
this.onmessage("drumroll", response => {
this.drumrollPace = response.pace
})
} }
open(){ open(){
this.closed = false this.closed = false
@ -92,7 +99,7 @@ class P2Connection{
this.msgCallbacks[data.type].forEach(obj => { this.msgCallbacks[data.type].forEach(obj => {
obj.callback(data.value) obj.callback(data.value)
if(obj.once){ if(obj.once){
delete this.msgCallbacks[obj] this.msgCallbacks[data.type].delete(obj)
} }
}) })
} }
@ -113,7 +120,10 @@ class P2Connection{
} }
play(circle, mekadon){ play(circle, mekadon){
if(this.otherConnected || this.notes.length > 0){ if(this.otherConnected || this.notes.length > 0){
if(this.notes.length == 0){ var type = circle.getType()
if(type == "balloon"|| type == "drumroll" || type == "daiDrumroll"){
mekadon.playDrumrollAt(circle, 0, this.drumrollPace)
}else if(this.notes.length == 0){
mekadon.play(circle) mekadon.play(circle)
}else{ }else{
var note = this.notes[0] var note = this.notes[0]

View File

@ -1,279 +1,311 @@
function ParseSong(fileContent){ class ParseSong{
constructor(fileContent){
var _this = this; this.data = fileContent
var _data = fileContent; this.osu = {
var _generalInfo={audioFilename:"", audioWait:0}; OFFSET: 0,
var _metadata={title:'', artist:''}; MSPERBEAT: 1,
var _difficulty={sliderMultiplier:0, sliderTickRate:0, approachRate:0}; METER: 2,
var _beatInfo={beatInterval:0, bpm:0}; SAMPLESET: 3,
var _editor={distanceSpacing:0, beatDivisor:0, gridSize:0}; SAMPLEINDEX: 4,
var _circleID=0; VOLUME: 5,
var _circles=[]; INHERITED: 6,
var _timingPoints=[]; KIAIMODE: 7,
var _measures=[];
X: 0,
this.getStartEndIndexes = function(type){ Y: 1,
TIME: 2,
var indexes = {start:0, end:0}; TYPE: 3,
HITSOUND: 4,
while(indexes.start<_data.length){ EXTRAS: 5,
if(_data[indexes.start].match(type)) ENDTIME: 5,
break;
else CIRCLE: 1,
indexes.start++; SLIDER: 2,
} NEWCOMBO: 4,
indexes.start++; SPINNER: 8,
indexes.end = indexes.start; NORMAL: 1,
while(indexes.end<_data.length){ WHISTLE: 2,
if(_data[indexes.end].match(/^\s*$/)) FINISH: 4,
break; CLAP: 8,
else
indexes.end++; CURVEPOINTS: 0,
} REPEAT: 1,
indexes.end--; PIXELLENGTH: 2,
EDGEHITSOUNDS: 3,
return indexes; EDGEADDITIONS: 4
} }
this.beatInfo = {
this.parseDifficulty = function(){ beatInterval: 0,
bpm: 0
var indexes = _this.getStartEndIndexes("Difficulty"); }
this.generalInfo = this.parseGeneralInfo()
for(var i=indexes.start; i<= indexes.end; i++){ this.metadata = this.parseMetadata()
this.editor = this.parseEditor()
var splitted = _data[i].split(":"); this.difficulty = this.parseDifficulty()
var item = splitted[0]; this.timingPoints = this.parseTiming()
var key = splitted[1]; this.circles = this.parseCircles()
this.measures = this.parseMeasures()
switch(item){
case 'SliderMultiplier':
_difficulty.sliderMultiplier = key;
_difficulty.originalMultiplier = key;
break;
case 'SliderTickRate':
_difficulty.sliderTickRate = key;
break;
case 'ApproachRate':
_difficulty.approachRate = key;
break;
}
}
}
this.parseTiming = function(){
var indexes = _this.getStartEndIndexes("TimingPoints");
var lastBeatInterval = parseInt(_data[indexes.start].split(",")[1]);
for(var i=indexes.start; i<= indexes.end; i++){
var values = _data[i].split(",");
var start=parseInt(values[0])
var msOrPercent=parseFloat(values[1])
if(i==indexes.start){
start=0
_beatInfo.beatInterval=msOrPercent;
_beatInfo.bpm=parseInt((1000/_beatInfo.beatInterval)*60);
}
if(msOrPercent<0){
var sliderMultiplier=_difficulty.originalMultiplier*1/Math.abs(msOrPercent/100);
}else{
var sliderMultiplier=500/msOrPercent;
_difficulty.originalMultiplier=sliderMultiplier
}
_timingPoints.push({
start:start,
sliderMultiplier:sliderMultiplier,
measure:parseInt(values[2]),
});
}
}
this.parseMeasures = function(){
var measureNumber=0;
for(var i=0; i<_timingPoints.length; i++){
var limit = (_timingPoints[i+1]) ? _timingPoints[i+1].start : _circles[_circles.length-1].getMS();
for(var j=_timingPoints[i].start; j<=limit; j+=_beatInfo.beatInterval){
_measures.push({
ms:j,
nb:measureNumber,
speed:_timingPoints[i].sliderMultiplier
});
measureNumber++;
if(measureNumber==_timingPoints[i].measure+1){
measureNumber=0;
}
}
}
}
this.parseGeneralInfo = function(){
var indexes = _this.getStartEndIndexes("General");
for(var i=indexes.start; i<= indexes.end; i++){
var splitted = _data[i].split(":");
var item = splitted[0];
var key = splitted[1];
switch(item){
case 'SliderMultiple':
_generalInfo.audioFilename = key;
break;
case 'AudioWait':
_generalInfo.audioWait = parseInt(key);
break;
}
}
}
this.parseMetadata = function(){
var indexes = _this.getStartEndIndexes("Metadata");
for(var i=indexes.start; i<= indexes.end; i++){
var splitted = _data[i].split(":");
var item = splitted[0];
var key = splitted[1];
switch(item){
case 'TitleUnicode':
_metadata.title = key;
break;
case 'ArtistUnicode':
_metadata.artist = key;
break;
}
}
}
this.parseEditor = function(){
var indexes = _this.getStartEndIndexes("Editor");
for(var i=indexes.start; i<= indexes.end; i++){
var splitted = _data[i].split(":");
var item = splitted[0];
var key = splitted[1];
switch(item){
case 'DistanceSpacing':
_editor.distanceSpacing = parseFloat(key);
break;
case 'BeatDivisor':
_editor.beatDivisor = parseInt(key);
break;
case 'GridSize':
_editor.gridSize = parseInt(key);
break;
}
}
}
this.parseCircles = function(){
var indexes = _this.getStartEndIndexes("HitObjects");
for(var i=indexes.start; i<= indexes.end; i++){
_circleID++;
var values = _data[i].split(",");
var type;
var txt;
var emptyValue=false;
var start=parseInt(values[2])
var speed=_difficulty.originalMultiplier
for(var j=0; j<_timingPoints.length; j++){
if(_timingPoints[j].start<=start){
speed=_timingPoints[j].sliderMultiplier
}else{
break
}
}
switch(parseInt(values[4])){
case 0:
type="don";
txt="ドン";
break;
case 2:
type="ka";
txt="カッ";
break;
case 4:
type="daiDon";
txt="ドン(大)";
break;
case 6:
type="daiKa";
txt="カッ(大)";
break;
case 8:
type="ka";
txt="カッ";
break;
case 10:
type="ka";
txt="カッ";
break;
case 12:
type="daiKa";
txt="カッ(大)";
break;
case 14:
type="daiKa";
txt="カッ(大)";
break;
default:
console.log('[WARNING] Unknown note type found on line ' + i+1 + ': ' + _data[i]);
emptyValue=true;
break;
}
if(!emptyValue)
_circles.push(new Circle(_circleID,start,type,txt,speed));
}
}
_this.parseGeneralInfo();
_this.parseMetadata();
_this.parseEditor();
_this.parseDifficulty();
_this.parseTiming();
_this.parseCircles();
_this.parseMeasures();
this.getData = function(){
return {
generalInfo: _generalInfo,
metaData: _metadata,
editor: _editor,
beatInfo: _beatInfo,
difficulty: _difficulty,
timingPoints: _timingPoints,
circles: _circles,
measures: _measures
};
} }
} getStartEndIndexes(type){
var indexes = {
start: 0,
end: 0
}
while(indexes.start < this.data.length){
if(this.data[indexes.start].match(type)){
break
}
indexes.start++
}
indexes.start++
indexes.end = indexes.start
while(indexes.end < this.data.length){
if(this.data[indexes.end].match(/^\s*$/)){
break
}
indexes.end++
}
indexes.end--
return indexes
}
parseDifficulty(){
var difficulty = {
sliderMultiplier: 0,
sliderTickRate: 0,
approachRate: 0
}
var indexes = this.getStartEndIndexes("Difficulty")
for(var i = indexes.start; i <= indexes.end; i++){
var [item, key] = this.data[i].split(":")
switch(item){
case "SliderMultiplier":
difficulty.sliderMultiplier = key
difficulty.originalMultiplier = key
break
case "SliderTickRate":
difficulty.sliderTickRate = key
break
case "ApproachRate":
difficulty.approachRate = key
break
case "OverallDifficulty":
difficulty.overallDifficulty = key
break
}
}
return difficulty
}
parseTiming(){
var timingPoints = []
var indexes = this.getStartEndIndexes("TimingPoints")
var lastBeatInterval = parseInt(this.data[indexes.start].split(",")[1])
for(var i = indexes.start; i<= indexes.end; i++){
var values = this.data[i].split(",")
var start = parseInt(values[this.osu.OFFSET])
var msOrPercent = parseFloat(values[this.osu.MSPERBEAT])
if(i == indexes.start){
start = 0
this.beatInfo.beatInterval = msOrPercent
this.beatInfo.bpm = Math.floor(1000 / this.beatInfo.beatInterval * 60)
}
if(msOrPercent < 0){
var sliderMultiplier = this.difficulty.lastMultiplier / Math.abs(msOrPercent / 100)
}else{
var sliderMultiplier = 500 / msOrPercent
if(i == 0){
this.difficulty.originalMultiplier = sliderMultiplier
}
this.difficulty.lastMultiplier = sliderMultiplier
}
timingPoints.push({
start: start,
sliderMultiplier: sliderMultiplier,
measure: parseInt(values[this.osu.METER])
})
}
return timingPoints
}
parseMeasures(){
var measures = []
var measureNumber = 0
for(var i = 0; i<this.timingPoints.length; i++){
if(this.timingPoints[i + 1]){
var limit = this.timingPoints[i + 1].start
}else{
var limit = this.circles[this.circles.length - 1].getMS()
}
for(var j = this.timingPoints[i].start; j <= limit; j += this.beatInfo.beatInterval){
measures.push({
ms: j,
nb: measureNumber,
speed: this.timingPoints[i].sliderMultiplier
})
measureNumber++
if(measureNumber == this.timingPoints[i].measure + 1){
measureNumber = 0
}
}
}
return measures
}
parseGeneralInfo(){
var generalInfo = {
audioFilename: "",
audioWait: 0
}
var indexes = this.getStartEndIndexes("General")
for(var i = indexes.start; i<= indexes.end; i++){
var [item, key] = this.data[i].split(":")
switch(item){
case "SliderMultiple":
generalInfo.audioFilename = key
break
case "AudioWait":
generalInfo.audioWait = parseInt(key)
break
}
}
return generalInfo
}
parseMetadata(){
var metadata = {
title: "",
artist: ""
}
var indexes = this.getStartEndIndexes("Metadata")
for(var i = indexes.start; i <= indexes.end; i++){
var [item, key] = this.data[i].split(":")
switch(item){
case "TitleUnicode":
metadata.title = key
break
case "ArtistUnicode":
metadata.artist = key
break
}
}
return metadata
}
parseEditor(){
var editor = {
distanceSpacing: 0,
beatDivisor: 0,
gridSize: 0
}
var indexes = this.getStartEndIndexes("Editor")
for(var i = indexes.start; i <= indexes.end; i++){
var [item, key] = this.data[i].split(":")
switch(item){
case "DistanceSpacing":
editor.distanceSpacing = parseFloat(key)
break
case "BeatDivisor":
editor.beatDivisor = parseInt(key)
break
case "GridSize":
editor.gridSize = parseInt(key)
break
}
}
return editor
}
difficultyRange(difficulty, min, mid, max){
if(difficulty > 5){
return mid + (max - mid) * (difficulty - 5) / 5
}
if(difficulty < 5){
return mid - (mid - min) * (5 - difficulty) / 5
}
return mid
}
parseCircles(){
var circles = []
var circleID = 0
var indexes = this.getStartEndIndexes("HitObjects")
for(var i = indexes.start; i <= indexes.end; i++){
circleID++
var values = this.data[i].split(",")
var emptyValue = false
var start = parseInt(values[this.osu.TIME])
var speed = this.difficulty.originalMultiplier
var osuType = parseInt(values[this.osu.TYPE])
var hitSound = parseInt(values[this.osu.HITSOUND])
for(var j = 0; j < this.timingPoints.length; j++){
if(this.timingPoints[j].start > start){
break
}
speed = this.timingPoints[j].sliderMultiplier
}
if(osuType & this.osu.SPINNER){
var endTime = parseInt(values[this.osu.ENDTIME])
var hitMultiplier = this.difficultyRange(this.difficulty.overallDifficulty, 3, 5, 7.5) * 1.65
var requiredHits = Math.floor(Math.max(1, (endTime - start) / 1000 * hitMultiplier))
circles.push(new Circle(circleID, start, "balloon", "ふうせん", speed, endTime, requiredHits))
}else if(osuType & this.osu.SLIDER){
var extras = values.slice(this.osu.EXTRAS)
var pixelLength = parseFloat(extras[this.osu.PIXELLENGTH])
var endTime = start + pixelLength / (this.difficulty.originalMultiplier * 100) * this.beatInfo.beatInterval
if(hitSound & this.osu.FINISH){
type = "daiDrumroll"
txt = "連打(大)ーっ!!"
}else{
type = "drumroll"
txt = "連打ーっ!!"
}
circles.push(new Circle(circleID, start, type, txt, speed, endTime))
}else if(osuType & this.osu.CIRCLE){
var type
var txt
if(hitSound & this.osu.FINISH){
if(hitSound & this.osu.WHISTLE || hitSound & this.osu.CLAP){
type = "daiKa"
txt = "カッ(大)"
}else if(hitSound & this.osu.NORMAL || hitSound == this.osu.FINISH){
type = "daiDon"
txt = "ドン(大)"
}else{
emptyValue = true
}
}else if(hitSound & this.osu.WHISTLE || hitSound & this.osu.CLAP){
type = "ka"
txt = "カッ"
}else if(hitSound & this.osu.NORMAL || hitSound == 0){
type = "don"
txt = "ドン"
}else{
emptyValue = true
}
if(!emptyValue){
circles.push(new Circle(circleID, start, type, txt, speed))
}
}else{
emptyValue = true
}
if(emptyValue){
console.warn("Unknown note type found on line " + (i + 1) + ": " + this.data[i])
}
}
return circles
}
getData(){
return {
generalInfo: this.generalInfo,
metaData: this.metadata,
editor: this.editor,
beatInfo: this.beatInfo,
difficulty: this.difficulty,
timingPoints: this.timingPoints,
circles: this.circles,
measures: this.measures
}
}
}

View File

@ -1,104 +1,104 @@
class Scoresheet{
function Scoresheet(controller, score){ constructor(controller, score, multiplayer){
this.controller = controller
var _this = this; this.score = score
var _score = score; this.multiplayer = multiplayer
var _mark; $("#screen").load("/src/views/scoresheet.html", () =>{
this.run()
this.setResults = function(){ })
if (_score.fail == 0) {
_mark = 'gold';
} else if (_score.hp >= 50) {
_mark = 'silver';
};
var imgW = (_score.hp*$("#score-hp-bar-colour").width())/100;
$("#score-hp-bar-colour img").css("clip", "rect(0, "+imgW+"px, "+$("#score-hp-bar-colour").height()+"px, 0)");
if (_mark == 'gold') {
$("#score-mark").attr("src", '/assets/img/ranking-X.png');
} else if (_mark == 'silver') {
$("#score-mark").attr("src", '/assets/img/ranking-S.png');
} else {
$("#score-mark").remove();
};
$("#score-points").html(_score.points+"点");
$("#nb-great").html(_score.great);
$("#nb-good").html(_score.good);
$("#nb-fail").html(_score.fail);
$("#max-combo").html(_score.maxCombo);
$('.result-song').attr('alt', _score.song).html(_score.song);
} }
setResults(score, scoreCont){
this.positionning = function(){ this.positionning(scoreCont)
var scoreMark = this.elem("score-mark", scoreCont)
var scoreHpBarColour = this.elem("score-hp-bar-colour", scoreCont)
$("#score-cont").css("top", $("#result-bar").height()/2 - ($("#score-cont").height()/2)); if(score.fail == 0){
var mark = "gold"
var markSize = 0.1*$("#score-cont").width(); }else if (score.hp >= 50){
var markX = $("#score-cont").offset().left - markSize - (0.5*markSize); var mark = "silver"
var markY = $("#score-cont").offset().top; }
scoreHpBarColour.dataset.hp = score.hp
$("#score-mark").width(markSize); var imgW = score.hp * scoreHpBarColour.offsetWidth / 100
$("#score-mark").height(markSize); var imgH = scoreHpBarColour.offsetHeight
$("#score-mark").css("left", markX); scoreHpBarColour.getElementsByTagName("img")[0].style.clip = "rect(0, " + imgW + "px, " + imgH + "px, 0)"
$("#score-mark").css("top", markY);
var scoreBarW = 0.9*$("#score-cont").width();
$("#score-hp-bar-bg").width(scoreBarW);
$("#score-hp-bar-bg").height((51/703)*scoreBarW);
var bgW = $("#score-hp-bar-bg").width();
var bgH = $("#score-hp-bar-bg").height();
var bgX = $("#score-hp-bar-bg").position().left;
var bgY = $("#score-hp-bar-bg").position().top;
$("#score-hp-bar-colour").css("left", bgX+(0.008*bgW));
$("#score-hp-bar-colour").css("top", bgY+(0.15*bgH));
$("#score-hp-bar-colour").width(bgW-(0.08*bgW));
$("#score-hp-bar-colour").height(bgH-(0.25*bgH));
$("#score-details").css("top", bgY+bgH+(bgH));
var barY = $("#result-bar").position().top;
var barH = $("#result-bar").height();
var bottomY = barY+barH+15;
var bottomH = $(window).height()-bottomY;
$("#bottom-part").css("top", bottomY);
$("#bottom-part").height(bottomH);
if(mark == "gold"){
scoreMark.src = "/assets/img/ranking-X.png"
}else if(mark == "silver"){
scoreMark.src = "/assets/img/ranking-S.png"
}else{
scoreMark.parentNode.removeChild(scoreMark)
}
this.altText(this.elem("score-points", scoreCont), score.points + "点")
this.altText(this.elem("nb-great", scoreCont), score.great)
this.altText(this.elem("nb-good", scoreCont), score.good)
this.altText(this.elem("nb-fail", scoreCont), score.fail)
this.altText(this.elem("max-combo", scoreCont), score.maxCombo)
this.altText(this.elem("nb-drumroll", scoreCont), score.drumroll)
addEventListener("resize", () => {
this.positionning(scoreCont)
})
} }
elem(className, parent){
this.run = function(){ return parent.getElementsByClassName(className)[0]
_this.positionning();
_this.setResults();
$("#song-select").click(function(){
assets.sounds["don"].play();
assets.sounds["bgm_result"].stop();
controller.songSelection();
});
$("#replay").click(function(){
assets.sounds["don"].play();
assets.sounds["bgm_result"].stop();
controller.restartSong();
});
$(window).resize(_this.positionning);
} }
text(string){
assets.sounds["results"].play() return document.createTextNode(string)
assets.sounds["bgm_result"].playLoop(0.1, false, 0, 0.847, 17.689) }
altText(element, string){
$("#screen").load("/src/views/scoresheet.html", _this.run); element.appendChild(this.text(string))
element.setAttribute("alt", string)
} }
positionning(scoreCont){
var scoreHpBarBg = this.elem("score-hp-bar-bg", scoreCont)
var scoreHpBarColour = this.elem("score-hp-bar-colour", scoreCont)
var scoreBarW = scoreCont.offsetWidth * 0.9
var bgW = scoreBarW
var bgH = 51 / 703 * scoreBarW
scoreHpBarBg.style.width = bgW + "px"
scoreHpBarBg.style.height = bgH + "px"
var bgX = scoreHpBarBg.offsetLeft
var bgY = scoreHpBarBg.offsetTop
scoreHpBarColour.style.left = (bgW * 0.008) + "px"
scoreHpBarColour.style.top = (bgH * 0.15) + "px"
scoreHpBarColour.style.width = (bgW - bgW * 0.08) + "px"
scoreHpBarColour.style.height = (bgH - bgH * 0.25) + "px"
var imgW = scoreHpBarColour.dataset.hp * scoreHpBarColour.offsetWidth / 100
var imgH = scoreHpBarColour.offsetHeight
scoreHpBarColour.getElementsByTagName("img")[0].style.clip = "rect(0, " + imgW + "px, " + imgH + "px, 0)"
}
run(){
this.scoresheet = document.getElementsByClassName("scoresheet")[0]
var scoreCont = this.elem("score-cont", this.scoresheet)
var scoreContHtml = scoreCont.innerHTML
assets.sounds["results"].play()
assets.sounds["bgm_result"].playLoop(0.1, false, 0, 0.847, 17.689)
this.setResults(this.score, scoreCont)
this.altText(this.elem("result-song", this.scoresheet), this.score.song)
this.elem("song-select", this.scoresheet).addEventListener("click", () => {
assets.sounds["don"].play()
assets.sounds["bgm_result"].stop()
this.controller.songSelection()
})
this.elem("replay", this.scoresheet).addEventListener("click", () => {
assets.sounds["don"].play()
assets.sounds["bgm_result"].stop()
this.controller.restartSong()
})
if(this.multiplayer && p2.results){
var scoreCont2 = document.createElement("div")
scoreCont2.classList.add("score-cont")
scoreCont2.innerHTML = scoreContHtml
scoreCont.parentNode.appendChild(scoreCont2)
this.setResults(p2.results, scoreCont2)
}
}
}

View File

@ -40,6 +40,8 @@ class View{
this.songTitle = title this.songTitle = title
this.songDifficulty = this.diff.split(".").slice(0, -1).join(".") this.songDifficulty = this.diff.split(".").slice(0, -1).join(".")
this.drumroll = []
this.beatInterval = this.controller.getSongData().beatInfo.beatInterval this.beatInterval = this.controller.getSongData().beatInfo.beatInterval
this.assets = [] this.assets = []
this.don = this.createAsset(frame => { this.don = this.createAsset(frame => {
@ -69,22 +71,15 @@ class View{
this.don.setAnimation("normal") this.don.setAnimation("normal")
this.don.setUpdateSpeed(this.beatInterval / 16) this.don.setUpdateSpeed(this.beatInterval / 16)
} }
run(){ run(){
this.ctx.font = "normal 14pt TnT" this.ctx.font = "normal 14pt TnT"
this.setBackground() this.setBackground()
$(".game-song").attr("alt", this.songTitle).html(this.songTitle) $(".game-song").attr("alt", this.songTitle).html(this.songTitle)
this.refresh() this.refresh()
} }
setBackground(){ setBackground(){
$("#game").css("background-image", "url('" + this.bg + "')") $("#game").css("background-image", "url('" + this.bg + "')")
} }
getDistanceForCircle(){
return this.distanceForCircle
}
positionning(){ positionning(){
this.canvas.rescale() this.canvas.rescale()
var height = $(window).height() var height = $(window).height()
@ -133,7 +128,6 @@ class View{
this.diffX = this.taikoX * 0.10 this.diffX = this.taikoX * 0.10
this.diffY = this.taikoY * 1.05 + this.taikoH * 0.19 this.diffY = this.taikoY * 1.05 + this.taikoH * 0.19
} }
refresh(){ refresh(){
this.positionning() this.positionning()
this.distanceForCircle = this.winW - this.slotX this.distanceForCircle = this.winW - this.slotX
@ -147,7 +141,8 @@ class View{
this.drawMeasures() this.drawMeasures()
this.drawHPBar() this.drawHPBar()
this.drawScore() this.drawScore()
this.drawCircles() this.drawCircles(this.controller.getCircles())
this.drawCircles(this.drumroll)
this.drawTaikoSquare() this.drawTaikoSquare()
this.drawDifficulty() this.drawDifficulty()
this.drawPressedKeys() this.drawPressedKeys()
@ -156,7 +151,6 @@ class View{
this.updateDonFaces() this.updateDonFaces()
//this.drawTime() //this.drawTime()
} }
updateDonFaces(){ updateDonFaces(){
if(this.controller.getElapsedTime().ms >= this.nextBeat){ if(this.controller.getElapsedTime().ms >= this.nextBeat){
this.nextBeat += this.beatInterval this.nextBeat += this.beatInterval
@ -170,7 +164,6 @@ class View{
} }
} }
} }
drawHPBar(){ drawHPBar(){
var z = this.canvas.scale var z = this.canvas.scale
@ -221,7 +214,6 @@ class View{
hpBar.canvasW, this.HPBarColH hpBar.canvasW, this.HPBarColH
) )
} }
getHP(){ getHP(){
var circles = this.controller.getCircles() var circles = this.controller.getCircles()
var currentCircle = this.controller.getCurrentCircle() var currentCircle = this.controller.getCurrentCircle()
@ -232,7 +224,6 @@ class View{
canvasW: width / 650 * this.HPBarColMaxW canvasW: width / 650 * this.HPBarColMaxW
} }
} }
drawMeasures(){ drawMeasures(){
var measures = this.controller.getSongData().measures var measures = this.controller.getSongData().measures
var currentTime = this.controller.getElapsedTime().ms var currentTime = this.controller.getElapsedTime().ms
@ -248,7 +239,6 @@ class View{
} }
}) })
} }
drawMeasure(measure){ drawMeasure(measure){
var z = this.canvas.scale var z = this.canvas.scale
var currentTime = this.controller.getElapsedTime().ms var currentTime = this.controller.getElapsedTime().ms
@ -261,7 +251,6 @@ class View{
this.ctx.closePath() this.ctx.closePath()
this.ctx.stroke() this.ctx.stroke()
} }
drawCombo(){ drawCombo(){
var comboCount = this.controller.getCombo() var comboCount = this.controller.getCombo()
if(comboCount >= 10){ if(comboCount >= 10){
@ -314,14 +303,12 @@ class View{
this.scoreDispCount++ this.scoreDispCount++
} }
} }
strokeFillText(text, x, y){ strokeFillText(text, x, y){
this.ctx.strokeText(text, x, y) this.ctx.strokeText(text, x, y)
this.ctx.fillText(text, x, y) this.ctx.fillText(text, x, y)
} }
drawGlobalScore(){ drawGlobalScore(){
/* Draw score square */ // Draw score square
this.ctx.fillStyle="#000" this.ctx.fillStyle="#000"
this.ctx.beginPath() this.ctx.beginPath()
this.ctx.fillRect(0, this.barY, this.scoreSquareW, this.scoreSquareH - 10) this.ctx.fillRect(0, this.barY, this.scoreSquareW, this.scoreSquareH - 10)
@ -350,7 +337,6 @@ class View{
) )
} }
} }
drawPressedKeys(){ drawPressedKeys(){
var keys = this.controller.getKeys() var keys = this.controller.getKeys()
var kbd = this.controller.getBindings() var kbd = this.controller.getBindings()
@ -399,14 +385,12 @@ class View{
) )
} }
} }
displayScore(score, notPlayed){ displayScore(score, notPlayed){
this.currentScore = score this.currentScore = score
this.special = notPlayed ? "-b" : "" this.special = notPlayed ? "-b" : ""
this.scoreDispCount = 0 this.scoreDispCount = 0
this.scoreOpacity = 1 this.scoreOpacity = 1
} }
drawScore(){ drawScore(){
if(this.scoreDispCount >= 0 && this.scoreDispCount <= 20){ if(this.scoreDispCount >= 0 && this.scoreDispCount <= 20){
this.ctx.globalAlpha = this.scoreOpacity this.ctx.globalAlpha = this.scoreOpacity
@ -427,63 +411,59 @@ class View{
} }
this.ctx.globalAlpha = 1 this.ctx.globalAlpha = 1
} }
posToMs(pos, speed){
drawCircles(){ return 70 / this.circleSize * pos / speed
var circles = this.controller.getCircles() }
msToPos(ms, speed){
return speed / (70 / this.circleSize) * ms
}
drawCircles(circles){
for(var i = circles.length; i--;){ for(var i = circles.length; i--;){
var circle = circles[i] var circle = circles[i]
var ms = this.controller.getElapsedTime().ms
var speed = circle.getSpeed()
var currentTime = this.controller.getElapsedTime().ms var timeForDistance = this.posToMs(this.distanceForCircle + this.bigCircleSize / 2, speed)
var timeForDistance = 70 / this.circleSize * this.distanceForCircle / circle.getSpeed() + this.bigCircleSize / 2
var startingTime = circle.getMS() - timeForDistance var startingTime = circle.getMS() - timeForDistance
// At circle.getMS(), the cirlce fits the slot var finishTime = circle.getEndTime() + this.posToMs(this.slotX - this.taikoSquareW + this.bigCircleSize / 2, speed)
var finishTime = circle.getMS() + 100
if(!circle.getPlayed() && currentTime >= startingTime && currentTime <= finishTime){ if(!circle.getPlayed() || circle.getScore() == 0){
this.drawCircle(circle) if(ms >= startingTime && ms <= finishTime){
} this.drawCircle(circle)
else{
// Animate circle to the HP bar
// Animation in ms
var animationDuration = 470
if(!circle.isAnimated()){
if(circle.getScore() != 0){
// Start animation to HP bar
circle.animate()
}
} }
if(circle.isAnimated()){ }else if(!circle.isAnimated()){
if(currentTime <= finishTime + animationDuration){ // Start animation to HP bar
var curveDistance = this.HPBarX + this.HPBarW - this.slotX circle.animate()
var bezierPoint = this.calcBezierPoint(circle.getAnimT(), [{ }
x: this.slotX, if(circle.isAnimated()){
y: this.circleY var animationDuration = 470
}, { if(ms <= finishTime + animationDuration){
x: this.slotX + curveDistance * 0.15, var curveDistance = this.HPBarX + this.HPBarW - this.slotX
y: this.barH * 0.5 var bezierPoint = this.calcBezierPoint(circle.getAnimT(), [{
}, { x: this.slotX + this.circleSize * 0.4,
x: this.slotX + curveDistance * 0.35, y: this.circleY - this.circleSize * 0.8
y: 0 }, {
}, { x: this.slotX + curveDistance * 0.15,
x: this.slotX + curveDistance, y: this.barH * 0.5
y: this.HPbarColY }, {
}]) x: this.slotX + curveDistance * 0.35,
this.drawCircle(circle, {x: bezierPoint.x, y: bezierPoint.y}) y: 0
}, {
// Update animation frame x: this.slotX + curveDistance,
circle.incAnimT() y: this.HPbarColY
circle.incFrame() }])
} this.drawCircle(circle, {x: bezierPoint.x, y: bezierPoint.y})
else{
circle.endAnimation() // Update animation frame
} circle.incAnimT()
circle.incFrame()
}
else{
circle.endAnimation()
} }
} }
} }
} }
calcBezierPoint(t, data){ calcBezierPoint(t, data){
var at = 1 - t var at = 1 - t
@ -498,72 +478,117 @@ class View{
return data[0] return data[0]
} }
drawCircle(circle, circlePos){ drawCircle(circle, circlePos){
var z = this.canvas.scale var z = this.canvas.scale
var fill, size, faceID var fill, size, faceID
var type = circle.getType()
var ms = this.controller.getElapsedTime().ms
var circleMs = circle.getMS()
var endTime = circle.getEndTime()
var animated = circle.isAnimated()
var speed = circle.getSpeed()
if(!circlePos){ if(!circlePos){
var currentTime = this.controller.getElapsedTime().ms
circlePos = { circlePos = {
x: this.slotX + circle.getSpeed() / (70 / this.circleSize) * (circle.getMS() - currentTime), x: this.slotX + this.msToPos(circleMs - ms, speed),
y: this.circleY y: this.circleY
} }
} }
if(circle.getPlayed()){ if(animated){
var currentDonFace = 1 var currentDonFace = 0
var currentBigDonFace = 1 var currentBigDonFace = 1
}else{ }else{
var currentDonFace = this.currentDonFace var currentDonFace = this.currentDonFace
var currentBigDonFace = this.currentBigDonFace var currentBigDonFace = this.currentBigDonFace
} }
switch(circle.getType()){ switch(type){
case "don": case "don":
fill = "#f54c25" fill = "#f34728"
size = this.circleSize size = this.circleSize
faceID = "don-" + currentDonFace faceID = "don-" + currentDonFace
break break
case "ka": case "ka":
fill = "#75cee9" fill = "#65bdbb"
size = this.circleSize size = this.circleSize
faceID = "don-" + currentDonFace faceID = "don-" + currentDonFace
break break
case "daiDon": case "daiDon":
fill = "#f54c25" fill = "#f34728"
size = this.bigCircleSize size = this.bigCircleSize
faceID = "big-don-" + currentBigDonFace faceID = "big-don-" + currentBigDonFace
break break
case "daiKa": case "daiKa":
fill = "#75cee9" fill = "#65bdbb"
size = this.bigCircleSize size = this.bigCircleSize
faceID = "big-don-" + currentBigDonFace faceID = "big-don-" + currentBigDonFace
break break
case "balloon":
if(animated){
fill = "#f34728"
size = this.bigCircleSize * 0.8
faceID = "big-don-" + currentBigDonFace
break
}
fill = "#f87700"
size = this.circleSize
faceID = "don-" + currentDonFace
var h = size * 1.8
if(circleMs < ms && ms <= endTime){
circlePos.x = this.slotX
}else if(ms > endTime){
circlePos.x = this.slotX + this.msToPos(endTime - ms, speed)
}
this.ctx.drawImage(assets.image["balloon"],
circlePos.x + size - 3,
circlePos.y - h / 2,
h / 61 * 115,
h
)
break
case "drumroll":
case "daiDrumroll":
fill = "#f3b500"
if(type == "drumroll"){
size = this.circleSize
faceID = "don-" + currentDonFace
}else{
size = this.bigCircleSize
faceID = "big-don-" + currentBigDonFace
}
var endX = this.msToPos(endTime - circleMs, speed)
this.ctx.fillStyle = fill
this.ctx.strokeStyle = "#1f1a17"
this.ctx.lineWidth = this.lyricsSize / 10
this.ctx.beginPath()
this.ctx.moveTo(circlePos.x, circlePos.y - size)
this.ctx.lineTo(circlePos.x + endX, circlePos.y - size)
this.ctx.arc(circlePos.x + endX, circlePos.y, size, -Math.PI / 2, Math.PI / 2)
this.ctx.lineTo(circlePos.x, circlePos.y + size)
this.ctx.fill()
this.ctx.stroke()
break
} }
// Main circle // Main circle
this.ctx.fillStyle = fill this.ctx.fillStyle = fill
this.ctx.beginPath() this.ctx.beginPath()
this.ctx.arc(circlePos.x, circlePos.y, size, 0, Math.PI * 2) this.ctx.arc(circlePos.x, circlePos.y, size, 0, Math.PI * 2)
this.ctx.closePath() this.ctx.closePath()
this.ctx.fill() this.ctx.fill()
// Face on circle // Face on circle
var face = assets.image[faceID] this.ctx.drawImage(assets.image[faceID],
this.ctx.drawImage(face,
circlePos.x - size - 2, circlePos.x - size - 2,
circlePos.y - size - 4, circlePos.y - size - 4,
size * 2 + 5, size * 2 + 5,
size * 2 + 6 size * 2 + 6
) )
if(!circle.isAnimated()){ if(!circle.isAnimated()){
// Text // Text
this.ctx.font = "normal bold " + this.lyricsSize + "px Kozuka" this.ctx.font = "normal bold " + this.lyricsSize + "px Kozuka"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
this.ctx.strokeStyle = "#000" this.ctx.strokeStyle = "#000"
this.ctx.lineWidth = this.lyricsSize / 5 this.ctx.lineWidth = this.lyricsSize / 5
this.ctx.fillStyle = "#fff" this.ctx.fillStyle = "#fff"
this.strokeFillText(circle.getText(), this.strokeFillText(circle.getText(),
circlePos.x, circlePos.x,
@ -571,7 +596,6 @@ class View{
) )
} }
} }
togglePauseMenu(){ togglePauseMenu(){
if($("#pause-menu").is(":visible")){ if($("#pause-menu").is(":visible")){
$("#pause-menu").hide() $("#pause-menu").hide()
@ -579,7 +603,6 @@ class View{
$("#pause-menu").show() $("#pause-menu").show()
} }
} }
drawDifficulty(){ drawDifficulty(){
this.ctx.drawImage(assets.image["muzu_" + this.songDifficulty], this.ctx.drawImage(assets.image["muzu_" + this.songDifficulty],
this.diffX, this.diffY, this.diffX, this.diffY,
@ -591,7 +614,6 @@ class View{
this.taikoW, this.taikoH this.taikoW, this.taikoH
) )
} }
drawTime(){ drawTime(){
var z = this.canvas.scale var z = this.canvas.scale
var time = this.controller.getElapsedTime() var time = this.controller.getElapsedTime()
@ -614,7 +636,6 @@ class View{
) )
this.ctx.fillText(time.ms, this.winW - 10 * z, this.winH - 10 * z) this.ctx.fillText(time.ms, this.winW - 10 * z, this.winH - 10 * z)
} }
drawBar(){ drawBar(){
this.ctx.strokeStyle = "#000" this.ctx.strokeStyle = "#000"
this.ctx.fillStyle = "#232323" this.ctx.fillStyle = "#232323"
@ -641,7 +662,6 @@ class View{
this.ctx.fill() this.ctx.fill()
this.ctx.globalAlpha = 1 this.ctx.globalAlpha = 1
} }
this.ctx.stroke() this.ctx.stroke()
// Lyrics bar // Lyrics bar
this.ctx.fillStyle = "#888888" this.ctx.fillStyle = "#888888"
@ -651,7 +671,6 @@ class View{
this.ctx.fill() this.ctx.fill()
this.ctx.stroke() this.ctx.stroke()
} }
drawSlot(){ drawSlot(){
// Main circle // Main circle
this.ctx.fillStyle = "#6f6f6e" this.ctx.fillStyle = "#6f6f6e"
@ -659,7 +678,6 @@ class View{
this.ctx.arc(this.slotX, this.circleY, this.circleSize - 0.2 * this.circleSize, 0, 2 * Math.PI) this.ctx.arc(this.slotX, this.circleY, this.circleSize - 0.2 * this.circleSize, 0, 2 * Math.PI)
this.ctx.closePath() this.ctx.closePath()
this.ctx.fill() this.ctx.fill()
// Big stroke circle // Big stroke circle
this.ctx.strokeStyle = "#9e9f9f" this.ctx.strokeStyle = "#9e9f9f"
this.ctx.lineWidth = 3 this.ctx.lineWidth = 3
@ -667,7 +685,6 @@ class View{
this.ctx.arc(this.slotX, this.circleY, this.circleSize, 0, 2 * Math.PI) this.ctx.arc(this.slotX, this.circleY, this.circleSize, 0, 2 * Math.PI)
this.ctx.closePath() this.ctx.closePath()
this.ctx.stroke() this.ctx.stroke()
// Bigger stroke circle // Bigger stroke circle
this.ctx.strokeStyle = "#6f6f6e" this.ctx.strokeStyle = "#6f6f6e"
this.ctx.lineWidth = 3 this.ctx.lineWidth = 3
@ -676,7 +693,6 @@ class View{
this.ctx.closePath() this.ctx.closePath()
this.ctx.stroke() this.ctx.stroke()
} }
drawTaikoSquare(){ drawTaikoSquare(){
// Taiko square // Taiko square
this.ctx.lineWidth = 7 this.ctx.lineWidth = 7
@ -688,13 +704,11 @@ class View{
this.ctx.closePath() this.ctx.closePath()
this.ctx.stroke() this.ctx.stroke()
} }
createAsset(image, position){ createAsset(image, position){
var asset = new CanvasAsset(this, image, position) var asset = new CanvasAsset(this, image, position)
this.assets.push(asset) this.assets.push(asset)
return asset return asset
} }
drawAssets(){ drawAssets(){
if(this.controller.multiplayer != 2){ if(this.controller.multiplayer != 2){
this.assets.forEach(asset => { this.assets.forEach(asset => {
@ -702,7 +716,6 @@ class View{
}) })
} }
} }
updateCombo(combo){ updateCombo(combo){
if(combo > 0 && combo % 10 == 0 && this.don.getAnimation() != "10combo"){ if(combo > 0 && combo % 10 == 0 && this.don.getAnimation() != "10combo"){
this.don.setAnimation("10combo") this.don.setAnimation("10combo")

View File

@ -1,43 +1,39 @@
<div id='scoresheet'> <div class="scoresheet">
<div class="top-part">
<div id='top-part'>
<h2 alt="成績発表" class="stroke-main result-title">成績発表</h2> <h2 alt="成績発表" class="stroke-main result-title">成績発表</h2>
<h3 alt="" class="stroke-sub result-song"></h3> <h3 alt="" class="stroke-sub result-song"></h3>
</div> </div>
<div class="result-bar">
<div id='result-bar'> <div class="score-cont">
<img class="score-mark" />
<img id='score-mark' /> <div class="score-hp-bar-bg">
<div class="score-hp-bar-colour">
<div id='score-cont'> <img src="/assets/img/hp-bar-colour.png" />
<div id='score-hp-bar-bg'>
<div id='score-hp-bar-colour'>
<img src="/assets/img/hp-bar-colour.png" />
</div> </div>
</div> </div>
<div class="score-points"></div>
<div id='score-points'></div> <table class="score-details">
<table id='score-details'>
<tr> <tr>
<td class='floatLeft'></td><td class='value' id='nb-great'></td> <th class="header-great stroke-sub" alt="良"></th>
<td>最大コンボ数</td><td class='value' id='max-combo'></td> <td class="value nb-great stroke-sub"></td>
<td class="stroke-sub" alt="最大コンボ数">最大コンボ数</td><td class="value max-combo stroke-sub"></td>
</tr> </tr>
<tr> <tr>
<td class='floatLeft'></td><td class='value' id='nb-good'></td> <th class="header-good stroke-sub" alt="可"></th>
<!--<td>連打数</td><td id='nb-rendasu'></td>--> <td class="value nb-good stroke-sub"></td>
<td class="stroke-sub" alt="連打数">連打数</td><td class="value nb-drumroll stroke-sub"></td>
</tr> </tr>
<tr> <tr>
<td class='floatLeft'>不可</td><td class='value' id='nb-fail'></td> <th class="header-fail stroke-sub" alt="不可">不可</th>
<td class="value nb-fail stroke-sub"></td>
<td></td><td></td> <td></td><td></td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
<div class="bottom-part">
<div id='bottom-part'> <div class="gradient-overlay"></div>
<div class='gradient-overlay'></div> <button type="button" class="song-select">Song select</button>
<button type='button' id='song-select'>Song select</button> <button type="button" class="replay">Replay</button>
<button type='button' id='replay'>Replay</button>
</div> </div>
</div>
</div>

View File

@ -4,9 +4,9 @@ import asyncio
import websockets import websockets
import json import json
users = []
server_status = { server_status = {
"waiting": {} "waiting": {},
"users": []
} }
def msgobj(type, value=None): def msgobj(type, value=None):
@ -25,7 +25,7 @@ def status_event():
return msgobj("users", value) return msgobj("users", value)
async def notify_status(): async def notify_status():
ready_users = [user for user in users if "ws" in user and user["action"] == "ready"] ready_users = [user for user in server_status["users"] if "ws" in user and user["action"] == "ready"]
if ready_users: if ready_users:
sent_msg = status_event() sent_msg = status_event()
await asyncio.wait([user["ws"].send(sent_msg) for user in ready_users]) await asyncio.wait([user["ws"].send(sent_msg) for user in ready_users])
@ -36,7 +36,7 @@ async def connection(ws, path):
"ws": ws, "ws": ws,
"action": "ready" "action": "ready"
} }
users.append(user) server_status["users"].append(user)
try: try:
# Notify user about other users # Notify user about other users
await ws.send(status_event()) await ws.send(status_event())
@ -126,8 +126,8 @@ async def connection(ws, path):
elif action == "playing": elif action == "playing":
# Playing with another user # Playing with another user
if "other_user" in user and "ws" in user["other_user"]: if "other_user" in user and "ws" in user["other_user"]:
if type == "note": if type == "note" or type == "drumroll" or type == "gameresults":
await user["other_user"]["ws"].send(msgobj("note", value)) await user["other_user"]["ws"].send(msgobj(type, value))
if type == "gameend": if type == "gameend":
# User wants to disconnect # User wants to disconnect
user["action"] = "ready" user["action"] = "ready"
@ -151,7 +151,7 @@ async def connection(ws, path):
finally: finally:
# User disconnected # User disconnected
del user["ws"] del user["ws"]
del users[users.index(user)] del server_status["users"][server_status["users"].index(user)]
if "other_user" in user and "ws" in user["other_user"]: if "other_user" in user and "ws" in user["other_user"]:
user["other_user"]["action"] = "ready" user["other_user"]["action"] = "ready"
await asyncio.wait([ await asyncio.wait([