diff --git a/public/index.html b/public/index.html index 6c35a2f..5d452c6 100644 --- a/public/index.html +++ b/public/index.html @@ -22,7 +22,6 @@ - @@ -47,6 +46,7 @@ +
diff --git a/public/src/css/animations.css b/public/src/css/animations.css deleted file mode 100644 index 82dce8a..0000000 --- a/public/src/css/animations.css +++ /dev/null @@ -1,58 +0,0 @@ -@keyframes don-normal { -0%{background-position-y:0px} -6.35%{background-position-y:-184px} -7.94%{background-position-y:-368px} -9.52%{background-position-y:-552px} -11.11%{background-position-y:-736px} -12.7%{background-position-y:-920px} -14.29%{background-position-y:-1104px} -15.87%{background-position-y:-1104px} -17.46%{background-position-y:-920px} -19.05%{background-position-y:-736px} -20.63%{background-position-y:-552px} -22.22%{background-position-y:-368px} -23.81%{background-position-y:-184px} -25.4%{background-position-y:0px} -31.75%{background-position-y:-184px} -33.33%{background-position-y:-368px} -34.92%{background-position-y:-552px} -36.51%{background-position-y:-736px} -38.1%{background-position-y:-920px} -39.68%{background-position-y:-1104px} -41.27%{background-position-y:-1104px} -42.86%{background-position-y:-920px} -44.44%{background-position-y:-736px} -46.03%{background-position-y:-552px} -47.62%{background-position-y:-368px} -49.21%{background-position-y:-184px} -50.79%{background-position-y:0px} -57.14%{background-position-y:-184px} -58.73%{background-position-y:-368px} -60.32%{background-position-y:-552px} -61.9%{background-position-y:-736px} -63.49%{background-position-y:-920px} -65.08%{background-position-y:-1104px} -66.67%{background-position-y:-1104px} -68.25%{background-position-y:-920px} -69.84%{background-position-y:-1288px} -71.43%{background-position-y:-1472px} -73.02%{background-position-y:-1656px} -74.6%{background-position-y:-1840px} -76.19%{background-position-y:-2024px} -77.78%{background-position-y:-2024px} -79.37%{background-position-y:-2024px} -80.95%{background-position-y:-2024px} -82.54%{background-position-y:-1840px} -84.13%{background-position-y:-1656px} -85.71%{background-position-y:-1472px} -87.3%{background-position-y:-1288px} -88.89%{background-position-y:-2392px} -90.48%{background-position-y:-2208px} -92.06%{background-position-y:-2208px} -93.65%{background-position-y:-2392px} -95.24%{background-position-y:-2576px} -96.83%{background-position-y:-2760px} -98.41%{background-position-y:-2944px} -100%{background-position-y:-3128px} -} - diff --git a/public/src/css/loadsong.css b/public/src/css/loadsong.css index a726880..78e368d 100644 --- a/public/src/css/loadsong.css +++ b/public/src/css/loadsong.css @@ -1,31 +1,31 @@ #load-song{ width: 100%; height: 100%; - margin:0; - padding: 0%; } - #loading-song{ - width:20%; - height:30%; position: absolute; - top:35%; - left:40%; - background: rgba(0,0,0,0.75); + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 20vw; + height: 15vw; + background: rgba(0, 0, 0, 0.75); border-radius: 5px; - border:3px solid white; + border: 3px solid white; + color: #fff; } - #loading-don{ - position: relative; - width:50%; - height:65%; - top: 12%; - left: 30%; + width: 50%; +} +.loading-text{ + position: relative; + font-size: 1.5vw; + text-align: center; + z-index: 1; } - -#loading-song p{ - position: absolute; - left:28%; - font-size: 3vmin; -} \ No newline at end of file diff --git a/public/src/css/main.css b/public/src/css/main.css index 064fc54..405920a 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -1,229 +1,190 @@ -@font-face { - font-family: 'TnT'; - src: url('../../assets/fonts/TnT.ttf') format('truetype'); +@font-face{ + font-family: TnT; + src: url("/assets/fonts/TnT.ttf") format("truetype"); } - -@font-face { - font-family: 'Kozuka'; - src: url('../../assets/fonts/KozGoPro-Bold.otf') format('truetype'); +@font-face{ + font-family: Kozuka; + src: url("/assets/fonts/KozGoPro-Bold.otf") format("truetype"); } - -html, body{ - padding: 0; +html, +body{ margin: 0; - width:100%; + width: 100%; height: 100%; - background: black; - color:white; - user-select: none; + background: #fe7839; + user-select: none; } - #screen{ - width:100%; - height:100%; - margin:0; - padding:0; - background: url('/assets/img/bg-pattern-1.png') top center; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + background: #fe7839 url("/assets/img/bg-pattern-1.png") top center; + font-family: TnT; } - #assets{ - display:none; + display: none; } - .window{ - width: 60vmin; - height: 23vmin; - padding: 3vmin; - color: black; - background: rgba(255, 220, 47, 0.95); - border: .5vmin outset #f4ae00; - box-shadow: 2px 2px 10px black; - margin: auto; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: flex; - flex-direction: column; - justify-content: space-between; - + width: 60vmin; + height: 23vmin; + padding: 3vmin; + color: black; + background: rgba(255, 220, 47, 0.95); + border: .5vmin outset #f4ae00; + box-shadow: 2px 2px 10px black; + margin: auto; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + } - -.stroke-main { - font-weight: 300; +.stroke-main{ + font-weight: 300; } - -.result-title { - margin-top: 9px !important; - margin-left: 5px !important; - z-index: 1; +.result-title{ + margin-top: 9px !important; + margin-left: 5px !important; + z-index: 1; } - -.result-song, .game-song { - position: absolute; - right: 0; - font-size: 5vmin; - margin: 3vmin 3vmin 0px 0px; - color: white; - float: right; - z-index: 1; - font-weight: 300; +.result-song, +.game-song{ + position: absolute; + right: 0; + font-size: 5vmin; + margin: 3vmin 3vmin 0px 0px; + color: white; + float: right; + z-index: 1; + font-weight: 300; } - -.stroke-main:before { - content: attr(alt); - left: 0; - z-index: -1; - position: absolute; - -webkit-text-stroke: 0.3em #fb3c0c; +.stroke-main::before{ + content: attr(alt); + left: 0; + z-index: -1; + position: absolute; + -webkit-text-stroke: 0.3em #fb3c0c; } - -.stroke-main:after { - content: attr(alt); - left: 0; - z-index: -2; - position: absolute; - -webkit-text-stroke: 0.5em #000; +.stroke-main::after{ + content: attr(alt); + left: 0; + z-index: -2; + position: absolute; + -webkit-text-stroke: 0.5em #000; } - -.stroke-sub:before { - content: attr(alt); - position: absolute; - -webkit-text-stroke: 0.25em #000; - left: 0; - z-index: -1; +.stroke-sub::before{ + content: attr(alt); + position: absolute; + -webkit-text-stroke: 0.25em #000; + left: 0; + z-index: -1; } - -.songsel-title { - position: absolute; - z-index: 1; - font-size: 7vmin; - margin: 20px; +.don{ + background-position-y: 0; + position: absolute; + top: 0px; } - -.click-to-continue:before { - width: 100%; +.alpha-title .song-title-char{ + transform: scale(1.3, 1); + font-size: 80%; + line-height: 22px; } - - -.don { - background-position-y: 0; - position: absolute; - top: 0px; +.song-title-apos{ + padding-left: 4px; } - -.alpha-title .song-title-char { - transform: scale(1.3, 1); - font-size: 80%; - line-height: 22px; +.song-title-char[alt="ぁ"], +.song-title-char[alt="ぃ"], +.song-title-char[alt="ぅ"], +.song-title-char[alt="ぇ"], +.song-title-char[alt="ぉ"], +.song-title-char[alt="ゃ"], +.song-title-char[alt="ゅ"], +.song-title-char[alt="ょ"], +.song-title-char[alt="っ"], +.song-title-char[alt="ァ"], +.song-title-char[alt="ィ"], +.song-title-char[alt="ゥ"], +.song-title-char[alt="ェ"], +.song-title-char[alt="ォ"], +.song-title-char[alt="ャ"], +.song-title-char[alt="ュ"], +.song-title-char[alt="ョ"], +.song-title-char[alt="ッ"]{ + margin-top: -6px; } - -.song-title-apos { - padding-left: 4px; +.song-title-char[alt="ー"], +.song-title-char[alt="-"]{ + transform: rotate(95deg); + font-size: 90%; } - -.song-title-char[alt="ぁ"],.song-title-char[alt="ぃ"],.song-title-char[alt="ぅ"],.song-title-char[alt="ぇ"],.song-title-char[alt="ぉ"], -.song-title-char[alt="ゃ"],.song-title-char[alt="ゅ"],.song-title-char[alt="ょ"],.song-title-char[alt="っ"], -.song-title-char[alt="ァ"],.song-title-char[alt="ィ"],.song-title-char[alt="ゥ"],.song-title-char[alt="ェ"],.song-title-char[alt="ォ"], -.song-title-char[alt="ャ"],.song-title-char[alt="ュ"],.song-title-char[alt="ョ"],.song-title-char[alt="ッ"] -{ - margin-top: -6px; +#tutorial-outer{ + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + position: absolute; + width: 100%; + height: 100%; } - -.song-title-char[alt="ー"], .song-title-char[alt="-"] { - transform: rotate(95deg); - font-size: 90%; +#tutorial{ + background: rgb(246, 234, 212); + color: black; + border: 5px black solid; + border-radius: 10px; + height: 65%; + width: 50%; + padding: 20px; + font-size: 16pt; + position: relative; } - - -#tutorial-outer { - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - position: absolute; - width: 100%; - height: 100%; +#tutorial-title{ + z-index: 1; + position: absolute; + color: white; + top: -25px; + font-size: 26pt; } - -#tutorial { - background: rgb(246, 234, 212); - color: black; - border: 5px black solid; - border-radius: 10px; - height: 65%; - width: 50%; - padding: 20px; - font-size: 16pt; - position: relative; +#tutorial-content{ + padding: 15px 30px; } - -#tutorial-title { - z-index: 1; - position: absolute; - color: white; - top: -25px; - font-size: 26pt; +kbd{ + font-family: inherit; + padding: 0.1em 0.6em; + border: 1px solid #ccc; + font-size: 13px; + background-color: #f7f7f7; + color: #333; + box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + border-radius: 3px; + display: inline-block; + text-shadow: 0 1px 0 #fff; + line-height: 1.4; + white-space: nowrap; } - -#tutorial-content { - padding: 15px 30px; +.taibtn{ + bottom: 15px; + margin: 0 auto; + position: absolute; + right: 15px; + padding: 10px 40px; + border-radius: 15px; + border: 3px rgba(218, 205, 178, 1) solid; + cursor: pointer; } - -kbd { - font-family: inherit; - padding: 0.1em 0.6em; - border: 1px solid #ccc; - font-size: 13px; - background-color: #f7f7f7; - color: #333; - -moz-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2),0 0 0 2px #ffffff inset; - -webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; - box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; - display: inline-block; - text-shadow: 0 1px 0 #fff; - line-height: 1.4; - white-space: nowrap; +.taibtn:hover{ + z-index: 1; + color: white; + background: rgb(255, 181, 71); + border-color: white; } - -.taibtn { - bottom: 15px; - margin: 0 auto; - position: absolute; - right: 15px; - padding: 10px 40px; - border-radius: 15px; - border: 3px rgba(218, 205, 178, 1) solid; - cursor: pointer; +.taibtn::before{ + padding: 0 40px; } - -.taibtn:hover { - z-index: 1; - color: white; - background: rgb(255, 181, 71); - border-color: white; +#tutorial-end-button{ + font-size: 22pt; } - -.taibtn:before { - padding: 0 40px; -} - -#tutorial-end-button { - font-size: 22pt; -} - -#songsel-help { - float: right; - background: rgba(255, 255, 255, 0.5); - color: black; - padding: 15px; - margin: 10px; - font-size: 18px; - border: 3px black solid; - border-radius: 50px; - cursor: pointer; -} \ No newline at end of file diff --git a/public/src/css/songselect.css b/public/src/css/songselect.css index 81a8298..6addc3f 100644 --- a/public/src/css/songselect.css +++ b/public/src/css/songselect.css @@ -1,139 +1,174 @@ -@-webkit-keyframes bgscroll { - from {background-position:0 0;} - to {background-position:-200px 0;} +@-webkit-keyframes bgscroll{ + from{ + background-position: 0 0; + } + to{ + background-position: -200px 0; + } } - -@keyframes bgscroll { - from {background-position:0 0;} - to {background-position:-200px 0;} +@keyframes bgscroll{ + from{ + background-position: 0 0; + } + to{ + background-position: -200px 0; + } } - #song-select{ width: 100%; - height:100%; - background: url('/assets/img/bg-pattern-1.png'); + height: 100%; + background: url("/assets/img/bg-pattern-1.png"); animation: bgscroll 3s infinite linear; - -webkit-animation: bgscroll 3s infinite linear; + white-space: nowrap; } - #song-container{ - width:98%; - height:80%; + width: 98%; + height: 80%; padding: 5% 1% 1% 1%; - text-align: center; + text-align: center; } - ul li{ - list-style:none; + list-style: none; } - .difficulties{ - float:left; - display:inline-block; - width:70%; - height: 100%; + position: absolute; + left: 0; + display: block; + width: 303px; + height: 100%; + opacity: 0; + transition: opacity 0.1s; } - -.song-title-char { - text-align: center; - width: 45px; - display: block; +.song.opened .difficulties{ + opacity: 1; + transition: opacity 0.1s 0.2s; } - -.song-title-char:before { - content: attr(alt); - position: absolute; - -webkit-text-stroke: 0.25em #000; - z-index: -1; +.song-title-char{ + text-align: center; + width: 45px; + display: block; +} +.song-title-char::before{ + content: attr(alt); + position: absolute; + -webkit-text-stroke: 0.25em #000; + z-index: -1; } - .song-title{ - float: right; - width: 45px; - padding: 10px 2px; - word-wrap: break-word; - font-size: 22pt; - color: white; - position: relative; - z-index: 1; - line-height: 28px; + float: right; + width: 45px; + height: 100%; + padding: 10px 2px; + word-wrap: break-word; + font-size: 22pt; + color: white; + position: relative; + z-index: 1; + line-height: 28px; } - -.song-title-space { - line-height: 25px; +.song-title-space{ + line-height: 25px; } - .song{ - font-size: 14pt; - width: 50px; - margin-right:15px; - height:100%; - color: black; - display: inline-block; - background: rgba(255, 220, 47, 0.90); - border: 7px outset #f4ae00; - box-shadow: 2px 2px 10px black; - overflow: hidden; + font-size: 14pt; + width: 50px; + margin-right: 15px; + height: 100%; + color: black; + display: inline-block; + background: rgba(255, 220, 47, 0.90); + border: 7px outset #f4ae00; + box-shadow: 2px 2px 10px black; + overflow: hidden; cursor: pointer; position: relative; + transition: width 0.3s; +} +.song:not(.opened):hover{ + background: rgba(255, 233, 125, 0.90); } - .opened{ - width:375px; + width: 375px; } - .difficulty{ - display:none; - cursor:pointer; - width: 35px; - height: 70%; - border-radius: 5px; - display: inline-block; - margin: 5px; - float: left; - background:white; - border:10px solid #ae7a26; - position:relative; + display: none; + cursor: pointer; + width: 35px; + height: 70%; + border-radius: 5px; + display: inline-block; + margin: 5px; + float: left; + background: white; + border: 10px solid #ae7a26; + position: relative; } - .difficulty .diffname{ - word-wrap: break-word; - width: 20px; - display: block; - margin: auto; - margin-top:10px; - font-size: 20pt; - margin-left: 6px; + word-wrap: break-word; + width: 20px; + display: block; + margin: auto; + margin-top: 10px; + font-size: 20pt; + margin-left: 6px; + white-space: normal; } - .difficulty .stars{ - position:absolute; - color: #f12b69; - margin-left: -17px; - width:100%; - bottom:10px; + position: absolute; + color: #f12b69; + margin-left: -17px; + width: 100%; + bottom: 10px; } - .difficulty:hover{ - border-color:#fa5d3a; - color:white; - background:#0c6577; + border-color: #fa5d3a; + color: white; + background: #0c6577; } - .difficulty:hover .diffname{ - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: black; + -webkit-text-stroke-width: 1px; + -webkit-text-stroke-color: black; } - .difficulty:hover .stars{ - color:white; + color: white; } - .song.p2:not(.opened)::after, .difficulty.p2::after{ - content:"P2"; - display:block; - position:absolute; - bottom:0; - width:100%; + content: "P2"; + display: block; + position: absolute; + bottom: 0; + width: 100%; +} +#songsel-help{ + float: right; + background: rgba(255, 255, 255, 0.5); + color: black; + padding: 15px; + margin: 10px; + font-size: 18px; + border: 3px black solid; + border-radius: 50px; + cursor: pointer; +} +.songsel-title-song, +.songsel-title-difficulty{ + position: absolute; + left: -300px; + opacity: 0; + margin: 20px; + color: #fff; + font-size: 7vmin; + z-index: 1; + transition: left 0s 0.2s, opacity 0.2s; +} +#song-select.difficulty-select .songsel-title-difficulty{ + left: 0; + opacity: 1; + transition: left 0.4s 0.2s, opacity 0.4s 0.2s; +} +#song-select:not(.difficulty-select) .songsel-title-song{ + left: 0; + opacity: 1; + transition: left 0.4s 0.2s, opacity 0.4s 0.2s; } diff --git a/public/src/css/titlescreen.css b/public/src/css/titlescreen.css index 4da86c8..95ef9b0 100644 --- a/public/src/css/titlescreen.css +++ b/public/src/css/titlescreen.css @@ -1,51 +1,39 @@ -@keyframes toggleFade { - - 0%{ - opacity:1; - } - 50% { - opacity: 0; - } +@keyframes toggleFade{ + 40%{ + opacity: 1; + } + 70%{ + opacity: 0.2; + } } - - #title-screen{ - position:absolute; - top:0; - left:0; - width:100%; - height:100%; - display: none; - margin:0px; - cursor: pointer; - background: url('/assets/img/title-screen.png'); - -webkit-background-size: cover; /* pour Chrome et Safari */ - -moz-background-size: cover; /* pour Firefox */ - -o-background-size: cover; /* pour Opera */ - background-size: cover; /* version standardis�e */ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + background: #1389f0 url("/assets/img/title-screen.png") no-repeat center; + background-size: cover; + cursor: pointer; } - -#logo-big-cont{ - position:absolute; - max-width: 654px; - max-height: 300px; +.logo-big{ + width: 90vmin; + height: auto; } - -#logo-big-cont img{ - width:100%; - height:100%; -} - .click-to-continue{ - - display:block; - font-size: 8vmin; - color:white; - text-align: center; - position:absolute; - bottom:2%; - width:100%; - animation: toggleFade 1s infinite ease-out; - z-index: 1; - -} \ No newline at end of file + position:absolute; + bottom: 10%; + color: #fff; + font-size: 8vmin; + text-align: center; + z-index: 1; + animation: toggleFade 2s infinite ease-in-out; +} +.click-to-continue::before{ + -webkit-text-stroke: 0.25em #f00; + filter: blur(0.3vmin); + left: auto; +} diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 6ddc3d0..cb91c81 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -1,106 +1,109 @@ var assets = { - - img: [ - 'background.png', - 'title-screen.png', - 'logo-big.png', - 'don-0.png', - 'don-1.png', - 'big-don-0.png', - 'big-don-1.png', - 'taiko.png', - 'taiko-key-blue.png', - 'taiko-key-red.png', - 'hp-bar-bg.png', - 'hp-bar-colour.png', - 'score-0.png', - 'score-0-b.png', - 'score-230.png', - 'score-450.png', - 'dancing-don.gif', - 'scoresheet.jpg', - 'bg-pattern-1.png', - 'bg-pattern-2.png', - 'ranking-S.png', - 'ranking-X.png', - 'muzu_easy.png', - 'muzu_normal.png', - 'muzu_hard.png', - 'muzu_oni.png', - 'don_anim_normal.png', - 'don_anim_10combo.png', - 'balloon.png' + "img": [ + "background.png", + "title-screen.png", + "logo-big.png", + "don-0.png", + "don-1.png", + "big-don-0.png", + "big-don-1.png", + "taiko.png", + "taiko-key-blue.png", + "taiko-key-red.png", + "hp-bar-bg.png", + "hp-bar-colour.png", + "score-0.png", + "score-0-b.png", + "score-230.png", + "score-450.png", + "dancing-don.gif", + "scoresheet.jpg", + "bg-pattern-1.png", + "bg-pattern-2.png", + "ranking-S.png", + "ranking-X.png", + "muzu_easy.png", + "muzu_normal.png", + "muzu_hard.png", + "muzu_oni.png", + "don_anim_normal.png", + "don_anim_10combo.png", + "balloon.png" + ], + "audioSfx": [ + "start.wav", + "don.wav", + "ka.wav", + + "combo-50.wav", + "combo-100.wav", + "combo-200.wav", + "combo-300.wav", + "combo-400.wav", + "combo-500.wav", + "combo-600.wav", + "combo-700.wav", + "combo-800.wav", + "combo-900.wav", + "combo-1000.wav", + "combo-1100.wav", + "combo-1200.wav", + "combo-1300.wav", + "combo-1400.wav", + "fullcombo.wav", + + "combo-50-meka.wav", + "combo-100-meka.wav", + "combo-200-meka.wav", + "combo-300-meka.wav", + "combo-400-meka.wav", + "combo-500-meka.wav", + "combo-600-meka.wav", + "combo-700-meka.wav", + "combo-800-meka.wav", + "combo-900-meka.wav", + "combo-1000-meka.wav", + "combo-1100-meka.wav", + "combo-1200-meka.wav", + "combo-1300-meka.wav", + "combo-1400-meka.wav", + "fullcombo-meka.wav", + + "song-select.wav", + "title.ogg", + "pause.wav", + "cancel.wav", + "results.wav", + "diffsel.wav", + + "gamefullcombo.wav", + "gameclear.wav", + "gamefail.wav", + + "note_don.ogg", + "note_ka.ogg", + "balloon.ogg" + ], + "audioMusic": [ + "bgm_songsel.ogg", + "bgm_result.ogg", + "bgm_setsume.ogg" + ], + "fonts": [ + "Kozuka", + "TnT" + ], + "views": [ + "game.html", + "loadsong.html", + "scoresheet.html", + "songselect.html", + "titlescreen.html", + "tutorial.html" ], - audioSfx: [ - 'start.wav', - 'don.wav', - 'ka.wav', - - 'combo-50.wav', - 'combo-100.wav', - 'combo-200.wav', - 'combo-300.wav', - 'combo-400.wav', - 'combo-500.wav', - 'combo-600.wav', - 'combo-700.wav', - 'combo-800.wav', - 'combo-900.wav', - 'combo-1000.wav', - 'combo-1100.wav', - 'combo-1200.wav', - 'combo-1300.wav', - 'combo-1400.wav', - 'fullcombo.wav', - - 'combo-50-meka.wav', - 'combo-100-meka.wav', - 'combo-200-meka.wav', - 'combo-300-meka.wav', - 'combo-400-meka.wav', - 'combo-500-meka.wav', - 'combo-600-meka.wav', - 'combo-700-meka.wav', - 'combo-800-meka.wav', - 'combo-900-meka.wav', - 'combo-1000-meka.wav', - 'combo-1100-meka.wav', - 'combo-1200-meka.wav', - 'combo-1300-meka.wav', - 'combo-1400-meka.wav', - 'fullcombo-meka.wav', - - 'song-select.wav', - 'title.ogg', - 'pause.wav', - 'cancel.wav', - 'results.wav', - 'diffsel.wav', - - 'gamefullcombo.wav', - 'gameclear.wav', - 'gamefail.wav', - - 'note_don.ogg', - 'note_ka.ogg', - 'balloon.ogg' - ], - - audioMusic:[ - 'bgm_songsel.ogg', - 'bgm_result.ogg', - 'bgm_setsume.ogg' - ], - - songs: [], - - fonts: [ - 'Kozuka', - 'TnT' - ], - - sounds: {}, - image: {} - -}; \ No newline at end of file + "songs": [], + "sounds": {}, + "image": {}, + "pages": {} +} diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 2414dc2..613b308 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -4,7 +4,6 @@ class Controller{ this.songData = songData this.autoPlayEnabled = autoPlayEnabled this.multiplayer = multiplayer - this.pauseMenu = false var backgroundURL = "/songs/" + this.selectedSong.folder + "/bg.png" var songParser = new ParseSong(songData) @@ -40,16 +39,19 @@ class Controller{ } } loadUIEvents(){ - $("#song-selection-butt").click(() => { - assets.sounds["don"].play() - this.songSelection() + this.continueBtn = document.getElementById("song-selection-butt") + this.restartBtn = document.getElementById("song-selection-butt") + this.songSelBtn = document.getElementById("song-selection-butt") + pageEvents.add(this.continueBtn, "click", () => { + this.togglePauseMenu() }) - $("#restart-butt").click(() => { + pageEvents.add(this.restartBtn, "click", () => { assets.sounds["don"].play() this.restartSong() }) - $("#continue-butt").click(() => { - this.togglePauseMenu() + pageEvents.add(this.songSelBtn, "click", () => { + assets.sounds["don"].play() + this.songSelection() }) } startMainLoop(){ @@ -66,7 +68,7 @@ class Controller{ } mainLoop(){ if(this.mainLoopRunning){ - if(this.multiplayer != 2){ + if(this.multiplayer !== 2){ requestAnimationFrame(() => { if(this.syncWith){ this.syncWith.game.elapsedTime.ms = this.game.elapsedTime.ms @@ -87,6 +89,9 @@ class Controller{ } if(this.mainLoopStarted){ this.game.update() + if(!this.mainLoopRunning){ + return + } this.game.playMainMusic() } this.view.refresh() @@ -99,10 +104,10 @@ class Controller{ this.togglePause() this.view.togglePauseMenu() } - displayResults(){ + gameEnded(){ var score = this.getGlobalScore() var vp - if(score.fail == 0){ + if(score.fail === 0){ vp = "fullcombo" this.playSoundMeka("fullcombo", 1.350) }else if(score.hp >= 50){ @@ -111,33 +116,29 @@ class Controller{ vp = "fail" } assets.sounds["game" + vp].play() - setTimeout(() => { - if(this.mainLoopRunning){ - this.stopMainLoop() - if(this.multiplayer != 2){ - new Scoresheet(this, this.getGlobalScore(), this.multiplayer) - } - } - }, 7000) + } + displayResults(){ + this.clean() + if(this.multiplayer !== 2){ + new Scoresheet(this, this.getGlobalScore(), this.multiplayer) + } } displayScore(score, notPlayed){ this.view.displayScore(score, notPlayed) } songSelection(){ - $("#music-bg").remove() - this.stopMainLoop() + this.clean() new SongSelect() } restartSong(){ - this.stopMainLoop() - $("#screen").load("/src/views/game.html", () => { - if(this.multiplayer){ - new loadSong(this.selectedSong, false, true) - }else{ - var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) - taikoGame.run() - } - }) + this.clean() + if(this.multiplayer){ + new loadSong(this.selectedSong, false, true) + }else{ + loader.changePage("game") + var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) + taikoGame.run() + } } playSoundMeka(soundID, time){ var meka = "" @@ -195,4 +196,16 @@ class Controller{ this.mekadon.play(circle) } } + clean(){ + this.stopMainLoop() + this.keyboard.clean() + this.view.clean() + + pageEvents.remove(this.continueBtn, "click") + delete this.continueBtn + pageEvents.remove(this.restartBtn, "click") + delete this.restartBtn + pageEvents.remove(this.songSelBtn, "click") + delete this.songSelBtn + } } diff --git a/public/src/js/game.js b/public/src/js/game.js index 7d660dd..d879ce2 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -219,27 +219,32 @@ class Game{ whenLastCirclePlayed(){ 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 + var ms = this.getElapsedTime().ms + if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 1900){ + this.fadeOutStarted = ms } } whenFadeoutMusic(){ - if(this.fadeOutStarted){ - if(this.musicFadeOut==0){ + var started = this.fadeOutStarted + if(started){ + var ms = this.getElapsedTime().ms + if(this.musicFadeOut === 0){ snd.musicGain.fadeOut(1.6) - if(this.controller.multiplayer == 1){ + if(this.controller.multiplayer === 1){ p2.send("gameresults", this.controller.getGlobalScore()) } this.musicFadeOut++ - } - if(this.musicFadeOut == 1 && this.getElapsedTime().ms >= this.fadeOutStarted + 1600){ - this.controller.displayResults() + }else if(this.musicFadeOut === 1 && ms >= started + 1600){ + this.controller.gameEnded() this.mainAsset.stop() p2.send("gameend") - setTimeout(() => { - snd.musicGain.fadeIn() - snd.musicGain.unmute() - }, 1000) + this.musicFadeOut++ + }else if(this.musicFadeOut === 2 && ms >= started + 2600){ + snd.musicGain.fadeIn() + snd.musicGain.unmute() + this.musicFadeOut++ + }else if(this.musicFadeOut === 3 && ms >= started + 8600){ + this.controller.displayResults() this.musicFadeOut++ } } diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index ee3ebe2..23fc160 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -1,145 +1,134 @@ -function Keyboard(controller){ - - var _kbd = { - "don_l": 86, // V - "don_r": 66, // B - "ka_l": 67, // C - "ka_r": 78, // N - "pause": 81, // Q - "back": 8 // Backspace - } - var _this = this; - var _keys = {}; - var _waitKeyupScore = {}; - var _waitKeyupSound = {}; - var _waitKeyupMenu = {}; - var _keyTime = { - "don": -Infinity, - "ka": -Infinity - } - - this.getBindings = function(){ - return _kbd - } - - var _gamepad = new Gamepad(this) - - $(document).keydown(function(e){ - - if (e.which === 8 && !$(e.target).is("input, textarea")) - // Disable back navigation when pressing backspace - e.preventDefault(); - - if(_this.buttonEnabled(e.which)){ - _this.setKey(e.which, true); - } - }); - - $(document).keyup(function(e){ - if(_this.buttonEnabled(e.which)){ - _this.setKey(e.which, false); - } - }); - - this.buttonEnabled = function(keyCode){ - if(controller.autoPlayEnabled){ - switch(keyCode){ - case _kbd["don_l"]: - case _kbd["don_r"]: - case _kbd["ka_l"]: - case _kbd["ka_r"]: - return false - } - } - return true - } - - this.checkGameKeys = function(){ - if(!controller.autoPlayEnabled){ - _gamepad.play() - } - _this.checkKeySound(_kbd["don_l"], "don") - _this.checkKeySound(_kbd["don_r"], "don") - _this.checkKeySound(_kbd["ka_l"], "ka") - _this.checkKeySound(_kbd["ka_r"], "ka") - } - - this.checkMenuKeys = function(){ - if(!controller.multiplayer){ - _gamepad.play(1) - _this.checkKey(_kbd["pause"], "menu", function(){ - controller.togglePauseMenu(); - }) - } - if(controller.multiplayer != 2){ - _this.checkKey(_kbd["back"], "menu", function(){ - if(controller.multiplayer == 1){ - p2.send("gameend") - } - controller.togglePause(); - controller.songSelection(); - }) - } - } - - this.checkKey = function(keyCode, keyup, callback){ - if(_keys[keyCode] && !_this.isWaitingForKeyup(keyCode, keyup)){ - _this.waitForKeyup(keyCode, keyup); - callback() - } - } - - this.checkKeySound = function(keyCode, sound){ - _this.checkKey(keyCode, "sound", function(){ - 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 - }) - } - - this.getKeys = function(){ - return _keys; - } - - this.setKey=function(keyCode, down){ - if(down){ - _keys[keyCode]=true; - }else{ - delete _keys[keyCode]; - delete _waitKeyupScore[keyCode]; - delete _waitKeyupSound[keyCode]; - delete _waitKeyupMenu[keyCode]; - } - } - - this.isWaitingForKeyup = function(key, type){ - var isWaiting; - if(type == "score") isWaiting = _waitKeyupScore[key]; - else if(type == "sound") isWaiting = _waitKeyupSound[key]; - else if(type == "menu") isWaiting = _waitKeyupMenu[key]; - return isWaiting; - } - - this.waitForKeyup = function(key, type){ - if(type == "score") _waitKeyupScore[key] = true; - else if(type == "sound") _waitKeyupSound[key] = true; - else if(type == "menu") _waitKeyupMenu[key] = true; - } - - this.getKeyTime = function(){ - return _keyTime; - } - -} \ No newline at end of file +class Keyboard{ + constructor(controller){ + this.controller = controller + this.kbd = { + "don_l": 86, // V + "don_r": 66, // B + "ka_l": 67, // C + "ka_r": 78, // N + "pause": 81, // Q + "back": 8 // Backspace + } + this.keys = {} + this.waitKeyupScore = {} + this.waitKeyupSound = {} + this.waitKeyupMenu = {} + this.keyTime = { + "don": -Infinity, + "ka": -Infinity + } + this.gamepad = new Gamepad(this) + pageEvents.keyAdd(this, "all", "both", event => { + if (event.keyCode === 8){ + // Disable back navigation when pressing backspace + event.preventDefault() + } + if(this.buttonEnabled(event.keyCode)){ + this.setKey(event.keyCode, event.type === "keydown") + } + }) + } + getBindings(){ + return this.kbd + } + buttonEnabled(keyCode){ + if(this.controller.autoPlayEnabled){ + switch(keyCode){ + case this.kbd["don_l"]: + case this.kbd["don_r"]: + case this.kbd["ka_l"]: + case this.kbd["ka_r"]: + return false + } + } + return true + } + checkGameKeys(){ + if(!this.controller.autoPlayEnabled){ + this.gamepad.play() + } + this.checkKeySound(this.kbd["don_l"], "don") + this.checkKeySound(this.kbd["don_r"], "don") + this.checkKeySound(this.kbd["ka_l"], "ka") + this.checkKeySound(this.kbd["ka_r"], "ka") + } + checkMenuKeys(){ + if(!this.controller.multiplayer){ + this.gamepad.play(true) + this.checkKey(this.kbd["pause"], "menu", () => { + this.controller.togglePauseMenu() + }) + } + if(this.controller.multiplayer !== 2){ + this.checkKey(this.kbd["back"], "menu", () => { + if(this.controller.multiplayer === 1){ + p2.send("gameend") + } + this.controller.togglePause() + this.controller.songSelection() + }) + } + } + checkKey(keyCode, keyup, callback){ + if(this.keys[keyCode] && !this.isWaitingForKeyup(keyCode, keyup)){ + this.waitForKeyup(keyCode, keyup) + callback() + } + } + checkKeySound(keyCode, sound){ + this.checkKey(keyCode, "sound", () => { + var circles = this.controller.parsedSongData.circles + var circle = circles[this.controller.game.getCurrentCircle()] + if( + (keyCode === this.kbd["don_l"] || keyCode === this.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() + } + this.keyTime[sound] = this.controller.getElapsedTime().ms + }) + } + getKeys(){ + return this.keys + } + setKey(keyCode, down){ + if(down){ + this.keys[keyCode] = true + }else{ + delete this.keys[keyCode] + delete this.waitKeyupScore[keyCode] + delete this.waitKeyupSound[keyCode] + delete this.waitKeyupMenu[keyCode] + } + } + isWaitingForKeyup(key, type){ + if(type === "score"){ + return this.waitKeyupScore[key] + }else if(type === "sound"){ + return this.waitKeyupSound[key] + }else if(type === "menu"){ + return this.waitKeyupMenu[key] + } + } + waitForKeyup(key, type){ + if(type === "score"){ + this.waitKeyupScore[key] = true + }else if(type === "sound"){ + this.waitKeyupSound[key] = true + }else if(type === "menu"){ + this.waitKeyupMenu[key] = true + } + } + getKeyTime(){ + return this.keyTime + } + clean(){ + pageEvents.keyRemove(this, "all") + } +} diff --git a/public/src/js/loader.js b/public/src/js/loader.js index deb91aa..4633fe9 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -1,15 +1,15 @@ class Loader{ constructor(){ this.loadedAssets = 0 - this.errorCount = 0 this.assetsDiv = document.getElementById("assets") - this.promises = [] - $("#screen").load("/src/views/loader.html", () => { - this.run() - }) + this.ajax("src/views/loader.html").then(this.run.bind(this)) } - run(){ + run(page){ + this.promises = [] + this.screen = document.getElementById("screen") + this.screen.innerHTML = page this.loaderPercentage = document.querySelector("#loader .percentage") + this.loaderProgress = document.querySelector("#loader .progress") assets.fonts.forEach(name => { var font = document.createElement("h1") @@ -20,11 +20,13 @@ class Loader{ FontDetect.onFontLoaded(name, resolve, reject, {msTimeout: 90000}) })) }) + var fontDetectDiv = document.getElementById("fontdetectHelper") + fontDetectDiv.parentNode.removeChild(fontDetectDiv) assets.img.forEach(name => { - var id = name.substr(0, name.length - 4) + var id = this.getFilename(name) var image = document.createElement("img") - this.promises.push(promiseLoad(image)) + this.promises.push(pageEvents.load(image)) image.id = name image.src = "/assets/img/" + name this.assetsDiv.appendChild(image) @@ -39,68 +41,82 @@ class Loader{ snd.previewGain.setVolume(0.5) assets.audioSfx.forEach(name => { - var id = name.substr(0, name.length-4) - this.promises.push(snd.sfxGain.load("/assets/audio/" + name).then(sound => { - assets.sounds[id] = sound - })) + this.promises.push(this.loadSound(name, snd.sfxGain)) }) assets.audioMusic.forEach(name => { - var id = name.substr(0, name.length-4) - this.promises.push(snd.musicGain.load("/assets/audio/" + name).then(sound => { - assets.sounds[id] = sound - })) + this.promises.push(this.loadSound(name, snd.musicGain)) }) p2 = new P2Connection() - this.promises.push(ajax("/api/songs").then(songs => { + this.promises.push(this.ajax("/api/songs").then(songs => { assets.songs = JSON.parse(songs) })) + assets.views.forEach(name => { + var id = this.getFilename(name) + this.promises.push(this.ajax("src/views/" + name).then(page => { + assets.pages[id] = page + })) + }) + this.promises.forEach(promise => { - promise.then(() => { - this.assetLoaded() - }, () => { - this.errorMsg() - }) + promise.then(this.assetLoaded.bind(this)) }) Promise.all(this.promises).then(() => { + this.clean() new Titlescreen() + }, this.errorMsg.bind(this)) + } + loadSound(name, gain){ + var id = this.getFilename(name) + return gain.load("/assets/audio/" + name).then(sound => { + assets.sounds[id] = sound }) } + getFilename(name){ + return name.slice(0, name.lastIndexOf(".")) + } errorMsg(){ - if(this.errorCount == 0){ - this.loaderPercentage.appendChild(document.createElement("br")) - this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) - } - this.errorCount++ + this.error = true + this.loaderPercentage.appendChild(document.createElement("br")) + this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) + this.clean() } assetLoaded(){ - this.loadedAssets++ - var percentage = parseInt(this.loadedAssets * 100 / this.promises.length) - document.querySelector("#loader .progress").style.width = percentage + "%" - this.loaderPercentage.firstChild.data = percentage + "%" + if(!this.error){ + this.loadedAssets++ + var percentage = Math.floor(this.loadedAssets * 100 / this.promises.length) + this.loaderProgress.style.width = percentage + "%" + this.loaderPercentage.firstChild.data = percentage + "%" + } + } + changePage(name){ + document.getElementById("screen").innerHTML = assets.pages[name] + } + ajax(url, customRequest){ + return new Promise((resolve, reject) => { + var request = new XMLHttpRequest() + request.open("GET", url) + pageEvents.load(request).then(() => { + resolve(request.response) + }, reject) + if(customRequest){ + customRequest(request) + } + request.send() + }) + } + clean(){ + delete this.assetsDiv + delete this.loaderPercentage + delete this.loaderProgress + delete this.promises } } -function ajax(url){ - return new Promise((resolve, reject) => { - var request = new XMLHttpRequest() - request.open("GET", url) - promiseLoad(request).then(() => { - resolve(request.response) - }, reject) - request.send() - }) -} -function promiseLoad(asset){ - return new Promise((resolve, reject) => { - asset.addEventListener("load", resolve) - asset.addEventListener("error", reject) - asset.addEventListener("abort", reject) - }) -} +var pageEvents = new PageEvents() +var loader = new Loader() var snd = {} var p2 -new Loader() diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index af8f3e3..8a6f925 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -5,9 +5,8 @@ class loadSong{ this.autoPlayEnabled = autoPlayEnabled this.diff = this.selectedSong.difficulty.slice(0, -4) this.songFilePath = "/songs/" + this.selectedSong.folder + "/" + this.selectedSong.difficulty - $("#screen").load("/src/views/loadsong.html", () => { - this.run() - }) + loader.changePage("loadsong") + this.run() } run(){ var id = this.selectedSong.folder @@ -15,7 +14,7 @@ class loadSong{ assets.sounds["start"].play() var img = document.createElement("img") - promises.push(promiseLoad(img)) + promises.push(pageEvents.load(img)) img.id = "music-bg" img.src = "/songs/" + id + "/bg.png" document.getElementById("assets").appendChild(img) @@ -37,15 +36,11 @@ class loadSong{ }, reject) } })) - - promises.push(ajax(this.songFilePath).then(data => { + promises.push(loader.ajax(this.songFilePath).then(data => { this.songData = data.replace(/\0/g, "").split("\n") })) - Promise.all(promises).then(() => { - $("#screen").load("/src/views/game.html", () => { - this.setupMultiplayer() - }) + this.setupMultiplayer() }, error => { console.error(error) alert("An error occurred, please refresh") @@ -53,37 +48,50 @@ class loadSong{ } setupMultiplayer(){ if(this.multiplayer){ + var loadingText = document.getElementsByClassName("loading-text")[0] + var waitingText = "Waiting for Another Player..." + loadingText.firstChild.data = waitingText + loadingText.setAttribute("alt", waitingText) + this.song2Data = this.songData this.selectedSong2 = this.selectedSong - p2.onmessage("gamestart", () => { - var taikoGame1 = new Controller(this.selectedSong, this.songData, false, 1) - var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2) - taikoGame1.run(taikoGame2) - }, true) - p2.onmessage("gameload", response => { - if(response == this.diff){ - p2.send("gamestart") - }else{ - this.selectedSong2 = { - title: this.selectedSong.title, - folder: this.selectedSong.folder, - difficulty: response + ".osu" + pageEvents.add(p2, "message", event => { + if(event.type === "gameload"){ + if(event.value === this.diff){ + p2.send("gamestart") + }else{ + this.selectedSong2 = { + title: this.selectedSong.title, + folder: this.selectedSong.folder, + difficulty: event.value + ".osu" + } + loader.ajax("/songs/" + this.selectedSong2.folder + "/" + this.selectedSong2.difficulty).then(data => { + this.song2Data = data.replace(/\0/g, "").split("\n") + p2.send("gamestart") + }, () => { + p2.send("gamestart") + }) } - ajax("/songs/" + this.selectedSong2.folder + "/" + this.selectedSong2.difficulty).then(data => { - this.song2Data = data.replace(/\0/g, "").split("\n") - p2.send("gamestart") - }, () => { - p2.send("gamestart") - }) + }else if(event.type === "gamestart"){ + this.clean() + loader.changePage("game") + var taikoGame1 = new Controller(this.selectedSong, this.songData, false, 1) + var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2) + taikoGame1.run(taikoGame2) } - }, true) + }) p2.send("join", { id: this.selectedSong.folder, diff: this.diff }) }else{ + this.clean() + loader.changePage("game") var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) taikoGame.run() } } + clean(){ + pageEvents.remove(p2, "message") + } } diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 205cb0d..9160510 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -2,128 +2,119 @@ class P2Connection{ constructor(){ this.closed = true this.lastMessages = {} - this.msgCallbacks = {} - this.closeCallbacks = new Set() - this.openCallbacks = new Set() this.otherConnected = false - this.onmessage("gamestart", () => { - this.otherConnected = true - this.notes = [] - this.drumrollPace = 45 - this.results = false - }) - this.onmessage("gameend", () => { - this.otherConnected = false - }) - this.onmessage("gameresults", response => { - this.results = response - }) - this.onmessage("note", response => { - this.notes.push(response) - }) - this.onmessage("drumroll", response => { - this.drumrollPace = response.pace - }) + this.allEvents = new Map() + this.addEventListener("message", this.message.bind(this)) + } + addEventListener(type, callback){ + var addedType = this.allEvents.get(type) + if(!addedType){ + addedType = new Set() + this.allEvents.set(type, addedType) + } + return addedType.add(callback) + } + removeEventListener(type, callback){ + var addedType = this.allEvents.get(type) + if(addedType){ + return addedType.delete(callback) + } } open(){ this.closed = false var wsProtocol = location.protocol == "https:" ? "wss:" : "ws:" this.socket = new WebSocket(wsProtocol + "//" + location.host + "/p2") - var events = ["open", "close", "message"] - events.forEach(eventName => { - this.socket.addEventListener(eventName, event => { - this[eventName + "Event"](event) - }) - }) - } - openEvent(event){ - this.openCallbacks.forEach(obj => { - obj.callback() - if(obj.once){ - this.openCallbacks.delete(obj) + pageEvents.race(this.socket, "open", "close", listener =>{ + if(listener === "open"){ + return this.openEvent() } + return this.closeEvent() }) + pageEvents.add(this.socket, "message", this.messageEvent.bind(this)) } - onopen(callback, once){ - this.openCallbacks.add({ - callback: callback, - once: once - }) + openEvent(){ + var addedType = this.allEvents.get("open") + if(addedType){ + addedType.forEach(callback => callback()) + } } close(){ this.closed = true this.socket.close() } - closeEvent(event){ + closeEvent(){ + this.removeEventListener(onmessage) + this.otherConnected = false if(!this.closed){ setTimeout(() => { - if(this.socket.readyState != this.socket.OPEN){ + if(this.socket.readyState !== this.socket.OPEN){ this.open() } }, 500) } - this.closeCallbacks.forEach(obj => { - obj.callback() - if(obj.once){ - this.closeCallbacks.delete(obj) - } - }) - } - onclose(callback, once){ - this.closeCallbacks.add({ - callback: callback, - once: once - }) + var addedType = this.allEvents.get("close") + if(addedType){ + addedType.forEach(callback => callback()) + } } send(type, value){ - if(this.socket.readyState == this.socket.OPEN){ - if(typeof value == "undefined"){ + if(this.socket.readyState === this.socket.OPEN){ + if(typeof value === "undefined"){ this.socket.send(JSON.stringify({type: type})) }else{ this.socket.send(JSON.stringify({type: type, value: value})) } }else{ - this.onopen(() => { + pageEvents.once(this, "open").then(() => { this.send(type, value) - }, true) + }) } } messageEvent(event){ try{ - var data = JSON.parse(event.data) + var response = JSON.parse(event.data) }catch(e){ - var data = {} + var response = {} } - this.lastMessages[data.type] = data.value - if(this.msgCallbacks[data.type]){ - this.msgCallbacks[data.type].forEach(obj => { - obj.callback(data.value) - if(obj.once){ - this.msgCallbacks[data.type].delete(obj) - } - }) + this.lastMessages[response.type] = response.value + var addedType = this.allEvents.get("message") + if(addedType){ + addedType.forEach(callback => callback(response)) } } - onmessage(type, callback, once){ - if(!(type in this.msgCallbacks)){ - this.msgCallbacks[type] = new Set() - } - this.msgCallbacks[type].add({ - callback: callback, - once: once - }) - } getMessage(type, callback){ if(type in this.lastMessages){ - callback(this.lastMessages[type]) + return this.lastMessages[type] + } + } + message(response){ + switch(response.type){ + case "gamestart": + this.otherConnected = true + this.notes = [] + this.drumrollPace = 45 + this.results = false + break + case "gameend": + this.otherConnected = false + break + case "gameresults": + this.results = response.value + break + case "note": + this.notes.push(response.value) + break + case "drumroll": + this.drumrollPace = response.value.pace + break } } play(circle, mekadon){ if(this.otherConnected || this.notes.length > 0){ var type = circle.getType() - if(type == "balloon"|| type == "drumroll" || type == "daiDrumroll"){ + if(type === "balloon"|| type === "drumroll" || type === "daiDrumroll"){ mekadon.playDrumrollAt(circle, 0, this.drumrollPace) - }else if(this.notes.length == 0){ + }else if(this.notes.length === 0){ mekadon.play(circle) }else{ var note = this.notes[0] diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js new file mode 100644 index 0000000..1847f1c --- /dev/null +++ b/public/src/js/pageevents.js @@ -0,0 +1,115 @@ +class PageEvents{ + constructor(){ + this.allEvents = new Map() + this.keyListeners = new Map() + this.add(window, "keydown", this.keyEvent.bind(this)) + this.add(window, "keyup", this.keyEvent.bind(this)) + } + add(target, type, callback){ + this.remove(target, type) + var addedEvent = this.allEvents.get(target) + if(!addedEvent){ + addedEvent = new Map() + this.allEvents.set(target, addedEvent) + } + addedEvent.set(type, callback) + return target.addEventListener(type, callback) + } + remove(target, type){ + var addedEvent = this.allEvents.get(target) + if(addedEvent){ + var callback = addedEvent.get(type) + if(callback){ + target.removeEventListener(type, callback) + addedEvent.delete(type) + if(addedEvent.size == 0){ + return this.allEvents.delete(target) + } + } + } + } + once(target, type){ + return new Promise(resolve => { + this.add(target, type, event => { + this.remove(target, type) + return resolve(event) + }) + }) + } + race(){ + var target = arguments[0] + return new Promise(resolve => { + for(var i = 1;i < arguments.length; i++){ + let type = arguments[i] + this.add(target, type, event => { + resolve({ + type: type, + event: event + }) + }) + } + }).then(response => { + for(var i = 1;i < arguments.length; i++){ + this.remove(target, arguments[i]) + } + return response + }) + } + load(target){ + return new Promise((resolve, reject) => { + this.race(target, "load", "error", "abort").then(response => { + if(response.type === "load"){ + return resolve(response.event) + } + return reject() + }) + }) + } + keyEvent(event){ + this.keyListeners.forEach(addedKeyCode => { + this.checkListener(addedKeyCode.get("all"), event) + this.checkListener(addedKeyCode.get(event.keyCode), event) + }) + } + checkListener(keyObj, event){ + if(keyObj && ( + keyObj.type === "both" + || keyObj.type === "down" && event.type === "keydown" + || keyObj.type === "up" && event.type === "up" + )){ + keyObj.callback(event) + } + } + keyAdd(target, keyCode, type, callback){ + // keyCode="all", type="both" + var addedKeyCode = this.keyListeners.get(target) + if(!addedKeyCode){ + addedKeyCode = new Map() + this.keyListeners.set(target, addedKeyCode) + } + addedKeyCode.set(keyCode, { + type: type, + callback: callback + }) + } + keyRemove(target, keyCode){ + var addedKeyCode = this.keyListeners.get(target) + if(addedKeyCode){ + var keyObj = addedKeyCode.get(keyCode) + if(keyObj){ + addedKeyCode.delete(keyCode) + if(addedKeyCode.size == 0){ + return this.keyListeners.delete(target) + } + } + } + } + keyOnce(target, keyCode, type){ + return new Promise(resolve => { + this.keyAdd(target, keyCode, type, event => { + this.keyRemove(target, keyCode) + return resolve(event) + }) + }) + } +} diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 766f2a9..79b9bf8 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -3,9 +3,8 @@ class Scoresheet{ this.controller = controller this.score = score this.multiplayer = multiplayer - $("#screen").load("/src/views/scoresheet.html", () =>{ - this.run() - }) + loader.changePage("scoresheet") + this.run() } setResults(score, scoreCont){ this.positionning(scoreCont) @@ -36,7 +35,7 @@ class Scoresheet{ this.altText(this.elem("max-combo", scoreCont), score.maxCombo) this.altText(this.elem("nb-drumroll", scoreCont), score.drumroll) - addEventListener("resize", () => { + pageEvents.add(window, "resize", () => { this.positionning(scoreCont) }) } @@ -82,17 +81,16 @@ class Scoresheet{ this.setResults(this.score, scoreCont) this.altText(this.elem("result-song", this.scoresheet), this.score.song) - this.elem("song-select", this.scoresheet).addEventListener("click", () => { + pageEvents.once(this.elem("song-select", this.scoresheet), "click").then(() => { + this.clean() assets.sounds["don"].play() - assets.sounds["bgm_result"].stop() this.controller.songSelection() }) - this.elem("replay", this.scoresheet).addEventListener("click", () => { + pageEvents.once(this.elem("replay", this.scoresheet), "click").then(() => { + this.clean() 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") @@ -101,4 +99,8 @@ class Scoresheet{ this.setResults(p2.results, scoreCont2) } } + clean(){ + assets.sounds["bgm_result"].stop() + pageEvents.remove(window, "resize") + } } diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 4832901..9c87356 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -1,202 +1,153 @@ -function SongSelect(){ - var _this=this; - var _songs; - var _selectedSong = {title:'', folder:'', difficulty:''}; - var _preview; - var _preview_id = 0 - var _diffNames={ - easy:"かんたん", - normal:"ふつう", - hard:"むずかしい", - oni:"おに" +class SongSelect{ + constructor(){ + this.songs + this.selectedSong = { + "title": "", + "folder": "", + "difficulty": "" + } + this.previewId = 0 + this.diffNames={ + "easy": "かんたん", + "normal": "ふつう", + "hard": "むずかしい", + "oni": "おに" + } + loader.changePage("songselect") + this.run() } - - this.startPreview = function(id, prvtime, first_open=true) { - _this.endPreview(); + startPreview(id, prvtime, switchedTo){ + this.endPreview() var startLoad = +new Date - var current_id = _preview_id - if(first_open){ + var currentId = this.previewId + if(!switchedTo){ snd.musicGain.fadeOut(0.4) } - var songObj - assets.songs.forEach(song => { - if(song.id == id){ - songObj = song - } - }) + var songObj = assets.songs.find(song => song.id == id) if(songObj.sound){ - _preview = songObj.sound - _preview.gain = snd.previewGain - this.previewLoaded(startLoad, prvtime, first_open) + this.preview = songObj.sound + this.preview.gain = snd.previewGain + this.previewLoaded(startLoad, prvtime, switchedTo) }else{ snd.previewGain.load("/songs/" + id + "/main.mp3").then(sound => { - if(current_id == _preview_id){ + if(currentId == this.previewId){ songObj.sound = sound - _preview = sound - this.previewLoaded(startLoad, prvtime, first_open) + this.preview = sound + this.previewLoaded(startLoad, prvtime, switchedTo) } }) } - }; - - this.previewLoaded = function(startLoad, prvtime, first_open){ + } + previewLoaded(startLoad, prvtime, switchedTo){ var endLoad = +new Date var difference = endLoad - startLoad - var minDelay = first_open ? 1000 : 300 + var minDelay = switchedTo ? 300 : 1000 var delay = minDelay - Math.min(minDelay, difference) - _preview.playLoop(delay / 1000, false, prvtime / 1000) + this.preview.playLoop(delay / 1000, false, prvtime / 1000) } - - this.endPreview = function() { - _preview_id++ - if (_preview) { - _preview.stop(); - }; - }; - - this.run = function(){ - _this.createCode(); - _this.startP2(); + endPreview() { + this.previewId++ + if(this.preview){ + this.preview.stop() + } + } + run(){ + this.createCode() + this.startP2() - $("#song-container").show(); + this.songselHelp = document.getElementById("songsel-help") + pageEvents.once(this.songselHelp, "click").then(() => { + this.clean() + assets.sounds["don"].play() + new Tutorial() + }) + this.diffElements = document.getElementsByClassName("difficulty") + for(let difficulty of this.diffElements){ + pageEvents.once(difficulty, "click").then(this.onDifficulty.bind(this)) + } + this.songElements = document.getElementsByClassName("song") + for(let song of this.songElements){ + pageEvents.add(song, "click", this.onSong.bind(this)) + } + this.songSelect = document.getElementById("song-select") + } + onDifficulty(event){ + this.clean() + var target = event.currentTarget + var song = target.parentNode.parentNode + assets.sounds["don"].play() - $('#songsel-help').click(function(){ - assets.sounds["bgm_songsel"].stop() + this.selectedSong.difficulty = target.classList[1] + ".osu" + this.selectedSong.title = song.dataset.title + this.selectedSong.folder = song.dataset.songId + + new loadSong(this.selectedSong, event.shiftKey, event.ctrlKey) + } + onSong(event){ + var target = event.currentTarget + var opened = document.getElementsByClassName("opened")[0] + if(!opened){ + this.startPreview(target.dataset.songId, target.dataset.preview) + assets.sounds["don"].play() assets.sounds["song-select"].stop() + assets.sounds["diffsel"].play(0.3) + target.classList.add("opened") + this.songSelect.classList.add("difficulty-select") + }else if(opened == target){ + this.endPreview() + snd.musicGain.fadeIn(0.4) assets.sounds["diffsel"].stop() - assets.sounds["don"].play() - snd.musicGain.fadeIn() - _this.endPreview(); - - new Tutorial(); - }); - - $(".difficulty").click(function(e){ - _this.endPreview(); - assets.sounds["bgm_songsel"].stop() - assets.sounds["diffsel"].stop() - assets.sounds["don"].play() - - var difficultyElement = (e.target.className=="stars" || e.target.className=="diffname") ? e.target.parentElement : e.target; - _selectedSong.difficulty = difficultyElement.classList[1]+'.osu'; - var parentID = $(this).parent().closest(".song").attr("id"); - var songID = parseInt(parentID.substr(5, parentID.length-1)); - _selectedSong.title = $(this).parent().closest('.song').data('title'); - _selectedSong.folder = songID; - - snd.musicGain.fadeIn() - new loadSong(_selectedSong, e.shiftKey, e.ctrlKey); - }); - - $(".song").hover(function(){ - if(!$(this).hasClass("opened")) - $(this).css("background", "rgba(255, 233, 125, 0.90)"); - }, - function(){ - if(!$(this).hasClass("opened")) - $(this).css("background", "rgba(255, 220, 47, 0.90)"); - }); - - $(".song").click(function(e){ - if (!$(e.target).parents('.difficulties').length) { - if ($(".opened").length && $(".opened").attr('id') == $(this).attr('id')) { - _this.endPreview(); - snd.musicGain.fadeIn(0.4) - assets.sounds["diffsel"].stop() - assets.sounds["cancel"].play() - assets.sounds["song-select"].play(0.3) - - $(".difficulty").hide(); - $(".opened").removeClass("opened", 300); - - $('.songsel-title').fadeOut(200, function(){ - $('.songsel-title').attr('alt', '曲をえらぶ').html('曲をえらぶ').css('left', -300); - $('.songsel-title').animate({left:0, opacity:"show"}, 400); - }); - - return; - } - - if(!$('.opened').length) { - _this.startPreview($(this).data('song-id'), $(this).data('preview')); - assets.sounds["don"].play() - assets.sounds["song-select"].stop() - assets.sounds["diffsel"].play(0.3) - - $('.songsel-title').fadeOut(200, function(){ - $('.songsel-title').attr('alt', 'むずかしさをえらぶ').html('むずかしさをえらぶ').css('left', -300); - $('.songsel-title').animate({left:0, opacity:"show"}, 400); - }); - } else { - _this.startPreview($(this).data('song-id'), $(this).data('preview'), false); - assets.sounds["ka"].play(); - } - }; - - $(".difficulty").hide(); - $(".opened").removeClass("opened", 300); - $(this).addClass("opened", 300, "linear", function(){ - $(this).find(".difficulty").show(); - $(this).css("background", "rgba(255, 220, 47, 0.90)"); - }); - }); - + assets.sounds["cancel"].play() + assets.sounds["song-select"].play(0.3) + opened.classList.remove("opened") + this.songSelect.classList.remove("difficulty-select") + }else{ + this.startPreview(target.dataset.songId, target.dataset.preview, true) + assets.sounds["ka"].play() + opened.classList.remove("opened") + target.classList.add("opened") + } } - - this.createCode = function(){ + createCode(){ assets.sounds["bgm_songsel"].playLoop(0.1, false, 0, 1.442, 3.506) - assets.sounds["song-select"].play(0.2); - + assets.sounds["song-select"].play(0.2) var songElements = [0] - for(var i=0; iLoading...
+