/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Obstacle = Container.expand(function (type, x, y) {
var self = Container.call(this);
self.obstacleType = type || 'spike';
if (self.obstacleType === 'spike') {
var obstacleGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1.0
});
} else if (self.obstacleType === 'platform') {
var obstacleGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.x = x || 0;
self.y = y || 0;
self.speed = -5;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Orb = Container.expand(function (x, y) {
var self = Container.call(this);
var orbGraphics = self.attachAsset('orb', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x || 0;
self.y = y || 0;
self.speed = -5;
self.collected = false;
self.update = function () {
self.x += self.speed;
// Gentle floating animation
orbGraphics.y = Math.sin(LK.ticks * 0.1) * 10;
// Gentle rotation
orbGraphics.rotation += 0.05;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.playerGraphics = playerGraphics; // Reference for icon switching
// Invincibility overlay (above player)
var invOverlay = self.attachAsset('Invincibility-overlay', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -60,
// above player, adjust as needed
visible: false,
alpha: 1
});
// Invincibility state and timer
self.isInvincible = false;
self.invincibleTicks = 0;
self.setInvincible = function (durationTicks) {
self.isInvincible = true;
self.invincibleTicks = durationTicks;
// Show overlay to indicate invincibility
if (powerOverlay) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.7;
}
// Show invincibility overlay
if (invOverlay) {
invOverlay.visible = true;
}
};
self.clearInvincible = function () {
self.isInvincible = false;
self.invincibleTicks = 0;
if (powerOverlay) {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5;
}
// Hide invincibility overlay
if (invOverlay) {
invOverlay.visible = false;
}
};
self.setIcon = function (iconId) {
// Remove old graphics
if (self.playerGraphics && self.playerGraphics.parent) {
self.playerGraphics.parent.removeChild(self.playerGraphics);
}
// Add new graphics
var newGfx = self.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 0.5
});
self.playerGraphics = newGfx;
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
var powerOverlay = self.attachAsset('Orb_powerup_overlay_on_player', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
alpha: 0.5
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -18;
self.powerJumpPower = -28;
self.hasPowerJump = false;
self.isGrounded = false;
self.groundY = 2400;
self.jump = function () {
if (self.isGrounded) {
if (self.hasPowerJump) {
self.velocityY = self.powerJumpPower;
self.hasPowerJump = false;
// Fade out power overlay with tween
tween(powerOverlay, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5; // Reset alpha for next use
}
});
// Flash player blue to indicate power jump used
LK.effects.flashObject(self, 0x00ffff, 300);
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
} else {
self.velocityY = self.jumpPower;
}
self.isGrounded = false;
// Start spinning on jump
self.spinSpeed = 0.25; // Always spin right, or randomize for variety
LK.getSound('jump').play();
}
};
self.showPowerOverlay = function () {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
self.hidePowerOverlay = function () {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5; // Reset alpha for next use
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
self.update = function () {
// Invincibility timer tick down
if (self.isInvincible) {
if (self.invincibleTicks > 0) {
self.invincibleTicks--;
if (self.invincibleTicks === 0) {
self.clearInvincible();
}
}
// Ensure invincibility overlay is visible
if (invOverlay) invOverlay.visible = true;
} else {
// Ensure invincibility overlay is hidden
if (invOverlay) invOverlay.visible = false;
}
// Only show rainbow overlay (powerOverlay) if orb powerup is active
if (powerOverlay) {
if (self.hasPowerJump) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
} else {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5;
}
}
// --- SPIN LOGIC START ---
if (typeof self.lastWasGrounded === "undefined") self.lastWasGrounded = self.isGrounded;
if (typeof self.spinSpeed === "undefined") self.spinSpeed = 0;
if (typeof self.currentRotation === "undefined") self.currentRotation = 0;
// If airborne, spin
if (!self.isGrounded) {
// Spin direction: positive for right, negative for left (could be random or based on last jump, here always right)
if (self.spinSpeed === 0) {
// Start spinning with a default speed if just left ground
self.spinSpeed = 0.25;
}
self.currentRotation += self.spinSpeed;
if (self.playerGraphics) self.playerGraphics.rotation = self.currentRotation;
} else {
// On ground, stop spinning but keep rotation
if (!self.lastWasGrounded) {
// Just landed, keep rotation and stop spin
self.spinSpeed = 0;
if (self.playerGraphics) self.playerGraphics.rotation = self.currentRotation;
}
}
// Track last grounded state for transition
self.lastWasGrounded = self.isGrounded;
// --- SPIN LOGIC END ---
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocityY = 0;
self.isGrounded = true;
}
// Screen bounds
if (self.y < 0) {
self.y = 0;
self.velocityY = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
var player;
var obstacles = [];
var orbs = [];
var gameSpeed = 5;
var spawnTimer = 0;
var orbSpawnTimer = 0;
var distance = 0;
var gameStarted = false;
var lastObstacleX = 0;
// Background
var bg = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create player
player = game.addChild(new Player());
player.x = 300;
player.y = 2400;
player.groundY = 2400;
// Score display
var scoreText = new Text2('Distance: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
// Icon kit button (top right, 100x100 safe zone)
var iconKitBtn = LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: -60,
y: 60,
scaleX: 0.7,
scaleY: 0.7
});
iconKitBtn.interactive = true;
iconKitBtn.buttonMode = true;
LK.gui.topRight.addChild(iconKitBtn);
// Icon selection overlay (hidden by default)
var iconOverlayBg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
iconOverlayBg.alpha = 0.7;
iconOverlayBg.visible = false;
var iconChoices = [];
var iconIds = ['player', 'Icon2', 'Icon3', 'Icon4'];
var iconSelectedIndex = 0; // 0 = default
for (var i = 0; i < 4; i++) {
var icon = LK.getAsset(iconIds[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + (i - 1.5) * 220,
y: 2732 / 2,
scaleX: 1.5,
scaleY: 1.5
});
icon.visible = false;
icon.interactive = true;
icon.buttonMode = true;
icon.iconIndex = i;
iconChoices.push(icon);
}
function showIconOverlay() {
iconOverlayBg.visible = true;
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].visible = true;
}
// Make player invincible while overlay is open (very long duration, will be cleared on hide)
if (player && player.setInvincible) {
player.setInvincible(999999); // Effectively infinite until overlay is closed
}
// Game is automatically paused by LK when overlays are shown
}
function hideIconOverlay() {
iconOverlayBg.visible = false;
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].visible = false;
}
// Grant 5 seconds (300 ticks) invincibility after overlay closes
if (player && player.setInvincible) {
player.setInvincible(300);
}
// Game is automatically resumed by LK when overlays are hidden
}
// Add overlay and icons to game (above everything)
game.addChild(iconOverlayBg);
for (var i = 0; i < iconChoices.length; i++) {
game.addChild(iconChoices[i]);
}
// Instructions
var instructionText = new Text2('TAP TO JUMP', {
size: 80,
fill: 0xFFFF00
});
instructionText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionText);
// Icon kit button event
iconKitBtn.down = function (x, y, obj) {
if (!iconOverlayBg.visible) {
showIconOverlay();
}
};
// Icon selection events
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].down = function (x, y, obj) {
var idx = this.iconIndex;
iconSelectedIndex = idx;
// Change player icon
if (player && player.setIcon) {
player.setIcon(iconIds[idx]);
}
hideIconOverlay();
};
}
// Hide overlay if background is tapped
iconOverlayBg.down = function (x, y, obj) {
hideIconOverlay();
};
function startGame() {
if (!gameStarted) {
gameStarted = true;
instructionText.visible = false;
LK.playMusic('bgMusic');
}
}
function resetGame() {
// Reset player
if (player && player.setIcon && typeof iconSelectedIndex !== "undefined" && typeof iconIds !== "undefined") {
player.setIcon(iconIds[iconSelectedIndex]);
}
player.x = 300;
player.y = 2400;
player.velocityY = 0;
player.isGrounded = true;
// Reset spin state
player.spinSpeed = 0;
player.currentRotation = 0;
if (player.playerGraphics) player.playerGraphics.rotation = 0;
// Clear obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
// Clear orbs
for (var i = orbs.length - 1; i >= 0; i--) {
orbs[i].destroy();
}
orbs = [];
// Reset player power jump
player.hasPowerJump = false;
// Hide power overlay
player.hidePowerOverlay();
// Reset game state
distance = 0;
spawnTimer = 0;
lastObstacleX = 0;
gameStarted = false;
instructionText.visible = true;
// Flash effect
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('death').play();
}
function spawnOrb() {
var orbX = 2048 + 100;
var orbY = 2000 + Math.random() * 400; // Random height between ground and air
var orb = new Orb(orbX, orbY);
orbs.push(orb);
game.addChild(orb);
}
function spawnObstacle() {
var minGap = 300;
var maxGap = 500;
var gap = minGap + Math.random() * (maxGap - minGap);
if (lastObstacleX === 0 || 2048 - lastObstacleX > gap) {
var obstacleX = 2048 + 100;
var obstacleY = 2400;
// Random obstacle type
var obstacleType = Math.random() < 0.5 ? 'spike' : 'platform'; // Lower spike chance to 50%
if (obstacleType === 'platform') {
obstacleY = 2200 + Math.random() * 200;
}
var obstacle = new Obstacle(obstacleType, obstacleX, obstacleY);
obstacles.push(obstacle);
game.addChild(obstacle);
lastObstacleX = obstacleX;
}
}
function checkCollisions() {
// Check orb collisions
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
if (!orb.collected && player.intersects(orb)) {
orb.collected = true;
player.hasPowerJump = true;
player.showPowerOverlay();
powerOverlay = player.children[player.children.length - 1];
if (powerOverlay) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
}
// Flash player cyan to indicate power-up collected
LK.effects.flashObject(player, 0x00ffff, 500);
orb.destroy();
orbs.splice(i, 1);
continue;
}
// Remove off-screen orbs
if (orb.x < -100) {
orb.destroy();
orbs.splice(i, 1);
}
}
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (player.intersects(obstacle)) {
if (!player.isInvincible) {
resetGame();
return;
}
// If invincible, ignore collision and continue
}
// Remove off-screen obstacles
if (obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
}
player.jump();
};
// Update game
game.update = function () {
if (!gameStarted) return;
// Update distance
distance += gameSpeed;
scoreText.setText('Distance: ' + Math.floor(distance / 10));
// Spawn obstacles
spawnTimer++;
if (spawnTimer % 45 === 0) {
// Spawn every 45 ticks (~0.75 seconds)
spawnObstacle();
}
// Spawn orbs occasionally
orbSpawnTimer++;
if (orbSpawnTimer % 120 === 0) {
// Spawn every 120 ticks (~2 seconds)
spawnOrb();
}
// Update obstacle positions
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
obstacle.x -= gameSpeed;
// Track last obstacle position for gap calculation
if (obstacle.x < 2048 && obstacle.x > lastObstacleX - 2048) {
lastObstacleX = obstacle.x;
}
}
// Update orb positions
for (var i = 0; i < orbs.length; i++) {
var orb = orbs[i];
orb.x -= gameSpeed;
}
// Check collisions
checkCollisions();
// Increase difficulty gradually
if (LK.ticks % 900 === 0) {
// Every 15 seconds
gameSpeed += 0.3;
gameSpeed = Math.min(gameSpeed, 10); // Cap max speed
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Obstacle = Container.expand(function (type, x, y) {
var self = Container.call(this);
self.obstacleType = type || 'spike';
if (self.obstacleType === 'spike') {
var obstacleGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1.0
});
} else if (self.obstacleType === 'platform') {
var obstacleGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.x = x || 0;
self.y = y || 0;
self.speed = -5;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Orb = Container.expand(function (x, y) {
var self = Container.call(this);
var orbGraphics = self.attachAsset('orb', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x || 0;
self.y = y || 0;
self.speed = -5;
self.collected = false;
self.update = function () {
self.x += self.speed;
// Gentle floating animation
orbGraphics.y = Math.sin(LK.ticks * 0.1) * 10;
// Gentle rotation
orbGraphics.rotation += 0.05;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.playerGraphics = playerGraphics; // Reference for icon switching
// Invincibility overlay (above player)
var invOverlay = self.attachAsset('Invincibility-overlay', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -60,
// above player, adjust as needed
visible: false,
alpha: 1
});
// Invincibility state and timer
self.isInvincible = false;
self.invincibleTicks = 0;
self.setInvincible = function (durationTicks) {
self.isInvincible = true;
self.invincibleTicks = durationTicks;
// Show overlay to indicate invincibility
if (powerOverlay) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.7;
}
// Show invincibility overlay
if (invOverlay) {
invOverlay.visible = true;
}
};
self.clearInvincible = function () {
self.isInvincible = false;
self.invincibleTicks = 0;
if (powerOverlay) {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5;
}
// Hide invincibility overlay
if (invOverlay) {
invOverlay.visible = false;
}
};
self.setIcon = function (iconId) {
// Remove old graphics
if (self.playerGraphics && self.playerGraphics.parent) {
self.playerGraphics.parent.removeChild(self.playerGraphics);
}
// Add new graphics
var newGfx = self.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 0.5
});
self.playerGraphics = newGfx;
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
var powerOverlay = self.attachAsset('Orb_powerup_overlay_on_player', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
alpha: 0.5
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -18;
self.powerJumpPower = -28;
self.hasPowerJump = false;
self.isGrounded = false;
self.groundY = 2400;
self.jump = function () {
if (self.isGrounded) {
if (self.hasPowerJump) {
self.velocityY = self.powerJumpPower;
self.hasPowerJump = false;
// Fade out power overlay with tween
tween(powerOverlay, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5; // Reset alpha for next use
}
});
// Flash player blue to indicate power jump used
LK.effects.flashObject(self, 0x00ffff, 300);
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
} else {
self.velocityY = self.jumpPower;
}
self.isGrounded = false;
// Start spinning on jump
self.spinSpeed = 0.25; // Always spin right, or randomize for variety
LK.getSound('jump').play();
}
};
self.showPowerOverlay = function () {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
self.hidePowerOverlay = function () {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5; // Reset alpha for next use
// Ensure player icon is always fully opaque
if (self.playerGraphics) {
self.playerGraphics.alpha = 1;
}
};
self.update = function () {
// Invincibility timer tick down
if (self.isInvincible) {
if (self.invincibleTicks > 0) {
self.invincibleTicks--;
if (self.invincibleTicks === 0) {
self.clearInvincible();
}
}
// Ensure invincibility overlay is visible
if (invOverlay) invOverlay.visible = true;
} else {
// Ensure invincibility overlay is hidden
if (invOverlay) invOverlay.visible = false;
}
// Only show rainbow overlay (powerOverlay) if orb powerup is active
if (powerOverlay) {
if (self.hasPowerJump) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
} else {
powerOverlay.visible = false;
powerOverlay.alpha = 0.5;
}
}
// --- SPIN LOGIC START ---
if (typeof self.lastWasGrounded === "undefined") self.lastWasGrounded = self.isGrounded;
if (typeof self.spinSpeed === "undefined") self.spinSpeed = 0;
if (typeof self.currentRotation === "undefined") self.currentRotation = 0;
// If airborne, spin
if (!self.isGrounded) {
// Spin direction: positive for right, negative for left (could be random or based on last jump, here always right)
if (self.spinSpeed === 0) {
// Start spinning with a default speed if just left ground
self.spinSpeed = 0.25;
}
self.currentRotation += self.spinSpeed;
if (self.playerGraphics) self.playerGraphics.rotation = self.currentRotation;
} else {
// On ground, stop spinning but keep rotation
if (!self.lastWasGrounded) {
// Just landed, keep rotation and stop spin
self.spinSpeed = 0;
if (self.playerGraphics) self.playerGraphics.rotation = self.currentRotation;
}
}
// Track last grounded state for transition
self.lastWasGrounded = self.isGrounded;
// --- SPIN LOGIC END ---
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocityY = 0;
self.isGrounded = true;
}
// Screen bounds
if (self.y < 0) {
self.y = 0;
self.velocityY = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
var player;
var obstacles = [];
var orbs = [];
var gameSpeed = 5;
var spawnTimer = 0;
var orbSpawnTimer = 0;
var distance = 0;
var gameStarted = false;
var lastObstacleX = 0;
// Background
var bg = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create player
player = game.addChild(new Player());
player.x = 300;
player.y = 2400;
player.groundY = 2400;
// Score display
var scoreText = new Text2('Distance: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
// Icon kit button (top right, 100x100 safe zone)
var iconKitBtn = LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: -60,
y: 60,
scaleX: 0.7,
scaleY: 0.7
});
iconKitBtn.interactive = true;
iconKitBtn.buttonMode = true;
LK.gui.topRight.addChild(iconKitBtn);
// Icon selection overlay (hidden by default)
var iconOverlayBg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
iconOverlayBg.alpha = 0.7;
iconOverlayBg.visible = false;
var iconChoices = [];
var iconIds = ['player', 'Icon2', 'Icon3', 'Icon4'];
var iconSelectedIndex = 0; // 0 = default
for (var i = 0; i < 4; i++) {
var icon = LK.getAsset(iconIds[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + (i - 1.5) * 220,
y: 2732 / 2,
scaleX: 1.5,
scaleY: 1.5
});
icon.visible = false;
icon.interactive = true;
icon.buttonMode = true;
icon.iconIndex = i;
iconChoices.push(icon);
}
function showIconOverlay() {
iconOverlayBg.visible = true;
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].visible = true;
}
// Make player invincible while overlay is open (very long duration, will be cleared on hide)
if (player && player.setInvincible) {
player.setInvincible(999999); // Effectively infinite until overlay is closed
}
// Game is automatically paused by LK when overlays are shown
}
function hideIconOverlay() {
iconOverlayBg.visible = false;
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].visible = false;
}
// Grant 5 seconds (300 ticks) invincibility after overlay closes
if (player && player.setInvincible) {
player.setInvincible(300);
}
// Game is automatically resumed by LK when overlays are hidden
}
// Add overlay and icons to game (above everything)
game.addChild(iconOverlayBg);
for (var i = 0; i < iconChoices.length; i++) {
game.addChild(iconChoices[i]);
}
// Instructions
var instructionText = new Text2('TAP TO JUMP', {
size: 80,
fill: 0xFFFF00
});
instructionText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionText);
// Icon kit button event
iconKitBtn.down = function (x, y, obj) {
if (!iconOverlayBg.visible) {
showIconOverlay();
}
};
// Icon selection events
for (var i = 0; i < iconChoices.length; i++) {
iconChoices[i].down = function (x, y, obj) {
var idx = this.iconIndex;
iconSelectedIndex = idx;
// Change player icon
if (player && player.setIcon) {
player.setIcon(iconIds[idx]);
}
hideIconOverlay();
};
}
// Hide overlay if background is tapped
iconOverlayBg.down = function (x, y, obj) {
hideIconOverlay();
};
function startGame() {
if (!gameStarted) {
gameStarted = true;
instructionText.visible = false;
LK.playMusic('bgMusic');
}
}
function resetGame() {
// Reset player
if (player && player.setIcon && typeof iconSelectedIndex !== "undefined" && typeof iconIds !== "undefined") {
player.setIcon(iconIds[iconSelectedIndex]);
}
player.x = 300;
player.y = 2400;
player.velocityY = 0;
player.isGrounded = true;
// Reset spin state
player.spinSpeed = 0;
player.currentRotation = 0;
if (player.playerGraphics) player.playerGraphics.rotation = 0;
// Clear obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
// Clear orbs
for (var i = orbs.length - 1; i >= 0; i--) {
orbs[i].destroy();
}
orbs = [];
// Reset player power jump
player.hasPowerJump = false;
// Hide power overlay
player.hidePowerOverlay();
// Reset game state
distance = 0;
spawnTimer = 0;
lastObstacleX = 0;
gameStarted = false;
instructionText.visible = true;
// Flash effect
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('death').play();
}
function spawnOrb() {
var orbX = 2048 + 100;
var orbY = 2000 + Math.random() * 400; // Random height between ground and air
var orb = new Orb(orbX, orbY);
orbs.push(orb);
game.addChild(orb);
}
function spawnObstacle() {
var minGap = 300;
var maxGap = 500;
var gap = minGap + Math.random() * (maxGap - minGap);
if (lastObstacleX === 0 || 2048 - lastObstacleX > gap) {
var obstacleX = 2048 + 100;
var obstacleY = 2400;
// Random obstacle type
var obstacleType = Math.random() < 0.5 ? 'spike' : 'platform'; // Lower spike chance to 50%
if (obstacleType === 'platform') {
obstacleY = 2200 + Math.random() * 200;
}
var obstacle = new Obstacle(obstacleType, obstacleX, obstacleY);
obstacles.push(obstacle);
game.addChild(obstacle);
lastObstacleX = obstacleX;
}
}
function checkCollisions() {
// Check orb collisions
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
if (!orb.collected && player.intersects(orb)) {
orb.collected = true;
player.hasPowerJump = true;
player.showPowerOverlay();
powerOverlay = player.children[player.children.length - 1];
if (powerOverlay) {
powerOverlay.visible = true;
powerOverlay.alpha = 0.5;
}
// Flash player cyan to indicate power-up collected
LK.effects.flashObject(player, 0x00ffff, 500);
orb.destroy();
orbs.splice(i, 1);
continue;
}
// Remove off-screen orbs
if (orb.x < -100) {
orb.destroy();
orbs.splice(i, 1);
}
}
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (player.intersects(obstacle)) {
if (!player.isInvincible) {
resetGame();
return;
}
// If invincible, ignore collision and continue
}
// Remove off-screen obstacles
if (obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
}
player.jump();
};
// Update game
game.update = function () {
if (!gameStarted) return;
// Update distance
distance += gameSpeed;
scoreText.setText('Distance: ' + Math.floor(distance / 10));
// Spawn obstacles
spawnTimer++;
if (spawnTimer % 45 === 0) {
// Spawn every 45 ticks (~0.75 seconds)
spawnObstacle();
}
// Spawn orbs occasionally
orbSpawnTimer++;
if (orbSpawnTimer % 120 === 0) {
// Spawn every 120 ticks (~2 seconds)
spawnOrb();
}
// Update obstacle positions
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
obstacle.x -= gameSpeed;
// Track last obstacle position for gap calculation
if (obstacle.x < 2048 && obstacle.x > lastObstacleX - 2048) {
lastObstacleX = obstacle.x;
}
}
// Update orb positions
for (var i = 0; i < orbs.length; i++) {
var orb = orbs[i];
orb.x -= gameSpeed;
}
// Check collisions
checkCollisions();
// Increase difficulty gradually
if (LK.ticks % 900 === 0) {
// Every 15 seconds
gameSpeed += 0.3;
gameSpeed = Math.min(gameSpeed, 10); // Cap max speed
}
};