/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // The main block the player controls var JumpBlock = Container.expand(function () { var self = Container.call(this); // Attach the block asset (a box) var block = self.attachAsset('jumpBlock', { anchorX: 0.5, anchorY: 0.5 }); // Block state self.isJumping = false; self.jumpHeight = 500; // How high the block jumps (in px) self.jumpDuration = 350; // ms for jump up self.fallDuration = 400; // ms for fall down // Store ground Y for reset self.groundY = 0; // Method to trigger jump self.jump = function (_onFinish) { if (self.isJumping) return; self.isJumping = true; // Animate up tween(self, { y: self.y - self.jumpHeight }, { duration: self.jumpDuration, easing: tween.cubicOut, onFinish: function onFinish() { // Animate down tween(self, { y: self.groundY }, { duration: self.fallDuration, easing: tween.bounceOut, onUpdate: function onUpdate() { // Check for landing on top of a spike during the fall if (typeof spikes !== "undefined" && Array.isArray(spikes)) { for (var i = 0; i < spikes.length; i++) { var s = spikes[i]; // Only check if block is falling and above the spike // Check if block's bottom is just above spike's top and horizontally overlapping var blockBottom = self.y + self.height / 2; var spikeTop = s.y - s.height / 2; var blockLastBottom = self.lastY !== undefined ? self.lastY + self.height / 2 : blockBottom; // Check if we just crossed the spike top from above if (blockLastBottom <= spikeTop && blockBottom > spikeTop && Math.abs(self.x - s.x) < (self.width / 2 + s.width / 2) * 0.7 // allow some tolerance ) { // Die if landed on spike LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } } // Track lastY for next update self.lastY = self.y; }, onFinish: function onFinish() { self.isJumping = false; if (_onFinish) _onFinish(); } }); } }); }; return self; }); // The jump arrow button var JumpButton = Container.expand(function () { var self = Container.call(this); // Attach a large ellipse as the button var btn = self.attachAsset('jumpArrowBtn', { anchorX: 0.5, anchorY: 0.5 }); // Attach an up arrow (triangle) var arrow = self.attachAsset('jumpArrow', { anchorX: 0.5, anchorY: 0.5 }); arrow.width = btn.width * 0.32; arrow.height = btn.height * 0.32; arrow.rotation = 0; // Upwards arrow.y = 0; // Visual feedback on press self.flash = function () { tween(btn, { scaleX: 0.92, scaleY: 0.92 }, { duration: 60, easing: tween.easeIn, onFinish: function onFinish() { tween(btn, { scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.easeOut }); } }); }; return self; }); // Spikes that move from right to left var Spike = Container.expand(function () { var self = Container.call(this); // Attach a triangle-like spike using the jumpArrow asset, rotated down var spike = self.attachAsset('jumpArrow', { anchorX: 0.5, anchorY: 0.5 }); spike.width = 120; spike.height = 120; spike.rotation = Math.PI; // Pointing down // Track lastX for event triggers self.lastX = 0; // Set up spike position and speed self.speed = 12; // px per frame, will be set by game self.update = function () { self.lastX = self.x; self.x -= self.speed; // Remove if off screen if (self.x < -spike.width) { if (self.parent) self.parent.removeChild(self); self.destroyed = true; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222a36 }); /**** * Game Code ****/ // Play GeometryDashSound when the game starts LK.getSound('GeometryDashSound').play(); // Old man image for YOU WIN popup // Score text // Create block asset (box) // Create jump button asset (ellipse) // Create arrow asset (box, will be rotated) var scoreTxt = new Text2('0', { size: 140, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Center block horizontally, place at bottom with margin var block = new JumpBlock(); game.addChild(block); block.x = 2048 / 2; block.groundY = 2732 - 220; block.y = block.groundY; // Place jump button above bottom, right side var jumpBtn = new JumpButton(); game.addChild(jumpBtn); // Position jump button on the right side, with a margin from the edge and a bit lower above the bottom jumpBtn.x = 2048 - 320; // 320px margin from right edge, fits button width jumpBtn.y = 2732 - 280; // moved further down (closer to bottom) // Score var score = 0; LK.setScore(0); // Touch/click handling for jump button var isBtnPressed = false; // Helper: check if point (x, y) is inside jumpBtn function isInsideJumpBtn(x, y) { // Use ellipse hit test var dx = x - jumpBtn.x; var dy = y - jumpBtn.y; var rx = jumpBtn.width / 2; var ry = jumpBtn.height / 2; return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1; } // Main move handler function handleMove(x, y, obj) { // No drag needed, just visual feedback if finger is on button if (isBtnPressed) { if (!isInsideJumpBtn(x, y)) { isBtnPressed = false; } } } // Down event: check if jumpBtn is pressed game.down = function (x, y, obj) { if (isInsideJumpBtn(x, y) && !block.isJumping) { isBtnPressed = true; jumpBtn.flash(); block.jump(function () { // On landing, increment score score += 1; LK.setScore(score); scoreTxt.setText(score); // Show ScaryFace image as a jumpscare centered in the middle if score reaches 5 if (score === 5) { var scaryFaceImg = LK.getAsset('ScaryFace', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 6, scaleY: 6 }); LK.gui.center.addChild(scaryFaceImg); // Remove the image after 2.5 seconds LK.setTimeout(function () { if (scaryFaceImg.parent) scaryFaceImg.parent.removeChild(scaryFaceImg); }, 2500); } // Show YOU WIN if score reaches 20 if (score === 20) { LK.showYouWin(); // Show old man image in the center of the screen var oldManImg = LK.getAsset('oldMan', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); LK.gui.center.addChild(oldManImg); // Remove the image after 2.5 seconds (YOU WIN popup will also reset game) LK.setTimeout(function () { if (oldManImg.parent) oldManImg.parent.removeChild(oldManImg); }, 2500); } }); } }; // Up event: reset press state game.up = function (x, y, obj) { isBtnPressed = false; }; // Move event: for touch feedback game.move = handleMove; // Spikes array var spikes = []; // How many frames between spikes var spikeInterval = 90; var spikeTimer = 0; // How fast the world moves (spikes and block) var worldSpeed = 12; // Game update: move spikes, spawn new, move block left, check collisions game.update = function () { // Move all spikes and remove destroyed ones for (var i = spikes.length - 1; i >= 0; i--) { var s = spikes[i]; s.update(); // Collision: only if block is on ground (not jumping) if (!block.isJumping && block.intersects(s)) { // Flash screen and game over LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } if (s.destroyed) { spikes.splice(i, 1); } } // Move block left to simulate screen movement (but clamp to min X) block.x -= worldSpeed; if (block.x < 400) block.x = 400; // (Do not move jump button with the world) // Spawn new spikes spikeTimer++; if (spikeTimer >= spikeInterval) { spikeTimer = 0; var newSpike = new Spike(); // Place spike at right edge, on ground newSpike.x = 2048 + 60; newSpike.y = block.groundY + 90; // Place spike base at ground newSpike.speed = worldSpeed; spikes.push(newSpike); game.addChild(newSpike); } }; // Reset score to 0 when the game is destroyed (exited) game.destroy = function () { score = 0; LK.setScore(0); // Reset spikes and world position for (var i = 0; i < spikes.length; i++) { if (spikes[i].parent) spikes[i].parent.removeChild(spikes[i]); } spikes = []; block.x = 2048 / 2; // (Do not reset jump button X, as it never moves) }; // Reset score to 0 when the game is paused game.pause = function () { score = 0; LK.setScore(0); // Reset spikes and world position for (var i = 0; i < spikes.length; i++) { if (spikes[i].parent) spikes[i].parent.removeChild(spikes[i]); } spikes = []; block.x = 2048 / 2; // (Do not reset jump button X, as it never moves) };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// The main block the player controls
var JumpBlock = Container.expand(function () {
var self = Container.call(this);
// Attach the block asset (a box)
var block = self.attachAsset('jumpBlock', {
anchorX: 0.5,
anchorY: 0.5
});
// Block state
self.isJumping = false;
self.jumpHeight = 500; // How high the block jumps (in px)
self.jumpDuration = 350; // ms for jump up
self.fallDuration = 400; // ms for fall down
// Store ground Y for reset
self.groundY = 0;
// Method to trigger jump
self.jump = function (_onFinish) {
if (self.isJumping) return;
self.isJumping = true;
// Animate up
tween(self, {
y: self.y - self.jumpHeight
}, {
duration: self.jumpDuration,
easing: tween.cubicOut,
onFinish: function onFinish() {
// Animate down
tween(self, {
y: self.groundY
}, {
duration: self.fallDuration,
easing: tween.bounceOut,
onUpdate: function onUpdate() {
// Check for landing on top of a spike during the fall
if (typeof spikes !== "undefined" && Array.isArray(spikes)) {
for (var i = 0; i < spikes.length; i++) {
var s = spikes[i];
// Only check if block is falling and above the spike
// Check if block's bottom is just above spike's top and horizontally overlapping
var blockBottom = self.y + self.height / 2;
var spikeTop = s.y - s.height / 2;
var blockLastBottom = self.lastY !== undefined ? self.lastY + self.height / 2 : blockBottom;
// Check if we just crossed the spike top from above
if (blockLastBottom <= spikeTop && blockBottom > spikeTop && Math.abs(self.x - s.x) < (self.width / 2 + s.width / 2) * 0.7 // allow some tolerance
) {
// Die if landed on spike
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
// Track lastY for next update
self.lastY = self.y;
},
onFinish: function onFinish() {
self.isJumping = false;
if (_onFinish) _onFinish();
}
});
}
});
};
return self;
});
// The jump arrow button
var JumpButton = Container.expand(function () {
var self = Container.call(this);
// Attach a large ellipse as the button
var btn = self.attachAsset('jumpArrowBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach an up arrow (triangle)
var arrow = self.attachAsset('jumpArrow', {
anchorX: 0.5,
anchorY: 0.5
});
arrow.width = btn.width * 0.32;
arrow.height = btn.height * 0.32;
arrow.rotation = 0; // Upwards
arrow.y = 0;
// Visual feedback on press
self.flash = function () {
tween(btn, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(btn, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeOut
});
}
});
};
return self;
});
// Spikes that move from right to left
var Spike = Container.expand(function () {
var self = Container.call(this);
// Attach a triangle-like spike using the jumpArrow asset, rotated down
var spike = self.attachAsset('jumpArrow', {
anchorX: 0.5,
anchorY: 0.5
});
spike.width = 120;
spike.height = 120;
spike.rotation = Math.PI; // Pointing down
// Track lastX for event triggers
self.lastX = 0;
// Set up spike position and speed
self.speed = 12; // px per frame, will be set by game
self.update = function () {
self.lastX = self.x;
self.x -= self.speed;
// Remove if off screen
if (self.x < -spike.width) {
if (self.parent) self.parent.removeChild(self);
self.destroyed = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222a36
});
/****
* Game Code
****/
// Play GeometryDashSound when the game starts
LK.getSound('GeometryDashSound').play();
// Old man image for YOU WIN popup
// Score text
// Create block asset (box)
// Create jump button asset (ellipse)
// Create arrow asset (box, will be rotated)
var scoreTxt = new Text2('0', {
size: 140,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Center block horizontally, place at bottom with margin
var block = new JumpBlock();
game.addChild(block);
block.x = 2048 / 2;
block.groundY = 2732 - 220;
block.y = block.groundY;
// Place jump button above bottom, right side
var jumpBtn = new JumpButton();
game.addChild(jumpBtn);
// Position jump button on the right side, with a margin from the edge and a bit lower above the bottom
jumpBtn.x = 2048 - 320; // 320px margin from right edge, fits button width
jumpBtn.y = 2732 - 280; // moved further down (closer to bottom)
// Score
var score = 0;
LK.setScore(0);
// Touch/click handling for jump button
var isBtnPressed = false;
// Helper: check if point (x, y) is inside jumpBtn
function isInsideJumpBtn(x, y) {
// Use ellipse hit test
var dx = x - jumpBtn.x;
var dy = y - jumpBtn.y;
var rx = jumpBtn.width / 2;
var ry = jumpBtn.height / 2;
return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1;
}
// Main move handler
function handleMove(x, y, obj) {
// No drag needed, just visual feedback if finger is on button
if (isBtnPressed) {
if (!isInsideJumpBtn(x, y)) {
isBtnPressed = false;
}
}
}
// Down event: check if jumpBtn is pressed
game.down = function (x, y, obj) {
if (isInsideJumpBtn(x, y) && !block.isJumping) {
isBtnPressed = true;
jumpBtn.flash();
block.jump(function () {
// On landing, increment score
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Show ScaryFace image as a jumpscare centered in the middle if score reaches 5
if (score === 5) {
var scaryFaceImg = LK.getAsset('ScaryFace', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 6,
scaleY: 6
});
LK.gui.center.addChild(scaryFaceImg);
// Remove the image after 2.5 seconds
LK.setTimeout(function () {
if (scaryFaceImg.parent) scaryFaceImg.parent.removeChild(scaryFaceImg);
}, 2500);
}
// Show YOU WIN if score reaches 20
if (score === 20) {
LK.showYouWin();
// Show old man image in the center of the screen
var oldManImg = LK.getAsset('oldMan', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
LK.gui.center.addChild(oldManImg);
// Remove the image after 2.5 seconds (YOU WIN popup will also reset game)
LK.setTimeout(function () {
if (oldManImg.parent) oldManImg.parent.removeChild(oldManImg);
}, 2500);
}
});
}
};
// Up event: reset press state
game.up = function (x, y, obj) {
isBtnPressed = false;
};
// Move event: for touch feedback
game.move = handleMove;
// Spikes array
var spikes = [];
// How many frames between spikes
var spikeInterval = 90;
var spikeTimer = 0;
// How fast the world moves (spikes and block)
var worldSpeed = 12;
// Game update: move spikes, spawn new, move block left, check collisions
game.update = function () {
// Move all spikes and remove destroyed ones
for (var i = spikes.length - 1; i >= 0; i--) {
var s = spikes[i];
s.update();
// Collision: only if block is on ground (not jumping)
if (!block.isJumping && block.intersects(s)) {
// Flash screen and game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
if (s.destroyed) {
spikes.splice(i, 1);
}
}
// Move block left to simulate screen movement (but clamp to min X)
block.x -= worldSpeed;
if (block.x < 400) block.x = 400;
// (Do not move jump button with the world)
// Spawn new spikes
spikeTimer++;
if (spikeTimer >= spikeInterval) {
spikeTimer = 0;
var newSpike = new Spike();
// Place spike at right edge, on ground
newSpike.x = 2048 + 60;
newSpike.y = block.groundY + 90; // Place spike base at ground
newSpike.speed = worldSpeed;
spikes.push(newSpike);
game.addChild(newSpike);
}
};
// Reset score to 0 when the game is destroyed (exited)
game.destroy = function () {
score = 0;
LK.setScore(0);
// Reset spikes and world position
for (var i = 0; i < spikes.length; i++) {
if (spikes[i].parent) spikes[i].parent.removeChild(spikes[i]);
}
spikes = [];
block.x = 2048 / 2;
// (Do not reset jump button X, as it never moves)
};
// Reset score to 0 when the game is paused
game.pause = function () {
score = 0;
LK.setScore(0);
// Reset spikes and world position
for (var i = 0; i < spikes.length; i++) {
if (spikes[i].parent) spikes[i].parent.removeChild(spikes[i]);
}
spikes = [];
block.x = 2048 / 2;
// (Do not reset jump button X, as it never moves)
};