/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 1;
self.direction = 1;
self.moveRange = 200;
self.startX = 0;
self.active = true;
self.lastWasHit = false;
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
self.active = false;
LK.getSound('alienDestroy').play();
// Flash effect before destruction
tween(alienGraphics, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
} else {
LK.getSound('alienHit').play();
// Flash red when hit
LK.effects.flashObject(self, 0xff0000, 200);
}
};
self.update = function () {
if (!self.active) return;
// Move alien horizontally
self.x += self.direction * self.speed;
// Reverse direction when reaching movement limits
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.direction *= -1;
}
// Keep alien within screen bounds
if (self.x < 40) {
self.x = 40;
self.direction = 1;
}
if (self.x > 2008) {
self.x = 2008;
self.direction = -1;
}
};
return self;
});
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.05;
self.pulseSpeed = 0.08;
self.lastWasIntersecting = false;
self.update = function () {
// Rotate bomb slowly for menacing effect
bombGraphics.rotation += self.rotationSpeed;
// Pulsing scale effect to make it more noticeable
var pulseScale = 1 + Math.sin(LK.ticks * self.pulseSpeed) * 0.2;
bombGraphics.scaleX = pulseScale;
bombGraphics.scaleY = pulseScale;
// Red tinting that pulses to indicate danger
var redIntensity = 0.5 + Math.sin(LK.ticks * self.pulseSpeed * 2) * 0.5;
bombGraphics.tint = 0xff << 16 | Math.floor((1 - redIntensity) * 255) << 8 | Math.floor((1 - redIntensity) * 255);
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.direction = {
x: 0,
y: -1
}; // Default upward direction
self.active = true;
self.update = function () {
// Find nearest alien to auto-target
var nearestAlien = null;
var nearestDistance = Infinity;
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
var distance = Math.sqrt(Math.pow(self.x - alien.x, 2) + Math.pow(self.y - alien.y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestAlien = alien;
}
}
}
// If there's an alien to target, automatically steer towards it
if (nearestAlien) {
var targetX = nearestAlien.x - self.x;
var targetY = nearestAlien.y - self.y;
var targetDistance = Math.sqrt(targetX * targetX + targetY * targetY);
if (targetDistance > 0) {
// Normalize direction towards target
self.direction.x = targetX / targetDistance;
self.direction.y = targetY / targetDistance;
}
}
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove bullet if it goes off screen
if (self.y < cameraY - 200 || self.y > cameraY + 2732 + 200 || self.x < -100 || self.x > 2148) {
self.active = false;
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.1;
self.update = function () {
// Rotate coin for visual appeal
coinGraphics.rotation += self.rotationSpeed;
// Float up and down slightly
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var Dude = Container.expand(function () {
var self = Container.call(this);
var dudeGraphics = self.attachAsset('dude', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.velocityX = 0;
self.isJumping = false;
self.isOnPlatform = false;
self.jumpPower = 35;
self.gravity = 0.8;
self.maxFallSpeed = 15;
self.horizontalSpeed = 12;
self.airResistance = 0.85;
self.invincible = false;
self.invincibleTimer = 0;
self.health = 4;
self.maxHealth = 4;
self.jump = function () {
if (self.isOnPlatform) {
self.velocityY = -self.jumpPower;
self.isJumping = true;
self.isOnPlatform = false;
LK.getSound('jump').play();
}
};
self.update = function () {
// Auto jump when on platform (only if not flying)
if (self.isOnPlatform && !self.canFly) {
self.jump();
}
// Apply gravity (reduced if flying)
if (self.canFly) {
self.velocityY += self.gravity * 0.5; // Reduced gravity for flying
} else {
self.velocityY += self.gravity;
}
if (self.velocityY > self.maxFallSpeed) {
self.velocityY = self.maxFallSpeed;
}
// Update position
self.y += self.velocityY;
self.x += self.velocityX;
// Apply continuous horizontal movement while pressed
if (isPressed && pressedSide !== 0) {
self.velocityX += pressedSide * self.horizontalSpeed * 0.3;
}
// Apply air resistance to horizontal movement
self.velocityX *= self.airResistance;
// Handle invincibility timer
if (self.invincible) {
self.invincibleTimer--;
if (self.invincibleTimer <= 0) {
self.invincible = false;
dudeGraphics.alpha = 1;
} else {
dudeGraphics.alpha = Math.sin(self.invincibleTimer * 0.3) * 0.5 + 0.5;
}
}
// Allow infinite horizontal movement - no bounds restriction
// Character can now move infinitely left and right
// Check if fallen off screen
if (self.y > cameraY + 2732 + 200) {
// Reset gold to zero when player falls off screen
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
};
self.takeDamage = function () {
if (self.invincible) return;
self.health--;
self.invincible = true;
self.invincibleTimer = 180; // 3 seconds of invincibility
LK.effects.flashObject(self, 0xff0000, 500);
updateHealthDisplay();
if (self.health <= 0) {
// Reset gold to zero when player dies
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
};
self.shoot = function (direction) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
// Set bullet direction based on parameter
if (direction === 'up') {
bullet.direction = {
x: 0,
y: -1
};
bullet.y = self.y - 30;
} else if (direction === 'down') {
bullet.direction = {
x: 0,
y: 1
};
bullet.y = self.y + 30;
} else if (direction === 'left') {
bullet.direction = {
x: -1,
y: 0
};
bullet.x = self.x - 30;
} else if (direction === 'right') {
bullet.direction = {
x: 1,
y: 0
};
bullet.x = self.x + 30;
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
return self;
});
var FlashBomb = Container.expand(function () {
var self = Container.call(this);
var flashBombGraphics = self.attachAsset('flashBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.05;
self.pulseSpeed = 0.08;
self.lastWasIntersecting = false;
// Make flash bomb visually different - white tint
flashBombGraphics.tint = 0xffffff;
self.update = function () {
// Rotate flash bomb slowly
flashBombGraphics.rotation += self.rotationSpeed;
// Pulsing scale effect
var pulseScale = 1 + Math.sin(LK.ticks * self.pulseSpeed) * 0.2;
flashBombGraphics.scaleX = pulseScale;
flashBombGraphics.scaleY = pulseScale;
// White tinting that pulses to indicate flash effect
var whiteIntensity = 0.7 + Math.sin(LK.ticks * self.pulseSpeed * 2) * 0.3;
flashBombGraphics.tint = Math.floor(whiteIntensity * 255) << 16 | Math.floor(whiteIntensity * 255) << 8 | Math.floor(whiteIntensity * 255);
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'normal';
self.landed = false;
self.disappearing = false;
self.moveDirection = 1;
self.moveRange = 300;
self.startX = 0;
var platformGraphics;
if (self.type === 'moving') {
platformGraphics = self.attachAsset('movingPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.type === 'disappearing') {
platformGraphics = self.attachAsset('disappearingPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.type === 'powerup') {
platformGraphics = self.attachAsset('powerUpPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.update = function () {
// Moving platform behavior
if (self.type === 'moving') {
self.x += self.moveDirection * 2;
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.moveDirection *= -1;
}
}
// Disappearing platform behavior
if (self.type === 'disappearing' && self.landed && !self.disappearing) {
self.disappearing = true;
tween(platformGraphics, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
self.active = false;
}
});
}
};
return self;
});
var Saw = Container.expand(function () {
var self = Container.call(this);
var sawGraphics = self.attachAsset('saw', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.3;
self.lastWasIntersecting = false;
self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
self.moveSpeed = 2;
self.moveRange = 150;
self.startX = 0;
self.update = function () {
// Move saw horizontally
self.x += self.moveDirection * self.moveSpeed;
// Reverse direction when reaching movement limits
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.moveDirection *= -1;
}
// Keep saw within screen bounds
if (self.x < 60) {
self.x = 60;
self.moveDirection = 1;
}
if (self.x > 1988) {
self.x = 1988;
self.moveDirection = -1;
}
};
return self;
});
var SpecialItem = Container.expand(function (itemType) {
var self = Container.call(this);
self.itemType = itemType || 1;
var assetId = 'specialItem' + self.itemType;
var itemGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Make special items larger
itemGraphics.scaleX = 2;
itemGraphics.scaleY = 2;
self.collected = false;
self.active = true;
self.rotationSpeed = 0.15;
self.floatOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Float up and down with more pronounced animation
self.y += Math.sin(LK.ticks * 0.06 + self.floatOffset) * 1.2;
// Pulsing scale effect
var pulseScale = 2 + Math.sin(LK.ticks * 0.08) * 0.3;
itemGraphics.scaleX = pulseScale;
itemGraphics.scaleY = pulseScale;
};
return self;
});
var Trampoline = Container.expand(function () {
var self = Container.call(this);
var trampolineGraphics = self.attachAsset('trampoline', {
anchorX: 0.5,
anchorY: 0.5
});
self.bounced = false;
self.active = true;
self.bounce = function () {
// Animate trampoline compression and expansion
tween(trampolineGraphics, {
scaleY: 0.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(trampolineGraphics, {
scaleY: 1.2
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(trampolineGraphics, {
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
var dude = game.addChild(new Dude());
var platforms = [];
var coins = [];
var bullets = [];
var trampolines = [];
var cameraY = 0;
var highestY = 2400;
var lastPlatformY = 2400;
var platformSpacing = 200;
var coinsCollected = 0;
var gold = storage.gold || 0;
var totalHeight = storage.totalHeight || 0;
var lastShootTime = 0;
var shootCooldown = 20; // 20 ticks between shots
var aliens = [];
var aliensKilled = 0;
var saws = [];
var specialItems = [];
var specialItemsCollected = 0;
var totalSpecialItems = 4;
var zombiesKilled = 0;
var bombs = [];
var flashBombs = [];
// Create score display
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create height display
var heightTxt = new Text2('Height: 0m', {
size: 40,
fill: 0xFFFFFF
});
heightTxt.anchor.set(1, 0);
heightTxt.x = -20;
heightTxt.y = 20;
LK.gui.topRight.addChild(heightTxt);
// Create coin counter display
var coinTxt = new Text2('Coins: 0', {
size: 40,
fill: 0xffd700
});
coinTxt.anchor.set(0, 0);
coinTxt.x = 20;
coinTxt.y = 20;
LK.gui.topLeft.addChild(coinTxt);
// Create gold display
var goldTxt = new Text2('Gold: ' + gold, {
size: 40,
fill: 0xffd700
});
goldTxt.anchor.set(0, 0);
goldTxt.x = 20;
goldTxt.y = 120;
LK.gui.topLeft.addChild(goldTxt);
// Create special items display
var specialItemsTxt = new Text2('Special Items: 0/' + totalSpecialItems, {
size: 40,
fill: 0xff0000
});
specialItemsTxt.anchor.set(0, 0);
specialItemsTxt.x = 20;
specialItemsTxt.y = 170;
LK.gui.topLeft.addChild(specialItemsTxt);
// Create health display
var hearts = [];
function createHealthDisplay() {
for (var i = 0; i < dude.maxHealth; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 20 + i * 50;
heart.y = 80;
hearts.push(heart);
LK.gui.topLeft.addChild(heart);
}
}
function updateHealthDisplay() {
for (var i = 0; i < hearts.length; i++) {
hearts[i].alpha = i < dude.health ? 1 : 0.3;
}
}
// Initialize dude position
dude.x = 1024;
dude.y = 2400;
// Initialize health display
createHealthDisplay();
updateHealthDisplay();
// Create fire buttons for 4 directions
var fireButtonUp = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonUp.x = -120;
fireButtonUp.y = -300;
LK.gui.bottomRight.addChild(fireButtonUp);
var fireButtonDown = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonDown.x = -120;
fireButtonDown.y = -100;
fireButtonDown.rotation = Math.PI; // Rotate 180 degrees
LK.gui.bottomRight.addChild(fireButtonDown);
var fireButtonLeft = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonLeft.x = -220;
fireButtonLeft.y = -200;
fireButtonLeft.rotation = Math.PI * 1.5; // Rotate 270 degrees
LK.gui.bottomRight.addChild(fireButtonLeft);
var fireButtonRight = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonRight.x = -20;
fireButtonRight.y = -200;
fireButtonRight.rotation = Math.PI * 0.5; // Rotate 90 degrees
LK.gui.bottomRight.addChild(fireButtonRight);
// Create initial platforms
function createPlatform(x, y, type) {
var platform = new Platform(type);
platform.x = x;
platform.y = y;
platform.startX = x;
platform.active = true;
platforms.push(platform);
game.addChild(platform);
return platform;
}
// Create starting platform
createPlatform(1024, 2450, 'normal');
// Generate initial platforms
for (var i = 0; i < 20; i++) {
generateNextPlatform();
}
function generateNextPlatform() {
lastPlatformY -= platformSpacing + Math.random() * 100;
var x = 200 + Math.random() * 1648;
// Determine platform type based on height
var type = 'normal';
var height = Math.abs(lastPlatformY - 2400);
if (height > 1000) {
var rand = Math.random();
var powerupChance = spaceThemeActivated ? 0.8 : 0.6; // Increased from 0.6 to 0.8 in space theme
if (rand < 0.3) {
type = 'moving';
} else if (rand < 0.5) {
type = 'disappearing';
} else if (rand < powerupChance) {
type = 'powerup';
}
}
createPlatform(x, lastPlatformY, type);
// Generate coins near platforms with increased rate after 1255m
var currentGameHeight = Math.abs(lastPlatformY - 2400);
var coinChance = currentGameHeight > 1255 ? 0.98 : 0.85; // 98% chance after 1255m, 85% before
if (Math.random() < coinChance) {
generateCoin(x + (Math.random() - 0.5) * 200, lastPlatformY - 80);
}
// Generate trampolines more frequently (25% chance, 40% in space theme)
var trampolineChance = spaceThemeActivated ? 0.40 : 0.25;
if (Math.random() < trampolineChance) {
createTrampoline(x, lastPlatformY - 100);
}
// Generate aliens with 15% chance
var alienChance = 0.15; // 15% chance
if (Math.random() < alienChance) {
createAlien(x + (Math.random() - 0.5) * 300, lastPlatformY - 150);
}
// Kittens removed from game
// Generate saws more frequently (25% chance)
var baseSawChance = 0.25; // 25% chance (increased from 10%)
var sawChance = baseSawChance * sawSpawnMultiplier;
if (Math.random() < sawChance) {
createSaw(x + (Math.random() - 0.5) * 300, lastPlatformY - 100);
}
// Generate bombs with 5% chance after reaching 500m height
var currentGameHeight = Math.abs(lastPlatformY - 2400);
if (currentGameHeight > 500 && Math.random() < 0.05) {
createBomb(x + (Math.random() - 0.5) * 300, lastPlatformY - 120);
}
// Generate flash bombs more frequently (20% chance after reaching 800m height)
if (currentGameHeight > 800 && Math.random() < 0.20) {
createFlashBomb(x + (Math.random() - 0.5) * 300, lastPlatformY - 120);
}
// Generate special items frequently (10% chance) and only if we haven't collected all yet
if (Math.random() < 0.10 && specialItemsCollected < totalSpecialItems) {
var nextItemType = specialItemsCollected + 1;
createSpecialItem(x + (Math.random() - 0.5) * 200, lastPlatformY - 150, nextItemType);
}
}
function generateCoin(x, y) {
var coin = new Coin();
coin.x = x;
coin.y = y;
coin.active = true;
coins.push(coin);
game.addChild(coin);
}
function createTrampoline(x, y) {
var trampoline = new Trampoline();
trampoline.x = x;
trampoline.y = y;
trampoline.active = true;
trampolines.push(trampoline);
game.addChild(trampoline);
return trampoline;
}
function createAlien(x, y) {
var alien = new Alien();
alien.x = x;
alien.y = y;
alien.startX = x;
alien.active = true;
aliens.push(alien);
game.addChild(alien);
return alien;
}
function createSaw(x, y) {
var saw = new Saw();
saw.x = x;
saw.y = y;
saw.startX = x;
saw.active = true;
saw.lastWasIntersecting = false;
saws.push(saw);
game.addChild(saw);
return saw;
}
function createBomb(x, y) {
var bomb = new Bomb();
bomb.x = x;
bomb.y = y;
bomb.active = true;
bomb.lastWasIntersecting = false;
bombs.push(bomb);
game.addChild(bomb);
return bomb;
}
function createFlashBomb(x, y) {
var flashBomb = new FlashBomb();
flashBomb.x = x;
flashBomb.y = y;
flashBomb.active = true;
flashBomb.lastWasIntersecting = false;
flashBombs.push(flashBomb);
game.addChild(flashBomb);
return flashBomb;
}
function createSpecialItem(x, y, itemType) {
var item = new SpecialItem(itemType);
item.x = x;
item.y = y;
item.active = true;
specialItems.push(item);
game.addChild(item);
return item;
}
function updateCamera() {
var targetY = dude.y - 1800;
if (targetY < cameraY) {
cameraY = targetY;
game.y = -cameraY;
// Update highest position
if (dude.y < highestY) {
highestY = dude.y;
var currentHeight = Math.floor((2400 - highestY) / 10);
var displayHeight = totalHeight + currentHeight;
LK.setScore(displayHeight);
scoreTxt.setText(LK.getScore());
heightTxt.setText('Height: ' + displayHeight + 'm');
}
}
}
function checkPlatformCollisions() {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (!platform.active) continue;
// Define dude and platform boundaries
var dudeLeft = dude.x - 40;
var dudeRight = dude.x + 40;
var dudeTop = dude.y - 40;
var dudeBottom = dude.y + 40;
var platformLeft = platform.x - 150;
var platformRight = platform.x + 150;
var platformTop = platform.y - 15;
var platformBottom = platform.y + 15;
// Check if dude and platform are overlapping horizontally and vertically
var horizontalOverlap = dudeRight > platformLeft && dudeLeft < platformRight;
var verticalOverlap = dudeBottom > platformTop && dudeTop < platformBottom;
if (horizontalOverlap && verticalOverlap) {
// Calculate overlap distances for each direction
var overlapLeft = dudeRight - platformLeft;
var overlapRight = platformRight - dudeLeft;
var overlapTop = dudeBottom - platformTop;
var overlapBottom = platformBottom - dudeTop;
// Find the smallest overlap to determine collision direction
var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
// Handle collision based on the direction with smallest overlap
if (minOverlap === overlapTop && dude.velocityY > 0) {
// Landing on top of platform (falling down)
dude.y = platformTop - 40;
dude.velocityY = 0;
dude.isOnPlatform = true;
dude.isJumping = false;
if (!platform.landed) {
platform.landed = true;
LK.getSound('land').play();
// Handle special platform effects
if (platform.type === 'powerup') {
dude.invincible = true;
dude.invincibleTimer = 300;
dude.jumpPower = 70; // Double the normal jump power (35 * 2)
LK.getSound('powerup').play();
// Reset jump power after 1 second using tween for precise timing
LK.setTimeout(function () {
dude.jumpPower = 35; // Reset to normal jump power
}, 1000); // Changed from 3000ms to 1000ms (1 second)
}
}
} else if (minOverlap === overlapLeft && dude.velocityX > 0) {
// Hitting platform from the left (moving right)
dude.x = platformLeft - 40;
dude.velocityX = 0;
} else if (minOverlap === overlapRight && dude.velocityX < 0) {
// Hitting platform from the right (moving left)
dude.x = platformRight + 40;
dude.velocityX = 0;
}
break;
}
}
}
function checkCoinCollisions() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.active || coin.collected) continue;
// Check if dude is close enough to collect coin
var distance = Math.sqrt(Math.pow(dude.x - coin.x, 2) + Math.pow(dude.y - coin.y, 2));
if (distance < 50) {
// Collect coin
coin.collected = true;
coin.active = false;
coinsCollected++;
coinTxt.setText('Coins: ' + coinsCollected);
LK.getSound('coinCollect').play();
// Check if player reached 20 coins
if (coinsCollected >= 20) {
// Show bravo message
LK.showYouWin();
}
// Remove coin with fade effect
tween(coin, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
coin.destroy();
coins.splice(i, 1);
}
});
}
}
}
function checkTrampolineCollisions() {
if (dude.velocityY <= 0) return; // Only check when falling
for (var i = 0; i < trampolines.length; i++) {
var trampoline = trampolines[i];
if (!trampoline.active) continue;
var dudeBottom = dude.y + 40;
var trampolineTop = trampoline.y - 30;
var trampolineBottom = trampoline.y + 30;
if (dudeBottom >= trampolineTop && dudeBottom <= trampolineBottom + 20) {
if (dude.x >= trampoline.x - 150 && dude.x <= trampoline.x + 150) {
// Bounce off trampoline with super jump
dude.velocityY = -60; // Much higher than normal jump
dude.isJumping = true;
dude.isOnPlatform = false;
trampoline.bounce();
LK.getSound('jump').play();
break;
}
}
}
}
function checkBulletAlienCollisions() {
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet.active) continue;
for (var j = aliens.length - 1; j >= 0; j--) {
var alien = aliens[j];
if (!alien.active) continue;
// Check collision between bullet and alien
var distance = Math.sqrt(Math.pow(bullet.x - alien.x, 2) + Math.pow(bullet.y - alien.y, 2));
if (distance < 50) {
// Hit detected
bullet.active = false;
bullet.destroy();
bullets.splice(i, 1);
alien.takeDamage();
if (!alien.active) {
aliensKilled++;
zombiesKilled++;
aliens.splice(j, 1);
// Increase score for killing alien
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Give gold reward with 50% chance (100/2 = 50%)
if (Math.random() < 0.5) {
gold += 1;
storage.gold = gold;
goldTxt.setText('Gold: ' + gold);
}
// Check if player killed 10 zombies
if (zombiesKilled >= 10) {
// Show you win message
LK.showYouWin();
}
}
break;
}
}
}
}
function cleanupPlatforms() {
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.y > cameraY + 3000 || !platform.active) {
platform.destroy();
platforms.splice(i, 1);
}
}
}
function cleanupCoins() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > cameraY + 3000 || !coin.active) {
coin.destroy();
coins.splice(i, 1);
}
}
}
function cleanupBullets() {
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.y < cameraY - 200 || !bullet.active) {
bullet.destroy();
bullets.splice(i, 1);
}
}
}
function cleanupTrampolines() {
for (var i = trampolines.length - 1; i >= 0; i--) {
var trampoline = trampolines[i];
if (trampoline.y > cameraY + 3000 || !trampoline.active) {
trampoline.destroy();
trampolines.splice(i, 1);
}
}
}
function checkSpecialItemCollisions() {
for (var i = specialItems.length - 1; i >= 0; i--) {
var item = specialItems[i];
if (!item.active || item.collected) continue;
// Check if dude is close enough to collect special item
var distance = Math.sqrt(Math.pow(dude.x - item.x, 2) + Math.pow(dude.y - item.y, 2));
if (distance < 60) {
// Collect special item
item.collected = true;
item.active = false;
specialItemsCollected++;
specialItemsTxt.setText('Special Items: ' + specialItemsCollected + '/' + totalSpecialItems);
// Visual feedback - dramatic collection effect
LK.effects.flashScreen(0xff0000, 500);
tween(item, {
alpha: 0,
scaleX: 4,
scaleY: 4
}, {
duration: 500,
onFinish: function onFinish() {
item.destroy();
specialItems.splice(i, 1);
}
});
// Check if all special items collected
if (specialItemsCollected >= totalSpecialItems) {
// Show you win message
LK.showYouWin();
}
break;
}
}
}
function checkAlienPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (!alien.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - alien.x, 2) + Math.pow(dude.y - alien.y, 2));
if (distance < 60) {
dude.takeDamage();
break;
}
}
}
function checkBombPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < bombs.length; i++) {
var bomb = bombs[i];
if (!bomb.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - bomb.x, 2) + Math.pow(dude.y - bomb.y, 2));
var currentIntersecting = distance < 60;
// Check for transition from not intersecting to intersecting
if (!bomb.lastWasIntersecting && currentIntersecting) {
// Take 3 damage from bomb
dude.health -= 3;
if (dude.health < 0) dude.health = 0;
dude.invincible = true;
dude.invincibleTimer = 180; // 3 seconds of invincibility
// Dramatic explosion effect
LK.effects.flashScreen(0xff4444, 1000);
LK.effects.flashObject(dude, 0xff0000, 800);
updateHealthDisplay();
// Destroy the bomb after explosion
bomb.active = false;
bomb.destroy();
bombs.splice(i, 1);
if (dude.health <= 0) {
// Reset gold to zero when player dies
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
break;
}
// Update last intersecting state
bomb.lastWasIntersecting = currentIntersecting;
}
}
function checkFlashBombPlayerCollisions() {
for (var i = 0; i < flashBombs.length; i++) {
var flashBomb = flashBombs[i];
if (!flashBomb.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - flashBomb.x, 2) + Math.pow(dude.y - flashBomb.y, 2));
var currentIntersecting = distance < 60;
// Check for transition from not intersecting to intersecting
if (!flashBomb.lastWasIntersecting && currentIntersecting) {
// Create a white overlay that covers the entire screen for 3 seconds
var whiteOverlay = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 100,
scaleY: 150,
alpha: 0
});
whiteOverlay.tint = 0xffffff;
whiteOverlay.x = 1024; // Center of screen
whiteOverlay.y = 1366; // Center of screen
LK.gui.center.addChild(whiteOverlay);
// Tween the overlay to full opacity immediately, then gradually fade out over 3 seconds
tween(whiteOverlay, {
alpha: 1
}, {
duration: 50,
onFinish: function onFinish() {
// Gradually fade out the white screen over 3 seconds
tween(whiteOverlay, {
alpha: 0
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
whiteOverlay.destroy();
}
});
}
});
// Destroy the flash bomb after activation
flashBomb.active = false;
flashBomb.destroy();
flashBombs.splice(i, 1);
break;
}
// Update last intersecting state
flashBomb.lastWasIntersecting = currentIntersecting;
}
}
function checkSawPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < saws.length; i++) {
var saw = saws[i];
if (!saw.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - saw.x, 2) + Math.pow(dude.y - saw.y, 2));
var currentIntersecting = distance < 70;
// Check for transition from not intersecting to intersecting
if (!saw.lastWasIntersecting && currentIntersecting) {
dude.takeDamage();
}
// Update last intersecting state
saw.lastWasIntersecting = currentIntersecting;
}
}
function cleanupAliens() {
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
if (alien.y > cameraY + 3000 || !alien.active) {
if (alien.active) {
alien.destroy();
}
aliens.splice(i, 1);
}
}
}
function cleanupSaws() {
for (var i = saws.length - 1; i >= 0; i--) {
var saw = saws[i];
if (saw.y > cameraY + 3000 || !saw.active) {
if (saw.active) {
saw.destroy();
}
saws.splice(i, 1);
}
}
}
function cleanupBombs() {
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
if (bomb.y > cameraY + 3000 || !bomb.active) {
if (bomb.active) {
bomb.destroy();
}
bombs.splice(i, 1);
}
}
}
function cleanupFlashBombs() {
for (var i = flashBombs.length - 1; i >= 0; i--) {
var flashBomb = flashBombs[i];
if (flashBomb.y > cameraY + 3000 || !flashBomb.active) {
if (flashBomb.active) {
flashBomb.destroy();
}
flashBombs.splice(i, 1);
}
}
}
function cleanupSpecialItems() {
for (var i = specialItems.length - 1; i >= 0; i--) {
var item = specialItems[i];
if (item.y > cameraY + 3000 || !item.active) {
if (item.active) {
item.destroy();
}
specialItems.splice(i, 1);
}
}
}
function generateMorePlatforms() {
while (lastPlatformY > cameraY - 1000) {
generateNextPlatform();
}
}
// Touch controls
var isPressed = false;
var pressedSide = 0; // -1 for left, 1 for right, 0 for center
game.down = function (x, y, obj) {
dude.jump();
isPressed = true;
// Determine which side was pressed
var screenCenter = 1024; // Half of 2048
var touchOffset = x - screenCenter;
if (touchOffset > 50) {
pressedSide = 1; // Right side
} else if (touchOffset < -50) {
pressedSide = -1; // Left side
} else {
pressedSide = 0; // Center
}
// Shoot when touching center area
if (Math.abs(touchOffset) <= 50 && LK.ticks - lastShootTime >= shootCooldown) {
dude.shoot('up');
lastShootTime = LK.ticks;
}
};
game.up = function (x, y, obj) {
isPressed = false;
pressedSide = 0;
};
// Fire button touch handlers for 4 directions
function createFireButtonHandler(button, direction) {
button.down = function (x, y, obj) {
if (LK.ticks - lastShootTime >= shootCooldown) {
dude.shoot(direction);
lastShootTime = LK.ticks;
// Visual feedback - scale animation
tween(button, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(button, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100
});
}
});
}
};
}
createFireButtonHandler(fireButtonUp, 'up');
createFireButtonHandler(fireButtonDown, 'down');
createFireButtonHandler(fireButtonLeft, 'left');
createFireButtonHandler(fireButtonRight, 'right');
// Track if space theme has been activated
var spaceThemeActivated = false;
// Track if 1500m jump boost has been applied
var jumpBoostApplied = false;
// Track if 1200m horizontal speed boost has been applied
var speedBoostApplied = false;
// Track if 4000m jumpscare has been triggered
var jumpscareTriggered = false;
// Track spawn rate multipliers that increase on restart
var alienSpawnMultiplier = 1.0;
var sawSpawnMultiplier = 1.0;
var hasRestarted = false;
var stars = [];
function createStar(x, y) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6 + Math.random() * 0.4
});
star.x = x;
star.y = y;
star.twinkleSpeed = 0.02 + Math.random() * 0.03;
star.twinkleOffset = Math.random() * Math.PI * 2;
stars.push(star);
game.addChild(star);
return star;
}
function generateStars() {
// Generate stars in the visible area and above
for (var i = 0; i < 50; i++) {
var x = Math.random() * 2048;
var y = cameraY - 1000 + Math.random() * 3732;
createStar(x, y);
}
}
// Initialize stars
generateStars();
// Main game loop
game.update = function () {
updateCamera();
checkPlatformCollisions();
checkTrampolineCollisions();
checkCoinCollisions();
checkSpecialItemCollisions();
checkBulletAlienCollisions();
checkAlienPlayerCollisions();
checkSawPlayerCollisions();
checkBombPlayerCollisions();
checkFlashBombPlayerCollisions();
generateMorePlatforms();
// Calculate current and total height
var currentHeight = Math.floor((2400 - dude.y) / 10);
var displayHeight = totalHeight + currentHeight;
// Check if player reached 4000m height for jumpscare
if (displayHeight >= 4000 && !jumpscareTriggered) {
jumpscareTriggered = true;
// Create scary alien jumpscare that covers the entire screen
var jumpscareAlien = LK.getAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 20,
alpha: 0
});
jumpscareAlien.x = 1024; // Center of screen
jumpscareAlien.y = 1366; // Center of screen
LK.gui.center.addChild(jumpscareAlien);
// Play loud scary scream sound with maximum volume for jumpscare effect
var jumpscareSound = LK.getSound('jumpscare');
jumpscareSound.volume = 1.0; // Maximum volume for scary effect
jumpscareSound.play();
// Additional sound effect layering for more intensity
LK.setTimeout(function () {
jumpscareSound.play(); // Play again for echo effect
}, 200);
// Jumpscare animation with red flash and massive scaling
LK.effects.flashScreen(0xff0000, 3000); // Red flash for 3 seconds
tween(jumpscareAlien, {
alpha: 1,
scaleX: 25,
scaleY: 25
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for a longer moment with terrifying effect
LK.setTimeout(function () {
tween(jumpscareAlien, {
alpha: 0,
scaleX: 30,
scaleY: 30
}, {
duration: 1500,
onFinish: function onFinish() {
jumpscareAlien.destroy();
}
});
}, 2000);
}
});
}
// Check if player reached height 1200 and reset to starting position
if (currentHeight >= 1200 && !speedBoostApplied) {
speedBoostApplied = true;
// Add current height to total height before reset
totalHeight += 1200;
storage.totalHeight = totalHeight;
// Activate space theme when resetting after 1200m
if (!spaceThemeActivated) {
spaceThemeActivated = true;
// Change background to dark space color
game.setBackgroundColor(0x0a0a2e); // Dark blue-purple space color
// Flash screen to indicate theme change
LK.effects.flashScreen(0x8a2be2, 1000); // Purple flash for 1 second
}
// Reset character to starting position
dude.x = 1024;
dude.y = 2400;
dude.velocityY = 0;
dude.velocityX = 0;
dude.isJumping = false;
dude.isOnPlatform = false;
// Reset camera
cameraY = 0;
game.y = -cameraY;
highestY = 2400;
// Reset current height tracking but keep total
var newDisplayHeight = totalHeight;
LK.setScore(newDisplayHeight);
scoreTxt.setText(newDisplayHeight.toString());
heightTxt.setText('Height: ' + newDisplayHeight + 'm');
// Reset boost flags for next cycle
jumpBoostApplied = false;
speedBoostApplied = false;
// Increase spawn rates on restart (100% aliens, 35% saws)
if (!hasRestarted) {
hasRestarted = true;
alienSpawnMultiplier = 2.0; // 100% increase (double the rate)
sawSpawnMultiplier = 1.35; // 35% increase
} else {
// Continue increasing on subsequent restarts
alienSpawnMultiplier += 1.0; // Additional 100% each restart
sawSpawnMultiplier += 0.35; // Additional 35% each restart
}
// Visual feedback for reset
LK.effects.flashScreen(0x00ff00, 500); // Green flash
}
// Check if player reached height 1500 and boost jump power
if (displayHeight >= 1500 && !jumpBoostApplied) {
jumpBoostApplied = true;
// Boost jump power by 1.5x (0.5x more than normal)
dude.jumpPower = 52.5; // 35 * 1.5 = 52.5
// Visual feedback for power boost
LK.effects.flashObject(dude, 0x00ff00, 500); // Green flash
}
// Update star twinkling animation
for (var s = 0; s < stars.length; s++) {
var star = stars[s];
star.alpha = 0.3 + Math.sin(LK.ticks * star.twinkleSpeed + star.twinkleOffset) * 0.4;
}
// Generate more stars as camera moves up
if (LK.ticks % 120 === 0) {
// Add new stars above the visible area
for (var i = 0; i < 10; i++) {
var x = Math.random() * 2048;
var y = cameraY - 500 + Math.random() * 500;
createStar(x, y);
}
}
// Remove platforms that are too far down
if (LK.ticks % 60 === 0) {
cleanupCoins();
cleanupBullets();
cleanupTrampolines();
cleanupAliens();
cleanupSaws();
cleanupBombs();
cleanupFlashBombs();
cleanupSpecialItems();
// Cleanup stars that are too far below
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
if (star.y > cameraY + 3000) {
star.destroy();
stars.splice(s, 1);
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 1;
self.direction = 1;
self.moveRange = 200;
self.startX = 0;
self.active = true;
self.lastWasHit = false;
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
self.active = false;
LK.getSound('alienDestroy').play();
// Flash effect before destruction
tween(alienGraphics, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
} else {
LK.getSound('alienHit').play();
// Flash red when hit
LK.effects.flashObject(self, 0xff0000, 200);
}
};
self.update = function () {
if (!self.active) return;
// Move alien horizontally
self.x += self.direction * self.speed;
// Reverse direction when reaching movement limits
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.direction *= -1;
}
// Keep alien within screen bounds
if (self.x < 40) {
self.x = 40;
self.direction = 1;
}
if (self.x > 2008) {
self.x = 2008;
self.direction = -1;
}
};
return self;
});
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.05;
self.pulseSpeed = 0.08;
self.lastWasIntersecting = false;
self.update = function () {
// Rotate bomb slowly for menacing effect
bombGraphics.rotation += self.rotationSpeed;
// Pulsing scale effect to make it more noticeable
var pulseScale = 1 + Math.sin(LK.ticks * self.pulseSpeed) * 0.2;
bombGraphics.scaleX = pulseScale;
bombGraphics.scaleY = pulseScale;
// Red tinting that pulses to indicate danger
var redIntensity = 0.5 + Math.sin(LK.ticks * self.pulseSpeed * 2) * 0.5;
bombGraphics.tint = 0xff << 16 | Math.floor((1 - redIntensity) * 255) << 8 | Math.floor((1 - redIntensity) * 255);
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.direction = {
x: 0,
y: -1
}; // Default upward direction
self.active = true;
self.update = function () {
// Find nearest alien to auto-target
var nearestAlien = null;
var nearestDistance = Infinity;
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
var distance = Math.sqrt(Math.pow(self.x - alien.x, 2) + Math.pow(self.y - alien.y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestAlien = alien;
}
}
}
// If there's an alien to target, automatically steer towards it
if (nearestAlien) {
var targetX = nearestAlien.x - self.x;
var targetY = nearestAlien.y - self.y;
var targetDistance = Math.sqrt(targetX * targetX + targetY * targetY);
if (targetDistance > 0) {
// Normalize direction towards target
self.direction.x = targetX / targetDistance;
self.direction.y = targetY / targetDistance;
}
}
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove bullet if it goes off screen
if (self.y < cameraY - 200 || self.y > cameraY + 2732 + 200 || self.x < -100 || self.x > 2148) {
self.active = false;
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.1;
self.update = function () {
// Rotate coin for visual appeal
coinGraphics.rotation += self.rotationSpeed;
// Float up and down slightly
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var Dude = Container.expand(function () {
var self = Container.call(this);
var dudeGraphics = self.attachAsset('dude', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.velocityX = 0;
self.isJumping = false;
self.isOnPlatform = false;
self.jumpPower = 35;
self.gravity = 0.8;
self.maxFallSpeed = 15;
self.horizontalSpeed = 12;
self.airResistance = 0.85;
self.invincible = false;
self.invincibleTimer = 0;
self.health = 4;
self.maxHealth = 4;
self.jump = function () {
if (self.isOnPlatform) {
self.velocityY = -self.jumpPower;
self.isJumping = true;
self.isOnPlatform = false;
LK.getSound('jump').play();
}
};
self.update = function () {
// Auto jump when on platform (only if not flying)
if (self.isOnPlatform && !self.canFly) {
self.jump();
}
// Apply gravity (reduced if flying)
if (self.canFly) {
self.velocityY += self.gravity * 0.5; // Reduced gravity for flying
} else {
self.velocityY += self.gravity;
}
if (self.velocityY > self.maxFallSpeed) {
self.velocityY = self.maxFallSpeed;
}
// Update position
self.y += self.velocityY;
self.x += self.velocityX;
// Apply continuous horizontal movement while pressed
if (isPressed && pressedSide !== 0) {
self.velocityX += pressedSide * self.horizontalSpeed * 0.3;
}
// Apply air resistance to horizontal movement
self.velocityX *= self.airResistance;
// Handle invincibility timer
if (self.invincible) {
self.invincibleTimer--;
if (self.invincibleTimer <= 0) {
self.invincible = false;
dudeGraphics.alpha = 1;
} else {
dudeGraphics.alpha = Math.sin(self.invincibleTimer * 0.3) * 0.5 + 0.5;
}
}
// Allow infinite horizontal movement - no bounds restriction
// Character can now move infinitely left and right
// Check if fallen off screen
if (self.y > cameraY + 2732 + 200) {
// Reset gold to zero when player falls off screen
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
};
self.takeDamage = function () {
if (self.invincible) return;
self.health--;
self.invincible = true;
self.invincibleTimer = 180; // 3 seconds of invincibility
LK.effects.flashObject(self, 0xff0000, 500);
updateHealthDisplay();
if (self.health <= 0) {
// Reset gold to zero when player dies
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
};
self.shoot = function (direction) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
// Set bullet direction based on parameter
if (direction === 'up') {
bullet.direction = {
x: 0,
y: -1
};
bullet.y = self.y - 30;
} else if (direction === 'down') {
bullet.direction = {
x: 0,
y: 1
};
bullet.y = self.y + 30;
} else if (direction === 'left') {
bullet.direction = {
x: -1,
y: 0
};
bullet.x = self.x - 30;
} else if (direction === 'right') {
bullet.direction = {
x: 1,
y: 0
};
bullet.x = self.x + 30;
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
return self;
});
var FlashBomb = Container.expand(function () {
var self = Container.call(this);
var flashBombGraphics = self.attachAsset('flashBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.05;
self.pulseSpeed = 0.08;
self.lastWasIntersecting = false;
// Make flash bomb visually different - white tint
flashBombGraphics.tint = 0xffffff;
self.update = function () {
// Rotate flash bomb slowly
flashBombGraphics.rotation += self.rotationSpeed;
// Pulsing scale effect
var pulseScale = 1 + Math.sin(LK.ticks * self.pulseSpeed) * 0.2;
flashBombGraphics.scaleX = pulseScale;
flashBombGraphics.scaleY = pulseScale;
// White tinting that pulses to indicate flash effect
var whiteIntensity = 0.7 + Math.sin(LK.ticks * self.pulseSpeed * 2) * 0.3;
flashBombGraphics.tint = Math.floor(whiteIntensity * 255) << 16 | Math.floor(whiteIntensity * 255) << 8 | Math.floor(whiteIntensity * 255);
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'normal';
self.landed = false;
self.disappearing = false;
self.moveDirection = 1;
self.moveRange = 300;
self.startX = 0;
var platformGraphics;
if (self.type === 'moving') {
platformGraphics = self.attachAsset('movingPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.type === 'disappearing') {
platformGraphics = self.attachAsset('disappearingPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.type === 'powerup') {
platformGraphics = self.attachAsset('powerUpPlatform', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.update = function () {
// Moving platform behavior
if (self.type === 'moving') {
self.x += self.moveDirection * 2;
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.moveDirection *= -1;
}
}
// Disappearing platform behavior
if (self.type === 'disappearing' && self.landed && !self.disappearing) {
self.disappearing = true;
tween(platformGraphics, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
self.active = false;
}
});
}
};
return self;
});
var Saw = Container.expand(function () {
var self = Container.call(this);
var sawGraphics = self.attachAsset('saw', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.rotationSpeed = 0.3;
self.lastWasIntersecting = false;
self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
self.moveSpeed = 2;
self.moveRange = 150;
self.startX = 0;
self.update = function () {
// Move saw horizontally
self.x += self.moveDirection * self.moveSpeed;
// Reverse direction when reaching movement limits
if (self.x > self.startX + self.moveRange || self.x < self.startX - self.moveRange) {
self.moveDirection *= -1;
}
// Keep saw within screen bounds
if (self.x < 60) {
self.x = 60;
self.moveDirection = 1;
}
if (self.x > 1988) {
self.x = 1988;
self.moveDirection = -1;
}
};
return self;
});
var SpecialItem = Container.expand(function (itemType) {
var self = Container.call(this);
self.itemType = itemType || 1;
var assetId = 'specialItem' + self.itemType;
var itemGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Make special items larger
itemGraphics.scaleX = 2;
itemGraphics.scaleY = 2;
self.collected = false;
self.active = true;
self.rotationSpeed = 0.15;
self.floatOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Float up and down with more pronounced animation
self.y += Math.sin(LK.ticks * 0.06 + self.floatOffset) * 1.2;
// Pulsing scale effect
var pulseScale = 2 + Math.sin(LK.ticks * 0.08) * 0.3;
itemGraphics.scaleX = pulseScale;
itemGraphics.scaleY = pulseScale;
};
return self;
});
var Trampoline = Container.expand(function () {
var self = Container.call(this);
var trampolineGraphics = self.attachAsset('trampoline', {
anchorX: 0.5,
anchorY: 0.5
});
self.bounced = false;
self.active = true;
self.bounce = function () {
// Animate trampoline compression and expansion
tween(trampolineGraphics, {
scaleY: 0.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(trampolineGraphics, {
scaleY: 1.2
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(trampolineGraphics, {
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
var dude = game.addChild(new Dude());
var platforms = [];
var coins = [];
var bullets = [];
var trampolines = [];
var cameraY = 0;
var highestY = 2400;
var lastPlatformY = 2400;
var platformSpacing = 200;
var coinsCollected = 0;
var gold = storage.gold || 0;
var totalHeight = storage.totalHeight || 0;
var lastShootTime = 0;
var shootCooldown = 20; // 20 ticks between shots
var aliens = [];
var aliensKilled = 0;
var saws = [];
var specialItems = [];
var specialItemsCollected = 0;
var totalSpecialItems = 4;
var zombiesKilled = 0;
var bombs = [];
var flashBombs = [];
// Create score display
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create height display
var heightTxt = new Text2('Height: 0m', {
size: 40,
fill: 0xFFFFFF
});
heightTxt.anchor.set(1, 0);
heightTxt.x = -20;
heightTxt.y = 20;
LK.gui.topRight.addChild(heightTxt);
// Create coin counter display
var coinTxt = new Text2('Coins: 0', {
size: 40,
fill: 0xffd700
});
coinTxt.anchor.set(0, 0);
coinTxt.x = 20;
coinTxt.y = 20;
LK.gui.topLeft.addChild(coinTxt);
// Create gold display
var goldTxt = new Text2('Gold: ' + gold, {
size: 40,
fill: 0xffd700
});
goldTxt.anchor.set(0, 0);
goldTxt.x = 20;
goldTxt.y = 120;
LK.gui.topLeft.addChild(goldTxt);
// Create special items display
var specialItemsTxt = new Text2('Special Items: 0/' + totalSpecialItems, {
size: 40,
fill: 0xff0000
});
specialItemsTxt.anchor.set(0, 0);
specialItemsTxt.x = 20;
specialItemsTxt.y = 170;
LK.gui.topLeft.addChild(specialItemsTxt);
// Create health display
var hearts = [];
function createHealthDisplay() {
for (var i = 0; i < dude.maxHealth; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 20 + i * 50;
heart.y = 80;
hearts.push(heart);
LK.gui.topLeft.addChild(heart);
}
}
function updateHealthDisplay() {
for (var i = 0; i < hearts.length; i++) {
hearts[i].alpha = i < dude.health ? 1 : 0.3;
}
}
// Initialize dude position
dude.x = 1024;
dude.y = 2400;
// Initialize health display
createHealthDisplay();
updateHealthDisplay();
// Create fire buttons for 4 directions
var fireButtonUp = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonUp.x = -120;
fireButtonUp.y = -300;
LK.gui.bottomRight.addChild(fireButtonUp);
var fireButtonDown = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonDown.x = -120;
fireButtonDown.y = -100;
fireButtonDown.rotation = Math.PI; // Rotate 180 degrees
LK.gui.bottomRight.addChild(fireButtonDown);
var fireButtonLeft = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonLeft.x = -220;
fireButtonLeft.y = -200;
fireButtonLeft.rotation = Math.PI * 1.5; // Rotate 270 degrees
LK.gui.bottomRight.addChild(fireButtonLeft);
var fireButtonRight = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
fireButtonRight.x = -20;
fireButtonRight.y = -200;
fireButtonRight.rotation = Math.PI * 0.5; // Rotate 90 degrees
LK.gui.bottomRight.addChild(fireButtonRight);
// Create initial platforms
function createPlatform(x, y, type) {
var platform = new Platform(type);
platform.x = x;
platform.y = y;
platform.startX = x;
platform.active = true;
platforms.push(platform);
game.addChild(platform);
return platform;
}
// Create starting platform
createPlatform(1024, 2450, 'normal');
// Generate initial platforms
for (var i = 0; i < 20; i++) {
generateNextPlatform();
}
function generateNextPlatform() {
lastPlatformY -= platformSpacing + Math.random() * 100;
var x = 200 + Math.random() * 1648;
// Determine platform type based on height
var type = 'normal';
var height = Math.abs(lastPlatformY - 2400);
if (height > 1000) {
var rand = Math.random();
var powerupChance = spaceThemeActivated ? 0.8 : 0.6; // Increased from 0.6 to 0.8 in space theme
if (rand < 0.3) {
type = 'moving';
} else if (rand < 0.5) {
type = 'disappearing';
} else if (rand < powerupChance) {
type = 'powerup';
}
}
createPlatform(x, lastPlatformY, type);
// Generate coins near platforms with increased rate after 1255m
var currentGameHeight = Math.abs(lastPlatformY - 2400);
var coinChance = currentGameHeight > 1255 ? 0.98 : 0.85; // 98% chance after 1255m, 85% before
if (Math.random() < coinChance) {
generateCoin(x + (Math.random() - 0.5) * 200, lastPlatformY - 80);
}
// Generate trampolines more frequently (25% chance, 40% in space theme)
var trampolineChance = spaceThemeActivated ? 0.40 : 0.25;
if (Math.random() < trampolineChance) {
createTrampoline(x, lastPlatformY - 100);
}
// Generate aliens with 15% chance
var alienChance = 0.15; // 15% chance
if (Math.random() < alienChance) {
createAlien(x + (Math.random() - 0.5) * 300, lastPlatformY - 150);
}
// Kittens removed from game
// Generate saws more frequently (25% chance)
var baseSawChance = 0.25; // 25% chance (increased from 10%)
var sawChance = baseSawChance * sawSpawnMultiplier;
if (Math.random() < sawChance) {
createSaw(x + (Math.random() - 0.5) * 300, lastPlatformY - 100);
}
// Generate bombs with 5% chance after reaching 500m height
var currentGameHeight = Math.abs(lastPlatformY - 2400);
if (currentGameHeight > 500 && Math.random() < 0.05) {
createBomb(x + (Math.random() - 0.5) * 300, lastPlatformY - 120);
}
// Generate flash bombs more frequently (20% chance after reaching 800m height)
if (currentGameHeight > 800 && Math.random() < 0.20) {
createFlashBomb(x + (Math.random() - 0.5) * 300, lastPlatformY - 120);
}
// Generate special items frequently (10% chance) and only if we haven't collected all yet
if (Math.random() < 0.10 && specialItemsCollected < totalSpecialItems) {
var nextItemType = specialItemsCollected + 1;
createSpecialItem(x + (Math.random() - 0.5) * 200, lastPlatformY - 150, nextItemType);
}
}
function generateCoin(x, y) {
var coin = new Coin();
coin.x = x;
coin.y = y;
coin.active = true;
coins.push(coin);
game.addChild(coin);
}
function createTrampoline(x, y) {
var trampoline = new Trampoline();
trampoline.x = x;
trampoline.y = y;
trampoline.active = true;
trampolines.push(trampoline);
game.addChild(trampoline);
return trampoline;
}
function createAlien(x, y) {
var alien = new Alien();
alien.x = x;
alien.y = y;
alien.startX = x;
alien.active = true;
aliens.push(alien);
game.addChild(alien);
return alien;
}
function createSaw(x, y) {
var saw = new Saw();
saw.x = x;
saw.y = y;
saw.startX = x;
saw.active = true;
saw.lastWasIntersecting = false;
saws.push(saw);
game.addChild(saw);
return saw;
}
function createBomb(x, y) {
var bomb = new Bomb();
bomb.x = x;
bomb.y = y;
bomb.active = true;
bomb.lastWasIntersecting = false;
bombs.push(bomb);
game.addChild(bomb);
return bomb;
}
function createFlashBomb(x, y) {
var flashBomb = new FlashBomb();
flashBomb.x = x;
flashBomb.y = y;
flashBomb.active = true;
flashBomb.lastWasIntersecting = false;
flashBombs.push(flashBomb);
game.addChild(flashBomb);
return flashBomb;
}
function createSpecialItem(x, y, itemType) {
var item = new SpecialItem(itemType);
item.x = x;
item.y = y;
item.active = true;
specialItems.push(item);
game.addChild(item);
return item;
}
function updateCamera() {
var targetY = dude.y - 1800;
if (targetY < cameraY) {
cameraY = targetY;
game.y = -cameraY;
// Update highest position
if (dude.y < highestY) {
highestY = dude.y;
var currentHeight = Math.floor((2400 - highestY) / 10);
var displayHeight = totalHeight + currentHeight;
LK.setScore(displayHeight);
scoreTxt.setText(LK.getScore());
heightTxt.setText('Height: ' + displayHeight + 'm');
}
}
}
function checkPlatformCollisions() {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (!platform.active) continue;
// Define dude and platform boundaries
var dudeLeft = dude.x - 40;
var dudeRight = dude.x + 40;
var dudeTop = dude.y - 40;
var dudeBottom = dude.y + 40;
var platformLeft = platform.x - 150;
var platformRight = platform.x + 150;
var platformTop = platform.y - 15;
var platformBottom = platform.y + 15;
// Check if dude and platform are overlapping horizontally and vertically
var horizontalOverlap = dudeRight > platformLeft && dudeLeft < platformRight;
var verticalOverlap = dudeBottom > platformTop && dudeTop < platformBottom;
if (horizontalOverlap && verticalOverlap) {
// Calculate overlap distances for each direction
var overlapLeft = dudeRight - platformLeft;
var overlapRight = platformRight - dudeLeft;
var overlapTop = dudeBottom - platformTop;
var overlapBottom = platformBottom - dudeTop;
// Find the smallest overlap to determine collision direction
var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
// Handle collision based on the direction with smallest overlap
if (minOverlap === overlapTop && dude.velocityY > 0) {
// Landing on top of platform (falling down)
dude.y = platformTop - 40;
dude.velocityY = 0;
dude.isOnPlatform = true;
dude.isJumping = false;
if (!platform.landed) {
platform.landed = true;
LK.getSound('land').play();
// Handle special platform effects
if (platform.type === 'powerup') {
dude.invincible = true;
dude.invincibleTimer = 300;
dude.jumpPower = 70; // Double the normal jump power (35 * 2)
LK.getSound('powerup').play();
// Reset jump power after 1 second using tween for precise timing
LK.setTimeout(function () {
dude.jumpPower = 35; // Reset to normal jump power
}, 1000); // Changed from 3000ms to 1000ms (1 second)
}
}
} else if (minOverlap === overlapLeft && dude.velocityX > 0) {
// Hitting platform from the left (moving right)
dude.x = platformLeft - 40;
dude.velocityX = 0;
} else if (minOverlap === overlapRight && dude.velocityX < 0) {
// Hitting platform from the right (moving left)
dude.x = platformRight + 40;
dude.velocityX = 0;
}
break;
}
}
}
function checkCoinCollisions() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.active || coin.collected) continue;
// Check if dude is close enough to collect coin
var distance = Math.sqrt(Math.pow(dude.x - coin.x, 2) + Math.pow(dude.y - coin.y, 2));
if (distance < 50) {
// Collect coin
coin.collected = true;
coin.active = false;
coinsCollected++;
coinTxt.setText('Coins: ' + coinsCollected);
LK.getSound('coinCollect').play();
// Check if player reached 20 coins
if (coinsCollected >= 20) {
// Show bravo message
LK.showYouWin();
}
// Remove coin with fade effect
tween(coin, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
coin.destroy();
coins.splice(i, 1);
}
});
}
}
}
function checkTrampolineCollisions() {
if (dude.velocityY <= 0) return; // Only check when falling
for (var i = 0; i < trampolines.length; i++) {
var trampoline = trampolines[i];
if (!trampoline.active) continue;
var dudeBottom = dude.y + 40;
var trampolineTop = trampoline.y - 30;
var trampolineBottom = trampoline.y + 30;
if (dudeBottom >= trampolineTop && dudeBottom <= trampolineBottom + 20) {
if (dude.x >= trampoline.x - 150 && dude.x <= trampoline.x + 150) {
// Bounce off trampoline with super jump
dude.velocityY = -60; // Much higher than normal jump
dude.isJumping = true;
dude.isOnPlatform = false;
trampoline.bounce();
LK.getSound('jump').play();
break;
}
}
}
}
function checkBulletAlienCollisions() {
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet.active) continue;
for (var j = aliens.length - 1; j >= 0; j--) {
var alien = aliens[j];
if (!alien.active) continue;
// Check collision between bullet and alien
var distance = Math.sqrt(Math.pow(bullet.x - alien.x, 2) + Math.pow(bullet.y - alien.y, 2));
if (distance < 50) {
// Hit detected
bullet.active = false;
bullet.destroy();
bullets.splice(i, 1);
alien.takeDamage();
if (!alien.active) {
aliensKilled++;
zombiesKilled++;
aliens.splice(j, 1);
// Increase score for killing alien
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Give gold reward with 50% chance (100/2 = 50%)
if (Math.random() < 0.5) {
gold += 1;
storage.gold = gold;
goldTxt.setText('Gold: ' + gold);
}
// Check if player killed 10 zombies
if (zombiesKilled >= 10) {
// Show you win message
LK.showYouWin();
}
}
break;
}
}
}
}
function cleanupPlatforms() {
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.y > cameraY + 3000 || !platform.active) {
platform.destroy();
platforms.splice(i, 1);
}
}
}
function cleanupCoins() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > cameraY + 3000 || !coin.active) {
coin.destroy();
coins.splice(i, 1);
}
}
}
function cleanupBullets() {
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.y < cameraY - 200 || !bullet.active) {
bullet.destroy();
bullets.splice(i, 1);
}
}
}
function cleanupTrampolines() {
for (var i = trampolines.length - 1; i >= 0; i--) {
var trampoline = trampolines[i];
if (trampoline.y > cameraY + 3000 || !trampoline.active) {
trampoline.destroy();
trampolines.splice(i, 1);
}
}
}
function checkSpecialItemCollisions() {
for (var i = specialItems.length - 1; i >= 0; i--) {
var item = specialItems[i];
if (!item.active || item.collected) continue;
// Check if dude is close enough to collect special item
var distance = Math.sqrt(Math.pow(dude.x - item.x, 2) + Math.pow(dude.y - item.y, 2));
if (distance < 60) {
// Collect special item
item.collected = true;
item.active = false;
specialItemsCollected++;
specialItemsTxt.setText('Special Items: ' + specialItemsCollected + '/' + totalSpecialItems);
// Visual feedback - dramatic collection effect
LK.effects.flashScreen(0xff0000, 500);
tween(item, {
alpha: 0,
scaleX: 4,
scaleY: 4
}, {
duration: 500,
onFinish: function onFinish() {
item.destroy();
specialItems.splice(i, 1);
}
});
// Check if all special items collected
if (specialItemsCollected >= totalSpecialItems) {
// Show you win message
LK.showYouWin();
}
break;
}
}
}
function checkAlienPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (!alien.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - alien.x, 2) + Math.pow(dude.y - alien.y, 2));
if (distance < 60) {
dude.takeDamage();
break;
}
}
}
function checkBombPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < bombs.length; i++) {
var bomb = bombs[i];
if (!bomb.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - bomb.x, 2) + Math.pow(dude.y - bomb.y, 2));
var currentIntersecting = distance < 60;
// Check for transition from not intersecting to intersecting
if (!bomb.lastWasIntersecting && currentIntersecting) {
// Take 3 damage from bomb
dude.health -= 3;
if (dude.health < 0) dude.health = 0;
dude.invincible = true;
dude.invincibleTimer = 180; // 3 seconds of invincibility
// Dramatic explosion effect
LK.effects.flashScreen(0xff4444, 1000);
LK.effects.flashObject(dude, 0xff0000, 800);
updateHealthDisplay();
// Destroy the bomb after explosion
bomb.active = false;
bomb.destroy();
bombs.splice(i, 1);
if (dude.health <= 0) {
// Reset gold to zero when player dies
gold = 0;
storage.gold = 0;
goldTxt.setText('Gold: ' + gold);
// Reset total height when player dies
totalHeight = 0;
storage.totalHeight = 0;
// Reset spawn rate multipliers when character dies
alienSpawnMultiplier = 1.0;
sawSpawnMultiplier = 1.0;
LK.showGameOver();
}
break;
}
// Update last intersecting state
bomb.lastWasIntersecting = currentIntersecting;
}
}
function checkFlashBombPlayerCollisions() {
for (var i = 0; i < flashBombs.length; i++) {
var flashBomb = flashBombs[i];
if (!flashBomb.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - flashBomb.x, 2) + Math.pow(dude.y - flashBomb.y, 2));
var currentIntersecting = distance < 60;
// Check for transition from not intersecting to intersecting
if (!flashBomb.lastWasIntersecting && currentIntersecting) {
// Create a white overlay that covers the entire screen for 3 seconds
var whiteOverlay = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 100,
scaleY: 150,
alpha: 0
});
whiteOverlay.tint = 0xffffff;
whiteOverlay.x = 1024; // Center of screen
whiteOverlay.y = 1366; // Center of screen
LK.gui.center.addChild(whiteOverlay);
// Tween the overlay to full opacity immediately, then gradually fade out over 3 seconds
tween(whiteOverlay, {
alpha: 1
}, {
duration: 50,
onFinish: function onFinish() {
// Gradually fade out the white screen over 3 seconds
tween(whiteOverlay, {
alpha: 0
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
whiteOverlay.destroy();
}
});
}
});
// Destroy the flash bomb after activation
flashBomb.active = false;
flashBomb.destroy();
flashBombs.splice(i, 1);
break;
}
// Update last intersecting state
flashBomb.lastWasIntersecting = currentIntersecting;
}
}
function checkSawPlayerCollisions() {
if (dude.invincible) return;
for (var i = 0; i < saws.length; i++) {
var saw = saws[i];
if (!saw.active) continue;
var distance = Math.sqrt(Math.pow(dude.x - saw.x, 2) + Math.pow(dude.y - saw.y, 2));
var currentIntersecting = distance < 70;
// Check for transition from not intersecting to intersecting
if (!saw.lastWasIntersecting && currentIntersecting) {
dude.takeDamage();
}
// Update last intersecting state
saw.lastWasIntersecting = currentIntersecting;
}
}
function cleanupAliens() {
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
if (alien.y > cameraY + 3000 || !alien.active) {
if (alien.active) {
alien.destroy();
}
aliens.splice(i, 1);
}
}
}
function cleanupSaws() {
for (var i = saws.length - 1; i >= 0; i--) {
var saw = saws[i];
if (saw.y > cameraY + 3000 || !saw.active) {
if (saw.active) {
saw.destroy();
}
saws.splice(i, 1);
}
}
}
function cleanupBombs() {
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
if (bomb.y > cameraY + 3000 || !bomb.active) {
if (bomb.active) {
bomb.destroy();
}
bombs.splice(i, 1);
}
}
}
function cleanupFlashBombs() {
for (var i = flashBombs.length - 1; i >= 0; i--) {
var flashBomb = flashBombs[i];
if (flashBomb.y > cameraY + 3000 || !flashBomb.active) {
if (flashBomb.active) {
flashBomb.destroy();
}
flashBombs.splice(i, 1);
}
}
}
function cleanupSpecialItems() {
for (var i = specialItems.length - 1; i >= 0; i--) {
var item = specialItems[i];
if (item.y > cameraY + 3000 || !item.active) {
if (item.active) {
item.destroy();
}
specialItems.splice(i, 1);
}
}
}
function generateMorePlatforms() {
while (lastPlatformY > cameraY - 1000) {
generateNextPlatform();
}
}
// Touch controls
var isPressed = false;
var pressedSide = 0; // -1 for left, 1 for right, 0 for center
game.down = function (x, y, obj) {
dude.jump();
isPressed = true;
// Determine which side was pressed
var screenCenter = 1024; // Half of 2048
var touchOffset = x - screenCenter;
if (touchOffset > 50) {
pressedSide = 1; // Right side
} else if (touchOffset < -50) {
pressedSide = -1; // Left side
} else {
pressedSide = 0; // Center
}
// Shoot when touching center area
if (Math.abs(touchOffset) <= 50 && LK.ticks - lastShootTime >= shootCooldown) {
dude.shoot('up');
lastShootTime = LK.ticks;
}
};
game.up = function (x, y, obj) {
isPressed = false;
pressedSide = 0;
};
// Fire button touch handlers for 4 directions
function createFireButtonHandler(button, direction) {
button.down = function (x, y, obj) {
if (LK.ticks - lastShootTime >= shootCooldown) {
dude.shoot(direction);
lastShootTime = LK.ticks;
// Visual feedback - scale animation
tween(button, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(button, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100
});
}
});
}
};
}
createFireButtonHandler(fireButtonUp, 'up');
createFireButtonHandler(fireButtonDown, 'down');
createFireButtonHandler(fireButtonLeft, 'left');
createFireButtonHandler(fireButtonRight, 'right');
// Track if space theme has been activated
var spaceThemeActivated = false;
// Track if 1500m jump boost has been applied
var jumpBoostApplied = false;
// Track if 1200m horizontal speed boost has been applied
var speedBoostApplied = false;
// Track if 4000m jumpscare has been triggered
var jumpscareTriggered = false;
// Track spawn rate multipliers that increase on restart
var alienSpawnMultiplier = 1.0;
var sawSpawnMultiplier = 1.0;
var hasRestarted = false;
var stars = [];
function createStar(x, y) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6 + Math.random() * 0.4
});
star.x = x;
star.y = y;
star.twinkleSpeed = 0.02 + Math.random() * 0.03;
star.twinkleOffset = Math.random() * Math.PI * 2;
stars.push(star);
game.addChild(star);
return star;
}
function generateStars() {
// Generate stars in the visible area and above
for (var i = 0; i < 50; i++) {
var x = Math.random() * 2048;
var y = cameraY - 1000 + Math.random() * 3732;
createStar(x, y);
}
}
// Initialize stars
generateStars();
// Main game loop
game.update = function () {
updateCamera();
checkPlatformCollisions();
checkTrampolineCollisions();
checkCoinCollisions();
checkSpecialItemCollisions();
checkBulletAlienCollisions();
checkAlienPlayerCollisions();
checkSawPlayerCollisions();
checkBombPlayerCollisions();
checkFlashBombPlayerCollisions();
generateMorePlatforms();
// Calculate current and total height
var currentHeight = Math.floor((2400 - dude.y) / 10);
var displayHeight = totalHeight + currentHeight;
// Check if player reached 4000m height for jumpscare
if (displayHeight >= 4000 && !jumpscareTriggered) {
jumpscareTriggered = true;
// Create scary alien jumpscare that covers the entire screen
var jumpscareAlien = LK.getAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 20,
alpha: 0
});
jumpscareAlien.x = 1024; // Center of screen
jumpscareAlien.y = 1366; // Center of screen
LK.gui.center.addChild(jumpscareAlien);
// Play loud scary scream sound with maximum volume for jumpscare effect
var jumpscareSound = LK.getSound('jumpscare');
jumpscareSound.volume = 1.0; // Maximum volume for scary effect
jumpscareSound.play();
// Additional sound effect layering for more intensity
LK.setTimeout(function () {
jumpscareSound.play(); // Play again for echo effect
}, 200);
// Jumpscare animation with red flash and massive scaling
LK.effects.flashScreen(0xff0000, 3000); // Red flash for 3 seconds
tween(jumpscareAlien, {
alpha: 1,
scaleX: 25,
scaleY: 25
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for a longer moment with terrifying effect
LK.setTimeout(function () {
tween(jumpscareAlien, {
alpha: 0,
scaleX: 30,
scaleY: 30
}, {
duration: 1500,
onFinish: function onFinish() {
jumpscareAlien.destroy();
}
});
}, 2000);
}
});
}
// Check if player reached height 1200 and reset to starting position
if (currentHeight >= 1200 && !speedBoostApplied) {
speedBoostApplied = true;
// Add current height to total height before reset
totalHeight += 1200;
storage.totalHeight = totalHeight;
// Activate space theme when resetting after 1200m
if (!spaceThemeActivated) {
spaceThemeActivated = true;
// Change background to dark space color
game.setBackgroundColor(0x0a0a2e); // Dark blue-purple space color
// Flash screen to indicate theme change
LK.effects.flashScreen(0x8a2be2, 1000); // Purple flash for 1 second
}
// Reset character to starting position
dude.x = 1024;
dude.y = 2400;
dude.velocityY = 0;
dude.velocityX = 0;
dude.isJumping = false;
dude.isOnPlatform = false;
// Reset camera
cameraY = 0;
game.y = -cameraY;
highestY = 2400;
// Reset current height tracking but keep total
var newDisplayHeight = totalHeight;
LK.setScore(newDisplayHeight);
scoreTxt.setText(newDisplayHeight.toString());
heightTxt.setText('Height: ' + newDisplayHeight + 'm');
// Reset boost flags for next cycle
jumpBoostApplied = false;
speedBoostApplied = false;
// Increase spawn rates on restart (100% aliens, 35% saws)
if (!hasRestarted) {
hasRestarted = true;
alienSpawnMultiplier = 2.0; // 100% increase (double the rate)
sawSpawnMultiplier = 1.35; // 35% increase
} else {
// Continue increasing on subsequent restarts
alienSpawnMultiplier += 1.0; // Additional 100% each restart
sawSpawnMultiplier += 0.35; // Additional 35% each restart
}
// Visual feedback for reset
LK.effects.flashScreen(0x00ff00, 500); // Green flash
}
// Check if player reached height 1500 and boost jump power
if (displayHeight >= 1500 && !jumpBoostApplied) {
jumpBoostApplied = true;
// Boost jump power by 1.5x (0.5x more than normal)
dude.jumpPower = 52.5; // 35 * 1.5 = 52.5
// Visual feedback for power boost
LK.effects.flashObject(dude, 0x00ff00, 500); // Green flash
}
// Update star twinkling animation
for (var s = 0; s < stars.length; s++) {
var star = stars[s];
star.alpha = 0.3 + Math.sin(LK.ticks * star.twinkleSpeed + star.twinkleOffset) * 0.4;
}
// Generate more stars as camera moves up
if (LK.ticks % 120 === 0) {
// Add new stars above the visible area
for (var i = 0; i < 10; i++) {
var x = Math.random() * 2048;
var y = cameraY - 500 + Math.random() * 500;
createStar(x, y);
}
}
// Remove platforms that are too far down
if (LK.ticks % 60 === 0) {
cleanupCoins();
cleanupBullets();
cleanupTrampolines();
cleanupAliens();
cleanupSaws();
cleanupBombs();
cleanupFlashBombs();
cleanupSpecialItems();
// Cleanup stars that are too far below
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
if (star.y > cameraY + 3000) {
star.destroy();
stars.splice(s, 1);
}
}
}
};
bir sevimli gülen yüzlü uzaylı. In-Game asset. 2d. High contrast. No shadows
coin. In-Game asset. 2d. High contrast. No shadows
trambolin. In-Game asset. 2d. High contrast. No shadows
çirkin korkutucu uzaylı. In-Game asset. 2d. High contrast. No shadows
kalp. In-Game asset. 2d. High contrast. No shadows
bir düğme ama içinde kurukafa .işareti olsun şeffaf. In-Game asset. 2d. High contrast. No shadows
platform. In-Game asset. 2d. High contrast. No shadows
güç platformu. In-Game asset. 2d. High contrast. No shadows
yuvarlak yeşil top. In-Game asset. 2d. High contrast. No shadows
sevimli bana yardım edin diyen bir uzaylı. In-Game asset. 2d. High contrast. No shadows
ufo. In-Game asset. 2d. High contrast. No shadows
bomba. In-Game asset. 2d. High contrast. No shadows
falsh bombası. In-Game asset. 2d. High contrast. No shadows