/****
* 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