/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highscore: 0, coins: 0 }); /**** * Classes ****/ var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.active = true; self.collected = false; // Coin animation function animateCoin() { tween(coinGraphics, { scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(coinGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut, onFinish: animateCoin }); } }); } animateCoin(); self.collect = function () { if (!self.collected) { self.collected = true; LK.getSound('coin_collect').play(); tween(self, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.active = false; self.destroy(); } }); // Update coins coins++; coinsText.setText("Coins: " + coins); // Save coins storage.coins = coins; } }; self.update = function () { if (!self.active) { return; } self.x -= self.speed; // Remove if off screen if (self.x < -coinGraphics.width) { self.active = false; self.destroy(); } }; return self; }); var Ground = Container.expand(function () { var self = Container.call(this); var groundGraphics = self.attachAsset('ground', { anchorX: 0, anchorY: 0 }); self.speed = 12; self.update = function () { self.x -= self.speed; // Loop ground if (self.x <= -groundGraphics.width) { self.x = 0; } }; return self; }); var GroundDecoration = Container.expand(function () { var self = Container.call(this); var decorationGraphics = self.attachAsset('ground_decoration', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.active = true; // Random height decorationGraphics.height = 10 + Math.random() * 20; // Random color tint var colors = [0x7f8c8d, 0x95a5a6, 0xbdc3c7]; decorationGraphics.tint = colors[Math.floor(Math.random() * colors.length)]; self.update = function () { if (!self.active) { return; } self.x -= self.speed; // Remove if off screen if (self.x < -decorationGraphics.width) { self.active = false; self.destroy(); } }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1.0 }); self.speed = 12; self.active = true; self.update = function () { if (!self.active) { return; } self.x -= self.speed; // Remove if off screen if (self.x < -obstacleGraphics.width) { self.active = false; self.destroy(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.velocity = 0; self.gravity = 1.5; self.jumpPower = -25; self.grounded = false; self.dead = false; self.jump = function () { if (self.grounded && !self.dead) { self.velocity = self.jumpPower; self.grounded = false; LK.getSound('jump').play(); // Jump animation tween(self, { rotation: -Math.PI * 2 }, { duration: 500, easing: tween.linear, onFinish: function onFinish() { self.rotation = 0; } }); } }; self.die = function () { if (!self.dead) { self.dead = true; LK.getSound('death').play(); LK.effects.flashObject(self, 0xff0000, 500); // Death animation tween(self, { alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { LK.showGameOver(); } }); } }; self.update = function () { if (self.dead) { return; } // Apply gravity self.velocity += self.gravity; self.y += self.velocity; // Check if on ground if (self.y >= groundY - playerGraphics.height / 2) { self.y = groundY - playerGraphics.height / 2; self.velocity = 0; self.grounded = true; } // Die if player falls below ground (into a pit) if (self.y > groundY + 300) { self.die(); } }; return self; }); var Spike = Container.expand(function () { var self = Container.call(this); var spikeGraphics = self.attachAsset('spike', { anchorX: 0.5, anchorY: 1.0 }); self.speed = 12; self.active = true; // Rotate to make it look like a spike spikeGraphics.rotation = Math.PI / 4; self.update = function () { if (!self.active) { return; } self.x -= self.speed; // Remove if off screen if (self.x < -spikeGraphics.width) { self.active = false; self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x34495e }); /**** * Game Code ****/ // Game variables var player; var obstacles = []; var spikes = []; var coins = []; var decorations = []; var grounds = []; var groundY = 2300; var score = 0; var distance = 0; var gameStarted = false; var gamePaused = false; var lastObstacleTime = 0; var obstacleSpawnRate = 120; // frames between obstacle spawns var coinCollected = storage.coins || 0; var coins = []; var highscore = storage.highscore || 0; // Background var background = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Create UI elements var scoreText = new Text2("Score: 0", { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); scoreText.y = 100; var coinsText = new Text2("Coins: " + coins, { size: 80, fill: 0xF1C40F }); coinsText.anchor.set(0.5, 0); LK.gui.top.addChild(coinsText); coinsText.y = 200; var highscoreText = new Text2("Best: " + highscore, { size: 80, fill: 0x2ECC71 }); highscoreText.anchor.set(0.5, 0); LK.gui.top.addChild(highscoreText); highscoreText.y = 300; var startText = new Text2("Tap to Start", { size: 120, fill: 0xFFFFFF }); startText.anchor.set(0.5, 0.5); LK.gui.center.addChild(startText); // Initialize grounds (double to create seamless loop) for (var i = 0; i < 2; i++) { var ground = new Ground(); ground.x = i * 2048; ground.y = groundY; grounds.push(ground); game.addChild(ground); } // Initialize player player = new Player(); player.x = 400; player.y = groundY - 50; game.addChild(player); // Start game function startGame() { if (!gameStarted) { gameStarted = true; LK.gui.center.removeChild(startText); LK.playMusic('bgmusic'); // Start with some decorations for (var i = 0; i < 15; i++) { spawnDecoration(200 + i * 200); } } } // Spawn obstacle function spawnObstacle() { var obstacleType = Math.random(); if (obstacleType < 0.6) { // Regular obstacle var obstacle = new Obstacle(); obstacle.x = 2148; // Just off screen to the right obstacle.y = groundY; obstacles.push(obstacle); game.addChild(obstacle); } else { // Spike var spike = new Spike(); spike.x = 2148; // Just off screen to the right spike.y = groundY; spikes.push(spike); game.addChild(spike); } // Maybe spawn a coin if (Math.random() < 0.3) { spawnCoin(); } } // Spawn coin function spawnCoin() { var coin = new Coin(); coin.x = 2148 + Math.random() * 200; // Slightly offset from obstacles coin.y = groundY - 150 - Math.random() * 200; // Above ground at varying heights coins.push(coin); game.addChild(coin); } // Spawn decorations function spawnDecoration(xPos) { var decoration = new GroundDecoration(); decoration.x = xPos || 2148 + Math.random() * 100; decoration.y = groundY - Math.random() * 10; decorations.push(decoration); game.addChild(decoration); } // Input handling game.down = function (x, y, obj) { if (!gameStarted) { startGame(); } else { player.jump(); } }; // Main game update loop game.update = function () { if (!gameStarted) { return; } // Update score if (!player.dead) { distance += 1; score = Math.floor(distance / 5); scoreText.setText("Score: " + score); // Update high score if needed if (score > highscore) { highscore = score; highscoreText.setText("Best: " + highscore); storage.highscore = highscore; } // Increase difficulty obstacleSpawnRate = Math.max(60, 120 - Math.floor(score / 100) * 10); } // Spawn obstacles if (LK.ticks - lastObstacleTime > obstacleSpawnRate) { spawnObstacle(); lastObstacleTime = LK.ticks; } // Spawn decorations randomly if (Math.random() < 0.05) { spawnDecoration(); } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Check collision with player if (!player.dead && player.intersects(obstacle)) { player.die(); } // Remove if not active anymore if (!obstacle.active) { obstacles.splice(i, 1); } } // Update spikes for (var i = spikes.length - 1; i >= 0; i--) { var spike = spikes[i]; // Check collision with player if (!player.dead && player.intersects(spike)) { player.die(); } // Remove if not active anymore if (!spike.active) { spikes.splice(i, 1); } } // Update coins for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; // Check collision with player if (!player.dead && !coin.collected && player.intersects(coin)) { coin.collect(); } // Remove if not active anymore if (!coin.active) { coins.splice(i, 1); } } // Update decorations for (var i = decorations.length - 1; i >= 0; i--) { if (!decorations[i].active) { decorations.splice(i, 1); } } // Increase game speed based on score var baseSpeed = 12; var speedMultiplier = 1 + Math.min(1, score / 1000); var gameSpeed = baseSpeed * speedMultiplier; // Update game speed for all moving objects for (var i = 0; i < obstacles.length; i++) { obstacles[i].speed = gameSpeed; } for (var i = 0; i < spikes.length; i++) { spikes[i].speed = gameSpeed; } for (var i = 0; i < coins.length; i++) { coins[i].speed = gameSpeed; } for (var i = 0; i < decorations.length; i++) { decorations[i].speed = gameSpeed; } for (var i = 0; i < grounds.length; i++) { grounds[i].speed = gameSpeed; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highscore: 0,
coins: 0
});
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.active = true;
self.collected = false;
// Coin animation
function animateCoin() {
tween(coinGraphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: animateCoin
});
}
});
}
animateCoin();
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.getSound('coin_collect').play();
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.active = false;
self.destroy();
}
});
// Update coins
coins++;
coinsText.setText("Coins: " + coins);
// Save coins
storage.coins = coins;
}
};
self.update = function () {
if (!self.active) {
return;
}
self.x -= self.speed;
// Remove if off screen
if (self.x < -coinGraphics.width) {
self.active = false;
self.destroy();
}
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0,
anchorY: 0
});
self.speed = 12;
self.update = function () {
self.x -= self.speed;
// Loop ground
if (self.x <= -groundGraphics.width) {
self.x = 0;
}
};
return self;
});
var GroundDecoration = Container.expand(function () {
var self = Container.call(this);
var decorationGraphics = self.attachAsset('ground_decoration', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.active = true;
// Random height
decorationGraphics.height = 10 + Math.random() * 20;
// Random color tint
var colors = [0x7f8c8d, 0x95a5a6, 0xbdc3c7];
decorationGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
self.update = function () {
if (!self.active) {
return;
}
self.x -= self.speed;
// Remove if off screen
if (self.x < -decorationGraphics.width) {
self.active = false;
self.destroy();
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 12;
self.active = true;
self.update = function () {
if (!self.active) {
return;
}
self.x -= self.speed;
// Remove if off screen
if (self.x < -obstacleGraphics.width) {
self.active = false;
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = 0;
self.gravity = 1.5;
self.jumpPower = -25;
self.grounded = false;
self.dead = false;
self.jump = function () {
if (self.grounded && !self.dead) {
self.velocity = self.jumpPower;
self.grounded = false;
LK.getSound('jump').play();
// Jump animation
tween(self, {
rotation: -Math.PI * 2
}, {
duration: 500,
easing: tween.linear,
onFinish: function onFinish() {
self.rotation = 0;
}
});
}
};
self.die = function () {
if (!self.dead) {
self.dead = true;
LK.getSound('death').play();
LK.effects.flashObject(self, 0xff0000, 500);
// Death animation
tween(self, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
};
self.update = function () {
if (self.dead) {
return;
}
// Apply gravity
self.velocity += self.gravity;
self.y += self.velocity;
// Check if on ground
if (self.y >= groundY - playerGraphics.height / 2) {
self.y = groundY - playerGraphics.height / 2;
self.velocity = 0;
self.grounded = true;
}
// Die if player falls below ground (into a pit)
if (self.y > groundY + 300) {
self.die();
}
};
return self;
});
var Spike = Container.expand(function () {
var self = Container.call(this);
var spikeGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 12;
self.active = true;
// Rotate to make it look like a spike
spikeGraphics.rotation = Math.PI / 4;
self.update = function () {
if (!self.active) {
return;
}
self.x -= self.speed;
// Remove if off screen
if (self.x < -spikeGraphics.width) {
self.active = false;
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Game variables
var player;
var obstacles = [];
var spikes = [];
var coins = [];
var decorations = [];
var grounds = [];
var groundY = 2300;
var score = 0;
var distance = 0;
var gameStarted = false;
var gamePaused = false;
var lastObstacleTime = 0;
var obstacleSpawnRate = 120; // frames between obstacle spawns
var coinCollected = storage.coins || 0;
var coins = [];
var highscore = storage.highscore || 0;
// Background
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create UI elements
var scoreText = new Text2("Score: 0", {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
var coinsText = new Text2("Coins: " + coins, {
size: 80,
fill: 0xF1C40F
});
coinsText.anchor.set(0.5, 0);
LK.gui.top.addChild(coinsText);
coinsText.y = 200;
var highscoreText = new Text2("Best: " + highscore, {
size: 80,
fill: 0x2ECC71
});
highscoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(highscoreText);
highscoreText.y = 300;
var startText = new Text2("Tap to Start", {
size: 120,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startText);
// Initialize grounds (double to create seamless loop)
for (var i = 0; i < 2; i++) {
var ground = new Ground();
ground.x = i * 2048;
ground.y = groundY;
grounds.push(ground);
game.addChild(ground);
}
// Initialize player
player = new Player();
player.x = 400;
player.y = groundY - 50;
game.addChild(player);
// Start game
function startGame() {
if (!gameStarted) {
gameStarted = true;
LK.gui.center.removeChild(startText);
LK.playMusic('bgmusic');
// Start with some decorations
for (var i = 0; i < 15; i++) {
spawnDecoration(200 + i * 200);
}
}
}
// Spawn obstacle
function spawnObstacle() {
var obstacleType = Math.random();
if (obstacleType < 0.6) {
// Regular obstacle
var obstacle = new Obstacle();
obstacle.x = 2148; // Just off screen to the right
obstacle.y = groundY;
obstacles.push(obstacle);
game.addChild(obstacle);
} else {
// Spike
var spike = new Spike();
spike.x = 2148; // Just off screen to the right
spike.y = groundY;
spikes.push(spike);
game.addChild(spike);
}
// Maybe spawn a coin
if (Math.random() < 0.3) {
spawnCoin();
}
}
// Spawn coin
function spawnCoin() {
var coin = new Coin();
coin.x = 2148 + Math.random() * 200; // Slightly offset from obstacles
coin.y = groundY - 150 - Math.random() * 200; // Above ground at varying heights
coins.push(coin);
game.addChild(coin);
}
// Spawn decorations
function spawnDecoration(xPos) {
var decoration = new GroundDecoration();
decoration.x = xPos || 2148 + Math.random() * 100;
decoration.y = groundY - Math.random() * 10;
decorations.push(decoration);
game.addChild(decoration);
}
// Input handling
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
} else {
player.jump();
}
};
// Main game update loop
game.update = function () {
if (!gameStarted) {
return;
}
// Update score
if (!player.dead) {
distance += 1;
score = Math.floor(distance / 5);
scoreText.setText("Score: " + score);
// Update high score if needed
if (score > highscore) {
highscore = score;
highscoreText.setText("Best: " + highscore);
storage.highscore = highscore;
}
// Increase difficulty
obstacleSpawnRate = Math.max(60, 120 - Math.floor(score / 100) * 10);
}
// Spawn obstacles
if (LK.ticks - lastObstacleTime > obstacleSpawnRate) {
spawnObstacle();
lastObstacleTime = LK.ticks;
}
// Spawn decorations randomly
if (Math.random() < 0.05) {
spawnDecoration();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Check collision with player
if (!player.dead && player.intersects(obstacle)) {
player.die();
}
// Remove if not active anymore
if (!obstacle.active) {
obstacles.splice(i, 1);
}
}
// Update spikes
for (var i = spikes.length - 1; i >= 0; i--) {
var spike = spikes[i];
// Check collision with player
if (!player.dead && player.intersects(spike)) {
player.die();
}
// Remove if not active anymore
if (!spike.active) {
spikes.splice(i, 1);
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
// Check collision with player
if (!player.dead && !coin.collected && player.intersects(coin)) {
coin.collect();
}
// Remove if not active anymore
if (!coin.active) {
coins.splice(i, 1);
}
}
// Update decorations
for (var i = decorations.length - 1; i >= 0; i--) {
if (!decorations[i].active) {
decorations.splice(i, 1);
}
}
// Increase game speed based on score
var baseSpeed = 12;
var speedMultiplier = 1 + Math.min(1, score / 1000);
var gameSpeed = baseSpeed * speedMultiplier;
// Update game speed for all moving objects
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].speed = gameSpeed;
}
for (var i = 0; i < spikes.length; i++) {
spikes[i].speed = gameSpeed;
}
for (var i = 0; i < coins.length; i++) {
coins[i].speed = gameSpeed;
}
for (var i = 0; i < decorations.length; i++) {
decorations[i].speed = gameSpeed;
}
for (var i = 0; i < grounds.length; i++) {
grounds[i].speed = gameSpeed;
}
};