diff --git a/src/App.svelte b/src/App.svelte
index 2f668cb..16616c5 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -8,10 +8,13 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { clone as cloneSkeleton } from "three/examples/jsm/utils/SkeletonUtils.js";
let showLanding = true;
-
-// Fix for Clock deprecation warning
let lastTime = performance.now();
+// --- LEADERBOARD STATE ---
+let leaderboard = [];
+let playerName = "";
+let hasSubmitted = false;
+
async function handleStart() {
showLanding = false;
// Wait for Svelte to render the #wrapper and canvas
@@ -34,7 +37,42 @@ async function handleStart() {
loop();
}
-// Change CONFIG to include speed limits
+// --- 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 = {
lane: 2.5,
jump: 0.35,
@@ -42,13 +80,13 @@ const CONFIG = {
playerScale: 1.7,
START_SPEED: 45, // Initial slow speed
MAX_SPEED: 95, // The "chaos" threshold
- ACCELERATION: 1.5 // Speed added per second
+ ACCELERATION: 1 // Speed added per second
};
let currentSpeed = CONFIG.START_SPEED;
let score = 0, isPlaying = false, gameOver = false, startScreen = true;
let attentiveness = 100;
-let lives = 5; // --- NEW: Lives tracker ---
+let lives = 5;
let lane = 0, currX = 0, isJumping = false, jumpV = 0, playerY = 0;
let container, canvas, scene, camera, renderer, p5Container;
let worldObjects = [], animationFrame, p5Instance;
@@ -60,7 +98,7 @@ const SPAWN_INTERVAL = 40; // Physical distance between obstacles
// 2D Game Logic
let gamePhase = "START";
let instructionTimer = 3;
-let targetType = "NEURON";
+let targetType = "STRAWBERRY";
let targets = [];
let playerAnchor, currentModel = null, currentMixer = null, swapToken = 0;
@@ -87,9 +125,9 @@ const sketch = (p) => {
p.loadImage(path, img => resolve(img), () => resolve(null));
});
- textures.NEURON = await loadImg('strawberry.png');
- textures.SUGAR = await loadImg('banana.png');
- textures.GLITCH = await loadImg('blubb.png');
+ textures.STRAWBERRY = await loadImg('strawberry.png');
+ textures.BANANA = await loadImg('banana.png');
+ textures.BLUEBERRY = await loadImg('blubb.png');
};
// --- NEW: Function to draw a pixelated heart ---
@@ -122,7 +160,7 @@ const sketch = (p) => {
// The Mission Text
p.textSize(28);
- p.text(`NEURO-MISSION: COLLECT`, p.width / 2, p.height / 2 - 100);
+ p.text(`MISSION: COLLECT`, p.width / 2, p.height / 2 - 100);
// Draw the target icon to collect
const targetImg = textures[targetType];
@@ -148,7 +186,7 @@ const sketch = (p) => {
// Spawning Logic (keeping your random chance)
if (p.random(1) < 0.004) {
- const types = ["NEURON", "SUGAR", "GLITCH"];
+ const types = ["STRAWBERRY", "BANANA", "BLUEBERRY"];
targets.push({
x: p.random(p.width * 0.2, p.width * 0.8),
y: -50,
@@ -427,6 +465,8 @@ function update() {
function triggerGameOver() {
isPlaying = false; gameOver = true; isDying = true; hitFlash = true;
+ hasSubmitted = false; // Allow a new submission for this game over
+ loadLeaderboard(); // Refresh board to show latest rankings
swapCharacter("Falling Back Death.glb", true);
setTimeout(() => hitFlash = false, 150);
}
@@ -435,7 +475,7 @@ async function startGame() {
if (!scene) return;
currentSpeed = CONFIG.START_SPEED;
// Choose a random target type for this mission
- const types = ["NEURON", "SUGAR", "GLITCH"];
+ const types = ["STRAWBERRY", "BANANA", "BLUEBERRY"];
targetType = types[Math.floor(Math.random() * types.length)];
worldObjects.forEach(obj => scene.remove(obj.mesh));
worldObjects = [];
@@ -462,6 +502,7 @@ const handleKeyDown = (e) => {
};
onMount(() => {
+ loadLeaderboard();
window.addEventListener("keydown", handleKeyDown);
return () => {
cancelAnimationFrame(animationFrame);
@@ -476,16 +517,60 @@ onMount(() => {
Final Score: {score}
- +Final Score: {score}
+ + + {#if !hasSubmitted} +SCORE SAVED!
+ {/if} + +