/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 9; // Will be set to wave * 9 (3x giant health)
self.maxHealth = 9;
self.speed = 0.5; // Slower than giant enemies
self.points = 100;
self.isBoss = true;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Boss moves slowly and deliberately
var randomX = (Math.random() - 0.5) * 1;
var randomY = (Math.random() - 0.5) * 1;
self.velocityX = (dx / distance + randomX * 0.2) * self.speed;
self.velocityY = (dy / distance + randomY * 0.2) * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('enemyHit').play();
// Flash red when hit
tween(bossGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(bossGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.makeBoss = function () {
// Boss has 3 times the health of giant enemies
self.health = wave * 9; // 3x giant health (wave * 3 * 3)
self.maxHealth = self.health;
self.speed = 0.5; // Slower than giants
self.points = self.points * 10; // High point value
// Scale up to twice the size of giant enemies (5x total)
tween(bossGraphics, {
scaleX: 5.0,
scaleY: 5.0,
tint: 0xFF6600 // Orange tint to distinguish from other enemies
}, {
duration: 1000,
easing: tween.bounceOut
});
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.isSuper = false;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 1;
self.makeSuper = function () {
self.isSuper = true;
self.removeChild(bulletGraphics);
bulletGraphics = self.attachAsset('superBullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glowing effect with tween
tween(bulletGraphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xffff00
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bulletGraphics, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xff4444
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.speed = 1;
self.points = 10;
self.isGiant = false;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Giant enemies change direction more aggressively
if (self.isGiant) {
// Add some randomness to giant enemy movement to make them more unpredictable
var randomX = (Math.random() - 0.5) * 2;
var randomY = (Math.random() - 0.5) * 2;
self.velocityX = (dx / distance + randomX * 0.3) * self.speed;
self.velocityY = (dy / distance + randomY * 0.3) * self.speed;
} else {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('enemyHit').play();
// Flash red when hit
tween(enemyGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.makeGiant = function () {
self.isGiant = true;
// Giant enemies have 3 times the health of regular enemies
self.health = wave * 3;
self.maxHealth = self.health;
self.speed = self.speed * 0.7;
self.points = self.points * 4;
// Scale up with tween animation
tween(enemyGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 500,
easing: tween.bounceOut
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.weapon = {
damage: 1,
fireRate: 10,
name: 'Basic Gun'
};
self.lastShot = 0;
self.shoot = function (targetX, targetY) {
// Super bullets have much slower fire rate
var currentFireRate = superBulletActive ? 60 : self.weapon.fireRate; // 60 ticks = 1 second delay for super bullets
if (LK.ticks - self.lastShot < currentFireRate) return;
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
if (superBulletActive) {
bullet.makeSuper();
bullet.damage = superBulletDamage; // Use very high damage for super bullets
} else {
bullet.damage = self.weapon.damage;
}
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = dx / distance * 15;
bullet.velocityY = dy / distance * 15;
bullets.push(bullet);
game.addChild(bullet);
self.lastShot = LK.ticks;
LK.getSound('shoot').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game state variables
var player;
var enemies = [];
var bullets = [];
var gamePoints = storage.points || 0;
var wave = storage.wave || 1;
var enemiesKilled = 0;
var enemiesInWave = 5;
var waveComplete = false;
var smallEnemiesSpawned = 0;
var bossSpawned = false;
var bossActive = false;
var shopOpen = false;
var isMouseDown = false;
var lastMouseX = 0;
var lastMouseY = 0;
var superBulletActive = false;
var superBulletCooldown = 0;
var superBulletDuration = 10000; // 10 seconds
var superBulletCooldownTime = 60000; // 60 seconds (1 minute)
var superBulletDamage = 100; // Very high damage for devastating effect
var atomCooldown = 0;
var atomCooldownTime = 120000; // 120 seconds (2 minutes)
// Weapon shop data - all weapons deal 1 damage for consistent bullet counting
var weapons = [{
name: 'Basic Gun',
damage: 1,
fireRate: 10,
cost: 0
}, {
name: 'Rapid Fire',
damage: 1,
fireRate: 5,
cost: 50
}, {
name: 'Heavy Cannon',
damage: 1,
fireRate: 20,
cost: 100
}, {
name: 'Sniper Rifle',
damage: 1,
fireRate: 30,
cost: 200
}, {
name: 'Plasma Gun',
damage: 1,
fireRate: 8,
cost: 150
}];
// UI Elements
var pointsText = new Text2('Points: 0', {
size: 40,
fill: 0xFFFFFF
});
pointsText.anchor.set(0, 0);
pointsText.x = 120;
pointsText.y = 20;
LK.gui.topLeft.addChild(pointsText);
var waveText = new Text2('Wave: 1', {
size: 40,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = -20;
waveText.y = 20;
LK.gui.topRight.addChild(waveText);
var healthText = new Text2('Health: 100', {
size: 40,
fill: 0xFF4444
});
healthText.anchor.set(0.5, 1);
healthText.y = -80;
LK.gui.bottom.addChild(healthText);
// Life bar background
var lifeBarBackground = LK.getAsset('lifeBarBackground', {
anchorX: 0.5,
anchorY: 0.5
});
lifeBarBackground.x = 0;
lifeBarBackground.y = -40;
LK.gui.bottom.addChild(lifeBarBackground);
// Life bar foreground
var lifeBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0.5
});
lifeBar.x = -400; // Start from left edge of background (doubled size)
lifeBar.y = -40;
LK.gui.bottom.addChild(lifeBar);
// Power button in middle left
var powerButton = game.addChild(LK.getAsset('powerButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 1200
}));
// Scale power button to 3.75 times bigger with smooth animation
tween(powerButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var powerButtonText = new Text2('SUPER', {
size: 24,
fill: 0xFFFFFF
});
powerButtonText.anchor.set(0.5, 0.5);
powerButtonText.x = powerButton.x;
powerButtonText.y = powerButton.y;
game.addChild(powerButtonText);
var powerCooldownText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
powerCooldownText.anchor.set(0.5, 0.5);
powerCooldownText.x = powerButton.x;
powerCooldownText.y = powerButton.y + 50;
game.addChild(powerCooldownText);
// Restart button under the atom button
var restartButton = game.addChild(LK.getAsset('restartButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 2200 // Position below atom button
}));
// Scale restart button to 3.75 times bigger with smooth animation
tween(restartButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var restartButtonText = new Text2('RESTART', {
size: 18,
fill: 0xFFFFFF
});
restartButtonText.anchor.set(0.5, 0.5);
restartButtonText.x = restartButton.x;
restartButtonText.y = restartButton.y;
game.addChild(restartButtonText);
// Atom button under the power button
var atomButton = game.addChild(LK.getAsset('atomButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 1700 // Further increased spacing to prevent overlap with scaled buttons
}));
// Scale atom button to 3.75 times bigger with smooth animation
tween(atomButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var atomButtonText = new Text2('ATOM', {
size: 24,
fill: 0xFFFFFF
});
atomButtonText.anchor.set(0.5, 0.5);
atomButtonText.x = atomButton.x;
atomButtonText.y = atomButton.y;
game.addChild(atomButtonText);
var atomCooldownText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
atomCooldownText.anchor.set(0.5, 0.5);
atomCooldownText.x = atomButton.x;
atomCooldownText.y = atomButton.y + 50;
game.addChild(atomCooldownText);
// Shop button
var shopButton = game.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 120,
y: 2732 - 100
}));
var shopButtonText = new Text2('SHOP', {
size: 32,
fill: 0xFFFFFF
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = shopButton.x;
shopButtonText.y = shopButton.y;
game.addChild(shopButtonText);
// Shop UI
var shopContainer = new Container();
shopContainer.visible = false;
game.addChild(shopContainer);
var shopBackground = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 6,
scaleY: 9
}));
var shopTitle = new Text2('WEAPON SHOP', {
size: 60,
fill: 0xFFFFFF
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 1024;
shopTitle.y = 800;
shopContainer.addChild(shopTitle);
var closeShopButton = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1800,
scaleX: 1.5,
scaleY: 0.75
}));
var closeShopText = new Text2('CLOSE', {
size: 40,
fill: 0xFFFFFF
});
closeShopText.anchor.set(0.5, 0.5);
closeShopText.x = 1024;
closeShopText.y = 1800;
shopContainer.addChild(closeShopText);
// Weapon shop items
var weaponButtons = [];
var weaponTexts = [];
for (var i = 0; i < weapons.length; i++) {
var weapon = weapons[i];
var buttonY = 1000 + i * 120;
var weaponButton = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: buttonY,
scaleX: 2.25,
scaleY: 0.75
}));
weaponButton.weaponIndex = i;
weaponButtons.push(weaponButton);
var weaponText = new Text2(weapon.name + ' - ' + weapon.cost + ' pts', {
size: 32,
fill: 0xFFFFFF
});
weaponText.anchor.set(0.5, 0.5);
weaponText.x = 1024;
weaponText.y = buttonY;
shopContainer.addChild(weaponText);
weaponTexts.push(weaponText);
}
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Scale player to 3 times bigger with smooth animation
var playerGraphics = player.children[0];
playerGraphics.scaleX = 1;
playerGraphics.scaleY = 1;
tween(playerGraphics, {
scaleX: 3,
scaleY: 3
}, {
duration: 800,
easing: tween.bounceOut
});
// Game functions
function spawnEnemy() {
var enemy = new Enemy();
// Spawn from random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
// Scale enemy with wave - health equals wave number for bullet count requirement
enemy.health = wave; // Wave 1 = 1 bullet, Wave 2 = 2 bullets, etc.
enemy.maxHealth = enemy.health;
enemy.speed = 1 + wave * 0.1;
enemy.points = 10 + wave * 2;
// Spawn giant enemy after every 10 small enemies
if (smallEnemiesSpawned >= 10) {
enemy.makeGiant();
smallEnemiesSpawned = 0; // Reset counter after spawning giant
} else {
smallEnemiesSpawned++; // Increment counter for small enemy
}
enemies.push(enemy);
game.addChild(enemy);
// Add spawn animation for all enemies
var enemyGraphics = enemy.children[0];
enemyGraphics.scaleX = 0.1;
enemyGraphics.scaleY = 0.1;
tween(enemyGraphics, {
scaleX: enemy.isGiant ? 2.5 : 1,
scaleY: enemy.isGiant ? 2.5 : 1
}, {
duration: 300,
easing: tween.elasticOut
});
}
function spawnBoss() {
var boss = new Boss();
// Spawn boss from center top
boss.x = 1024;
boss.y = -100;
boss.makeBoss();
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
bossActive = true;
// Add dramatic spawn animation for boss
var bossGraphics = boss.children[0];
bossGraphics.scaleX = 0.1;
bossGraphics.scaleY = 0.1;
tween(bossGraphics, {
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 1500,
easing: tween.elasticOut
});
}
function updateUI() {
pointsText.setText('Points: ' + gamePoints);
waveText.setText('Wave: ' + wave);
healthText.setText('Health: ' + player.health);
// Update life bar width based on player health
var healthPercentage = player.health / player.maxHealth;
var newWidth = 800 * healthPercentage;
lifeBar.width = Math.max(0, newWidth);
// Change life bar color based on health percentage
if (healthPercentage > 0.6) {
lifeBar.tint = 0x4caf50; // Green
} else if (healthPercentage > 0.3) {
lifeBar.tint = 0xffc107; // Yellow
} else {
lifeBar.tint = 0xf44336; // Red
}
}
function openShop() {
shopOpen = true;
shopContainer.visible = true;
// Update weapon button states
for (var i = 0; i < weapons.length; i++) {
var weapon = weapons[i];
var canAfford = gamePoints >= weapon.cost;
var owned = player.weapon.name === weapon.name;
var colorHex = owned ? 0x00ff00 : canAfford ? 0xffffff : 0x666666;
var text = weapon.name + ' - ' + weapon.cost + ' pts';
if (owned) text = weapon.name + ' - EQUIPPED';
weaponTexts[i].setText(text);
weaponTexts[i].tint = colorHex;
}
}
function closeShop() {
shopOpen = false;
shopContainer.visible = false;
}
function buyWeapon(weaponIndex) {
var weapon = weapons[weaponIndex];
if (weapon && gamePoints >= weapon.cost && player.weapon.name !== weapon.name) {
gamePoints -= weapon.cost;
player.weapon = {
damage: weapon.damage,
fireRate: weapon.fireRate,
name: weapon.name
};
storage.points = gamePoints;
updateUI();
openShop(); // Refresh shop display
}
}
// Event handlers
shopButton.down = function (x, y, obj) {
openShop();
};
closeShopButton.down = function (x, y, obj) {
closeShop();
};
for (var i = 0; i < weaponButtons.length; i++) {
weaponButtons[i].down = function (x, y, obj) {
buyWeapon(obj.weaponIndex);
};
}
powerButton.down = function (x, y, obj) {
if (superBulletCooldown <= 0 && !superBulletActive) {
superBulletActive = true;
superBulletCooldown = superBulletCooldownTime;
// Visual feedback
tween(powerButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
superBulletActive = false;
tween(powerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, superBulletDuration);
}
};
restartButton.down = function (x, y, obj) {
// Reset all game state to starting values
gamePoints = 0;
wave = 1;
enemiesKilled = 0;
enemiesInWave = 5;
waveComplete = false;
smallEnemiesSpawned = 0;
bossSpawned = false;
bossActive = false;
superBulletActive = false;
superBulletCooldown = 0;
atomCooldown = 0;
isMouseDown = false;
// Reset player health and position
player.health = 100;
player.maxHealth = 100;
player.weapon = {
damage: 1,
fireRate: 10,
name: 'Basic Gun'
};
player.x = 1024;
player.y = 1366;
// Clear all enemies and bullets
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
// Reset storage
storage.points = 0;
storage.wave = 1;
// Visual feedback for restart button
tween(restartButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, 500);
// Spawn initial enemies for wave 1
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 2000);
}
};
atomButton.down = function (x, y, obj) {
if (atomCooldown <= 0) {
// Make all enemies disappear by going up quickly with moving effect
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
gamePoints += enemy.points;
enemiesKilled++;
LK.getSound('enemyDestroy').play();
// Create moving effect - enemies fly up quickly and fade out
tween(enemy, {
y: enemy.y - 1000,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
enemy.destroy();
}
});
enemies.splice(i, 1);
}
atomCooldown = atomCooldownTime;
// Visual feedback
tween(atomButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
tween(atomButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, 500);
}
};
game.down = function (x, y, obj) {
if (!shopOpen && player) {
// Right click moves player, left click shoots
if (obj.event && obj.event.button === 2) {
// Right click - move player
player.x = x;
player.y = y;
} else {
// Left click or touch - shoot
isMouseDown = true;
lastMouseX = x;
lastMouseY = y;
player.shoot(x, y);
}
}
};
// Spawn initial enemies
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 2000);
}
game.move = function (x, y, obj) {
if (isMouseDown && !shopOpen) {
lastMouseX = x;
lastMouseY = y;
}
};
game.up = function (x, y, obj) {
isMouseDown = false;
};
// Prevent context menu on right click
game.on('rightdown', function (x, y, obj) {
if (obj.event) {
obj.event.preventDefault();
}
});
// Main game loop
game.update = function () {
if (shopOpen) return;
// Continuous firing when mouse is held down
if (isMouseDown && player) {
player.shoot(lastMouseX, lastMouseY);
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet is off screen
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (bullet.isSuper) {
// Super bullet area damage - hit all enemies in area
var areaRadius = 200;
for (var k = enemies.length - 1; k >= 0; k--) {
var areaEnemy = enemies[k];
var dx = areaEnemy.x - bullet.x;
var dy = areaEnemy.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= areaRadius) {
var destroyed = areaEnemy.takeDamage(bullet.damage);
if (destroyed) {
gamePoints += areaEnemy.points;
enemiesKilled++;
if (areaEnemy.isBoss) {
bossActive = false;
}
LK.getSound('enemyDestroy').play();
enemies.splice(k, 1);
if (k < j) j--; // Adjust index if we removed an enemy before current
}
}
}
} else {
// Regular bullet single target damage
var destroyed = enemy.takeDamage(bullet.damage);
if (destroyed) {
gamePoints += enemy.points;
enemiesKilled++;
if (enemy.isBoss) {
bossActive = false;
}
LK.getSound('enemyDestroy').play();
enemies.splice(j, 1);
}
}
bullet.destroy();
bullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (hitEnemy) continue;
}
// Check enemy-player collisions
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(player)) {
// Boss enemies deal 3x damage, giant enemies deal 2x damage compared to regular enemies
var damage = enemy.isBoss ? 30 : enemy.isGiant ? 20 : 10;
player.health -= damage;
if (enemy.isBoss) {
bossActive = false;
}
enemy.destroy();
enemies.splice(i, 1);
if (player.health <= 0) {
// Game over - reset to chapter 1
gamePoints = 0; // Reset score to 0 when player dies
storage.points = gamePoints;
storage.wave = 1; // Reset to chapter 1 when player dies
LK.showGameOver();
return;
}
}
}
// Check wave completion
if (enemiesKilled >= enemiesInWave && enemies.length === 0 && !waveComplete && !bossSpawned) {
// Only spawn boss at the end of wave 1 (first section)
if (wave === 1) {
bossSpawned = true;
waveComplete = true; // Mark wave as complete so no more regular enemies spawn
LK.setTimeout(function () {
spawnBoss();
}, 2000);
} else {
// For all other waves, advance directly to next wave without boss
waveComplete = true;
wave++;
enemiesKilled = 0;
smallEnemiesSpawned = 0;
bossSpawned = false;
bossActive = false;
enemiesInWave = Math.min(5 + wave, 15);
// Spawn next wave after delay
LK.setTimeout(function () {
waveComplete = false;
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 1500);
}
}, 3000);
}
} else if (bossSpawned && !bossActive && enemies.length === 0 && waveComplete) {
// Boss defeated, advance to next wave (this will be wave 2 after boss from wave 1)
wave++;
enemiesKilled = 0;
smallEnemiesSpawned = 0; // Reset small enemies counter for new wave
bossSpawned = false;
bossActive = false;
enemiesInWave = Math.min(5 + wave, 15);
// Spawn next wave after delay
LK.setTimeout(function () {
waveComplete = false;
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 1500);
}
}, 3000);
}
// Periodic enemy spawning during wave - but not when boss is active or wave is complete
if (!waveComplete && !bossActive && enemies.length < Math.min(enemiesInWave, 8)) {
if (Math.random() < 0.01) {
spawnEnemy();
}
}
// Update super bullet system
if (superBulletCooldown > 0) {
superBulletCooldown -= 16.67; // Approximately 1 frame at 60fps
if (superBulletCooldown < 0) superBulletCooldown = 0;
}
// Update atom button system
if (atomCooldown > 0) {
atomCooldown -= 16.67; // Approximately 1 frame at 60fps
if (atomCooldown < 0) atomCooldown = 0;
}
// Update power button UI
if (superBulletActive) {
var remaining = Math.ceil((superBulletDuration - LK.ticks * 16.67) / 1000);
powerButtonText.setText('ACTIVE');
powerCooldownText.setText('');
if (powerButton.tint !== 0x00ff00) {
tween(powerButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
} else if (superBulletCooldown > 0) {
var cooldownSeconds = Math.ceil(superBulletCooldown / 1000);
powerButtonText.setText('SUPER');
powerCooldownText.setText(cooldownSeconds + 's');
if (powerButton.tint !== 0xff0000) {
tween(powerButton, {
tint: 0xff0000,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
powerButtonText.setText('SUPER');
powerCooldownText.setText('READY');
if (powerButton.tint !== 0x00ff00) {
tween(powerButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Update atom button UI
if (atomCooldown > 0) {
var atomCooldownSeconds = Math.ceil(atomCooldown / 1000);
atomButtonText.setText('ATOM');
atomCooldownText.setText(atomCooldownSeconds + 's');
if (atomButton.tint !== 0xff0000) {
tween(atomButton, {
tint: 0xff0000,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
atomButtonText.setText('ATOM');
atomCooldownText.setText('READY');
if (atomButton.tint !== 0x00ff00) {
tween(atomButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
}
updateUI();
// Save progress
if (LK.ticks % 300 === 0) {
storage.points = gamePoints;
storage.wave = wave;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 9; // Will be set to wave * 9 (3x giant health)
self.maxHealth = 9;
self.speed = 0.5; // Slower than giant enemies
self.points = 100;
self.isBoss = true;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Boss moves slowly and deliberately
var randomX = (Math.random() - 0.5) * 1;
var randomY = (Math.random() - 0.5) * 1;
self.velocityX = (dx / distance + randomX * 0.2) * self.speed;
self.velocityY = (dy / distance + randomY * 0.2) * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('enemyHit').play();
// Flash red when hit
tween(bossGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(bossGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.makeBoss = function () {
// Boss has 3 times the health of giant enemies
self.health = wave * 9; // 3x giant health (wave * 3 * 3)
self.maxHealth = self.health;
self.speed = 0.5; // Slower than giants
self.points = self.points * 10; // High point value
// Scale up to twice the size of giant enemies (5x total)
tween(bossGraphics, {
scaleX: 5.0,
scaleY: 5.0,
tint: 0xFF6600 // Orange tint to distinguish from other enemies
}, {
duration: 1000,
easing: tween.bounceOut
});
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.isSuper = false;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 1;
self.makeSuper = function () {
self.isSuper = true;
self.removeChild(bulletGraphics);
bulletGraphics = self.attachAsset('superBullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glowing effect with tween
tween(bulletGraphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xffff00
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bulletGraphics, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xff4444
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.speed = 1;
self.points = 10;
self.isGiant = false;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Giant enemies change direction more aggressively
if (self.isGiant) {
// Add some randomness to giant enemy movement to make them more unpredictable
var randomX = (Math.random() - 0.5) * 2;
var randomY = (Math.random() - 0.5) * 2;
self.velocityX = (dx / distance + randomX * 0.3) * self.speed;
self.velocityY = (dy / distance + randomY * 0.3) * self.speed;
} else {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('enemyHit').play();
// Flash red when hit
tween(enemyGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.makeGiant = function () {
self.isGiant = true;
// Giant enemies have 3 times the health of regular enemies
self.health = wave * 3;
self.maxHealth = self.health;
self.speed = self.speed * 0.7;
self.points = self.points * 4;
// Scale up with tween animation
tween(enemyGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 500,
easing: tween.bounceOut
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.weapon = {
damage: 1,
fireRate: 10,
name: 'Basic Gun'
};
self.lastShot = 0;
self.shoot = function (targetX, targetY) {
// Super bullets have much slower fire rate
var currentFireRate = superBulletActive ? 60 : self.weapon.fireRate; // 60 ticks = 1 second delay for super bullets
if (LK.ticks - self.lastShot < currentFireRate) return;
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
if (superBulletActive) {
bullet.makeSuper();
bullet.damage = superBulletDamage; // Use very high damage for super bullets
} else {
bullet.damage = self.weapon.damage;
}
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = dx / distance * 15;
bullet.velocityY = dy / distance * 15;
bullets.push(bullet);
game.addChild(bullet);
self.lastShot = LK.ticks;
LK.getSound('shoot').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game state variables
var player;
var enemies = [];
var bullets = [];
var gamePoints = storage.points || 0;
var wave = storage.wave || 1;
var enemiesKilled = 0;
var enemiesInWave = 5;
var waveComplete = false;
var smallEnemiesSpawned = 0;
var bossSpawned = false;
var bossActive = false;
var shopOpen = false;
var isMouseDown = false;
var lastMouseX = 0;
var lastMouseY = 0;
var superBulletActive = false;
var superBulletCooldown = 0;
var superBulletDuration = 10000; // 10 seconds
var superBulletCooldownTime = 60000; // 60 seconds (1 minute)
var superBulletDamage = 100; // Very high damage for devastating effect
var atomCooldown = 0;
var atomCooldownTime = 120000; // 120 seconds (2 minutes)
// Weapon shop data - all weapons deal 1 damage for consistent bullet counting
var weapons = [{
name: 'Basic Gun',
damage: 1,
fireRate: 10,
cost: 0
}, {
name: 'Rapid Fire',
damage: 1,
fireRate: 5,
cost: 50
}, {
name: 'Heavy Cannon',
damage: 1,
fireRate: 20,
cost: 100
}, {
name: 'Sniper Rifle',
damage: 1,
fireRate: 30,
cost: 200
}, {
name: 'Plasma Gun',
damage: 1,
fireRate: 8,
cost: 150
}];
// UI Elements
var pointsText = new Text2('Points: 0', {
size: 40,
fill: 0xFFFFFF
});
pointsText.anchor.set(0, 0);
pointsText.x = 120;
pointsText.y = 20;
LK.gui.topLeft.addChild(pointsText);
var waveText = new Text2('Wave: 1', {
size: 40,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = -20;
waveText.y = 20;
LK.gui.topRight.addChild(waveText);
var healthText = new Text2('Health: 100', {
size: 40,
fill: 0xFF4444
});
healthText.anchor.set(0.5, 1);
healthText.y = -80;
LK.gui.bottom.addChild(healthText);
// Life bar background
var lifeBarBackground = LK.getAsset('lifeBarBackground', {
anchorX: 0.5,
anchorY: 0.5
});
lifeBarBackground.x = 0;
lifeBarBackground.y = -40;
LK.gui.bottom.addChild(lifeBarBackground);
// Life bar foreground
var lifeBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0.5
});
lifeBar.x = -400; // Start from left edge of background (doubled size)
lifeBar.y = -40;
LK.gui.bottom.addChild(lifeBar);
// Power button in middle left
var powerButton = game.addChild(LK.getAsset('powerButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 1200
}));
// Scale power button to 3.75 times bigger with smooth animation
tween(powerButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var powerButtonText = new Text2('SUPER', {
size: 24,
fill: 0xFFFFFF
});
powerButtonText.anchor.set(0.5, 0.5);
powerButtonText.x = powerButton.x;
powerButtonText.y = powerButton.y;
game.addChild(powerButtonText);
var powerCooldownText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
powerCooldownText.anchor.set(0.5, 0.5);
powerCooldownText.x = powerButton.x;
powerCooldownText.y = powerButton.y + 50;
game.addChild(powerCooldownText);
// Restart button under the atom button
var restartButton = game.addChild(LK.getAsset('restartButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 2200 // Position below atom button
}));
// Scale restart button to 3.75 times bigger with smooth animation
tween(restartButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var restartButtonText = new Text2('RESTART', {
size: 18,
fill: 0xFFFFFF
});
restartButtonText.anchor.set(0.5, 0.5);
restartButtonText.x = restartButton.x;
restartButtonText.y = restartButton.y;
game.addChild(restartButtonText);
// Atom button under the power button
var atomButton = game.addChild(LK.getAsset('atomButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 1700 // Further increased spacing to prevent overlap with scaled buttons
}));
// Scale atom button to 3.75 times bigger with smooth animation
tween(atomButton, {
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 800,
easing: tween.bounceOut
});
var atomButtonText = new Text2('ATOM', {
size: 24,
fill: 0xFFFFFF
});
atomButtonText.anchor.set(0.5, 0.5);
atomButtonText.x = atomButton.x;
atomButtonText.y = atomButton.y;
game.addChild(atomButtonText);
var atomCooldownText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
atomCooldownText.anchor.set(0.5, 0.5);
atomCooldownText.x = atomButton.x;
atomCooldownText.y = atomButton.y + 50;
game.addChild(atomCooldownText);
// Shop button
var shopButton = game.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 120,
y: 2732 - 100
}));
var shopButtonText = new Text2('SHOP', {
size: 32,
fill: 0xFFFFFF
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = shopButton.x;
shopButtonText.y = shopButton.y;
game.addChild(shopButtonText);
// Shop UI
var shopContainer = new Container();
shopContainer.visible = false;
game.addChild(shopContainer);
var shopBackground = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 6,
scaleY: 9
}));
var shopTitle = new Text2('WEAPON SHOP', {
size: 60,
fill: 0xFFFFFF
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 1024;
shopTitle.y = 800;
shopContainer.addChild(shopTitle);
var closeShopButton = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1800,
scaleX: 1.5,
scaleY: 0.75
}));
var closeShopText = new Text2('CLOSE', {
size: 40,
fill: 0xFFFFFF
});
closeShopText.anchor.set(0.5, 0.5);
closeShopText.x = 1024;
closeShopText.y = 1800;
shopContainer.addChild(closeShopText);
// Weapon shop items
var weaponButtons = [];
var weaponTexts = [];
for (var i = 0; i < weapons.length; i++) {
var weapon = weapons[i];
var buttonY = 1000 + i * 120;
var weaponButton = shopContainer.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: buttonY,
scaleX: 2.25,
scaleY: 0.75
}));
weaponButton.weaponIndex = i;
weaponButtons.push(weaponButton);
var weaponText = new Text2(weapon.name + ' - ' + weapon.cost + ' pts', {
size: 32,
fill: 0xFFFFFF
});
weaponText.anchor.set(0.5, 0.5);
weaponText.x = 1024;
weaponText.y = buttonY;
shopContainer.addChild(weaponText);
weaponTexts.push(weaponText);
}
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Scale player to 3 times bigger with smooth animation
var playerGraphics = player.children[0];
playerGraphics.scaleX = 1;
playerGraphics.scaleY = 1;
tween(playerGraphics, {
scaleX: 3,
scaleY: 3
}, {
duration: 800,
easing: tween.bounceOut
});
// Game functions
function spawnEnemy() {
var enemy = new Enemy();
// Spawn from random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
// Scale enemy with wave - health equals wave number for bullet count requirement
enemy.health = wave; // Wave 1 = 1 bullet, Wave 2 = 2 bullets, etc.
enemy.maxHealth = enemy.health;
enemy.speed = 1 + wave * 0.1;
enemy.points = 10 + wave * 2;
// Spawn giant enemy after every 10 small enemies
if (smallEnemiesSpawned >= 10) {
enemy.makeGiant();
smallEnemiesSpawned = 0; // Reset counter after spawning giant
} else {
smallEnemiesSpawned++; // Increment counter for small enemy
}
enemies.push(enemy);
game.addChild(enemy);
// Add spawn animation for all enemies
var enemyGraphics = enemy.children[0];
enemyGraphics.scaleX = 0.1;
enemyGraphics.scaleY = 0.1;
tween(enemyGraphics, {
scaleX: enemy.isGiant ? 2.5 : 1,
scaleY: enemy.isGiant ? 2.5 : 1
}, {
duration: 300,
easing: tween.elasticOut
});
}
function spawnBoss() {
var boss = new Boss();
// Spawn boss from center top
boss.x = 1024;
boss.y = -100;
boss.makeBoss();
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
bossActive = true;
// Add dramatic spawn animation for boss
var bossGraphics = boss.children[0];
bossGraphics.scaleX = 0.1;
bossGraphics.scaleY = 0.1;
tween(bossGraphics, {
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 1500,
easing: tween.elasticOut
});
}
function updateUI() {
pointsText.setText('Points: ' + gamePoints);
waveText.setText('Wave: ' + wave);
healthText.setText('Health: ' + player.health);
// Update life bar width based on player health
var healthPercentage = player.health / player.maxHealth;
var newWidth = 800 * healthPercentage;
lifeBar.width = Math.max(0, newWidth);
// Change life bar color based on health percentage
if (healthPercentage > 0.6) {
lifeBar.tint = 0x4caf50; // Green
} else if (healthPercentage > 0.3) {
lifeBar.tint = 0xffc107; // Yellow
} else {
lifeBar.tint = 0xf44336; // Red
}
}
function openShop() {
shopOpen = true;
shopContainer.visible = true;
// Update weapon button states
for (var i = 0; i < weapons.length; i++) {
var weapon = weapons[i];
var canAfford = gamePoints >= weapon.cost;
var owned = player.weapon.name === weapon.name;
var colorHex = owned ? 0x00ff00 : canAfford ? 0xffffff : 0x666666;
var text = weapon.name + ' - ' + weapon.cost + ' pts';
if (owned) text = weapon.name + ' - EQUIPPED';
weaponTexts[i].setText(text);
weaponTexts[i].tint = colorHex;
}
}
function closeShop() {
shopOpen = false;
shopContainer.visible = false;
}
function buyWeapon(weaponIndex) {
var weapon = weapons[weaponIndex];
if (weapon && gamePoints >= weapon.cost && player.weapon.name !== weapon.name) {
gamePoints -= weapon.cost;
player.weapon = {
damage: weapon.damage,
fireRate: weapon.fireRate,
name: weapon.name
};
storage.points = gamePoints;
updateUI();
openShop(); // Refresh shop display
}
}
// Event handlers
shopButton.down = function (x, y, obj) {
openShop();
};
closeShopButton.down = function (x, y, obj) {
closeShop();
};
for (var i = 0; i < weaponButtons.length; i++) {
weaponButtons[i].down = function (x, y, obj) {
buyWeapon(obj.weaponIndex);
};
}
powerButton.down = function (x, y, obj) {
if (superBulletCooldown <= 0 && !superBulletActive) {
superBulletActive = true;
superBulletCooldown = superBulletCooldownTime;
// Visual feedback
tween(powerButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
superBulletActive = false;
tween(powerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, superBulletDuration);
}
};
restartButton.down = function (x, y, obj) {
// Reset all game state to starting values
gamePoints = 0;
wave = 1;
enemiesKilled = 0;
enemiesInWave = 5;
waveComplete = false;
smallEnemiesSpawned = 0;
bossSpawned = false;
bossActive = false;
superBulletActive = false;
superBulletCooldown = 0;
atomCooldown = 0;
isMouseDown = false;
// Reset player health and position
player.health = 100;
player.maxHealth = 100;
player.weapon = {
damage: 1,
fireRate: 10,
name: 'Basic Gun'
};
player.x = 1024;
player.y = 1366;
// Clear all enemies and bullets
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
// Reset storage
storage.points = 0;
storage.wave = 1;
// Visual feedback for restart button
tween(restartButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, 500);
// Spawn initial enemies for wave 1
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 2000);
}
};
atomButton.down = function (x, y, obj) {
if (atomCooldown <= 0) {
// Make all enemies disappear by going up quickly with moving effect
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
gamePoints += enemy.points;
enemiesKilled++;
LK.getSound('enemyDestroy').play();
// Create moving effect - enemies fly up quickly and fade out
tween(enemy, {
y: enemy.y - 1000,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
enemy.destroy();
}
});
enemies.splice(i, 1);
}
atomCooldown = atomCooldownTime;
// Visual feedback
tween(atomButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00ff00
}, {
duration: 200,
easing: tween.bounceOut
});
LK.setTimeout(function () {
tween(atomButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200
});
}, 500);
}
};
game.down = function (x, y, obj) {
if (!shopOpen && player) {
// Right click moves player, left click shoots
if (obj.event && obj.event.button === 2) {
// Right click - move player
player.x = x;
player.y = y;
} else {
// Left click or touch - shoot
isMouseDown = true;
lastMouseX = x;
lastMouseY = y;
player.shoot(x, y);
}
}
};
// Spawn initial enemies
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 2000);
}
game.move = function (x, y, obj) {
if (isMouseDown && !shopOpen) {
lastMouseX = x;
lastMouseY = y;
}
};
game.up = function (x, y, obj) {
isMouseDown = false;
};
// Prevent context menu on right click
game.on('rightdown', function (x, y, obj) {
if (obj.event) {
obj.event.preventDefault();
}
});
// Main game loop
game.update = function () {
if (shopOpen) return;
// Continuous firing when mouse is held down
if (isMouseDown && player) {
player.shoot(lastMouseX, lastMouseY);
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet is off screen
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (bullet.isSuper) {
// Super bullet area damage - hit all enemies in area
var areaRadius = 200;
for (var k = enemies.length - 1; k >= 0; k--) {
var areaEnemy = enemies[k];
var dx = areaEnemy.x - bullet.x;
var dy = areaEnemy.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= areaRadius) {
var destroyed = areaEnemy.takeDamage(bullet.damage);
if (destroyed) {
gamePoints += areaEnemy.points;
enemiesKilled++;
if (areaEnemy.isBoss) {
bossActive = false;
}
LK.getSound('enemyDestroy').play();
enemies.splice(k, 1);
if (k < j) j--; // Adjust index if we removed an enemy before current
}
}
}
} else {
// Regular bullet single target damage
var destroyed = enemy.takeDamage(bullet.damage);
if (destroyed) {
gamePoints += enemy.points;
enemiesKilled++;
if (enemy.isBoss) {
bossActive = false;
}
LK.getSound('enemyDestroy').play();
enemies.splice(j, 1);
}
}
bullet.destroy();
bullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (hitEnemy) continue;
}
// Check enemy-player collisions
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(player)) {
// Boss enemies deal 3x damage, giant enemies deal 2x damage compared to regular enemies
var damage = enemy.isBoss ? 30 : enemy.isGiant ? 20 : 10;
player.health -= damage;
if (enemy.isBoss) {
bossActive = false;
}
enemy.destroy();
enemies.splice(i, 1);
if (player.health <= 0) {
// Game over - reset to chapter 1
gamePoints = 0; // Reset score to 0 when player dies
storage.points = gamePoints;
storage.wave = 1; // Reset to chapter 1 when player dies
LK.showGameOver();
return;
}
}
}
// Check wave completion
if (enemiesKilled >= enemiesInWave && enemies.length === 0 && !waveComplete && !bossSpawned) {
// Only spawn boss at the end of wave 1 (first section)
if (wave === 1) {
bossSpawned = true;
waveComplete = true; // Mark wave as complete so no more regular enemies spawn
LK.setTimeout(function () {
spawnBoss();
}, 2000);
} else {
// For all other waves, advance directly to next wave without boss
waveComplete = true;
wave++;
enemiesKilled = 0;
smallEnemiesSpawned = 0;
bossSpawned = false;
bossActive = false;
enemiesInWave = Math.min(5 + wave, 15);
// Spawn next wave after delay
LK.setTimeout(function () {
waveComplete = false;
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 1500);
}
}, 3000);
}
} else if (bossSpawned && !bossActive && enemies.length === 0 && waveComplete) {
// Boss defeated, advance to next wave (this will be wave 2 after boss from wave 1)
wave++;
enemiesKilled = 0;
smallEnemiesSpawned = 0; // Reset small enemies counter for new wave
bossSpawned = false;
bossActive = false;
enemiesInWave = Math.min(5 + wave, 15);
// Spawn next wave after delay
LK.setTimeout(function () {
waveComplete = false;
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
spawnEnemy();
}, i * 1500);
}
}, 3000);
}
// Periodic enemy spawning during wave - but not when boss is active or wave is complete
if (!waveComplete && !bossActive && enemies.length < Math.min(enemiesInWave, 8)) {
if (Math.random() < 0.01) {
spawnEnemy();
}
}
// Update super bullet system
if (superBulletCooldown > 0) {
superBulletCooldown -= 16.67; // Approximately 1 frame at 60fps
if (superBulletCooldown < 0) superBulletCooldown = 0;
}
// Update atom button system
if (atomCooldown > 0) {
atomCooldown -= 16.67; // Approximately 1 frame at 60fps
if (atomCooldown < 0) atomCooldown = 0;
}
// Update power button UI
if (superBulletActive) {
var remaining = Math.ceil((superBulletDuration - LK.ticks * 16.67) / 1000);
powerButtonText.setText('ACTIVE');
powerCooldownText.setText('');
if (powerButton.tint !== 0x00ff00) {
tween(powerButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
} else if (superBulletCooldown > 0) {
var cooldownSeconds = Math.ceil(superBulletCooldown / 1000);
powerButtonText.setText('SUPER');
powerCooldownText.setText(cooldownSeconds + 's');
if (powerButton.tint !== 0xff0000) {
tween(powerButton, {
tint: 0xff0000,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
powerButtonText.setText('SUPER');
powerCooldownText.setText('READY');
if (powerButton.tint !== 0x00ff00) {
tween(powerButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Update atom button UI
if (atomCooldown > 0) {
var atomCooldownSeconds = Math.ceil(atomCooldown / 1000);
atomButtonText.setText('ATOM');
atomCooldownText.setText(atomCooldownSeconds + 's');
if (atomButton.tint !== 0xff0000) {
tween(atomButton, {
tint: 0xff0000,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
atomButtonText.setText('ATOM');
atomCooldownText.setText('READY');
if (atomButton.tint !== 0x00ff00) {
tween(atomButton, {
tint: 0x00ff00,
scaleX: 3.75,
scaleY: 3.75
}, {
duration: 300,
easing: tween.easeOut
});
}
}
updateUI();
// Save progress
if (LK.ticks % 300 === 0) {
storage.points = gamePoints;
storage.wave = wave;
}
};