made a leaderboard module

This commit is contained in:
Mak
2026-05-10 11:47:48 +09:00
parent 03aebbe5a4
commit 658dd91b82
2 changed files with 58 additions and 66 deletions

View File

@@ -7,14 +7,11 @@ import p5 from "p5";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { clone as cloneSkeleton } from "three/examples/jsm/utils/SkeletonUtils.js"; import { clone as cloneSkeleton } from "three/examples/jsm/utils/SkeletonUtils.js";
import { loadLeaderboard, saveScore, playerName, leaderboard , hasSubmitted } from './leaderboard.js';
let showLanding = true; let showLanding = true;
let lastTime = performance.now(); let lastTime = performance.now();
// --- LEADERBOARD STATE ---
let leaderboard = [];
let playerName = "";
let hasSubmitted = false;
async function handleStart() { async function handleStart() {
showLanding = false; showLanding = false;
// Wait for Svelte to render the #wrapper and canvas // Wait for Svelte to render the #wrapper and canvas
@@ -37,41 +34,6 @@ async function handleStart() {
loop(); loop();
} }
// --- LEADERBOARD LOGIC ---
function saveScore() {
if (hasSubmitted) return;
const name = playerName.trim() || "Anonymous";
let currentBoard = JSON.parse(localStorage.getItem("neuro_leaderboard") || "[]");
// Check if this player already has a record (case-insensitive)
const existingIndex = currentBoard.findIndex(
entry => entry.name.toLowerCase() === name.toLowerCase()
);
if (existingIndex !== -1) {
// Only update if the new score is actually higher
if (score > currentBoard[existingIndex].score) {
currentBoard[existingIndex].score = score;
}
} else {
// New player, just add them
currentBoard.push({ name: name, score: score });
}
// Sort by highest score first and keep only top 5
currentBoard.sort((a, b) => b.score - a.score);
currentBoard = currentBoard.slice(0, 5);
localStorage.setItem("neuro_leaderboard", JSON.stringify(currentBoard));
leaderboard = currentBoard;
hasSubmitted = true;
playerName = ""; // Reset for next time
}
function loadLeaderboard() {
leaderboard = JSON.parse(localStorage.getItem("neuro_leaderboard") || "[]");
}
const CONFIG = { const CONFIG = {
lane: 2.5, lane: 2.5,
@@ -529,16 +491,6 @@ const l = Math.floor(Math.random() * 5) - 2;
// ADD THIS: Save the type so the collision logic knows it's tall // ADD THIS: Save the type so the collision logic knows it's tall
worldObjects = [...worldObjects, { mesh: pivot, lane: l, isTall: isRare }]; worldObjects = [...worldObjects, { mesh: pivot, lane: l, isTall: isRare }];
// const source = await getCachedGLTF("Simple computer.glb");
// const model = cloneSkeleton(source.scene);
// const pivot = new THREE.Group();
// pivot.position.set(l * CONFIG.lane, 0, -130);
// model.position.set(0, 0.6, 0);
// model.rotation.y = Math.PI;
// model.scale.setScalar(5.5);
// pivot.add(model);
// scene.add(pivot);
// worldObjects = [...worldObjects, { mesh: pivot, lane: l }];
} }
@@ -634,16 +586,6 @@ function update() {
} }
playerAnchor.position.y = playerY; playerAnchor.position.y = playerY;
// worldObjects = worldObjects.map(obj => {
// obj.mesh.position.z += moveStep;
// if (Math.abs(obj.mesh.position.z) < 1.5 && obj.lane === lane && playerY < 1.5) triggerGameOver();
// return obj;
// }).filter(obj => {
// const active = obj.mesh.position.z < 25;
// if (!active) scene.remove(obj.mesh);
// return active;
// });
worldObjects = worldObjects.map(obj => { worldObjects = worldObjects.map(obj => {
obj.mesh.position.z += moveStep; obj.mesh.position.z += moveStep;
@@ -678,7 +620,7 @@ function update() {
function triggerGameOver() { function triggerGameOver() {
isPlaying = false; gameOver = true; isDying = true; hitFlash = true; isPlaying = false; gameOver = true; isDying = true; hitFlash = true;
hasSubmitted = false; // Allow a new submission for this game over hasSubmitted.set(false); // Allow a new submission for this game over
loadLeaderboard(); // Refresh board to show latest rankings loadLeaderboard(); // Refresh board to show latest rankings
swapCharacter("Falling Back Death.glb", true); swapCharacter("Falling Back Death.glb", true);
setTimeout(() => hitFlash = false, 150); setTimeout(() => hitFlash = false, 150);
@@ -743,8 +685,8 @@ onMount(() => {
<div class="leaderboard-view"> <div class="leaderboard-view">
<h3>TOP RUNNERS</h3> <h3>TOP RUNNERS</h3>
<ul> <ul>
{#if leaderboard.length > 0} {#if $leaderboard.length > 0}
{#each leaderboard as entry, i} {#each $leaderboard as entry, i}
<li> <li>
<span>{i + 1}. {entry.name}</span> <span>{i + 1}. {entry.name}</span>
<span>{entry.score}</span> <span>{entry.score}</span>
@@ -769,15 +711,15 @@ onMount(() => {
<p>Final Score: <strong>{score}</strong></p> <p>Final Score: <strong>{score}</strong></p>
<!-- Only show the save input if they haven't submitted yet --> <!-- Only show the save input if they haven't submitted yet -->
{#if !hasSubmitted} {#if !$hasSubmitted}
<div class="leaderboard-entry"> <div class="leaderboard-entry">
<input <input
type="text" type="text"
bind:value={playerName} bind:value={$playerName}
placeholder="ENTER NAME" placeholder="ENTER NAME"
maxlength="10" maxlength="10"
/> />
<button class="save-btn" on:click={saveScore}>SAVE TO BOARD</button> <button class="save-btn" on:click={() => saveScore(score)}>SAVE TO BOARD</button>
</div> </div>
{:else} {:else}
<p class="saved-msg">SCORE SAVED!</p> <p class="saved-msg">SCORE SAVED!</p>

50
src/leaderboard.js Normal file
View File

@@ -0,0 +1,50 @@
// @ts-nocheck
import { writable, get } from "svelte/store";
const STORAGE_KEY = "neuro_leaderboard";
export const leaderboard = writable([]);
export const playerName = writable("");
export const hasSubmitted = writable(false);
// Load leaderboard
export function loadLeaderboard() {
try {
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
leaderboard.set(stored);
} catch {
leaderboard.set([]);
}
}
// Save leaderboard to storage
export function commitLeaderboard() {
const board = get(leaderboard);
localStorage.setItem(STORAGE_KEY, JSON.stringify(board));
}
// Save score
export function saveScore(score) {
if (get(hasSubmitted)) return;
let name = get(playerName).trim() || "Anonymous";
const board = [...get(leaderboard)];
const index = board.findIndex(
entry => entry.name.toLowerCase() === name.toLowerCase()
);
if (index !== -1) {
if (score > board[index].score) {
board[index].score = score;
}
} else {
board.push({ name, score });
}
board.sort((a, b) => b.score - a.score);
leaderboard.set(board);
commitLeaderboard();
hasSubmitted.set(true);
}