/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
level: 1
});
/****
* Classes
****/
var CounterRocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphic = self.attachAsset('counter_rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.active = true;
self.blastRadius = 100;
self.init = function (startX, startY, targetX, targetY) {
self.x = startX;
self.y = startY;
self.targetX = targetX;
self.targetY = targetY;
// Calculate direction vector
var dx = targetX - startX;
var dy = targetY - startY;
var dist = Math.sqrt(dx * dx + dy * dy);
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
// Set rotation
self.rotation = Math.atan2(dx, -dy);
};
self.update = function () {
if (!self.active) {
return;
}
// Move along trajectory
self.x += self.vx;
self.y += self.vy;
// Check if reached target area
var distToTarget = Math.sqrt(Math.pow(self.x - self.targetX, 2) + Math.pow(self.y - self.targetY, 2));
if (distToTarget < 10) {
self.explode();
}
// Check for missile hits
if (self.active) {
// Track if we hit any missiles directly
var hitMissile = false;
// Check all missiles for direct hits
for (var i = 0; i < missiles.length; i++) {
var missile = missiles[i];
if (missile.active) {
var dist = Math.sqrt(Math.pow(self.x - missile.x, 2) + Math.pow(self.y - missile.y, 2));
// Direct hit if within 30px
if (dist < 30) {
missile.explode();
self.explode();
hitMissile = true;
// Award points and increase combo
score += 20 * (1 + level * 0.1);
comboCount++;
if (comboCount > 1) {
// Bonus points for combos
score += 5 * comboCount;
}
updateUI();
break;
}
}
}
// Check if level should advance
if (score >= level * 1000) {
advanceLevel();
}
}
// Check if off screen
if (self.y < -100 || self.y > 2832 || self.x < -100 || self.x > 2148) {
self.destroy();
// Remove from counter rockets array
var index = counterRockets.indexOf(self);
if (index !== -1) {
counterRockets.splice(index, 1);
}
}
};
self.explode = function () {
self.active = false;
// Create explosion
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
explosion.init(self.blastRadius);
game.addChild(explosion);
// Check for missile hits
game.checkMissileHits(self.x, self.y, self.blastRadius);
// Play sound
LK.getSound('explosion_sound').play();
// Remove rocket
self.destroy();
// Remove from counter rockets array
var index = counterRockets.indexOf(self);
if (index !== -1) {
counterRockets.splice(index, 1);
}
};
return self;
});
var DefenseStation = Container.expand(function () {
var self = Container.call(this);
var stationGraphic = self.attachAsset('defense_station', {
anchorX: 0.5,
anchorY: 0.5
});
var aimLine = self.attachAsset('aim_line', {
anchorX: 0.5,
anchorY: 1,
alpha: 0.7
});
self.init = function () {
self.x = 2048 / 2;
self.y = 2732 - 60 - 100; // Just above ground
aimLine.visible = false;
aimLine.rotation = -Math.PI / 2; // Pointing upward
};
self.startAiming = function (x, y) {
aimLine.visible = true;
self.updateAimLine(x, y);
};
self.updateAimLine = function (x, y) {
if (!aimLine.visible) {
return;
}
// Calculate angle for aim line
var dx = x - self.x;
var dy = y - self.y;
var angle = Math.atan2(dx, -dy); // Negative dy because y is inverted
// Restrict angle (can't aim below horizon)
if (angle > Math.PI / 2) {
angle = Math.PI / 2;
}
if (angle < -Math.PI / 2) {
angle = -Math.PI / 2;
}
aimLine.rotation = angle;
};
self.stopAiming = function () {
aimLine.visible = false;
};
self.fire = function (x, y) {
// Calculate direction and target position
var dx = x - self.x;
var dy = y - self.y;
var angle = Math.atan2(dx, -dy);
// Restrict angle (can't fire below horizon)
if (angle > Math.PI / 2) {
angle = Math.PI / 2;
}
if (angle < -Math.PI / 2) {
angle = -Math.PI / 2;
}
// Calculate target point
var reach = 2000;
var targetX = self.x + Math.sin(angle) * reach;
var targetY = self.y - Math.cos(angle) * reach;
// Fire main rocket
var rocket = new CounterRocket();
rocket.init(self.x, self.y, targetX, targetY);
counterRockets.push(rocket);
game.addChild(rocket);
// Fire additional rockets if multishot is active
if (game.multishotActive) {
var spread = Math.PI / 12; // 15 degrees
// Left rocket
var leftRocket = new CounterRocket();
var leftAngle = angle - spread;
var leftTargetX = self.x + Math.sin(leftAngle) * reach;
var leftTargetY = self.y - Math.cos(leftAngle) * reach;
leftRocket.init(self.x, self.y, leftTargetX, leftTargetY);
counterRockets.push(leftRocket);
game.addChild(leftRocket);
// Right rocket
var rightRocket = new CounterRocket();
var rightAngle = angle + spread;
var rightTargetX = self.x + Math.sin(rightAngle) * reach;
var rightTargetY = self.y - Math.cos(rightAngle) * reach;
rightRocket.init(self.x, self.y, rightTargetX, rightTargetY);
counterRockets.push(rightRocket);
game.addChild(rightRocket);
}
// Play sound
LK.getSound('rocket_launch').play();
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.init = function (radius) {
self.radius = radius || 75;
explosionGraphic.width = self.radius * 2;
explosionGraphic.height = self.radius * 2;
// Start animation
explosionGraphic.alpha = 0.9;
tween(explosionGraphic, {
alpha: 0,
width: self.radius * 3,
height: self.radius * 3
}, {
duration: 600,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Missile = Container.expand(function () {
var self = Container.call(this);
var missileGraphic = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 0.5
});
// Default properties
self.speed = 3;
self.targetX = 0;
self.active = true;
self.init = function (startX, speed, targetX) {
self.x = startX;
self.y = -100;
self.speed = speed || 3;
self.targetX = targetX || self.x;
// Calculate angle based on trajectory
var dx = self.targetX - self.x;
var dy = 2732 - self.y;
self.rotation = Math.atan2(dx, dy);
};
self.update = function () {
if (!self.active) {
return;
}
// Move towards target
var dx = self.targetX - self.x;
var groundY = 2732 - 60; // Ground level
var percentComplete = self.y / groundY;
self.x += dx * 0.005;
self.y += self.speed;
// Check if hit ground
if (self.y >= groundY - 40) {
self.explode();
game.missileHitGround(self.x);
}
};
self.explode = function () {
self.active = false;
// Create explosion
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
explosion.init(75);
game.addChild(explosion);
// Play sound
LK.getSound('explosion_sound').play();
// Remove missile
self.destroy();
// Remove from missiles array
var index = missiles.indexOf(self);
if (index !== -1) {
missiles.splice(index, 1);
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphic = self.attachAsset('power_up', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = "multishot";
self.fallSpeed = 2;
self.active = true;
self.init = function (type) {
self.type = type || (Math.random() < 0.5 ? "multishot" : "nuke");
// Set color based on type
if (self.type === "multishot") {
powerUpGraphic.tint = 0x9b59b6; // Purple
} else {
powerUpGraphic.tint = 0xe74c3c; // Red
}
// Position
self.x = 100 + Math.random() * (2048 - 200);
self.y = -100;
// Animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 3000,
onFinish: function onFinish() {
if (self.active) {
self.rotation = 0;
tween(self, {
rotation: Math.PI * 2
}, {
duration: 3000
});
}
}
});
};
self.update = function () {
if (!self.active) {
return;
}
// Fall down
self.y += self.fallSpeed;
// Check if hit ground
if (self.y >= 2732 - 60 - 40) {
self.destroy();
var index = powerUps.indexOf(self);
if (index !== -1) {
powerUps.splice(index, 1);
}
}
// Check if near defense station
var distToStation = Math.sqrt(Math.pow(self.x - defenseStation.x, 2) + Math.pow(self.y - defenseStation.y, 2));
if (distToStation < 150) {
self.collect();
}
};
self.collect = function () {
self.active = false;
// Apply power up effect
if (self.type === "multishot") {
game.activateMultishot();
} else {
game.activateNuke();
}
// Play sound
LK.getSound('power_up_collect').play();
// Remove power up
self.destroy();
// Remove from powerUps array
var index = powerUps.indexOf(self);
if (index !== -1) {
powerUps.splice(index, 1);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x121f2a
});
/****
* Game Code
****/
// Game variables
var score = 0;
var level = 1;
var lives = 3;
var isAiming = false;
var aimStartX = 0;
var aimStartY = 0;
var missiles = [];
var counterRockets = [];
var powerUps = [];
var defenseStation;
var ground;
var gameActive = true;
var missileSpawnRate = 3000; // Time in ms between missile spawns
var missileSpawnTimer = null;
var powerUpSpawnTimer = null;
var multishotTimeoutId = null;
var comboCount = 0;
var comboTimer = null;
// UI elements
var scoreTxt;
var livesTxt;
var levelTxt;
var comboTxt;
// Initialize game objects
function initGame() {
// Set background
game.setBackgroundColor(0x121f2a);
// Play background music
LK.playMusic('game_music');
// Create ground
ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
ground.x = 2048 / 2;
ground.y = 2732 - 30; // Bottom of screen
game.addChild(ground);
// Create defense station
defenseStation = new DefenseStation();
defenseStation.init();
game.addChild(defenseStation);
// Setup UI
setupUI();
// Start missile spawning
startMissileSpawner();
// Start power-up spawning
startPowerUpSpawner();
// Reset game state
score = 0;
level = storage.level || 1;
lives = 3;
gameActive = true;
game.multishotActive = false;
comboCount = 0;
// Update UI
updateUI();
}
function setupUI() {
// Glaud inscription
var glaudTxt = new Text2('Glaud', {
size: 40,
fill: 0xFF8C00
});
glaudTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(glaudTxt);
glaudTxt.x = -20;
glaudTxt.y = 80;
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -280;
scoreTxt.y = 20;
// Lives text
livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.top.addChild(livesTxt);
livesTxt.y = 20;
// Level text
levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
levelTxt.x = 120; // Avoid the top-left 100x100 reserved area
levelTxt.y = 20;
// Combo text
comboTxt = new Text2('', {
size: 80,
fill: 0xF1C40F
});
comboTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(comboTxt);
comboTxt.visible = false;
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
livesTxt.setText('Lives: ' + lives);
levelTxt.setText('Level: ' + level);
if (comboCount > 1) {
comboTxt.setText('COMBO x' + comboCount + '!');
comboTxt.visible = true;
// Reset combo timer
if (comboTimer) {
LK.clearTimeout(comboTimer);
}
comboTimer = LK.setTimeout(function () {
comboTxt.visible = false;
comboCount = 0;
}, 2000);
}
}
function startMissileSpawner() {
// Clear any existing timer
if (missileSpawnTimer) {
LK.clearInterval(missileSpawnTimer);
}
// Calculate spawn rate based on level
var rate = Math.max(3000 - level * 200, 500);
missileSpawnTimer = LK.setInterval(function () {
if (!gameActive) {
return;
}
spawnMissile();
}, rate);
}
function spawnMissile() {
// Create a new missile
var missile = new Missile();
// Randomize starting position
var startX = Math.random() * 2048;
// Randomize target position
var targetX = Math.random() * 2048;
// Calculate speed based on level
var speed = 3 + level * 0.5;
// Initialize missile
missile.init(startX, speed, targetX);
// Add to game
missiles.push(missile);
game.addChild(missile);
}
function startPowerUpSpawner() {
// Clear any existing timer
if (powerUpSpawnTimer) {
LK.clearInterval(powerUpSpawnTimer);
}
powerUpSpawnTimer = LK.setInterval(function () {
if (!gameActive) {
return;
}
// 10% chance to spawn a power-up
if (Math.random() < 0.1) {
spawnPowerUp();
}
}, 5000);
}
function spawnPowerUp() {
// Create a new power-up
var powerUp = new PowerUp();
// Initialize power-up
powerUp.init();
// Add to game
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Game mechanics
game.checkMissileHits = function (x, y, radius) {
var hitCount = 0;
// Check all missiles
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
if (!missile.active) {
continue;
}
// Calculate distance
var dist = Math.sqrt(Math.pow(missile.x - x, 2) + Math.pow(missile.y - y, 2));
// If missile is within blast radius
if (dist <= radius) {
missile.explode();
hitCount++;
// Award points
score += 10 * (1 + level * 0.1);
// Increment combo
comboCount++;
if (comboCount > 1) {
// Bonus points for combos
score += 5 * comboCount;
}
}
}
// Check if level should advance
if (score >= level * 1000) {
advanceLevel();
}
// Update UI
updateUI();
return hitCount;
};
game.missileHitGround = function (x) {
// Visual effect
var groundExplosion = new Explosion();
groundExplosion.x = x;
groundExplosion.y = 2732 - 60;
groundExplosion.init(100);
game.addChild(groundExplosion);
// Reduce lives
lives--;
// Reset combo
comboCount = 0;
if (comboTimer) {
LK.clearTimeout(comboTimer);
}
comboTxt.visible = false;
// Update UI
updateUI();
// Check for game over
if (lives <= 0) {
gameOver();
}
};
function gameOver() {
gameActive = false;
// Stop spawners
if (missileSpawnTimer) {
LK.clearInterval(missileSpawnTimer);
}
if (powerUpSpawnTimer) {
LK.clearInterval(powerUpSpawnTimer);
}
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Set final score
LK.setScore(score);
// Show game over screen
LK.showGameOver();
}
function advanceLevel() {
level++;
storage.level = level;
// Update UI
updateUI();
// Flash level indicator
tween(levelTxt, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
tween(levelTxt, {
alpha: 1
}, {
duration: 200
});
}
});
// Restart missile spawner with new rate
startMissileSpawner();
}
game.activateMultishot = function () {
game.multishotActive = true;
// Create visual indicator
defenseStation.attachAsset('power_up', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
tint: 0x9b59b6,
alpha: 0.7,
scale: 0.5
});
// Clear previous timeout if exists
if (multishotTimeoutId) {
LK.clearTimeout(multishotTimeoutId);
}
// Set timeout to disable multishot
multishotTimeoutId = LK.setTimeout(function () {
game.multishotActive = false;
// Remove all power-up indicators from defense station
for (var i = 0; i < defenseStation.children.length; i++) {
var child = defenseStation.children[i];
if (child.color && child.color === 0x9b59b6) {
defenseStation.removeChild(child);
child.destroy();
}
}
}, 10000); // 10 seconds
};
game.activateNuke = function () {
// Create large explosion at center
var nukeExplosion = new Explosion();
nukeExplosion.x = 2048 / 2;
nukeExplosion.y = 2732 / 2;
nukeExplosion.init(1500); // Large radius
game.addChild(nukeExplosion);
// Destroy all missiles
var destroyedCount = 0;
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
if (missile.active) {
missile.explode();
destroyedCount++;
}
}
// Award points
if (destroyedCount > 0) {
score += destroyedCount * 15;
updateUI();
}
};
// Input handling
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
isAiming = true;
aimStartX = x;
aimStartY = y;
// Start aiming
defenseStation.startAiming(x, y);
};
game.move = function (x, y, obj) {
if (!isAiming || !gameActive) {
return;
}
// Update aim line
defenseStation.updateAimLine(x, y);
};
game.up = function (x, y, obj) {
if (!isAiming || !gameActive) {
return;
}
// Fire rocket
defenseStation.fire(x, y);
// Reset aiming
isAiming = false;
defenseStation.stopAiming();
};
// Game loop
game.update = function () {
if (!gameActive) {
return;
}
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
missiles[i].update();
}
// Update counter rockets
for (var i = counterRockets.length - 1; i >= 0; i--) {
counterRockets[i].update();
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].update();
}
};
// Initialize the game
initGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
level: 1
});
/****
* Classes
****/
var CounterRocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphic = self.attachAsset('counter_rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.active = true;
self.blastRadius = 100;
self.init = function (startX, startY, targetX, targetY) {
self.x = startX;
self.y = startY;
self.targetX = targetX;
self.targetY = targetY;
// Calculate direction vector
var dx = targetX - startX;
var dy = targetY - startY;
var dist = Math.sqrt(dx * dx + dy * dy);
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
// Set rotation
self.rotation = Math.atan2(dx, -dy);
};
self.update = function () {
if (!self.active) {
return;
}
// Move along trajectory
self.x += self.vx;
self.y += self.vy;
// Check if reached target area
var distToTarget = Math.sqrt(Math.pow(self.x - self.targetX, 2) + Math.pow(self.y - self.targetY, 2));
if (distToTarget < 10) {
self.explode();
}
// Check for missile hits
if (self.active) {
// Track if we hit any missiles directly
var hitMissile = false;
// Check all missiles for direct hits
for (var i = 0; i < missiles.length; i++) {
var missile = missiles[i];
if (missile.active) {
var dist = Math.sqrt(Math.pow(self.x - missile.x, 2) + Math.pow(self.y - missile.y, 2));
// Direct hit if within 30px
if (dist < 30) {
missile.explode();
self.explode();
hitMissile = true;
// Award points and increase combo
score += 20 * (1 + level * 0.1);
comboCount++;
if (comboCount > 1) {
// Bonus points for combos
score += 5 * comboCount;
}
updateUI();
break;
}
}
}
// Check if level should advance
if (score >= level * 1000) {
advanceLevel();
}
}
// Check if off screen
if (self.y < -100 || self.y > 2832 || self.x < -100 || self.x > 2148) {
self.destroy();
// Remove from counter rockets array
var index = counterRockets.indexOf(self);
if (index !== -1) {
counterRockets.splice(index, 1);
}
}
};
self.explode = function () {
self.active = false;
// Create explosion
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
explosion.init(self.blastRadius);
game.addChild(explosion);
// Check for missile hits
game.checkMissileHits(self.x, self.y, self.blastRadius);
// Play sound
LK.getSound('explosion_sound').play();
// Remove rocket
self.destroy();
// Remove from counter rockets array
var index = counterRockets.indexOf(self);
if (index !== -1) {
counterRockets.splice(index, 1);
}
};
return self;
});
var DefenseStation = Container.expand(function () {
var self = Container.call(this);
var stationGraphic = self.attachAsset('defense_station', {
anchorX: 0.5,
anchorY: 0.5
});
var aimLine = self.attachAsset('aim_line', {
anchorX: 0.5,
anchorY: 1,
alpha: 0.7
});
self.init = function () {
self.x = 2048 / 2;
self.y = 2732 - 60 - 100; // Just above ground
aimLine.visible = false;
aimLine.rotation = -Math.PI / 2; // Pointing upward
};
self.startAiming = function (x, y) {
aimLine.visible = true;
self.updateAimLine(x, y);
};
self.updateAimLine = function (x, y) {
if (!aimLine.visible) {
return;
}
// Calculate angle for aim line
var dx = x - self.x;
var dy = y - self.y;
var angle = Math.atan2(dx, -dy); // Negative dy because y is inverted
// Restrict angle (can't aim below horizon)
if (angle > Math.PI / 2) {
angle = Math.PI / 2;
}
if (angle < -Math.PI / 2) {
angle = -Math.PI / 2;
}
aimLine.rotation = angle;
};
self.stopAiming = function () {
aimLine.visible = false;
};
self.fire = function (x, y) {
// Calculate direction and target position
var dx = x - self.x;
var dy = y - self.y;
var angle = Math.atan2(dx, -dy);
// Restrict angle (can't fire below horizon)
if (angle > Math.PI / 2) {
angle = Math.PI / 2;
}
if (angle < -Math.PI / 2) {
angle = -Math.PI / 2;
}
// Calculate target point
var reach = 2000;
var targetX = self.x + Math.sin(angle) * reach;
var targetY = self.y - Math.cos(angle) * reach;
// Fire main rocket
var rocket = new CounterRocket();
rocket.init(self.x, self.y, targetX, targetY);
counterRockets.push(rocket);
game.addChild(rocket);
// Fire additional rockets if multishot is active
if (game.multishotActive) {
var spread = Math.PI / 12; // 15 degrees
// Left rocket
var leftRocket = new CounterRocket();
var leftAngle = angle - spread;
var leftTargetX = self.x + Math.sin(leftAngle) * reach;
var leftTargetY = self.y - Math.cos(leftAngle) * reach;
leftRocket.init(self.x, self.y, leftTargetX, leftTargetY);
counterRockets.push(leftRocket);
game.addChild(leftRocket);
// Right rocket
var rightRocket = new CounterRocket();
var rightAngle = angle + spread;
var rightTargetX = self.x + Math.sin(rightAngle) * reach;
var rightTargetY = self.y - Math.cos(rightAngle) * reach;
rightRocket.init(self.x, self.y, rightTargetX, rightTargetY);
counterRockets.push(rightRocket);
game.addChild(rightRocket);
}
// Play sound
LK.getSound('rocket_launch').play();
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.init = function (radius) {
self.radius = radius || 75;
explosionGraphic.width = self.radius * 2;
explosionGraphic.height = self.radius * 2;
// Start animation
explosionGraphic.alpha = 0.9;
tween(explosionGraphic, {
alpha: 0,
width: self.radius * 3,
height: self.radius * 3
}, {
duration: 600,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Missile = Container.expand(function () {
var self = Container.call(this);
var missileGraphic = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 0.5
});
// Default properties
self.speed = 3;
self.targetX = 0;
self.active = true;
self.init = function (startX, speed, targetX) {
self.x = startX;
self.y = -100;
self.speed = speed || 3;
self.targetX = targetX || self.x;
// Calculate angle based on trajectory
var dx = self.targetX - self.x;
var dy = 2732 - self.y;
self.rotation = Math.atan2(dx, dy);
};
self.update = function () {
if (!self.active) {
return;
}
// Move towards target
var dx = self.targetX - self.x;
var groundY = 2732 - 60; // Ground level
var percentComplete = self.y / groundY;
self.x += dx * 0.005;
self.y += self.speed;
// Check if hit ground
if (self.y >= groundY - 40) {
self.explode();
game.missileHitGround(self.x);
}
};
self.explode = function () {
self.active = false;
// Create explosion
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
explosion.init(75);
game.addChild(explosion);
// Play sound
LK.getSound('explosion_sound').play();
// Remove missile
self.destroy();
// Remove from missiles array
var index = missiles.indexOf(self);
if (index !== -1) {
missiles.splice(index, 1);
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphic = self.attachAsset('power_up', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = "multishot";
self.fallSpeed = 2;
self.active = true;
self.init = function (type) {
self.type = type || (Math.random() < 0.5 ? "multishot" : "nuke");
// Set color based on type
if (self.type === "multishot") {
powerUpGraphic.tint = 0x9b59b6; // Purple
} else {
powerUpGraphic.tint = 0xe74c3c; // Red
}
// Position
self.x = 100 + Math.random() * (2048 - 200);
self.y = -100;
// Animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 3000,
onFinish: function onFinish() {
if (self.active) {
self.rotation = 0;
tween(self, {
rotation: Math.PI * 2
}, {
duration: 3000
});
}
}
});
};
self.update = function () {
if (!self.active) {
return;
}
// Fall down
self.y += self.fallSpeed;
// Check if hit ground
if (self.y >= 2732 - 60 - 40) {
self.destroy();
var index = powerUps.indexOf(self);
if (index !== -1) {
powerUps.splice(index, 1);
}
}
// Check if near defense station
var distToStation = Math.sqrt(Math.pow(self.x - defenseStation.x, 2) + Math.pow(self.y - defenseStation.y, 2));
if (distToStation < 150) {
self.collect();
}
};
self.collect = function () {
self.active = false;
// Apply power up effect
if (self.type === "multishot") {
game.activateMultishot();
} else {
game.activateNuke();
}
// Play sound
LK.getSound('power_up_collect').play();
// Remove power up
self.destroy();
// Remove from powerUps array
var index = powerUps.indexOf(self);
if (index !== -1) {
powerUps.splice(index, 1);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x121f2a
});
/****
* Game Code
****/
// Game variables
var score = 0;
var level = 1;
var lives = 3;
var isAiming = false;
var aimStartX = 0;
var aimStartY = 0;
var missiles = [];
var counterRockets = [];
var powerUps = [];
var defenseStation;
var ground;
var gameActive = true;
var missileSpawnRate = 3000; // Time in ms between missile spawns
var missileSpawnTimer = null;
var powerUpSpawnTimer = null;
var multishotTimeoutId = null;
var comboCount = 0;
var comboTimer = null;
// UI elements
var scoreTxt;
var livesTxt;
var levelTxt;
var comboTxt;
// Initialize game objects
function initGame() {
// Set background
game.setBackgroundColor(0x121f2a);
// Play background music
LK.playMusic('game_music');
// Create ground
ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
ground.x = 2048 / 2;
ground.y = 2732 - 30; // Bottom of screen
game.addChild(ground);
// Create defense station
defenseStation = new DefenseStation();
defenseStation.init();
game.addChild(defenseStation);
// Setup UI
setupUI();
// Start missile spawning
startMissileSpawner();
// Start power-up spawning
startPowerUpSpawner();
// Reset game state
score = 0;
level = storage.level || 1;
lives = 3;
gameActive = true;
game.multishotActive = false;
comboCount = 0;
// Update UI
updateUI();
}
function setupUI() {
// Glaud inscription
var glaudTxt = new Text2('Glaud', {
size: 40,
fill: 0xFF8C00
});
glaudTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(glaudTxt);
glaudTxt.x = -20;
glaudTxt.y = 80;
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -280;
scoreTxt.y = 20;
// Lives text
livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.top.addChild(livesTxt);
livesTxt.y = 20;
// Level text
levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
levelTxt.x = 120; // Avoid the top-left 100x100 reserved area
levelTxt.y = 20;
// Combo text
comboTxt = new Text2('', {
size: 80,
fill: 0xF1C40F
});
comboTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(comboTxt);
comboTxt.visible = false;
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
livesTxt.setText('Lives: ' + lives);
levelTxt.setText('Level: ' + level);
if (comboCount > 1) {
comboTxt.setText('COMBO x' + comboCount + '!');
comboTxt.visible = true;
// Reset combo timer
if (comboTimer) {
LK.clearTimeout(comboTimer);
}
comboTimer = LK.setTimeout(function () {
comboTxt.visible = false;
comboCount = 0;
}, 2000);
}
}
function startMissileSpawner() {
// Clear any existing timer
if (missileSpawnTimer) {
LK.clearInterval(missileSpawnTimer);
}
// Calculate spawn rate based on level
var rate = Math.max(3000 - level * 200, 500);
missileSpawnTimer = LK.setInterval(function () {
if (!gameActive) {
return;
}
spawnMissile();
}, rate);
}
function spawnMissile() {
// Create a new missile
var missile = new Missile();
// Randomize starting position
var startX = Math.random() * 2048;
// Randomize target position
var targetX = Math.random() * 2048;
// Calculate speed based on level
var speed = 3 + level * 0.5;
// Initialize missile
missile.init(startX, speed, targetX);
// Add to game
missiles.push(missile);
game.addChild(missile);
}
function startPowerUpSpawner() {
// Clear any existing timer
if (powerUpSpawnTimer) {
LK.clearInterval(powerUpSpawnTimer);
}
powerUpSpawnTimer = LK.setInterval(function () {
if (!gameActive) {
return;
}
// 10% chance to spawn a power-up
if (Math.random() < 0.1) {
spawnPowerUp();
}
}, 5000);
}
function spawnPowerUp() {
// Create a new power-up
var powerUp = new PowerUp();
// Initialize power-up
powerUp.init();
// Add to game
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Game mechanics
game.checkMissileHits = function (x, y, radius) {
var hitCount = 0;
// Check all missiles
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
if (!missile.active) {
continue;
}
// Calculate distance
var dist = Math.sqrt(Math.pow(missile.x - x, 2) + Math.pow(missile.y - y, 2));
// If missile is within blast radius
if (dist <= radius) {
missile.explode();
hitCount++;
// Award points
score += 10 * (1 + level * 0.1);
// Increment combo
comboCount++;
if (comboCount > 1) {
// Bonus points for combos
score += 5 * comboCount;
}
}
}
// Check if level should advance
if (score >= level * 1000) {
advanceLevel();
}
// Update UI
updateUI();
return hitCount;
};
game.missileHitGround = function (x) {
// Visual effect
var groundExplosion = new Explosion();
groundExplosion.x = x;
groundExplosion.y = 2732 - 60;
groundExplosion.init(100);
game.addChild(groundExplosion);
// Reduce lives
lives--;
// Reset combo
comboCount = 0;
if (comboTimer) {
LK.clearTimeout(comboTimer);
}
comboTxt.visible = false;
// Update UI
updateUI();
// Check for game over
if (lives <= 0) {
gameOver();
}
};
function gameOver() {
gameActive = false;
// Stop spawners
if (missileSpawnTimer) {
LK.clearInterval(missileSpawnTimer);
}
if (powerUpSpawnTimer) {
LK.clearInterval(powerUpSpawnTimer);
}
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Set final score
LK.setScore(score);
// Show game over screen
LK.showGameOver();
}
function advanceLevel() {
level++;
storage.level = level;
// Update UI
updateUI();
// Flash level indicator
tween(levelTxt, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
tween(levelTxt, {
alpha: 1
}, {
duration: 200
});
}
});
// Restart missile spawner with new rate
startMissileSpawner();
}
game.activateMultishot = function () {
game.multishotActive = true;
// Create visual indicator
defenseStation.attachAsset('power_up', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
tint: 0x9b59b6,
alpha: 0.7,
scale: 0.5
});
// Clear previous timeout if exists
if (multishotTimeoutId) {
LK.clearTimeout(multishotTimeoutId);
}
// Set timeout to disable multishot
multishotTimeoutId = LK.setTimeout(function () {
game.multishotActive = false;
// Remove all power-up indicators from defense station
for (var i = 0; i < defenseStation.children.length; i++) {
var child = defenseStation.children[i];
if (child.color && child.color === 0x9b59b6) {
defenseStation.removeChild(child);
child.destroy();
}
}
}, 10000); // 10 seconds
};
game.activateNuke = function () {
// Create large explosion at center
var nukeExplosion = new Explosion();
nukeExplosion.x = 2048 / 2;
nukeExplosion.y = 2732 / 2;
nukeExplosion.init(1500); // Large radius
game.addChild(nukeExplosion);
// Destroy all missiles
var destroyedCount = 0;
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
if (missile.active) {
missile.explode();
destroyedCount++;
}
}
// Award points
if (destroyedCount > 0) {
score += destroyedCount * 15;
updateUI();
}
};
// Input handling
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
isAiming = true;
aimStartX = x;
aimStartY = y;
// Start aiming
defenseStation.startAiming(x, y);
};
game.move = function (x, y, obj) {
if (!isAiming || !gameActive) {
return;
}
// Update aim line
defenseStation.updateAimLine(x, y);
};
game.up = function (x, y, obj) {
if (!isAiming || !gameActive) {
return;
}
// Fire rocket
defenseStation.fire(x, y);
// Reset aiming
isAiming = false;
defenseStation.stopAiming();
};
// Game loop
game.update = function () {
if (!gameActive) {
return;
}
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
missiles[i].update();
}
// Update counter rockets
for (var i = counterRockets.length - 1; i >= 0; i--) {
counterRockets[i].update();
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].update();
}
};
// Initialize the game
initGame();
defense_station. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
counter rocket. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
power up. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
explosion. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
missile. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
aim line. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
graund. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows