Skip to content

Commit

Permalink
a lot
Browse files Browse the repository at this point in the history
  • Loading branch information
Lyall-A committed Jun 24, 2024
1 parent d971ea3 commit a857ab5
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 69 deletions.
152 changes: 92 additions & 60 deletions Game.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
class Game {
constructor(gameContainer, map, level, userSettings, gameSettings = {
globalSpeed: 1,
logFps: false,
logDeltaTime: false,
dontCheckIfNotesOffScreen: true,
points: [
{ distance: 25, points: 350 },
{ distance: 50, points: 300 },
{ distance: 100, points: 200 },
{ distance: 150, points: 100 },
{ distance: 175, points: 50 },
{ distance: 200, points: 0, isBad: true },
{ distance: 200, points: 0, isBadHit: true },
]
}) {
this.gameContainer = gameContainer;
Expand All @@ -16,7 +19,12 @@ class Game {
this.userSettings = userSettings;
this.gameSettings = gameSettings;

this.msToKey = 700; // TODO: add ms to key to spawn keys early
this.notesReady = null;
this.startTime = null;
this.running = false;
this.msToKey = 500; // TODO: add ms to key to spawn keys early
this.notesToSpawn = this.level.data;
this.runningTime = 0;
this.lanes = [];

this.points = 0;
Expand All @@ -29,80 +37,90 @@ class Game {
}

async start() {
// Pause game when document is hidden (TODO)

// Game loop
this.gameLoop((deltaTime, loop, fps) => {
this.gameLoop(async (deltaTime, loop, fps) => {
this.runningTime += deltaTime;

if (!this.running) {
// First run
document.onvisibilitychange = () => {
if (document.hidden) this.stop();
}

setTimeout(() => this.notesReady = true, this.map.offset);
// TODO: make neater
if (this.map.backgroundData) {
const backgroundURL = URL.createObjectURL(this.map.backgroundData);
this.backgroundElement.style.backgroundImage = `url("${backgroundURL}")`;
}
const audioURL = URL.createObjectURL(this.map.audioData);
this.audio = new Audio(audioURL);
this.audio.onloadeddata = () => URL.revokeObjectURL(audioURL);
this.audio.onended = () => this.stop();
this.audio.volume = 0.25; // kill oyurself
// this.audio.playbackRate = this.gameSettings.globalSpeed;
await this.audio.play().catch(err => console.log("For some reason the Audio API errors sometimes but does actually work, I write good code.", err));
this.startTime = Date.now();
this.running = true;
}

// Spawn notes
if (this.notesReady) {
for (const i in { ...this.notesToSpawn }) { // the fuck?
const noteToSpawn = this.notesToSpawn[0];
if (this.beatToMs(noteToSpawn[2]) + this.map.offset >= this.runningTime + this.msToKey) break; // TODO: is this right?
this.spawnNote(noteToSpawn[0], noteToSpawn[1]);
this.notesToSpawn.shift();
}
}

// Move notes down/despawn when off screen
this.lanes.forEach((lane, laneIndex) => {
lane.notes.forEach(note => {
note.top += 1 * deltaTime * this.gameSettings.globalSpeed * ((this.userSettings.scrollSpeed || this.level.scrollSpeed) / 10);
note.noteElement.style.top = `${note.top}px`;
if (note.noteElement.getBoundingClientRect().y >= screen.availHeight) {
if (!this.gameSettings.dontCheckIfNotesOffScreen && note.noteElement.getBoundingClientRect().y >= document.body.offsetHeight) {
if (!lane.notesElement.contains(note.noteElement)) return;
this.removeClosestNote(laneIndex);
this.removeNote(laneIndex, note);
}
});
});

if (this.gameSettings.logFps) console.log(`FPS: ${fps}`);
if (this.gameSettings.logDeltaTime) console.log(`Delta Time: ${deltaTime}`);

loop();
});

// THIS IS JUST TEMP SHIT FRRRRRR IMA MAKE THIS BETTER (PROBABLY NOT)
if (this.map.backgroundData) {
const backgroundURL = URL.createObjectURL(this.map.backgroundData);
this.gameContainer.style.backgroundImage = `url("${backgroundURL}")`;
}
const audioURL = URL.createObjectURL(this.map.audioData);
const audio = new Audio(audioURL);
audio.onloadeddata = () => URL.revokeObjectURL(audioURL);
audio.volume = 0.25; // kill oyurself
audio.playbackRate = this.gameSettings.globalSpeed;
await audio.play();

setTimeout(() => {
let lastBeat = 0;
const getNextNote = index => {
const nextNote = this.level.data[index];
if (!nextNote) return;
const lane = nextNote[0];
const sliderHeight = nextNote[1];
const beat = nextNote[2];

setTimeout(() => {
lastBeat = beat;
this.spawnNote(lane, sliderHeight);
}, (((beat - lastBeat) / this.map.bpm) * 60 * 1000) - this.msToKey);

getNextNote(index + 1);
}
getNextNote(0);
}, this.map.offset);
}

// ----

msToBeat(ms, bpm = this.map.bpm) {
return ms / (60 * 1000 / bpm);
return parseFloat(ms.toFixed(10)) / (60 * 1000 / bpm);
}

beatToMs(beat, bpm = this.map.bpm) {
return (beat / bpm) * 60 * 1000;
return parseFloat(((beat / bpm) * 60 * 1000).toFixed(10));
}

spawnNote(laneNum, sliderHeight = 0) {
const laneIndex = laneNum - 1;
const lane = this.lanes[laneIndex];
let top = 0;
const noteElement = document.createElement("div");
noteElement.classList.add("note");
noteElement.style.top = `${top}px`;
this.lanes[laneIndex].notes.push({ top, noteElement, slider: sliderHeight ? true : false });
this.lanes[laneIndex].notesElement.appendChild(noteElement);
lane.notesSpawned++;
lane.notes.push({ top, noteElement, id: lane.notesSpawned, slider: sliderHeight ? true : false });
lane.notesElement.appendChild(noteElement);
// TODO: slider height is in beats, gota calcualte somehow
noteElement.style.height = sliderHeight ? `calc(${noteElement.offsetHeight}px * (1 + ${sliderHeight}))` : "auto";
}

removeClosestNote(laneIndex) {
if (!this.lanes[laneIndex].notes.length) return;
this.lanes[laneIndex].notes[0].noteElement.remove();
this.lanes[laneIndex].notes.splice(0, 1);
removeNote(laneIndex, note) {
const lane = this.lanes[laneIndex];
lane.notes.splice(lane.notes.findIndex(i => i.id == note.id), 1);
note.noteElement.remove();
}

onKeyPress(laneIndex) {
Expand All @@ -116,28 +134,40 @@ class Game {
}

stop() {

this.running = false;
this.audio.pause();
this.audio.remove();
this.gameContainer.style = "";
this.gameContainer.innerHTML = "";
this.onstop();
}

hitNote(laneIndex) {
const closestNote = this.lanes[laneIndex].notes[0].noteElement;
const closestNoteY = closestNote.offsetTop;
const keyY = this.lanes[laneIndex].keyElement.offsetTop + this.lanes[laneIndex].keyElement.offsetHeight;
// const closestNote = this.lanes[laneIndex].notes[0].noteElement;
const lane = this.lanes[laneIndex];
const keyY = lane.keyElement.offsetTop + lane.keyElement.offsetHeight;
const closestNote = lane.notes.reduce((prev, curr) => {
const currDistance = Math.max(curr.top - keyY, keyY - curr.top);
const prevDistance = Math.max(prev.top - keyY, keyY - prev.top);
return currDistance < prevDistance ? curr : prev;
});

const distance = Math.max(closestNoteY - keyY, keyY - closestNoteY);
const distance = Math.max(closestNote.top - keyY, keyY - closestNote.top);

if (distance > this.gameSettings.points[this.gameSettings.points.length - 1].distance) return;

// TODO: add points
this.removeClosestNote(laneIndex);
this.removeNote(laneIndex, closestNote);
}

init() {
// Create game
this.gameContainer.innerHTML = "";
this.gameElement = document.createElement("div");
this.gameElement.classList.add("game");
this.gameContainer.appendChild(this.gameElement);

// Create background
this.backgroundElement = document.createElement("background");
this.backgroundElement.classList.add("background");

// Create lanes
const lanesElement = document.createElement("div");
Expand All @@ -157,9 +187,13 @@ class Game {
keyElement.classList.add("key");
laneElement.appendChild(keyElement);

this.lanes.push({ laneElement, notesElement, keyElement, keyPressed: false, notes: [] });
this.lanes.push({ laneElement, notesElement, notesSpawned: 0, keyElement, keyPressed: false, notes: [] });
}

// Append to game container
this.gameContainer.appendChild(this.gameElement);
this.gameContainer.appendChild(this.backgroundElement);

// Create events
// Key pressed
document.body.onkeydown = ev => {
Expand All @@ -179,11 +213,6 @@ class Game {
}
}

destroy() {
this.gameContainer.innerHTML = "";
// TODO: remove events etc
}

gameLoop(callback) {
let prevTime;
let fps = 0;
Expand All @@ -199,4 +228,7 @@ class Game {

requestAnimationFrame(loop);
}

// Game events
onstop() { }
}
23 changes: 17 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
<script src="./Game.js"></script>
</head>
<body>
<button id="temp" style="width: 100%; height: 100%; font-size: 5em;" onclick="doThing(this)">CLICK ME</button>
<div id="game-container"></div>
<button style="width: 100%; height: 100%;" onclick="doThing(this)">CLICK ME</button>
<script>
async function doThing(e) {
e.remove();
try {
const userSettings = {
scrollSpeed: 17,
keybinds: {
Expand All @@ -25,16 +25,27 @@
loadSkin("/skins/default");
// for testing
// const mapPath = "./maps/Quaver - JUST LIKE WE NEVER SAID GOODBYE";
// const mapPath = "./maps/Quaver - ";
const mapPath = "./maps/Quaver - Kyu-kurarin (7_7 bootleg)";
const levelIndex = 0;
const mapPath = "./maps/Quaver - Bad Apple!!";
// const mapPath = "./maps/Quaver - Kyu-kurarin (7_7 bootleg)";
// const mapPath = "./maps/test";
// const mapPath = "./maps/Quaver - Animosity";
// const mapPath = "./maps/Quaver - Invisible Frenzy";
// const mapPath = "./maps/Quaver - Feral";
const levelIndex = 2;
const map = await getMap(mapPath);
const level = await getLevel(mapPath, map.levels[levelIndex]);


document.title += ` | ${map.name}`
game = new Game(document.getElementById("game-container"), map, level, userSettings);
game.init();
game.start();
game.onstop = () => location.reload();
if (e) e.remove();
} catch (err) {
if (e) e.innerHTML = err;
}
}
try { doThing(document.getElementById("temp")) } catch (err) { }
</script>
</body>
</html>
Binary file added maps/test/audio.mp3
Binary file not shown.
22 changes: 22 additions & 0 deletions maps/test/map.gmm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"audioFile": "audio.mp3",
"coverFile": null,
"backgroundFile": null,
"name": "test",
"artist": "test",
"mappers": [
{
"name": "test"
}
],
"offset": 0,
"bpm": 100,
"levels": [
{
"scrollSpeed": 17,
"name": "test",
"keys": 4,
"file": "test.gml"
}
]
}
31 changes: 31 additions & 0 deletions maps/test/test.gml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[
[1,0,1],
[2,0,1],
[3,0,1],
[4,0,1],

[1,0,2],
[2,0,2],
[3,0,2],
[4,0,2],

[1,0,3],
[2,0,3],
[3,0,3],
[4,0,3],

[1,0,4],
[2,0,4],
[3,0,4],
[4,0,4],

[1,0,5],
[2,0,5],
[3,0,5],
[4,0,5],

[1,0,6],
[2,0,6],
[3,0,6],
[4,0,6]
]
13 changes: 10 additions & 3 deletions skins/default/skin.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@
align-items: center;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}

.game {
display: flex;
height: 100%;
}

.background {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}

.lanes {
display: flex;
background-color: rgba(0, 0, 0, 0.7);
Expand Down

0 comments on commit a857ab5

Please sign in to comment.