/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var CeilingSegment = Container.expand(function () { var self = Container.call(this); var ceilingGraphics = self.attachAsset('ceiling', { anchorX: 0, anchorY: 1 }); self.speed = -8; self.update = function () { self.x += self.speed; }; return self; }); var GroundSegment = Container.expand(function () { var self = Container.call(this); var groundGraphics = self.attachAsset('ground', { anchorX: 0, anchorY: 0 }); self.speed = -8; self.update = function () { self.x += self.speed; }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('spike', { anchorX: 0.5, anchorY: 1.0 }); self.speed = -8; self.update = function () { self.x += self.speed; }; return self; }); var Orb = Container.expand(function () { var self = Container.call(this); var orbGraphics = self.attachAsset('orb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -8; self.floatOffset = 0; // Start floating animation tween(self, { floatOffset: Math.PI * 2 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { // Loop the animation self.floatOffset = 0; tween(self, { floatOffset: Math.PI * 2 }, { duration: 2000, easing: tween.linear }); } }); self.update = function () { self.x += self.speed; // Apply floating motion orbGraphics.y = Math.sin(self.floatOffset) * 20; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.velocityY = 0; self.gravity = 0.8; self.jumpPower = -16; self.isGrounded = false; self.groundY = 2400; self.isPoweredUp = false; self.powerupJumpsLeft = 0; self.originalScale = 1; self.originalJumpPower = self.jumpPower; self.jump = function () { if (self.isGrounded) { // Use enhanced jump power if powered up var currentJumpPower = self.isPoweredUp ? self.originalJumpPower * 1.5 : self.jumpPower; self.velocityY = currentJumpPower; self.isGrounded = false; LK.getSound('jump').play(); // Decrease powerup jumps if active if (self.isPoweredUp) { self.powerupJumpsLeft--; if (self.powerupJumpsLeft <= 0) { self.deactivatePowerup(); } } } }; self.update = function () { // Apply gravity self.velocityY += self.gravity; self.y += self.velocityY; // Adjust ground position based on scale - when small, player needs to be lower to touch ground var currentScale = self.isPoweredUp ? 0.7 : 1; var adjustedGroundY = self.groundY + 101 * (1 - currentScale); // 101 is half the player height // Ground collision if (self.y >= adjustedGroundY) { self.y = adjustedGroundY; self.velocityY = 0; self.isGrounded = true; } // Ceiling collision if (self.y <= 200) { self.y = 200; self.velocityY = 0; } }; self.activatePowerup = function () { self.isPoweredUp = true; self.powerupJumpsLeft = 5; // Make player smaller and change tint to golden tween(playerGraphics, { scaleX: 0.7, scaleY: 0.7, tint: 0xFFD700 }, { duration: 300, easing: tween.easeOut }); }; self.deactivatePowerup = function () { self.isPoweredUp = false; self.powerupJumpsLeft = 0; // Return player to normal size and color tween(playerGraphics, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c1810 }); /**** * Game Code ****/ var player; var obstacles = []; var orbs = []; var groundSegments = []; var ceilingSegments = []; var gameSpeed = 8; var obstacleSpawnTimer = 0; var orbSpawnTimer = 0; var groundSpawnTimer = 0; var ceilingSpawnTimer = 0; var distance = 0; var isGameRunning = true; var obstaclePattern = []; var orbPattern = []; var patternIndex = 0; // Score display var scoreTxt = new Text2('Distance: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Add multiple background images for seamless looping var backgroundImages = []; for (var i = 0; i < 3; i++) { var backgroundImage = game.addChild(LK.getAsset('Bg', { anchorX: 0, anchorY: 0, scaleX: 20.48, scaleY: 24 })); backgroundImage.x = i * 2048; // Position backgrounds side by side backgroundImage.y = 100; // Start from ceiling backgroundImages.push(backgroundImage); } // Start background music LK.playMusic('Bg-music-loop'); // Generate initial random patterns generateRandomPattern(); // Create player player = game.addChild(new Player()); player.x = 400; player.y = 2400; // Initialize ground segments for (var i = 0; i < 15; i++) { var groundSeg = new GroundSegment(); groundSeg.x = i * 200; groundSeg.y = 2500; groundSegments.push(groundSeg); game.addChild(groundSeg); } // Initialize ceiling segments for (var i = 0; i < 15; i++) { var ceilingSeg = new CeilingSegment(); ceilingSeg.x = i * 200; ceilingSeg.y = 100; ceilingSegments.push(ceilingSeg); game.addChild(ceilingSeg); } function generateRandomPattern() { obstaclePattern = []; orbPattern = []; // Generate random obstacle pattern (30 positions) for (var i = 0; i < 30; i++) { obstaclePattern.push(Math.random() < 0.4); // 40% chance of obstacle } // Generate random orb pattern (15 positions, less frequent) for (var i = 0; i < 15; i++) { orbPattern.push(Math.random() < 0.2); // 20% chance of orb } patternIndex = 0; } function spawnObstacle() { // Use pattern if available, otherwise random var shouldSpawn = obstaclePattern.length > 0 ? obstaclePattern[patternIndex % obstaclePattern.length] : Math.random() < 0.4; if (shouldSpawn) { var obstacle = new Obstacle(); obstacle.x = 2200; obstacle.y = 2500; obstacles.push(obstacle); game.addChild(obstacle); } } function spawnOrb() { // Use pattern if available, otherwise random var shouldSpawn = orbPattern.length > 0 ? orbPattern[Math.floor(patternIndex / 2) % orbPattern.length] : Math.random() < 0.15; if (shouldSpawn) { var orb = new Orb(); orb.x = 2200; orb.y = 2200; // Higher up than obstacles orbs.push(orb); game.addChild(orb); } } function spawnGroundSegment() { var groundSeg = new GroundSegment(); groundSeg.x = 2200; groundSeg.y = 2500; groundSegments.push(groundSeg); game.addChild(groundSeg); } function spawnCeilingSegment() { var ceilingSeg = new CeilingSegment(); ceilingSeg.x = 2200; ceilingSeg.y = 100; ceilingSegments.push(ceilingSeg); game.addChild(ceilingSeg); } function resetGame() { isGameRunning = false; LK.getSound('death').play(); LK.effects.flashScreen(0xff0000, 500); LK.setTimeout(function () { LK.showGameOver(); }, 500); } function checkCollisions() { if (!isGameRunning) return; // Check obstacle collisions with precise hitboxes for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; // Player hitbox - smaller when powered up var hitboxScale = player.isPoweredUp ? 0.7 : 1; var playerLeft = player.x - 60 * hitboxScale; var playerRight = player.x + 60 * hitboxScale; var playerTop = player.y - 80 * hitboxScale; var playerBottom = player.y + 80 * hitboxScale; // Obstacle hitbox (spike - reduce width by 30% and height by 20% to match visual spike shape) var obstacleLeft = obstacle.x - 28; var obstacleRight = obstacle.x + 28; var obstacleTop = obstacle.y - 55; var obstacleBottom = obstacle.y; // Check if hitboxes overlap if (playerLeft < obstacleRight && playerRight > obstacleLeft && playerTop < obstacleBottom && playerBottom > obstacleTop) { resetGame(); return; } } // Check orb collisions for (var i = orbs.length - 1; i >= 0; i--) { var orb = orbs[i]; // Player hitbox - smaller when powered up var hitboxScale = player.isPoweredUp ? 0.7 : 1; var playerLeft = player.x - 60 * hitboxScale; var playerRight = player.x + 60 * hitboxScale; var playerTop = player.y - 80 * hitboxScale; var playerBottom = player.y + 80 * hitboxScale; // Orb hitbox var orbLeft = orb.x - 30; var orbRight = orb.x + 30; var orbTop = orb.y - 30; var orbBottom = orb.y + 30; // Check if hitboxes overlap if (playerLeft < orbRight && playerRight > orbLeft && playerTop < orbBottom && playerBottom > orbTop) { // Activate powerup player.activatePowerup(); LK.getSound('powerup').play(); // Remove orb orb.destroy(); orbs.splice(i, 1); } } } game.down = function (x, y, obj) { if (isGameRunning) { player.jump(); } }; game.update = function () { if (!isGameRunning) return; // Update distance distance += gameSpeed; LK.setScore(Math.floor(distance / 10)); scoreTxt.setText('Distance: ' + Math.floor(distance / 10)); // Move all background images with game world for (var i = 0; i < backgroundImages.length; i++) { backgroundImages[i].x -= gameSpeed; // Reset background position when it moves too far left for seamless looping if (backgroundImages[i].x <= -2048) { backgroundImages[i].x += 2048 * backgroundImages.length; } } // Spawn obstacles obstacleSpawnTimer++; if (obstacleSpawnTimer >= 90) { spawnObstacle(); obstacleSpawnTimer = 0; patternIndex++; // Generate new pattern every 30 spawns if (patternIndex % 30 === 0) { generateRandomPattern(); } } // Spawn orbs orbSpawnTimer++; if (orbSpawnTimer >= 180) { // Less frequent than obstacles spawnOrb(); orbSpawnTimer = 0; } // Spawn ground segments groundSpawnTimer++; if (groundSpawnTimer >= 25) { spawnGroundSegment(); groundSpawnTimer = 0; } // Spawn ceiling segments ceilingSpawnTimer++; if (ceilingSpawnTimer >= 25) { spawnCeilingSegment(); ceilingSpawnTimer = 0; } // Remove off-screen obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; if (obstacle.x < -100) { obstacle.destroy(); obstacles.splice(i, 1); } } // Remove off-screen orbs for (var i = orbs.length - 1; i >= 0; i--) { var orb = orbs[i]; if (orb.x < -100) { orb.destroy(); orbs.splice(i, 1); } } // Remove off-screen ground segments for (var i = groundSegments.length - 1; i >= 0; i--) { var groundSeg = groundSegments[i]; if (groundSeg.x < -300) { groundSeg.destroy(); groundSegments.splice(i, 1); } } // Remove off-screen ceiling segments for (var i = ceilingSegments.length - 1; i >= 0; i--) { var ceilingSeg = ceilingSegments[i]; if (ceilingSeg.x < -300) { ceilingSeg.destroy(); ceilingSegments.splice(i, 1); } } // Check collisions checkCollisions(); // Increase difficulty over time if (LK.ticks % 600 === 0 && gameSpeed < 12) { gameSpeed += 0.5; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CeilingSegment = Container.expand(function () {
var self = Container.call(this);
var ceilingGraphics = self.attachAsset('ceiling', {
anchorX: 0,
anchorY: 1
});
self.speed = -8;
self.update = function () {
self.x += self.speed;
};
return self;
});
var GroundSegment = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0,
anchorY: 0
});
self.speed = -8;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = -8;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Orb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('orb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8;
self.floatOffset = 0;
// Start floating animation
tween(self, {
floatOffset: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
// Loop the animation
self.floatOffset = 0;
tween(self, {
floatOffset: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear
});
}
});
self.update = function () {
self.x += self.speed;
// Apply floating motion
orbGraphics.y = Math.sin(self.floatOffset) * 20;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -16;
self.isGrounded = false;
self.groundY = 2400;
self.isPoweredUp = false;
self.powerupJumpsLeft = 0;
self.originalScale = 1;
self.originalJumpPower = self.jumpPower;
self.jump = function () {
if (self.isGrounded) {
// Use enhanced jump power if powered up
var currentJumpPower = self.isPoweredUp ? self.originalJumpPower * 1.5 : self.jumpPower;
self.velocityY = currentJumpPower;
self.isGrounded = false;
LK.getSound('jump').play();
// Decrease powerup jumps if active
if (self.isPoweredUp) {
self.powerupJumpsLeft--;
if (self.powerupJumpsLeft <= 0) {
self.deactivatePowerup();
}
}
}
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Adjust ground position based on scale - when small, player needs to be lower to touch ground
var currentScale = self.isPoweredUp ? 0.7 : 1;
var adjustedGroundY = self.groundY + 101 * (1 - currentScale); // 101 is half the player height
// Ground collision
if (self.y >= adjustedGroundY) {
self.y = adjustedGroundY;
self.velocityY = 0;
self.isGrounded = true;
}
// Ceiling collision
if (self.y <= 200) {
self.y = 200;
self.velocityY = 0;
}
};
self.activatePowerup = function () {
self.isPoweredUp = true;
self.powerupJumpsLeft = 5;
// Make player smaller and change tint to golden
tween(playerGraphics, {
scaleX: 0.7,
scaleY: 0.7,
tint: 0xFFD700
}, {
duration: 300,
easing: tween.easeOut
});
};
self.deactivatePowerup = function () {
self.isPoweredUp = false;
self.powerupJumpsLeft = 0;
// Return player to normal size and color
tween(playerGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c1810
});
/****
* Game Code
****/
var player;
var obstacles = [];
var orbs = [];
var groundSegments = [];
var ceilingSegments = [];
var gameSpeed = 8;
var obstacleSpawnTimer = 0;
var orbSpawnTimer = 0;
var groundSpawnTimer = 0;
var ceilingSpawnTimer = 0;
var distance = 0;
var isGameRunning = true;
var obstaclePattern = [];
var orbPattern = [];
var patternIndex = 0;
// Score display
var scoreTxt = new Text2('Distance: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Add multiple background images for seamless looping
var backgroundImages = [];
for (var i = 0; i < 3; i++) {
var backgroundImage = game.addChild(LK.getAsset('Bg', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
scaleY: 24
}));
backgroundImage.x = i * 2048; // Position backgrounds side by side
backgroundImage.y = 100; // Start from ceiling
backgroundImages.push(backgroundImage);
}
// Start background music
LK.playMusic('Bg-music-loop');
// Generate initial random patterns
generateRandomPattern();
// Create player
player = game.addChild(new Player());
player.x = 400;
player.y = 2400;
// Initialize ground segments
for (var i = 0; i < 15; i++) {
var groundSeg = new GroundSegment();
groundSeg.x = i * 200;
groundSeg.y = 2500;
groundSegments.push(groundSeg);
game.addChild(groundSeg);
}
// Initialize ceiling segments
for (var i = 0; i < 15; i++) {
var ceilingSeg = new CeilingSegment();
ceilingSeg.x = i * 200;
ceilingSeg.y = 100;
ceilingSegments.push(ceilingSeg);
game.addChild(ceilingSeg);
}
function generateRandomPattern() {
obstaclePattern = [];
orbPattern = [];
// Generate random obstacle pattern (30 positions)
for (var i = 0; i < 30; i++) {
obstaclePattern.push(Math.random() < 0.4); // 40% chance of obstacle
}
// Generate random orb pattern (15 positions, less frequent)
for (var i = 0; i < 15; i++) {
orbPattern.push(Math.random() < 0.2); // 20% chance of orb
}
patternIndex = 0;
}
function spawnObstacle() {
// Use pattern if available, otherwise random
var shouldSpawn = obstaclePattern.length > 0 ? obstaclePattern[patternIndex % obstaclePattern.length] : Math.random() < 0.4;
if (shouldSpawn) {
var obstacle = new Obstacle();
obstacle.x = 2200;
obstacle.y = 2500;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
function spawnOrb() {
// Use pattern if available, otherwise random
var shouldSpawn = orbPattern.length > 0 ? orbPattern[Math.floor(patternIndex / 2) % orbPattern.length] : Math.random() < 0.15;
if (shouldSpawn) {
var orb = new Orb();
orb.x = 2200;
orb.y = 2200; // Higher up than obstacles
orbs.push(orb);
game.addChild(orb);
}
}
function spawnGroundSegment() {
var groundSeg = new GroundSegment();
groundSeg.x = 2200;
groundSeg.y = 2500;
groundSegments.push(groundSeg);
game.addChild(groundSeg);
}
function spawnCeilingSegment() {
var ceilingSeg = new CeilingSegment();
ceilingSeg.x = 2200;
ceilingSeg.y = 100;
ceilingSegments.push(ceilingSeg);
game.addChild(ceilingSeg);
}
function resetGame() {
isGameRunning = false;
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 500);
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
function checkCollisions() {
if (!isGameRunning) return;
// Check obstacle collisions with precise hitboxes
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Player hitbox - smaller when powered up
var hitboxScale = player.isPoweredUp ? 0.7 : 1;
var playerLeft = player.x - 60 * hitboxScale;
var playerRight = player.x + 60 * hitboxScale;
var playerTop = player.y - 80 * hitboxScale;
var playerBottom = player.y + 80 * hitboxScale;
// Obstacle hitbox (spike - reduce width by 30% and height by 20% to match visual spike shape)
var obstacleLeft = obstacle.x - 28;
var obstacleRight = obstacle.x + 28;
var obstacleTop = obstacle.y - 55;
var obstacleBottom = obstacle.y;
// Check if hitboxes overlap
if (playerLeft < obstacleRight && playerRight > obstacleLeft && playerTop < obstacleBottom && playerBottom > obstacleTop) {
resetGame();
return;
}
}
// Check orb collisions
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
// Player hitbox - smaller when powered up
var hitboxScale = player.isPoweredUp ? 0.7 : 1;
var playerLeft = player.x - 60 * hitboxScale;
var playerRight = player.x + 60 * hitboxScale;
var playerTop = player.y - 80 * hitboxScale;
var playerBottom = player.y + 80 * hitboxScale;
// Orb hitbox
var orbLeft = orb.x - 30;
var orbRight = orb.x + 30;
var orbTop = orb.y - 30;
var orbBottom = orb.y + 30;
// Check if hitboxes overlap
if (playerLeft < orbRight && playerRight > orbLeft && playerTop < orbBottom && playerBottom > orbTop) {
// Activate powerup
player.activatePowerup();
LK.getSound('powerup').play();
// Remove orb
orb.destroy();
orbs.splice(i, 1);
}
}
}
game.down = function (x, y, obj) {
if (isGameRunning) {
player.jump();
}
};
game.update = function () {
if (!isGameRunning) return;
// Update distance
distance += gameSpeed;
LK.setScore(Math.floor(distance / 10));
scoreTxt.setText('Distance: ' + Math.floor(distance / 10));
// Move all background images with game world
for (var i = 0; i < backgroundImages.length; i++) {
backgroundImages[i].x -= gameSpeed;
// Reset background position when it moves too far left for seamless looping
if (backgroundImages[i].x <= -2048) {
backgroundImages[i].x += 2048 * backgroundImages.length;
}
}
// Spawn obstacles
obstacleSpawnTimer++;
if (obstacleSpawnTimer >= 90) {
spawnObstacle();
obstacleSpawnTimer = 0;
patternIndex++;
// Generate new pattern every 30 spawns
if (patternIndex % 30 === 0) {
generateRandomPattern();
}
}
// Spawn orbs
orbSpawnTimer++;
if (orbSpawnTimer >= 180) {
// Less frequent than obstacles
spawnOrb();
orbSpawnTimer = 0;
}
// Spawn ground segments
groundSpawnTimer++;
if (groundSpawnTimer >= 25) {
spawnGroundSegment();
groundSpawnTimer = 0;
}
// Spawn ceiling segments
ceilingSpawnTimer++;
if (ceilingSpawnTimer >= 25) {
spawnCeilingSegment();
ceilingSpawnTimer = 0;
}
// Remove off-screen obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Remove off-screen orbs
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
if (orb.x < -100) {
orb.destroy();
orbs.splice(i, 1);
}
}
// Remove off-screen ground segments
for (var i = groundSegments.length - 1; i >= 0; i--) {
var groundSeg = groundSegments[i];
if (groundSeg.x < -300) {
groundSeg.destroy();
groundSegments.splice(i, 1);
}
}
// Remove off-screen ceiling segments
for (var i = ceilingSegments.length - 1; i >= 0; i--) {
var ceilingSeg = ceilingSegments[i];
if (ceilingSeg.x < -300) {
ceilingSeg.destroy();
ceilingSegments.splice(i, 1);
}
}
// Check collisions
checkCollisions();
// Increase difficulty over time
if (LK.ticks % 600 === 0 && gameSpeed < 12) {
gameSpeed += 0.5;
}
};