add all code
commit
516f756124
|
@ -0,0 +1,3 @@
|
|||
# /charts/*
|
||||
# !/charts/test
|
||||
.DS_Store
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
import { GameScreen } from "./screenGame.js";
|
||||
|
||||
/**
|
||||
* Chart Manager
|
||||
* Loads charts from server
|
||||
*/
|
||||
class ChartManager {
|
||||
constructor() {
|
||||
this.cache = new Map();
|
||||
this.covers = new Map();
|
||||
}
|
||||
|
||||
async get(id) {
|
||||
if(!this.cache.has(id)) {
|
||||
await fetch("./charts/" + id + "/chart.json")
|
||||
.then(res => res.json())
|
||||
.then(json => this.cache.set(id, json))
|
||||
|
||||
this.covers.set(id, loadImage("./charts/" + id + "/cover.jpg"));
|
||||
}
|
||||
return this.cache.get(id)
|
||||
}
|
||||
|
||||
async loadChart(selectedChart) {
|
||||
console.log("loading", selectedChart)
|
||||
let ch = await this.get(selectedChart)
|
||||
return new GameScreen(ch);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ChartManager();
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
|
@ -0,0 +1,779 @@
|
|||
{
|
||||
"id": "golddust",
|
||||
"file": "golddust.mp3",
|
||||
"name": "Gold Dust",
|
||||
"artist": "DJ Fresh",
|
||||
"bpm": 177,
|
||||
"difficulty": "Medium",
|
||||
"len": "1:32",
|
||||
"notes": [
|
||||
{
|
||||
"beat": 5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 6.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 8,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 9.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 11,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 12.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 13,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 14.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 16,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 17.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 19,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 20.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 21,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 22.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 24,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 25.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 27,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 28.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 29,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 30.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 32,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 33.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 35,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 36.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 37,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 38.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 40,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 41.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 43,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 44.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 45,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 46.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 48,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 49.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 51,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 52.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 53,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 54.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 56,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 57.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 59,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 60.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 61,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 62.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 64,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 65.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 67,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 68.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 69,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 70.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 72,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 73.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 75,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 76.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 77,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 78.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 80,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 81.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 83,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 84.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 85,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 86.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 88,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 89.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 91,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 92.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 93,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 94.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 96,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 97.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 99,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 100.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 101,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 102.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 104,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 105.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 107,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 108.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 109,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 110.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 112,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 113.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 115,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 116.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 117,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 118.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 120,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 121.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 123,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 124.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 125,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 126.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 128,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 129.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 131,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 132.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 133,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 134.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 136,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 137.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 139,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 140.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 141,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 142.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 144,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 145.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 147,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 148.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 149,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 150.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 152,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 153.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 155,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 156.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 157,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 158.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 160,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 161.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 163,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 164.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 165,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 166.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 168,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 169.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 171,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 172.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 173,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 174.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 176,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 177.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 179,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 180.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 181,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 182.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 184,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 185.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 187,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 188.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 189,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 190.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 192,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 193.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 195,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 196.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 197,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 198.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 200,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 201.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 203,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 204.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 205,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 206.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 208,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 209.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 211,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 212.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 213,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 214.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 216,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 217.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 219,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 220.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 221,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 222.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 224,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 225.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 227,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 228.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 229,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 230.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 232,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 233.5,
|
||||
"lane": 0
|
||||
},
|
||||
{
|
||||
"beat": 235,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 236.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 237,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 238.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 240,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 241.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 243,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 244.5,
|
||||
"lane": 3
|
||||
},
|
||||
{
|
||||
"beat": 245,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 246.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 248,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 249.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 251,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 252.5,
|
||||
"lane": 1
|
||||
},
|
||||
{
|
||||
"beat": 253,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 254.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 256,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 257.5,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 259,
|
||||
"lane": 2
|
||||
},
|
||||
{
|
||||
"beat": 260.5,
|
||||
"lane": 2
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 621 KiB |
Binary file not shown.
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "test",
|
||||
"file": "song.wav",
|
||||
"name": "Test Chart",
|
||||
"artist": "Untitled Band",
|
||||
"len": "0:08",
|
||||
"bpm": 120,
|
||||
"notes": [
|
||||
{ "beat": 2, "lane": 1},
|
||||
|
||||
{ "beat": 4, "lane": 0},
|
||||
{ "beat": 4, "lane": 1},
|
||||
|
||||
{ "beat": 6, "lane": 2},
|
||||
{ "beat": 8, "lane": 3},
|
||||
{ "beat": 8.25, "lane": 3},
|
||||
{ "beat": 8.5, "lane": 3},
|
||||
{ "beat": 8.75, "lane": 3}
|
||||
]
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,16 @@
|
|||
export const KEYS = [
|
||||
68, // D
|
||||
70, // F
|
||||
74, // J
|
||||
75 // K
|
||||
]
|
||||
export const LANE_COLORS = [
|
||||
[28, 237, 102],
|
||||
[245, 201, 27],
|
||||
[66, 110, 255],
|
||||
[255, 94, 180]
|
||||
];
|
||||
export const GRACE_BEAT = 0.175;
|
||||
export let NOTE_SPEED = 80; // this isnt a constant so players can adjust their notespeed
|
||||
|
||||
export const getPixelsPerBeat = () => NOTE_SPEED * 3.5
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Entity
|
||||
* Anything with an X and Y
|
||||
*/
|
||||
export class Entity {
|
||||
x;
|
||||
y;
|
||||
constructor(x = 0, y = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sprite
|
||||
* Anything that can be drawn to the screen
|
||||
*/
|
||||
export class Sprite extends Entity {
|
||||
constructor(x = 0, y = 0) {
|
||||
super(x, y)
|
||||
}
|
||||
|
||||
draw() {
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,114 @@
|
|||
import { Sprite } from './entity.js';
|
||||
import { LANE_COLORS, getPixelsPerBeat } from './config.js';
|
||||
import { KeyHint } from './ui.js';
|
||||
|
||||
class BeatLine extends Sprite {
|
||||
constructor() {
|
||||
super((700 - 300) / 2, 40)
|
||||
}
|
||||
|
||||
draw() {
|
||||
stroke(190)
|
||||
strokeWeight(1)
|
||||
line(this.x, this.y, this.x + 300, this.y)
|
||||
}
|
||||
}
|
||||
|
||||
export class PressIndicator extends Sprite {
|
||||
constructor(lane) {
|
||||
super(((width - 300) / 2) + (75*lane), height - 40 - 24);
|
||||
|
||||
this.heldFor = 0;
|
||||
|
||||
this.laneTransparency = 0
|
||||
this.transparency = 0
|
||||
this.hit = false;
|
||||
}
|
||||
|
||||
draw(held) {
|
||||
// console.log("hf", this.heldFor, held)
|
||||
if(held) {
|
||||
if(this.hit) {
|
||||
blur(color(255,255,255), 16)
|
||||
if(this.heldFor == 0) {
|
||||
this.transparency = 255
|
||||
this.laneTransparency = 100
|
||||
} else {
|
||||
this.transparency = lerp(this.transparency, 50, 0.2)
|
||||
}
|
||||
} else {
|
||||
this.transparency = lerp(this.transparency, 50, 0.6);
|
||||
}
|
||||
} else {
|
||||
this.transparency = lerp(this.transparency, 0, 0.5)
|
||||
}
|
||||
|
||||
fill(255, 255, 255, this.transparency)
|
||||
noStroke()
|
||||
rect(this.x, this.y, 75, 24)
|
||||
|
||||
|
||||
// lane
|
||||
this.laneTransparency = lerp(this.laneTransparency, 0, 0.05)
|
||||
fill(255, 255, 255, this.laneTransparency)
|
||||
noStroke()
|
||||
rect(this.x, 0, 75, height)
|
||||
|
||||
if(this.hit) {
|
||||
blur(0, 0)
|
||||
}
|
||||
|
||||
if(!held && this.heldFor > 0)
|
||||
this.heldFor = 0;
|
||||
|
||||
if(held)
|
||||
this.heldFor += 1;
|
||||
|
||||
if(this.hit && held)
|
||||
this.hit = false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Highway extends Sprite {
|
||||
constructor() {
|
||||
super(0,0)
|
||||
}
|
||||
|
||||
static draw(curBeat) {
|
||||
noStroke()
|
||||
blur(color(20), 16)
|
||||
fill(140)
|
||||
rect((width - 300) / 2, 0, 300, height)
|
||||
blur(0, 0)
|
||||
|
||||
fill(80)
|
||||
rect((width - 300) / 2, height - 28 - 12, 300, 28 + 12)
|
||||
|
||||
// purple bar
|
||||
for(let i = 0; i < LANE_COLORS.length; i++) {
|
||||
let c = color(LANE_COLORS[i][0], LANE_COLORS[i][1], LANE_COLORS[i][2])
|
||||
fill(lerpColor(c, color(0), 0.5))
|
||||
rect((width - 300) / 2 + ((300/4) * i), height - 28 - 24 - 12, (300 / 4), 24)
|
||||
}
|
||||
|
||||
// Lines
|
||||
let PIXELS_PER_BEAT = getPixelsPerBeat();
|
||||
let beatLineX = height - 40
|
||||
while(beatLineX > 0) {
|
||||
stroke(170);
|
||||
strokeWeight(2);
|
||||
line(
|
||||
(width - 300) / 2,
|
||||
beatLineX + (PIXELS_PER_BEAT * (curBeat % 1) - 1),
|
||||
(width - 300) / 2 + 300,
|
||||
beatLineX + (PIXELS_PER_BEAT * (curBeat % 1) - 1)
|
||||
);
|
||||
beatLineX -= PIXELS_PER_BEAT;
|
||||
}
|
||||
|
||||
KeyHint.draw("D", (width/2) + 182 - (300 / 4)*4, height - 14)
|
||||
KeyHint.draw("F", (width/2) + 182 - (300 / 4)*3, height - 14)
|
||||
KeyHint.draw("J", (width/2) + 182 - (300 / 4)*2, height - 14)
|
||||
KeyHint.draw("K", (width/2) + 182 - (300 / 4)*1, height - 14)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
main {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./ext/p5.min.js"></script>
|
||||
<script src="./ext/p5.sound.min.js"></script>
|
||||
|
||||
<!-- module type allows import+export-->
|
||||
<script src="main.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,149 @@
|
|||
import {
|
||||
Entity,
|
||||
Sprite
|
||||
} from './entity.js';
|
||||
import { GameScreen } from './screenGame.js';
|
||||
import { SongSelectScreen } from './screenSongSelect.js';
|
||||
import {
|
||||
KeyHint
|
||||
} from './ui.js'
|
||||
import chartmgr from './chartmgr.js';
|
||||
import state from './state.js';
|
||||
|
||||
const charts = [
|
||||
"bozo",
|
||||
"dashstar",
|
||||
"golddust",
|
||||
"pixelpalace"
|
||||
// "test"
|
||||
]
|
||||
|
||||
// STUFF
|
||||
let songSelectScreen;
|
||||
|
||||
// ASSETS
|
||||
let sndBoop;
|
||||
let sndCombobreak;
|
||||
let sndSongselect;
|
||||
let fntRenogare;
|
||||
|
||||
function blur(col, blurFactor) {
|
||||
drawingContext.shadowColor = col;
|
||||
drawingContext.shadowBlur = blurFactor;
|
||||
}
|
||||
|
||||
function debugMsg(msg) {
|
||||
fill(255);
|
||||
stroke(0);
|
||||
textSize(12);
|
||||
text(msg, 24, 24);
|
||||
}
|
||||
|
||||
function drawFps() {
|
||||
let fps = frameRate();
|
||||
fill(255);
|
||||
stroke(0);
|
||||
textSize(12);
|
||||
text("FPS: " + fps.toFixed(2), 10, height - 10);
|
||||
}
|
||||
|
||||
async function preload() {
|
||||
console.log("preloading..")
|
||||
|
||||
// load sounds
|
||||
soundFormats('mp3')
|
||||
sndCombobreak = loadSound('./assets/sfx/combobreak');
|
||||
sndCombobreak.volume = 0.6
|
||||
|
||||
sndBoop = loadSound('./assets/sfx/boop')
|
||||
sndBoop.volume = 0.6
|
||||
|
||||
sndSongselect = loadSound('./assets/sfx/songselect')
|
||||
sndSongselect.volume = 0.4
|
||||
|
||||
// load fonts
|
||||
fntRenogare = loadFont("./assets/fonts/Renogare-Regular.otf");
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
console.log("setting up..")
|
||||
// frameRate(144)
|
||||
frameRate(60)
|
||||
createCanvas(1280, 720)
|
||||
|
||||
for await (let chartid of charts) {
|
||||
try {
|
||||
await chartmgr.get(chartid)
|
||||
} catch(e) {
|
||||
console.log(`error loading chart ${chartid}`, e)
|
||||
}
|
||||
}
|
||||
|
||||
songSelectScreen = new SongSelectScreen();
|
||||
// gameScreen = await chartmgr.loadChart('test')
|
||||
}
|
||||
|
||||
function draw() {
|
||||
textFont(fntRenogare);
|
||||
background(10)
|
||||
|
||||
switch(state.state) {
|
||||
case "game":
|
||||
if(!window.gameScreen) {
|
||||
debugMsg("err: gamescreen not initialized!")
|
||||
break;
|
||||
}
|
||||
|
||||
if(!window.gameScreen.song.isLoaded()) {
|
||||
fill(255);
|
||||
stroke(0);
|
||||
textSize(12);
|
||||
text("Loading song..", (width - textWidth("Loading song..")) / 2, height /2);
|
||||
|
||||
fill(40, 40, 255)
|
||||
rect(0,0,window.gameScreen.loadPercent * width, 12)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
window.gameScreen.calcBeat();
|
||||
window.gameScreen.draw();
|
||||
break;
|
||||
|
||||
case "songselect":
|
||||
if(!songSelectScreen) {
|
||||
debugMsg(`loading charts (${chartmgr.cache.size}/${charts.length})`)
|
||||
break;
|
||||
}
|
||||
songSelectScreen.draw()
|
||||
break;
|
||||
}
|
||||
|
||||
drawFps();
|
||||
}
|
||||
|
||||
function keyPressed() {
|
||||
switch(state.state) {
|
||||
case "game":
|
||||
window.gameScreen.checkHit();
|
||||
break;
|
||||
|
||||
case "songselect":
|
||||
songSelectScreen.keyPressed()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make p5 work in a js module environment because variables
|
||||
// arent exposed to window by default in module
|
||||
window.preload = preload;
|
||||
window.setup = setup;
|
||||
window.draw = draw;
|
||||
window.keyPressed = keyPressed;
|
||||
|
||||
export {
|
||||
sndCombobreak,
|
||||
sndBoop,
|
||||
sndSongselect,
|
||||
fntRenogare
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import { Sprite } from './entity.js';
|
||||
import { GRACE_BEAT, LANE_COLORS, getPixelsPerBeat } from './config.js';
|
||||
import { sndCombobreak } from './main.js';
|
||||
|
||||
let PIXELS_PER_BEAT = getPixelsPerBeat();
|
||||
|
||||
export class Note extends Sprite {
|
||||
constructor(lane, beat) {
|
||||
super((width - 300)/ 2 + (lane * 75) + 4, 0)
|
||||
this.lane = lane;
|
||||
this.beat = beat;
|
||||
this.symbol = Symbol();
|
||||
|
||||
this.pressed = false;
|
||||
}
|
||||
|
||||
draw(curBeat) {
|
||||
strokeWeight(2);
|
||||
stroke(6);
|
||||
fill(LANE_COLORS[this.lane])
|
||||
rect(this.x, this.y, 68, 16) // 20
|
||||
|
||||
let initialPos = ((height - 40) - 20 / 2)
|
||||
this.y = initialPos - (PIXELS_PER_BEAT * (this.beat - curBeat))
|
||||
|
||||
if(this.beat + GRACE_BEAT < curBeat) {
|
||||
// remove note from array
|
||||
this.remove();
|
||||
if(!this.pressed) {
|
||||
// sndIncorrect.play();
|
||||
if(window.gameScreen.score.combo > 4) {
|
||||
sndCombobreak.play();
|
||||
}
|
||||
window.gameScreen.score.combo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove() {
|
||||
window.gameScreen.notes.splice(window.gameScreen.notes.findIndex(n => n.symbol == this.symbol), 1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
export class ScoreManager {
|
||||
constructor() {
|
||||
this.score = 0;
|
||||
this.combo = 0
|
||||
}
|
||||
|
||||
addScore(toAdd) {
|
||||
this.score += toAdd
|
||||
}
|
||||
|
||||
onHit() {
|
||||
this.combo += 1;
|
||||
this.score += 200 * Math.min(1, (Math.min(this.combo, 16) /4))
|
||||
}
|
||||
|
||||
resetCombo() {
|
||||
this.combo = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
import {
|
||||
ScoreUi,
|
||||
CurrentSongUi
|
||||
} from './ui.js'
|
||||
|
||||
import { KEYS, GRACE_BEAT } from './config.js'
|
||||
import { PressIndicator, Highway } from './highway.js';
|
||||
import { Note } from './note.js';
|
||||
import { ScoreManager } from './score.js'
|
||||
import chartmgr from './chartmgr.js';
|
||||
|
||||
export class GameScreen {
|
||||
constructor(chart) {
|
||||
this.chart = chart;
|
||||
this.score = new ScoreManager();
|
||||
this.scoreUi = new ScoreUi();
|
||||
this.curBeat = 1;
|
||||
|
||||
this.background = 10;
|
||||
this.started = false;
|
||||
|
||||
this.pressIndicators = [];
|
||||
// populate press indicators
|
||||
KEYS.forEach((_, i) => {
|
||||
this.pressIndicators.push(new PressIndicator(i));
|
||||
})
|
||||
|
||||
// load song
|
||||
this.notes = []
|
||||
if(this.chart) {
|
||||
this.chart.notes.forEach(n => {
|
||||
this.notes.push(new Note(n.lane, n.beat))
|
||||
})
|
||||
}
|
||||
this.song = loadSound("./charts/" + this.chart.id + "/" + this.chart.file, null, null, (percent) => {
|
||||
this.loadPercent = percent
|
||||
console.log(percent)
|
||||
});
|
||||
this.loadPercent = 0;
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.background = lerp(this.background, 50, 0.02)
|
||||
background(this.background)
|
||||
if(this.background > 40 &&
|
||||
!this.started && this.song.isLoaded() && this.chart.id != "test") {
|
||||
this.song.play();
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
Highway.draw(this.curBeat);
|
||||
|
||||
// notes
|
||||
for(let i = 0; i < this.notes.length; i++) {
|
||||
this.notes[i].draw(this.curBeat)
|
||||
}
|
||||
|
||||
// key indicators
|
||||
for(let i = 0; i < this.pressIndicators.length; i++) {
|
||||
let pi = this.pressIndicators[i];
|
||||
pi.draw(keyIsDown(KEYS[i]))
|
||||
};
|
||||
|
||||
// draw score
|
||||
this.scoreUi.draw();
|
||||
|
||||
if(!this.chart) {
|
||||
return debugMsg("no chart data!")
|
||||
} else if (!this.song) {
|
||||
return debugMsg("audio not loaded!")
|
||||
}
|
||||
CurrentSongUi.draw(chartmgr.covers.get(this.chart.id), this.chart.name, this.chart.artist);
|
||||
}
|
||||
|
||||
calcBeat() {
|
||||
if(this.song) {
|
||||
let beatSecs = 60 / this.chart.bpm;
|
||||
this.curBeat = (this.song.currentTime() / beatSecs) + 1
|
||||
}
|
||||
}
|
||||
|
||||
checkHit() {
|
||||
let pressTime = this.song.currentTime();
|
||||
let pressBeat = (pressTime / (60 / this.chart.bpm)) + 1
|
||||
|
||||
// scan for notes
|
||||
if(this.notes.length < 1) return;
|
||||
|
||||
let targetNotes = []
|
||||
targetNotes.push(this.notes[0])
|
||||
while(true) {
|
||||
if(this.notes.length < 2)
|
||||
break;
|
||||
|
||||
if(!this.notes[targetNotes.length])
|
||||
break;
|
||||
|
||||
if(
|
||||
this.notes[targetNotes.length].beat == targetNotes[targetNotes.length - 1].beat
|
||||
&& this.notes[targetNotes.length].beat == targetNotes[targetNotes.length - 1].beat) {
|
||||
targetNotes.push(this.notes[targetNotes.length])
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(let i = 0; i < targetNotes.length; i++) {
|
||||
let k = targetNotes[i];
|
||||
if(targetNotes[0].beat + GRACE_BEAT > pressBeat
|
||||
&& targetNotes[0].beat - GRACE_BEAT < pressBeat
|
||||
&& keyIsDown(KEYS[k.lane])){
|
||||
// console.log("HIT", k.lane)
|
||||
|
||||
// hit note!
|
||||
this.notes.find(n=> n.symbol == k.symbol).pressed = true;
|
||||
this.notes.find(n=> n.symbol == k.symbol).remove();
|
||||
this.pressIndicators[k.lane].hit = true;
|
||||
|
||||
this.score.onHit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
class ResultsScreen {
|
||||
constructor(chart, score) {
|
||||
this.chart = chart
|
||||
this.score = score
|
||||
}
|
||||
|
||||
draw() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
import state from './state.js';
|
||||
import chartmgr from './chartmgr.js';
|
||||
import { KeyHint } from './ui.js'
|
||||
import { sndBoop, sndSongselect } from './main.js';
|
||||
|
||||
export class SongSelectScreen {
|
||||
constructor() {
|
||||
this.covers = [...chartmgr.covers.entries()].map(c => c[1])
|
||||
this.songs = [...chartmgr.cache.entries()].map(c => c[1])
|
||||
this.curSelection = 0;
|
||||
}
|
||||
|
||||
draw() {
|
||||
KeyHint.draw(">", width - 48 - 4, (height / 2) + 100)
|
||||
KeyHint.draw("<", 48 - 8, (height / 2) + 100)
|
||||
KeyHint.draw("Enter", (width/2) - 24, height - 40)
|
||||
|
||||
textSize(36);
|
||||
fill(255);
|
||||
text("Select a song", 16, 48);
|
||||
|
||||
fill(215);
|
||||
stroke(0);
|
||||
|
||||
// current song
|
||||
image(this.covers[this.curSelection], (width-256)/2, (height-256)/2, 256, 256)
|
||||
|
||||
textSize(48);
|
||||
text(this.songs[this.curSelection].name,
|
||||
(width / 2) - (textWidth(this.songs[this.curSelection].name) / 2),
|
||||
height - 128 - 36);
|
||||
|
||||
textSize(24);
|
||||
text(this.songs[this.curSelection].artist,
|
||||
(width / 2) - (textWidth(this.songs[this.curSelection].artist) / 2),
|
||||
height - 128);
|
||||
|
||||
let etcmeta = this.songs[this.curSelection].difficulty + " - " + this.songs[this.curSelection].len
|
||||
|
||||
textSize(18);
|
||||
text(etcmeta,
|
||||
(width - textWidth(etcmeta) ) / 2,
|
||||
height - 128 + 32);
|
||||
|
||||
let nextSelection = (this.curSelection + 1 > this.songs.length - 1)
|
||||
? 0
|
||||
: this.curSelection + 1
|
||||
|
||||
let prevSelection = (this.curSelection - 1 < 0)
|
||||
? this.songs.length - 1
|
||||
: this.curSelection - 1
|
||||
|
||||
image(this.covers[prevSelection],
|
||||
32, (height - 128) / 2, 128, 128);
|
||||
|
||||
image(this.covers[nextSelection],
|
||||
(width - 128) - 32, (height - 128) / 2, 128, 128);
|
||||
}
|
||||
|
||||
async keyPressed() {
|
||||
switch(keyCode) {
|
||||
case 37:
|
||||
if(this.curSelection - 1 < 0) {
|
||||
this.curSelection = this.songs.length - 1
|
||||
} else {
|
||||
this.curSelection -= 1
|
||||
}
|
||||
sndBoop.play()
|
||||
break;
|
||||
|
||||
case 39: //right
|
||||
if(this.curSelection + 1 > this.songs.length - 1) {
|
||||
this.curSelection = 0
|
||||
} else {
|
||||
this.curSelection += 1
|
||||
}
|
||||
sndBoop.play()
|
||||
break;
|
||||
|
||||
case 13: //enter
|
||||
sndSongselect.play();
|
||||
window.gameScreen = await chartmgr.loadChart(this.songs[this.curSelection].id)
|
||||
state.setState("game");
|
||||
redraw()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
class State {
|
||||
constructor() {
|
||||
this.state = "songselect"
|
||||
}
|
||||
|
||||
setState(newState) {
|
||||
this.state = newState;
|
||||
}
|
||||
}
|
||||
|
||||
export default new State();
|
|
@ -0,0 +1,59 @@
|
|||
import { Sprite } from './entity.js';
|
||||
|
||||
class ScoreUiTextValue extends Sprite {
|
||||
constructor(title, x, y) {
|
||||
super(x, y)
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
setTitle(newTitle) {
|
||||
this.title = newTitle;
|
||||
}
|
||||
|
||||
draw(val) {
|
||||
fill(255);
|
||||
|
||||
textSize(18);
|
||||
text(this.title, this.x, this.y - 48)
|
||||
|
||||
textSize(48);
|
||||
text(val, this.x, this.y)
|
||||
}
|
||||
}
|
||||
|
||||
export class ScoreUi extends Sprite {
|
||||
constructor() {
|
||||
super((width / 2) + 175, height - 40);
|
||||
this.score = new ScoreUiTextValue("SCORE", this.x, this.y);
|
||||
this.combo = new ScoreUiTextValue("COMBO", this.x, this.y - 86);
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.combo.draw(window.gameScreen.score.combo);
|
||||
this.score.draw(window.gameScreen.score.score);
|
||||
}
|
||||
}
|
||||
|
||||
export class CurrentSongUi extends Sprite {
|
||||
static draw(img, name, artist) {
|
||||
fill(255);
|
||||
|
||||
textSize(18);
|
||||
text(artist, (width / 2) + 175 + 40, 40 + 24)
|
||||
|
||||
textSize(24);
|
||||
text(name, (width / 2) + 175 + 40, 40)
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyHint extends Sprite {
|
||||
static draw(innerText, x, y) {
|
||||
stroke(255)
|
||||
noFill()
|
||||
textSize(16)
|
||||
rect(x - 8, y - 20, textWidth(innerText) + 16, 28)
|
||||
fill(255)
|
||||
noStroke()
|
||||
text(innerText, x, y)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue