/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var B52 = Container.expand(function () {
var self = Container.call(this);
var b52Graphics = self.attachAsset('B52', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint B52 to make it visually distinct (dark gray)
b52Graphics.tint = 0x666666;
self.speed = 1; // Very slow speed
self.health = 5; // 5 hit points - highest health
self.reward = 15000; // $15000 reward - highest reward
self.targetX = 0;
self.targetY = 0;
self.moveTimer = 0;
self.dodgeTimer = 0;
self.dodgeDirection = 1;
self.decoyTimer = 0;
self.maxDecoyRate = 90; // Can deploy decoy every 1.5 seconds
self.update = function () {
// B52 moves slowly and steadily towards target with enhanced dodging
self.moveTimer++;
self.dodgeTimer++;
self.decoyTimer++;
// Enhanced dodging behavior - check for nearby lasers
var shouldDodge = false;
for (var i = 0; i < lasers.length; i++) {
var laser = lasers[i];
var distanceToLaser = Math.sqrt((laser.x - self.x) * (laser.x - self.x) + (laser.y - self.y) * (laser.y - self.y));
if (distanceToLaser < 150 && laser.y < self.y) {
shouldDodge = true;
// Deploy decoy if available
if (self.decoyTimer >= self.maxDecoyRate) {
self.deployDecoy();
}
break;
}
}
// Evasive maneuvers when dodging
if (shouldDodge) {
if (self.dodgeTimer % 30 === 0) {
self.dodgeDirection *= -1;
}
}
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
// Add dodging movement
if (shouldDodge) {
moveX += Math.sin(self.moveTimer * 0.2) * 3 * self.dodgeDirection;
moveY *= 0.5; // Slow down forward movement when dodging
}
self.x += moveX;
self.y += moveY;
// Keep within screen bounds
self.x = Math.max(60, Math.min(2048 - 60, self.x));
}
};
self.deployDecoy = function () {
self.decoyTimer = 0;
// Create decoy explosive
var decoy = new Decoy();
decoy.x = self.x + (Math.random() - 0.5) * 100; // Random offset
decoy.y = self.y - 30;
decoys.push(decoy);
game.addChild(decoy);
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // B52 destroyed
}
return false;
};
self.explodeAreaDamage = function () {
// Area damage when B52 is destroyed
var damageRadius = 200;
LK.effects.flashObject(self, 0xFF6600, 600);
// Damage nearby enemies (friendly fire)
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy !== self) {
var distance = Math.sqrt((enemy.x - self.x) * (enemy.x - self.x) + (enemy.y - self.y) * (enemy.y - self.y));
if (distance < damageRadius) {
if (enemy.takeDamage && enemy.takeDamage()) {
// Enemy destroyed by area damage
LK.effects.flashObject(enemy, 0xFF6600, 400);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
}
// Destroy nearby lasers
for (var j = lasers.length - 1; j >= 0; j--) {
var laser = lasers[j];
var distance = Math.sqrt((laser.x - self.x) * (laser.x - self.x) + (laser.y - self.y) * (laser.y - self.y));
if (distance < damageRadius) {
laser.destroy();
lasers.splice(j, 1);
}
}
};
return self;
});
var Cannon = Container.expand(function () {
var self = Container.call(this);
var cannonGraphics = self.attachAsset('cannon', {
anchorX: 0.5,
anchorY: 1.0
});
self.fireRate = 0;
self.maxFireRate = 2; // Fire every 2 frames at max - 3 shots per second
self.update = function () {
if (self.fireRate > 0) {
self.fireRate--;
}
};
self.canFire = function () {
return self.fireRate <= 0;
};
self.fire = function () {
if (self.canFire()) {
self.fireRate = self.maxFireRate;
return true;
}
return false;
};
return self;
});
var Decoy = Container.expand(function () {
var self = Container.call(this);
var decoyGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint decoy to make it look like a small explosive (red-orange)
decoyGraphics.tint = 0xFF4500;
decoyGraphics.scaleX = 0.6;
decoyGraphics.scaleY = 0.6;
self.speed = -8; // Move upward to intercept lasers
self.lifeTime = 180; // 3 seconds at 60fps
self.update = function () {
self.y += self.speed;
self.lifeTime--;
// Self-destruct after lifetime expires
if (self.lifeTime <= 0) {
return true; // Mark for destruction
}
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.reward = 500; // Default reward for basic enemy - increased reward
self.update = function () {
self.y += self.speed;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // Enemy destroyed
}
return false;
};
return self;
});
var F35 = Container.expand(function () {
var self = Container.call(this);
var f35Graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint F35 to make it visually distinct (darker blue)
f35Graphics.tint = 0x4444FF;
self.speed = 2; // Slow speed
self.health = 3; // 3 hit points
self.reward = 10000; // $10000 reward
self.targetX = 0;
self.targetY = 0;
self.agileTimer = 0;
self.agileDirection = 1;
self.update = function () {
// Agile movement - add evasive maneuvers
self.agileTimer++;
if (self.agileTimer % 60 === 0) {
self.agileDirection *= -1;
}
// Move towards target with agile zigzag pattern
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 + Math.sin(self.agileTimer * 0.1) * 2 * self.agileDirection;
self.y += dy / distance * self.speed;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // F35 destroyed
}
return false;
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphics = self.attachAsset('Rockets', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6; // Fast speed
self.health = 1; // 1 hit point
self.reward = 1000; // $1000 reward
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Move directly towards the cannon with higher speed
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;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // Rocket destroyed
}
return false;
};
return self;
});
var UAV = Container.expand(function () {
var self = Container.call(this);
var uavGraphics = self.attachAsset('UAV', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4; // Medium speed
self.health = 2; // 2 hit points
self.reward = 2500; // $2500 reward
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Move directly towards the cannon
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;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // UAV destroyed
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Create gradient background from sky blue at top to green-brown at bottom
var backgroundGradient = LK.getAsset('background', {
width: 2048,
height: 2732,
color: 0x87CEEB,
// Sky blue
shape: 'box'
});
game.addChild(backgroundGradient);
// Create multiple horizontal strips for gradient effect
var gradientStrips = [];
var stripHeight = 60;
var totalStrips = Math.ceil(2732 / stripHeight);
for (var i = 0; i < totalStrips; i++) {
var strip = LK.getAsset('gradientStrip_' + i, {
width: 2048,
height: stripHeight,
color: 0x87CEEB,
// Will be tinted for gradient
shape: 'box'
});
strip.y = i * stripHeight;
// Calculate gradient progression from sky blue to green to brown
var progress = i / totalStrips;
var r, g, b;
if (progress < 0.6) {
// Sky blue to green transition (top 60% of screen)
var skyProgress = progress / 0.6;
r = Math.floor(135 + (34 - 135) * skyProgress); // 135 -> 34
g = Math.floor(206 + (139 - 206) * skyProgress); // 206 -> 139
b = Math.floor(235 + (34 - 235) * skyProgress); // 235 -> 34
} else {
// Green to brown transition (bottom 40% of screen)
var groundProgress = (progress - 0.6) / 0.4;
r = Math.floor(34 + (139 - 34) * groundProgress); // 34 -> 139
g = Math.floor(139 + (69 - 139) * groundProgress); // 139 -> 69
b = Math.floor(34 + (19 - 34) * groundProgress); // 34 -> 19
}
var color = r << 16 | g << 8 | b;
strip.tint = color;
game.addChild(strip);
gradientStrips.push(strip);
}
// Game variables
var cannon;
var lasers = [];
var enemies = [];
var decoys = [];
var enemySpawnTimer = 0;
var enemySpawnRate = 120; // Spawn enemy every 2 seconds initially
var gameSpeed = 1;
var waveNumber = 1;
var currentLevel = 1;
var enemiesKilledThisLevel = 0;
var requiredKills = {
1: 10,
2: 20,
3: 30
}; // Total enemies per level
var scoreToAdvance = {
1: 10000,
2: 25000,
3: 50000
};
var levelComplete = false;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
var levelTxt = new Text2('Level: 1', {
size: 50,
fill: 0x00FFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120; // Offset from left edge to avoid menu icon
LK.gui.topLeft.addChild(levelTxt);
// Initialize cannon
cannon = game.addChild(new Cannon());
cannon.x = 2048 / 2;
cannon.y = 2732 - 100;
// Set initial cannon stats for level 1
function updateCannonStats() {
if (currentLevel === 1) {
cannon.maxFireRate = 2; // 3 shots per second
cannonSpeed = 24; // Normal movement
} else if (currentLevel === 2) {
cannon.maxFireRate = 1; // 6 shots per second - faster
cannonSpeed = 32; // Faster movement
} else if (currentLevel === 3) {
cannon.maxFireRate = 1; // Keep high fire rate
cannonSpeed = 40; // Fastest movement
}
}
updateCannonStats();
// Touch controls
var isDragging = false;
var cannonSpeed = 24;
game.down = function (x, y, obj) {
// Check if touch is in the cannon control area for dragging
if (y > 2732 - 300) {
isDragging = true;
cannon.x = Math.max(60, Math.min(2048 - 60, x));
}
// Fire laser on any tap/touch - gun sound plays when player pushes laser
if (cannon.fire()) {
if (currentLevel === 3) {
// Double laser beams for level 3
var laser1 = new Laser();
laser1.x = cannon.x - 30;
laser1.y = cannon.y - 50;
lasers.push(laser1);
game.addChild(laser1);
var laser2 = new Laser();
laser2.x = cannon.x + 30;
laser2.y = cannon.y - 50;
lasers.push(laser2);
game.addChild(laser2);
} else {
// Single laser beam for levels 1 and 2
var laser = new Laser();
laser.x = cannon.x;
laser.y = cannon.y - 50;
lasers.push(laser);
game.addChild(laser);
}
LK.getSound('shoot').play();
}
};
game.move = function (x, y, obj) {
if (isDragging) {
cannon.x = Math.max(60, Math.min(2048 - 60, x));
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Spawn enemy function
function spawnEnemy() {
// Level-based enemy spawning
var levelSpawnQueue = [];
if (currentLevel === 1) {
// Level 1: 5 Rockets, 3 Drones, 1 F-35, 1 B52
for (var i = 0; i < 5; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 1; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 1; i++) levelSpawnQueue.push('b52');
} else if (currentLevel === 2) {
// Level 2: 10 Rockets, 6 Drones, 2 F-35s, 2 B52s
for (var i = 0; i < 10; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 6; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 2; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 2; i++) levelSpawnQueue.push('b52');
} else if (currentLevel === 3) {
// Level 3: 15 Rockets, 9 Drones, 3 F-35s, 3 B52s
for (var i = 0; i < 15; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 9; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('b52');
}
// Don't spawn if we've reached the level limit
if (enemiesKilledThisLevel >= requiredKills[currentLevel]) {
return;
}
// Randomly pick from the queue
var enemyType = levelSpawnQueue[Math.floor(Math.random() * levelSpawnQueue.length)];
// Level multipliers for stats
var speedMultiplier = currentLevel === 1 ? 1 : currentLevel === 2 ? 1.5 : 2;
var healthMultiplier = currentLevel === 1 ? 1 : currentLevel === 2 ? 1.5 : 2;
if (enemyType === 'rocket') {
var rocket = new Rocket();
rocket.x = Math.random() * (2048 - 160) + 80;
rocket.y = -100;
rocket.speed = (6 + Math.random() * 1.5) * speedMultiplier;
rocket.health = Math.floor(1 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) rocket.reward = 1000;else if (currentLevel === 2) rocket.reward = 1200;else if (currentLevel === 3) rocket.reward = 1500;
rocket.setTarget(cannon.x, cannon.y);
enemies.push(rocket);
game.addChild(rocket);
} else if (enemyType === 'uav') {
var uav = new UAV();
uav.x = Math.random() * (2048 - 160) + 80;
uav.y = -100;
uav.speed = (4 + Math.random() * 1.5) * speedMultiplier;
uav.health = Math.floor(2 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) uav.reward = 2500;else if (currentLevel === 2) uav.reward = 3000;else if (currentLevel === 3) uav.reward = 4000;
uav.setTarget(cannon.x, cannon.y);
enemies.push(uav);
game.addChild(uav);
} else if (enemyType === 'f35') {
var f35 = new F35();
f35.x = Math.random() * (2048 - 160) + 80;
f35.y = -100;
f35.speed = (2 + Math.random() * 0.5) * speedMultiplier;
f35.health = Math.floor(3 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) f35.reward = 5000;else if (currentLevel === 2) f35.reward = 6000;else if (currentLevel === 3) f35.reward = 8000;
f35.setTarget(cannon.x, cannon.y);
enemies.push(f35);
game.addChild(f35);
} else if (enemyType === 'b52') {
var b52 = new B52();
b52.x = Math.random() * (2048 - 160) + 80;
b52.y = -100;
b52.speed = (1 + Math.random() * 0.5) * speedMultiplier;
b52.health = Math.floor(5 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) b52.reward = 15000;else if (currentLevel === 2) b52.reward = 18000;else if (currentLevel === 3) b52.reward = 22000;
b52.setTarget(cannon.x, cannon.y);
enemies.push(b52);
game.addChild(b52);
}
}
// Update wave difficulty
function updateWave() {
waveNumber++;
enemySpawnRate = Math.max(30, enemySpawnRate - 10);
waveTxt.setText('Wave: ' + waveNumber);
// Flash effect for new wave
LK.effects.flashScreen(0x00FF00, 500);
}
// Main game loop
game.update = function () {
// Player-controlled laser firing - only when player touches/taps
// No automatic firing - gun sound only plays when player pushes laser
// Update enemy spawn timer
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
// Update lasers
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
if (laser.lastY === undefined) laser.lastY = laser.y;
// Remove laser if off screen
if (laser.lastY >= -50 && laser.y < -50) {
laser.destroy();
lasers.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (laser.intersects(enemy)) {
// Hit enemy
LK.getSound('enemyHit').play();
// Different laser effects based on enemy type
var effectColor = 0xFFFFFF;
var effectDuration = 200;
if (enemy.constructor.name === 'Rocket') {
effectColor = 0xFF6600; // Orange effect for rockets
effectDuration = 150;
} else if (enemy.constructor.name === 'UAV') {
effectColor = 0x00FFFF; // Cyan effect for UAVs
effectDuration = 250;
} else if (enemy.constructor.name === 'F35') {
effectColor = 0xFF00FF; // Magenta effect for F35s
effectDuration = 300;
} else if (enemy.constructor.name === 'B52') {
effectColor = 0xFFFF00; // Yellow effect for B52s
effectDuration = 400;
}
LK.effects.flashObject(laser, effectColor, effectDuration);
if (enemy.takeDamage()) {
// Enemy destroyed - use enemy's reward value
var reward = enemy.reward || 100;
LK.setScore(LK.getScore() + reward);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyDestroy').play();
// Flash effect
LK.effects.flashObject(enemy, effectColor, effectDuration);
// Special area damage for B52
if (enemy.constructor.name === 'B52' && enemy.explodeAreaDamage) {
enemy.explodeAreaDamage();
}
enemy.destroy();
enemies.splice(j, 1);
enemiesKilledThisLevel++;
// Check for level progression
if (LK.getScore() >= scoreToAdvance[currentLevel] && enemiesKilledThisLevel >= requiredKills[currentLevel] && currentLevel < 3) {
currentLevel++;
enemiesKilledThisLevel = 0;
levelComplete = false;
levelTxt.setText('Level: ' + currentLevel);
updateCannonStats();
LK.effects.flashScreen(0x00FF00, 1000);
}
} else {
// Enemy damaged but not destroyed
LK.effects.flashObject(enemy, 0xFF0000, 300);
}
laser.destroy();
lasers.splice(i, 1);
hitEnemy = true;
break;
}
}
// Check collision with decoys
if (!hitEnemy) {
for (var d = decoys.length - 1; d >= 0; d--) {
var decoy = decoys[d];
if (laser.intersects(decoy)) {
// Laser intercepted by decoy
LK.effects.flashObject(decoy, 0xFF4500, 200);
LK.effects.flashObject(laser, 0xFF4500, 200);
laser.destroy();
lasers.splice(i, 1);
decoy.destroy();
decoys.splice(d, 1);
hitEnemy = true;
break;
}
}
}
if (!hitEnemy) {
laser.lastY = laser.y;
}
}
// Update decoys
for (var d = decoys.length - 1; d >= 0; d--) {
var decoy = decoys[d];
if (decoy.update && decoy.update()) {
// Decoy expired
decoy.destroy();
decoys.splice(d, 1);
continue;
}
// Remove decoy if off screen
if (decoy.y < -50) {
decoy.destroy();
decoys.splice(d, 1);
continue;
}
}
// Update enemies
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
if (enemy.lastY === undefined) enemy.lastY = enemy.y;
// Update UAV and Rocket targets to track cannon
if (enemy.setTarget) {
enemy.setTarget(cannon.x, cannon.y);
}
// Check if enemy reached bottom
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(k, 1);
continue;
}
// Check collision with cannon
if (enemy.intersects(cannon)) {
// Game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
enemy.lastY = enemy.y;
}
// Check for wave completion and increase difficulty
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
updateWave();
}
// Victory condition - complete level 3
if (currentLevel === 3 && LK.getScore() >= scoreToAdvance[3] && enemiesKilledThisLevel >= requiredKills[3]) {
LK.showYouWin();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var B52 = Container.expand(function () {
var self = Container.call(this);
var b52Graphics = self.attachAsset('B52', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint B52 to make it visually distinct (dark gray)
b52Graphics.tint = 0x666666;
self.speed = 1; // Very slow speed
self.health = 5; // 5 hit points - highest health
self.reward = 15000; // $15000 reward - highest reward
self.targetX = 0;
self.targetY = 0;
self.moveTimer = 0;
self.dodgeTimer = 0;
self.dodgeDirection = 1;
self.decoyTimer = 0;
self.maxDecoyRate = 90; // Can deploy decoy every 1.5 seconds
self.update = function () {
// B52 moves slowly and steadily towards target with enhanced dodging
self.moveTimer++;
self.dodgeTimer++;
self.decoyTimer++;
// Enhanced dodging behavior - check for nearby lasers
var shouldDodge = false;
for (var i = 0; i < lasers.length; i++) {
var laser = lasers[i];
var distanceToLaser = Math.sqrt((laser.x - self.x) * (laser.x - self.x) + (laser.y - self.y) * (laser.y - self.y));
if (distanceToLaser < 150 && laser.y < self.y) {
shouldDodge = true;
// Deploy decoy if available
if (self.decoyTimer >= self.maxDecoyRate) {
self.deployDecoy();
}
break;
}
}
// Evasive maneuvers when dodging
if (shouldDodge) {
if (self.dodgeTimer % 30 === 0) {
self.dodgeDirection *= -1;
}
}
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
// Add dodging movement
if (shouldDodge) {
moveX += Math.sin(self.moveTimer * 0.2) * 3 * self.dodgeDirection;
moveY *= 0.5; // Slow down forward movement when dodging
}
self.x += moveX;
self.y += moveY;
// Keep within screen bounds
self.x = Math.max(60, Math.min(2048 - 60, self.x));
}
};
self.deployDecoy = function () {
self.decoyTimer = 0;
// Create decoy explosive
var decoy = new Decoy();
decoy.x = self.x + (Math.random() - 0.5) * 100; // Random offset
decoy.y = self.y - 30;
decoys.push(decoy);
game.addChild(decoy);
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // B52 destroyed
}
return false;
};
self.explodeAreaDamage = function () {
// Area damage when B52 is destroyed
var damageRadius = 200;
LK.effects.flashObject(self, 0xFF6600, 600);
// Damage nearby enemies (friendly fire)
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy !== self) {
var distance = Math.sqrt((enemy.x - self.x) * (enemy.x - self.x) + (enemy.y - self.y) * (enemy.y - self.y));
if (distance < damageRadius) {
if (enemy.takeDamage && enemy.takeDamage()) {
// Enemy destroyed by area damage
LK.effects.flashObject(enemy, 0xFF6600, 400);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
}
// Destroy nearby lasers
for (var j = lasers.length - 1; j >= 0; j--) {
var laser = lasers[j];
var distance = Math.sqrt((laser.x - self.x) * (laser.x - self.x) + (laser.y - self.y) * (laser.y - self.y));
if (distance < damageRadius) {
laser.destroy();
lasers.splice(j, 1);
}
}
};
return self;
});
var Cannon = Container.expand(function () {
var self = Container.call(this);
var cannonGraphics = self.attachAsset('cannon', {
anchorX: 0.5,
anchorY: 1.0
});
self.fireRate = 0;
self.maxFireRate = 2; // Fire every 2 frames at max - 3 shots per second
self.update = function () {
if (self.fireRate > 0) {
self.fireRate--;
}
};
self.canFire = function () {
return self.fireRate <= 0;
};
self.fire = function () {
if (self.canFire()) {
self.fireRate = self.maxFireRate;
return true;
}
return false;
};
return self;
});
var Decoy = Container.expand(function () {
var self = Container.call(this);
var decoyGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint decoy to make it look like a small explosive (red-orange)
decoyGraphics.tint = 0xFF4500;
decoyGraphics.scaleX = 0.6;
decoyGraphics.scaleY = 0.6;
self.speed = -8; // Move upward to intercept lasers
self.lifeTime = 180; // 3 seconds at 60fps
self.update = function () {
self.y += self.speed;
self.lifeTime--;
// Self-destruct after lifetime expires
if (self.lifeTime <= 0) {
return true; // Mark for destruction
}
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.reward = 500; // Default reward for basic enemy - increased reward
self.update = function () {
self.y += self.speed;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // Enemy destroyed
}
return false;
};
return self;
});
var F35 = Container.expand(function () {
var self = Container.call(this);
var f35Graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint F35 to make it visually distinct (darker blue)
f35Graphics.tint = 0x4444FF;
self.speed = 2; // Slow speed
self.health = 3; // 3 hit points
self.reward = 10000; // $10000 reward
self.targetX = 0;
self.targetY = 0;
self.agileTimer = 0;
self.agileDirection = 1;
self.update = function () {
// Agile movement - add evasive maneuvers
self.agileTimer++;
if (self.agileTimer % 60 === 0) {
self.agileDirection *= -1;
}
// Move towards target with agile zigzag pattern
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 + Math.sin(self.agileTimer * 0.1) * 2 * self.agileDirection;
self.y += dy / distance * self.speed;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // F35 destroyed
}
return false;
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphics = self.attachAsset('Rockets', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6; // Fast speed
self.health = 1; // 1 hit point
self.reward = 1000; // $1000 reward
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Move directly towards the cannon with higher speed
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;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // Rocket destroyed
}
return false;
};
return self;
});
var UAV = Container.expand(function () {
var self = Container.call(this);
var uavGraphics = self.attachAsset('UAV', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4; // Medium speed
self.health = 2; // 2 hit points
self.reward = 2500; // $2500 reward
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Move directly towards the cannon
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;
}
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // UAV destroyed
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Create gradient background from sky blue at top to green-brown at bottom
var backgroundGradient = LK.getAsset('background', {
width: 2048,
height: 2732,
color: 0x87CEEB,
// Sky blue
shape: 'box'
});
game.addChild(backgroundGradient);
// Create multiple horizontal strips for gradient effect
var gradientStrips = [];
var stripHeight = 60;
var totalStrips = Math.ceil(2732 / stripHeight);
for (var i = 0; i < totalStrips; i++) {
var strip = LK.getAsset('gradientStrip_' + i, {
width: 2048,
height: stripHeight,
color: 0x87CEEB,
// Will be tinted for gradient
shape: 'box'
});
strip.y = i * stripHeight;
// Calculate gradient progression from sky blue to green to brown
var progress = i / totalStrips;
var r, g, b;
if (progress < 0.6) {
// Sky blue to green transition (top 60% of screen)
var skyProgress = progress / 0.6;
r = Math.floor(135 + (34 - 135) * skyProgress); // 135 -> 34
g = Math.floor(206 + (139 - 206) * skyProgress); // 206 -> 139
b = Math.floor(235 + (34 - 235) * skyProgress); // 235 -> 34
} else {
// Green to brown transition (bottom 40% of screen)
var groundProgress = (progress - 0.6) / 0.4;
r = Math.floor(34 + (139 - 34) * groundProgress); // 34 -> 139
g = Math.floor(139 + (69 - 139) * groundProgress); // 139 -> 69
b = Math.floor(34 + (19 - 34) * groundProgress); // 34 -> 19
}
var color = r << 16 | g << 8 | b;
strip.tint = color;
game.addChild(strip);
gradientStrips.push(strip);
}
// Game variables
var cannon;
var lasers = [];
var enemies = [];
var decoys = [];
var enemySpawnTimer = 0;
var enemySpawnRate = 120; // Spawn enemy every 2 seconds initially
var gameSpeed = 1;
var waveNumber = 1;
var currentLevel = 1;
var enemiesKilledThisLevel = 0;
var requiredKills = {
1: 10,
2: 20,
3: 30
}; // Total enemies per level
var scoreToAdvance = {
1: 10000,
2: 25000,
3: 50000
};
var levelComplete = false;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
var levelTxt = new Text2('Level: 1', {
size: 50,
fill: 0x00FFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120; // Offset from left edge to avoid menu icon
LK.gui.topLeft.addChild(levelTxt);
// Initialize cannon
cannon = game.addChild(new Cannon());
cannon.x = 2048 / 2;
cannon.y = 2732 - 100;
// Set initial cannon stats for level 1
function updateCannonStats() {
if (currentLevel === 1) {
cannon.maxFireRate = 2; // 3 shots per second
cannonSpeed = 24; // Normal movement
} else if (currentLevel === 2) {
cannon.maxFireRate = 1; // 6 shots per second - faster
cannonSpeed = 32; // Faster movement
} else if (currentLevel === 3) {
cannon.maxFireRate = 1; // Keep high fire rate
cannonSpeed = 40; // Fastest movement
}
}
updateCannonStats();
// Touch controls
var isDragging = false;
var cannonSpeed = 24;
game.down = function (x, y, obj) {
// Check if touch is in the cannon control area for dragging
if (y > 2732 - 300) {
isDragging = true;
cannon.x = Math.max(60, Math.min(2048 - 60, x));
}
// Fire laser on any tap/touch - gun sound plays when player pushes laser
if (cannon.fire()) {
if (currentLevel === 3) {
// Double laser beams for level 3
var laser1 = new Laser();
laser1.x = cannon.x - 30;
laser1.y = cannon.y - 50;
lasers.push(laser1);
game.addChild(laser1);
var laser2 = new Laser();
laser2.x = cannon.x + 30;
laser2.y = cannon.y - 50;
lasers.push(laser2);
game.addChild(laser2);
} else {
// Single laser beam for levels 1 and 2
var laser = new Laser();
laser.x = cannon.x;
laser.y = cannon.y - 50;
lasers.push(laser);
game.addChild(laser);
}
LK.getSound('shoot').play();
}
};
game.move = function (x, y, obj) {
if (isDragging) {
cannon.x = Math.max(60, Math.min(2048 - 60, x));
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Spawn enemy function
function spawnEnemy() {
// Level-based enemy spawning
var levelSpawnQueue = [];
if (currentLevel === 1) {
// Level 1: 5 Rockets, 3 Drones, 1 F-35, 1 B52
for (var i = 0; i < 5; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 1; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 1; i++) levelSpawnQueue.push('b52');
} else if (currentLevel === 2) {
// Level 2: 10 Rockets, 6 Drones, 2 F-35s, 2 B52s
for (var i = 0; i < 10; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 6; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 2; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 2; i++) levelSpawnQueue.push('b52');
} else if (currentLevel === 3) {
// Level 3: 15 Rockets, 9 Drones, 3 F-35s, 3 B52s
for (var i = 0; i < 15; i++) levelSpawnQueue.push('rocket');
for (var i = 0; i < 9; i++) levelSpawnQueue.push('uav');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('f35');
for (var i = 0; i < 3; i++) levelSpawnQueue.push('b52');
}
// Don't spawn if we've reached the level limit
if (enemiesKilledThisLevel >= requiredKills[currentLevel]) {
return;
}
// Randomly pick from the queue
var enemyType = levelSpawnQueue[Math.floor(Math.random() * levelSpawnQueue.length)];
// Level multipliers for stats
var speedMultiplier = currentLevel === 1 ? 1 : currentLevel === 2 ? 1.5 : 2;
var healthMultiplier = currentLevel === 1 ? 1 : currentLevel === 2 ? 1.5 : 2;
if (enemyType === 'rocket') {
var rocket = new Rocket();
rocket.x = Math.random() * (2048 - 160) + 80;
rocket.y = -100;
rocket.speed = (6 + Math.random() * 1.5) * speedMultiplier;
rocket.health = Math.floor(1 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) rocket.reward = 1000;else if (currentLevel === 2) rocket.reward = 1200;else if (currentLevel === 3) rocket.reward = 1500;
rocket.setTarget(cannon.x, cannon.y);
enemies.push(rocket);
game.addChild(rocket);
} else if (enemyType === 'uav') {
var uav = new UAV();
uav.x = Math.random() * (2048 - 160) + 80;
uav.y = -100;
uav.speed = (4 + Math.random() * 1.5) * speedMultiplier;
uav.health = Math.floor(2 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) uav.reward = 2500;else if (currentLevel === 2) uav.reward = 3000;else if (currentLevel === 3) uav.reward = 4000;
uav.setTarget(cannon.x, cannon.y);
enemies.push(uav);
game.addChild(uav);
} else if (enemyType === 'f35') {
var f35 = new F35();
f35.x = Math.random() * (2048 - 160) + 80;
f35.y = -100;
f35.speed = (2 + Math.random() * 0.5) * speedMultiplier;
f35.health = Math.floor(3 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) f35.reward = 5000;else if (currentLevel === 2) f35.reward = 6000;else if (currentLevel === 3) f35.reward = 8000;
f35.setTarget(cannon.x, cannon.y);
enemies.push(f35);
game.addChild(f35);
} else if (enemyType === 'b52') {
var b52 = new B52();
b52.x = Math.random() * (2048 - 160) + 80;
b52.y = -100;
b52.speed = (1 + Math.random() * 0.5) * speedMultiplier;
b52.health = Math.floor(5 * healthMultiplier);
// Update rewards based on level
if (currentLevel === 1) b52.reward = 15000;else if (currentLevel === 2) b52.reward = 18000;else if (currentLevel === 3) b52.reward = 22000;
b52.setTarget(cannon.x, cannon.y);
enemies.push(b52);
game.addChild(b52);
}
}
// Update wave difficulty
function updateWave() {
waveNumber++;
enemySpawnRate = Math.max(30, enemySpawnRate - 10);
waveTxt.setText('Wave: ' + waveNumber);
// Flash effect for new wave
LK.effects.flashScreen(0x00FF00, 500);
}
// Main game loop
game.update = function () {
// Player-controlled laser firing - only when player touches/taps
// No automatic firing - gun sound only plays when player pushes laser
// Update enemy spawn timer
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
// Update lasers
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
if (laser.lastY === undefined) laser.lastY = laser.y;
// Remove laser if off screen
if (laser.lastY >= -50 && laser.y < -50) {
laser.destroy();
lasers.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (laser.intersects(enemy)) {
// Hit enemy
LK.getSound('enemyHit').play();
// Different laser effects based on enemy type
var effectColor = 0xFFFFFF;
var effectDuration = 200;
if (enemy.constructor.name === 'Rocket') {
effectColor = 0xFF6600; // Orange effect for rockets
effectDuration = 150;
} else if (enemy.constructor.name === 'UAV') {
effectColor = 0x00FFFF; // Cyan effect for UAVs
effectDuration = 250;
} else if (enemy.constructor.name === 'F35') {
effectColor = 0xFF00FF; // Magenta effect for F35s
effectDuration = 300;
} else if (enemy.constructor.name === 'B52') {
effectColor = 0xFFFF00; // Yellow effect for B52s
effectDuration = 400;
}
LK.effects.flashObject(laser, effectColor, effectDuration);
if (enemy.takeDamage()) {
// Enemy destroyed - use enemy's reward value
var reward = enemy.reward || 100;
LK.setScore(LK.getScore() + reward);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyDestroy').play();
// Flash effect
LK.effects.flashObject(enemy, effectColor, effectDuration);
// Special area damage for B52
if (enemy.constructor.name === 'B52' && enemy.explodeAreaDamage) {
enemy.explodeAreaDamage();
}
enemy.destroy();
enemies.splice(j, 1);
enemiesKilledThisLevel++;
// Check for level progression
if (LK.getScore() >= scoreToAdvance[currentLevel] && enemiesKilledThisLevel >= requiredKills[currentLevel] && currentLevel < 3) {
currentLevel++;
enemiesKilledThisLevel = 0;
levelComplete = false;
levelTxt.setText('Level: ' + currentLevel);
updateCannonStats();
LK.effects.flashScreen(0x00FF00, 1000);
}
} else {
// Enemy damaged but not destroyed
LK.effects.flashObject(enemy, 0xFF0000, 300);
}
laser.destroy();
lasers.splice(i, 1);
hitEnemy = true;
break;
}
}
// Check collision with decoys
if (!hitEnemy) {
for (var d = decoys.length - 1; d >= 0; d--) {
var decoy = decoys[d];
if (laser.intersects(decoy)) {
// Laser intercepted by decoy
LK.effects.flashObject(decoy, 0xFF4500, 200);
LK.effects.flashObject(laser, 0xFF4500, 200);
laser.destroy();
lasers.splice(i, 1);
decoy.destroy();
decoys.splice(d, 1);
hitEnemy = true;
break;
}
}
}
if (!hitEnemy) {
laser.lastY = laser.y;
}
}
// Update decoys
for (var d = decoys.length - 1; d >= 0; d--) {
var decoy = decoys[d];
if (decoy.update && decoy.update()) {
// Decoy expired
decoy.destroy();
decoys.splice(d, 1);
continue;
}
// Remove decoy if off screen
if (decoy.y < -50) {
decoy.destroy();
decoys.splice(d, 1);
continue;
}
}
// Update enemies
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
if (enemy.lastY === undefined) enemy.lastY = enemy.y;
// Update UAV and Rocket targets to track cannon
if (enemy.setTarget) {
enemy.setTarget(cannon.x, cannon.y);
}
// Check if enemy reached bottom
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(k, 1);
continue;
}
// Check collision with cannon
if (enemy.intersects(cannon)) {
// Game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
enemy.lastY = enemy.y;
}
// Check for wave completion and increase difficulty
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
updateWave();
}
// Victory condition - complete level 3
if (currentLevel === 3 && LK.getScore() >= scoreToAdvance[3] && enemiesKilledThisLevel >= requiredKills[3]) {
LK.showYouWin();
}
};
F35 like fighter jet. In-Game asset. 2d. High contrast. No shadows
Overwiev of unmanned aircraft coming to us. 2d. High contrast. No shadows
Looking like real rocket. Rocket picture. In-Game asset. 2d. High contrast. No shadows
Imagine that a Big laser machine you see from upside. Stands from back to the forward. Tries to hit enemy's.. In-Game asset. 2d. High contrast. No shadows