/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Drone = Container.expand(function () {
var self = Container.call(this);
var droneBody = self.attachAsset('drone', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.direction = 1;
self.startX = 0;
self.patrolDistance = 250;
self.shootCooldown = 2000; // 2 seconds
self.lastShotTime = 0;
self.detectionRange = 400;
self.hoverHeight = 100; // Height above ground to hover
self.update = function () {
// Patrol movement
self.x += self.speed * self.direction;
if (Math.abs(self.x - self.startX) > self.patrolDistance) {
self.direction *= -1;
}
// Hover at fixed height
var targetY = groundLevel - self.hoverHeight;
if (self.y > targetY) {
self.y -= 2;
} else if (self.y < targetY) {
self.y += 2;
}
// Check if player is in range and shoot
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
var currentTime = Date.now();
if (distanceToPlayer < self.detectionRange && currentTime - self.lastShotTime >= self.shootCooldown) {
self.shoot();
self.lastShotTime = currentTime;
}
// Add floating animation with tween
if (!self.isFloating) {
self.isFloating = true;
self.startFloat();
}
};
self.shoot = function () {
// Calculate direction to player
var deltaX = player.x - self.x;
var deltaY = player.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Normalize direction
var dirX = deltaX / distance;
var dirY = deltaY / distance;
// Create bullet
var bullet = game.addChild(new DroneBullet());
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = dirX * bullet.speed;
bullet.velocityY = dirY * bullet.speed;
droneBullets.push(bullet);
// Play shoot sound
LK.getSound('droneShoot').play();
// Visual feedback - flash red briefly
tween(self, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
self.startFloat = function () {
tween(self, {
y: self.y - 10
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 10
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isFloating = false;
}
});
}
});
};
return self;
});
var DroneBullet = Container.expand(function () {
var self = Container.call(this);
var bulletBody = self.attachAsset('droneBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.lifeTime = 3000; // 3 seconds
self.age = 0;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.age += 16; // Assuming 60fps
// Remove bullet if it's too old or off screen
if (self.age >= self.lifeTime || self.x < -100 || self.x > levelWidth + 100 || self.y < -100 || self.y > groundLevel + 500) {
self.destroy();
for (var i = droneBullets.length - 1; i >= 0; i--) {
if (droneBullets[i] === self) {
droneBullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyBody = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 2;
self.direction = 1;
self.startX = 0;
self.patrolDistance = 300;
self.update = function () {
self.x += self.speed * self.direction;
if (Math.abs(self.x - self.startX) > self.patrolDistance) {
self.direction *= -1;
}
// Ground collision for enemies
if (self.y >= groundLevel) {
self.y = groundLevel;
}
// Platform collision for enemies
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
// Check if enemy is on top of platform
if (self.intersects(platform)) {
var platformLeft = platform.x - 100; // platform width/2
var platformRight = platform.x + 100; // platform width/2
var platformTop = platform.y - 20; // platform height/2
var enemyLeft = self.x - 30; // enemy width/2
var enemyRight = self.x + 30; // enemy width/2
var enemyBottom = self.y;
// Landing on platform
if (enemyBottom > platformTop && enemyBottom < platformTop + 50 && enemyRight > platformLeft && enemyLeft < platformRight) {
self.y = platformTop;
}
}
}
};
return self;
});
var HomingMissile = Container.expand(function () {
var self = Container.call(this);
var missileBody = self.attachAsset('homingMissile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 6;
self.homingStrength = 0.15;
self.lifeTime = 5000; // 5 seconds
self.age = 0;
self.hasExploded = false;
self.update = function () {
// Calculate direction to player
var deltaX = player.x - self.x;
var deltaY = player.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
// Normalize direction
var dirX = deltaX / distance;
var dirY = deltaY / distance;
// Apply homing
self.velocityX += dirX * self.homingStrength;
self.velocityY += dirY * self.homingStrength;
// Limit speed
var currentSpeed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (currentSpeed > self.speed) {
self.velocityX = self.velocityX / currentSpeed * self.speed;
self.velocityY = self.velocityY / currentSpeed * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
self.age += 16; // Assuming 60fps
// Check ground/platform collision for explosion
if (self.y >= groundLevel && !self.hasExploded) {
self.explode();
}
// Check platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && !self.hasExploded) {
self.explode();
break;
}
}
// Remove missile if it's too old or off screen
if (self.age >= self.lifeTime || self.x < -200 || self.x > levelWidth + 200 || self.y > groundLevel + 500) {
self.destroy();
for (var j = homingMissiles.length - 1; j >= 0; j--) {
if (homingMissiles[j] === self) {
homingMissiles.splice(j, 1);
break;
}
}
}
};
self.explode = function () {
if (self.hasExploded) return;
self.hasExploded = true;
// Create explosion visual
var explosion = game.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.8
}));
// Explosion animation with tween
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Damage player if close enough
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
if (distanceToPlayer < 100) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
// Remove missile from game
self.destroy();
for (var j = homingMissiles.length - 1; j >= 0; j--) {
if (homingMissiles[j] === self) {
homingMissiles.splice(j, 1);
break;
}
}
};
return self;
});
var JunkPile = Container.expand(function () {
var self = Container.call(this);
var junkBody = self.attachAsset('junkPile', {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformBody = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerBody = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
var leftEye = self.attachAsset('playerEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
y: -50
});
var rightEye = self.attachAsset('playerEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 20,
y: -50
});
var leftPupil = self.attachAsset('playerPupil', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
y: -50
});
var rightPupil = self.attachAsset('playerPupil', {
anchorX: 0.5,
anchorY: 0.5,
x: 20,
y: -50
});
self.velocityX = 0;
self.velocityY = 0;
self.onGround = false;
self.jumpCount = 0;
self.maxJumps = 2;
self.jumpPower = -15;
self.gravity = 0.8;
self.maxSpeed = 8;
self.friction = 0.85;
self.dashPower = 20;
self.dashDuration = 200;
self.dashCooldown = 1000;
self.isDashing = false;
self.dashTimeRemaining = 0;
self.lastDashTime = 0;
self.isSprinting = false;
self.sprintMultiplier = 1.8;
self.normalMaxSpeed = 8;
self.sprintMaxSpeed = 14;
self.speedBoostActive = false;
self.speedBoostStartTime = 0;
self.speedBoostDuration = 20000; // 20 seconds
self.boostMaxSpeed = 18;
self.update = function () {
// Handle dash mechanics
if (self.isDashing && self.dashTimeRemaining > 0) {
self.dashTimeRemaining -= 16; // Assuming 60fps, ~16ms per frame
if (self.dashTimeRemaining <= 0) {
self.isDashing = false;
}
}
// Handle speed boost timer
if (self.speedBoostActive) {
var currentTime = Date.now();
if (currentTime - self.speedBoostStartTime >= self.speedBoostDuration) {
self.deactivateSpeedBoost();
}
}
// Apply gravity (reduced during dash)
if (!self.isDashing) {
self.velocityY += self.gravity;
} else {
self.velocityY += self.gravity * 0.3; // Reduced gravity during dash
}
// Apply friction
self.velocityX *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel) {
self.y = groundLevel;
self.velocityY = 0;
self.onGround = true;
self.jumpCount = 0;
} else {
self.onGround = false;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
// Check if player is intersecting with platform
if (self.intersects(platform)) {
// Calculate platform boundaries
var platformLeft = platform.x - 100; // platform width/2
var platformRight = platform.x + 100; // platform width/2
var platformTop = platform.y - 20; // platform height/2
var platformBottom = platform.y + 20; // platform height/2
var playerLeft = self.x - 40; // player width/2
var playerRight = self.x + 40; // player width/2
var playerTop = self.y - 80; // player height
var playerBottom = self.y;
// Landing on top of platform
if (self.velocityY > 0 && playerBottom > platformTop && playerTop < platformTop && playerRight > platformLeft && playerLeft < platformRight) {
self.y = platformTop;
self.velocityY = 0;
self.onGround = true;
self.jumpCount = 0;
}
// Hitting platform from below
else if (self.velocityY < 0 && playerTop < platformBottom && playerBottom > platformBottom && playerRight > platformLeft && playerLeft < platformRight) {
self.y = platformBottom + 80;
self.velocityY = 0;
}
// Hitting platform from left
else if (self.velocityX > 0 && playerRight > platformLeft && playerLeft < platformLeft && playerBottom > platformTop && playerTop < platformBottom) {
self.x = platformLeft - 40;
self.velocityX = 0;
}
// Hitting platform from right
else if (self.velocityX < 0 && playerLeft < platformRight && playerRight > platformRight && playerBottom > platformTop && playerTop < platformBottom) {
self.x = platformRight + 40;
self.velocityX = 0;
}
}
}
// Boundary checking
if (self.x < 40) {
self.x = 40;
}
if (self.x > levelWidth - 40) {
self.x = levelWidth - 40;
}
};
self.jump = function () {
if (self.jumpCount < self.maxJumps) {
self.velocityY = self.jumpPower;
self.jumpCount++;
self.onGround = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
var baseSpeed = self.normalMaxSpeed;
var sprintSpeed = self.sprintMaxSpeed;
if (self.speedBoostActive) {
baseSpeed = self.boostMaxSpeed;
sprintSpeed = self.boostMaxSpeed * 1.2;
}
var currentMaxSpeed = self.isSprinting ? sprintSpeed : baseSpeed;
var acceleration = self.isSprinting ? 2.2 : 1.5;
self.velocityX = Math.max(self.velocityX - acceleration, -currentMaxSpeed);
};
self.moveRight = function () {
var baseSpeed = self.normalMaxSpeed;
var sprintSpeed = self.sprintMaxSpeed;
if (self.speedBoostActive) {
baseSpeed = self.boostMaxSpeed;
sprintSpeed = self.boostMaxSpeed * 1.2;
}
var currentMaxSpeed = self.isSprinting ? sprintSpeed : baseSpeed;
var acceleration = self.isSprinting ? 2.2 : 1.5;
self.velocityX = Math.min(self.velocityX + acceleration, currentMaxSpeed);
};
self.dash = function (direction) {
var currentTime = Date.now();
if (currentTime - self.lastDashTime >= self.dashCooldown && !self.isDashing) {
self.isDashing = true;
self.dashTimeRemaining = self.dashDuration;
self.lastDashTime = currentTime;
// Apply dash velocity
self.velocityX = self.dashPower * direction;
// Visual dash effect with tween
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Flash effect during dash
tween(self, {
alpha: 0.7
}, {
duration: self.dashDuration / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: self.dashDuration / 2,
easing: tween.easeInOut
});
}
});
}
};
self.startSprint = function () {
self.isSprinting = true;
// Visual sprint effect with tween
tween(self, {
tint: 0x87CEEB
}, {
duration: 200,
easing: tween.easeOut
});
};
self.stopSprint = function () {
self.isSprinting = false;
// Remove sprint visual effect
tween(self, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
};
self.activateSpeedBoost = function () {
if (!self.speedBoostActive) {
self.speedBoostActive = true;
self.speedBoostStartTime = Date.now();
// Visual speed boost effect - bright green tint
tween(self, {
tint: 0x00ff00
}, {
duration: 300,
easing: tween.easeOut
});
}
};
self.deactivateSpeedBoost = function () {
if (self.speedBoostActive) {
self.speedBoostActive = false;
// Remove speed boost visual effect
tween(self, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
}
};
return self;
});
var SpeedBoostPlatform = Container.expand(function () {
var self = Container.call(this);
var platformBody = self.attachAsset('speedBoostPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Turret = Container.expand(function () {
var self = Container.call(this);
var turretBody = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 1.0
});
self.shootCooldown = 3000; // 3 seconds
self.lastShotTime = 0;
self.detectionRange = 500;
self.update = function () {
// Check if player is in range and shoot
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
var currentTime = Date.now();
if (distanceToPlayer < self.detectionRange && currentTime - self.lastShotTime >= self.shootCooldown) {
self.shoot();
self.lastShotTime = currentTime;
}
};
self.shoot = function () {
// Create homing missile
var missile = game.addChild(new HomingMissile());
missile.x = self.x;
missile.y = self.y - 40;
// Initial velocity toward player
var deltaX = player.x - missile.x;
var deltaY = player.y - missile.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var dirX = deltaX / distance;
var dirY = deltaY / distance;
missile.velocityX = dirX * 3;
missile.velocityY = dirY * 3;
homingMissiles.push(missile);
// Visual feedback - flash red briefly
tween(self, {
tint: 0xff0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
tint: 0xFFFFFF
}, {
duration: 150,
easing: tween.easeIn
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var player;
var enemies = [];
var platforms = [];
var junkPiles = [];
var drones = [];
var droneBullets = [];
var turrets = [];
var homingMissiles = [];
var speedBoostPlatforms = [];
var goal;
var camera;
var groundLevel = 2600;
var levelWidth = 4000;
var gameWon = false;
// Create camera object for following player
camera = {
x: 0,
y: 0,
targetX: 0,
targetY: 0,
smoothing: 0.1
};
// Create player
player = game.addChild(new Player());
player.x = 200;
player.y = groundLevel;
// Create platforms
var platformPositions = [{
x: 500,
y: 2400
}, {
x: 800,
y: 2200
}, {
x: 1200,
y: 2300
}, {
x: 1600,
y: 2100
}, {
x: 2000,
y: 2000
}, {
x: 2400,
y: 2200
}, {
x: 2800,
y: 2400
}, {
x: 3200,
y: 2300
}, {
x: 3600,
y: 2500
}];
for (var i = 0; i < platformPositions.length; i++) {
var platform = game.addChild(new Platform());
platform.x = platformPositions[i].x;
platform.y = platformPositions[i].y;
platforms.push(platform);
}
// Create enemies
var enemyPositions = [{
x: 600,
y: groundLevel
}, {
x: 1000,
y: 2200
}, {
x: 1400,
y: groundLevel
}, {
x: 1800,
y: 2000
}, {
x: 2200,
y: groundLevel
}, {
x: 2600,
y: 2200
}, {
x: 3000,
y: groundLevel
}, {
x: 3400,
y: 2300
}];
for (var i = 0; i < enemyPositions.length; i++) {
var enemy = game.addChild(new Enemy());
enemy.x = enemyPositions[i].x;
enemy.y = enemyPositions[i].y;
enemy.startX = enemy.x;
enemies.push(enemy);
}
// Create junk piles for decoration
var junkPositions = [{
x: 300,
y: groundLevel
}, {
x: 700,
y: groundLevel
}, {
x: 1100,
y: groundLevel
}, {
x: 1500,
y: groundLevel
}, {
x: 1900,
y: groundLevel
}, {
x: 2300,
y: groundLevel
}, {
x: 2700,
y: groundLevel
}, {
x: 3100,
y: groundLevel
}, {
x: 3500,
y: groundLevel
}];
for (var i = 0; i < junkPositions.length; i++) {
var junk = game.addChild(new JunkPile());
junk.x = junkPositions[i].x;
junk.y = junkPositions[i].y;
junkPiles.push(junk);
}
// Create drones
var dronePositions = [{
x: 800,
y: groundLevel - 150
}, {
x: 1400,
y: groundLevel - 200
}, {
x: 2200,
y: groundLevel - 180
}, {
x: 2900,
y: groundLevel - 160
}, {
x: 3500,
y: groundLevel - 170
}];
for (var i = 0; i < dronePositions.length; i++) {
var drone = game.addChild(new Drone());
drone.x = dronePositions[i].x;
drone.y = dronePositions[i].y;
drone.startX = drone.x;
drones.push(drone);
}
// Create turrets
var turretPositions = [{
x: 1000,
y: groundLevel
}, {
x: 1800,
y: 2000
}, {
x: 2600,
y: groundLevel
}, {
x: 3200,
y: 2300
}];
for (var i = 0; i < turretPositions.length; i++) {
var turret = game.addChild(new Turret());
turret.x = turretPositions[i].x;
turret.y = turretPositions[i].y;
turrets.push(turret);
}
// Create speed boost platforms
var speedBoostPositions = [{
x: 900,
y: 2150
}, {
x: 1700,
y: 1950
}, {
x: 2500,
y: 2050
}, {
x: 3300,
y: 2250
}];
for (var i = 0; i < speedBoostPositions.length; i++) {
var speedBoostPlatform = game.addChild(new SpeedBoostPlatform());
speedBoostPlatform.x = speedBoostPositions[i].x;
speedBoostPlatform.y = speedBoostPositions[i].y;
speedBoostPlatforms.push(speedBoostPlatform);
}
// Create goal
goal = game.addChild(LK.getAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
}));
goal.x = levelWidth - 200;
goal.y = groundLevel - 50;
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
isDragging = true;
// Jump on tap
player.jump();
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = x - touchStartX;
var deltaY = Math.abs(y - touchStartY);
// Check for dash gesture (fast horizontal swipe)
if (Math.abs(deltaX) > 100 && deltaY < 50) {
var dashDirection = deltaX > 0 ? 1 : -1;
player.dash(dashDirection);
isDragging = false; // End drag to prevent continuous movement
}
// Check for sprint gesture (long horizontal drag)
else if (Math.abs(deltaX) > 50) {
if (!player.isSprinting) {
player.startSprint();
}
if (deltaX < -20) {
player.moveLeft();
} else if (deltaX > 20) {
player.moveRight();
}
}
// Regular movement for smaller gestures
else if (deltaX < -20) {
player.moveLeft();
} else if (deltaX > 20) {
player.moveRight();
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
if (player.isSprinting) {
player.stopSprint();
}
};
// Game update loop
game.update = function () {
if (gameWon) return;
// Update camera to follow player
camera.targetX = player.x - 1024;
camera.targetY = player.y - 1366;
camera.x += (camera.targetX - camera.x) * camera.smoothing;
camera.y += (camera.targetY - camera.y) * camera.smoothing;
// Keep camera within level bounds
if (camera.x < 0) camera.x = 0;
if (camera.x > levelWidth - 2048) camera.x = levelWidth - 2048;
if (camera.y < -500) camera.y = -500;
if (camera.y > 0) camera.y = 0;
// Apply camera offset to game
game.x = -camera.x;
game.y = -camera.y;
// Check collision with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (player.intersects(enemy)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
}
// Check collision with drone bullets
for (var i = droneBullets.length - 1; i >= 0; i--) {
var bullet = droneBullets[i];
if (player.intersects(bullet)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
bullet.destroy();
droneBullets.splice(i, 1);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
}
// Check collision with homing missiles
for (var i = homingMissiles.length - 1; i >= 0; i--) {
var missile = homingMissiles[i];
if (player.intersects(missile) && !missile.hasExploded) {
missile.explode();
return;
}
}
// Check collision with speed boost platforms
for (var i = 0; i < speedBoostPlatforms.length; i++) {
var boostPlatform = speedBoostPlatforms[i];
if (player.intersects(boostPlatform)) {
player.activateSpeedBoost();
}
}
// Check if player reached goal
if (player.intersects(goal)) {
gameWon = true;
LK.effects.flashScreen(0x00FF00, 1000);
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
return;
}
// Check if player fell off the level
if (player.y > groundLevel + 500) {
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Drone = Container.expand(function () {
var self = Container.call(this);
var droneBody = self.attachAsset('drone', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.direction = 1;
self.startX = 0;
self.patrolDistance = 250;
self.shootCooldown = 2000; // 2 seconds
self.lastShotTime = 0;
self.detectionRange = 400;
self.hoverHeight = 100; // Height above ground to hover
self.update = function () {
// Patrol movement
self.x += self.speed * self.direction;
if (Math.abs(self.x - self.startX) > self.patrolDistance) {
self.direction *= -1;
}
// Hover at fixed height
var targetY = groundLevel - self.hoverHeight;
if (self.y > targetY) {
self.y -= 2;
} else if (self.y < targetY) {
self.y += 2;
}
// Check if player is in range and shoot
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
var currentTime = Date.now();
if (distanceToPlayer < self.detectionRange && currentTime - self.lastShotTime >= self.shootCooldown) {
self.shoot();
self.lastShotTime = currentTime;
}
// Add floating animation with tween
if (!self.isFloating) {
self.isFloating = true;
self.startFloat();
}
};
self.shoot = function () {
// Calculate direction to player
var deltaX = player.x - self.x;
var deltaY = player.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Normalize direction
var dirX = deltaX / distance;
var dirY = deltaY / distance;
// Create bullet
var bullet = game.addChild(new DroneBullet());
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = dirX * bullet.speed;
bullet.velocityY = dirY * bullet.speed;
droneBullets.push(bullet);
// Play shoot sound
LK.getSound('droneShoot').play();
// Visual feedback - flash red briefly
tween(self, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
self.startFloat = function () {
tween(self, {
y: self.y - 10
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 10
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isFloating = false;
}
});
}
});
};
return self;
});
var DroneBullet = Container.expand(function () {
var self = Container.call(this);
var bulletBody = self.attachAsset('droneBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.lifeTime = 3000; // 3 seconds
self.age = 0;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.age += 16; // Assuming 60fps
// Remove bullet if it's too old or off screen
if (self.age >= self.lifeTime || self.x < -100 || self.x > levelWidth + 100 || self.y < -100 || self.y > groundLevel + 500) {
self.destroy();
for (var i = droneBullets.length - 1; i >= 0; i--) {
if (droneBullets[i] === self) {
droneBullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyBody = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 2;
self.direction = 1;
self.startX = 0;
self.patrolDistance = 300;
self.update = function () {
self.x += self.speed * self.direction;
if (Math.abs(self.x - self.startX) > self.patrolDistance) {
self.direction *= -1;
}
// Ground collision for enemies
if (self.y >= groundLevel) {
self.y = groundLevel;
}
// Platform collision for enemies
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
// Check if enemy is on top of platform
if (self.intersects(platform)) {
var platformLeft = platform.x - 100; // platform width/2
var platformRight = platform.x + 100; // platform width/2
var platformTop = platform.y - 20; // platform height/2
var enemyLeft = self.x - 30; // enemy width/2
var enemyRight = self.x + 30; // enemy width/2
var enemyBottom = self.y;
// Landing on platform
if (enemyBottom > platformTop && enemyBottom < platformTop + 50 && enemyRight > platformLeft && enemyLeft < platformRight) {
self.y = platformTop;
}
}
}
};
return self;
});
var HomingMissile = Container.expand(function () {
var self = Container.call(this);
var missileBody = self.attachAsset('homingMissile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 6;
self.homingStrength = 0.15;
self.lifeTime = 5000; // 5 seconds
self.age = 0;
self.hasExploded = false;
self.update = function () {
// Calculate direction to player
var deltaX = player.x - self.x;
var deltaY = player.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
// Normalize direction
var dirX = deltaX / distance;
var dirY = deltaY / distance;
// Apply homing
self.velocityX += dirX * self.homingStrength;
self.velocityY += dirY * self.homingStrength;
// Limit speed
var currentSpeed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (currentSpeed > self.speed) {
self.velocityX = self.velocityX / currentSpeed * self.speed;
self.velocityY = self.velocityY / currentSpeed * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
self.age += 16; // Assuming 60fps
// Check ground/platform collision for explosion
if (self.y >= groundLevel && !self.hasExploded) {
self.explode();
}
// Check platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && !self.hasExploded) {
self.explode();
break;
}
}
// Remove missile if it's too old or off screen
if (self.age >= self.lifeTime || self.x < -200 || self.x > levelWidth + 200 || self.y > groundLevel + 500) {
self.destroy();
for (var j = homingMissiles.length - 1; j >= 0; j--) {
if (homingMissiles[j] === self) {
homingMissiles.splice(j, 1);
break;
}
}
}
};
self.explode = function () {
if (self.hasExploded) return;
self.hasExploded = true;
// Create explosion visual
var explosion = game.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.8
}));
// Explosion animation with tween
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Damage player if close enough
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
if (distanceToPlayer < 100) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
// Remove missile from game
self.destroy();
for (var j = homingMissiles.length - 1; j >= 0; j--) {
if (homingMissiles[j] === self) {
homingMissiles.splice(j, 1);
break;
}
}
};
return self;
});
var JunkPile = Container.expand(function () {
var self = Container.call(this);
var junkBody = self.attachAsset('junkPile', {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformBody = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerBody = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
var leftEye = self.attachAsset('playerEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
y: -50
});
var rightEye = self.attachAsset('playerEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 20,
y: -50
});
var leftPupil = self.attachAsset('playerPupil', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
y: -50
});
var rightPupil = self.attachAsset('playerPupil', {
anchorX: 0.5,
anchorY: 0.5,
x: 20,
y: -50
});
self.velocityX = 0;
self.velocityY = 0;
self.onGround = false;
self.jumpCount = 0;
self.maxJumps = 2;
self.jumpPower = -15;
self.gravity = 0.8;
self.maxSpeed = 8;
self.friction = 0.85;
self.dashPower = 20;
self.dashDuration = 200;
self.dashCooldown = 1000;
self.isDashing = false;
self.dashTimeRemaining = 0;
self.lastDashTime = 0;
self.isSprinting = false;
self.sprintMultiplier = 1.8;
self.normalMaxSpeed = 8;
self.sprintMaxSpeed = 14;
self.speedBoostActive = false;
self.speedBoostStartTime = 0;
self.speedBoostDuration = 20000; // 20 seconds
self.boostMaxSpeed = 18;
self.update = function () {
// Handle dash mechanics
if (self.isDashing && self.dashTimeRemaining > 0) {
self.dashTimeRemaining -= 16; // Assuming 60fps, ~16ms per frame
if (self.dashTimeRemaining <= 0) {
self.isDashing = false;
}
}
// Handle speed boost timer
if (self.speedBoostActive) {
var currentTime = Date.now();
if (currentTime - self.speedBoostStartTime >= self.speedBoostDuration) {
self.deactivateSpeedBoost();
}
}
// Apply gravity (reduced during dash)
if (!self.isDashing) {
self.velocityY += self.gravity;
} else {
self.velocityY += self.gravity * 0.3; // Reduced gravity during dash
}
// Apply friction
self.velocityX *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel) {
self.y = groundLevel;
self.velocityY = 0;
self.onGround = true;
self.jumpCount = 0;
} else {
self.onGround = false;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
// Check if player is intersecting with platform
if (self.intersects(platform)) {
// Calculate platform boundaries
var platformLeft = platform.x - 100; // platform width/2
var platformRight = platform.x + 100; // platform width/2
var platformTop = platform.y - 20; // platform height/2
var platformBottom = platform.y + 20; // platform height/2
var playerLeft = self.x - 40; // player width/2
var playerRight = self.x + 40; // player width/2
var playerTop = self.y - 80; // player height
var playerBottom = self.y;
// Landing on top of platform
if (self.velocityY > 0 && playerBottom > platformTop && playerTop < platformTop && playerRight > platformLeft && playerLeft < platformRight) {
self.y = platformTop;
self.velocityY = 0;
self.onGround = true;
self.jumpCount = 0;
}
// Hitting platform from below
else if (self.velocityY < 0 && playerTop < platformBottom && playerBottom > platformBottom && playerRight > platformLeft && playerLeft < platformRight) {
self.y = platformBottom + 80;
self.velocityY = 0;
}
// Hitting platform from left
else if (self.velocityX > 0 && playerRight > platformLeft && playerLeft < platformLeft && playerBottom > platformTop && playerTop < platformBottom) {
self.x = platformLeft - 40;
self.velocityX = 0;
}
// Hitting platform from right
else if (self.velocityX < 0 && playerLeft < platformRight && playerRight > platformRight && playerBottom > platformTop && playerTop < platformBottom) {
self.x = platformRight + 40;
self.velocityX = 0;
}
}
}
// Boundary checking
if (self.x < 40) {
self.x = 40;
}
if (self.x > levelWidth - 40) {
self.x = levelWidth - 40;
}
};
self.jump = function () {
if (self.jumpCount < self.maxJumps) {
self.velocityY = self.jumpPower;
self.jumpCount++;
self.onGround = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
var baseSpeed = self.normalMaxSpeed;
var sprintSpeed = self.sprintMaxSpeed;
if (self.speedBoostActive) {
baseSpeed = self.boostMaxSpeed;
sprintSpeed = self.boostMaxSpeed * 1.2;
}
var currentMaxSpeed = self.isSprinting ? sprintSpeed : baseSpeed;
var acceleration = self.isSprinting ? 2.2 : 1.5;
self.velocityX = Math.max(self.velocityX - acceleration, -currentMaxSpeed);
};
self.moveRight = function () {
var baseSpeed = self.normalMaxSpeed;
var sprintSpeed = self.sprintMaxSpeed;
if (self.speedBoostActive) {
baseSpeed = self.boostMaxSpeed;
sprintSpeed = self.boostMaxSpeed * 1.2;
}
var currentMaxSpeed = self.isSprinting ? sprintSpeed : baseSpeed;
var acceleration = self.isSprinting ? 2.2 : 1.5;
self.velocityX = Math.min(self.velocityX + acceleration, currentMaxSpeed);
};
self.dash = function (direction) {
var currentTime = Date.now();
if (currentTime - self.lastDashTime >= self.dashCooldown && !self.isDashing) {
self.isDashing = true;
self.dashTimeRemaining = self.dashDuration;
self.lastDashTime = currentTime;
// Apply dash velocity
self.velocityX = self.dashPower * direction;
// Visual dash effect with tween
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Flash effect during dash
tween(self, {
alpha: 0.7
}, {
duration: self.dashDuration / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: self.dashDuration / 2,
easing: tween.easeInOut
});
}
});
}
};
self.startSprint = function () {
self.isSprinting = true;
// Visual sprint effect with tween
tween(self, {
tint: 0x87CEEB
}, {
duration: 200,
easing: tween.easeOut
});
};
self.stopSprint = function () {
self.isSprinting = false;
// Remove sprint visual effect
tween(self, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
};
self.activateSpeedBoost = function () {
if (!self.speedBoostActive) {
self.speedBoostActive = true;
self.speedBoostStartTime = Date.now();
// Visual speed boost effect - bright green tint
tween(self, {
tint: 0x00ff00
}, {
duration: 300,
easing: tween.easeOut
});
}
};
self.deactivateSpeedBoost = function () {
if (self.speedBoostActive) {
self.speedBoostActive = false;
// Remove speed boost visual effect
tween(self, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
}
};
return self;
});
var SpeedBoostPlatform = Container.expand(function () {
var self = Container.call(this);
var platformBody = self.attachAsset('speedBoostPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Turret = Container.expand(function () {
var self = Container.call(this);
var turretBody = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 1.0
});
self.shootCooldown = 3000; // 3 seconds
self.lastShotTime = 0;
self.detectionRange = 500;
self.update = function () {
// Check if player is in range and shoot
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
var currentTime = Date.now();
if (distanceToPlayer < self.detectionRange && currentTime - self.lastShotTime >= self.shootCooldown) {
self.shoot();
self.lastShotTime = currentTime;
}
};
self.shoot = function () {
// Create homing missile
var missile = game.addChild(new HomingMissile());
missile.x = self.x;
missile.y = self.y - 40;
// Initial velocity toward player
var deltaX = player.x - missile.x;
var deltaY = player.y - missile.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var dirX = deltaX / distance;
var dirY = deltaY / distance;
missile.velocityX = dirX * 3;
missile.velocityY = dirY * 3;
homingMissiles.push(missile);
// Visual feedback - flash red briefly
tween(self, {
tint: 0xff0000
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
tint: 0xFFFFFF
}, {
duration: 150,
easing: tween.easeIn
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var player;
var enemies = [];
var platforms = [];
var junkPiles = [];
var drones = [];
var droneBullets = [];
var turrets = [];
var homingMissiles = [];
var speedBoostPlatforms = [];
var goal;
var camera;
var groundLevel = 2600;
var levelWidth = 4000;
var gameWon = false;
// Create camera object for following player
camera = {
x: 0,
y: 0,
targetX: 0,
targetY: 0,
smoothing: 0.1
};
// Create player
player = game.addChild(new Player());
player.x = 200;
player.y = groundLevel;
// Create platforms
var platformPositions = [{
x: 500,
y: 2400
}, {
x: 800,
y: 2200
}, {
x: 1200,
y: 2300
}, {
x: 1600,
y: 2100
}, {
x: 2000,
y: 2000
}, {
x: 2400,
y: 2200
}, {
x: 2800,
y: 2400
}, {
x: 3200,
y: 2300
}, {
x: 3600,
y: 2500
}];
for (var i = 0; i < platformPositions.length; i++) {
var platform = game.addChild(new Platform());
platform.x = platformPositions[i].x;
platform.y = platformPositions[i].y;
platforms.push(platform);
}
// Create enemies
var enemyPositions = [{
x: 600,
y: groundLevel
}, {
x: 1000,
y: 2200
}, {
x: 1400,
y: groundLevel
}, {
x: 1800,
y: 2000
}, {
x: 2200,
y: groundLevel
}, {
x: 2600,
y: 2200
}, {
x: 3000,
y: groundLevel
}, {
x: 3400,
y: 2300
}];
for (var i = 0; i < enemyPositions.length; i++) {
var enemy = game.addChild(new Enemy());
enemy.x = enemyPositions[i].x;
enemy.y = enemyPositions[i].y;
enemy.startX = enemy.x;
enemies.push(enemy);
}
// Create junk piles for decoration
var junkPositions = [{
x: 300,
y: groundLevel
}, {
x: 700,
y: groundLevel
}, {
x: 1100,
y: groundLevel
}, {
x: 1500,
y: groundLevel
}, {
x: 1900,
y: groundLevel
}, {
x: 2300,
y: groundLevel
}, {
x: 2700,
y: groundLevel
}, {
x: 3100,
y: groundLevel
}, {
x: 3500,
y: groundLevel
}];
for (var i = 0; i < junkPositions.length; i++) {
var junk = game.addChild(new JunkPile());
junk.x = junkPositions[i].x;
junk.y = junkPositions[i].y;
junkPiles.push(junk);
}
// Create drones
var dronePositions = [{
x: 800,
y: groundLevel - 150
}, {
x: 1400,
y: groundLevel - 200
}, {
x: 2200,
y: groundLevel - 180
}, {
x: 2900,
y: groundLevel - 160
}, {
x: 3500,
y: groundLevel - 170
}];
for (var i = 0; i < dronePositions.length; i++) {
var drone = game.addChild(new Drone());
drone.x = dronePositions[i].x;
drone.y = dronePositions[i].y;
drone.startX = drone.x;
drones.push(drone);
}
// Create turrets
var turretPositions = [{
x: 1000,
y: groundLevel
}, {
x: 1800,
y: 2000
}, {
x: 2600,
y: groundLevel
}, {
x: 3200,
y: 2300
}];
for (var i = 0; i < turretPositions.length; i++) {
var turret = game.addChild(new Turret());
turret.x = turretPositions[i].x;
turret.y = turretPositions[i].y;
turrets.push(turret);
}
// Create speed boost platforms
var speedBoostPositions = [{
x: 900,
y: 2150
}, {
x: 1700,
y: 1950
}, {
x: 2500,
y: 2050
}, {
x: 3300,
y: 2250
}];
for (var i = 0; i < speedBoostPositions.length; i++) {
var speedBoostPlatform = game.addChild(new SpeedBoostPlatform());
speedBoostPlatform.x = speedBoostPositions[i].x;
speedBoostPlatform.y = speedBoostPositions[i].y;
speedBoostPlatforms.push(speedBoostPlatform);
}
// Create goal
goal = game.addChild(LK.getAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
}));
goal.x = levelWidth - 200;
goal.y = groundLevel - 50;
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
isDragging = true;
// Jump on tap
player.jump();
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = x - touchStartX;
var deltaY = Math.abs(y - touchStartY);
// Check for dash gesture (fast horizontal swipe)
if (Math.abs(deltaX) > 100 && deltaY < 50) {
var dashDirection = deltaX > 0 ? 1 : -1;
player.dash(dashDirection);
isDragging = false; // End drag to prevent continuous movement
}
// Check for sprint gesture (long horizontal drag)
else if (Math.abs(deltaX) > 50) {
if (!player.isSprinting) {
player.startSprint();
}
if (deltaX < -20) {
player.moveLeft();
} else if (deltaX > 20) {
player.moveRight();
}
}
// Regular movement for smaller gestures
else if (deltaX < -20) {
player.moveLeft();
} else if (deltaX > 20) {
player.moveRight();
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
if (player.isSprinting) {
player.stopSprint();
}
};
// Game update loop
game.update = function () {
if (gameWon) return;
// Update camera to follow player
camera.targetX = player.x - 1024;
camera.targetY = player.y - 1366;
camera.x += (camera.targetX - camera.x) * camera.smoothing;
camera.y += (camera.targetY - camera.y) * camera.smoothing;
// Keep camera within level bounds
if (camera.x < 0) camera.x = 0;
if (camera.x > levelWidth - 2048) camera.x = levelWidth - 2048;
if (camera.y < -500) camera.y = -500;
if (camera.y > 0) camera.y = 0;
// Apply camera offset to game
game.x = -camera.x;
game.y = -camera.y;
// Check collision with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (player.intersects(enemy)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
}
// Check collision with drone bullets
for (var i = droneBullets.length - 1; i >= 0; i--) {
var bullet = droneBullets[i];
if (player.intersects(bullet)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 500);
bullet.destroy();
droneBullets.splice(i, 1);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
}
// Check collision with homing missiles
for (var i = homingMissiles.length - 1; i >= 0; i--) {
var missile = homingMissiles[i];
if (player.intersects(missile) && !missile.hasExploded) {
missile.explode();
return;
}
}
// Check collision with speed boost platforms
for (var i = 0; i < speedBoostPlatforms.length; i++) {
var boostPlatform = speedBoostPlatforms[i];
if (player.intersects(boostPlatform)) {
player.activateSpeedBoost();
}
}
// Check if player reached goal
if (player.intersects(goal)) {
gameWon = true;
LK.effects.flashScreen(0x00FF00, 1000);
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
return;
}
// Check if player fell off the level
if (player.y > groundLevel + 500) {
LK.effects.flashScreen(0xFF0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
};