/****
* 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)
};