/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Enemy base class var Enemy = Container.expand(function () { var self = Container.call(this); self.type = 'base'; self.speed = 4; self.health = 3; self.isFlashing = false; self.flashTimeout = null; self.update = function () {}; self.takeDamage = function () { if (self.isFlashing) return; self.health--; self.isFlashing = true; // Flash red for 200ms LK.effects.flashObject(self, 0xff0000, 200); if (self.flashTimeout) LK.clearTimeout(self.flashTimeout); self.flashTimeout = LK.setTimeout(function () { self.isFlashing = false; }, 200); }; return self; }); // Enemy: Spinner (orbits the central target) var EnemySpinner = Enemy.expand(function () { var self = Enemy.call(this); var asset = self.attachAsset('enemySpinner', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'spinner'; self.radius = 400 + Math.random() * 200; self.angle = Math.random() * Math.PI * 2; self.speed = 0.012 + Math.random() * 0.005; self.update = function () { self.angle += self.speed; self.x = centralTarget.x + Math.cos(self.angle) * self.radius; self.y = centralTarget.y + Math.sin(self.angle) * self.radius; }; return self; }); // Enemy: Seeker (moves toward player) var EnemySeeker = Enemy.expand(function () { var self = Enemy.call(this); var asset = self.attachAsset('enemySeeker', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'seeker'; self.speed = 3; self.update = function () { // Move toward player if (!player) return; var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } }; return self; }); // Enemy: Dasher (dashes horizontally or vertically) var EnemyDasher = Enemy.expand(function () { var self = Enemy.call(this); var asset = self.attachAsset('enemyDasher', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'dasher'; self.axis = Math.random() < 0.5 ? 'x' : 'y'; self.speed = 9 + Math.random() * 3; self.direction = Math.random() < 0.5 ? 1 : -1; self.update = function () { if (self.axis === 'x') { self.x += self.speed * self.direction; } else { self.y += self.speed * self.direction; } }; return self; }); // Health Pickup var HealthPickup = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0x2ecc71 // green tint for health }); self.type = 'health'; self.update = function () {}; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 700; self.angle = -Math.PI / 2; self.x = 0; self.y = 0; self.updatePosition = function () { self.x = centralTarget.x + Math.cos(self.angle) * self.radius; self.y = centralTarget.y + Math.sin(self.angle) * self.radius; }; self.updatePosition(); return self; }); // Player bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletAsset = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); // vx, vy will be set on creation self.vx = 0; self.vy = -32; self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Shield Pickup var ShieldPickup = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0xf1c40f // yellow tint for shield }); self.type = 'shield'; self.update = function () {}; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c20 }); /**** * Game Code ****/ // Central target // Player character // Player bullet // Central target // Enemy type 1: Seeker // Enemy type 2: Spinner // Enemy type 3: Dasher // Sound for shooting // Sound for enemy destroyed // Sound for hit target // Music var centralTarget = LK.getAsset('centralTarget', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(centralTarget); // Player var player = new Player(); player.updatePosition(); game.addChild(player); // Player health (3 hits to die) var playerHealth = 3; // Shield state var playerShieldActive = false; var playerShieldTimer = 0; // Bullets and enemies arrays var playerBullets = []; var enemies = []; // Score var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Track background state for multi-background progression game.backgroundChanged = 0; // Timer text (minutes:seconds) var timerTxt = new Text2('0:00', { size: 90, fill: 0xFFFFFF }); timerTxt.anchor.set(0.5, 0); timerTxt.y = 110; // Place below score, avoid top 100px LK.gui.top.addChild(timerTxt); // Track elapsed time in frames var elapsedFrames = 0; // Difficulty and spawn control var spawnTimer = 0; var spawnInterval = 90; // frames var enemyTypes = ['seeker']; var difficultyTimer = 0; // Stage control var stage = 1; var fireTimer = 0; var fireInterval = 18; // frames between shots, default for stage 1 // Drag control var dragging = false; var dragStartAngle = 0; var dragStartX = 0; var dragStartY = 0; // Helper: get angle from center to (x, y) function getAngleToCenter(x, y) { var dx = x - centralTarget.x; var dy = y - centralTarget.y; return Math.atan2(dy, dx); } // Move handler: drag around the central target function handleMove(x, y, obj) { if (!dragging) return; var angle = getAngleToCenter(x, y); player.angle = angle; player.updatePosition(); } game.move = handleMove; game.down = function (x, y, obj) { // Only start drag if not on top left 100x100 if (x < 100 && y < 100) return; dragging = true; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragging = false; }; // Shoot on tap anywhere (except top left) game.down = function (x, y, obj) { if (x < 100 && y < 100) return; // Fire bullet toward tap/click var bullet = new PlayerBullet(); bullet.x = player.x; bullet.y = player.y; bullet.lastY = bullet.y; bullet.lastIntersecting = false; // Calculate direction from player to tap/click var dx = x - player.x; var dy = y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var speed = 32; bullet.vx = dx / dist * speed; bullet.vy = dy / dist * speed; // Rotate player to face shooting direction player.angle = Math.atan2(dy, dx); player.updatePosition(); } else { bullet.vx = 0; bullet.vy = -32; } playerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); // Also allow drag dragging = true; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragging = false; }; // Enemy spawn logic function spawnEnemy() { var type = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy; if (type === 'seeker') { enemy = new EnemySeeker(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top enemy.x = Math.random() * 2048; enemy.y = -100; } else if (edge === 1) { // right enemy.x = 2048 + 100; enemy.y = Math.random() * 2732; } else if (edge === 2) { // bottom enemy.x = Math.random() * 2048; enemy.y = 2732 + 100; } else { // left enemy.x = -100; enemy.y = Math.random() * 2732; } } else if (type === 'spinner') { enemy = new EnemySpinner(); // Place at random angle enemy.angle = Math.random() * Math.PI * 2; enemy.radius = 400 + Math.random() * 400; enemy.x = centralTarget.x + Math.cos(enemy.angle) * enemy.radius; enemy.y = centralTarget.y + Math.sin(enemy.angle) * enemy.radius; } else if (type === 'dasher') { enemy = new EnemyDasher(); // Start at random edge if (enemy.axis === 'x') { enemy.x = enemy.direction > 0 ? -100 : 2048 + 100; enemy.y = Math.random() * 2732; } else { enemy.x = Math.random() * 2048; enemy.y = enemy.direction > 0 ? -100 : 2732 + 100; } } if (enemy) { enemy.lastIntersectingPlayer = false; enemy.lastIntersectingTarget = false; enemies.push(enemy); game.addChild(enemy); } } // Main update loop game.update = function () { // Update timer elapsedFrames++; var totalSeconds = Math.floor(elapsedFrames / 60); var minutes = Math.floor(totalSeconds / 60); var seconds = totalSeconds % 60; var secondsStr = seconds < 10 ? '0' + seconds : '' + seconds; timerTxt.setText(minutes + ':' + secondsStr); // Difficulty scaling difficultyTimer++; if (difficultyTimer % 600 === 0 && enemyTypes.length < 3) { if (enemyTypes.length === 1) { enemyTypes.push('spinner'); } else if (enemyTypes.length === 2) { enemyTypes.push('dasher'); } if (spawnInterval > 40) spawnInterval -= 10; } // Stage progression: switch to stage 2 at score 30, and to stage 3 at score 70 if (stage === 1 && LK.getScore() >= 30) { stage = 2; spawnInterval = 90; // slower spawn for stage 2 fireInterval = 7; // faster fire rate } if (stage === 2 && LK.getScore() >= 70) { stage = 3; spawnInterval = 30; // much faster enemy spawn in stage 3 fireInterval = 4; // even faster fire rate // Activate shield for 3 seconds (180 frames) if (!playerShieldActive) { playerShieldActive = true; playerShieldTimer = 180; // Optional: flash player or add effect LK.effects.flashObject(player, 0xf1c40f, 3000); } } // Handle shield timer if (playerShieldActive) { playerShieldTimer--; if (playerShieldTimer <= 0) { playerShieldActive = false; playerShieldTimer = 0; } } // Spawn enemies spawnTimer++; if (spawnTimer >= spawnInterval) { // In stage 1, spawn 1 enemy per interval if (stage === 1) { spawnEnemy(); } else if (stage === 2) { // In stage 2, spawn 1 enemy per interval (less than before) spawnEnemy(); } else if (stage === 3) { // In stage 3, spawn 4 enemies per interval (increase) spawnEnemy(); spawnEnemy(); spawnEnemy(); spawnEnemy(); } spawnTimer = 0; } // Automatic fire logic (increased fire rate in stage 2 and 3) fireTimer++; if (fireTimer >= fireInterval && dragging) { // Fire bullet toward current player angle (in direction player is facing) var bullet = new PlayerBullet(); bullet.x = player.x; bullet.y = player.y; bullet.lastY = bullet.y; bullet.lastIntersecting = false; // Fire toward central target var dx = centralTarget.x - player.x; var dy = centralTarget.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var speed = 32; bullet.vx = dx / dist * speed; bullet.vy = dy / dist * speed; } else { bullet.vx = 0; bullet.vy = -32; } playerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); fireTimer = 0; } // Update player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; bullet.update(); // Remove if off screen if (bullet.y < -60 || bullet.y > 2732 + 60 || bullet.x < -60 || bullet.x > 2048 + 60) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check hit on central target var hitTarget = bullet.intersects(centralTarget); if (!bullet.lastIntersecting && hitTarget) { LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('targetHit').play(); bullet.destroy(); playerBullets.splice(i, 1); // Win condition: Instead of ending, change background and continue if (LK.getScore() >= 100) { if (!game.backgroundChanged) { // First background change (after 100 points) game.setBackgroundColor(0x1a1a40); // 2nd background color game.backgroundChanged = 1; // Remove all enemies from the game for (var ei = enemies.length - 1; ei >= 0; ei--) { enemies[ei].destroy(); } enemies = []; // Reset score, stage, and timer LK.setScore(0); scoreTxt.setText('0'); stage = 1; spawnInterval = 90; fireInterval = 18; elapsedFrames = 0; difficultyTimer = 0; // Set new enemy types for 2nd background enemyTypes = ['spinner', 'dasher']; // Optionally, you could add a visual effect or message here } else if (game.backgroundChanged === 1 && LK.getScore() >= 100) { // Second background change (after 2nd 100 points) game.setBackgroundColor(0x1a4020); // 3rd background color game.backgroundChanged = 2; for (var ei = enemies.length - 1; ei >= 0; ei--) { enemies[ei].destroy(); } enemies = []; LK.setScore(0); scoreTxt.setText('0'); stage = 1; spawnInterval = 90; fireInterval = 18; elapsedFrames = 0; difficultyTimer = 0; // Set new enemy types for 3rd background enemyTypes = ['seeker', 'dasher']; } else if (game.backgroundChanged === 2 && LK.getScore() >= 100) { // Third background change (after 3rd 100 points) game.setBackgroundColor(0x40201a); // 4th background color game.backgroundChanged = 3; for (var ei = enemies.length - 1; ei >= 0; ei--) { enemies[ei].destroy(); } enemies = []; LK.setScore(0); scoreTxt.setText('0'); stage = 1; spawnInterval = 90; fireInterval = 18; elapsedFrames = 0; difficultyTimer = 0; // Set new enemy types for 4th background enemyTypes = ['seeker', 'spinner']; } else if (game.backgroundChanged === 3 && LK.getScore() >= 100) { // Fourth background change (after 4th 100 points) game.setBackgroundColor(0x204040); // 5th background color game.backgroundChanged = 4; for (var ei = enemies.length - 1; ei >= 0; ei--) { enemies[ei].destroy(); } enemies = []; LK.setScore(0); scoreTxt.setText('0'); stage = 1; spawnInterval = 90; fireInterval = 18; elapsedFrames = 0; difficultyTimer = 0; // Set new enemy types for 5th background enemyTypes = ['dasher', 'spinner']; } } continue; } bullet.lastIntersecting = hitTarget; // Check hit on enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { LK.getSound('enemyDown').play(); bullet.destroy(); playerBullets.splice(i, 1); enemy.takeDamage(); if (enemy.health <= 0) { enemy.destroy(); enemies.splice(j, 1); } break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Remove if off screen (for dashers) if (enemy.x < -200 || enemy.x > 2048 + 200 || enemy.y < -200 || enemy.y > 2732 + 200) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check collision with player var hitPlayer = enemy.intersects(player); if (!enemy.lastIntersectingPlayer && hitPlayer) { if (!playerShieldActive) { playerHealth--; LK.effects.flashScreen(0xff0000, 800); if (playerHealth <= 0) { LK.showGameOver(); return; } } } enemy.lastIntersectingPlayer = hitPlayer; // Check collision with central target (optional: could penalize or just remove) var hitTarget = enemy.intersects(centralTarget); if (!enemy.lastIntersectingTarget && hitTarget) { // Remove enemy enemy.destroy(); enemies.splice(i, 1); continue; } enemy.lastIntersectingTarget = hitTarget; } }; // Play background music LK.playMusic('bgmusic', { fade: { start: 0, end: 1, duration: 1200 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy base class
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.type = 'base';
self.speed = 4;
self.health = 3;
self.isFlashing = false;
self.flashTimeout = null;
self.update = function () {};
self.takeDamage = function () {
if (self.isFlashing) return;
self.health--;
self.isFlashing = true;
// Flash red for 200ms
LK.effects.flashObject(self, 0xff0000, 200);
if (self.flashTimeout) LK.clearTimeout(self.flashTimeout);
self.flashTimeout = LK.setTimeout(function () {
self.isFlashing = false;
}, 200);
};
return self;
});
// Enemy: Spinner (orbits the central target)
var EnemySpinner = Enemy.expand(function () {
var self = Enemy.call(this);
var asset = self.attachAsset('enemySpinner', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'spinner';
self.radius = 400 + Math.random() * 200;
self.angle = Math.random() * Math.PI * 2;
self.speed = 0.012 + Math.random() * 0.005;
self.update = function () {
self.angle += self.speed;
self.x = centralTarget.x + Math.cos(self.angle) * self.radius;
self.y = centralTarget.y + Math.sin(self.angle) * self.radius;
};
return self;
});
// Enemy: Seeker (moves toward player)
var EnemySeeker = Enemy.expand(function () {
var self = Enemy.call(this);
var asset = self.attachAsset('enemySeeker', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'seeker';
self.speed = 3;
self.update = function () {
// Move toward player
if (!player) return;
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
};
return self;
});
// Enemy: Dasher (dashes horizontally or vertically)
var EnemyDasher = Enemy.expand(function () {
var self = Enemy.call(this);
var asset = self.attachAsset('enemyDasher', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'dasher';
self.axis = Math.random() < 0.5 ? 'x' : 'y';
self.speed = 9 + Math.random() * 3;
self.direction = Math.random() < 0.5 ? 1 : -1;
self.update = function () {
if (self.axis === 'x') {
self.x += self.speed * self.direction;
} else {
self.y += self.speed * self.direction;
}
};
return self;
});
// Health Pickup
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0x2ecc71 // green tint for health
});
self.type = 'health';
self.update = function () {};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 700;
self.angle = -Math.PI / 2;
self.x = 0;
self.y = 0;
self.updatePosition = function () {
self.x = centralTarget.x + Math.cos(self.angle) * self.radius;
self.y = centralTarget.y + Math.sin(self.angle) * self.radius;
};
self.updatePosition();
return self;
});
// Player bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
// vx, vy will be set on creation
self.vx = 0;
self.vy = -32;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Shield Pickup
var ShieldPickup = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xf1c40f // yellow tint for shield
});
self.type = 'shield';
self.update = function () {};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c20
});
/****
* Game Code
****/
// Central target
// Player character
// Player bullet
// Central target
// Enemy type 1: Seeker
// Enemy type 2: Spinner
// Enemy type 3: Dasher
// Sound for shooting
// Sound for enemy destroyed
// Sound for hit target
// Music
var centralTarget = LK.getAsset('centralTarget', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
game.addChild(centralTarget);
// Player
var player = new Player();
player.updatePosition();
game.addChild(player);
// Player health (3 hits to die)
var playerHealth = 3;
// Shield state
var playerShieldActive = false;
var playerShieldTimer = 0;
// Bullets and enemies arrays
var playerBullets = [];
var enemies = [];
// Score
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Track background state for multi-background progression
game.backgroundChanged = 0;
// Timer text (minutes:seconds)
var timerTxt = new Text2('0:00', {
size: 90,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
timerTxt.y = 110; // Place below score, avoid top 100px
LK.gui.top.addChild(timerTxt);
// Track elapsed time in frames
var elapsedFrames = 0;
// Difficulty and spawn control
var spawnTimer = 0;
var spawnInterval = 90; // frames
var enemyTypes = ['seeker'];
var difficultyTimer = 0;
// Stage control
var stage = 1;
var fireTimer = 0;
var fireInterval = 18; // frames between shots, default for stage 1
// Drag control
var dragging = false;
var dragStartAngle = 0;
var dragStartX = 0;
var dragStartY = 0;
// Helper: get angle from center to (x, y)
function getAngleToCenter(x, y) {
var dx = x - centralTarget.x;
var dy = y - centralTarget.y;
return Math.atan2(dy, dx);
}
// Move handler: drag around the central target
function handleMove(x, y, obj) {
if (!dragging) return;
var angle = getAngleToCenter(x, y);
player.angle = angle;
player.updatePosition();
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only start drag if not on top left 100x100
if (x < 100 && y < 100) return;
dragging = true;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragging = false;
};
// Shoot on tap anywhere (except top left)
game.down = function (x, y, obj) {
if (x < 100 && y < 100) return;
// Fire bullet toward tap/click
var bullet = new PlayerBullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.lastY = bullet.y;
bullet.lastIntersecting = false;
// Calculate direction from player to tap/click
var dx = x - player.x;
var dy = y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var speed = 32;
bullet.vx = dx / dist * speed;
bullet.vy = dy / dist * speed;
// Rotate player to face shooting direction
player.angle = Math.atan2(dy, dx);
player.updatePosition();
} else {
bullet.vx = 0;
bullet.vy = -32;
}
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Also allow drag
dragging = true;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragging = false;
};
// Enemy spawn logic
function spawnEnemy() {
var type = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy;
if (type === 'seeker') {
enemy = new EnemySeeker();
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
enemy.x = Math.random() * 2048;
enemy.y = -100;
} else if (edge === 1) {
// right
enemy.x = 2048 + 100;
enemy.y = Math.random() * 2732;
} else if (edge === 2) {
// bottom
enemy.x = Math.random() * 2048;
enemy.y = 2732 + 100;
} else {
// left
enemy.x = -100;
enemy.y = Math.random() * 2732;
}
} else if (type === 'spinner') {
enemy = new EnemySpinner();
// Place at random angle
enemy.angle = Math.random() * Math.PI * 2;
enemy.radius = 400 + Math.random() * 400;
enemy.x = centralTarget.x + Math.cos(enemy.angle) * enemy.radius;
enemy.y = centralTarget.y + Math.sin(enemy.angle) * enemy.radius;
} else if (type === 'dasher') {
enemy = new EnemyDasher();
// Start at random edge
if (enemy.axis === 'x') {
enemy.x = enemy.direction > 0 ? -100 : 2048 + 100;
enemy.y = Math.random() * 2732;
} else {
enemy.x = Math.random() * 2048;
enemy.y = enemy.direction > 0 ? -100 : 2732 + 100;
}
}
if (enemy) {
enemy.lastIntersectingPlayer = false;
enemy.lastIntersectingTarget = false;
enemies.push(enemy);
game.addChild(enemy);
}
}
// Main update loop
game.update = function () {
// Update timer
elapsedFrames++;
var totalSeconds = Math.floor(elapsedFrames / 60);
var minutes = Math.floor(totalSeconds / 60);
var seconds = totalSeconds % 60;
var secondsStr = seconds < 10 ? '0' + seconds : '' + seconds;
timerTxt.setText(minutes + ':' + secondsStr);
// Difficulty scaling
difficultyTimer++;
if (difficultyTimer % 600 === 0 && enemyTypes.length < 3) {
if (enemyTypes.length === 1) {
enemyTypes.push('spinner');
} else if (enemyTypes.length === 2) {
enemyTypes.push('dasher');
}
if (spawnInterval > 40) spawnInterval -= 10;
}
// Stage progression: switch to stage 2 at score 30, and to stage 3 at score 70
if (stage === 1 && LK.getScore() >= 30) {
stage = 2;
spawnInterval = 90; // slower spawn for stage 2
fireInterval = 7; // faster fire rate
}
if (stage === 2 && LK.getScore() >= 70) {
stage = 3;
spawnInterval = 30; // much faster enemy spawn in stage 3
fireInterval = 4; // even faster fire rate
// Activate shield for 3 seconds (180 frames)
if (!playerShieldActive) {
playerShieldActive = true;
playerShieldTimer = 180;
// Optional: flash player or add effect
LK.effects.flashObject(player, 0xf1c40f, 3000);
}
}
// Handle shield timer
if (playerShieldActive) {
playerShieldTimer--;
if (playerShieldTimer <= 0) {
playerShieldActive = false;
playerShieldTimer = 0;
}
}
// Spawn enemies
spawnTimer++;
if (spawnTimer >= spawnInterval) {
// In stage 1, spawn 1 enemy per interval
if (stage === 1) {
spawnEnemy();
} else if (stage === 2) {
// In stage 2, spawn 1 enemy per interval (less than before)
spawnEnemy();
} else if (stage === 3) {
// In stage 3, spawn 4 enemies per interval (increase)
spawnEnemy();
spawnEnemy();
spawnEnemy();
spawnEnemy();
}
spawnTimer = 0;
}
// Automatic fire logic (increased fire rate in stage 2 and 3)
fireTimer++;
if (fireTimer >= fireInterval && dragging) {
// Fire bullet toward current player angle (in direction player is facing)
var bullet = new PlayerBullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.lastY = bullet.y;
bullet.lastIntersecting = false;
// Fire toward central target
var dx = centralTarget.x - player.x;
var dy = centralTarget.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var speed = 32;
bullet.vx = dx / dist * speed;
bullet.vy = dy / dist * speed;
} else {
bullet.vx = 0;
bullet.vy = -32;
}
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
fireTimer = 0;
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Remove if off screen
if (bullet.y < -60 || bullet.y > 2732 + 60 || bullet.x < -60 || bullet.x > 2048 + 60) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check hit on central target
var hitTarget = bullet.intersects(centralTarget);
if (!bullet.lastIntersecting && hitTarget) {
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('targetHit').play();
bullet.destroy();
playerBullets.splice(i, 1);
// Win condition: Instead of ending, change background and continue
if (LK.getScore() >= 100) {
if (!game.backgroundChanged) {
// First background change (after 100 points)
game.setBackgroundColor(0x1a1a40); // 2nd background color
game.backgroundChanged = 1;
// Remove all enemies from the game
for (var ei = enemies.length - 1; ei >= 0; ei--) {
enemies[ei].destroy();
}
enemies = [];
// Reset score, stage, and timer
LK.setScore(0);
scoreTxt.setText('0');
stage = 1;
spawnInterval = 90;
fireInterval = 18;
elapsedFrames = 0;
difficultyTimer = 0;
// Set new enemy types for 2nd background
enemyTypes = ['spinner', 'dasher'];
// Optionally, you could add a visual effect or message here
} else if (game.backgroundChanged === 1 && LK.getScore() >= 100) {
// Second background change (after 2nd 100 points)
game.setBackgroundColor(0x1a4020); // 3rd background color
game.backgroundChanged = 2;
for (var ei = enemies.length - 1; ei >= 0; ei--) {
enemies[ei].destroy();
}
enemies = [];
LK.setScore(0);
scoreTxt.setText('0');
stage = 1;
spawnInterval = 90;
fireInterval = 18;
elapsedFrames = 0;
difficultyTimer = 0;
// Set new enemy types for 3rd background
enemyTypes = ['seeker', 'dasher'];
} else if (game.backgroundChanged === 2 && LK.getScore() >= 100) {
// Third background change (after 3rd 100 points)
game.setBackgroundColor(0x40201a); // 4th background color
game.backgroundChanged = 3;
for (var ei = enemies.length - 1; ei >= 0; ei--) {
enemies[ei].destroy();
}
enemies = [];
LK.setScore(0);
scoreTxt.setText('0');
stage = 1;
spawnInterval = 90;
fireInterval = 18;
elapsedFrames = 0;
difficultyTimer = 0;
// Set new enemy types for 4th background
enemyTypes = ['seeker', 'spinner'];
} else if (game.backgroundChanged === 3 && LK.getScore() >= 100) {
// Fourth background change (after 4th 100 points)
game.setBackgroundColor(0x204040); // 5th background color
game.backgroundChanged = 4;
for (var ei = enemies.length - 1; ei >= 0; ei--) {
enemies[ei].destroy();
}
enemies = [];
LK.setScore(0);
scoreTxt.setText('0');
stage = 1;
spawnInterval = 90;
fireInterval = 18;
elapsedFrames = 0;
difficultyTimer = 0;
// Set new enemy types for 5th background
enemyTypes = ['dasher', 'spinner'];
}
}
continue;
}
bullet.lastIntersecting = hitTarget;
// Check hit on enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
LK.getSound('enemyDown').play();
bullet.destroy();
playerBullets.splice(i, 1);
enemy.takeDamage();
if (enemy.health <= 0) {
enemy.destroy();
enemies.splice(j, 1);
}
break;
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Remove if off screen (for dashers)
if (enemy.x < -200 || enemy.x > 2048 + 200 || enemy.y < -200 || enemy.y > 2732 + 200) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
var hitPlayer = enemy.intersects(player);
if (!enemy.lastIntersectingPlayer && hitPlayer) {
if (!playerShieldActive) {
playerHealth--;
LK.effects.flashScreen(0xff0000, 800);
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
}
enemy.lastIntersectingPlayer = hitPlayer;
// Check collision with central target (optional: could penalize or just remove)
var hitTarget = enemy.intersects(centralTarget);
if (!enemy.lastIntersectingTarget && hitTarget) {
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
continue;
}
enemy.lastIntersectingTarget = hitTarget;
}
};
// Play background music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});