/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Nyan Cat class var NyanCat = Container.expand(function () { var self = Container.call(this); // Rainbow trail (visual only, not collidable) var rainbow = self.attachAsset('rainbow', { anchorX: 1, anchorY: 0.5, x: -90, y: 0, scaleY: 1.2 }); // Add a soft highlight to rainbow for polish rainbow.alpha = 0.92; rainbow.tint = 0xffe0fa; // Add additional rainbow bands for a lively animated effect self.rainbowBands = []; var rainbowColors = [0xfe6cd1, 0xf9d423, 0x7ed957, 0x4a90e2, 0x9b59b6, 0xffffff]; for (var i = 0; i < rainbowColors.length; i++) { var band = self.attachAsset('rainbow', { anchorX: 1, anchorY: 0.5, x: -90, y: (i - 2.5) * 18, // stack vertically scaleY: 0.18, scaleX: 1.0 }); band.alpha = 0.82; band.tint = rainbowColors[i]; self.addChildAt(band, i); self.rainbowBands.push(band); } // Nyan Cat sprite var cat = self.attachAsset('nyanCat', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Add a soft shadow to Nyan Cat for depth cat.alpha = 1; cat.tint = 0xffffff; self.catShadow = LK.getAsset('nyanCat', { anchorX: 0.5, anchorY: 0.5, x: 8, y: 18 }); self.catShadow.alpha = 0.22; self.catShadow.tint = 0x000000; self.addChildAt(self.catShadow, 0); // For collision, use the cat's bounds (not rainbow) self.getCollisionBounds = function () { return { x: self.x - cat.width / 2, y: self.y - cat.height / 2, width: cat.width, height: cat.height }; }; // Flash effect on hit self.flash = function () { tween(cat, { alpha: 0.3 }, { duration: 80, onFinish: function onFinish() { tween(cat, { alpha: 1 }, { duration: 120 }); } }); }; // Rainbow parallax movement for quality polish self.update = function () { // Rainbow trail parallax: slight horizontal movement for visual polish rainbow.x = -90 + Math.sin(LK.ticks * 0.12) * 12; // Animate rainbow bands for a lively, wavy effect for (var i = 0; i < self.rainbowBands.length; i++) { var band = self.rainbowBands[i]; // Wavy movement: each band has a phase offset band.x = -90 + Math.sin(LK.ticks * 0.12 + i * 0.5) * (12 + i * 2); band.y = (i - 2.5) * 18 + Math.sin(LK.ticks * 0.18 + i * 0.7) * 8; // Animate alpha for shimmer band.alpha = 0.7 + 0.25 * Math.abs(Math.sin(LK.ticks * 0.09 + i)); // Animate scale for a breathing effect band.scaleX = 1.0 + 0.13 * Math.sin(LK.ticks * 0.11 + i * 0.8); } }; return self; }); // Obstacle class (cloud or star) var Obstacle = Container.expand(function () { var self = Container.call(this); // Randomly choose cloud or star var isStar = Math.random() < 0.4; var assetId = isStar ? 'star' : 'cloud'; var asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Add soft shadow for depth self.shadow = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, x: 10, y: 18 }); self.shadow.alpha = 0.18; self.shadow.tint = 0x000000; self.addChildAt(self.shadow, 0); self.isStar = isStar; // For collision self.getCollisionBounds = function () { return { x: self.x - asset.width / 2, y: self.y - asset.height / 2, width: asset.width, height: asset.height }; }; // Speed will be set on spawn self.speed = 0; self.update = function () { self.x -= self.speed; }; return self; }); // Shooting Star class for lively background var ShootingStar = Container.expand(function () { var self = Container.call(this); // Use the 'star' asset, small and bright var star = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.32, scaleY: 0.32 }); self.star = star; // Randomize speed and angle self.speed = 18 + Math.random() * 10; //{U} // Reduced speed for slower falling stars self.angle = Math.PI * (0.18 + Math.random() * 0.12); // ~10deg downward self.alpha = 0.7 + Math.random() * 0.3; // Trail effect (simple, fade out) self.update = function () { self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; self.alpha -= 0.018 + Math.random() * 0.008; if (self.alpha <= 0.01) { self.destroy(); } }; return self; }); // Treat class (collectible) var Treat = Container.expand(function () { var self = Container.call(this); var treat = self.attachAsset('treat', { anchorX: 0.5, anchorY: 0.5 }); // Add soft shadow for treat self.shadow = self.attachAsset('treat', { anchorX: 0.5, anchorY: 0.5, x: 10, y: 18 }); self.shadow.alpha = 0.18; self.shadow.tint = 0x000000; self.addChildAt(self.shadow, 0); // For collision self.getCollisionBounds = function () { return { x: self.x - treat.width / 2, y: self.y - treat.height / 2, width: treat.width, height: treat.height }; }; // Speed will be set on spawn self.speed = 0; self.update = function () { self.x -= self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Main Menu Overlay --- // UFO asset var mainMenuOverlay = new Container(); mainMenuOverlay.visible = true; // Hide in-game UI when menu is visible if (typeof scoreTxt !== "undefined" && scoreTxt !== null) scoreTxt.visible = false; if (typeof pauseBtnBg !== "undefined" && pauseBtnBg !== null) pauseBtnBg.visible = false; if (typeof pauseBtnText !== "undefined" && pauseBtnText !== null) pauseBtnText.visible = false; // Ensure backgroundPlanets is always defined before menu background is created if (typeof backgroundPlanets === "undefined" || !backgroundPlanets) backgroundPlanets = []; // Take a screenshot of the game area for menu background (simulate by rendering planets and Nyan Cat in background) function createMenuBackground() { // Remove all children from overlay while (mainMenuOverlay.children.length > 0) mainMenuOverlay.removeChildAt(0); // Add background planets (simulate by copying their positions) for (var i = 0; i < backgroundPlanets.length; i++) { var p = backgroundPlanets[i]; var planet = LK.getAsset(p.assetId || p._assetId || p.id || 'planetBlue', { anchorX: 0.5, anchorY: 0.5 }); planet.x = p.x; planet.y = p.y; planet.scaleX = planet.scaleY = p.scaleX || 1; planet.alpha = p.alpha || 0.18; mainMenuOverlay.addChild(planet); } // Add Nyan Cat in the center (large, faded) var menuCat = LK.getAsset('nyanCat', { anchorX: 0.5, anchorY: 0.5 }); menuCat.x = 2048; menuCat.y = 1200; menuCat.scaleX = menuCat.scaleY = 2.2; menuCat.alpha = 0.18; mainMenuOverlay.addChild(menuCat); } // Game Title var titleText = new Text2('NYAN CAT SPACE RUN', { size: 220, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048; titleText.y = 420; mainMenuOverlay.addChild(titleText); // Play Button var playBtnBg = LK.getAsset('planetYellow', { anchorX: 0.5, anchorY: 0.5 }); playBtnBg.x = 2048; playBtnBg.y = 1200 + 420; playBtnBg.scaleX = playBtnBg.scaleY = 2.2; mainMenuOverlay.addChild(playBtnBg); var playBtnText = new Text2('OYNA', { size: 180, fill: "#222" }); playBtnText.anchor.set(0.5, 0.5); playBtnText.x = 2048; playBtnText.y = 1200 + 420; mainMenuOverlay.addChild(playBtnText); // Play button interaction mainMenuOverlay.down = function (x, y, obj) { // Check if touch is inside play button var dx = x - playBtnBg.x; var dy = y - playBtnBg.y; var r = playBtnBg.width * playBtnBg.scaleX * 0.5; if (dx * dx + dy * dy < r * r) { // Hide menu, start game mainMenuOverlay.visible = false; game.paused = false; // Show in-game UI when menu is hidden scoreTxt.visible = true; pauseBtnBg.visible = true; pauseBtnText.visible = true; // Make sure in-game UI is visible and up to date scoreTxt.visible = true; pauseBtnBg.visible = true; pauseBtnText.visible = true; // Reset game state LK.setScore(0); scoreTxt.setText('0'); for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy(); obstacles = []; for (var j = 0; j < treats.length; j++) treats[j].destroy(); treats = []; nyanCat.x = 3840 * 0.25; nyanCat.y = 2160 * 0.6; nyanCatBaseY = nyanCat.y; speed = baseSpeed; spawnInterval = 70; treatInterval = 110; dragNode = null; lastHit = false; // Resume music LK.playMusic('nyanMusic'); } }; mainMenuOverlay.move = function (x, y, obj) {}; mainMenuOverlay.up = function (x, y, obj) {}; // Add overlay to GUI (centered, covers all) LK.gui.center.addChild(mainMenuOverlay); // Show menu at start game.paused = true; createMenuBackground(); // Animate planets in menu LK.on('tick', function () { if (mainMenuOverlay.visible) { // Animate title titleText.y = 420 + Math.sin(LK.ticks * 0.06) * 24; titleText.scaleX = titleText.scaleY = 1.0 + Math.sin(LK.ticks * 0.09) * 0.04; // Animate play button playBtnBg.scaleX = playBtnBg.scaleY = 2.2 + Math.sin(LK.ticks * 0.13) * 0.13; playBtnText.scaleX = playBtnText.scaleY = 1.0 + Math.sin(LK.ticks * 0.13) * 0.04; } }); // Animate background planets (subtle drifting and glow, and spawn new ones as needed) var backgroundPlanets = []; // --- Drifting Planets for Extra Parallax --- if (!game.backgroundDriftPlanets) game.backgroundDriftPlanets = []; // Spawn drifting planets if needed if (game.backgroundDriftPlanets.length < 3 && Math.random() < 0.04) { var driftPlanetTypes = ['planetBlue', 'planetGreen', 'planetPurple', 'planetRed', 'planetYellow']; var driftId = driftPlanetTypes[Math.floor(Math.random() * driftPlanetTypes.length)]; var driftScale = 0.7 + Math.random() * 0.7; var driftAlpha = 0.10 + Math.random() * 0.10; var driftSpeed = 0.18 + Math.random() * 0.18; var driftY = 200 + Math.random() * (GAME_BOTTOM - 400); var driftPlanet = LK.getAsset(driftId, { anchorX: 0.5, anchorY: 0.5 }); driftPlanet.x = GAME_RIGHT + 600 + Math.random() * 400; driftPlanet.y = driftY; driftPlanet.scaleX = driftPlanet.scaleY = driftScale; driftPlanet.alpha = driftAlpha; driftPlanet._speed = driftSpeed; driftPlanet._drift = 0.03 + Math.random() * 0.07; driftPlanet._driftPhase = Math.random() * Math.PI * 2; game.backgroundDriftPlanets.push(driftPlanet); game.addChildAt(driftPlanet, 0); } // Animate drifting planets for (var dp = game.backgroundDriftPlanets.length - 1; dp >= 0; dp--) { var driftPlanet = game.backgroundDriftPlanets[dp]; driftPlanet.x -= driftPlanet._speed; driftPlanet._driftPhase += driftPlanet._drift; driftPlanet.y += Math.sin(driftPlanet._driftPhase) * 1.2; // Subtle alpha pulsing driftPlanet.alpha = Math.abs(Math.sin(LK.ticks * 0.007 + dp)) * 0.06 + 0.10; // Remove if off screen if (driftPlanet.x < -600) { if (driftPlanet.destroy) driftPlanet.destroy(); game.backgroundDriftPlanets.splice(dp, 1); } } // Sparkle and nebula arrays for lively background if (!game.backgroundSparkles) game.backgroundSparkles = []; if (!game.backgroundNebulas) game.backgroundNebulas = []; if (!game.backgroundAuroras) game.backgroundAuroras = []; // --- Add more planets, flying UFOs, and large moving asteroids to the background --- if (!game.backgroundUFOs) game.backgroundUFOs = []; if (!game.backgroundAsteroids) game.backgroundAsteroids = []; // --- Animate Planets --- for (var i = backgroundPlanets.length - 1; i >= 0; i--) { var p = backgroundPlanets[i]; // Parallax horizontal movement for planets (move left, speed up with game speed) // Make background move faster/slower based on Nyan Cat's movement (if being dragged) var parallaxSpeed = (0.7 + speed * 0.18) * (1 + p.drift * 2); if (dragNode === nyanCat && typeof nyanCat.lastX !== "undefined") { // If Nyan Cat is being dragged, adjust parallax based on delta X var deltaX = nyanCat.x - nyanCat.lastX; // Planets move opposite to Nyan Cat's movement for parallax parallaxSpeed += -deltaX * (0.08 + p.drift * 0.12); } p.x -= parallaxSpeed; // If planet is off screen to the left, remove and spawn a new one at right if (p.x < -500) { p.destroy(); backgroundPlanets.splice(i, 1); // Randomly pick a planet type var planetTypes = ['planetBlue', 'planetGreen', 'planetPurple', 'planetRed', 'planetYellow']; var newId = planetTypes[Math.floor(Math.random() * planetTypes.length)]; var newScale = 0.8 + Math.random() * 0.8; var newAlpha = 0.12 + Math.random() * 0.13; var newDrift = 0.04 + Math.random() * 0.08; var newDriftMag = 18 + Math.random() * 30; var newY = 300 + Math.random() * (GAME_BOTTOM - 600); var newPlanet = LK.getAsset(newId, { anchorX: 0.5, anchorY: 0.5 }); newPlanet.x = GAME_RIGHT + 500 + Math.random() * 400; newPlanet.y = newY; newPlanet.scaleX = newPlanet.scaleY = newScale; newPlanet.alpha = newAlpha; newPlanet.drift = newDrift; newPlanet.driftMag = newDriftMag; backgroundPlanets.push(newPlanet); game.addChildAt(newPlanet, 0); continue; } // Subtle drifting p.x += Math.sin(LK.ticks * p.drift + i) * 0.2; p.y += Math.cos(LK.ticks * p.drift + i) * 0.2; // Subtle alpha pulsing for glow p.alpha = Math.abs(Math.sin(LK.ticks * 0.008 + i)) * 0.08 + 0.13 + p.drift * 0.7; // Twinkle effect: scale planets up/down slightly for more life var twinkle = 1 + Math.sin(LK.ticks * 0.04 + i * 1.7) * 0.018; p.scaleX = p.scaleY = (p.scaleX || 1) * twinkle; } // --- Flying UFOs (background) --- if (game.backgroundUFOs.length < 2 && Math.random() < 0.04) { var ufo = LK.getAsset('ufo', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7 + Math.random() * 0.5, scaleY: 0.7 + Math.random() * 0.5 }); ufo.x = GAME_RIGHT + 300 + Math.random() * 400; ufo.y = 200 + Math.random() * (GAME_BOTTOM - 400); ufo.alpha = 0.7 + Math.random() * 0.2; ufo._speed = 9 + Math.random() * 4; ufo._drift = 0.04 + Math.random() * 0.09; ufo._driftPhase = Math.random() * Math.PI * 2; // Add a glow under the UFO for effect ufo._glow = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.38 + Math.random() * 0.18, scaleY: 0.18 + Math.random() * 0.12 }); ufo._glow.x = 0; ufo._glow.y = ufo.height * 0.22; ufo._glow.alpha = 0.18; ufo._glow.tint = 0x4a90e2; ufo.addChildAt(ufo._glow, 0); game.backgroundUFOs.push(ufo); game.addChild(ufo); } // --- Animated Satellites (background) --- if (!game.backgroundSatellites) game.backgroundSatellites = []; if (game.backgroundSatellites.length < 2 && Math.random() < 0.03) { // Use 'rainbow' asset as a placeholder for a satellite body, with a star as a solar panel var sat = LK.getAsset('rainbow', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5 + Math.random() * 0.4, scaleY: 0.18 + Math.random() * 0.12 }); sat.x = GAME_RIGHT + 200 + Math.random() * 600; sat.y = 200 + Math.random() * (GAME_BOTTOM - 400); sat.alpha = 0.19 + Math.random() * 0.13; sat.tint = 0x4a90e2 + Math.floor(Math.random() * 0x222222); // blueish sat._speed = 6 + Math.random() * 3; sat._drift = 0.03 + Math.random() * 0.07; sat._driftPhase = Math.random() * Math.PI * 2; sat._rotSpeed = 0.01 + Math.random() * 0.02; // Add solar panel (star) to each side var panelL = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18, scaleY: 0.18 }); panelL.x = -60; panelL.y = 0; panelL.alpha = 0.18; panelL.tint = 0xf9d423; var panelR = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18, scaleY: 0.18 }); panelR.x = 60; panelR.y = 0; panelR.alpha = 0.18; panelR.tint = 0xf9d423; sat.addChildAt(panelL, 0); sat.addChildAt(panelR, 0); game.backgroundSatellites.push(sat); game.addChild(sat); } // Animate satellites if (game.backgroundSatellites) { for (var s = game.backgroundSatellites.length - 1; s >= 0; s--) { var sat = game.backgroundSatellites[s]; sat.x -= sat._speed; sat._driftPhase += sat._drift; sat.y += Math.sin(sat._driftPhase) * 1.2; sat.rotation = (sat.rotation || 0) + sat._rotSpeed; // Remove if off screen if (sat.x < -400) { if (sat.destroy) sat.destroy(); game.backgroundSatellites.splice(s, 1); } } } // Animate UFOs for (var u = game.backgroundUFOs.length - 1; u >= 0; u--) { var ufo = game.backgroundUFOs[u]; ufo.x -= ufo._speed; ufo._driftPhase += ufo._drift; ufo.y += Math.sin(ufo._driftPhase) * 1.2; ufo._glow.alpha = 0.13 + Math.abs(Math.sin(LK.ticks * 0.09 + u)) * 0.13; // Remove if off screen if (ufo.x < -400) { if (ufo.destroy) ufo.destroy(); game.backgroundUFOs.splice(u, 1); } } // --- Large Asteroids (background) --- if (game.backgroundAsteroids.length < 2 && Math.random() < 0.03) { // Use 'planetRed' or 'planetPurple' as a placeholder for big asteroid, squashed and tinted var asteroidTypes = ['planetRed', 'planetPurple']; var asteroidId = asteroidTypes[Math.floor(Math.random() * asteroidTypes.length)]; var asteroid = LK.getAsset(asteroidId, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7 + Math.random() * 0.7, scaleY: 0.38 + Math.random() * 0.22 }); asteroid.x = GAME_RIGHT + 600 + Math.random() * 400; asteroid.y = 200 + Math.random() * (GAME_BOTTOM - 400); asteroid.alpha = 0.19 + Math.random() * 0.13; asteroid.tint = 0x888888 + Math.floor(Math.random() * 0x222222); // grayish asteroid._speed = 10 + Math.random() * 6; asteroid._drift = 0.03 + Math.random() * 0.07; asteroid._driftPhase = Math.random() * Math.PI * 2; asteroid._rotSpeed = 0.01 + Math.random() * 0.02; game.backgroundAsteroids.push(asteroid); game.addChild(asteroid); } // --- Space Debris (background) --- if (!game.backgroundDebris) game.backgroundDebris = []; if (game.backgroundDebris.length < 3 && Math.random() < 0.04) { // Use 'rainbow' or 'planetYellow' as placeholder for debris var debrisTypes = ['rainbow', 'planetYellow']; var debrisId = debrisTypes[Math.floor(Math.random() * debrisTypes.length)]; var debris = LK.getAsset(debrisId, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18 + Math.random() * 0.22, scaleY: 0.18 + Math.random() * 0.22 }); debris.x = GAME_RIGHT + 200 + Math.random() * 800; debris.y = 200 + Math.random() * (GAME_BOTTOM - 400); debris.alpha = 0.13 + Math.random() * 0.13; debris.tint = 0x888888 + Math.floor(Math.random() * 0x222222); debris._speed = 8 + Math.random() * 4; debris._drift = 0.04 + Math.random() * 0.09; debris._driftPhase = Math.random() * Math.PI * 2; debris._rotSpeed = 0.02 + Math.random() * 0.03; game.backgroundDebris.push(debris); game.addChild(debris); } // Animate debris if (game.backgroundDebris) { for (var d = game.backgroundDebris.length - 1; d >= 0; d--) { var debris = game.backgroundDebris[d]; debris.x -= debris._speed; debris._driftPhase += debris._drift; debris.y += Math.sin(debris._driftPhase) * 1.2; debris.rotation = (debris.rotation || 0) + debris._rotSpeed; // Remove if off screen if (debris.x < -400) { if (debris.destroy) debris.destroy(); game.backgroundDebris.splice(d, 1); } } } // Animate asteroids for (var a = game.backgroundAsteroids.length - 1; a >= 0; a--) { var asteroid = game.backgroundAsteroids[a]; asteroid.x -= asteroid._speed; asteroid._driftPhase += asteroid._drift; asteroid.y += Math.sin(asteroid._driftPhase) * 2.2; asteroid.rotation = (asteroid.rotation || 0) + asteroid._rotSpeed; // Remove if off screen if (asteroid.x < -600) { if (asteroid.destroy) asteroid.destroy(); game.backgroundAsteroids.splice(a, 1); } } // --- Sparkle background effect --- if (game.backgroundSparkles.length < 32 && Math.random() < 0.18) { // Add a new sparkle at random position, random size var sparkle = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.13 + Math.random() * 0.11, scaleY: 0.13 + Math.random() * 0.11 }); sparkle.x = Math.random() * (GAME_RIGHT + 400) - 200; sparkle.y = Math.random() * (GAME_BOTTOM + 400) - 200; sparkle.alpha = 0.13 + Math.random() * 0.13; sparkle._twinklePhase = Math.random() * Math.PI * 2; sparkle._twinkleSpeed = 0.04 + Math.random() * 0.07; sparkle._baseAlpha = sparkle.alpha; sparkle._baseScale = sparkle.scaleX; game.backgroundSparkles.push(sparkle); game.addChildAt(sparkle, 0); } // --- Parallax dust particles for extra movement --- if (!game.backgroundDust) game.backgroundDust = []; if (game.backgroundDust.length < 18 && Math.random() < 0.13) { var dust = LK.getAsset('cloud', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18 + Math.random() * 0.22, scaleY: 0.18 + Math.random() * 0.22 }); dust.x = Math.random() * (GAME_RIGHT + 400) - 200; dust.y = Math.random() * (GAME_BOTTOM + 400) - 200; dust.alpha = 0.06 + Math.random() * 0.07; dust._speed = 0.13 + Math.random() * 0.09; dust._drift = 0.04 + Math.random() * 0.09; dust._driftPhase = Math.random() * Math.PI * 2; game.backgroundDust.push(dust); game.addChildAt(dust, 0); } // Animate dust for (var d = game.backgroundDust.length - 1; d >= 0; d--) { var dust = game.backgroundDust[d]; dust.x -= dust._speed; dust._driftPhase += dust._drift; dust.y += Math.sin(dust._driftPhase) * 0.7; // Subtle alpha pulsing dust.alpha = Math.abs(Math.sin(LK.ticks * 0.009 + d)) * 0.03 + 0.06; // Remove if off screen if (dust.x < -400 || dust.y < -400 || dust.y > GAME_BOTTOM + 400) { if (dust.destroy) dust.destroy(); game.backgroundDust.splice(d, 1); } } // Animate sparkles for (var s = game.backgroundSparkles.length - 1; s >= 0; s--) { var sparkle = game.backgroundSparkles[s]; // Twinkle alpha and scale sparkle._twinklePhase += sparkle._twinkleSpeed; sparkle.alpha = sparkle._baseAlpha * (0.7 + 0.6 * Math.abs(Math.sin(sparkle._twinklePhase))); sparkle.scaleX = sparkle.scaleY = sparkle._baseScale * (0.9 + 0.2 * Math.abs(Math.cos(sparkle._twinklePhase * 0.7))); // Slow drift sparkle.x += Math.sin(sparkle._twinklePhase * 0.5) * 0.13; sparkle.y += Math.cos(sparkle._twinklePhase * 0.5) * 0.13; // Remove if off screen if (sparkle.x < -300 || sparkle.x > GAME_RIGHT + 300 || sparkle.y < -300 || sparkle.y > GAME_BOTTOM + 300) { if (sparkle.destroy) sparkle.destroy(); game.backgroundSparkles.splice(s, 1); } } // --- Nebula cloud effect (soft colored clouds drifting) --- if (game.backgroundNebulas.length < 5 && Math.random() < 0.04) { var nebulaColors = [0xf9d423, 0x9b59b6, 0x4a90e2, 0x7ed957, 0xe94e77]; var color = nebulaColors[Math.floor(Math.random() * nebulaColors.length)]; var nebula = LK.getAsset('cloud', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2 + Math.random() * 1.8, scaleY: 1.2 + Math.random() * 1.8 }); nebula.x = GAME_RIGHT + 400 + Math.random() * 400; nebula.y = 200 + Math.random() * (GAME_BOTTOM - 400); nebula.alpha = 0.08 + Math.random() * 0.08; nebula.tint = color; nebula._speed = 0.18 + Math.random() * 0.22; nebula._drift = 0.12 + Math.random() * 0.13; nebula._driftPhase = Math.random() * Math.PI * 2; game.backgroundNebulas.push(nebula); game.addChildAt(nebula, 0); } // Animate nebulas for (var n = game.backgroundNebulas.length - 1; n >= 0; n--) { var nebula = game.backgroundNebulas[n]; nebula.x -= nebula._speed; nebula._driftPhase += nebula._drift; nebula.y += Math.sin(nebula._driftPhase) * 0.7; // Subtle alpha pulsing nebula.alpha = Math.abs(Math.sin(LK.ticks * 0.006 + n)) * 0.04 + 0.08; // Remove if off screen if (nebula.x < -600) { if (nebula.destroy) nebula.destroy(); game.backgroundNebulas.splice(n, 1); } } // --- Aurora band effect (animated colored bands drifting horizontally) --- if (game.backgroundAuroras.length < 3 && Math.random() < 0.03) { var auroraColors = [0x7ed957, 0x4a90e2, 0xfe6cd1, 0xf9d423, 0x9b59b6]; var color = auroraColors[Math.floor(Math.random() * auroraColors.length)]; var aurora = LK.getAsset('rainbow', { anchorX: 0.5, anchorY: 0.5, scaleX: 18 + Math.random() * 6, scaleY: 0.7 + Math.random() * 0.5 }); aurora.x = GAME_RIGHT + 800 + Math.random() * 400; aurora.y = 400 + Math.random() * (GAME_BOTTOM - 800); aurora.alpha = 0.09 + Math.random() * 0.07; aurora.tint = color; aurora._speed = 0.11 + Math.random() * 0.13; aurora._wavePhase = Math.random() * Math.PI * 2; aurora._waveSpeed = 0.008 + Math.random() * 0.012; aurora._baseY = aurora.y; game.backgroundAuroras.push(aurora); game.addChildAt(aurora, 0); } // Animate auroras for (var a = game.backgroundAuroras.length - 1; a >= 0; a--) { var aurora = game.backgroundAuroras[a]; aurora.x -= aurora._speed; aurora._wavePhase += aurora._waveSpeed; aurora.y = aurora._baseY + Math.sin(aurora._wavePhase + a) * 38; // Subtle alpha pulsing aurora.alpha = Math.abs(Math.sin(LK.ticks * 0.004 + a)) * 0.05 + 0.09; // Remove if off screen if (aurora.x < -1200) { if (aurora.destroy) aurora.destroy(); game.backgroundAuroras.splice(a, 1); } } // --- Comet trail effect (fast-moving, glowing comets with fading tails) --- if (!game.backgroundComets) game.backgroundComets = []; if (game.backgroundComets.length < 4 && Math.random() < 0.04) { var comet = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.22 + Math.random() * 0.18, scaleY: 0.22 + Math.random() * 0.18 }); comet.x = -200 - Math.random() * 400; comet.y = 200 + Math.random() * (GAME_BOTTOM - 400); comet.alpha = 0.19 + Math.random() * 0.13; comet._speed = 18 + Math.random() * 12; comet._angle = Math.PI * (0.01 + Math.random() * 0.08); // slight downward comet._tail = []; comet._tailColor = [0xf9d423, 0x9b59b6, 0x4a90e2, 0x7ed957, 0xe94e77][Math.floor(Math.random() * 5)]; // Add a glow for more dynamic effect comet._glow = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: comet.scaleX * 2.2, scaleY: comet.scaleY * 2.2 }); comet._glow.x = 0; comet._glow.y = 0; comet._glow.alpha = 0.13; comet._glow.tint = comet._tailColor; comet.addChildAt(comet._glow, 0); game.backgroundComets.push(comet); game.addChildAt(comet, 1); } // Animate comets and their tails for (var c = game.backgroundComets.length - 1; c >= 0; c--) { var comet = game.backgroundComets[c]; // Move comet comet.x += Math.cos(comet._angle) * comet._speed; comet.y += Math.sin(comet._angle) * comet._speed; // Fade out slightly comet.alpha -= 0.002 + Math.random() * 0.002; if (comet._glow) { comet._glow.alpha = comet.alpha * 0.5; comet._glow.scaleX = comet._glow.scaleY = comet.scaleX * (2.1 + Math.sin(LK.ticks * 0.13 + c) * 0.2); } // Store tail positions if (!comet._tail) comet._tail = []; comet._tail.unshift({ x: comet.x, y: comet.y, alpha: comet.alpha, scale: comet.scaleX }); if (comet._tail.length > 14) comet._tail.pop(); // Draw tail as faded stars for (var t = 1; t < comet._tail.length; t += 2) { var tail = comet._tail[t]; if (!tail._sprite) { tail._sprite = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: comet.scaleX * (1 - t * 0.06), scaleY: comet.scaleY * (1 - t * 0.06) }); tail._sprite.x = tail.x; tail._sprite.y = tail.y; tail._sprite.alpha = comet.alpha * (0.5 - t * 0.04); tail._sprite.tint = comet._tailColor; game.addChildAt(tail._sprite, 0); } else { tail._sprite.x = tail.x; tail._sprite.y = tail.y; tail._sprite.alpha = comet.alpha * (0.5 - t * 0.04); tail._sprite.scaleX = tail._sprite.scaleY = comet.scaleX * (1 - t * 0.06); } } // Remove if off screen if (comet.x > GAME_RIGHT + 400 || comet.y > GAME_BOTTOM + 400 || comet.alpha < 0.01) { // Remove tail sprites for (var t = 1; t < comet._tail.length; t += 2) { var tail = comet._tail[t]; if (tail._sprite && tail._sprite.destroy) tail._sprite.destroy(); } if (comet._glow && comet._glow.destroy) comet._glow.destroy(); if (comet.destroy) comet.destroy(); game.backgroundComets.splice(c, 1); } } function spawnBackgroundPlanets() { // Remove any existing for (var i = 0; i < backgroundPlanets.length; i++) { backgroundPlanets[i].destroy(); } backgroundPlanets = []; // Place a few planets at random positions, different depths/colors var planetDefs = [{ id: 'planetBlue', x: 900, y: 400, scale: 1.2, alpha: 0.22, drift: 0.08, driftMag: 40 }, { id: 'planetGreen', x: 3200, y: 600, scale: 1.1, alpha: 0.18, drift: 0.06, driftMag: 30 }, { id: 'planetPurple', x: 2600, y: 1700, scale: 1.4, alpha: 0.16, drift: 0.07, driftMag: 36 }, { id: 'planetRed', x: 1800, y: 1400, scale: 1.0, alpha: 0.19, drift: 0.09, driftMag: 28 }, { id: 'planetYellow', x: 3400, y: 1800, scale: 0.9, alpha: 0.13, drift: 0.05, driftMag: 22 }]; for (var i = 0; i < planetDefs.length; i++) { var def = planetDefs[i]; var planet = LK.getAsset(def.id, { anchorX: 0.5, anchorY: 0.5 }); planet.x = def.x; planet.y = def.y; planet.scaleX = planet.scaleY = def.scale; planet.alpha = def.alpha; planet.drift = def.drift; planet.driftMag = def.driftMag; backgroundPlanets.push(planet); game.addChildAt(planet, 0); // Always behind everything } } spawnBackgroundPlanets(); // Music // Sound effects // Rainbow trail // Treat (pop tart) // Obstacle (star) // Obstacle (cloud) // Nyan Cat (main character) // Game area margins var GAME_TOP = 0; var GAME_BOTTOM = 2160; var GAME_LEFT = 0; var GAME_RIGHT = 3840; // Avoid top left 100x100 for menu var SAFE_TOP = 120; // Main character var nyanCat = new NyanCat(); game.addChild(nyanCat); // Center Nyan Cat horizontally, place at 60% height nyanCat.x = 3840 * 0.25; nyanCat.y = 2160 * 0.6; var nyanCatBaseY = nyanCat.y; // --- In-Game UI Overlay --- // Score display (smaller, always visible at top center) var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = 2048; scoreTxt.y = 20; LK.gui.top.addChild(scoreTxt); // Pause button (top right, avoid top left 100x100) var pauseBtnBg = LK.getAsset('planetPurple', { anchorX: 0.5, anchorY: 0.5 }); pauseBtnBg.x = 2048 * 2 - 180; pauseBtnBg.y = 100; pauseBtnBg.scaleX = pauseBtnBg.scaleY = 0.7; pauseBtnBg.alpha = 0.85; LK.gui.top.addChild(pauseBtnBg); var pauseBtnText = new Text2('II', { size: 90, fill: "#fff" }); pauseBtnText.anchor.set(0.5, 0.5); pauseBtnText.x = pauseBtnBg.x; pauseBtnText.y = pauseBtnBg.y; LK.gui.top.addChild(pauseBtnText); // Pause button interaction pauseBtnBg.down = function (x, y, obj) { // Pause the game and show the menu overlay if (!mainMenuOverlay.visible) { mainMenuOverlay.visible = true; game.paused = true; createMenuBackground(); LK.stopMusic(); } }; pauseBtnText.down = pauseBtnBg.down; // Arrays for obstacles and treats var obstacles = []; var treats = []; // Difficulty parameters var baseSpeed = 12; var speed = baseSpeed; var spawnInterval = 70; // ticks between spawns var treatInterval = 110; // ticks between treat spawns var minSpawnInterval = 30; var maxSpeed = 32; // Dragging var dragNode = null; // Last collision state var lastHit = false; // Play music LK.playMusic('nyanMusic'); // Helper: collision check (AABB) function isColliding(a, b) { var ab = a.getCollisionBounds(); var bb = b.getCollisionBounds(); return ab.x < bb.x + bb.width && ab.x + ab.width > bb.x && ab.y < bb.y + bb.height && ab.y + ab.height > bb.y; } // Move handler (drag Nyan Cat) function handleMove(x, y, obj) { if (dragNode) { // Clamp to game area, avoid top left 100x100 var cat = dragNode; var bounds = cat.getCollisionBounds(); var halfW = bounds.width / 2; var halfH = bounds.height / 2; var minX = GAME_LEFT + halfW; var maxX = GAME_RIGHT - halfW; var minY = Math.max(GAME_TOP + halfH, SAFE_TOP + halfH); var maxY = GAME_BOTTOM - halfH; cat.x = Math.max(minX, Math.min(maxX, x)); cat.y = Math.max(minY, Math.min(maxY, y)); } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if touch is on Nyan Cat var bounds = nyanCat.getCollisionBounds(); if (x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height) { dragNode = nyanCat; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; // Game update loop game.update = function () { // Only planets are used for the space background; no starfield, clouds, or other backgrounds // Animate shooting stars for lively background if (!game.shootingStars) game.shootingStars = []; // Spawn a shooting star at random intervals if (LK.ticks % 23 === 0 && Math.random() < 0.45) { var star = new ShootingStar(); // Start at random X on left, random Y in upper half star.x = Math.random() * 1200; star.y = 80 + Math.random() * 900; game.shootingStars.push(star); game.addChildAt(star, 1); // Behind main gameplay } // Update and clean up shooting stars for (var s = game.shootingStars.length - 1; s >= 0; s--) { var star = game.shootingStars[s]; if (star.destroyed || star.alpha <= 0.01 || star.x > GAME_RIGHT + 200 || star.y > GAME_BOTTOM + 200) { if (!star.destroyed) star.destroy(); game.shootingStars.splice(s, 1); continue; } star.update(); } // Increase difficulty over time if (LK.ticks % 180 === 0 && speed < maxSpeed) { speed += 1.2; spawnInterval = Math.max(minSpawnInterval, spawnInterval - 4); } // Spawn obstacles if (LK.ticks % spawnInterval === 0) { var obs = new Obstacle(); obs.speed = speed; // Random Y, avoid top 100px var asset = obs.children[0]; var minY = SAFE_TOP + asset.height / 2; var maxY = GAME_BOTTOM - asset.height / 2; obs.x = GAME_RIGHT + asset.width / 2 + 10; obs.y = Math.random() * (maxY - minY) + minY; obstacles.push(obs); game.addChild(obs); } // Spawn treats if (LK.ticks % treatInterval === 0) { var treat = new Treat(); treat.speed = speed * 0.95; var asset = treat.children[0]; var minY = SAFE_TOP + asset.height / 2; var maxY = GAME_BOTTOM - asset.height / 2; treat.x = GAME_RIGHT + asset.width / 2 + 10; treat.y = Math.random() * (maxY - minY) + minY; treats.push(treat); game.addChild(treat); } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Twinkle and pulse for obstacles (clouds/stars) if (obs.children && obs.children.length > 1) { var obsSprite = obs.children[1]; obsSprite.rotation = Math.sin(LK.ticks * 0.09 + i) * 0.13; obsSprite.scaleX = 1 + Math.sin(LK.ticks * 0.15 + i) * 0.09; obsSprite.scaleY = 1 + Math.cos(LK.ticks * 0.13 + i) * 0.09; } // Remove if off screen if (obs.x < -300) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with Nyan Cat var hit = isColliding(obs, nyanCat); if (hit && !lastHit) { // Flash, play sound, game over nyanCat.flash(); LK.getSound('hit').play(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); lastHit = true; break; // Stop further checks } } // Update treats for (var j = treats.length - 1; j >= 0; j--) { var treat = treats[j]; treat.update(); // Twinkle effect for treats (make them pulse and rotate for more life) if (treat.children && treat.children.length > 1) { var treatSprite = treat.children[1]; treatSprite.rotation = Math.sin(LK.ticks * 0.13 + j) * 0.18; treatSprite.scaleX = 1 + Math.sin(LK.ticks * 0.19 + j) * 0.13; treatSprite.scaleY = 1 + Math.cos(LK.ticks * 0.17 + j) * 0.13; } // Remove if off screen if (treat.x < -200) { treat.destroy(); treats.splice(j, 1); continue; } // Collision with Nyan Cat if (isColliding(treat, nyanCat)) { LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('collect').play(); // Animate treat tween(treat, { scaleX: 2.1, scaleY: 2.1, alpha: 0 }, { duration: 220, ease: "outBack", onFinish: function onFinish() { treat.destroy(); } }); treats.splice(j, 1); continue; } } // Track Nyan Cat's lastX for parallax if (typeof nyanCat.lastX === "undefined") nyanCat.lastX = nyanCat.x; // Nyan Cat idle bobbing and lively animation if (!dragNode) { nyanCat.y = nyanCatBaseY + Math.sin(LK.ticks * 0.08) * 22; // Subtle rotation and scale for lively effect if (nyanCat.children && nyanCat.children.length > 1) { var catSprite = nyanCat.children[1]; catSprite.rotation = Math.sin(LK.ticks * 0.07) * 0.08; catSprite.scaleX = 1 + Math.sin(LK.ticks * 0.11) * 0.04; catSprite.scaleY = 1 + Math.cos(LK.ticks * 0.13) * 0.04; } // Subtle color pulsing for rainbow trail if (nyanCat.children && nyanCat.children.length > 0) { var rainbowSprite = nyanCat.children[0]; var baseTint = 0xffe0fa; var pulse = Math.floor(0x20 * (1 + Math.sin(LK.ticks * 0.09))); // Animate tint between pink and yellowish rainbowSprite.tint = 0xffe0fa + (pulse << 8); } } // Update lastX for next frame nyanCat.lastX = nyanCat.x; // Reset lastHit if not colliding if (!obstacles.some(function (obs) { return isColliding(obs, nyanCat); })) { lastHit = false; } }; // Reset score and all game state on game start LK.setScore(0); scoreTxt.setText('0'); // Remove all obstacles and treats from game for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; for (var j = 0; j < treats.length; j++) { treats[j].destroy(); } treats = []; // Reset Nyan Cat position and base Y nyanCat.x = 3840 * 0.25; nyanCat.y = 2160 * 0.6; nyanCatBaseY = nyanCat.y; // Reset difficulty speed = baseSpeed; spawnInterval = 70; treatInterval = 110; // Reset drag and collision state dragNode = null; lastHit = false;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Nyan Cat class
var NyanCat = Container.expand(function () {
var self = Container.call(this);
// Rainbow trail (visual only, not collidable)
var rainbow = self.attachAsset('rainbow', {
anchorX: 1,
anchorY: 0.5,
x: -90,
y: 0,
scaleY: 1.2
});
// Add a soft highlight to rainbow for polish
rainbow.alpha = 0.92;
rainbow.tint = 0xffe0fa;
// Add additional rainbow bands for a lively animated effect
self.rainbowBands = [];
var rainbowColors = [0xfe6cd1, 0xf9d423, 0x7ed957, 0x4a90e2, 0x9b59b6, 0xffffff];
for (var i = 0; i < rainbowColors.length; i++) {
var band = self.attachAsset('rainbow', {
anchorX: 1,
anchorY: 0.5,
x: -90,
y: (i - 2.5) * 18,
// stack vertically
scaleY: 0.18,
scaleX: 1.0
});
band.alpha = 0.82;
band.tint = rainbowColors[i];
self.addChildAt(band, i);
self.rainbowBands.push(band);
}
// Nyan Cat sprite
var cat = self.attachAsset('nyanCat', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Add a soft shadow to Nyan Cat for depth
cat.alpha = 1;
cat.tint = 0xffffff;
self.catShadow = LK.getAsset('nyanCat', {
anchorX: 0.5,
anchorY: 0.5,
x: 8,
y: 18
});
self.catShadow.alpha = 0.22;
self.catShadow.tint = 0x000000;
self.addChildAt(self.catShadow, 0);
// For collision, use the cat's bounds (not rainbow)
self.getCollisionBounds = function () {
return {
x: self.x - cat.width / 2,
y: self.y - cat.height / 2,
width: cat.width,
height: cat.height
};
};
// Flash effect on hit
self.flash = function () {
tween(cat, {
alpha: 0.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(cat, {
alpha: 1
}, {
duration: 120
});
}
});
};
// Rainbow parallax movement for quality polish
self.update = function () {
// Rainbow trail parallax: slight horizontal movement for visual polish
rainbow.x = -90 + Math.sin(LK.ticks * 0.12) * 12;
// Animate rainbow bands for a lively, wavy effect
for (var i = 0; i < self.rainbowBands.length; i++) {
var band = self.rainbowBands[i];
// Wavy movement: each band has a phase offset
band.x = -90 + Math.sin(LK.ticks * 0.12 + i * 0.5) * (12 + i * 2);
band.y = (i - 2.5) * 18 + Math.sin(LK.ticks * 0.18 + i * 0.7) * 8;
// Animate alpha for shimmer
band.alpha = 0.7 + 0.25 * Math.abs(Math.sin(LK.ticks * 0.09 + i));
// Animate scale for a breathing effect
band.scaleX = 1.0 + 0.13 * Math.sin(LK.ticks * 0.11 + i * 0.8);
}
};
return self;
});
// Obstacle class (cloud or star)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Randomly choose cloud or star
var isStar = Math.random() < 0.4;
var assetId = isStar ? 'star' : 'cloud';
var asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add soft shadow for depth
self.shadow = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
x: 10,
y: 18
});
self.shadow.alpha = 0.18;
self.shadow.tint = 0x000000;
self.addChildAt(self.shadow, 0);
self.isStar = isStar;
// For collision
self.getCollisionBounds = function () {
return {
x: self.x - asset.width / 2,
y: self.y - asset.height / 2,
width: asset.width,
height: asset.height
};
};
// Speed will be set on spawn
self.speed = 0;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Shooting Star class for lively background
var ShootingStar = Container.expand(function () {
var self = Container.call(this);
// Use the 'star' asset, small and bright
var star = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.32,
scaleY: 0.32
});
self.star = star;
// Randomize speed and angle
self.speed = 18 + Math.random() * 10; //{U} // Reduced speed for slower falling stars
self.angle = Math.PI * (0.18 + Math.random() * 0.12); // ~10deg downward
self.alpha = 0.7 + Math.random() * 0.3;
// Trail effect (simple, fade out)
self.update = function () {
self.x += Math.cos(self.angle) * self.speed;
self.y += Math.sin(self.angle) * self.speed;
self.alpha -= 0.018 + Math.random() * 0.008;
if (self.alpha <= 0.01) {
self.destroy();
}
};
return self;
});
// Treat class (collectible)
var Treat = Container.expand(function () {
var self = Container.call(this);
var treat = self.attachAsset('treat', {
anchorX: 0.5,
anchorY: 0.5
});
// Add soft shadow for treat
self.shadow = self.attachAsset('treat', {
anchorX: 0.5,
anchorY: 0.5,
x: 10,
y: 18
});
self.shadow.alpha = 0.18;
self.shadow.tint = 0x000000;
self.addChildAt(self.shadow, 0);
// For collision
self.getCollisionBounds = function () {
return {
x: self.x - treat.width / 2,
y: self.y - treat.height / 2,
width: treat.width,
height: treat.height
};
};
// Speed will be set on spawn
self.speed = 0;
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- Main Menu Overlay ---
// UFO asset
var mainMenuOverlay = new Container();
mainMenuOverlay.visible = true;
// Hide in-game UI when menu is visible
if (typeof scoreTxt !== "undefined" && scoreTxt !== null) scoreTxt.visible = false;
if (typeof pauseBtnBg !== "undefined" && pauseBtnBg !== null) pauseBtnBg.visible = false;
if (typeof pauseBtnText !== "undefined" && pauseBtnText !== null) pauseBtnText.visible = false;
// Ensure backgroundPlanets is always defined before menu background is created
if (typeof backgroundPlanets === "undefined" || !backgroundPlanets) backgroundPlanets = [];
// Take a screenshot of the game area for menu background (simulate by rendering planets and Nyan Cat in background)
function createMenuBackground() {
// Remove all children from overlay
while (mainMenuOverlay.children.length > 0) mainMenuOverlay.removeChildAt(0);
// Add background planets (simulate by copying their positions)
for (var i = 0; i < backgroundPlanets.length; i++) {
var p = backgroundPlanets[i];
var planet = LK.getAsset(p.assetId || p._assetId || p.id || 'planetBlue', {
anchorX: 0.5,
anchorY: 0.5
});
planet.x = p.x;
planet.y = p.y;
planet.scaleX = planet.scaleY = p.scaleX || 1;
planet.alpha = p.alpha || 0.18;
mainMenuOverlay.addChild(planet);
}
// Add Nyan Cat in the center (large, faded)
var menuCat = LK.getAsset('nyanCat', {
anchorX: 0.5,
anchorY: 0.5
});
menuCat.x = 2048;
menuCat.y = 1200;
menuCat.scaleX = menuCat.scaleY = 2.2;
menuCat.alpha = 0.18;
mainMenuOverlay.addChild(menuCat);
}
// Game Title
var titleText = new Text2('NYAN CAT SPACE RUN', {
size: 220,
fill: "#fff",
font: "Impact, Arial Black, Tahoma"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048;
titleText.y = 420;
mainMenuOverlay.addChild(titleText);
// Play Button
var playBtnBg = LK.getAsset('planetYellow', {
anchorX: 0.5,
anchorY: 0.5
});
playBtnBg.x = 2048;
playBtnBg.y = 1200 + 420;
playBtnBg.scaleX = playBtnBg.scaleY = 2.2;
mainMenuOverlay.addChild(playBtnBg);
var playBtnText = new Text2('OYNA', {
size: 180,
fill: "#222"
});
playBtnText.anchor.set(0.5, 0.5);
playBtnText.x = 2048;
playBtnText.y = 1200 + 420;
mainMenuOverlay.addChild(playBtnText);
// Play button interaction
mainMenuOverlay.down = function (x, y, obj) {
// Check if touch is inside play button
var dx = x - playBtnBg.x;
var dy = y - playBtnBg.y;
var r = playBtnBg.width * playBtnBg.scaleX * 0.5;
if (dx * dx + dy * dy < r * r) {
// Hide menu, start game
mainMenuOverlay.visible = false;
game.paused = false;
// Show in-game UI when menu is hidden
scoreTxt.visible = true;
pauseBtnBg.visible = true;
pauseBtnText.visible = true;
// Make sure in-game UI is visible and up to date
scoreTxt.visible = true;
pauseBtnBg.visible = true;
pauseBtnText.visible = true;
// Reset game state
LK.setScore(0);
scoreTxt.setText('0');
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
obstacles = [];
for (var j = 0; j < treats.length; j++) treats[j].destroy();
treats = [];
nyanCat.x = 3840 * 0.25;
nyanCat.y = 2160 * 0.6;
nyanCatBaseY = nyanCat.y;
speed = baseSpeed;
spawnInterval = 70;
treatInterval = 110;
dragNode = null;
lastHit = false;
// Resume music
LK.playMusic('nyanMusic');
}
};
mainMenuOverlay.move = function (x, y, obj) {};
mainMenuOverlay.up = function (x, y, obj) {};
// Add overlay to GUI (centered, covers all)
LK.gui.center.addChild(mainMenuOverlay);
// Show menu at start
game.paused = true;
createMenuBackground();
// Animate planets in menu
LK.on('tick', function () {
if (mainMenuOverlay.visible) {
// Animate title
titleText.y = 420 + Math.sin(LK.ticks * 0.06) * 24;
titleText.scaleX = titleText.scaleY = 1.0 + Math.sin(LK.ticks * 0.09) * 0.04;
// Animate play button
playBtnBg.scaleX = playBtnBg.scaleY = 2.2 + Math.sin(LK.ticks * 0.13) * 0.13;
playBtnText.scaleX = playBtnText.scaleY = 1.0 + Math.sin(LK.ticks * 0.13) * 0.04;
}
});
// Animate background planets (subtle drifting and glow, and spawn new ones as needed)
var backgroundPlanets = [];
// --- Drifting Planets for Extra Parallax ---
if (!game.backgroundDriftPlanets) game.backgroundDriftPlanets = [];
// Spawn drifting planets if needed
if (game.backgroundDriftPlanets.length < 3 && Math.random() < 0.04) {
var driftPlanetTypes = ['planetBlue', 'planetGreen', 'planetPurple', 'planetRed', 'planetYellow'];
var driftId = driftPlanetTypes[Math.floor(Math.random() * driftPlanetTypes.length)];
var driftScale = 0.7 + Math.random() * 0.7;
var driftAlpha = 0.10 + Math.random() * 0.10;
var driftSpeed = 0.18 + Math.random() * 0.18;
var driftY = 200 + Math.random() * (GAME_BOTTOM - 400);
var driftPlanet = LK.getAsset(driftId, {
anchorX: 0.5,
anchorY: 0.5
});
driftPlanet.x = GAME_RIGHT + 600 + Math.random() * 400;
driftPlanet.y = driftY;
driftPlanet.scaleX = driftPlanet.scaleY = driftScale;
driftPlanet.alpha = driftAlpha;
driftPlanet._speed = driftSpeed;
driftPlanet._drift = 0.03 + Math.random() * 0.07;
driftPlanet._driftPhase = Math.random() * Math.PI * 2;
game.backgroundDriftPlanets.push(driftPlanet);
game.addChildAt(driftPlanet, 0);
}
// Animate drifting planets
for (var dp = game.backgroundDriftPlanets.length - 1; dp >= 0; dp--) {
var driftPlanet = game.backgroundDriftPlanets[dp];
driftPlanet.x -= driftPlanet._speed;
driftPlanet._driftPhase += driftPlanet._drift;
driftPlanet.y += Math.sin(driftPlanet._driftPhase) * 1.2;
// Subtle alpha pulsing
driftPlanet.alpha = Math.abs(Math.sin(LK.ticks * 0.007 + dp)) * 0.06 + 0.10;
// Remove if off screen
if (driftPlanet.x < -600) {
if (driftPlanet.destroy) driftPlanet.destroy();
game.backgroundDriftPlanets.splice(dp, 1);
}
}
// Sparkle and nebula arrays for lively background
if (!game.backgroundSparkles) game.backgroundSparkles = [];
if (!game.backgroundNebulas) game.backgroundNebulas = [];
if (!game.backgroundAuroras) game.backgroundAuroras = [];
// --- Add more planets, flying UFOs, and large moving asteroids to the background ---
if (!game.backgroundUFOs) game.backgroundUFOs = [];
if (!game.backgroundAsteroids) game.backgroundAsteroids = [];
// --- Animate Planets ---
for (var i = backgroundPlanets.length - 1; i >= 0; i--) {
var p = backgroundPlanets[i];
// Parallax horizontal movement for planets (move left, speed up with game speed)
// Make background move faster/slower based on Nyan Cat's movement (if being dragged)
var parallaxSpeed = (0.7 + speed * 0.18) * (1 + p.drift * 2);
if (dragNode === nyanCat && typeof nyanCat.lastX !== "undefined") {
// If Nyan Cat is being dragged, adjust parallax based on delta X
var deltaX = nyanCat.x - nyanCat.lastX;
// Planets move opposite to Nyan Cat's movement for parallax
parallaxSpeed += -deltaX * (0.08 + p.drift * 0.12);
}
p.x -= parallaxSpeed;
// If planet is off screen to the left, remove and spawn a new one at right
if (p.x < -500) {
p.destroy();
backgroundPlanets.splice(i, 1);
// Randomly pick a planet type
var planetTypes = ['planetBlue', 'planetGreen', 'planetPurple', 'planetRed', 'planetYellow'];
var newId = planetTypes[Math.floor(Math.random() * planetTypes.length)];
var newScale = 0.8 + Math.random() * 0.8;
var newAlpha = 0.12 + Math.random() * 0.13;
var newDrift = 0.04 + Math.random() * 0.08;
var newDriftMag = 18 + Math.random() * 30;
var newY = 300 + Math.random() * (GAME_BOTTOM - 600);
var newPlanet = LK.getAsset(newId, {
anchorX: 0.5,
anchorY: 0.5
});
newPlanet.x = GAME_RIGHT + 500 + Math.random() * 400;
newPlanet.y = newY;
newPlanet.scaleX = newPlanet.scaleY = newScale;
newPlanet.alpha = newAlpha;
newPlanet.drift = newDrift;
newPlanet.driftMag = newDriftMag;
backgroundPlanets.push(newPlanet);
game.addChildAt(newPlanet, 0);
continue;
}
// Subtle drifting
p.x += Math.sin(LK.ticks * p.drift + i) * 0.2;
p.y += Math.cos(LK.ticks * p.drift + i) * 0.2;
// Subtle alpha pulsing for glow
p.alpha = Math.abs(Math.sin(LK.ticks * 0.008 + i)) * 0.08 + 0.13 + p.drift * 0.7;
// Twinkle effect: scale planets up/down slightly for more life
var twinkle = 1 + Math.sin(LK.ticks * 0.04 + i * 1.7) * 0.018;
p.scaleX = p.scaleY = (p.scaleX || 1) * twinkle;
}
// --- Flying UFOs (background) ---
if (game.backgroundUFOs.length < 2 && Math.random() < 0.04) {
var ufo = LK.getAsset('ufo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7 + Math.random() * 0.5,
scaleY: 0.7 + Math.random() * 0.5
});
ufo.x = GAME_RIGHT + 300 + Math.random() * 400;
ufo.y = 200 + Math.random() * (GAME_BOTTOM - 400);
ufo.alpha = 0.7 + Math.random() * 0.2;
ufo._speed = 9 + Math.random() * 4;
ufo._drift = 0.04 + Math.random() * 0.09;
ufo._driftPhase = Math.random() * Math.PI * 2;
// Add a glow under the UFO for effect
ufo._glow = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.38 + Math.random() * 0.18,
scaleY: 0.18 + Math.random() * 0.12
});
ufo._glow.x = 0;
ufo._glow.y = ufo.height * 0.22;
ufo._glow.alpha = 0.18;
ufo._glow.tint = 0x4a90e2;
ufo.addChildAt(ufo._glow, 0);
game.backgroundUFOs.push(ufo);
game.addChild(ufo);
}
// --- Animated Satellites (background) ---
if (!game.backgroundSatellites) game.backgroundSatellites = [];
if (game.backgroundSatellites.length < 2 && Math.random() < 0.03) {
// Use 'rainbow' asset as a placeholder for a satellite body, with a star as a solar panel
var sat = LK.getAsset('rainbow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5 + Math.random() * 0.4,
scaleY: 0.18 + Math.random() * 0.12
});
sat.x = GAME_RIGHT + 200 + Math.random() * 600;
sat.y = 200 + Math.random() * (GAME_BOTTOM - 400);
sat.alpha = 0.19 + Math.random() * 0.13;
sat.tint = 0x4a90e2 + Math.floor(Math.random() * 0x222222); // blueish
sat._speed = 6 + Math.random() * 3;
sat._drift = 0.03 + Math.random() * 0.07;
sat._driftPhase = Math.random() * Math.PI * 2;
sat._rotSpeed = 0.01 + Math.random() * 0.02;
// Add solar panel (star) to each side
var panelL = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18,
scaleY: 0.18
});
panelL.x = -60;
panelL.y = 0;
panelL.alpha = 0.18;
panelL.tint = 0xf9d423;
var panelR = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18,
scaleY: 0.18
});
panelR.x = 60;
panelR.y = 0;
panelR.alpha = 0.18;
panelR.tint = 0xf9d423;
sat.addChildAt(panelL, 0);
sat.addChildAt(panelR, 0);
game.backgroundSatellites.push(sat);
game.addChild(sat);
}
// Animate satellites
if (game.backgroundSatellites) {
for (var s = game.backgroundSatellites.length - 1; s >= 0; s--) {
var sat = game.backgroundSatellites[s];
sat.x -= sat._speed;
sat._driftPhase += sat._drift;
sat.y += Math.sin(sat._driftPhase) * 1.2;
sat.rotation = (sat.rotation || 0) + sat._rotSpeed;
// Remove if off screen
if (sat.x < -400) {
if (sat.destroy) sat.destroy();
game.backgroundSatellites.splice(s, 1);
}
}
}
// Animate UFOs
for (var u = game.backgroundUFOs.length - 1; u >= 0; u--) {
var ufo = game.backgroundUFOs[u];
ufo.x -= ufo._speed;
ufo._driftPhase += ufo._drift;
ufo.y += Math.sin(ufo._driftPhase) * 1.2;
ufo._glow.alpha = 0.13 + Math.abs(Math.sin(LK.ticks * 0.09 + u)) * 0.13;
// Remove if off screen
if (ufo.x < -400) {
if (ufo.destroy) ufo.destroy();
game.backgroundUFOs.splice(u, 1);
}
}
// --- Large Asteroids (background) ---
if (game.backgroundAsteroids.length < 2 && Math.random() < 0.03) {
// Use 'planetRed' or 'planetPurple' as a placeholder for big asteroid, squashed and tinted
var asteroidTypes = ['planetRed', 'planetPurple'];
var asteroidId = asteroidTypes[Math.floor(Math.random() * asteroidTypes.length)];
var asteroid = LK.getAsset(asteroidId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7 + Math.random() * 0.7,
scaleY: 0.38 + Math.random() * 0.22
});
asteroid.x = GAME_RIGHT + 600 + Math.random() * 400;
asteroid.y = 200 + Math.random() * (GAME_BOTTOM - 400);
asteroid.alpha = 0.19 + Math.random() * 0.13;
asteroid.tint = 0x888888 + Math.floor(Math.random() * 0x222222); // grayish
asteroid._speed = 10 + Math.random() * 6;
asteroid._drift = 0.03 + Math.random() * 0.07;
asteroid._driftPhase = Math.random() * Math.PI * 2;
asteroid._rotSpeed = 0.01 + Math.random() * 0.02;
game.backgroundAsteroids.push(asteroid);
game.addChild(asteroid);
}
// --- Space Debris (background) ---
if (!game.backgroundDebris) game.backgroundDebris = [];
if (game.backgroundDebris.length < 3 && Math.random() < 0.04) {
// Use 'rainbow' or 'planetYellow' as placeholder for debris
var debrisTypes = ['rainbow', 'planetYellow'];
var debrisId = debrisTypes[Math.floor(Math.random() * debrisTypes.length)];
var debris = LK.getAsset(debrisId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18 + Math.random() * 0.22,
scaleY: 0.18 + Math.random() * 0.22
});
debris.x = GAME_RIGHT + 200 + Math.random() * 800;
debris.y = 200 + Math.random() * (GAME_BOTTOM - 400);
debris.alpha = 0.13 + Math.random() * 0.13;
debris.tint = 0x888888 + Math.floor(Math.random() * 0x222222);
debris._speed = 8 + Math.random() * 4;
debris._drift = 0.04 + Math.random() * 0.09;
debris._driftPhase = Math.random() * Math.PI * 2;
debris._rotSpeed = 0.02 + Math.random() * 0.03;
game.backgroundDebris.push(debris);
game.addChild(debris);
}
// Animate debris
if (game.backgroundDebris) {
for (var d = game.backgroundDebris.length - 1; d >= 0; d--) {
var debris = game.backgroundDebris[d];
debris.x -= debris._speed;
debris._driftPhase += debris._drift;
debris.y += Math.sin(debris._driftPhase) * 1.2;
debris.rotation = (debris.rotation || 0) + debris._rotSpeed;
// Remove if off screen
if (debris.x < -400) {
if (debris.destroy) debris.destroy();
game.backgroundDebris.splice(d, 1);
}
}
}
// Animate asteroids
for (var a = game.backgroundAsteroids.length - 1; a >= 0; a--) {
var asteroid = game.backgroundAsteroids[a];
asteroid.x -= asteroid._speed;
asteroid._driftPhase += asteroid._drift;
asteroid.y += Math.sin(asteroid._driftPhase) * 2.2;
asteroid.rotation = (asteroid.rotation || 0) + asteroid._rotSpeed;
// Remove if off screen
if (asteroid.x < -600) {
if (asteroid.destroy) asteroid.destroy();
game.backgroundAsteroids.splice(a, 1);
}
}
// --- Sparkle background effect ---
if (game.backgroundSparkles.length < 32 && Math.random() < 0.18) {
// Add a new sparkle at random position, random size
var sparkle = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.13 + Math.random() * 0.11,
scaleY: 0.13 + Math.random() * 0.11
});
sparkle.x = Math.random() * (GAME_RIGHT + 400) - 200;
sparkle.y = Math.random() * (GAME_BOTTOM + 400) - 200;
sparkle.alpha = 0.13 + Math.random() * 0.13;
sparkle._twinklePhase = Math.random() * Math.PI * 2;
sparkle._twinkleSpeed = 0.04 + Math.random() * 0.07;
sparkle._baseAlpha = sparkle.alpha;
sparkle._baseScale = sparkle.scaleX;
game.backgroundSparkles.push(sparkle);
game.addChildAt(sparkle, 0);
}
// --- Parallax dust particles for extra movement ---
if (!game.backgroundDust) game.backgroundDust = [];
if (game.backgroundDust.length < 18 && Math.random() < 0.13) {
var dust = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18 + Math.random() * 0.22,
scaleY: 0.18 + Math.random() * 0.22
});
dust.x = Math.random() * (GAME_RIGHT + 400) - 200;
dust.y = Math.random() * (GAME_BOTTOM + 400) - 200;
dust.alpha = 0.06 + Math.random() * 0.07;
dust._speed = 0.13 + Math.random() * 0.09;
dust._drift = 0.04 + Math.random() * 0.09;
dust._driftPhase = Math.random() * Math.PI * 2;
game.backgroundDust.push(dust);
game.addChildAt(dust, 0);
}
// Animate dust
for (var d = game.backgroundDust.length - 1; d >= 0; d--) {
var dust = game.backgroundDust[d];
dust.x -= dust._speed;
dust._driftPhase += dust._drift;
dust.y += Math.sin(dust._driftPhase) * 0.7;
// Subtle alpha pulsing
dust.alpha = Math.abs(Math.sin(LK.ticks * 0.009 + d)) * 0.03 + 0.06;
// Remove if off screen
if (dust.x < -400 || dust.y < -400 || dust.y > GAME_BOTTOM + 400) {
if (dust.destroy) dust.destroy();
game.backgroundDust.splice(d, 1);
}
}
// Animate sparkles
for (var s = game.backgroundSparkles.length - 1; s >= 0; s--) {
var sparkle = game.backgroundSparkles[s];
// Twinkle alpha and scale
sparkle._twinklePhase += sparkle._twinkleSpeed;
sparkle.alpha = sparkle._baseAlpha * (0.7 + 0.6 * Math.abs(Math.sin(sparkle._twinklePhase)));
sparkle.scaleX = sparkle.scaleY = sparkle._baseScale * (0.9 + 0.2 * Math.abs(Math.cos(sparkle._twinklePhase * 0.7)));
// Slow drift
sparkle.x += Math.sin(sparkle._twinklePhase * 0.5) * 0.13;
sparkle.y += Math.cos(sparkle._twinklePhase * 0.5) * 0.13;
// Remove if off screen
if (sparkle.x < -300 || sparkle.x > GAME_RIGHT + 300 || sparkle.y < -300 || sparkle.y > GAME_BOTTOM + 300) {
if (sparkle.destroy) sparkle.destroy();
game.backgroundSparkles.splice(s, 1);
}
}
// --- Nebula cloud effect (soft colored clouds drifting) ---
if (game.backgroundNebulas.length < 5 && Math.random() < 0.04) {
var nebulaColors = [0xf9d423, 0x9b59b6, 0x4a90e2, 0x7ed957, 0xe94e77];
var color = nebulaColors[Math.floor(Math.random() * nebulaColors.length)];
var nebula = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2 + Math.random() * 1.8,
scaleY: 1.2 + Math.random() * 1.8
});
nebula.x = GAME_RIGHT + 400 + Math.random() * 400;
nebula.y = 200 + Math.random() * (GAME_BOTTOM - 400);
nebula.alpha = 0.08 + Math.random() * 0.08;
nebula.tint = color;
nebula._speed = 0.18 + Math.random() * 0.22;
nebula._drift = 0.12 + Math.random() * 0.13;
nebula._driftPhase = Math.random() * Math.PI * 2;
game.backgroundNebulas.push(nebula);
game.addChildAt(nebula, 0);
}
// Animate nebulas
for (var n = game.backgroundNebulas.length - 1; n >= 0; n--) {
var nebula = game.backgroundNebulas[n];
nebula.x -= nebula._speed;
nebula._driftPhase += nebula._drift;
nebula.y += Math.sin(nebula._driftPhase) * 0.7;
// Subtle alpha pulsing
nebula.alpha = Math.abs(Math.sin(LK.ticks * 0.006 + n)) * 0.04 + 0.08;
// Remove if off screen
if (nebula.x < -600) {
if (nebula.destroy) nebula.destroy();
game.backgroundNebulas.splice(n, 1);
}
}
// --- Aurora band effect (animated colored bands drifting horizontally) ---
if (game.backgroundAuroras.length < 3 && Math.random() < 0.03) {
var auroraColors = [0x7ed957, 0x4a90e2, 0xfe6cd1, 0xf9d423, 0x9b59b6];
var color = auroraColors[Math.floor(Math.random() * auroraColors.length)];
var aurora = LK.getAsset('rainbow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 18 + Math.random() * 6,
scaleY: 0.7 + Math.random() * 0.5
});
aurora.x = GAME_RIGHT + 800 + Math.random() * 400;
aurora.y = 400 + Math.random() * (GAME_BOTTOM - 800);
aurora.alpha = 0.09 + Math.random() * 0.07;
aurora.tint = color;
aurora._speed = 0.11 + Math.random() * 0.13;
aurora._wavePhase = Math.random() * Math.PI * 2;
aurora._waveSpeed = 0.008 + Math.random() * 0.012;
aurora._baseY = aurora.y;
game.backgroundAuroras.push(aurora);
game.addChildAt(aurora, 0);
}
// Animate auroras
for (var a = game.backgroundAuroras.length - 1; a >= 0; a--) {
var aurora = game.backgroundAuroras[a];
aurora.x -= aurora._speed;
aurora._wavePhase += aurora._waveSpeed;
aurora.y = aurora._baseY + Math.sin(aurora._wavePhase + a) * 38;
// Subtle alpha pulsing
aurora.alpha = Math.abs(Math.sin(LK.ticks * 0.004 + a)) * 0.05 + 0.09;
// Remove if off screen
if (aurora.x < -1200) {
if (aurora.destroy) aurora.destroy();
game.backgroundAuroras.splice(a, 1);
}
}
// --- Comet trail effect (fast-moving, glowing comets with fading tails) ---
if (!game.backgroundComets) game.backgroundComets = [];
if (game.backgroundComets.length < 4 && Math.random() < 0.04) {
var comet = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.22 + Math.random() * 0.18,
scaleY: 0.22 + Math.random() * 0.18
});
comet.x = -200 - Math.random() * 400;
comet.y = 200 + Math.random() * (GAME_BOTTOM - 400);
comet.alpha = 0.19 + Math.random() * 0.13;
comet._speed = 18 + Math.random() * 12;
comet._angle = Math.PI * (0.01 + Math.random() * 0.08); // slight downward
comet._tail = [];
comet._tailColor = [0xf9d423, 0x9b59b6, 0x4a90e2, 0x7ed957, 0xe94e77][Math.floor(Math.random() * 5)];
// Add a glow for more dynamic effect
comet._glow = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: comet.scaleX * 2.2,
scaleY: comet.scaleY * 2.2
});
comet._glow.x = 0;
comet._glow.y = 0;
comet._glow.alpha = 0.13;
comet._glow.tint = comet._tailColor;
comet.addChildAt(comet._glow, 0);
game.backgroundComets.push(comet);
game.addChildAt(comet, 1);
}
// Animate comets and their tails
for (var c = game.backgroundComets.length - 1; c >= 0; c--) {
var comet = game.backgroundComets[c];
// Move comet
comet.x += Math.cos(comet._angle) * comet._speed;
comet.y += Math.sin(comet._angle) * comet._speed;
// Fade out slightly
comet.alpha -= 0.002 + Math.random() * 0.002;
if (comet._glow) {
comet._glow.alpha = comet.alpha * 0.5;
comet._glow.scaleX = comet._glow.scaleY = comet.scaleX * (2.1 + Math.sin(LK.ticks * 0.13 + c) * 0.2);
}
// Store tail positions
if (!comet._tail) comet._tail = [];
comet._tail.unshift({
x: comet.x,
y: comet.y,
alpha: comet.alpha,
scale: comet.scaleX
});
if (comet._tail.length > 14) comet._tail.pop();
// Draw tail as faded stars
for (var t = 1; t < comet._tail.length; t += 2) {
var tail = comet._tail[t];
if (!tail._sprite) {
tail._sprite = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: comet.scaleX * (1 - t * 0.06),
scaleY: comet.scaleY * (1 - t * 0.06)
});
tail._sprite.x = tail.x;
tail._sprite.y = tail.y;
tail._sprite.alpha = comet.alpha * (0.5 - t * 0.04);
tail._sprite.tint = comet._tailColor;
game.addChildAt(tail._sprite, 0);
} else {
tail._sprite.x = tail.x;
tail._sprite.y = tail.y;
tail._sprite.alpha = comet.alpha * (0.5 - t * 0.04);
tail._sprite.scaleX = tail._sprite.scaleY = comet.scaleX * (1 - t * 0.06);
}
}
// Remove if off screen
if (comet.x > GAME_RIGHT + 400 || comet.y > GAME_BOTTOM + 400 || comet.alpha < 0.01) {
// Remove tail sprites
for (var t = 1; t < comet._tail.length; t += 2) {
var tail = comet._tail[t];
if (tail._sprite && tail._sprite.destroy) tail._sprite.destroy();
}
if (comet._glow && comet._glow.destroy) comet._glow.destroy();
if (comet.destroy) comet.destroy();
game.backgroundComets.splice(c, 1);
}
}
function spawnBackgroundPlanets() {
// Remove any existing
for (var i = 0; i < backgroundPlanets.length; i++) {
backgroundPlanets[i].destroy();
}
backgroundPlanets = [];
// Place a few planets at random positions, different depths/colors
var planetDefs = [{
id: 'planetBlue',
x: 900,
y: 400,
scale: 1.2,
alpha: 0.22,
drift: 0.08,
driftMag: 40
}, {
id: 'planetGreen',
x: 3200,
y: 600,
scale: 1.1,
alpha: 0.18,
drift: 0.06,
driftMag: 30
}, {
id: 'planetPurple',
x: 2600,
y: 1700,
scale: 1.4,
alpha: 0.16,
drift: 0.07,
driftMag: 36
}, {
id: 'planetRed',
x: 1800,
y: 1400,
scale: 1.0,
alpha: 0.19,
drift: 0.09,
driftMag: 28
}, {
id: 'planetYellow',
x: 3400,
y: 1800,
scale: 0.9,
alpha: 0.13,
drift: 0.05,
driftMag: 22
}];
for (var i = 0; i < planetDefs.length; i++) {
var def = planetDefs[i];
var planet = LK.getAsset(def.id, {
anchorX: 0.5,
anchorY: 0.5
});
planet.x = def.x;
planet.y = def.y;
planet.scaleX = planet.scaleY = def.scale;
planet.alpha = def.alpha;
planet.drift = def.drift;
planet.driftMag = def.driftMag;
backgroundPlanets.push(planet);
game.addChildAt(planet, 0); // Always behind everything
}
}
spawnBackgroundPlanets();
// Music
// Sound effects
// Rainbow trail
// Treat (pop tart)
// Obstacle (star)
// Obstacle (cloud)
// Nyan Cat (main character)
// Game area margins
var GAME_TOP = 0;
var GAME_BOTTOM = 2160;
var GAME_LEFT = 0;
var GAME_RIGHT = 3840;
// Avoid top left 100x100 for menu
var SAFE_TOP = 120;
// Main character
var nyanCat = new NyanCat();
game.addChild(nyanCat);
// Center Nyan Cat horizontally, place at 60% height
nyanCat.x = 3840 * 0.25;
nyanCat.y = 2160 * 0.6;
var nyanCatBaseY = nyanCat.y;
// --- In-Game UI Overlay ---
// Score display (smaller, always visible at top center)
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.x = 2048;
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
// Pause button (top right, avoid top left 100x100)
var pauseBtnBg = LK.getAsset('planetPurple', {
anchorX: 0.5,
anchorY: 0.5
});
pauseBtnBg.x = 2048 * 2 - 180;
pauseBtnBg.y = 100;
pauseBtnBg.scaleX = pauseBtnBg.scaleY = 0.7;
pauseBtnBg.alpha = 0.85;
LK.gui.top.addChild(pauseBtnBg);
var pauseBtnText = new Text2('II', {
size: 90,
fill: "#fff"
});
pauseBtnText.anchor.set(0.5, 0.5);
pauseBtnText.x = pauseBtnBg.x;
pauseBtnText.y = pauseBtnBg.y;
LK.gui.top.addChild(pauseBtnText);
// Pause button interaction
pauseBtnBg.down = function (x, y, obj) {
// Pause the game and show the menu overlay
if (!mainMenuOverlay.visible) {
mainMenuOverlay.visible = true;
game.paused = true;
createMenuBackground();
LK.stopMusic();
}
};
pauseBtnText.down = pauseBtnBg.down;
// Arrays for obstacles and treats
var obstacles = [];
var treats = [];
// Difficulty parameters
var baseSpeed = 12;
var speed = baseSpeed;
var spawnInterval = 70; // ticks between spawns
var treatInterval = 110; // ticks between treat spawns
var minSpawnInterval = 30;
var maxSpeed = 32;
// Dragging
var dragNode = null;
// Last collision state
var lastHit = false;
// Play music
LK.playMusic('nyanMusic');
// Helper: collision check (AABB)
function isColliding(a, b) {
var ab = a.getCollisionBounds();
var bb = b.getCollisionBounds();
return ab.x < bb.x + bb.width && ab.x + ab.width > bb.x && ab.y < bb.y + bb.height && ab.y + ab.height > bb.y;
}
// Move handler (drag Nyan Cat)
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp to game area, avoid top left 100x100
var cat = dragNode;
var bounds = cat.getCollisionBounds();
var halfW = bounds.width / 2;
var halfH = bounds.height / 2;
var minX = GAME_LEFT + halfW;
var maxX = GAME_RIGHT - halfW;
var minY = Math.max(GAME_TOP + halfH, SAFE_TOP + halfH);
var maxY = GAME_BOTTOM - halfH;
cat.x = Math.max(minX, Math.min(maxX, x));
cat.y = Math.max(minY, Math.min(maxY, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch is on Nyan Cat
var bounds = nyanCat.getCollisionBounds();
if (x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height) {
dragNode = nyanCat;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Game update loop
game.update = function () {
// Only planets are used for the space background; no starfield, clouds, or other backgrounds
// Animate shooting stars for lively background
if (!game.shootingStars) game.shootingStars = [];
// Spawn a shooting star at random intervals
if (LK.ticks % 23 === 0 && Math.random() < 0.45) {
var star = new ShootingStar();
// Start at random X on left, random Y in upper half
star.x = Math.random() * 1200;
star.y = 80 + Math.random() * 900;
game.shootingStars.push(star);
game.addChildAt(star, 1); // Behind main gameplay
}
// Update and clean up shooting stars
for (var s = game.shootingStars.length - 1; s >= 0; s--) {
var star = game.shootingStars[s];
if (star.destroyed || star.alpha <= 0.01 || star.x > GAME_RIGHT + 200 || star.y > GAME_BOTTOM + 200) {
if (!star.destroyed) star.destroy();
game.shootingStars.splice(s, 1);
continue;
}
star.update();
}
// Increase difficulty over time
if (LK.ticks % 180 === 0 && speed < maxSpeed) {
speed += 1.2;
spawnInterval = Math.max(minSpawnInterval, spawnInterval - 4);
}
// Spawn obstacles
if (LK.ticks % spawnInterval === 0) {
var obs = new Obstacle();
obs.speed = speed;
// Random Y, avoid top 100px
var asset = obs.children[0];
var minY = SAFE_TOP + asset.height / 2;
var maxY = GAME_BOTTOM - asset.height / 2;
obs.x = GAME_RIGHT + asset.width / 2 + 10;
obs.y = Math.random() * (maxY - minY) + minY;
obstacles.push(obs);
game.addChild(obs);
}
// Spawn treats
if (LK.ticks % treatInterval === 0) {
var treat = new Treat();
treat.speed = speed * 0.95;
var asset = treat.children[0];
var minY = SAFE_TOP + asset.height / 2;
var maxY = GAME_BOTTOM - asset.height / 2;
treat.x = GAME_RIGHT + asset.width / 2 + 10;
treat.y = Math.random() * (maxY - minY) + minY;
treats.push(treat);
game.addChild(treat);
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Twinkle and pulse for obstacles (clouds/stars)
if (obs.children && obs.children.length > 1) {
var obsSprite = obs.children[1];
obsSprite.rotation = Math.sin(LK.ticks * 0.09 + i) * 0.13;
obsSprite.scaleX = 1 + Math.sin(LK.ticks * 0.15 + i) * 0.09;
obsSprite.scaleY = 1 + Math.cos(LK.ticks * 0.13 + i) * 0.09;
}
// Remove if off screen
if (obs.x < -300) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with Nyan Cat
var hit = isColliding(obs, nyanCat);
if (hit && !lastHit) {
// Flash, play sound, game over
nyanCat.flash();
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
lastHit = true;
break; // Stop further checks
}
}
// Update treats
for (var j = treats.length - 1; j >= 0; j--) {
var treat = treats[j];
treat.update();
// Twinkle effect for treats (make them pulse and rotate for more life)
if (treat.children && treat.children.length > 1) {
var treatSprite = treat.children[1];
treatSprite.rotation = Math.sin(LK.ticks * 0.13 + j) * 0.18;
treatSprite.scaleX = 1 + Math.sin(LK.ticks * 0.19 + j) * 0.13;
treatSprite.scaleY = 1 + Math.cos(LK.ticks * 0.17 + j) * 0.13;
}
// Remove if off screen
if (treat.x < -200) {
treat.destroy();
treats.splice(j, 1);
continue;
}
// Collision with Nyan Cat
if (isColliding(treat, nyanCat)) {
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('collect').play();
// Animate treat
tween(treat, {
scaleX: 2.1,
scaleY: 2.1,
alpha: 0
}, {
duration: 220,
ease: "outBack",
onFinish: function onFinish() {
treat.destroy();
}
});
treats.splice(j, 1);
continue;
}
}
// Track Nyan Cat's lastX for parallax
if (typeof nyanCat.lastX === "undefined") nyanCat.lastX = nyanCat.x;
// Nyan Cat idle bobbing and lively animation
if (!dragNode) {
nyanCat.y = nyanCatBaseY + Math.sin(LK.ticks * 0.08) * 22;
// Subtle rotation and scale for lively effect
if (nyanCat.children && nyanCat.children.length > 1) {
var catSprite = nyanCat.children[1];
catSprite.rotation = Math.sin(LK.ticks * 0.07) * 0.08;
catSprite.scaleX = 1 + Math.sin(LK.ticks * 0.11) * 0.04;
catSprite.scaleY = 1 + Math.cos(LK.ticks * 0.13) * 0.04;
}
// Subtle color pulsing for rainbow trail
if (nyanCat.children && nyanCat.children.length > 0) {
var rainbowSprite = nyanCat.children[0];
var baseTint = 0xffe0fa;
var pulse = Math.floor(0x20 * (1 + Math.sin(LK.ticks * 0.09)));
// Animate tint between pink and yellowish
rainbowSprite.tint = 0xffe0fa + (pulse << 8);
}
}
// Update lastX for next frame
nyanCat.lastX = nyanCat.x;
// Reset lastHit if not colliding
if (!obstacles.some(function (obs) {
return isColliding(obs, nyanCat);
})) {
lastHit = false;
}
};
// Reset score and all game state on game start
LK.setScore(0);
scoreTxt.setText('0');
// Remove all obstacles and treats from game
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
for (var j = 0; j < treats.length; j++) {
treats[j].destroy();
}
treats = [];
// Reset Nyan Cat position and base Y
nyanCat.x = 3840 * 0.25;
nyanCat.y = 2160 * 0.6;
nyanCatBaseY = nyanCat.y;
// Reset difficulty
speed = baseSpeed;
spawnInterval = 70;
treatInterval = 110;
// Reset drag and collision state
dragNode = null;
lastHit = false;
NYAN CAT. In-Game asset. 2d. High contrast. No shadows
DİKENLİ TOP. In-Game asset. 2d. High contrast. No shadows
TAŞ. In-Game asset. 2d. High contrast. No shadows
kurabiye. In-Game asset. 2d. High contrast. No shadows
satürn. In-Game asset. 2d. High contrast. No shadows
neptün. In-Game asset. 2d. High contrast. No shadows