/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
// Create bomb visual
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
// Random movement properties
self.velocityX = (Math.random() - 0.5) * 12;
self.velocityY = (Math.random() - 0.5) * 12;
self.size = 40; // Half of width for collision detection
// Track last position for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = [];
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move bomb
self.x += self.velocityX * targetSpeedMultiplier;
self.y += self.velocityY * targetSpeedMultiplier;
// Bounce off edges
if (self.x <= self.size || self.x >= 2048 - self.size) {
self.velocityX *= -1;
self.x = Math.max(self.size, Math.min(2048 - self.size, self.x));
}
if (self.y <= self.size || self.y >= 2732 - 200 - self.size) {
self.velocityY *= -1;
self.y = Math.max(self.size, Math.min(2732 - 200 - self.size, self.y));
}
};
self.explode = function () {
// Visual explosion effect - red flash for bomb
LK.effects.flashObject(self, 0xFF0000, 300);
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var DesertBackground = Container.expand(function () {
var self = Container.call(this);
// Create multiple layers of sand dunes
var backDune = self.attachAsset('sandDune3', {
anchorX: 0.5,
anchorY: 1.0,
x: 1024,
y: 2732,
alpha: 0.6
});
var midDune1 = self.attachAsset('sandDune1', {
anchorX: 0.5,
anchorY: 1.0,
x: 400,
y: 2732 - 100,
alpha: 0.8
});
var midDune2 = self.attachAsset('sandDune2', {
anchorX: 0.5,
anchorY: 1.0,
x: 1600,
y: 2732 - 150,
alpha: 0.7
});
// Add cacti scattered around
var cactus1 = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1.0,
x: 300,
y: 2500
});
var cactusArm1 = self.attachAsset('cactusArm', {
anchorX: 0,
anchorY: 0.5,
x: 320,
y: 2400
});
var cactus2 = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1.0,
x: 1700,
y: 2400,
scaleX: 0.8,
scaleY: 0.8
});
var cactusArm2 = self.attachAsset('cactusArm', {
anchorX: 1,
anchorY: 0.5,
x: 1680,
y: 2320,
scaleX: 0.8,
scaleY: 0.8
});
// Add some rocks
var rock1 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 800,
y: 2600,
alpha: 0.8
});
var rock2 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 1200,
y: 2550,
alpha: 0.7,
scaleX: 0.6,
scaleY: 0.6
});
var rock3 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 1500,
y: 2650,
alpha: 0.9,
scaleX: 1.2,
scaleY: 1.2
});
return self;
});
var Missile = Container.expand(function () {
var self = Container.call(this);
var missileGraphics = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 30;
self.setTarget = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
// Rotate missile to face direction of travel
self.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var RocketLauncher = Container.expand(function () {
var self = Container.call(this);
var launcherBase = self.attachAsset('launcher', {
anchorX: 0.5,
anchorY: 1.0
});
var barrel = self.attachAsset('launcherBarrel', {
anchorX: 0.5,
anchorY: 1.0,
y: -20
});
self.targetAngle = 0;
self.currentAngle = 0;
self.rotationSpeed = 0.15;
self.aimAt = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
self.targetAngle = Math.atan2(dx, dy);
};
self.fire = function (targetX, targetY) {
var missile = new Missile();
missile.x = self.x;
missile.y = self.y - 40;
missile.setTarget(targetX, targetY);
missiles.push(missile);
game.addChild(missile);
LK.getSound('launch').play();
// Add some recoil effect
tween(self, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
};
self.update = function () {
// Smoothly rotate launcher to target angle
var angleDiff = self.targetAngle - self.currentAngle;
// Handle angle wrapping
if (angleDiff > Math.PI) {
angleDiff -= 2 * Math.PI;
} else if (angleDiff < -Math.PI) {
angleDiff += 2 * Math.PI;
}
self.currentAngle += angleDiff * self.rotationSpeed;
self.rotation = self.currentAngle;
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
// Create target visual
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
// Random movement properties
self.velocityX = (Math.random() - 0.5) * 16;
self.velocityY = (Math.random() - 0.5) * 16;
self.size = 44; // Half of scaled width for collision detection
// Track last position for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = [];
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move target
self.x += self.velocityX * targetSpeedMultiplier;
self.y += self.velocityY * targetSpeedMultiplier;
// Bounce off edges
if (self.x <= self.size || self.x >= 2048 - self.size) {
self.velocityX *= -1;
self.x = Math.max(self.size, Math.min(2048 - self.size, self.x));
}
if (self.y <= self.size || self.y >= 2732 - 200 - self.size) {
self.velocityY *= -1;
self.y = Math.max(self.size, Math.min(2732 - 200 - self.size, self.y));
}
};
self.explode = function () {
// Visual explosion effect
LK.effects.flashObject(self, 0xFFFF00, 300);
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF4A460
});
/****
* Game Code
****/
// Desert background elements
var missiles = [];
var targets = [];
var bombs = [];
var launcher = null;
var targetSpawnTimer = 0;
var missileCount = 5;
var maxMissiles = 5;
var targetSpeedMultiplier = 1.0;
// Create and add desert background
var desertBackground = game.addChild(new DesertBackground());
// Initialize rocket launcher
launcher = game.addChild(new RocketLauncher());
launcher.x = 2048 / 2;
launcher.y = 2732 - 100;
// Level system variables
var currentLevel = 1;
var levelThresholds = [0, 50, 150, 300, 500, 750, 1000, 1500, 2000, 3000];
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Level display
var levelTxt = new Text2('Level: 1', {
size: 70,
fill: 0x00FF00
});
levelTxt.anchor.set(1, 0);
levelTxt.y = 80;
LK.gui.topRight.addChild(levelTxt);
// Instructions
var instructionsTxt = new Text2('Tap anywhere to fire missiles!', {
size: 48,
fill: 0xCCCCCC
});
instructionsTxt.anchor.set(0.5, 0);
instructionsTxt.y = 100;
LK.gui.top.addChild(instructionsTxt);
// Missile count display
var missileCountTxt = new Text2('5/5', {
size: 60,
fill: 0xFFFFFF
});
missileCountTxt.anchor.set(1, 0);
missileCountTxt.y = 140;
LK.gui.topRight.addChild(missileCountTxt);
// Function to calculate current level based on score
function calculateLevel(score) {
for (var i = levelThresholds.length - 1; i >= 0; i--) {
if (score >= levelThresholds[i]) {
return i + 1;
}
}
return 1;
}
// Function to update level display
function updateLevel() {
var newLevel = calculateLevel(LK.getScore());
if (newLevel !== currentLevel) {
currentLevel = newLevel;
levelTxt.setText('Level: ' + currentLevel);
// Level up effect
LK.effects.flashScreen(0xFFD700, 500);
// Scale animation for level text
tween(levelTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}
// Game tap handler
game.down = function (x, y, obj) {
// Don't fire if tapping on launcher area
if (y > 2732 - 200) {
return;
}
// Aim and fire
launcher.aimAt(x, y);
// Check if enough time has passed since last shot (1 second)
if (!game.lastShotTime) game.lastShotTime = 0;
var currentTime = LK.ticks;
var requiredTicks = LK.getScore() > 150 ? 12 : 30; // 12 ticks = 0.2 seconds, 30 ticks = 0.5 seconds
if (currentTime - game.lastShotTime >= requiredTicks && missileCount > 0) {
// 12 ticks = 0.2 seconds at 60fps when score > 150
// 30 ticks = 0.5 seconds at 60fps and have missiles
// 60 ticks = 1 second at 60fps and have missiles
// Small delay before firing for visual feedback
LK.setTimeout(function () {
launcher.fire(x, y);
// Update score - decrease by 1 for firing
LK.setScore(LK.getScore() - 1);
scoreTxt.setText('Score: ' + LK.getScore());
updateLevel();
// Decrease missile count
missileCount--;
missileCountTxt.setText(missileCount + '/' + maxMissiles);
}, 200);
game.lastShotTime = currentTime;
}
};
game.update = function () {
// Update target speed multiplier based on score
if (LK.getScore() > 300) {
targetSpeedMultiplier = 3.5;
} else if (LK.getScore() > 150) {
targetSpeedMultiplier = 2.5;
} else if (LK.getScore() > 50) {
targetSpeedMultiplier = 1.5;
} else {
targetSpeedMultiplier = 1.0;
}
// Spawn targets periodically
targetSpawnTimer++;
if (targetSpawnTimer >= 90) {
// Spawn every 1.5 seconds, no limit
var target = new Target();
target.x = Math.random() * (2048 - 200) + 100;
target.y = Math.random() * (2732 - 400) + 100;
target.lastX = target.x;
target.lastY = target.y;
target.lastIntersecting = [];
targets.push(target);
game.addChild(target);
targetSpawnTimer = 0;
}
// Spawn only 1 bomb maximum (only when none exists)
if (bombs.length === 0) {
// Spawn bomb when no bombs exist
var bomb = new Bomb();
bomb.x = Math.random() * (2048 - 200) + 100;
bomb.y = Math.random() * (2732 - 400) + 100;
bomb.lastX = bomb.x;
bomb.lastY = bomb.y;
bomb.lastIntersecting = [];
bombs.push(bomb);
game.addChild(bomb);
}
// Update missile speed based on score
var missileSpeedMultiplier = LK.getScore() >= 300 ? 2.0 : 1.0;
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
// Apply speed multiplier to missile movement
missile.velocityX *= missileSpeedMultiplier;
missile.velocityY *= missileSpeedMultiplier;
// Track last position for boundary checking
if (missile.lastX === undefined) missile.lastX = missile.x;
if (missile.lastY === undefined) missile.lastY = missile.y;
if (missile.lastIntersecting === undefined) missile.lastIntersecting = [];
// Check missile-bomb collisions first (game over condition)
for (var j = bombs.length - 1; j >= 0; j--) {
var bomb = bombs[j];
var wasIntersecting = missile.lastIntersecting.indexOf('bomb_' + j) !== -1;
var isIntersecting = missile.intersects(bomb);
if (!wasIntersecting && isIntersecting) {
// Missile hit bomb - game over!
bomb.explode();
bombs.splice(j, 1);
// Flash screen red and show game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
if (isIntersecting) {
if (missile.lastIntersecting.indexOf('bomb_' + j) === -1) {
missile.lastIntersecting.push('bomb_' + j);
}
}
}
// Check missile-target collisions
var hitTarget = false;
for (var j = targets.length - 1; j >= 0; j--) {
var target = targets[j];
var wasIntersecting = missile.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = missile.intersects(target);
if (!wasIntersecting && isIntersecting) {
// Missile hit target
target.explode();
targets.splice(j, 1);
// Update score
LK.setScore(LK.getScore() + 6);
scoreTxt.setText('Score: ' + LK.getScore());
updateLevel();
// Restore missile count to maximum
missileCount = maxMissiles;
missileCountTxt.setText(missileCount + '/' + maxMissiles);
// Remove missile
missile.destroy();
missiles.splice(i, 1);
hitTarget = true;
break;
}
if (isIntersecting) {
if (missile.lastIntersecting.indexOf(j) === -1) {
missile.lastIntersecting.push(j);
}
}
}
if (hitTarget) continue;
// Check if missile went off screen
var offScreen = missile.x < -50 || missile.x > 2048 + 50 || missile.y < -50 || missile.y > 2732 + 50;
if (offScreen) {
missile.destroy();
missiles.splice(i, 1);
continue;
}
// Update last position
missile.lastX = missile.x;
missile.lastY = missile.y;
}
// Check game over condition - if more than 15 targets are alive
if (targets.length > 15) {
LK.showGameOver();
return;
}
// Check game over condition - if missile count reaches 0
if (missileCount <= 0) {
LK.showGameOver();
return;
}
// Update targets and handle target-target collisions
for (var i = targets.length - 1; i >= 0; i--) {
var target1 = targets[i];
if (target1.lastIntersecting === undefined) target1.lastIntersecting = [];
// Check collisions with other targets
for (var j = i + 1; j < targets.length; j++) {
var target2 = targets[j];
var wasIntersecting = target1.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = target1.intersects(target2);
if (!wasIntersecting && isIntersecting) {
// Collision detected - bounce off each other
var dx = target2.x - target1.x;
var dy = target2.y - target1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize collision vector
dx /= distance;
dy /= distance;
// Separate targets
var overlap = target1.size + target2.size - distance;
target1.x -= dx * overlap * 0.5;
target1.y -= dy * overlap * 0.5;
target2.x += dx * overlap * 0.5;
target2.y += dy * overlap * 0.5;
// Exchange velocities (simplified collision response)
var tempVelX = target1.velocityX;
var tempVelY = target1.velocityY;
target1.velocityX = target2.velocityX;
target1.velocityY = target2.velocityY;
target2.velocityX = tempVelX;
target2.velocityY = tempVelY;
}
}
// Update intersection tracking
if (isIntersecting) {
if (target1.lastIntersecting.indexOf(j) === -1) {
target1.lastIntersecting.push(j);
}
} else {
var index = target1.lastIntersecting.indexOf(j);
if (index !== -1) {
target1.lastIntersecting.splice(index, 1);
}
}
}
}
// Update bombs and handle bomb-bomb collisions
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb1 = bombs[i];
if (bomb1.lastIntersecting === undefined) bomb1.lastIntersecting = [];
// Check collisions with other bombs
for (var j = i + 1; j < bombs.length; j++) {
var bomb2 = bombs[j];
var wasIntersecting = bomb1.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = bomb1.intersects(bomb2);
if (!wasIntersecting && isIntersecting) {
// Collision detected - bounce off each other
var dx = bomb2.x - bomb1.x;
var dy = bomb2.y - bomb1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize collision vector
dx /= distance;
dy /= distance;
// Separate bombs
var overlap = bomb1.size + bomb2.size - distance;
bomb1.x -= dx * overlap * 0.5;
bomb1.y -= dy * overlap * 0.5;
bomb2.x += dx * overlap * 0.5;
bomb2.y += dy * overlap * 0.5;
// Exchange velocities (simplified collision response)
var tempVelX = bomb1.velocityX;
var tempVelY = bomb1.velocityY;
bomb1.velocityX = bomb2.velocityX;
bomb1.velocityY = bomb2.velocityY;
bomb2.velocityX = tempVelX;
bomb2.velocityY = tempVelY;
}
}
// Update intersection tracking
if (isIntersecting) {
if (bomb1.lastIntersecting.indexOf(j) === -1) {
bomb1.lastIntersecting.push(j);
}
} else {
var index = bomb1.lastIntersecting.indexOf(j);
if (index !== -1) {
bomb1.lastIntersecting.splice(index, 1);
}
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
// Create bomb visual
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
// Random movement properties
self.velocityX = (Math.random() - 0.5) * 12;
self.velocityY = (Math.random() - 0.5) * 12;
self.size = 40; // Half of width for collision detection
// Track last position for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = [];
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move bomb
self.x += self.velocityX * targetSpeedMultiplier;
self.y += self.velocityY * targetSpeedMultiplier;
// Bounce off edges
if (self.x <= self.size || self.x >= 2048 - self.size) {
self.velocityX *= -1;
self.x = Math.max(self.size, Math.min(2048 - self.size, self.x));
}
if (self.y <= self.size || self.y >= 2732 - 200 - self.size) {
self.velocityY *= -1;
self.y = Math.max(self.size, Math.min(2732 - 200 - self.size, self.y));
}
};
self.explode = function () {
// Visual explosion effect - red flash for bomb
LK.effects.flashObject(self, 0xFF0000, 300);
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var DesertBackground = Container.expand(function () {
var self = Container.call(this);
// Create multiple layers of sand dunes
var backDune = self.attachAsset('sandDune3', {
anchorX: 0.5,
anchorY: 1.0,
x: 1024,
y: 2732,
alpha: 0.6
});
var midDune1 = self.attachAsset('sandDune1', {
anchorX: 0.5,
anchorY: 1.0,
x: 400,
y: 2732 - 100,
alpha: 0.8
});
var midDune2 = self.attachAsset('sandDune2', {
anchorX: 0.5,
anchorY: 1.0,
x: 1600,
y: 2732 - 150,
alpha: 0.7
});
// Add cacti scattered around
var cactus1 = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1.0,
x: 300,
y: 2500
});
var cactusArm1 = self.attachAsset('cactusArm', {
anchorX: 0,
anchorY: 0.5,
x: 320,
y: 2400
});
var cactus2 = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1.0,
x: 1700,
y: 2400,
scaleX: 0.8,
scaleY: 0.8
});
var cactusArm2 = self.attachAsset('cactusArm', {
anchorX: 1,
anchorY: 0.5,
x: 1680,
y: 2320,
scaleX: 0.8,
scaleY: 0.8
});
// Add some rocks
var rock1 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 800,
y: 2600,
alpha: 0.8
});
var rock2 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 1200,
y: 2550,
alpha: 0.7,
scaleX: 0.6,
scaleY: 0.6
});
var rock3 = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 1.0,
x: 1500,
y: 2650,
alpha: 0.9,
scaleX: 1.2,
scaleY: 1.2
});
return self;
});
var Missile = Container.expand(function () {
var self = Container.call(this);
var missileGraphics = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 30;
self.setTarget = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
// Rotate missile to face direction of travel
self.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var RocketLauncher = Container.expand(function () {
var self = Container.call(this);
var launcherBase = self.attachAsset('launcher', {
anchorX: 0.5,
anchorY: 1.0
});
var barrel = self.attachAsset('launcherBarrel', {
anchorX: 0.5,
anchorY: 1.0,
y: -20
});
self.targetAngle = 0;
self.currentAngle = 0;
self.rotationSpeed = 0.15;
self.aimAt = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
self.targetAngle = Math.atan2(dx, dy);
};
self.fire = function (targetX, targetY) {
var missile = new Missile();
missile.x = self.x;
missile.y = self.y - 40;
missile.setTarget(targetX, targetY);
missiles.push(missile);
game.addChild(missile);
LK.getSound('launch').play();
// Add some recoil effect
tween(self, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
};
self.update = function () {
// Smoothly rotate launcher to target angle
var angleDiff = self.targetAngle - self.currentAngle;
// Handle angle wrapping
if (angleDiff > Math.PI) {
angleDiff -= 2 * Math.PI;
} else if (angleDiff < -Math.PI) {
angleDiff += 2 * Math.PI;
}
self.currentAngle += angleDiff * self.rotationSpeed;
self.rotation = self.currentAngle;
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
// Create target visual
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
// Random movement properties
self.velocityX = (Math.random() - 0.5) * 16;
self.velocityY = (Math.random() - 0.5) * 16;
self.size = 44; // Half of scaled width for collision detection
// Track last position for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = [];
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move target
self.x += self.velocityX * targetSpeedMultiplier;
self.y += self.velocityY * targetSpeedMultiplier;
// Bounce off edges
if (self.x <= self.size || self.x >= 2048 - self.size) {
self.velocityX *= -1;
self.x = Math.max(self.size, Math.min(2048 - self.size, self.x));
}
if (self.y <= self.size || self.y >= 2732 - 200 - self.size) {
self.velocityY *= -1;
self.y = Math.max(self.size, Math.min(2732 - 200 - self.size, self.y));
}
};
self.explode = function () {
// Visual explosion effect
LK.effects.flashObject(self, 0xFFFF00, 300);
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF4A460
});
/****
* Game Code
****/
// Desert background elements
var missiles = [];
var targets = [];
var bombs = [];
var launcher = null;
var targetSpawnTimer = 0;
var missileCount = 5;
var maxMissiles = 5;
var targetSpeedMultiplier = 1.0;
// Create and add desert background
var desertBackground = game.addChild(new DesertBackground());
// Initialize rocket launcher
launcher = game.addChild(new RocketLauncher());
launcher.x = 2048 / 2;
launcher.y = 2732 - 100;
// Level system variables
var currentLevel = 1;
var levelThresholds = [0, 50, 150, 300, 500, 750, 1000, 1500, 2000, 3000];
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Level display
var levelTxt = new Text2('Level: 1', {
size: 70,
fill: 0x00FF00
});
levelTxt.anchor.set(1, 0);
levelTxt.y = 80;
LK.gui.topRight.addChild(levelTxt);
// Instructions
var instructionsTxt = new Text2('Tap anywhere to fire missiles!', {
size: 48,
fill: 0xCCCCCC
});
instructionsTxt.anchor.set(0.5, 0);
instructionsTxt.y = 100;
LK.gui.top.addChild(instructionsTxt);
// Missile count display
var missileCountTxt = new Text2('5/5', {
size: 60,
fill: 0xFFFFFF
});
missileCountTxt.anchor.set(1, 0);
missileCountTxt.y = 140;
LK.gui.topRight.addChild(missileCountTxt);
// Function to calculate current level based on score
function calculateLevel(score) {
for (var i = levelThresholds.length - 1; i >= 0; i--) {
if (score >= levelThresholds[i]) {
return i + 1;
}
}
return 1;
}
// Function to update level display
function updateLevel() {
var newLevel = calculateLevel(LK.getScore());
if (newLevel !== currentLevel) {
currentLevel = newLevel;
levelTxt.setText('Level: ' + currentLevel);
// Level up effect
LK.effects.flashScreen(0xFFD700, 500);
// Scale animation for level text
tween(levelTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}
// Game tap handler
game.down = function (x, y, obj) {
// Don't fire if tapping on launcher area
if (y > 2732 - 200) {
return;
}
// Aim and fire
launcher.aimAt(x, y);
// Check if enough time has passed since last shot (1 second)
if (!game.lastShotTime) game.lastShotTime = 0;
var currentTime = LK.ticks;
var requiredTicks = LK.getScore() > 150 ? 12 : 30; // 12 ticks = 0.2 seconds, 30 ticks = 0.5 seconds
if (currentTime - game.lastShotTime >= requiredTicks && missileCount > 0) {
// 12 ticks = 0.2 seconds at 60fps when score > 150
// 30 ticks = 0.5 seconds at 60fps and have missiles
// 60 ticks = 1 second at 60fps and have missiles
// Small delay before firing for visual feedback
LK.setTimeout(function () {
launcher.fire(x, y);
// Update score - decrease by 1 for firing
LK.setScore(LK.getScore() - 1);
scoreTxt.setText('Score: ' + LK.getScore());
updateLevel();
// Decrease missile count
missileCount--;
missileCountTxt.setText(missileCount + '/' + maxMissiles);
}, 200);
game.lastShotTime = currentTime;
}
};
game.update = function () {
// Update target speed multiplier based on score
if (LK.getScore() > 300) {
targetSpeedMultiplier = 3.5;
} else if (LK.getScore() > 150) {
targetSpeedMultiplier = 2.5;
} else if (LK.getScore() > 50) {
targetSpeedMultiplier = 1.5;
} else {
targetSpeedMultiplier = 1.0;
}
// Spawn targets periodically
targetSpawnTimer++;
if (targetSpawnTimer >= 90) {
// Spawn every 1.5 seconds, no limit
var target = new Target();
target.x = Math.random() * (2048 - 200) + 100;
target.y = Math.random() * (2732 - 400) + 100;
target.lastX = target.x;
target.lastY = target.y;
target.lastIntersecting = [];
targets.push(target);
game.addChild(target);
targetSpawnTimer = 0;
}
// Spawn only 1 bomb maximum (only when none exists)
if (bombs.length === 0) {
// Spawn bomb when no bombs exist
var bomb = new Bomb();
bomb.x = Math.random() * (2048 - 200) + 100;
bomb.y = Math.random() * (2732 - 400) + 100;
bomb.lastX = bomb.x;
bomb.lastY = bomb.y;
bomb.lastIntersecting = [];
bombs.push(bomb);
game.addChild(bomb);
}
// Update missile speed based on score
var missileSpeedMultiplier = LK.getScore() >= 300 ? 2.0 : 1.0;
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
// Apply speed multiplier to missile movement
missile.velocityX *= missileSpeedMultiplier;
missile.velocityY *= missileSpeedMultiplier;
// Track last position for boundary checking
if (missile.lastX === undefined) missile.lastX = missile.x;
if (missile.lastY === undefined) missile.lastY = missile.y;
if (missile.lastIntersecting === undefined) missile.lastIntersecting = [];
// Check missile-bomb collisions first (game over condition)
for (var j = bombs.length - 1; j >= 0; j--) {
var bomb = bombs[j];
var wasIntersecting = missile.lastIntersecting.indexOf('bomb_' + j) !== -1;
var isIntersecting = missile.intersects(bomb);
if (!wasIntersecting && isIntersecting) {
// Missile hit bomb - game over!
bomb.explode();
bombs.splice(j, 1);
// Flash screen red and show game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
if (isIntersecting) {
if (missile.lastIntersecting.indexOf('bomb_' + j) === -1) {
missile.lastIntersecting.push('bomb_' + j);
}
}
}
// Check missile-target collisions
var hitTarget = false;
for (var j = targets.length - 1; j >= 0; j--) {
var target = targets[j];
var wasIntersecting = missile.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = missile.intersects(target);
if (!wasIntersecting && isIntersecting) {
// Missile hit target
target.explode();
targets.splice(j, 1);
// Update score
LK.setScore(LK.getScore() + 6);
scoreTxt.setText('Score: ' + LK.getScore());
updateLevel();
// Restore missile count to maximum
missileCount = maxMissiles;
missileCountTxt.setText(missileCount + '/' + maxMissiles);
// Remove missile
missile.destroy();
missiles.splice(i, 1);
hitTarget = true;
break;
}
if (isIntersecting) {
if (missile.lastIntersecting.indexOf(j) === -1) {
missile.lastIntersecting.push(j);
}
}
}
if (hitTarget) continue;
// Check if missile went off screen
var offScreen = missile.x < -50 || missile.x > 2048 + 50 || missile.y < -50 || missile.y > 2732 + 50;
if (offScreen) {
missile.destroy();
missiles.splice(i, 1);
continue;
}
// Update last position
missile.lastX = missile.x;
missile.lastY = missile.y;
}
// Check game over condition - if more than 15 targets are alive
if (targets.length > 15) {
LK.showGameOver();
return;
}
// Check game over condition - if missile count reaches 0
if (missileCount <= 0) {
LK.showGameOver();
return;
}
// Update targets and handle target-target collisions
for (var i = targets.length - 1; i >= 0; i--) {
var target1 = targets[i];
if (target1.lastIntersecting === undefined) target1.lastIntersecting = [];
// Check collisions with other targets
for (var j = i + 1; j < targets.length; j++) {
var target2 = targets[j];
var wasIntersecting = target1.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = target1.intersects(target2);
if (!wasIntersecting && isIntersecting) {
// Collision detected - bounce off each other
var dx = target2.x - target1.x;
var dy = target2.y - target1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize collision vector
dx /= distance;
dy /= distance;
// Separate targets
var overlap = target1.size + target2.size - distance;
target1.x -= dx * overlap * 0.5;
target1.y -= dy * overlap * 0.5;
target2.x += dx * overlap * 0.5;
target2.y += dy * overlap * 0.5;
// Exchange velocities (simplified collision response)
var tempVelX = target1.velocityX;
var tempVelY = target1.velocityY;
target1.velocityX = target2.velocityX;
target1.velocityY = target2.velocityY;
target2.velocityX = tempVelX;
target2.velocityY = tempVelY;
}
}
// Update intersection tracking
if (isIntersecting) {
if (target1.lastIntersecting.indexOf(j) === -1) {
target1.lastIntersecting.push(j);
}
} else {
var index = target1.lastIntersecting.indexOf(j);
if (index !== -1) {
target1.lastIntersecting.splice(index, 1);
}
}
}
}
// Update bombs and handle bomb-bomb collisions
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb1 = bombs[i];
if (bomb1.lastIntersecting === undefined) bomb1.lastIntersecting = [];
// Check collisions with other bombs
for (var j = i + 1; j < bombs.length; j++) {
var bomb2 = bombs[j];
var wasIntersecting = bomb1.lastIntersecting.indexOf(j) !== -1;
var isIntersecting = bomb1.intersects(bomb2);
if (!wasIntersecting && isIntersecting) {
// Collision detected - bounce off each other
var dx = bomb2.x - bomb1.x;
var dy = bomb2.y - bomb1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize collision vector
dx /= distance;
dy /= distance;
// Separate bombs
var overlap = bomb1.size + bomb2.size - distance;
bomb1.x -= dx * overlap * 0.5;
bomb1.y -= dy * overlap * 0.5;
bomb2.x += dx * overlap * 0.5;
bomb2.y += dy * overlap * 0.5;
// Exchange velocities (simplified collision response)
var tempVelX = bomb1.velocityX;
var tempVelY = bomb1.velocityY;
bomb1.velocityX = bomb2.velocityX;
bomb1.velocityY = bomb2.velocityY;
bomb2.velocityX = tempVelX;
bomb2.velocityY = tempVelY;
}
}
// Update intersection tracking
if (isIntersecting) {
if (bomb1.lastIntersecting.indexOf(j) === -1) {
bomb1.lastIntersecting.push(j);
}
} else {
var index = bomb1.lastIntersecting.indexOf(j);
if (index !== -1) {
bomb1.lastIntersecting.splice(index, 1);
}
}
}
}
};
a bird's eye view of a tank . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
missile . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
War plane. In-Game asset. 2d. High contrast. No shadows
Cactus. In-Game asset. 2d. High contrast. No shadows
Bomb. In-Game asset. 2d. High contrast. No shadows