/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Coin var Coin = Container.expand(function () { var self = Container.call(this); var coinGfx = self.attachAsset('coin', { anchorX: 0.5, anchorY: 1 }); self.lane = 1; self.collected = false; return self; }); // Magnet Powerup var Magnet = Container.expand(function () { var self = Container.call(this); var magGfx = self.attachAsset('magnet', { anchorX: 0.5, anchorY: 1 }); self.lane = 1; self.collected = false; return self; }); // Obstacle (train/barrier) var Obstacle = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1 }); self.lane = 1; // 0,1,2 self.passed = false; return self; }); // Player Runner var Runner = Container.expand(function () { var self = Container.call(this); var runnerGfx = self.attachAsset('runner', { anchorX: 0.5, anchorY: 1 }); self.lane = 1; // 0: left, 1: center, 2: right self.isShielded = false; self.magnetActive = false; self.shieldActive = false; self.magnetTimer = 0; self.shieldTimer = 0; // Animate shield effect self.showShield = function () { if (!self.shieldCircle) { self.shieldCircle = self.attachAsset('shield', { anchorX: 0.5, anchorY: 1, scaleX: 1.3, scaleY: 1.3, alpha: 0.5 }); } self.shieldCircle.visible = true; }; self.hideShield = function () { if (self.shieldCircle) self.shieldCircle.visible = false; }; // Animate magnet effect self.showMagnet = function () { if (!self.magnetCircle) { self.magnetCircle = self.attachAsset('magnet', { anchorX: 0.5, anchorY: 1, scaleX: 1.5, scaleY: 1.5, alpha: 0.3 }); } self.magnetCircle.visible = true; }; self.hideMagnet = function () { if (self.magnetCircle) self.magnetCircle.visible = false; }; return self; }); // Shield Powerup var Shield = Container.expand(function () { var self = Container.call(this); var shGfx = self.attachAsset('shield', { anchorX: 0.5, anchorY: 1 }); self.lane = 1; self.collected = false; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // Add rails and grass background // Shield Powerup // Magnet Powerup // Coin // Obstacle (train/barrier) // Character (player) // Lane positions (3 lanes) var railWidth = 180; var railSpacing = 260; var grassWidth = (2048 - (railWidth * 3 + railSpacing * 2)) / 2; // Grass left var grassLeft = LK.getAsset('grass', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: grassWidth, height: 2732 }); game.addChild(grassLeft); // Grass right var grassRight = LK.getAsset('grass', { anchorX: 0, anchorY: 0, x: 2048 - grassWidth, y: 0, width: grassWidth, height: 2732 }); game.addChild(grassRight); // Rails var railX = [grassWidth, grassWidth + railWidth + railSpacing, grassWidth + (railWidth + railSpacing) * 2]; for (var i = 0; i < 3; ++i) { var rail = LK.getAsset('rail', { anchorX: 0, anchorY: 0, x: railX[i], y: 0, width: railWidth, height: 2732 }); game.addChild(rail); } // Lane positions (center of each rail) var laneX = [railX[0] + railWidth / 2, railX[1] + railWidth / 2, railX[2] + railWidth / 2]; // Track Y positions var groundY = 2732 - 200; // Game state var runner; var obstacles = []; var coins = []; var magnets = []; var shields = []; var speed = 18; // Initial speed (pixels per frame) var maxSpeed = 38; var speedInc = 0.0007; // Speed increase per tick var score = 0; var coinScore = 0; var lastObstacleTick = 0; var lastCoinTick = 0; var lastPowerupTick = 0; var dragStartX = null; var dragStartY = null; var dragStartTime = null; var swipeThreshold = 80; // px var swipeTime = 350; // ms var isMovingLane = false; var moveTween = null; var magnetDuration = 600; // ticks (10s) var shieldDuration = 600; // ticks (10s) var gameOver = false; // Score text var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Coin text var coinTxt = new Text2('0', { size: 80, fill: 0xFFE066 }); coinTxt.anchor.set(0, 0); LK.gui.topRight.addChild(coinTxt); // Helper: spawn runner function spawnRunner() { runner = new Runner(); runner.x = laneX[1]; runner.y = groundY; runner.lane = 1; game.addChild(runner); } // Helper: spawn obstacle function spawnObstacle() { var obs = new Obstacle(); obs.lane = Math.floor(Math.random() * 3); obs.x = laneX[obs.lane]; obs.y = -20; obstacles.push(obs); game.addChild(obs); } // Helper: spawn coin function spawnCoin() { var coin = new Coin(); coin.lane = Math.floor(Math.random() * 3); coin.x = laneX[coin.lane]; coin.y = -20; coins.push(coin); game.addChild(coin); } // Helper: spawn magnet function spawnMagnet() { var mag = new Magnet(); mag.lane = Math.floor(Math.random() * 3); mag.x = laneX[mag.lane]; mag.y = -20; magnets.push(mag); game.addChild(mag); } // Helper: spawn shield function spawnShield() { var sh = new Shield(); sh.lane = Math.floor(Math.random() * 3); sh.x = laneX[sh.lane]; sh.y = -20; shields.push(sh); game.addChild(sh); } // Helper: move runner to lane function moveRunnerToLane(targetLane) { if (isMovingLane || targetLane < 0 || targetLane > 2 || targetLane === runner.lane) return; isMovingLane = true; if (moveTween) tween.stop(runner, { x: true }); moveTween = tween(runner, { x: laneX[targetLane] }, { duration: 120, easing: tween.cubicOut, onFinish: function onFinish() { runner.lane = targetLane; isMovingLane = false; } }); } // Helper: handle swipe function handleSwipe(startX, startY, endX, endY, dt) { var dx = endX - startX; var dy = endY - startY; if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > swipeThreshold && dt < swipeTime) { // Horizontal swipe if (dx > 0) { // Swipe right if (runner) moveRunnerToLane(runner.lane + 1); } else { // Swipe left if (runner) moveRunnerToLane(runner.lane - 1); } } } // Helper: reset game state function resetGame() { // Remove all obstacles, coins, powerups for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy(); for (var i = 0; i < coins.length; ++i) coins[i].destroy(); for (var i = 0; i < magnets.length; ++i) magnets[i].destroy(); for (var i = 0; i < shields.length; ++i) shields[i].destroy(); obstacles = []; coins = []; magnets = []; shields = []; if (runner) runner.destroy(); runner = null; speed = 18; score = 0; coinScore = 0; lastObstacleTick = 0; lastCoinTick = 0; lastPowerupTick = 0; isMovingLane = false; moveTween = null; gameOver = false; scoreTxt.setText('0'); coinTxt.setText('0'); spawnRunner(); } // Game move handler (for swipe) game.down = function (x, y, obj) { dragStartX = x; dragStartY = y; dragStartTime = Date.now(); }; game.up = function (x, y, obj) { if (dragStartX !== null && dragStartY !== null && dragStartTime !== null) { var dt = Date.now() - dragStartTime; handleSwipe(dragStartX, dragStartY, x, y, dt); } dragStartX = null; dragStartY = null; dragStartTime = null; }; game.move = function (x, y, obj) { // No drag-to-move, only swipe }; // Main game update loop game.update = function () { if (gameOver) return; // Increase speed over time if (speed < maxSpeed) speed += speedInc; // Score increases with distance score += Math.floor(speed / 8); scoreTxt.setText(score + ''); // Spawn obstacles if (LK.ticks - lastObstacleTick > 38 + Math.floor(60 / speed * 10)) { spawnObstacle(); lastObstacleTick = LK.ticks; } // Spawn coins if (LK.ticks - lastCoinTick > 28 + Math.floor(60 / speed * 6)) { spawnCoin(); lastCoinTick = LK.ticks; } // Spawn powerups (magnet/shield) occasionally if (LK.ticks - lastPowerupTick > 600 && Math.random() < 0.015) { if (Math.random() < 0.5) { spawnMagnet(); } else { spawnShield(); } lastPowerupTick = LK.ticks; } // Move obstacles for (var i = obstacles.length - 1; i >= 0; --i) { var obs = obstacles[i]; obs.y += speed; if (obs.y > 2732 + 100) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with runner if (!gameOver && runner && // Defensive: runner must be defined obs.lane === runner.lane && !obs.passed && obs.y + 180 > runner.y - 200 && obs.y < runner.y) { if (runner.shieldActive) { // Shield absorbs hit runner.shieldActive = false; runner.hideShield(); obs.passed = true; LK.effects.flashObject(runner, 0x00ffff, 400); } else { // Game over gameOver = true; LK.effects.flashScreen(0xff0000, 900); LK.showGameOver(); return; } } } // Move coins for (var i = coins.length - 1; i >= 0; --i) { var coin = coins[i]; coin.y += speed; if (coin.y > 2732 + 100) { coin.destroy(); coins.splice(i, 1); continue; } // Magnet effect: attract coins in any lane if active if (runner && runner.magnetActive && Math.abs(coin.y - runner.y) < 400) { var dx = laneX[runner.lane] - coin.x; coin.x += dx * 0.18; } // Collect coin if (runner && !coin.collected && Math.abs(coin.lane - runner.lane) <= (runner.magnetActive ? 1 : 0) && Math.abs(coin.y - runner.y) < 120) { coin.collected = true; coin.destroy(); coins.splice(i, 1); coinScore += 1; coinTxt.setText(coinScore + ''); LK.effects.flashObject(runner, 0xf7d21a, 200); } } // Move magnets for (var i = magnets.length - 1; i >= 0; --i) { var mag = magnets[i]; mag.y += speed; if (mag.y > 2732 + 100) { mag.destroy(); magnets.splice(i, 1); continue; } // Collect magnet if (runner && !mag.collected && mag.lane === runner.lane && Math.abs(mag.y - runner.y) < 120) { mag.collected = true; mag.destroy(); magnets.splice(i, 1); runner.magnetActive = true; runner.magnetTimer = magnetDuration; runner.showMagnet(); LK.effects.flashObject(runner, 0xff00ff, 300); } } // Move shields for (var i = shields.length - 1; i >= 0; --i) { var sh = shields[i]; sh.y += speed; if (sh.y > 2732 + 100) { sh.destroy(); shields.splice(i, 1); continue; } // Collect shield if (runner && !sh.collected && sh.lane === runner.lane && Math.abs(sh.y - runner.y) < 120) { sh.collected = true; sh.destroy(); shields.splice(i, 1); runner.shieldActive = true; runner.shieldTimer = shieldDuration; runner.showShield(); LK.effects.flashObject(runner, 0x00ffff, 300); } } // Powerup timers if (runner && runner.magnetActive) { runner.magnetTimer--; if (runner.magnetTimer <= 0) { runner.magnetActive = false; runner.hideMagnet(); } } if (runner && runner.shieldActive) { runner.shieldTimer--; if (runner.shieldTimer <= 0) { runner.shieldActive = false; runner.hideShield(); } } }; // On game start, always spawn the runner spawnRunner(); // On game over, reset state for replay LK.on('gameover', function () { resetGame(); }); LK.on('youwin', function () { resetGame(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Coin
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGfx = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1;
self.collected = false;
return self;
});
// Magnet Powerup
var Magnet = Container.expand(function () {
var self = Container.call(this);
var magGfx = self.attachAsset('magnet', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1;
self.collected = false;
return self;
});
// Obstacle (train/barrier)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1; // 0,1,2
self.passed = false;
return self;
});
// Player Runner
var Runner = Container.expand(function () {
var self = Container.call(this);
var runnerGfx = self.attachAsset('runner', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1; // 0: left, 1: center, 2: right
self.isShielded = false;
self.magnetActive = false;
self.shieldActive = false;
self.magnetTimer = 0;
self.shieldTimer = 0;
// Animate shield effect
self.showShield = function () {
if (!self.shieldCircle) {
self.shieldCircle = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 1,
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.5
});
}
self.shieldCircle.visible = true;
};
self.hideShield = function () {
if (self.shieldCircle) self.shieldCircle.visible = false;
};
// Animate magnet effect
self.showMagnet = function () {
if (!self.magnetCircle) {
self.magnetCircle = self.attachAsset('magnet', {
anchorX: 0.5,
anchorY: 1,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
});
}
self.magnetCircle.visible = true;
};
self.hideMagnet = function () {
if (self.magnetCircle) self.magnetCircle.visible = false;
};
return self;
});
// Shield Powerup
var Shield = Container.expand(function () {
var self = Container.call(this);
var shGfx = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1;
self.collected = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Add rails and grass background
// Shield Powerup
// Magnet Powerup
// Coin
// Obstacle (train/barrier)
// Character (player)
// Lane positions (3 lanes)
var railWidth = 180;
var railSpacing = 260;
var grassWidth = (2048 - (railWidth * 3 + railSpacing * 2)) / 2;
// Grass left
var grassLeft = LK.getAsset('grass', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: grassWidth,
height: 2732
});
game.addChild(grassLeft);
// Grass right
var grassRight = LK.getAsset('grass', {
anchorX: 0,
anchorY: 0,
x: 2048 - grassWidth,
y: 0,
width: grassWidth,
height: 2732
});
game.addChild(grassRight);
// Rails
var railX = [grassWidth, grassWidth + railWidth + railSpacing, grassWidth + (railWidth + railSpacing) * 2];
for (var i = 0; i < 3; ++i) {
var rail = LK.getAsset('rail', {
anchorX: 0,
anchorY: 0,
x: railX[i],
y: 0,
width: railWidth,
height: 2732
});
game.addChild(rail);
}
// Lane positions (center of each rail)
var laneX = [railX[0] + railWidth / 2, railX[1] + railWidth / 2, railX[2] + railWidth / 2];
// Track Y positions
var groundY = 2732 - 200;
// Game state
var runner;
var obstacles = [];
var coins = [];
var magnets = [];
var shields = [];
var speed = 18; // Initial speed (pixels per frame)
var maxSpeed = 38;
var speedInc = 0.0007; // Speed increase per tick
var score = 0;
var coinScore = 0;
var lastObstacleTick = 0;
var lastCoinTick = 0;
var lastPowerupTick = 0;
var dragStartX = null;
var dragStartY = null;
var dragStartTime = null;
var swipeThreshold = 80; // px
var swipeTime = 350; // ms
var isMovingLane = false;
var moveTween = null;
var magnetDuration = 600; // ticks (10s)
var shieldDuration = 600; // ticks (10s)
var gameOver = false;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Coin text
var coinTxt = new Text2('0', {
size: 80,
fill: 0xFFE066
});
coinTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(coinTxt);
// Helper: spawn runner
function spawnRunner() {
runner = new Runner();
runner.x = laneX[1];
runner.y = groundY;
runner.lane = 1;
game.addChild(runner);
}
// Helper: spawn obstacle
function spawnObstacle() {
var obs = new Obstacle();
obs.lane = Math.floor(Math.random() * 3);
obs.x = laneX[obs.lane];
obs.y = -20;
obstacles.push(obs);
game.addChild(obs);
}
// Helper: spawn coin
function spawnCoin() {
var coin = new Coin();
coin.lane = Math.floor(Math.random() * 3);
coin.x = laneX[coin.lane];
coin.y = -20;
coins.push(coin);
game.addChild(coin);
}
// Helper: spawn magnet
function spawnMagnet() {
var mag = new Magnet();
mag.lane = Math.floor(Math.random() * 3);
mag.x = laneX[mag.lane];
mag.y = -20;
magnets.push(mag);
game.addChild(mag);
}
// Helper: spawn shield
function spawnShield() {
var sh = new Shield();
sh.lane = Math.floor(Math.random() * 3);
sh.x = laneX[sh.lane];
sh.y = -20;
shields.push(sh);
game.addChild(sh);
}
// Helper: move runner to lane
function moveRunnerToLane(targetLane) {
if (isMovingLane || targetLane < 0 || targetLane > 2 || targetLane === runner.lane) return;
isMovingLane = true;
if (moveTween) tween.stop(runner, {
x: true
});
moveTween = tween(runner, {
x: laneX[targetLane]
}, {
duration: 120,
easing: tween.cubicOut,
onFinish: function onFinish() {
runner.lane = targetLane;
isMovingLane = false;
}
});
}
// Helper: handle swipe
function handleSwipe(startX, startY, endX, endY, dt) {
var dx = endX - startX;
var dy = endY - startY;
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > swipeThreshold && dt < swipeTime) {
// Horizontal swipe
if (dx > 0) {
// Swipe right
if (runner) moveRunnerToLane(runner.lane + 1);
} else {
// Swipe left
if (runner) moveRunnerToLane(runner.lane - 1);
}
}
}
// Helper: reset game state
function resetGame() {
// Remove all obstacles, coins, powerups
for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy();
for (var i = 0; i < coins.length; ++i) coins[i].destroy();
for (var i = 0; i < magnets.length; ++i) magnets[i].destroy();
for (var i = 0; i < shields.length; ++i) shields[i].destroy();
obstacles = [];
coins = [];
magnets = [];
shields = [];
if (runner) runner.destroy();
runner = null;
speed = 18;
score = 0;
coinScore = 0;
lastObstacleTick = 0;
lastCoinTick = 0;
lastPowerupTick = 0;
isMovingLane = false;
moveTween = null;
gameOver = false;
scoreTxt.setText('0');
coinTxt.setText('0');
spawnRunner();
}
// Game move handler (for swipe)
game.down = function (x, y, obj) {
dragStartX = x;
dragStartY = y;
dragStartTime = Date.now();
};
game.up = function (x, y, obj) {
if (dragStartX !== null && dragStartY !== null && dragStartTime !== null) {
var dt = Date.now() - dragStartTime;
handleSwipe(dragStartX, dragStartY, x, y, dt);
}
dragStartX = null;
dragStartY = null;
dragStartTime = null;
};
game.move = function (x, y, obj) {
// No drag-to-move, only swipe
};
// Main game update loop
game.update = function () {
if (gameOver) return;
// Increase speed over time
if (speed < maxSpeed) speed += speedInc;
// Score increases with distance
score += Math.floor(speed / 8);
scoreTxt.setText(score + '');
// Spawn obstacles
if (LK.ticks - lastObstacleTick > 38 + Math.floor(60 / speed * 10)) {
spawnObstacle();
lastObstacleTick = LK.ticks;
}
// Spawn coins
if (LK.ticks - lastCoinTick > 28 + Math.floor(60 / speed * 6)) {
spawnCoin();
lastCoinTick = LK.ticks;
}
// Spawn powerups (magnet/shield) occasionally
if (LK.ticks - lastPowerupTick > 600 && Math.random() < 0.015) {
if (Math.random() < 0.5) {
spawnMagnet();
} else {
spawnShield();
}
lastPowerupTick = LK.ticks;
}
// Move obstacles
for (var i = obstacles.length - 1; i >= 0; --i) {
var obs = obstacles[i];
obs.y += speed;
if (obs.y > 2732 + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with runner
if (!gameOver && runner &&
// Defensive: runner must be defined
obs.lane === runner.lane && !obs.passed && obs.y + 180 > runner.y - 200 && obs.y < runner.y) {
if (runner.shieldActive) {
// Shield absorbs hit
runner.shieldActive = false;
runner.hideShield();
obs.passed = true;
LK.effects.flashObject(runner, 0x00ffff, 400);
} else {
// Game over
gameOver = true;
LK.effects.flashScreen(0xff0000, 900);
LK.showGameOver();
return;
}
}
}
// Move coins
for (var i = coins.length - 1; i >= 0; --i) {
var coin = coins[i];
coin.y += speed;
if (coin.y > 2732 + 100) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Magnet effect: attract coins in any lane if active
if (runner && runner.magnetActive && Math.abs(coin.y - runner.y) < 400) {
var dx = laneX[runner.lane] - coin.x;
coin.x += dx * 0.18;
}
// Collect coin
if (runner && !coin.collected && Math.abs(coin.lane - runner.lane) <= (runner.magnetActive ? 1 : 0) && Math.abs(coin.y - runner.y) < 120) {
coin.collected = true;
coin.destroy();
coins.splice(i, 1);
coinScore += 1;
coinTxt.setText(coinScore + '');
LK.effects.flashObject(runner, 0xf7d21a, 200);
}
}
// Move magnets
for (var i = magnets.length - 1; i >= 0; --i) {
var mag = magnets[i];
mag.y += speed;
if (mag.y > 2732 + 100) {
mag.destroy();
magnets.splice(i, 1);
continue;
}
// Collect magnet
if (runner && !mag.collected && mag.lane === runner.lane && Math.abs(mag.y - runner.y) < 120) {
mag.collected = true;
mag.destroy();
magnets.splice(i, 1);
runner.magnetActive = true;
runner.magnetTimer = magnetDuration;
runner.showMagnet();
LK.effects.flashObject(runner, 0xff00ff, 300);
}
}
// Move shields
for (var i = shields.length - 1; i >= 0; --i) {
var sh = shields[i];
sh.y += speed;
if (sh.y > 2732 + 100) {
sh.destroy();
shields.splice(i, 1);
continue;
}
// Collect shield
if (runner && !sh.collected && sh.lane === runner.lane && Math.abs(sh.y - runner.y) < 120) {
sh.collected = true;
sh.destroy();
shields.splice(i, 1);
runner.shieldActive = true;
runner.shieldTimer = shieldDuration;
runner.showShield();
LK.effects.flashObject(runner, 0x00ffff, 300);
}
}
// Powerup timers
if (runner && runner.magnetActive) {
runner.magnetTimer--;
if (runner.magnetTimer <= 0) {
runner.magnetActive = false;
runner.hideMagnet();
}
}
if (runner && runner.shieldActive) {
runner.shieldTimer--;
if (runner.shieldTimer <= 0) {
runner.shieldActive = false;
runner.hideShield();
}
}
};
// On game start, always spawn the runner
spawnRunner();
// On game over, reset state for replay
LK.on('gameover', function () {
resetGame();
});
LK.on('youwin', function () {
resetGame();
});
coin. In-Game asset. 2d. High contrast. No shadows
obstacle. In-Game asset. 2d. High contrast. No shadows
man. In-Game asset. 2d. High contrast. No shadows
magnet. In-Game asset. 2d. High contrast. No shadows
shield. In-Game asset. 2d. High contrast. No shadows
road. In-Game asset. 2d. High contrast. No shadows
grass road. In-Game asset. 2d. High contrast. No shadows