/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
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.update = function () {
// Simple rotation animation
coinGraphics.rotation += 0.1;
// Bob up and down slightly
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
// Add coins to storage
var currentCoins = storage.coins || 0;
storage.coins = currentCoins + 1;
// Play sound
LK.getSound('coin').play();
// Animate collection
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
self.platformType = type || 'normal';
var assetName = 'platform';
if (self.platformType === 'moving') {
assetName = 'movingPlatform';
} else if (self.platformType === 'bounce') {
assetName = 'bouncePlatform';
} else if (self.platformType === 'trap') {
assetName = 'trapPlatform';
}
var platformGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.moveDirection = 1;
self.moveSpeed = 2;
self.isTrapped = false;
self.trapTimer = 0;
self.update = function () {
if (self.platformType === 'moving') {
self.x += self.moveDirection * self.moveSpeed;
if (self.x <= 100 || self.x >= 1948) {
self.moveDirection *= -1;
}
} else if (self.platformType === 'trap' && self.isTrapped) {
self.trapTimer++;
if (self.trapTimer >= 60) {
// 1 second at 60 FPS
self.destroy();
// Remove from platforms array
for (var i = platforms.length - 1; i >= 0; i--) {
if (platforms[i] === self) {
platforms.splice(i, 1);
break;
}
}
}
}
};
self.getBounceForce = function () {
if (self.platformType === 'bounce') {
return -25;
}
return -18;
};
self.activateTrap = function () {
if (self.platformType === 'trap' && !self.isTrapped) {
self.isTrapped = true;
self.trapTimer = 0;
// Make platform semi-transparent to show it's breaking
tween(self, {
alpha: 0.3
}, {
duration: 1000
});
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isOnPlatform = false;
self.lastY = 0;
self.jumpsUsed = 0; // Track number of jumps used while airborne
self.maxJumps = 2; // Maximum jumps allowed while in air
self.isFallingToDeath = false; // Track if player is falling to death
self.update = function () {
// Store last position for collision detection
self.lastY = self.y;
// Store current platform if on one
var currentPlatform = null;
if (self.isOnPlatform) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerLeft = self.x - 40;
var playerRight = self.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
var playerBottom = self.y + 40;
var platformTop = platform.y - 10;
if (Math.abs(playerBottom - platformTop) <= 5 && playerRight > platformLeft && playerLeft < platformRight) {
currentPlatform = platform;
break;
}
}
}
// Apply horizontal movement
self.x += self.velocityX;
// If on a moving platform, move with it
if (currentPlatform && currentPlatform.platformType === 'moving') {
self.x += currentPlatform.moveDirection * currentPlatform.moveSpeed;
}
// Apply gravity when not on platform
if (!self.isOnPlatform) {
self.velocityY += 0.6; // Reduced gravity for higher jumps
} else {
// When on platform, gradually reduce velocities
self.velocityY = Math.max(0, self.velocityY);
}
self.y += self.velocityY;
// Apply friction to horizontal movement
self.velocityX *= 0.95;
// Wrap player horizontally from right to left
if (self.x < 40) {
self.x = 2008; // Wrap to right side
}
if (self.x > 2008) {
self.x = 40; // Wrap to left side
}
};
self.bounce = function (bounceForce) {
self.velocityY = bounceForce || -18;
self.isOnPlatform = true; // Set to true initially, will be updated in next frame
self.jumpsUsed = 0; // Reset jump counter when landing
self.isFallingToDeath = false; // Reset falling to death state when bouncing
LK.getSound('bounce').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var player;
var platforms = [];
var coins = [];
var cameraY = 0;
var nextPlatformY = 2500;
var highestY = 2732;
var gameStarted = false;
var fallStartTime = null;
var isFalling = false;
// Initialize height display
var heightTxt = new Text2('Height: 0m', {
size: 60,
fill: 0xFFD700
});
heightTxt.anchor.set(0, 0);
heightTxt.x = 120; // Position away from platform menu icon
heightTxt.y = 20;
LK.gui.topLeft.addChild(heightTxt);
// Initialize coins display
var pointsTxt = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
pointsTxt.anchor.set(1, 0);
pointsTxt.y = 20;
LK.gui.topRight.addChild(pointsTxt);
// Initialize score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFD700
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
// Create player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2560; // Position player on top of the starting platform (2600 - 40 = 2560)
player.isOnPlatform = true; // Start on platform
// Create coin function
function createCoin(x, y) {
var coin = new Coin();
coin.x = x;
coin.y = y;
coins.push(coin);
game.addChild(coin);
return coin;
}
// Create initial platforms
function createPlatform(x, y, type) {
var platform = new Platform(type);
platform.x = x;
platform.y = y;
platforms.push(platform);
game.addChild(platform);
// 30% chance to add a coin on normal platforms (not on trap platforms)
if (type !== 'trap' && Math.random() < 0.3) {
createCoin(x, y - 40); // Position coin above platform
}
return platform;
}
// Generate initial platforms
var startingPlatform = createPlatform(1024, 2600, 'normal');
startingPlatform.isStartingPlatform = true;
for (var i = 0; i < 15; i++) {
var x = Math.random() * 1600 + 200;
var y = nextPlatformY - Math.random() * 200 - 150; // Increased vertical spacing between platforms
var platformType = 'normal';
if (Math.random() < 0.2) {
platformType = 'moving';
} else if (Math.random() < 0.1) {
platformType = 'bounce';
} else if (Math.random() < 0.15) {
platformType = 'trap';
}
createPlatform(x, y, platformType);
nextPlatformY = y;
}
function generateNewPlatforms() {
while (nextPlatformY > cameraY - 1000) {
var x = Math.random() * 1600 + 200;
var y = nextPlatformY - Math.random() * 250 - 180; // Increased spacing for more challenging platform jumping
var platformType = 'normal';
var random = Math.random();
if (random < 0.25) {
platformType = 'moving';
} else if (random < 0.15) {
platformType = 'bounce';
} else if (random < 0.2) {
platformType = 'trap';
}
createPlatform(x, y, platformType);
nextPlatformY = y;
}
}
function updateCamera() {
var targetCameraY = player.y - 1800;
if (targetCameraY < cameraY) {
cameraY = targetCameraY;
}
game.y = -cameraY;
}
function updateScore() {
if (player.y < highestY) {
highestY = player.y;
var score = Math.floor((2732 - highestY) / 10);
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
var height = Math.floor(score / 10);
heightTxt.setText('Height: ' + height + 'm');
}
}
function checkPlatformCollisions() {
// Don't check collisions if player is falling to death
if (player.isFallingToDeath) {
return;
}
// Check for platform collision when falling
if (player.velocityY > 0) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerBottom = player.y + 40;
var platformTop = platform.y - 10;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
// Check if player is landing on platform from above
if (playerBottom >= platformTop && playerBottom <= platformTop + 25 && playerRight > platformLeft && playerLeft < platformRight && player.lastY + 40 <= platformTop) {
// Check if this is a trap platform
if (platform.platformType === 'trap' && !platform.isTrapped) {
platform.activateTrap();
// Player falls through trap platform - don't land on it
player.isFallingToDeath = true; // Start falling to death
return;
}
// Don't land on already trapped platforms
if (platform.platformType === 'trap' && platform.isTrapped) {
player.isFallingToDeath = true; // Start falling to death
return;
}
player.y = platformTop - 40;
player.isOnPlatform = true;
player.velocityY = 0; // Stop falling, prepare for immediate auto-jump
player.jumpsUsed = 0; // Reset jump counter when landing
player.isFallingToDeath = false; // Reset falling to death state
// Only bounce on bounce platforms
if (platform.platformType === 'bounce') {
player.bounce(platform.getBounceForce());
}
return;
}
}
}
// Check if player is still on a platform (for standing)
if (player.velocityY >= 0 && !player.isFallingToDeath) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerBottom = player.y + 40;
var platformTop = platform.y - 10;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
// Check if player is standing on platform
if (Math.abs(playerBottom - platformTop) <= 5 && playerRight > platformLeft && playerLeft < platformRight) {
// Don't stand on trapped platforms
if (platform.platformType === 'trap' && platform.isTrapped) {
player.isFallingToDeath = true; // Start falling to death
return;
}
player.y = platformTop - 40;
player.isOnPlatform = true;
player.jumpsUsed = 0; // Reset jump counter when on platform
player.isFallingToDeath = false; // Reset falling to death state
// For starting platform, ensure player can stay indefinitely
if (platform.isStartingPlatform) {
player.velocityY = 0; // Completely stop vertical movement on starting platform
} else {
player.velocityY = Math.max(0, player.velocityY); // Prevent falling through
}
return;
}
}
}
// If no platform found, player is not on platform
player.isOnPlatform = false;
}
function checkCoinCollisions() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.collected) continue;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var playerTop = player.y - 40;
var playerBottom = player.y + 40;
var coinLeft = coin.x - 20;
var coinRight = coin.x + 20;
var coinTop = coin.y - 20;
var coinBottom = coin.y + 20;
// Check collision
if (playerRight > coinLeft && playerLeft < coinRight && playerBottom > coinTop && playerTop < coinBottom) {
coin.collect();
coins.splice(i, 1);
}
}
}
function updatePointsDisplay() {
var currentCoins = storage.coins || 0;
pointsTxt.setText('Coins: ' + currentCoins);
}
function cleanupCoins() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > cameraY + 3000) {
coin.destroy();
coins.splice(i, 1);
}
}
}
function cleanupPlatforms() {
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.y > cameraY + 3000) {
platform.destroy();
platforms.splice(i, 1);
}
}
}
function handleInput() {
// Input handling now done through click events
}
// Game controls - jump toward clicked position
game.down = function (x, y, obj) {
gameStarted = true;
// Check if player has jumps remaining
if (player.jumpsUsed >= player.maxJumps) {
return; // Cannot jump anymore
}
// Calculate direction toward clicked position
var deltaX = x - player.x;
var deltaY = y - player.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Normalize direction and apply jump force
if (distance > 0) {
var jumpForce = 22; // Increased jump force for higher jumps
var horizontalForce = deltaX / distance * jumpForce * 0.8; // Reduced horizontal component
var verticalForce = Math.min(-18, deltaY / distance * jumpForce); // Increased vertical force for higher jumps
player.velocityX = horizontalForce;
player.velocityY = verticalForce;
player.isOnPlatform = false;
player.jumpsUsed++; // Increment jump counter
LK.getSound('bounce').play();
// Removed scaling animation during jumps
}
};
game.up = function (x, y, obj) {
// No longer needed for directional movement
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
handleInput();
checkPlatformCollisions();
checkCoinCollisions();
updateCamera();
updateScore();
updatePointsDisplay();
generateNewPlatforms();
cleanupPlatforms();
cleanupCoins();
// Track falling state
var wasOnPlatform = player.isOnPlatform;
var currentlyFalling = player.velocityY > 0 && !player.isOnPlatform;
// Start fall timer when player starts falling
if (!isFalling && currentlyFalling) {
isFalling = true;
fallStartTime = LK.ticks;
}
// Reset fall timer when player lands or bounces up
if (isFalling && (!currentlyFalling || player.velocityY < 0)) {
isFalling = false;
fallStartTime = null;
}
// Check for 2-second fall timer (120 ticks = 2 seconds at 60 FPS)
if (isFalling && fallStartTime !== null && LK.ticks - fallStartTime >= 120) {
LK.getSound('fall').play();
LK.showGameOver();
}
// Check for game over (player falls too far below camera)
if (player.y > cameraY + 2900) {
LK.getSound('fall').play();
LK.showGameOver();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
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.update = function () {
// Simple rotation animation
coinGraphics.rotation += 0.1;
// Bob up and down slightly
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
// Add coins to storage
var currentCoins = storage.coins || 0;
storage.coins = currentCoins + 1;
// Play sound
LK.getSound('coin').play();
// Animate collection
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
self.platformType = type || 'normal';
var assetName = 'platform';
if (self.platformType === 'moving') {
assetName = 'movingPlatform';
} else if (self.platformType === 'bounce') {
assetName = 'bouncePlatform';
} else if (self.platformType === 'trap') {
assetName = 'trapPlatform';
}
var platformGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.moveDirection = 1;
self.moveSpeed = 2;
self.isTrapped = false;
self.trapTimer = 0;
self.update = function () {
if (self.platformType === 'moving') {
self.x += self.moveDirection * self.moveSpeed;
if (self.x <= 100 || self.x >= 1948) {
self.moveDirection *= -1;
}
} else if (self.platformType === 'trap' && self.isTrapped) {
self.trapTimer++;
if (self.trapTimer >= 60) {
// 1 second at 60 FPS
self.destroy();
// Remove from platforms array
for (var i = platforms.length - 1; i >= 0; i--) {
if (platforms[i] === self) {
platforms.splice(i, 1);
break;
}
}
}
}
};
self.getBounceForce = function () {
if (self.platformType === 'bounce') {
return -25;
}
return -18;
};
self.activateTrap = function () {
if (self.platformType === 'trap' && !self.isTrapped) {
self.isTrapped = true;
self.trapTimer = 0;
// Make platform semi-transparent to show it's breaking
tween(self, {
alpha: 0.3
}, {
duration: 1000
});
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isOnPlatform = false;
self.lastY = 0;
self.jumpsUsed = 0; // Track number of jumps used while airborne
self.maxJumps = 2; // Maximum jumps allowed while in air
self.isFallingToDeath = false; // Track if player is falling to death
self.update = function () {
// Store last position for collision detection
self.lastY = self.y;
// Store current platform if on one
var currentPlatform = null;
if (self.isOnPlatform) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerLeft = self.x - 40;
var playerRight = self.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
var playerBottom = self.y + 40;
var platformTop = platform.y - 10;
if (Math.abs(playerBottom - platformTop) <= 5 && playerRight > platformLeft && playerLeft < platformRight) {
currentPlatform = platform;
break;
}
}
}
// Apply horizontal movement
self.x += self.velocityX;
// If on a moving platform, move with it
if (currentPlatform && currentPlatform.platformType === 'moving') {
self.x += currentPlatform.moveDirection * currentPlatform.moveSpeed;
}
// Apply gravity when not on platform
if (!self.isOnPlatform) {
self.velocityY += 0.6; // Reduced gravity for higher jumps
} else {
// When on platform, gradually reduce velocities
self.velocityY = Math.max(0, self.velocityY);
}
self.y += self.velocityY;
// Apply friction to horizontal movement
self.velocityX *= 0.95;
// Wrap player horizontally from right to left
if (self.x < 40) {
self.x = 2008; // Wrap to right side
}
if (self.x > 2008) {
self.x = 40; // Wrap to left side
}
};
self.bounce = function (bounceForce) {
self.velocityY = bounceForce || -18;
self.isOnPlatform = true; // Set to true initially, will be updated in next frame
self.jumpsUsed = 0; // Reset jump counter when landing
self.isFallingToDeath = false; // Reset falling to death state when bouncing
LK.getSound('bounce').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var player;
var platforms = [];
var coins = [];
var cameraY = 0;
var nextPlatformY = 2500;
var highestY = 2732;
var gameStarted = false;
var fallStartTime = null;
var isFalling = false;
// Initialize height display
var heightTxt = new Text2('Height: 0m', {
size: 60,
fill: 0xFFD700
});
heightTxt.anchor.set(0, 0);
heightTxt.x = 120; // Position away from platform menu icon
heightTxt.y = 20;
LK.gui.topLeft.addChild(heightTxt);
// Initialize coins display
var pointsTxt = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
pointsTxt.anchor.set(1, 0);
pointsTxt.y = 20;
LK.gui.topRight.addChild(pointsTxt);
// Initialize score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFD700
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
// Create player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2560; // Position player on top of the starting platform (2600 - 40 = 2560)
player.isOnPlatform = true; // Start on platform
// Create coin function
function createCoin(x, y) {
var coin = new Coin();
coin.x = x;
coin.y = y;
coins.push(coin);
game.addChild(coin);
return coin;
}
// Create initial platforms
function createPlatform(x, y, type) {
var platform = new Platform(type);
platform.x = x;
platform.y = y;
platforms.push(platform);
game.addChild(platform);
// 30% chance to add a coin on normal platforms (not on trap platforms)
if (type !== 'trap' && Math.random() < 0.3) {
createCoin(x, y - 40); // Position coin above platform
}
return platform;
}
// Generate initial platforms
var startingPlatform = createPlatform(1024, 2600, 'normal');
startingPlatform.isStartingPlatform = true;
for (var i = 0; i < 15; i++) {
var x = Math.random() * 1600 + 200;
var y = nextPlatformY - Math.random() * 200 - 150; // Increased vertical spacing between platforms
var platformType = 'normal';
if (Math.random() < 0.2) {
platformType = 'moving';
} else if (Math.random() < 0.1) {
platformType = 'bounce';
} else if (Math.random() < 0.15) {
platformType = 'trap';
}
createPlatform(x, y, platformType);
nextPlatformY = y;
}
function generateNewPlatforms() {
while (nextPlatformY > cameraY - 1000) {
var x = Math.random() * 1600 + 200;
var y = nextPlatformY - Math.random() * 250 - 180; // Increased spacing for more challenging platform jumping
var platformType = 'normal';
var random = Math.random();
if (random < 0.25) {
platformType = 'moving';
} else if (random < 0.15) {
platformType = 'bounce';
} else if (random < 0.2) {
platformType = 'trap';
}
createPlatform(x, y, platformType);
nextPlatformY = y;
}
}
function updateCamera() {
var targetCameraY = player.y - 1800;
if (targetCameraY < cameraY) {
cameraY = targetCameraY;
}
game.y = -cameraY;
}
function updateScore() {
if (player.y < highestY) {
highestY = player.y;
var score = Math.floor((2732 - highestY) / 10);
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
var height = Math.floor(score / 10);
heightTxt.setText('Height: ' + height + 'm');
}
}
function checkPlatformCollisions() {
// Don't check collisions if player is falling to death
if (player.isFallingToDeath) {
return;
}
// Check for platform collision when falling
if (player.velocityY > 0) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerBottom = player.y + 40;
var platformTop = platform.y - 10;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
// Check if player is landing on platform from above
if (playerBottom >= platformTop && playerBottom <= platformTop + 25 && playerRight > platformLeft && playerLeft < platformRight && player.lastY + 40 <= platformTop) {
// Check if this is a trap platform
if (platform.platformType === 'trap' && !platform.isTrapped) {
platform.activateTrap();
// Player falls through trap platform - don't land on it
player.isFallingToDeath = true; // Start falling to death
return;
}
// Don't land on already trapped platforms
if (platform.platformType === 'trap' && platform.isTrapped) {
player.isFallingToDeath = true; // Start falling to death
return;
}
player.y = platformTop - 40;
player.isOnPlatform = true;
player.velocityY = 0; // Stop falling, prepare for immediate auto-jump
player.jumpsUsed = 0; // Reset jump counter when landing
player.isFallingToDeath = false; // Reset falling to death state
// Only bounce on bounce platforms
if (platform.platformType === 'bounce') {
player.bounce(platform.getBounceForce());
}
return;
}
}
}
// Check if player is still on a platform (for standing)
if (player.velocityY >= 0 && !player.isFallingToDeath) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var playerBottom = player.y + 40;
var platformTop = platform.y - 10;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var platformLeft = platform.x - 100;
var platformRight = platform.x + 100;
// Check if player is standing on platform
if (Math.abs(playerBottom - platformTop) <= 5 && playerRight > platformLeft && playerLeft < platformRight) {
// Don't stand on trapped platforms
if (platform.platformType === 'trap' && platform.isTrapped) {
player.isFallingToDeath = true; // Start falling to death
return;
}
player.y = platformTop - 40;
player.isOnPlatform = true;
player.jumpsUsed = 0; // Reset jump counter when on platform
player.isFallingToDeath = false; // Reset falling to death state
// For starting platform, ensure player can stay indefinitely
if (platform.isStartingPlatform) {
player.velocityY = 0; // Completely stop vertical movement on starting platform
} else {
player.velocityY = Math.max(0, player.velocityY); // Prevent falling through
}
return;
}
}
}
// If no platform found, player is not on platform
player.isOnPlatform = false;
}
function checkCoinCollisions() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.collected) continue;
var playerLeft = player.x - 40;
var playerRight = player.x + 40;
var playerTop = player.y - 40;
var playerBottom = player.y + 40;
var coinLeft = coin.x - 20;
var coinRight = coin.x + 20;
var coinTop = coin.y - 20;
var coinBottom = coin.y + 20;
// Check collision
if (playerRight > coinLeft && playerLeft < coinRight && playerBottom > coinTop && playerTop < coinBottom) {
coin.collect();
coins.splice(i, 1);
}
}
}
function updatePointsDisplay() {
var currentCoins = storage.coins || 0;
pointsTxt.setText('Coins: ' + currentCoins);
}
function cleanupCoins() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > cameraY + 3000) {
coin.destroy();
coins.splice(i, 1);
}
}
}
function cleanupPlatforms() {
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.y > cameraY + 3000) {
platform.destroy();
platforms.splice(i, 1);
}
}
}
function handleInput() {
// Input handling now done through click events
}
// Game controls - jump toward clicked position
game.down = function (x, y, obj) {
gameStarted = true;
// Check if player has jumps remaining
if (player.jumpsUsed >= player.maxJumps) {
return; // Cannot jump anymore
}
// Calculate direction toward clicked position
var deltaX = x - player.x;
var deltaY = y - player.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Normalize direction and apply jump force
if (distance > 0) {
var jumpForce = 22; // Increased jump force for higher jumps
var horizontalForce = deltaX / distance * jumpForce * 0.8; // Reduced horizontal component
var verticalForce = Math.min(-18, deltaY / distance * jumpForce); // Increased vertical force for higher jumps
player.velocityX = horizontalForce;
player.velocityY = verticalForce;
player.isOnPlatform = false;
player.jumpsUsed++; // Increment jump counter
LK.getSound('bounce').play();
// Removed scaling animation during jumps
}
};
game.up = function (x, y, obj) {
// No longer needed for directional movement
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
handleInput();
checkPlatformCollisions();
checkCoinCollisions();
updateCamera();
updateScore();
updatePointsDisplay();
generateNewPlatforms();
cleanupPlatforms();
cleanupCoins();
// Track falling state
var wasOnPlatform = player.isOnPlatform;
var currentlyFalling = player.velocityY > 0 && !player.isOnPlatform;
// Start fall timer when player starts falling
if (!isFalling && currentlyFalling) {
isFalling = true;
fallStartTime = LK.ticks;
}
// Reset fall timer when player lands or bounces up
if (isFalling && (!currentlyFalling || player.velocityY < 0)) {
isFalling = false;
fallStartTime = null;
}
// Check for 2-second fall timer (120 ticks = 2 seconds at 60 FPS)
if (isFalling && fallStartTime !== null && LK.ticks - fallStartTime >= 120) {
LK.getSound('fall').play();
LK.showGameOver();
}
// Check for game over (player falls too far below camera)
if (player.y > cameraY + 2900) {
LK.getSound('fall').play();
LK.showGameOver();
}
};