/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var DarkMatter = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('darkMatter', { anchorX: 0.5, anchorY: 0.5 }); self.health = 10; self.hitCount = 0; self.moveTimer = 0; self.speed = 1; self.direction = 0; self.update = function () { self.moveTimer++; // Change direction every 2 seconds if (self.moveTimer % 120 === 0) { self.direction = Math.random() * Math.PI * 2; } self.x += Math.cos(self.direction) * self.speed; self.y += Math.sin(self.direction) * self.speed; // Keep in bounds self.x = Math.max(100, Math.min(1948, self.x)); self.y = Math.max(100, Math.min(2632, self.y)); // Pulsing dark energy effect graphics.scaleX = 1 + Math.sin(self.moveTimer * 0.15) * 0.3; graphics.scaleY = 1 + Math.sin(self.moveTimer * 0.15) * 0.3; // Shoot green water projectiles every 2 seconds if (self.moveTimer % 120 === 0) { self.shootGreenWater(); } }; self.shootGreenWater = function () { // Create green water projectile aimed at Kirby var projectile = new GreenWaterProjectile(); projectile.x = self.x; projectile.y = self.y; // Calculate direction to Kirby var dx = kirby.x - self.x; var dy = kirby.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { projectile.velocityX = dx / distance * projectile.speed; projectile.velocityY = dy / distance * projectile.speed; } game.addChild(projectile); greenWaterProjectiles.push(projectile); }; return self; }); var GreenWaterProjectile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5 }); // Tint the water green graphics.tint = 0x00FF00; self.velocityX = 0; self.velocityY = 0; self.speed = 4; self.lifetime = 300; // 5 seconds at 60fps self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.lifetime--; // Remove if off screen or lifetime expired if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); } }; return self; }); var Kirby = Container.expand(function () { var self = Container.call(this); var kirbyGraphics = self.attachAsset('kirby', { anchorX: 0.5, anchorY: 0.5 }); self.isInfected = false; self.infectionTimer = 0; self.controlLossTimer = 0; self.isControlLoss = false; self.danceTimer = 0; self.isDancing = false; self.update = function () { if (self.infectionTimer > 0) { self.infectionTimer--; if (self.infectionTimer <= 0) { // Infection timer expired - game over LK.showGameOver(); } } if (self.controlLossTimer > 0) { self.controlLossTimer--; // Start spinning and show dizzy star if not already if (!self._dizzyStar) { // Add dizzy star emoji above Kirby var star = new Text2('⭐', { size: 80, fill: 0xFFFF00 }); star.anchor.set(0.5, 1.2); star.x = 0; star.y = -kirbyGraphics.height * 0.7; self.addChild(star); self._dizzyStar = star; // Animate star floating up and down star._dizzyTween = tween(star, { y: star.y - 30 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { tween(star, { y: star.y + 30 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { if (self._dizzyStar) { // Loop the float star.y = -kirbyGraphics.height * 0.7; star._dizzyTween = tween(star, { y: star.y - 30 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { if (self._dizzyStar) { tween(star, { y: star.y + 30 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { if (self._dizzyStar) { // Loop again star.y = -kirbyGraphics.height * 0.7; star._dizzyTween = tween(star, { y: star.y - 30 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { // Continue loop } }); } } }); } } }); } } }); } }); } // Spin Kirby kirbyGraphics.rotation += 0.3; if (self.controlLossTimer <= 0) { self.isControlLoss = false; self.isInfected = false; // Clear infection when control loss ends // Remove dizzy star and reset rotation if (self._dizzyStar) { if (self._dizzyStar._dizzyTween) { tween.stop(self._dizzyStar); } self.removeChild(self._dizzyStar); self._dizzyStar = null; } kirbyGraphics.rotation = 0; } } // Update visual feedback for infection if (self.isInfected) { kirbyGraphics.tint = 0x00FF00; // Green tint when infected // Stop dancing when infected if (self.isDancing) { tween.stop(kirbyGraphics); self.isDancing = false; kirbyGraphics.scaleX = 1; kirbyGraphics.scaleY = 1; kirbyGraphics.rotation = 0; } // If not in control loss, make sure dizzy star is removed and rotation reset if (!self.isControlLoss && self._dizzyStar) { if (self._dizzyStar._dizzyTween) { tween.stop(self._dizzyStar); } self.removeChild(self._dizzyStar); self._dizzyStar = null; kirbyGraphics.rotation = 0; } } else { kirbyGraphics.tint = 0xFFFFFF; // Normal color // Remove dizzy star and reset rotation if present if (self._dizzyStar) { if (self._dizzyStar._dizzyTween) { tween.stop(self._dizzyStar); } self.removeChild(self._dizzyStar); self._dizzyStar = null; kirbyGraphics.rotation = 0; } // Start dance animation when not infected if (!self.isDancing) { self.isDancing = true; self.startDance(); } } }; self.getInfected = function () { if (self.isInfected) return; // Already infected var outcome = Math.floor(Math.random() * 3); if (outcome === 0) { // Instant death (33% chance) LK.showGameOver(); } else if (outcome === 1) { // Control loss for 5 seconds (33% chance) self.isControlLoss = true; self.controlLossTimer = 300; // 5 seconds at 60fps self.isInfected = true; } else { // 1 minute survival timer (33% chance) self.isInfected = true; self.infectionTimer = 3600; // 60 seconds at 60fps } LK.getSound('infection').play(); }; self.cleanse = function () { self.isInfected = false; self.infectionTimer = 0; self.controlLossTimer = 0; self.isControlLoss = false; LK.getSound('cleanse').play(); }; self.startDance = function () { // Bouncy scale animation tween(kirbyGraphics, { scaleX: 1.2, scaleY: 0.8 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { tween(kirbyGraphics, { scaleX: 0.8, scaleY: 1.2 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { if (self.isDancing && !self.isInfected) { self.startDance(); // Loop the dance } } }); } }); // Gentle rotation tween(kirbyGraphics, { rotation: 0.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(kirbyGraphics, { rotation: -0.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (self.isDancing && !self.isInfected) { tween(kirbyGraphics, { rotation: 0 }, { duration: 400 }); } } }); } }); }; return self; }); var WaddleDee = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('waddleDee', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.direction = Math.random() * Math.PI * 2; self.update = function () { self.x += Math.cos(self.direction) * self.speed; self.y += Math.sin(self.direction) * self.speed; // Bounce off edges if (self.x < 40 || self.x > 2008) { self.direction = Math.PI - self.direction; } if (self.y < 40 || self.y > 2692) { self.direction = -self.direction; } // Keep in bounds self.x = Math.max(40, Math.min(2008, self.x)); self.y = Math.max(40, Math.min(2692, self.y)); }; return self; }); var WaddleDoo = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('waddleDoo', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.targetX = 0; self.targetY = 0; self.update = function () { // Move toward Kirby var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); var Water = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5 }); // Gentle pulsing animation self.pulseTimer = 0; self.regenTimer = 0; self.isHidden = false; self.update = function () { self.pulseTimer++; if (self.isHidden) { self.regenTimer--; if (self.regenTimer <= 0) { self.isHidden = false; graphics.alpha = 1; graphics.scaleX = 1; graphics.scaleY = 1; } } else { graphics.scaleX = 1 + Math.sin(self.pulseTimer * 0.1) * 0.2; graphics.scaleY = 1 + Math.sin(self.pulseTimer * 0.1) * 0.2; } }; self.hide = function () { self.isHidden = true; self.regenTimer = 300; // 5 seconds at 60fps graphics.alpha = 0; }; return self; }); var WaterProjectile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.speed = 8; self.lifetime = 180; // 3 seconds at 60fps self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.lifetime--; // Remove if off screen or lifetime expired if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var kirby; var waddleDees = []; var waddleDoos = []; var waters = []; var waterProjectiles = []; var greenWaterProjectiles = []; var darkMatter = null; var gameTimer = 0; var waveLevel = 1; var enemySpawnTimer = 0; var waterSpawnTimer = 0; var dragNode = null; var bossSpawned = false; var canThrow = true; var waterCount = 0; // UI Elements var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var infectionTxt = new Text2('', { size: 60, fill: 0x00FF00 }); infectionTxt.anchor.set(0.5, 0); infectionTxt.y = 100; LK.gui.top.addChild(infectionTxt); var waveTxt = new Text2('Wave: 1', { size: 70, fill: 0xFFFFFF }); waveTxt.anchor.set(0, 0); LK.gui.topRight.addChild(waveTxt); waveTxt.x = -280; var throwBtnBg = LK.getAsset('throwBtnBg', { width: 120, height: 80, anchorX: 0.5, anchorY: 0.5 }); LK.gui.bottomRight.addChild(throwBtnBg); throwBtnBg.x = -60; throwBtnBg.y = -60; var throwBtn = new Text2('THROW', { size: 60, fill: 0x00AAFF }); throwBtn.anchor.set(0.5, 0.5); throwBtnBg.addChild(throwBtn); var waterCountTxt = new Text2('Water: 0', { size: 60, fill: 0x00AAFF }); waterCountTxt.anchor.set(0, 1); LK.gui.bottomLeft.addChild(waterCountTxt); waterCountTxt.x = 20; waterCountTxt.y = -20; // Initialize Kirby kirby = game.addChild(new Kirby()); kirby.x = 1024; kirby.y = 1366; // Spawn initial water for (var i = 0; i < 3; i++) { var water = game.addChild(new Water()); water.x = Math.random() * 1800 + 200; water.y = Math.random() * 2400 + 200; waters.push(water); waterCount++; } function spawnWaddleDee() { var waddleDee = game.addChild(new WaddleDee()); var edge = Math.floor(Math.random() * 4); if (edge === 0) { // Top waddleDee.x = Math.random() * 2048; waddleDee.y = 0; } else if (edge === 1) { // Right waddleDee.x = 2048; waddleDee.y = Math.random() * 2732; } else if (edge === 2) { // Bottom waddleDee.x = Math.random() * 2048; waddleDee.y = 2732; } else { // Left waddleDee.x = 0; waddleDee.y = Math.random() * 2732; } waddleDees.push(waddleDee); LK.getSound('enemySpawn').play(); } function spawnWaddleDoo() { var waddleDoo = game.addChild(new WaddleDoo()); var edge = Math.floor(Math.random() * 4); if (edge === 0) { // Top waddleDoo.x = Math.random() * 2048; waddleDoo.y = 0; } else if (edge === 1) { // Right waddleDoo.x = 2048; waddleDoo.y = Math.random() * 2732; } else if (edge === 2) { // Bottom waddleDoo.x = Math.random() * 2048; waddleDoo.y = 2732; } else { // Left waddleDoo.x = 0; waddleDoo.y = Math.random() * 2732; } waddleDoo.targetX = kirby.x; waddleDoo.targetY = kirby.y; waddleDoos.push(waddleDoo); LK.getSound('enemySpawn').play(); } function spawnWater() { if (waters.length < 2) { var water = game.addChild(new Water()); water.x = Math.random() * 1800 + 200; water.y = Math.random() * 2400 + 200; waters.push(water); waterCount++; } } function spawnDarkMatter() { if (!bossSpawned) { darkMatter = game.addChild(new DarkMatter()); darkMatter.x = 1024; darkMatter.y = 500; bossSpawned = true; // Change background to red game.setBackgroundColor(0xFF0000); // Clear all other enemies when boss spawns for (var i = waddleDees.length - 1; i >= 0; i--) { waddleDees[i].destroy(); } waddleDees = []; for (var j = waddleDoos.length - 1; j >= 0; j--) { waddleDoos[j].destroy(); } waddleDoos = []; } } function handleMove(x, y, obj) { if (dragNode && !kirby.isControlLoss) { dragNode.x = x; dragNode.y = y; } } game.move = handleMove; throwBtnBg.down = function (x, y, obj) { if (canThrow && waterCount > 0) { // Find nearest enemy to target var nearestEnemy = null; var minEnemyDistance = Infinity; // Check WaddleDees for (var wd = 0; wd < waddleDees.length; wd++) { var dx = waddleDees[wd].x - kirby.x; var dy = waddleDees[wd].y - kirby.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minEnemyDistance) { minEnemyDistance = distance; nearestEnemy = waddleDees[wd]; } } // Check WaddleDoos for (var wo = 0; wo < waddleDoos.length; wo++) { var dx = waddleDoos[wo].x - kirby.x; var dy = waddleDoos[wo].y - kirby.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minEnemyDistance) { minEnemyDistance = distance; nearestEnemy = waddleDoos[wo]; } } // Check Dark Matter if (darkMatter) { var dx = darkMatter.x - kirby.x; var dy = darkMatter.y - kirby.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minEnemyDistance) { minEnemyDistance = distance; nearestEnemy = darkMatter; } } // Create water projectile var projectile = game.addChild(new WaterProjectile()); projectile.x = kirby.x; projectile.y = kirby.y; var targetX, targetY; if (nearestEnemy) { // Throw towards nearest enemy targetX = nearestEnemy.x; targetY = nearestEnemy.y; } else { // Throw towards center of screen if no enemies targetX = 1024; targetY = 1366; } var dx = targetX - kirby.x; var dy = targetY - kirby.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { projectile.velocityX = dx / distance * projectile.speed; projectile.velocityY = dy / distance * projectile.speed; } waterProjectiles.push(projectile); waterCount--; canThrow = false; LK.setTimeout(function () { canThrow = true; }, 500); // 0.5 second cooldown } }; game.down = function (x, y, obj) { dragNode = kirby; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; game.update = function () { gameTimer++; // Update score LK.setScore(Math.floor(gameTimer / 60)); scoreTxt.setText('Score: ' + LK.getScore()); // Update water counter display waterCountTxt.setText('Water: ' + waterCount); // Update infection display if (kirby.isInfected) { var timeLeft = Math.ceil(kirby.infectionTimer / 60); if (kirby.isControlLoss) { var controlLeft = Math.ceil(kirby.controlLossTimer / 60); infectionTxt.setText('INFECTED! Control Lost: ' + controlLeft + 's'); } else { infectionTxt.setText('INFECTED! Time Left: ' + timeLeft + 's'); } } else { infectionTxt.setText(''); } // Wave progression if (LK.getScore() > 0 && LK.getScore() % 20 === 0 && LK.getScore() / 20 > waveLevel - 1 && waveLevel < 3) { // Every 20 score, max 3 waves waveLevel++; waveTxt.setText('Wave: ' + waveLevel); // Spawn dark matter in wave 3 if (waveLevel === 3) { spawnDarkMatter(); } } // Enemy spawning if (!bossSpawned) { enemySpawnTimer++; var spawnRate = Math.max(60, 180 - waveLevel * 20); // Faster spawning each wave if (enemySpawnTimer >= spawnRate) { enemySpawnTimer = 0; if (Math.random() < 0.7) { spawnWaddleDee(); } else { spawnWaddleDoo(); } } } // Water spawning waterSpawnTimer++; if (waterSpawnTimer >= 600) { // Every 10 seconds waterSpawnTimer = 0; spawnWater(); } // Update WaddleDoo targets for (var i = 0; i < waddleDoos.length; i++) { waddleDoos[i].targetX = kirby.x; waddleDoos[i].targetY = kirby.y; } // Collision detection - WaddleDees for (var j = waddleDees.length - 1; j >= 0; j--) { var waddleDee = waddleDees[j]; if (kirby.intersects(waddleDee)) { kirby.getInfected(); waddleDee.destroy(); waddleDees.splice(j, 1); } } // Collision detection - WaddleDoos (always dangerous) for (var k = waddleDoos.length - 1; k >= 0; k--) { var waddleDoo = waddleDoos[k]; if (kirby.intersects(waddleDoo)) { LK.showGameOver(); } } // Collision detection - Water for (var l = waters.length - 1; l >= 0; l--) { var water = waters[l]; if (kirby.intersects(water) && !water.isHidden) { kirby.cleanse(); water.destroy(); waters.splice(l, 1); waterCount++; } } // Water projectile collisions with enemies for (var p = waterProjectiles.length - 1; p >= 0; p--) { var projectile = waterProjectiles[p]; var hitSomething = false; // Check collision with WaddleDees for (var wd = waddleDees.length - 1; wd >= 0; wd--) { if (projectile.intersects(waddleDees[wd])) { waddleDees[wd].destroy(); waddleDees.splice(wd, 1); projectile.destroy(); waterProjectiles.splice(p, 1); hitSomething = true; break; } } if (hitSomething) continue; // Check collision with WaddleDoos for (var wo = waddleDoos.length - 1; wo >= 0; wo--) { if (projectile.intersects(waddleDoos[wo])) { waddleDoos[wo].destroy(); waddleDoos.splice(wo, 1); projectile.destroy(); waterProjectiles.splice(p, 1); hitSomething = true; break; } } if (hitSomething) continue; // Check collision with Dark Matter (requires 4 hits) if (darkMatter && projectile.intersects(darkMatter)) { darkMatter.hitCount++; LK.effects.flashObject(darkMatter, 0xFFFFFF, 200); projectile.destroy(); waterProjectiles.splice(p, 1); if (darkMatter.hitCount >= 4) { LK.showYouWin(); } } } // Clean up destroyed projectiles for (var pr = waterProjectiles.length - 1; pr >= 0; pr--) { if (!waterProjectiles[pr].parent) { waterProjectiles.splice(pr, 1); } } // Green water projectile collisions with Kirby for (var gp = greenWaterProjectiles.length - 1; gp >= 0; gp--) { var greenProjectile = greenWaterProjectiles[gp]; if (kirby.intersects(greenProjectile)) { kirby.getInfected(); greenProjectile.destroy(); greenWaterProjectiles.splice(gp, 1); } } // Clean up destroyed green projectiles for (var gpr = greenWaterProjectiles.length - 1; gpr >= 0; gpr--) { if (!greenWaterProjectiles[gpr].parent) { greenWaterProjectiles.splice(gpr, 1); } } // Collision detection - Dark Matter if (darkMatter && kirby.intersects(darkMatter)) { darkMatter.health--; LK.effects.flashObject(darkMatter, 0xFFFFFF, 200); if (darkMatter.health <= 0) { LK.showYouWin(); } else { // Push Kirby away from Dark Matter var dx = kirby.x - darkMatter.x; var dy = kirby.y - darkMatter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { kirby.x += dx / distance * 50; kirby.y += dy / distance * 50; } } } }; // Start background music LK.playMusic('bgmusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DarkMatter = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('darkMatter', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 10;
self.hitCount = 0;
self.moveTimer = 0;
self.speed = 1;
self.direction = 0;
self.update = function () {
self.moveTimer++;
// Change direction every 2 seconds
if (self.moveTimer % 120 === 0) {
self.direction = Math.random() * Math.PI * 2;
}
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Keep in bounds
self.x = Math.max(100, Math.min(1948, self.x));
self.y = Math.max(100, Math.min(2632, self.y));
// Pulsing dark energy effect
graphics.scaleX = 1 + Math.sin(self.moveTimer * 0.15) * 0.3;
graphics.scaleY = 1 + Math.sin(self.moveTimer * 0.15) * 0.3;
// Shoot green water projectiles every 2 seconds
if (self.moveTimer % 120 === 0) {
self.shootGreenWater();
}
};
self.shootGreenWater = function () {
// Create green water projectile aimed at Kirby
var projectile = new GreenWaterProjectile();
projectile.x = self.x;
projectile.y = self.y;
// Calculate direction to Kirby
var dx = kirby.x - self.x;
var dy = kirby.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
projectile.velocityX = dx / distance * projectile.speed;
projectile.velocityY = dy / distance * projectile.speed;
}
game.addChild(projectile);
greenWaterProjectiles.push(projectile);
};
return self;
});
var GreenWaterProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('water', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint the water green
graphics.tint = 0x00FF00;
self.velocityX = 0;
self.velocityY = 0;
self.speed = 4;
self.lifetime = 300; // 5 seconds at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
// Remove if off screen or lifetime expired
if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
}
};
return self;
});
var Kirby = Container.expand(function () {
var self = Container.call(this);
var kirbyGraphics = self.attachAsset('kirby', {
anchorX: 0.5,
anchorY: 0.5
});
self.isInfected = false;
self.infectionTimer = 0;
self.controlLossTimer = 0;
self.isControlLoss = false;
self.danceTimer = 0;
self.isDancing = false;
self.update = function () {
if (self.infectionTimer > 0) {
self.infectionTimer--;
if (self.infectionTimer <= 0) {
// Infection timer expired - game over
LK.showGameOver();
}
}
if (self.controlLossTimer > 0) {
self.controlLossTimer--;
// Start spinning and show dizzy star if not already
if (!self._dizzyStar) {
// Add dizzy star emoji above Kirby
var star = new Text2('⭐', {
size: 80,
fill: 0xFFFF00
});
star.anchor.set(0.5, 1.2);
star.x = 0;
star.y = -kirbyGraphics.height * 0.7;
self.addChild(star);
self._dizzyStar = star;
// Animate star floating up and down
star._dizzyTween = tween(star, {
y: star.y - 30
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(star, {
y: star.y + 30
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self._dizzyStar) {
// Loop the float
star.y = -kirbyGraphics.height * 0.7;
star._dizzyTween = tween(star, {
y: star.y - 30
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self._dizzyStar) {
tween(star, {
y: star.y + 30
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self._dizzyStar) {
// Loop again
star.y = -kirbyGraphics.height * 0.7;
star._dizzyTween = tween(star, {
y: star.y - 30
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue loop
}
});
}
}
});
}
}
});
}
}
});
}
});
}
// Spin Kirby
kirbyGraphics.rotation += 0.3;
if (self.controlLossTimer <= 0) {
self.isControlLoss = false;
self.isInfected = false; // Clear infection when control loss ends
// Remove dizzy star and reset rotation
if (self._dizzyStar) {
if (self._dizzyStar._dizzyTween) {
tween.stop(self._dizzyStar);
}
self.removeChild(self._dizzyStar);
self._dizzyStar = null;
}
kirbyGraphics.rotation = 0;
}
}
// Update visual feedback for infection
if (self.isInfected) {
kirbyGraphics.tint = 0x00FF00; // Green tint when infected
// Stop dancing when infected
if (self.isDancing) {
tween.stop(kirbyGraphics);
self.isDancing = false;
kirbyGraphics.scaleX = 1;
kirbyGraphics.scaleY = 1;
kirbyGraphics.rotation = 0;
}
// If not in control loss, make sure dizzy star is removed and rotation reset
if (!self.isControlLoss && self._dizzyStar) {
if (self._dizzyStar._dizzyTween) {
tween.stop(self._dizzyStar);
}
self.removeChild(self._dizzyStar);
self._dizzyStar = null;
kirbyGraphics.rotation = 0;
}
} else {
kirbyGraphics.tint = 0xFFFFFF; // Normal color
// Remove dizzy star and reset rotation if present
if (self._dizzyStar) {
if (self._dizzyStar._dizzyTween) {
tween.stop(self._dizzyStar);
}
self.removeChild(self._dizzyStar);
self._dizzyStar = null;
kirbyGraphics.rotation = 0;
}
// Start dance animation when not infected
if (!self.isDancing) {
self.isDancing = true;
self.startDance();
}
}
};
self.getInfected = function () {
if (self.isInfected) return; // Already infected
var outcome = Math.floor(Math.random() * 3);
if (outcome === 0) {
// Instant death (33% chance)
LK.showGameOver();
} else if (outcome === 1) {
// Control loss for 5 seconds (33% chance)
self.isControlLoss = true;
self.controlLossTimer = 300; // 5 seconds at 60fps
self.isInfected = true;
} else {
// 1 minute survival timer (33% chance)
self.isInfected = true;
self.infectionTimer = 3600; // 60 seconds at 60fps
}
LK.getSound('infection').play();
};
self.cleanse = function () {
self.isInfected = false;
self.infectionTimer = 0;
self.controlLossTimer = 0;
self.isControlLoss = false;
LK.getSound('cleanse').play();
};
self.startDance = function () {
// Bouncy scale animation
tween(kirbyGraphics, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(kirbyGraphics, {
scaleX: 0.8,
scaleY: 1.2
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isDancing && !self.isInfected) {
self.startDance(); // Loop the dance
}
}
});
}
});
// Gentle rotation
tween(kirbyGraphics, {
rotation: 0.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(kirbyGraphics, {
rotation: -0.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isDancing && !self.isInfected) {
tween(kirbyGraphics, {
rotation: 0
}, {
duration: 400
});
}
}
});
}
});
};
return self;
});
var WaddleDee = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('waddleDee', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off edges
if (self.x < 40 || self.x > 2008) {
self.direction = Math.PI - self.direction;
}
if (self.y < 40 || self.y > 2692) {
self.direction = -self.direction;
}
// Keep in bounds
self.x = Math.max(40, Math.min(2008, self.x));
self.y = Math.max(40, Math.min(2692, self.y));
};
return self;
});
var WaddleDoo = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('waddleDoo', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Move toward Kirby
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var Water = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('water', {
anchorX: 0.5,
anchorY: 0.5
});
// Gentle pulsing animation
self.pulseTimer = 0;
self.regenTimer = 0;
self.isHidden = false;
self.update = function () {
self.pulseTimer++;
if (self.isHidden) {
self.regenTimer--;
if (self.regenTimer <= 0) {
self.isHidden = false;
graphics.alpha = 1;
graphics.scaleX = 1;
graphics.scaleY = 1;
}
} else {
graphics.scaleX = 1 + Math.sin(self.pulseTimer * 0.1) * 0.2;
graphics.scaleY = 1 + Math.sin(self.pulseTimer * 0.1) * 0.2;
}
};
self.hide = function () {
self.isHidden = true;
self.regenTimer = 300; // 5 seconds at 60fps
graphics.alpha = 0;
};
return self;
});
var WaterProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('water', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.lifetime = 180; // 3 seconds at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
// Remove if off screen or lifetime expired
if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var kirby;
var waddleDees = [];
var waddleDoos = [];
var waters = [];
var waterProjectiles = [];
var greenWaterProjectiles = [];
var darkMatter = null;
var gameTimer = 0;
var waveLevel = 1;
var enemySpawnTimer = 0;
var waterSpawnTimer = 0;
var dragNode = null;
var bossSpawned = false;
var canThrow = true;
var waterCount = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var infectionTxt = new Text2('', {
size: 60,
fill: 0x00FF00
});
infectionTxt.anchor.set(0.5, 0);
infectionTxt.y = 100;
LK.gui.top.addChild(infectionTxt);
var waveTxt = new Text2('Wave: 1', {
size: 70,
fill: 0xFFFFFF
});
waveTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(waveTxt);
waveTxt.x = -280;
var throwBtnBg = LK.getAsset('throwBtnBg', {
width: 120,
height: 80,
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.bottomRight.addChild(throwBtnBg);
throwBtnBg.x = -60;
throwBtnBg.y = -60;
var throwBtn = new Text2('THROW', {
size: 60,
fill: 0x00AAFF
});
throwBtn.anchor.set(0.5, 0.5);
throwBtnBg.addChild(throwBtn);
var waterCountTxt = new Text2('Water: 0', {
size: 60,
fill: 0x00AAFF
});
waterCountTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(waterCountTxt);
waterCountTxt.x = 20;
waterCountTxt.y = -20;
// Initialize Kirby
kirby = game.addChild(new Kirby());
kirby.x = 1024;
kirby.y = 1366;
// Spawn initial water
for (var i = 0; i < 3; i++) {
var water = game.addChild(new Water());
water.x = Math.random() * 1800 + 200;
water.y = Math.random() * 2400 + 200;
waters.push(water);
waterCount++;
}
function spawnWaddleDee() {
var waddleDee = game.addChild(new WaddleDee());
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// Top
waddleDee.x = Math.random() * 2048;
waddleDee.y = 0;
} else if (edge === 1) {
// Right
waddleDee.x = 2048;
waddleDee.y = Math.random() * 2732;
} else if (edge === 2) {
// Bottom
waddleDee.x = Math.random() * 2048;
waddleDee.y = 2732;
} else {
// Left
waddleDee.x = 0;
waddleDee.y = Math.random() * 2732;
}
waddleDees.push(waddleDee);
LK.getSound('enemySpawn').play();
}
function spawnWaddleDoo() {
var waddleDoo = game.addChild(new WaddleDoo());
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// Top
waddleDoo.x = Math.random() * 2048;
waddleDoo.y = 0;
} else if (edge === 1) {
// Right
waddleDoo.x = 2048;
waddleDoo.y = Math.random() * 2732;
} else if (edge === 2) {
// Bottom
waddleDoo.x = Math.random() * 2048;
waddleDoo.y = 2732;
} else {
// Left
waddleDoo.x = 0;
waddleDoo.y = Math.random() * 2732;
}
waddleDoo.targetX = kirby.x;
waddleDoo.targetY = kirby.y;
waddleDoos.push(waddleDoo);
LK.getSound('enemySpawn').play();
}
function spawnWater() {
if (waters.length < 2) {
var water = game.addChild(new Water());
water.x = Math.random() * 1800 + 200;
water.y = Math.random() * 2400 + 200;
waters.push(water);
waterCount++;
}
}
function spawnDarkMatter() {
if (!bossSpawned) {
darkMatter = game.addChild(new DarkMatter());
darkMatter.x = 1024;
darkMatter.y = 500;
bossSpawned = true;
// Change background to red
game.setBackgroundColor(0xFF0000);
// Clear all other enemies when boss spawns
for (var i = waddleDees.length - 1; i >= 0; i--) {
waddleDees[i].destroy();
}
waddleDees = [];
for (var j = waddleDoos.length - 1; j >= 0; j--) {
waddleDoos[j].destroy();
}
waddleDoos = [];
}
}
function handleMove(x, y, obj) {
if (dragNode && !kirby.isControlLoss) {
dragNode.x = x;
dragNode.y = y;
}
}
game.move = handleMove;
throwBtnBg.down = function (x, y, obj) {
if (canThrow && waterCount > 0) {
// Find nearest enemy to target
var nearestEnemy = null;
var minEnemyDistance = Infinity;
// Check WaddleDees
for (var wd = 0; wd < waddleDees.length; wd++) {
var dx = waddleDees[wd].x - kirby.x;
var dy = waddleDees[wd].y - kirby.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minEnemyDistance) {
minEnemyDistance = distance;
nearestEnemy = waddleDees[wd];
}
}
// Check WaddleDoos
for (var wo = 0; wo < waddleDoos.length; wo++) {
var dx = waddleDoos[wo].x - kirby.x;
var dy = waddleDoos[wo].y - kirby.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minEnemyDistance) {
minEnemyDistance = distance;
nearestEnemy = waddleDoos[wo];
}
}
// Check Dark Matter
if (darkMatter) {
var dx = darkMatter.x - kirby.x;
var dy = darkMatter.y - kirby.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minEnemyDistance) {
minEnemyDistance = distance;
nearestEnemy = darkMatter;
}
}
// Create water projectile
var projectile = game.addChild(new WaterProjectile());
projectile.x = kirby.x;
projectile.y = kirby.y;
var targetX, targetY;
if (nearestEnemy) {
// Throw towards nearest enemy
targetX = nearestEnemy.x;
targetY = nearestEnemy.y;
} else {
// Throw towards center of screen if no enemies
targetX = 1024;
targetY = 1366;
}
var dx = targetX - kirby.x;
var dy = targetY - kirby.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
projectile.velocityX = dx / distance * projectile.speed;
projectile.velocityY = dy / distance * projectile.speed;
}
waterProjectiles.push(projectile);
waterCount--;
canThrow = false;
LK.setTimeout(function () {
canThrow = true;
}, 500); // 0.5 second cooldown
}
};
game.down = function (x, y, obj) {
dragNode = kirby;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.update = function () {
gameTimer++;
// Update score
LK.setScore(Math.floor(gameTimer / 60));
scoreTxt.setText('Score: ' + LK.getScore());
// Update water counter display
waterCountTxt.setText('Water: ' + waterCount);
// Update infection display
if (kirby.isInfected) {
var timeLeft = Math.ceil(kirby.infectionTimer / 60);
if (kirby.isControlLoss) {
var controlLeft = Math.ceil(kirby.controlLossTimer / 60);
infectionTxt.setText('INFECTED! Control Lost: ' + controlLeft + 's');
} else {
infectionTxt.setText('INFECTED! Time Left: ' + timeLeft + 's');
}
} else {
infectionTxt.setText('');
}
// Wave progression
if (LK.getScore() > 0 && LK.getScore() % 20 === 0 && LK.getScore() / 20 > waveLevel - 1 && waveLevel < 3) {
// Every 20 score, max 3 waves
waveLevel++;
waveTxt.setText('Wave: ' + waveLevel);
// Spawn dark matter in wave 3
if (waveLevel === 3) {
spawnDarkMatter();
}
}
// Enemy spawning
if (!bossSpawned) {
enemySpawnTimer++;
var spawnRate = Math.max(60, 180 - waveLevel * 20); // Faster spawning each wave
if (enemySpawnTimer >= spawnRate) {
enemySpawnTimer = 0;
if (Math.random() < 0.7) {
spawnWaddleDee();
} else {
spawnWaddleDoo();
}
}
}
// Water spawning
waterSpawnTimer++;
if (waterSpawnTimer >= 600) {
// Every 10 seconds
waterSpawnTimer = 0;
spawnWater();
}
// Update WaddleDoo targets
for (var i = 0; i < waddleDoos.length; i++) {
waddleDoos[i].targetX = kirby.x;
waddleDoos[i].targetY = kirby.y;
}
// Collision detection - WaddleDees
for (var j = waddleDees.length - 1; j >= 0; j--) {
var waddleDee = waddleDees[j];
if (kirby.intersects(waddleDee)) {
kirby.getInfected();
waddleDee.destroy();
waddleDees.splice(j, 1);
}
}
// Collision detection - WaddleDoos (always dangerous)
for (var k = waddleDoos.length - 1; k >= 0; k--) {
var waddleDoo = waddleDoos[k];
if (kirby.intersects(waddleDoo)) {
LK.showGameOver();
}
}
// Collision detection - Water
for (var l = waters.length - 1; l >= 0; l--) {
var water = waters[l];
if (kirby.intersects(water) && !water.isHidden) {
kirby.cleanse();
water.destroy();
waters.splice(l, 1);
waterCount++;
}
}
// Water projectile collisions with enemies
for (var p = waterProjectiles.length - 1; p >= 0; p--) {
var projectile = waterProjectiles[p];
var hitSomething = false;
// Check collision with WaddleDees
for (var wd = waddleDees.length - 1; wd >= 0; wd--) {
if (projectile.intersects(waddleDees[wd])) {
waddleDees[wd].destroy();
waddleDees.splice(wd, 1);
projectile.destroy();
waterProjectiles.splice(p, 1);
hitSomething = true;
break;
}
}
if (hitSomething) continue;
// Check collision with WaddleDoos
for (var wo = waddleDoos.length - 1; wo >= 0; wo--) {
if (projectile.intersects(waddleDoos[wo])) {
waddleDoos[wo].destroy();
waddleDoos.splice(wo, 1);
projectile.destroy();
waterProjectiles.splice(p, 1);
hitSomething = true;
break;
}
}
if (hitSomething) continue;
// Check collision with Dark Matter (requires 4 hits)
if (darkMatter && projectile.intersects(darkMatter)) {
darkMatter.hitCount++;
LK.effects.flashObject(darkMatter, 0xFFFFFF, 200);
projectile.destroy();
waterProjectiles.splice(p, 1);
if (darkMatter.hitCount >= 4) {
LK.showYouWin();
}
}
}
// Clean up destroyed projectiles
for (var pr = waterProjectiles.length - 1; pr >= 0; pr--) {
if (!waterProjectiles[pr].parent) {
waterProjectiles.splice(pr, 1);
}
}
// Green water projectile collisions with Kirby
for (var gp = greenWaterProjectiles.length - 1; gp >= 0; gp--) {
var greenProjectile = greenWaterProjectiles[gp];
if (kirby.intersects(greenProjectile)) {
kirby.getInfected();
greenProjectile.destroy();
greenWaterProjectiles.splice(gp, 1);
}
}
// Clean up destroyed green projectiles
for (var gpr = greenWaterProjectiles.length - 1; gpr >= 0; gpr--) {
if (!greenWaterProjectiles[gpr].parent) {
greenWaterProjectiles.splice(gpr, 1);
}
}
// Collision detection - Dark Matter
if (darkMatter && kirby.intersects(darkMatter)) {
darkMatter.health--;
LK.effects.flashObject(darkMatter, 0xFFFFFF, 200);
if (darkMatter.health <= 0) {
LK.showYouWin();
} else {
// Push Kirby away from Dark Matter
var dx = kirby.x - darkMatter.x;
var dy = kirby.y - darkMatter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
kirby.x += dx / distance * 50;
kirby.y += dy / distance * 50;
}
}
}
};
// Start background music
LK.playMusic('bgmusic');
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Kirby's Infection Crisis" and with the description "Navigate Kirby through infected Dream Land, avoiding Waddle Dees and Waddle Doos while managing random infection consequences. Find water to cleanse infections and defeat Dark Matter to save the world.". No text on banner!
Waddle dee. In-Game asset. 2d. High contrast. No shadows
Waddle doo. In-Game asset. 2d. High contrast. No shadows
Water. In-Game asset. 2d. High contrast. No shadows