/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Cloud (background) var Cloud = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); self.width = sprite.width; self.height = sprite.height; self.speed = 3 + Math.random() * 2; self.update = function () { self.x -= self.speed; }; return self; }); // Crocodile (underground obstacle) var Croc = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('croc', { anchorX: 0.5, anchorY: 1 }); self.width = sprite.width; self.height = sprite.height; self.speed = 24; self.update = function () { self.x -= self.speed; }; return self; }); // Pipe (portal) var Pipe = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 1 }); self.width = sprite.width; self.height = sprite.height; self.speed = 22; self.update = function () { self.x -= self.speed; }; return self; }); // Plumber (player) class var Plumber = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('plumber', { anchorX: 0.5, anchorY: 1 }); self.width = sprite.width; self.height = sprite.height; self.isJumping = false; self.jumpVY = 0; self.gravity = 3.5; self.jumpPower = -55; self.groundY = 0; // Set by game on spawn self.state = 'surface'; // 'surface' or 'lahim' self.update = function () { // Gravity/jump if (self.isJumping) { self.y += self.jumpVY; self.jumpVY += self.gravity; if (self.y >= self.groundY) { self.y = self.groundY; self.isJumping = false; self.jumpVY = 0; } } }; // Jump method self.jump = function () { if (!self.isJumping) { self.isJumping = true; self.jumpVY = self.jumpPower; LK.getSound('jump').play(); } }; // For pipe transition self.setState = function (state, groundY) { self.state = state; self.groundY = groundY; if (self.y > groundY) self.y = groundY; self.isJumping = false; self.jumpVY = 0; }; return self; }); // Thorn (surface obstacle) var Thorn = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('thorn', { anchorX: 0.5, anchorY: 1 }); self.width = sprite.width; self.height = sprite.height; self.speed = 22; self.update = function () { self.x -= self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x7ecbff // blue sky }); /**** * Game Code ****/ // Add a background for lahim section (gray bricks, pixel art style) // darker gray for pixel art // Sound for fail // Sound for pipe // Sound for jump // Cloud - white ellipse // Sky background - blue box // Underground floor - dark gray box // Ground (surface) - brown box // Pipe (portal between worlds) - green ellipse // Crocodile (underground obstacle) - green box // Thorn (surface obstacle) - purple ellipse // Plumber (player) - red box // Constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var GROUND_HEIGHT = 120; var LAHIM_HEIGHT = 120; var PLUMBER_X = 420; var SURFACE_GROUND_Y = GAME_HEIGHT - GROUND_HEIGHT; var LAHIM_GROUND_Y = GAME_HEIGHT - LAHIM_HEIGHT; var OBSTACLE_SPAWN_X = GAME_WIDTH + 200; // State var plumber; var ground; var lahimfloor; var sky; var clouds = []; var obstacles = []; var pipe = null; var inLahim = false; var score = 0; var scoreTxt; var lastObstacleTick = 0; var lastCloudTick = 0; var pipeCooldown = 0; var dragNode = null; var gameOver = false; var transitionAnim = false; // --- Setup background --- sky = LK.getAsset('sky', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(sky); // Clouds function spawnCloud() { var c = new Cloud(); c.x = GAME_WIDTH + 200 + Math.random() * 400; c.y = 200 + Math.random() * 600; c.speed = 2 + Math.random() * 2; clouds.push(c); game.addChild(c); } // --- Setup ground --- ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: SURFACE_GROUND_Y }); game.addChild(ground); // Lahim background (hidden at start) var lahim_bg = LK.getAsset('lahim_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); lahim_bg.visible = false; game.addChild(lahim_bg); // Underground floor (hidden at start) lahimfloor = LK.getAsset('lahimfloor', { anchorX: 0, anchorY: 0, x: 0, y: LAHIM_GROUND_Y }); lahimfloor.visible = false; game.addChild(lahimfloor); // --- Setup plumber --- plumber = new Plumber(); plumber.x = PLUMBER_X; plumber.groundY = SURFACE_GROUND_Y; plumber.y = SURFACE_GROUND_Y; plumber.state = 'surface'; game.addChild(plumber); // --- Setup score text --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Game tap/jump handler --- game.down = function (x, y, obj) { if (transitionAnim || gameOver) return; plumber.jump(); }; // --- Main update loop --- game.update = function () { if (gameOver) return; // Clouds if (!inLahim && LK.ticks - lastCloudTick > 60) { spawnCloud(); lastCloudTick = LK.ticks; } for (var i = clouds.length - 1; i >= 0; i--) { var c = clouds[i]; c.update(); if (c.x < -c.width) { c.destroy(); clouds.splice(i, 1); } } // Pipe cooldown if (pipeCooldown > 0) pipeCooldown--; // Obstacles and pipe for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); if (obs.x < -200) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with plumber if (!transitionAnim && obs.intersects(plumber)) { if (inLahim) { // If it's a Croc, fail in lahim: now game over if (obs instanceof Croc) { failLahim(); return; } } else { // Fail on surface: game over failSurface(); return; } } } // Pipe logic if (pipe) { pipe.update(); if (pipe.x < -200) { pipe.destroy(); pipe = null; } else if (!transitionAnim && pipe.intersects(plumber)) { enterLahim(); } } // Plumber update plumber.update(); // Spawn obstacles if (!transitionAnim && LK.ticks - lastObstacleTick > (inLahim ? 60 : 50)) { lastObstacleTick = LK.ticks; if (!inLahim) { // Surface: spawn thorn or pipe if (!pipe && Math.random() < 0.18 && pipeCooldown === 0) { pipe = new Pipe(); pipe.x = OBSTACLE_SPAWN_X; pipe.y = SURFACE_GROUND_Y; game.addChild(pipe); pipeCooldown = 180; } else { var thorn = new Thorn(); thorn.x = OBSTACLE_SPAWN_X; thorn.y = SURFACE_GROUND_Y; obstacles.push(thorn); game.addChild(thorn); } } else { // Lahim: spawn croc (no pipes or clouds in lahim) var croc = new Croc(); croc.x = OBSTACLE_SPAWN_X; croc.y = LAHIM_GROUND_Y; obstacles.push(croc); game.addChild(croc); } } // Score: every tick plumber passes an obstacle, +1 for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; if (!obs.passed && obs.x + obs.width / 2 < plumber.x - plumber.width / 2) { obs.passed = true; score++; scoreTxt.setText(score); } } }; // --- Enter lahim (underground) --- function enterLahim() { transitionAnim = true; LK.getSound('pipe').play(); // Animate plumber into pipe (down) tween(plumber, { y: plumber.y + 200 }, { duration: 220, easing: tween.easeIn, onFinish: function onFinish() { // Switch to lahim inLahim = true; plumber.setState('lahim', LAHIM_GROUND_Y); ground.visible = false; lahimfloor.visible = true; lahim_bg.visible = true; sky.visible = false; // Remove all surface obstacles for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Hide all clouds in lahim for (var i = 0; i < clouds.length; i++) { clouds[i].visible = false; } if (pipe) { pipe.destroy(); pipe = null; } // Animate plumber up from below plumber.y = LAHIM_GROUND_Y + 200; tween(plumber, { y: LAHIM_GROUND_Y }, { duration: 220, easing: tween.easeOut, onFinish: function onFinish() { transitionAnim = false; } }); } }); } // --- Fail in lahim: game over --- function failLahim() { gameOver = true; LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } // --- Fail on surface: game over --- function failSurface() { gameOver = true; LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } // --- Reset state on game restart --- game.on('reset', function () { // Remove all obstacles, clouds, pipe for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy(); obstacles = []; for (var i = 0; i < clouds.length; i++) { clouds[i].destroy(); clouds[i].visible = true; } clouds = []; if (pipe) { pipe.destroy(); pipe = null; } inLahim = false; plumber.setState('surface', SURFACE_GROUND_Y); plumber.x = PLUMBER_X; plumber.y = SURFACE_GROUND_Y; ground.visible = true; lahimfloor.visible = false; lahim_bg.visible = false; sky.visible = true; score = 0; scoreTxt.setText(score); lastObstacleTick = LK.ticks; lastCloudTick = LK.ticks; pipeCooldown = 0; gameOver = false; transitionAnim = false; });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cloud (background)
var Cloud = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = sprite.width;
self.height = sprite.height;
self.speed = 3 + Math.random() * 2;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Crocodile (underground obstacle)
var Croc = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('croc', {
anchorX: 0.5,
anchorY: 1
});
self.width = sprite.width;
self.height = sprite.height;
self.speed = 24;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Pipe (portal)
var Pipe = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
self.width = sprite.width;
self.height = sprite.height;
self.speed = 22;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Plumber (player) class
var Plumber = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('plumber', {
anchorX: 0.5,
anchorY: 1
});
self.width = sprite.width;
self.height = sprite.height;
self.isJumping = false;
self.jumpVY = 0;
self.gravity = 3.5;
self.jumpPower = -55;
self.groundY = 0; // Set by game on spawn
self.state = 'surface'; // 'surface' or 'lahim'
self.update = function () {
// Gravity/jump
if (self.isJumping) {
self.y += self.jumpVY;
self.jumpVY += self.gravity;
if (self.y >= self.groundY) {
self.y = self.groundY;
self.isJumping = false;
self.jumpVY = 0;
}
}
};
// Jump method
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.jumpVY = self.jumpPower;
LK.getSound('jump').play();
}
};
// For pipe transition
self.setState = function (state, groundY) {
self.state = state;
self.groundY = groundY;
if (self.y > groundY) self.y = groundY;
self.isJumping = false;
self.jumpVY = 0;
};
return self;
});
// Thorn (surface obstacle)
var Thorn = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('thorn', {
anchorX: 0.5,
anchorY: 1
});
self.width = sprite.width;
self.height = sprite.height;
self.speed = 22;
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x7ecbff // blue sky
});
/****
* Game Code
****/
// Add a background for lahim section (gray bricks, pixel art style)
// darker gray for pixel art
// Sound for fail
// Sound for pipe
// Sound for jump
// Cloud - white ellipse
// Sky background - blue box
// Underground floor - dark gray box
// Ground (surface) - brown box
// Pipe (portal between worlds) - green ellipse
// Crocodile (underground obstacle) - green box
// Thorn (surface obstacle) - purple ellipse
// Plumber (player) - red box
// Constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GROUND_HEIGHT = 120;
var LAHIM_HEIGHT = 120;
var PLUMBER_X = 420;
var SURFACE_GROUND_Y = GAME_HEIGHT - GROUND_HEIGHT;
var LAHIM_GROUND_Y = GAME_HEIGHT - LAHIM_HEIGHT;
var OBSTACLE_SPAWN_X = GAME_WIDTH + 200;
// State
var plumber;
var ground;
var lahimfloor;
var sky;
var clouds = [];
var obstacles = [];
var pipe = null;
var inLahim = false;
var score = 0;
var scoreTxt;
var lastObstacleTick = 0;
var lastCloudTick = 0;
var pipeCooldown = 0;
var dragNode = null;
var gameOver = false;
var transitionAnim = false;
// --- Setup background ---
sky = LK.getAsset('sky', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(sky);
// Clouds
function spawnCloud() {
var c = new Cloud();
c.x = GAME_WIDTH + 200 + Math.random() * 400;
c.y = 200 + Math.random() * 600;
c.speed = 2 + Math.random() * 2;
clouds.push(c);
game.addChild(c);
}
// --- Setup ground ---
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: SURFACE_GROUND_Y
});
game.addChild(ground);
// Lahim background (hidden at start)
var lahim_bg = LK.getAsset('lahim_bg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
lahim_bg.visible = false;
game.addChild(lahim_bg);
// Underground floor (hidden at start)
lahimfloor = LK.getAsset('lahimfloor', {
anchorX: 0,
anchorY: 0,
x: 0,
y: LAHIM_GROUND_Y
});
lahimfloor.visible = false;
game.addChild(lahimfloor);
// --- Setup plumber ---
plumber = new Plumber();
plumber.x = PLUMBER_X;
plumber.groundY = SURFACE_GROUND_Y;
plumber.y = SURFACE_GROUND_Y;
plumber.state = 'surface';
game.addChild(plumber);
// --- Setup score text ---
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Game tap/jump handler ---
game.down = function (x, y, obj) {
if (transitionAnim || gameOver) return;
plumber.jump();
};
// --- Main update loop ---
game.update = function () {
if (gameOver) return;
// Clouds
if (!inLahim && LK.ticks - lastCloudTick > 60) {
spawnCloud();
lastCloudTick = LK.ticks;
}
for (var i = clouds.length - 1; i >= 0; i--) {
var c = clouds[i];
c.update();
if (c.x < -c.width) {
c.destroy();
clouds.splice(i, 1);
}
}
// Pipe cooldown
if (pipeCooldown > 0) pipeCooldown--;
// Obstacles and pipe
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
if (obs.x < -200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with plumber
if (!transitionAnim && obs.intersects(plumber)) {
if (inLahim) {
// If it's a Croc, fail in lahim: now game over
if (obs instanceof Croc) {
failLahim();
return;
}
} else {
// Fail on surface: game over
failSurface();
return;
}
}
}
// Pipe logic
if (pipe) {
pipe.update();
if (pipe.x < -200) {
pipe.destroy();
pipe = null;
} else if (!transitionAnim && pipe.intersects(plumber)) {
enterLahim();
}
}
// Plumber update
plumber.update();
// Spawn obstacles
if (!transitionAnim && LK.ticks - lastObstacleTick > (inLahim ? 60 : 50)) {
lastObstacleTick = LK.ticks;
if (!inLahim) {
// Surface: spawn thorn or pipe
if (!pipe && Math.random() < 0.18 && pipeCooldown === 0) {
pipe = new Pipe();
pipe.x = OBSTACLE_SPAWN_X;
pipe.y = SURFACE_GROUND_Y;
game.addChild(pipe);
pipeCooldown = 180;
} else {
var thorn = new Thorn();
thorn.x = OBSTACLE_SPAWN_X;
thorn.y = SURFACE_GROUND_Y;
obstacles.push(thorn);
game.addChild(thorn);
}
} else {
// Lahim: spawn croc (no pipes or clouds in lahim)
var croc = new Croc();
croc.x = OBSTACLE_SPAWN_X;
croc.y = LAHIM_GROUND_Y;
obstacles.push(croc);
game.addChild(croc);
}
}
// Score: every tick plumber passes an obstacle, +1
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
if (!obs.passed && obs.x + obs.width / 2 < plumber.x - plumber.width / 2) {
obs.passed = true;
score++;
scoreTxt.setText(score);
}
}
};
// --- Enter lahim (underground) ---
function enterLahim() {
transitionAnim = true;
LK.getSound('pipe').play();
// Animate plumber into pipe (down)
tween(plumber, {
y: plumber.y + 200
}, {
duration: 220,
easing: tween.easeIn,
onFinish: function onFinish() {
// Switch to lahim
inLahim = true;
plumber.setState('lahim', LAHIM_GROUND_Y);
ground.visible = false;
lahimfloor.visible = true;
lahim_bg.visible = true;
sky.visible = false;
// Remove all surface obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Hide all clouds in lahim
for (var i = 0; i < clouds.length; i++) {
clouds[i].visible = false;
}
if (pipe) {
pipe.destroy();
pipe = null;
}
// Animate plumber up from below
plumber.y = LAHIM_GROUND_Y + 200;
tween(plumber, {
y: LAHIM_GROUND_Y
}, {
duration: 220,
easing: tween.easeOut,
onFinish: function onFinish() {
transitionAnim = false;
}
});
}
});
}
// --- Fail in lahim: game over ---
function failLahim() {
gameOver = true;
LK.getSound('fail').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
// --- Fail on surface: game over ---
function failSurface() {
gameOver = true;
LK.getSound('fail').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
// --- Reset state on game restart ---
game.on('reset', function () {
// Remove all obstacles, clouds, pipe
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
obstacles = [];
for (var i = 0; i < clouds.length; i++) {
clouds[i].destroy();
clouds[i].visible = true;
}
clouds = [];
if (pipe) {
pipe.destroy();
pipe = null;
}
inLahim = false;
plumber.setState('surface', SURFACE_GROUND_Y);
plumber.x = PLUMBER_X;
plumber.y = SURFACE_GROUND_Y;
ground.visible = true;
lahimfloor.visible = false;
lahim_bg.visible = false;
sky.visible = true;
score = 0;
scoreTxt.setText(score);
lastObstacleTick = LK.ticks;
lastCloudTick = LK.ticks;
pipeCooldown = 0;
gameOver = false;
transitionAnim = false;
});
A man with a mustache. In the style of Pixek Art.. In-Game asset. 2d. High contrast. No shadows
white thorn. flat. thick bottom. upright. pixel art.. In-Game asset. 2d. High contrast. No shadows
green pipe. pixel art.. In-Game asset. 2d. High contrast. No shadows
a grey, brick floor. pixel art.. In-Game asset. 2d. High contrast. No shadows
green crocodile. looking left. pixel art.. In-Game asset. 2d. High contrast. No shadows
sunny sky. no cloud. pixel art.. In-Game asset. 2d. High contrast. No shadows
white cloud. pixel art.. In-Game asset. 2d. High contrast. No shadows
a brown, flat strip with green top (due to short, flat grass) pixel art.. In-Game asset. 2d. High contrast. No shadows