/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Obstacle class: moves in a straight or curved unpredictable path, fast var Obstacle = Container.expand(function () { var self = Container.call(this); // Randomly pick a shape and color var type = Math.floor(Math.random() * 4); var assetId = 'obstacleBox'; if (type === 1) assetId = 'obstacleEllipse'; if (type === 2) assetId = 'obstacleBox2'; if (type === 3) assetId = 'obstacleEllipse2'; var obstacleGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); obstacleGraphics.assetId = assetId; // Tint obstacles to a backrooms yellow obstacleGraphics.tint = 0xffe066; // Randomize size a bit for more chaos var scale = 0.8 + Math.random() * 0.7; obstacleGraphics.scaleX = scale; obstacleGraphics.scaleY = scale; // Movement: always target the player's current position at spawn // Start position: randomly from one of the four edges var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left var startX = 0, startY = 0, endX = 0, endY = 0; var w = 2048, h = 2732; // For curved movement, we use a simple parametric curve (sin/cos offset) self.curve = Math.random() < 0.5; // 50% chance to curve self.curvePhase = Math.random() * Math.PI * 2; self.curveAmp = 80 + Math.random() * 120; // Speed: fast, but random self.speed = 22 + Math.random() * 18; // px per frame // Set start position based on edge if (edge === 0) { // top startX = 100 + Math.random() * (w - 200); startY = -100; } else if (edge === 1) { // right startX = w + 100; startY = 100 + Math.random() * (h - 200); } else if (edge === 2) { // bottom startX = 100 + Math.random() * (w - 200); startY = h + 100; } else { // left startX = -100; startY = 100 + Math.random() * (h - 200); } // Target the player's current position at spawn if (typeof player !== "undefined" && player) { endX = player.x; endY = player.y; } else { // fallback to center if player not defined yet endX = w / 2; endY = h / 2; } self.x = startX; self.y = startY; self.startX = startX; self.startY = startY; self.endX = endX; self.endY = endY; // For movement progress self.progress = 0; // 0 to 1 // For collision detection self.lastIntersecting = false; // Update method: move along the path self.update = function () { // Move progress var dx = self.endX - self.startX; var dy = self.endY - self.startY; var dist = Math.sqrt(dx * dx + dy * dy); var totalFrames = dist / self.speed; self.progress += 1 / totalFrames; // Obstacles never stop: let them continue past the player and offscreen // Remove the progress clamp so they keep moving // (no if (self.progress > 1.1) ...) // Linear movement var px = self.startX + dx * self.progress; var py = self.startY + dy * self.progress; // Add curve if needed if (self.curve) { // Perpendicular direction var perpAngle = Math.atan2(dy, dx) + Math.PI / 2; var curveOffset = Math.sin(self.progress * Math.PI + self.curvePhase) * self.curveAmp; px += Math.cos(perpAngle) * curveOffset; py += Math.sin(perpAngle) * curveOffset; } self.x = px; self.y = py; }; return self; }); // Player class: draggable circle var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Tint player to a faded yellow for backrooms vibe playerGraphics.tint = 0xfff7b2; // --- Smaller hitbox for collision detection --- self.hitboxScale = 0.62; // 62% of visual size (smaller hitbox) self.getHitboxRect = function () { var w = playerGraphics.width * self.hitboxScale; var h = playerGraphics.height * self.hitboxScale; return { x: self.x - w / 2, y: self.y - h / 2, width: w, height: h }; }; // Override intersects to use smaller hitbox self.intersects = function (other) { var a = self.getHitboxRect(); var b; if (typeof other.getHitboxRect === "function") { b = other.getHitboxRect(); } else { // fallback to bounding box b = { x: other.x - other.width / 2, y: other.y - other.height / 2, width: other.width, height: other.height }; } return !(a.x + a.width < b.x || a.x > b.x + b.width || a.y + a.height < b.y || a.y > b.y + b.height); }; // --- Raster/grid overlay effect --- var gridRows = 6; var gridCols = 6; var gridW = playerGraphics.width; var gridH = playerGraphics.height; var cellW = gridW / gridCols; var cellH = gridH / gridRows; for (var gx = 0; gx < gridCols; gx++) { for (var gy = 0; gy < gridRows; gy++) { // Use a small rectangle asset for the raster cell var cell = self.attachAsset('obstacleBox2', { anchorX: 0.5, anchorY: 0.5, scaleX: cellW / 20 * 0.85, scaleY: cellH / 30 * 0.85, x: (gx - (gridCols - 1) / 2) * cellW, y: (gy - (gridRows - 1) / 2) * cellH, tint: 0xffffff }); cell.alpha = 0.18 + 0.08 * ((gx + gy) % 2); // subtle grid } } // For touch feedback self.flash = function () { tween(playerGraphics, { tint: 0xff0000 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { tween(playerGraphics, { tint: 0xffffff }, { duration: 200, easing: tween.linear }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffe066 // Backrooms yellow }); /**** * Game Code ****/ // LK.init.sound('dodge', {volume: 0.5}); // Sound for dodge (optional, not used as per guidelines) // Player: small, bright circle // Obstacles: fast-moving, unpredictable shapes (boxes and ellipses, different colors/sizes) // Game variables // Toplist icon as a top tier image asset function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var player = new Player(); var obstacles = []; var dragNode = null; var lastGameOver = false; var timeSurvived = 0; // in ms var timerText = null; var spawnInterval = 36; // frames between spawns, will decrease var minSpawnInterval = 12; var spawnTick = 0; var gameOver = false; // --- Main Menu Overlay --- // Remove old overlay if present (defensive) if (typeof mainMenuOverlay !== "undefined" && mainMenuOverlay && mainMenuOverlay.parent) { mainMenuOverlay.parent.removeChild(mainMenuOverlay); } var mainMenuOverlay = new Container(); mainMenuOverlay.zIndex = 10000; // ensure on top // Animated, layered background var menuBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 44, x: 2048 / 2, y: 2732 / 2 }); menuBg.alpha = 0.96; menuBg.tint = 0x181818; mainMenuOverlay.addChild(menuBg); // Add a subtle, animated "glow" behind the title var glow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 2.2, x: 2048 / 2, y: 600 }); glow.alpha = 0.22; glow.tint = 0xffe066; mainMenuOverlay.addChild(glow); // Title with shadow effect var titleText = new Text2('DODGE THE CHAOS', { size: 200, fill: 0xFFE066 }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 420; // Add shadow first so it's behind the title var titleShadow = new Text2('DODGE THE CHAOS', { size: 200, fill: "#000" }); titleShadow.anchor.set(0.5, 0); titleShadow.x = 2048 / 2 + 8; titleShadow.y = 420 + 10; titleShadow.alpha = 0.18; mainMenuOverlay.addChild(titleShadow); mainMenuOverlay.addChild(titleText); // Subtitle with more punch var subtitleText = new Text2('Survive as long as you can\nby dodging unpredictable obstacles!', { size: 90, fill: "#fff" }); subtitleText.anchor.set(0.5, 0); subtitleText.x = 2048 / 2; subtitleText.y = 670; mainMenuOverlay.addChild(subtitleText); // Start Button (now using a new image asset for the button) var startBtn = LK.getAsset('startBtnImage', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, x: 2048 / 2, y: 1250 }); mainMenuOverlay.addChild(startBtn); // Optional: add a subtle glow behind the image button for effect var startBtnGlow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.7, x: 2048 / 2, y: 1250 }); startBtnGlow.tint = 0x83de44; startBtnGlow.alpha = 0.18; mainMenuOverlay.addChild(startBtnGlow); // Optional: add text overlay for accessibility/clarity var startBtnText = new Text2('START', { size: 130, fill: "#222" }); startBtnText.anchor.set(0.5, 0.5); startBtnText.x = 2048 / 2; startBtnText.y = 1250; mainMenuOverlay.addChild(startBtnText); // Add a "How to Play" quick tip var tipText = new Text2('Drag the player to dodge!\nTouch START to begin.', { size: 70, fill: 0xFFE066 }); tipText.anchor.set(0.5, 0); tipText.x = 2048 / 2; tipText.y = 1450; mainMenuOverlay.addChild(tipText); // Show overlay game.addChild(mainMenuOverlay); // Block game logic until started var menuActive = true; // Animate menu elements for polish tween(glow, { scaleX: 10, scaleY: 2.7, alpha: 0.32 }, { duration: 1200, yoyo: true, repeat: Infinity, easing: tween.sineInOut }); // Start button interaction mainMenuOverlay.down = function (x, y, obj) { // Only start if touch/click is on the button var dx = x - startBtn.x; var dy = y - startBtn.y; var w = startBtn.width / 2, h = startBtn.height / 2; if (dx >= -w && dx <= w && dy >= -h && dy <= h) { // Animate out tween(mainMenuOverlay, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { mainMenuOverlay.visible = false; menuActive = false; player.visible = true; // Show player when game starts } }); } }; mainMenuOverlay.interactive = true; // Place player at center (do not add to mainMenuOverlay, only to game scene) player.x = 2048 / 2; player.y = 2732 / 2; player.visible = false; // Hide player in main menu game.addChild(player); // (Meme corner logic removed) // Timer text (top center) timerText = new Text2('0.00', { size: 120, fill: "#fff" }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // Prevent player from being placed in top left 100x100 function clampPlayerPosition(x, y) { var px = x, py = y; var r = player.width / 2; if (px < r + 10) px = r + 10; if (px > 2048 - r - 10) px = 2048 - r - 10; if (py < r + 10) py = r + 10; if (py > 2732 - r - 10) py = 2732 - r - 10; // Avoid top left menu if (px - r < 100 && py - r < 100) { if (px > py) px = 100 + r + 10;else py = 100 + r + 10; } return { x: px, y: py }; } // Dragging logic function handleMove(x, y, obj) { if (menuActive || gameOver) return; if (dragNode) { var pos = clampPlayerPosition(x, y); dragNode.x = pos.x; dragNode.y = pos.y; } } game.move = handleMove; game.down = function (x, y, obj) { if (menuActive) return; // Only allow drag if touch is on player var dx = x - player.x; var dy = y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < player.width / 2 + 10) { dragNode = player; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { if (menuActive) return; dragNode = null; }; // --- Leaderboard Overlay --- // Remade leaderboard overlay with a new visual style and layout var leaderboardOverlay = new Container(); leaderboardOverlay.zIndex = 9999; leaderboardOverlay.visible = false; // New background: larger, more vibrant, with a subtle border var lbBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 24, x: 2048 / 2, y: 2732 / 2 }); lbBg.alpha = 0.97; lbBg.tint = 0x181818; leaderboardOverlay.addChild(lbBg); // Add a glowing border effect var lbGlow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 21.5, scaleY: 25.5, x: 2048 / 2, y: 2732 / 2 }); lbGlow.alpha = 0.13; lbGlow.tint = 0xffe066; leaderboardOverlay.addChild(lbGlow); // Top tier icon, larger and with a glow var lbIcon = LK.getAsset('topTierIcon', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 340, scaleX: 1.6, scaleY: 1.6 }); leaderboardOverlay.addChild(lbIcon); var lbIconGlow = LK.getAsset('topTierIcon', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 340, scaleX: 2.2, scaleY: 2.2 }); lbIconGlow.alpha = 0.18; lbIconGlow.tint = 0xffe066; leaderboardOverlay.addChild(lbIconGlow); // Title with shadow and highlight var lbTitleShadow = new Text2('TOP PLAYERS', { size: 140, fill: "#000" }); lbTitleShadow.anchor.set(0.5, 0); lbTitleShadow.x = 2048 / 2 + 8; lbTitleShadow.y = 440 + 10; lbTitleShadow.alpha = 0.18; leaderboardOverlay.addChild(lbTitleShadow); var lbTitle = new Text2('TOP PLAYERS', { size: 140, fill: 0xFFE066 }); lbTitle.anchor.set(0.5, 0); lbTitle.x = 2048 / 2; lbTitle.y = 440; leaderboardOverlay.addChild(lbTitle); // Subtitle var lbSubtitle = new Text2('Survive the chaos. Can you make the list?', { size: 70, fill: "#fff" }); lbSubtitle.anchor.set(0.5, 0); lbSubtitle.x = 2048 / 2; lbSubtitle.y = 600; leaderboardOverlay.addChild(lbSubtitle); // List of top players, larger and more spaced var lbListText = new Text2('', { size: 100, fill: "#fff" }); lbListText.anchor.set(0.5, 0); lbListText.x = 2048 / 2; lbListText.y = 740; leaderboardOverlay.addChild(lbListText); // Close button: new style, round and more visible var lbCloseBtn = LK.getAsset('topTierIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, x: 2048 / 2, y: 2200 }); lbCloseBtn.tint = 0xd83318; leaderboardOverlay.addChild(lbCloseBtn); var lbCloseBtnGlow = LK.getAsset('topTierIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.1, scaleY: 2.1, x: 2048 / 2, y: 2200 }); lbCloseBtnGlow.tint = 0xd83318; lbCloseBtnGlow.alpha = 0.13; leaderboardOverlay.addChild(lbCloseBtnGlow); var lbCloseText = new Text2('CLOSE', { size: 90, fill: "#fff" }); lbCloseText.anchor.set(0.5, 0.5); lbCloseText.x = 2048 / 2; lbCloseText.y = 2200; leaderboardOverlay.addChild(lbCloseText); // Show leaderboard overlay function showLeaderboard() { // Get top 5 scores from storage (convert 1-level deep object to array) var scoresObj = storage.topScores || {}; var scores = []; for (var k in scoresObj) { if (scoresObj.hasOwnProperty(k)) scores.push(scoresObj[k]); } // Sort descending scores.sort(function (a, b) { return b.score - a.score; }); // Format for display var lines = []; for (var i = 0; i < Math.min(5, scores.length); i++) { var entry = scores[i]; // Add a trophy emoji for top 1, 2, 3 var trophy = ""; if (i === 0) trophy = "🥇 ";else if (i === 1) trophy = "🥈 ";else if (i === 2) trophy = "🥉 "; lines.push(trophy + (i + 1) + ". " + (entry.name && entry.name.length > 0 ? entry.name : "Player") + " - " + entry.score.toFixed(2) + "s"); } if (lines.length === 0) lines.push("No scores yet!"); lbListText.setText(lines.join("\n\n")); leaderboardOverlay.visible = true; leaderboardOverlay.alpha = 1; } lbCloseBtn.interactive = true; leaderboardOverlay.down = function (x, y, obj) { // Only close if touch/click is on the button var dx = x - lbCloseBtn.x; var dy = y - lbCloseBtn.y; var w = lbCloseBtn.width / 2, h = lbCloseBtn.height / 2; if (dx >= -w && dx <= w && dy >= -h && dy <= h) { leaderboardOverlay.visible = false; } }; game.addChild(leaderboardOverlay); // (Leaderboard button removed from main menu overlay) // Main update loop game.update = function () { if (menuActive || gameOver) return; // Update timer timeSurvived += 1000 / 60; var t = Math.floor(timeSurvived) / 1000; timerText.setText(t.toFixed(2)); // Increase difficulty over time if (timeSurvived > 8000 && spawnInterval > minSpawnInterval) { spawnInterval = 24; } if (timeSurvived > 18000 && spawnInterval > minSpawnInterval) { spawnInterval = 16; } if (timeSurvived > 30000 && spawnInterval > minSpawnInterval) { spawnInterval = minSpawnInterval; } // Spawn new obstacles spawnTick++; if (spawnTick >= spawnInterval) { spawnTick = 0; var obs = new Obstacle(); obstacles.push(obs); game.addChild(obs); // Play Panda sound if obstacle is of type obstacleEllipse2 if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleEllipse2') { LK.getSound('Panda').play(); } // Play Papa sound if obstacle is of type obstacleEllipse if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleEllipse') { LK.getSound('Papa').play(); } // Play Kanye sound if obstacle is of type obstacleBox2 if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleBox2') { LK.getSound('Kanye').play(); } // Play Godzilla sound if obstacle is of type obstacleBox if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleBox') { LK.getSound('Godzilla').play(); } } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if far offscreen (let them go well past the screen) if (obs.x < -400 || obs.x > 2048 + 400 || obs.y < -400 || obs.y > 2732 + 400) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection var intersecting = obs.intersects && player.intersects ? player.intersects(obs) : obs.intersects(player); if (!obs.lastIntersecting && intersecting) { // Game over: flash, then show dead screen overlay player.flash(); LK.effects.flashScreen(0xff0000, 800); gameOver = true; // Mute all sounds when player dies and dead screen is shown if (typeof LK.muteAllSounds === "function") { LK.muteAllSounds(); } // Show dead screen overlay if (typeof deadScreenOverlay !== "undefined" && deadScreenOverlay && deadScreenOverlay.parent) { deadScreenOverlay.parent.removeChild(deadScreenOverlay); } var deadScreenOverlay = new Container(); deadScreenOverlay.zIndex = 10001; // Background var deadBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 24, x: 2048 / 2, y: 2732 / 2 }); deadBg.alpha = 0.97; deadBg.tint = 0x181818; deadScreenOverlay.addChild(deadBg); // Glow var deadGlow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 21.5, scaleY: 25.5, x: 2048 / 2, y: 2732 / 2 }); deadGlow.alpha = 0.13; deadGlow.tint = 0xff0000; deadScreenOverlay.addChild(deadGlow); // Title var deadTitleShadow = new Text2('YOU DIED', { size: 180, fill: "#000" }); deadTitleShadow.anchor.set(0.5, 0); deadTitleShadow.x = 2048 / 2 + 8; deadTitleShadow.y = 700 + 10; deadTitleShadow.alpha = 0.18; deadScreenOverlay.addChild(deadTitleShadow); var deadTitle = new Text2('YOU DIED', { size: 180, fill: 0xff0000 }); deadTitle.anchor.set(0.5, 0); deadTitle.x = 2048 / 2; deadTitle.y = 700; deadScreenOverlay.addChild(deadTitle); // Subtitle var deadSubtitle = new Text2('Survived: ' + (Math.floor(timeSurvived) / 1000).toFixed(2) + 's', { size: 90, fill: "#fff" }); deadSubtitle.anchor.set(0.5, 0); deadSubtitle.x = 2048 / 2; deadSubtitle.y = 900; deadScreenOverlay.addChild(deadSubtitle); // Restart Button (replaces Main Menu) var restartBtn = LK.getAsset('startBtnImage', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, x: 2048 / 2, y: 1400 }); deadScreenOverlay.addChild(restartBtn); var restartBtnGlow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.7, x: 2048 / 2, y: 1400 }); restartBtnGlow.tint = 0x83de44; restartBtnGlow.alpha = 0.18; deadScreenOverlay.addChild(restartBtnGlow); var restartBtnText = new Text2('RESTART', { size: 130, fill: "#222" }); restartBtnText.anchor.set(0.5, 0.5); restartBtnText.x = 2048 / 2; restartBtnText.y = 1400; deadScreenOverlay.addChild(restartBtnText); // Optionally, add a "Leaderboard" button var mainMenuBtn = LK.getAsset('topTierIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, x: 2048 / 2, y: 1700 }); mainMenuBtn.tint = 0x4e9ae7; deadScreenOverlay.addChild(mainMenuBtn); var mainMenuBtnText = new Text2('MAIN MENU', { size: 90, fill: "#fff" }); mainMenuBtnText.anchor.set(0.5, 0.5); mainMenuBtnText.x = 2048 / 2; mainMenuBtnText.y = 1700; deadScreenOverlay.addChild(mainMenuBtnText); // Interactivity deadScreenOverlay.interactive = true; deadScreenOverlay.down = function (x, y, obj) { // Restart button var dx = x - restartBtn.x; var dy = y - restartBtn.y; var w = restartBtn.width / 2, h = restartBtn.height / 2; if (dx >= -w && dx <= w && dy >= -h && dy <= h) { deadScreenOverlay.visible = false; // Instantly restart the game: hide overlays, reset state, and start game mainMenuOverlay.visible = false; menuActive = false; player.visible = true; gameOver = false; timeSurvived = 0; spawnInterval = 36; spawnTick = 0; timerText.setText('0.00'); // Remove all obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; // Reset player position player.x = 2048 / 2; player.y = 2732 / 2; dragNode = null; return; } // Main Menu button var dx2 = x - mainMenuBtn.x; var dy2 = y - mainMenuBtn.y; var w2 = mainMenuBtn.width / 2, h2 = mainMenuBtn.height / 2; if (dx2 >= -w2 && dx2 <= w2 && dy2 >= -h2 && dy2 <= h2) { deadScreenOverlay.visible = false; mainMenuOverlay.visible = true; mainMenuOverlay.alpha = 1; menuActive = true; player.visible = false; return; } }; game.addChild(deadScreenOverlay); break; } obs.lastIntersecting = intersecting; } }; // Reset logic (when game restarts) game.on('reset', function () { // Remove all obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; // Reset player position player.x = 2048 / 2; player.y = 2732 / 2; dragNode = null; timeSurvived = 0; spawnInterval = 36; spawnTick = 0; gameOver = false; timerText.setText('0.00'); // Hide dead screen overlay if present if (typeof deadScreenOverlay !== "undefined" && deadScreenOverlay) { deadScreenOverlay.visible = false; } // Show main menu again mainMenuOverlay.visible = true; mainMenuOverlay.alpha = 1; menuActive = true; player.visible = false; // Hide player in main menu after reset });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Obstacle class: moves in a straight or curved unpredictable path, fast
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Randomly pick a shape and color
var type = Math.floor(Math.random() * 4);
var assetId = 'obstacleBox';
if (type === 1) assetId = 'obstacleEllipse';
if (type === 2) assetId = 'obstacleBox2';
if (type === 3) assetId = 'obstacleEllipse2';
var obstacleGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
obstacleGraphics.assetId = assetId;
// Tint obstacles to a backrooms yellow
obstacleGraphics.tint = 0xffe066;
// Randomize size a bit for more chaos
var scale = 0.8 + Math.random() * 0.7;
obstacleGraphics.scaleX = scale;
obstacleGraphics.scaleY = scale;
// Movement: always target the player's current position at spawn
// Start position: randomly from one of the four edges
var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
var startX = 0,
startY = 0,
endX = 0,
endY = 0;
var w = 2048,
h = 2732;
// For curved movement, we use a simple parametric curve (sin/cos offset)
self.curve = Math.random() < 0.5; // 50% chance to curve
self.curvePhase = Math.random() * Math.PI * 2;
self.curveAmp = 80 + Math.random() * 120;
// Speed: fast, but random
self.speed = 22 + Math.random() * 18; // px per frame
// Set start position based on edge
if (edge === 0) {
// top
startX = 100 + Math.random() * (w - 200);
startY = -100;
} else if (edge === 1) {
// right
startX = w + 100;
startY = 100 + Math.random() * (h - 200);
} else if (edge === 2) {
// bottom
startX = 100 + Math.random() * (w - 200);
startY = h + 100;
} else {
// left
startX = -100;
startY = 100 + Math.random() * (h - 200);
}
// Target the player's current position at spawn
if (typeof player !== "undefined" && player) {
endX = player.x;
endY = player.y;
} else {
// fallback to center if player not defined yet
endX = w / 2;
endY = h / 2;
}
self.x = startX;
self.y = startY;
self.startX = startX;
self.startY = startY;
self.endX = endX;
self.endY = endY;
// For movement progress
self.progress = 0; // 0 to 1
// For collision detection
self.lastIntersecting = false;
// Update method: move along the path
self.update = function () {
// Move progress
var dx = self.endX - self.startX;
var dy = self.endY - self.startY;
var dist = Math.sqrt(dx * dx + dy * dy);
var totalFrames = dist / self.speed;
self.progress += 1 / totalFrames;
// Obstacles never stop: let them continue past the player and offscreen
// Remove the progress clamp so they keep moving
// (no if (self.progress > 1.1) ...)
// Linear movement
var px = self.startX + dx * self.progress;
var py = self.startY + dy * self.progress;
// Add curve if needed
if (self.curve) {
// Perpendicular direction
var perpAngle = Math.atan2(dy, dx) + Math.PI / 2;
var curveOffset = Math.sin(self.progress * Math.PI + self.curvePhase) * self.curveAmp;
px += Math.cos(perpAngle) * curveOffset;
py += Math.sin(perpAngle) * curveOffset;
}
self.x = px;
self.y = py;
};
return self;
});
// Player class: draggable circle
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint player to a faded yellow for backrooms vibe
playerGraphics.tint = 0xfff7b2;
// --- Smaller hitbox for collision detection ---
self.hitboxScale = 0.62; // 62% of visual size (smaller hitbox)
self.getHitboxRect = function () {
var w = playerGraphics.width * self.hitboxScale;
var h = playerGraphics.height * self.hitboxScale;
return {
x: self.x - w / 2,
y: self.y - h / 2,
width: w,
height: h
};
};
// Override intersects to use smaller hitbox
self.intersects = function (other) {
var a = self.getHitboxRect();
var b;
if (typeof other.getHitboxRect === "function") {
b = other.getHitboxRect();
} else {
// fallback to bounding box
b = {
x: other.x - other.width / 2,
y: other.y - other.height / 2,
width: other.width,
height: other.height
};
}
return !(a.x + a.width < b.x || a.x > b.x + b.width || a.y + a.height < b.y || a.y > b.y + b.height);
};
// --- Raster/grid overlay effect ---
var gridRows = 6;
var gridCols = 6;
var gridW = playerGraphics.width;
var gridH = playerGraphics.height;
var cellW = gridW / gridCols;
var cellH = gridH / gridRows;
for (var gx = 0; gx < gridCols; gx++) {
for (var gy = 0; gy < gridRows; gy++) {
// Use a small rectangle asset for the raster cell
var cell = self.attachAsset('obstacleBox2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: cellW / 20 * 0.85,
scaleY: cellH / 30 * 0.85,
x: (gx - (gridCols - 1) / 2) * cellW,
y: (gy - (gridRows - 1) / 2) * cellH,
tint: 0xffffff
});
cell.alpha = 0.18 + 0.08 * ((gx + gy) % 2); // subtle grid
}
}
// For touch feedback
self.flash = function () {
tween(playerGraphics, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(playerGraphics, {
tint: 0xffffff
}, {
duration: 200,
easing: tween.linear
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffe066 // Backrooms yellow
});
/****
* Game Code
****/
// LK.init.sound('dodge', {volume: 0.5});
// Sound for dodge (optional, not used as per guidelines)
// Player: small, bright circle
// Obstacles: fast-moving, unpredictable shapes (boxes and ellipses, different colors/sizes)
// Game variables
// Toplist icon as a top tier image asset
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
var player = new Player();
var obstacles = [];
var dragNode = null;
var lastGameOver = false;
var timeSurvived = 0; // in ms
var timerText = null;
var spawnInterval = 36; // frames between spawns, will decrease
var minSpawnInterval = 12;
var spawnTick = 0;
var gameOver = false;
// --- Main Menu Overlay ---
// Remove old overlay if present (defensive)
if (typeof mainMenuOverlay !== "undefined" && mainMenuOverlay && mainMenuOverlay.parent) {
mainMenuOverlay.parent.removeChild(mainMenuOverlay);
}
var mainMenuOverlay = new Container();
mainMenuOverlay.zIndex = 10000; // ensure on top
// Animated, layered background
var menuBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 44,
x: 2048 / 2,
y: 2732 / 2
});
menuBg.alpha = 0.96;
menuBg.tint = 0x181818;
mainMenuOverlay.addChild(menuBg);
// Add a subtle, animated "glow" behind the title
var glow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 2.2,
x: 2048 / 2,
y: 600
});
glow.alpha = 0.22;
glow.tint = 0xffe066;
mainMenuOverlay.addChild(glow);
// Title with shadow effect
var titleText = new Text2('DODGE THE CHAOS', {
size: 200,
fill: 0xFFE066
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 420;
// Add shadow first so it's behind the title
var titleShadow = new Text2('DODGE THE CHAOS', {
size: 200,
fill: "#000"
});
titleShadow.anchor.set(0.5, 0);
titleShadow.x = 2048 / 2 + 8;
titleShadow.y = 420 + 10;
titleShadow.alpha = 0.18;
mainMenuOverlay.addChild(titleShadow);
mainMenuOverlay.addChild(titleText);
// Subtitle with more punch
var subtitleText = new Text2('Survive as long as you can\nby dodging unpredictable obstacles!', {
size: 90,
fill: "#fff"
});
subtitleText.anchor.set(0.5, 0);
subtitleText.x = 2048 / 2;
subtitleText.y = 670;
mainMenuOverlay.addChild(subtitleText);
// Start Button (now using a new image asset for the button)
var startBtn = LK.getAsset('startBtnImage', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 2048 / 2,
y: 1250
});
mainMenuOverlay.addChild(startBtn);
// Optional: add a subtle glow behind the image button for effect
var startBtnGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 0.7,
x: 2048 / 2,
y: 1250
});
startBtnGlow.tint = 0x83de44;
startBtnGlow.alpha = 0.18;
mainMenuOverlay.addChild(startBtnGlow);
// Optional: add text overlay for accessibility/clarity
var startBtnText = new Text2('START', {
size: 130,
fill: "#222"
});
startBtnText.anchor.set(0.5, 0.5);
startBtnText.x = 2048 / 2;
startBtnText.y = 1250;
mainMenuOverlay.addChild(startBtnText);
// Add a "How to Play" quick tip
var tipText = new Text2('Drag the player to dodge!\nTouch START to begin.', {
size: 70,
fill: 0xFFE066
});
tipText.anchor.set(0.5, 0);
tipText.x = 2048 / 2;
tipText.y = 1450;
mainMenuOverlay.addChild(tipText);
// Show overlay
game.addChild(mainMenuOverlay);
// Block game logic until started
var menuActive = true;
// Animate menu elements for polish
tween(glow, {
scaleX: 10,
scaleY: 2.7,
alpha: 0.32
}, {
duration: 1200,
yoyo: true,
repeat: Infinity,
easing: tween.sineInOut
});
// Start button interaction
mainMenuOverlay.down = function (x, y, obj) {
// Only start if touch/click is on the button
var dx = x - startBtn.x;
var dy = y - startBtn.y;
var w = startBtn.width / 2,
h = startBtn.height / 2;
if (dx >= -w && dx <= w && dy >= -h && dy <= h) {
// Animate out
tween(mainMenuOverlay, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
mainMenuOverlay.visible = false;
menuActive = false;
player.visible = true; // Show player when game starts
}
});
}
};
mainMenuOverlay.interactive = true;
// Place player at center (do not add to mainMenuOverlay, only to game scene)
player.x = 2048 / 2;
player.y = 2732 / 2;
player.visible = false; // Hide player in main menu
game.addChild(player);
// (Meme corner logic removed)
// Timer text (top center)
timerText = new Text2('0.00', {
size: 120,
fill: "#fff"
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Prevent player from being placed in top left 100x100
function clampPlayerPosition(x, y) {
var px = x,
py = y;
var r = player.width / 2;
if (px < r + 10) px = r + 10;
if (px > 2048 - r - 10) px = 2048 - r - 10;
if (py < r + 10) py = r + 10;
if (py > 2732 - r - 10) py = 2732 - r - 10;
// Avoid top left menu
if (px - r < 100 && py - r < 100) {
if (px > py) px = 100 + r + 10;else py = 100 + r + 10;
}
return {
x: px,
y: py
};
}
// Dragging logic
function handleMove(x, y, obj) {
if (menuActive || gameOver) return;
if (dragNode) {
var pos = clampPlayerPosition(x, y);
dragNode.x = pos.x;
dragNode.y = pos.y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (menuActive) return;
// Only allow drag if touch is on player
var dx = x - player.x;
var dy = y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < player.width / 2 + 10) {
dragNode = player;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
if (menuActive) return;
dragNode = null;
};
// --- Leaderboard Overlay ---
// Remade leaderboard overlay with a new visual style and layout
var leaderboardOverlay = new Container();
leaderboardOverlay.zIndex = 9999;
leaderboardOverlay.visible = false;
// New background: larger, more vibrant, with a subtle border
var lbBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 24,
x: 2048 / 2,
y: 2732 / 2
});
lbBg.alpha = 0.97;
lbBg.tint = 0x181818;
leaderboardOverlay.addChild(lbBg);
// Add a glowing border effect
var lbGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 21.5,
scaleY: 25.5,
x: 2048 / 2,
y: 2732 / 2
});
lbGlow.alpha = 0.13;
lbGlow.tint = 0xffe066;
leaderboardOverlay.addChild(lbGlow);
// Top tier icon, larger and with a glow
var lbIcon = LK.getAsset('topTierIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 340,
scaleX: 1.6,
scaleY: 1.6
});
leaderboardOverlay.addChild(lbIcon);
var lbIconGlow = LK.getAsset('topTierIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 340,
scaleX: 2.2,
scaleY: 2.2
});
lbIconGlow.alpha = 0.18;
lbIconGlow.tint = 0xffe066;
leaderboardOverlay.addChild(lbIconGlow);
// Title with shadow and highlight
var lbTitleShadow = new Text2('TOP PLAYERS', {
size: 140,
fill: "#000"
});
lbTitleShadow.anchor.set(0.5, 0);
lbTitleShadow.x = 2048 / 2 + 8;
lbTitleShadow.y = 440 + 10;
lbTitleShadow.alpha = 0.18;
leaderboardOverlay.addChild(lbTitleShadow);
var lbTitle = new Text2('TOP PLAYERS', {
size: 140,
fill: 0xFFE066
});
lbTitle.anchor.set(0.5, 0);
lbTitle.x = 2048 / 2;
lbTitle.y = 440;
leaderboardOverlay.addChild(lbTitle);
// Subtitle
var lbSubtitle = new Text2('Survive the chaos. Can you make the list?', {
size: 70,
fill: "#fff"
});
lbSubtitle.anchor.set(0.5, 0);
lbSubtitle.x = 2048 / 2;
lbSubtitle.y = 600;
leaderboardOverlay.addChild(lbSubtitle);
// List of top players, larger and more spaced
var lbListText = new Text2('', {
size: 100,
fill: "#fff"
});
lbListText.anchor.set(0.5, 0);
lbListText.x = 2048 / 2;
lbListText.y = 740;
leaderboardOverlay.addChild(lbListText);
// Close button: new style, round and more visible
var lbCloseBtn = LK.getAsset('topTierIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
x: 2048 / 2,
y: 2200
});
lbCloseBtn.tint = 0xd83318;
leaderboardOverlay.addChild(lbCloseBtn);
var lbCloseBtnGlow = LK.getAsset('topTierIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.1,
scaleY: 2.1,
x: 2048 / 2,
y: 2200
});
lbCloseBtnGlow.tint = 0xd83318;
lbCloseBtnGlow.alpha = 0.13;
leaderboardOverlay.addChild(lbCloseBtnGlow);
var lbCloseText = new Text2('CLOSE', {
size: 90,
fill: "#fff"
});
lbCloseText.anchor.set(0.5, 0.5);
lbCloseText.x = 2048 / 2;
lbCloseText.y = 2200;
leaderboardOverlay.addChild(lbCloseText);
// Show leaderboard overlay
function showLeaderboard() {
// Get top 5 scores from storage (convert 1-level deep object to array)
var scoresObj = storage.topScores || {};
var scores = [];
for (var k in scoresObj) {
if (scoresObj.hasOwnProperty(k)) scores.push(scoresObj[k]);
}
// Sort descending
scores.sort(function (a, b) {
return b.score - a.score;
});
// Format for display
var lines = [];
for (var i = 0; i < Math.min(5, scores.length); i++) {
var entry = scores[i];
// Add a trophy emoji for top 1, 2, 3
var trophy = "";
if (i === 0) trophy = "🥇 ";else if (i === 1) trophy = "🥈 ";else if (i === 2) trophy = "🥉 ";
lines.push(trophy + (i + 1) + ". " + (entry.name && entry.name.length > 0 ? entry.name : "Player") + " - " + entry.score.toFixed(2) + "s");
}
if (lines.length === 0) lines.push("No scores yet!");
lbListText.setText(lines.join("\n\n"));
leaderboardOverlay.visible = true;
leaderboardOverlay.alpha = 1;
}
lbCloseBtn.interactive = true;
leaderboardOverlay.down = function (x, y, obj) {
// Only close if touch/click is on the button
var dx = x - lbCloseBtn.x;
var dy = y - lbCloseBtn.y;
var w = lbCloseBtn.width / 2,
h = lbCloseBtn.height / 2;
if (dx >= -w && dx <= w && dy >= -h && dy <= h) {
leaderboardOverlay.visible = false;
}
};
game.addChild(leaderboardOverlay);
// (Leaderboard button removed from main menu overlay)
// Main update loop
game.update = function () {
if (menuActive || gameOver) return;
// Update timer
timeSurvived += 1000 / 60;
var t = Math.floor(timeSurvived) / 1000;
timerText.setText(t.toFixed(2));
// Increase difficulty over time
if (timeSurvived > 8000 && spawnInterval > minSpawnInterval) {
spawnInterval = 24;
}
if (timeSurvived > 18000 && spawnInterval > minSpawnInterval) {
spawnInterval = 16;
}
if (timeSurvived > 30000 && spawnInterval > minSpawnInterval) {
spawnInterval = minSpawnInterval;
}
// Spawn new obstacles
spawnTick++;
if (spawnTick >= spawnInterval) {
spawnTick = 0;
var obs = new Obstacle();
obstacles.push(obs);
game.addChild(obs);
// Play Panda sound if obstacle is of type obstacleEllipse2
if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleEllipse2') {
LK.getSound('Panda').play();
}
// Play Papa sound if obstacle is of type obstacleEllipse
if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleEllipse') {
LK.getSound('Papa').play();
}
// Play Kanye sound if obstacle is of type obstacleBox2
if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleBox2') {
LK.getSound('Kanye').play();
}
// Play Godzilla sound if obstacle is of type obstacleBox
if (obs && obs.children && obs.children.length > 0 && obs.children[0].assetId === 'obstacleBox') {
LK.getSound('Godzilla').play();
}
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if far offscreen (let them go well past the screen)
if (obs.x < -400 || obs.x > 2048 + 400 || obs.y < -400 || obs.y > 2732 + 400) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
var intersecting = obs.intersects && player.intersects ? player.intersects(obs) : obs.intersects(player);
if (!obs.lastIntersecting && intersecting) {
// Game over: flash, then show dead screen overlay
player.flash();
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
// Mute all sounds when player dies and dead screen is shown
if (typeof LK.muteAllSounds === "function") {
LK.muteAllSounds();
}
// Show dead screen overlay
if (typeof deadScreenOverlay !== "undefined" && deadScreenOverlay && deadScreenOverlay.parent) {
deadScreenOverlay.parent.removeChild(deadScreenOverlay);
}
var deadScreenOverlay = new Container();
deadScreenOverlay.zIndex = 10001;
// Background
var deadBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 24,
x: 2048 / 2,
y: 2732 / 2
});
deadBg.alpha = 0.97;
deadBg.tint = 0x181818;
deadScreenOverlay.addChild(deadBg);
// Glow
var deadGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 21.5,
scaleY: 25.5,
x: 2048 / 2,
y: 2732 / 2
});
deadGlow.alpha = 0.13;
deadGlow.tint = 0xff0000;
deadScreenOverlay.addChild(deadGlow);
// Title
var deadTitleShadow = new Text2('YOU DIED', {
size: 180,
fill: "#000"
});
deadTitleShadow.anchor.set(0.5, 0);
deadTitleShadow.x = 2048 / 2 + 8;
deadTitleShadow.y = 700 + 10;
deadTitleShadow.alpha = 0.18;
deadScreenOverlay.addChild(deadTitleShadow);
var deadTitle = new Text2('YOU DIED', {
size: 180,
fill: 0xff0000
});
deadTitle.anchor.set(0.5, 0);
deadTitle.x = 2048 / 2;
deadTitle.y = 700;
deadScreenOverlay.addChild(deadTitle);
// Subtitle
var deadSubtitle = new Text2('Survived: ' + (Math.floor(timeSurvived) / 1000).toFixed(2) + 's', {
size: 90,
fill: "#fff"
});
deadSubtitle.anchor.set(0.5, 0);
deadSubtitle.x = 2048 / 2;
deadSubtitle.y = 900;
deadScreenOverlay.addChild(deadSubtitle);
// Restart Button (replaces Main Menu)
var restartBtn = LK.getAsset('startBtnImage', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 2048 / 2,
y: 1400
});
deadScreenOverlay.addChild(restartBtn);
var restartBtnGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 0.7,
x: 2048 / 2,
y: 1400
});
restartBtnGlow.tint = 0x83de44;
restartBtnGlow.alpha = 0.18;
deadScreenOverlay.addChild(restartBtnGlow);
var restartBtnText = new Text2('RESTART', {
size: 130,
fill: "#222"
});
restartBtnText.anchor.set(0.5, 0.5);
restartBtnText.x = 2048 / 2;
restartBtnText.y = 1400;
deadScreenOverlay.addChild(restartBtnText);
// Optionally, add a "Leaderboard" button
var mainMenuBtn = LK.getAsset('topTierIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: 2048 / 2,
y: 1700
});
mainMenuBtn.tint = 0x4e9ae7;
deadScreenOverlay.addChild(mainMenuBtn);
var mainMenuBtnText = new Text2('MAIN MENU', {
size: 90,
fill: "#fff"
});
mainMenuBtnText.anchor.set(0.5, 0.5);
mainMenuBtnText.x = 2048 / 2;
mainMenuBtnText.y = 1700;
deadScreenOverlay.addChild(mainMenuBtnText);
// Interactivity
deadScreenOverlay.interactive = true;
deadScreenOverlay.down = function (x, y, obj) {
// Restart button
var dx = x - restartBtn.x;
var dy = y - restartBtn.y;
var w = restartBtn.width / 2,
h = restartBtn.height / 2;
if (dx >= -w && dx <= w && dy >= -h && dy <= h) {
deadScreenOverlay.visible = false;
// Instantly restart the game: hide overlays, reset state, and start game
mainMenuOverlay.visible = false;
menuActive = false;
player.visible = true;
gameOver = false;
timeSurvived = 0;
spawnInterval = 36;
spawnTick = 0;
timerText.setText('0.00');
// Remove all obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
// Reset player position
player.x = 2048 / 2;
player.y = 2732 / 2;
dragNode = null;
return;
}
// Main Menu button
var dx2 = x - mainMenuBtn.x;
var dy2 = y - mainMenuBtn.y;
var w2 = mainMenuBtn.width / 2,
h2 = mainMenuBtn.height / 2;
if (dx2 >= -w2 && dx2 <= w2 && dy2 >= -h2 && dy2 <= h2) {
deadScreenOverlay.visible = false;
mainMenuOverlay.visible = true;
mainMenuOverlay.alpha = 1;
menuActive = true;
player.visible = false;
return;
}
};
game.addChild(deadScreenOverlay);
break;
}
obs.lastIntersecting = intersecting;
}
};
// Reset logic (when game restarts)
game.on('reset', function () {
// Remove all obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
// Reset player position
player.x = 2048 / 2;
player.y = 2732 / 2;
dragNode = null;
timeSurvived = 0;
spawnInterval = 36;
spawnTick = 0;
gameOver = false;
timerText.setText('0.00');
// Hide dead screen overlay if present
if (typeof deadScreenOverlay !== "undefined" && deadScreenOverlay) {
deadScreenOverlay.visible = false;
}
// Show main menu again
mainMenuOverlay.visible = true;
mainMenuOverlay.alpha = 1;
menuActive = true;
player.visible = false; // Hide player in main menu after reset
});