/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
musicVolume: 1
});
/****
* Classes
****/
var ControlButton = Container.expand(function (type) {
var self = Container.call(this);
self.buttonType = type;
self.isPressed = false;
var buttonGraphics;
if (type === 'jump') {
buttonGraphics = self.attachAsset('jumpButton', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'run') {
buttonGraphics = self.attachAsset('runButton', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
buttonGraphics = self.attachAsset(type === 'left' ? 'leftButton' : 'rightButton', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Add larger transparent hitbox for easier touch detection
var hitboxSize = 240; // Larger than visual button (180px)
var hitbox = LK.getAsset('jumpButton', {
anchorX: 0.5,
anchorY: 0.5,
width: hitboxSize,
height: hitboxSize,
alpha: 0 // Invisible
});
self.addChild(hitbox);
self.down = function (x, y, obj) {
self.isPressed = true;
// Scale down and change alpha for press effect
tween(buttonGraphics, {
scaleX: 0.85,
scaleY: 0.85,
alpha: 0.7
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
self.isPressed = false;
// Scale back up and restore alpha for release effect
tween(buttonGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
};
// Add idle floating animation
self.animationTimer = Math.random() * 100; // Random start offset
self.update = function () {
if (!self.isPressed) {
// Gentle floating animation when not pressed
self.animationTimer += 0.05;
var floatOffset = Math.sin(self.animationTimer) * 3;
buttonGraphics.y = floatOffset;
// Subtle breathing scale effect
var breathingScale = 1.0 + Math.sin(self.animationTimer * 2) * 0.02;
if (!buttonGraphics._tweening) {
buttonGraphics.scaleX = breathingScale;
buttonGraphics.scaleY = breathingScale;
}
}
};
return self;
});
var MenuButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Add menu icon (three lines)
var line1 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line1.anchor.set(0.5, 0.5);
line1.y = -15;
self.addChild(line1);
var line2 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line2.anchor.set(0.5, 0.5);
self.addChild(line2);
var line3 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line3.anchor.set(0.5, 0.5);
line3.y = 15;
self.addChild(line3);
self.down = function (x, y, obj) {
// Scale down for press effect
tween(buttonGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
// Show menu
showMenu();
};
self.up = function (x, y, obj) {
// Scale back up
tween(buttonGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
};
return self;
});
var MenuOverlay = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var background = LK.getAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
alpha: 0.8
});
background.interactive = true;
self.addChild(background);
// Menu panel
var menuPanel = self.attachAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5
});
// Menu title
var titleText = new Text2('MENU', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
// Restart Level button
var restartButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
restartButton.y = -150;
restartButton.interactive = true;
var restartText = new Text2('RESTART LEVEL', {
size: 36,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartButton.addChild(restartText);
restartButton.down = function () {
tween(restartButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButton.up = function () {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show final score before restart
LK.setScore(gamePoints);
// Reset points for new game
gamePoints = 0;
pointsText.setText('Points: 0');
// Reset power usage flags
superJumpUsed = false;
slowFallModeUsed = false;
// Restart current level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
player.velocityX = 0;
player.velocityY = 0;
player.powerUpActive = false;
player.slowFallActive = false;
player.jumpPower = player.baseJumpPower;
player.gravity = player.baseGravity;
hideMenu();
}
});
};
// Music Volume Controls
var volumeText = new Text2('MUSIC VOLUME', {
size: 32,
fill: 0xFFFFFF
});
volumeText.anchor.set(0.5, 0.5);
volumeText.y = -100;
self.addChild(volumeText);
var volumeDisplayText = new Text2(Math.round(musicVolume * 100) + '%', {
size: 28,
fill: 0xf39c12
});
volumeDisplayText.anchor.set(0.5, 0.5);
volumeDisplayText.y = -60;
self.addChild(volumeDisplayText);
// Volume Down Button
var volumeDownButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeDownButton.x = -100;
volumeDownButton.y = -20;
volumeDownButton.interactive = true;
var volumeDownText = new Text2('−', {
size: 40,
fill: 0xFFFFFF
});
volumeDownText.anchor.set(0.5, 0.5);
volumeDownButton.addChild(volumeDownText);
volumeDownButton.down = function () {
tween(volumeDownButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
volumeDownButton.up = function () {
tween(volumeDownButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
decreaseMusicVolume();
volumeDisplayText.setText(Math.round(musicVolume * 100) + '%');
}
});
};
// Volume Up Button
var volumeUpButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeUpButton.x = 100;
volumeUpButton.y = -20;
volumeUpButton.interactive = true;
var volumeUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
volumeUpText.anchor.set(0.5, 0.5);
volumeUpButton.addChild(volumeUpText);
volumeUpButton.down = function () {
tween(volumeUpButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
volumeUpButton.up = function () {
tween(volumeUpButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
increaseMusicVolume();
volumeDisplayText.setText(Math.round(musicVolume * 100) + '%');
}
});
};
// Sky Color Controls
var skyColorText = new Text2('SKY COLOR', {
size: 32,
fill: 0xFFFFFF
});
skyColorText.anchor.set(0.5, 0.5);
skyColorText.y = 40;
self.addChild(skyColorText);
// Previous Sky Color Button
var skyPrevButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
skyPrevButton.x = -100;
skyPrevButton.y = 80;
skyPrevButton.interactive = true;
var skyPrevText = new Text2('←', {
size: 40,
fill: 0xFFFFFF
});
skyPrevText.anchor.set(0.5, 0.5);
skyPrevButton.addChild(skyPrevText);
skyPrevButton.down = function () {
tween(skyPrevButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
skyPrevButton.up = function () {
tween(skyPrevButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
var prevIndex = currentSkyColorIndex - 1;
if (prevIndex < 0) {
prevIndex = skyColors.length - 1;
}
changeSkyColor(prevIndex);
}
});
};
// Next Sky Color Button
var skyNextButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
skyNextButton.x = 100;
skyNextButton.y = 80;
skyNextButton.interactive = true;
var skyNextText = new Text2('→', {
size: 40,
fill: 0xFFFFFF
});
skyNextText.anchor.set(0.5, 0.5);
skyNextButton.addChild(skyNextText);
skyNextButton.down = function () {
tween(skyNextButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
skyNextButton.up = function () {
tween(skyNextButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
cycleSkyColor();
}
});
};
// Random Sky Color Button
var skyRandomButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
skyRandomButton.y = 140;
skyRandomButton.interactive = true;
var skyRandomText = new Text2('RANDOM SKY', {
size: 28,
fill: 0xFFFFFF
});
skyRandomText.anchor.set(0.5, 0.5);
skyRandomButton.addChild(skyRandomText);
skyRandomButton.down = function () {
tween(skyRandomButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
skyRandomButton.up = function () {
tween(skyRandomButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
var randomIndex = getRandomSkyColor();
changeSkyColor(randomIndex);
}
});
};
// Cycle Sky Colors Button
var cycleSkyButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
cycleSkyButton.y = 200;
cycleSkyButton.interactive = true;
var cycleSkyText = new Text2('CYCLE SKY COLORS', {
size: 28,
fill: 0xFFFFFF
});
cycleSkyText.anchor.set(0.5, 0.5);
cycleSkyButton.addChild(cycleSkyText);
cycleSkyButton.down = function () {
tween(cycleSkyButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
cycleSkyButton.up = function () {
tween(cycleSkyButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start automatic sky color cycling
startSkyCycling();
}
});
};
// Close button
var closeButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 260;
closeButton.interactive = true;
var closeText = new Text2('CLOSE', {
size: 36,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
hideMenu();
}
});
};
// Background click to close
background.down = function () {
hideMenu();
};
return self;
});
var Platform = Container.expand(function (width, height, number) {
var self = Container.call(this);
self.platformWidth = width || 300;
self.platformHeight = height || 40;
self.platformNumber = number || 0;
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.platformWidth / 300,
scaleY: self.platformHeight / 40
});
// Add number text if platform has a number
if (self.platformNumber > 0) {
var numberText = new Text2(self.platformNumber.toString(), {
size: 30,
fill: 0x000000
});
numberText.anchor.set(0.5, 0.5);
self.addChild(numberText);
}
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 12;
self.runSpeed = 20;
self.isRunning = false;
self.jumpPower = 30;
self.baseJumpPower = 30;
self.powerUpJumpPower = 45;
self.powerUpActive = false;
self.powerUpTimer = 0;
self.slowFallActive = false;
self.slowFallTimer = 0;
self.gravity = 0.8;
self.baseGravity = 0.8;
self.slowFallGravity = 0.25;
self.onGround = false;
self.canDoubleJump = false;
self.hasDoubleJumped = false;
self.parachute = null;
self.boots = null;
self.maxFallSpeed = 15;
// Animation states
self.animationState = 'idle'; // 'idle', 'falling', 'jumping'
self.lastOnGround = true;
self.animationTimer = 0;
self.moveLeft = function () {
self.velocityX = self.isRunning ? -self.runSpeed : -self.speed;
};
self.moveRight = function () {
self.velocityX = self.isRunning ? self.runSpeed : self.speed;
};
self.setRunning = function (running) {
self.isRunning = running;
};
self.jump = function () {
if (self.onGround) {
self.velocityY = -self.jumpPower;
self.onGround = false;
self.canDoubleJump = true;
self.hasDoubleJumped = false;
// Play voice sound when jumping
LK.getSound('Voz').play();
} else if (self.canDoubleJump && !self.hasDoubleJumped) {
// Double jump
self.velocityY = -self.jumpPower * 0.9; // Slightly weaker than first jump
self.hasDoubleJumped = true;
self.canDoubleJump = false;
// Play voice sound when double jumping
LK.getSound('Voz').play();
// Flash player purple to show double jump
LK.effects.flashObject(self, 0x9b59b6, 200);
}
};
self.stopHorizontalMovement = function () {
self.velocityX = 0;
};
self.collectPowerUp = function () {
self.powerUpActive = true;
self.powerUpTimer = 300; // 5 seconds at 60fps
self.jumpPower = self.powerUpJumpPower;
// Flash player green to show power-up is active
LK.effects.flashObject(self, 0x00ff00, 300);
// Create boots visual effect
self.boots = LK.getAsset('boots', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0
});
self.addChild(self.boots);
self.boots.x = 0;
self.boots.y = 0; // Position at player's feet
// Animate boots appearing
tween(self.boots, {
alpha: 1.0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
};
self.collectSlowFallPowerUp = function () {
self.slowFallActive = true;
self.slowFallTimer = 300; // 5 seconds at 60fps
self.gravity = self.slowFallGravity;
// Flash player blue to show slow fall is active
LK.effects.flashObject(self, 0x3498db, 300);
// Add gentle blue tint while active
tween(playerGraphics, {
tint: 0xadd8e6
}, {
duration: 300,
easing: tween.easeOut
});
// Create parachute
self.parachute = LK.getAsset('parachute', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0
});
self.addChild(self.parachute);
self.parachute.x = 0;
self.parachute.y = -200; // Position above player
// Animate parachute appearing
tween(self.parachute, {
alpha: 0.8,
y: -180
}, {
duration: 500,
easing: tween.easeOut
});
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Limit fall speed
if (self.velocityY > self.maxFallSpeed) {
self.velocityY = self.maxFallSpeed;
}
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Flip sprite based on movement direction
if (self.velocityX > 0) {
// Moving right - face right (normal)
playerGraphics.scaleX = Math.abs(playerGraphics.scaleX);
} else if (self.velocityX < 0) {
// Moving left - face left (flipped)
playerGraphics.scaleX = -Math.abs(playerGraphics.scaleX);
}
// Update animation timer
self.animationTimer += 0.1;
// Determine animation state
var newAnimationState = 'idle';
if (!self.onGround && self.velocityY < -5) {
newAnimationState = 'jumping';
} else if (!self.onGround && self.velocityY > 5) {
newAnimationState = 'falling';
} else if (self.onGround && self.velocityX !== 0) {
newAnimationState = 'walking';
} else if (self.onGround) {
newAnimationState = 'idle';
}
// Apply animations based on state transitions
if (self.animationState !== newAnimationState) {
// State changed, apply new animation
if (newAnimationState === 'jumping') {
// Jump animation - stretch upward
tween(playerGraphics, {
scaleY: 1.3,
scaleX: 0.8,
rotation: self.velocityX > 0 ? 0.1 : self.velocityX < 0 ? -0.1 : 0
}, {
duration: 200,
easing: tween.easeOut
});
} else if (newAnimationState === 'falling') {
// Fall animation - compress and tilt
tween(playerGraphics, {
scaleY: 0.7,
scaleX: 1.2,
rotation: self.velocityX > 0 ? 0.2 : self.velocityX < 0 ? -0.2 : 0
}, {
duration: 300,
easing: tween.easeOut
});
} else if (newAnimationState === 'idle' && !self.lastOnGround && self.onGround) {
// Landing animation - squash and recover
tween(playerGraphics, {
scaleY: 0.6,
scaleX: 1.4,
rotation: 0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
} else if (newAnimationState === 'walking') {
// Walking animation - return to normal scale for bouncing
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
} else if (newAnimationState === 'idle') {
// Return to idle animation
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Continuous animations based on state
if (newAnimationState === 'idle' && self.onGround) {
// Gentle breathing effect
var breathingScale = 1.0 + Math.sin(self.animationTimer * 2) * 0.02;
if (!playerGraphics._tweening) {
// Only apply if not currently tweening
playerGraphics.scaleY = breathingScale;
}
} else if (newAnimationState === 'walking' && self.onGround) {
// Walking animation - bouncing effect (slower)
var walkingBounce = 1.0 + Math.sin(self.animationTimer * 4) * 0.15;
var walkingTilt = Math.sin(self.animationTimer * 4) * 0.05;
if (!playerGraphics._tweening) {
// Only apply if not currently tweening
playerGraphics.scaleY = walkingBounce;
playerGraphics.rotation = walkingTilt * (self.velocityX > 0 ? 1 : -1);
}
}
// Update states for next frame
self.animationState = newAnimationState;
self.lastOnGround = self.onGround;
// Keep player within screen bounds horizontally
if (self.x < 90) {
self.x = 90;
}
if (self.x > 1958) {
self.x = 1958;
}
// Handle power-up timer
if (self.powerUpActive) {
self.powerUpTimer--;
if (self.powerUpTimer <= 0) {
self.powerUpActive = false;
self.jumpPower = self.baseJumpPower;
// Flash player red to show power-up expired
LK.effects.flashObject(self, 0xff0000, 200);
// Remove boots with animation
if (self.boots) {
tween(self.boots, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.boots) {
self.removeChild(self.boots);
self.boots = null;
}
}
});
}
}
}
// Handle slow fall timer
if (self.slowFallActive) {
self.slowFallTimer--;
// Animate parachute swaying
if (self.parachute) {
var swayAmount = Math.sin(self.animationTimer * 3) * 15;
self.parachute.x = swayAmount;
self.parachute.rotation = Math.sin(self.animationTimer * 2) * 0.1;
}
if (self.slowFallTimer <= 0) {
self.slowFallActive = false;
self.gravity = self.baseGravity;
// Flash player red to show slow fall expired and remove tint
LK.effects.flashObject(self, 0xff0000, 200);
tween(playerGraphics, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
// Remove parachute with animation
if (self.parachute) {
tween(self.parachute, {
alpha: 0,
y: -220
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parachute) {
self.removeChild(self.parachute);
self.parachute = null;
}
}
});
}
}
}
// Reset double jump when landing
if (self.onGround && !self.lastOnGround) {
self.canDoubleJump = false;
self.hasDoubleJumped = false;
}
// Reset onGround flag
self.onGround = false;
};
return self;
});
var PowerMenuOverlay = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var background = LK.getAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
alpha: 0.8
});
background.interactive = true;
self.addChild(background);
// Menu panel
var menuPanel = self.attachAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5
});
// Menu title
var titleText = new Text2('POWER MENU', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
// Super Jump Button
var superJumpButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
superJumpButton.y = -150;
superJumpButton.interactive = true;
var superJumpText = new Text2('SUPER JUMP', {
size: 36,
fill: 0xFFFFFF
});
superJumpText.anchor.set(0.5, 0.5);
superJumpButton.addChild(superJumpText);
superJumpButton.down = function () {
tween(superJumpButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
superJumpButton.up = function () {
tween(superJumpButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check if super jump has already been used
if (!superJumpUsed) {
// Activate super jump mode
activateSuperJumpMode();
superJumpUsed = true;
// Update button appearance to show it's used
superJumpText.setText('USED');
superJumpButton.alpha = 0.5;
superJumpButton.interactive = false;
}
hidePowerMenu();
}
});
};
// Slow Fall Button
var slowFallButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
slowFallButton.y = -50;
slowFallButton.interactive = true;
var slowFallButtonText = new Text2('SLOW FALL MODE', {
size: 36,
fill: 0xFFFFFF
});
slowFallButtonText.anchor.set(0.5, 0.5);
slowFallButton.addChild(slowFallButtonText);
slowFallButton.down = function () {
tween(slowFallButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
slowFallButton.up = function () {
tween(slowFallButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check if slow fall mode has already been used
if (!slowFallModeUsed) {
// Activate slow fall mode
activateSlowFallMode();
slowFallModeUsed = true;
// Update button appearance to show it's used
slowFallButtonText.setText('USED');
slowFallButton.alpha = 0.5;
slowFallButton.interactive = false;
}
hidePowerMenu();
}
});
};
// Close button
var closeButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 50;
closeButton.interactive = true;
var closeText = new Text2('CLOSE', {
size: 36,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
hidePowerMenu();
}
});
};
// Background click to close
background.down = function () {
hidePowerMenu();
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.collected = false;
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual indicator (star symbol)
var starText = new Text2('★', {
size: 30,
fill: 0xFFFFFF
});
starText.anchor.set(0.5, 0.5);
self.addChild(starText);
// Floating animation
self.floatOffset = 0;
self.update = function () {
// Create floating effect
self.floatOffset += 0.1;
powerupGraphics.y = Math.sin(self.floatOffset) * 10;
starText.y = Math.sin(self.floatOffset) * 10;
// Rotate the star
starText.rotation += 0.05;
};
return self;
});
var SlowFallPowerUp = Container.expand(function () {
var self = Container.call(this);
self.collected = false;
var powerupGraphics = self.attachAsset('slowfallpowerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint it blue to distinguish from jump power-up
powerupGraphics.tint = 0x3498db;
// Add visual indicator (feather symbol)
var featherText = new Text2('🪶', {
size: 30,
fill: 0xFFFFFF
});
featherText.anchor.set(0.5, 0.5);
self.addChild(featherText);
// Floating animation with slower movement
self.floatOffset = 0;
self.update = function () {
// Create gentle floating effect
self.floatOffset += 0.05;
var floatY = Math.sin(self.floatOffset) * 15;
powerupGraphics.y = floatY;
featherText.y = floatY;
// Gentle rotation
featherText.rotation += 0.02;
// Subtle pulsing effect using tween
if (LK.ticks % 120 === 0) {
tween(powerupGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.easeInOut
});
tween(powerupGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
var currentLevel = 1;
var menuOverlay = null;
var isMenuOpen = false;
var powerMenuOverlay = null;
var isPowerMenuOpen = false;
var superJumpUsed = false;
var slowFallModeUsed = false;
var powerMenuOpened = false;
var musicVolume = storage.musicVolume || 1.0;
var gamePoints = 0;
var highScore = storage.highScore || 0;
// Sky color system
var skyColors = [0x87ceeb,
// Sky blue (default)
0xff6b6b,
// Sunset red
0x4ecdc4,
// Turquoise
0x45b7d1,
// Ocean blue
0xf9ca24,
// Golden yellow
0x6c5ce7,
// Purple
0xa29bfe,
// Light purple
0xfd79a8,
// Pink
0x00b894,
// Emerald
0xe17055 // Orange
];
var currentSkyColorIndex = 0;
var skyTransitionActive = false;
var skyCyclingActive = false;
var skyCyclingTimer = null;
function increaseMusicVolume() {
musicVolume = Math.min(1.0, musicVolume + 0.1);
storage.musicVolume = musicVolume;
LK.stopMusic();
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 300
}
});
}
function decreaseMusicVolume() {
musicVolume = Math.max(0.0, musicVolume - 0.1);
storage.musicVolume = musicVolume;
if (musicVolume === 0) {
LK.stopMusic();
} else {
LK.stopMusic();
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 300
}
});
}
}
function changeSkyColor(newColorIndex) {
if (skyTransitionActive) {
return;
}
if (newColorIndex < 0 || newColorIndex >= skyColors.length) {
return;
}
skyTransitionActive = true;
currentSkyColorIndex = newColorIndex;
// Create smooth color transition using tween
var startColor = game.backgroundColor;
var endColor = skyColors[newColorIndex];
// Animate background color change
var colorTransition = {
r: startColor >> 16 & 0xFF,
g: startColor >> 8 & 0xFF,
b: startColor & 0xFF
};
var targetColor = {
r: endColor >> 16 & 0xFF,
g: endColor >> 8 & 0xFF,
b: endColor & 0xFF
};
tween(colorTransition, targetColor, {
duration: 2000,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
var r = Math.round(colorTransition.r);
var g = Math.round(colorTransition.g);
var b = Math.round(colorTransition.b);
var newColor = r << 16 | g << 8 | b;
game.setBackgroundColor(newColor);
},
onFinish: function onFinish() {
skyTransitionActive = false;
game.setBackgroundColor(endColor);
}
});
}
function getRandomSkyColor() {
var randomIndex;
do {
randomIndex = Math.floor(Math.random() * skyColors.length);
} while (randomIndex === currentSkyColorIndex);
return randomIndex;
}
function cycleSkyColor() {
var nextIndex = (currentSkyColorIndex + 1) % skyColors.length;
changeSkyColor(nextIndex);
}
function startSkyCycling() {
if (skyCyclingActive) {
// Stop cycling if already active
stopSkyCycling();
return;
}
skyCyclingActive = true;
// Change sky color every 2 seconds
function cycleNext() {
if (skyCyclingActive) {
var nextIndex = (currentSkyColorIndex + 1) % skyColors.length;
changeSkyColor(nextIndex);
skyCyclingTimer = LK.setTimeout(cycleNext, 3000); // 3 seconds between changes
}
}
// Start first cycle
skyCyclingTimer = LK.setTimeout(cycleNext, 1000); // 1 second delay before first change
}
function stopSkyCycling() {
skyCyclingActive = false;
if (skyCyclingTimer) {
LK.clearTimeout(skyCyclingTimer);
skyCyclingTimer = null;
}
}
function showPowerMenu() {
if (isPowerMenuOpen || powerMenuOpened) {
return;
}
powerMenuOpened = true;
isPowerMenuOpen = true;
powerMenuOverlay = LK.gui.center.addChild(new PowerMenuOverlay());
// Animate menu appearing
powerMenuOverlay.alpha = 0;
powerMenuOverlay.scaleX = 0.8;
powerMenuOverlay.scaleY = 0.8;
tween(powerMenuOverlay, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
function hidePowerMenu() {
if (!isPowerMenuOpen || !powerMenuOverlay) {
return;
}
tween(powerMenuOverlay, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (powerMenuOverlay) {
powerMenuOverlay.destroy();
powerMenuOverlay = null;
}
isPowerMenuOpen = false;
}
});
}
function activateSuperJumpMode() {
// Give player super jump for 10 seconds
player.jumpPower = player.powerUpJumpPower * 1.5; // Even stronger than normal power-up
player.powerUpActive = true;
player.powerUpTimer = 600; // 10 seconds at 60fps
// Flash player golden to show super jump mode
LK.effects.flashObject(player, 0xFFD700, 500);
// Create special golden boots visual effect
if (player.boots) {
player.removeChild(player.boots);
}
player.boots = LK.getAsset('boots', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
tint: 0xFFD700
});
player.addChild(player.boots);
player.boots.x = 0;
player.boots.y = 0;
// Animate boots appearing
tween(player.boots, {
alpha: 1.0,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 300,
easing: tween.easeOut
});
}
function activateSlowFallMode() {
// Give player slow fall for 10 seconds
player.gravity = player.slowFallGravity * 0.5; // Even slower than normal slow fall
player.slowFallActive = true;
player.slowFallTimer = 600; // 10 seconds at 60fps
// Flash player blue to show slow fall mode
LK.effects.flashObject(player, 0x3498db, 500);
// Create special enhanced parachute
if (player.parachute) {
player.removeChild(player.parachute);
}
player.parachute = LK.getAsset('parachute', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
tint: 0x3498db
});
player.addChild(player.parachute);
player.parachute.x = 0;
player.parachute.y = -200;
// Animate parachute appearing
tween(player.parachute, {
alpha: 0.9,
y: -180,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
easing: tween.easeOut
});
}
function showMenu() {
if (isMenuOpen) {
return;
}
isMenuOpen = true;
menuOverlay = LK.gui.center.addChild(new MenuOverlay());
// Animate menu appearing
menuOverlay.alpha = 0;
menuOverlay.scaleX = 0.8;
menuOverlay.scaleY = 0.8;
tween(menuOverlay, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
function hideMenu() {
if (!isMenuOpen || !menuOverlay) {
return;
}
// Stop sky cycling when menu closes
stopSkyCycling();
tween(menuOverlay, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuOverlay) {
menuOverlay.destroy();
menuOverlay = null;
}
isMenuOpen = false;
}
});
}
var player = game.addChild(new Player());
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
var platforms = [];
var powerUps = [];
var slowFallPowerUps = [];
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 1.0,
scaleY: 1.7 // Extend ground 70% more downward
}));
ground.x = 1024;
ground.y = 2732;
// Create platforms with numbers 1-15
var platformData = [{
x: 400,
y: 2400,
width: 200,
number: 1
}, {
x: 800,
y: 2200,
width: 250,
number: 2
}, {
x: 1200,
y: 2000,
width: 200,
number: 3
}, {
x: 600,
y: 1800,
width: 300,
number: 4
}, {
x: 1400,
y: 1600,
width: 200,
number: 5
}, {
x: 300,
y: 1400,
width: 250,
number: 6
}, {
x: 1000,
y: 1200,
width: 300,
number: 7
}, {
x: 1600,
y: 1000,
width: 200,
number: 8
}, {
x: 400,
y: 800,
width: 250,
number: 9
}, {
x: 1200,
y: 600,
width: 200,
number: 10
}, {
x: 800,
y: 400,
width: 300,
number: 11
}, {
x: 500,
y: 200,
width: 180,
number: 12
}, {
x: 1400,
y: 100,
width: 220,
number: 13
}, {
x: 200,
y: -100,
width: 250,
number: 14
}, {
x: 1000,
y: -300,
width: 200,
number: 15
}];
function createLevel(levelNumber) {
// Clear existing platforms
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].destroy();
}
platforms = [];
// Clear existing power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
powerUps = [];
// Clear existing slow fall power-ups
for (var i = slowFallPowerUps.length - 1; i >= 0; i--) {
slowFallPowerUps[i].destroy();
}
slowFallPowerUps = [];
// Enhanced difficulty scaling for levels after 5
var isHardMode = levelNumber > 5;
var difficultyMultiplier = isHardMode ? levelNumber - 5 : 0;
// Platform sizing - much smaller after level 5
var basePlatformWidth = isHardMode ? Math.max(120, 200 - difficultyMultiplier * 15) : Math.max(150, 250 - (levelNumber - 1) * 10);
var platformHeight = isHardMode ? Math.max(25, 40 - difficultyMultiplier * 2) : 40;
// Vertical spacing - increased gaps after level 5
var baseY = 2400;
var yStep = isHardMode ? Math.min(280, 200 + difficultyMultiplier * 15) : 200;
// Generate new platform layout for each level
var _loop = function _loop() {
platformNumber = i + 1;
// Calculate platform width with additional randomness for hard mode
var platformWidth = basePlatformWidth;
if (isHardMode && platformNumber > 1 && platformNumber < 15) {
// Add random variation to platform sizes (±20 pixels)
platformWidth += (Math.random() - 0.5) * 40;
platformWidth = Math.max(100, Math.min(platformWidth, 200)); // Clamp between 100-200
}
platform = game.addChild(new Platform(platformWidth, platformHeight, platformNumber));
// Positioning logic - more challenging after level 5
var minX, maxX, randomX;
if (isHardMode) {
// Hard mode: More precise positioning requirements
minX = 150 + platformWidth / 2;
maxX = 1898 - platformWidth / 2;
// Create more challenging horizontal gaps between platforms
if (i > 0) {
var lastPlatform = platforms[platforms.length - 1];
var minGap = 200 + difficultyMultiplier * 20; // Minimum gap increases with difficulty
var maxGap = 400 + difficultyMultiplier * 30; // Maximum gap increases with difficulty
// Try to place platform at challenging but reachable distance
var preferredDistance = minGap + Math.random() * (maxGap - minGap);
var direction = Math.random() > 0.5 ? 1 : -1; // Random direction
randomX = lastPlatform.x + direction * preferredDistance;
randomX = Math.max(minX, Math.min(maxX, randomX)); // Keep within bounds
} else {
randomX = minX + Math.random() * (maxX - minX);
}
} else {
// Normal mode: Original positioning
minX = 200;
maxX = 1848;
randomX = minX + Math.random() * (maxX - minX);
}
platform.x = randomX;
platform.y = baseY - i * yStep;
platforms.push(platform);
// Make the last platform (platform 15) shine with golden glow
if (platformNumber === 15) {
// Golden color
// Create pulsing glow effect
var _createPulsingGlow = function createPulsingGlow() {
tween(platform.children[0], {
alpha: 0.6,
scaleX: platform.children[0].scaleX * 1.1,
scaleY: platform.children[0].scaleY * 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(platform.children[0], {
alpha: 1.0,
scaleX: platform.children[0].scaleX / 1.1,
scaleY: platform.children[0].scaleY / 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: _createPulsingGlow // Loop the animation
});
}
});
}; // Start the pulsing animation with a delay to make it more noticeable
// Add sparkling effect with tint changes
var createSparkleEffect = function createSparkleEffect() {
var sparkleColors = [0xFFD700, 0xFFF700, 0xFFFF00, 0xFFD700]; // Golden to bright yellow
var currentColorIndex = 0;
function nextSparkle() {
currentColorIndex = (currentColorIndex + 1) % sparkleColors.length;
tween(platform.children[0], {
tint: sparkleColors[currentColorIndex]
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(nextSparkle, Math.random() * 800 + 400); // Random delay between sparkles
}
});
}
nextSparkle();
}; // Start sparkling effect
// Add golden tint to make it special
platform.children[0].tint = 0xFFD700;
LK.setTimeout(function () {
_createPulsingGlow();
}, 500);
LK.setTimeout(function () {
createSparkleEffect();
}, 1000);
}
// Spawn power-up randomly - reduced chance in hard mode
var powerUpChance = isHardMode ? Math.max(0.02, 0.07 - difficultyMultiplier * 0.01) : 0.07;
if (Math.random() < powerUpChance && platformNumber !== 1 && platformNumber !== 15) {
powerUp = game.addChild(new PowerUp());
powerUp.x = platform.x;
powerUp.y = platform.y - 60; // Position above platform
powerUps.push(powerUp);
}
// Spawn slow fall power-up randomly - reduced chance in hard mode
var slowFallChance = isHardMode ? Math.max(0.02, 0.07 - difficultyMultiplier * 0.01) : 0.07;
if (Math.random() < slowFallChance && platformNumber !== 1 && platformNumber !== 15) {
slowFallPowerUp = game.addChild(new SlowFallPowerUp());
slowFallPowerUp.x = platform.x + 50; // Offset slightly to avoid overlap
slowFallPowerUp.y = platform.y - 60; // Position above platform
slowFallPowerUps.push(slowFallPowerUp);
}
},
platformNumber,
platform,
minX,
maxX,
randomX,
powerUp,
slowFallPowerUp;
for (var i = 0; i < 15; i++) {
_loop();
}
}
// Apply difficulty modifiers to player stats for hard mode
function applyDifficultyModifiers(levelNumber) {
var isHardMode = levelNumber > 5;
if (isHardMode) {
var difficultyMultiplier = levelNumber - 5;
// Increase gravity slightly (making falls faster and jumps shorter)
player.baseGravity = Math.min(1.2, 0.8 + difficultyMultiplier * 0.05);
player.gravity = player.slowFallActive ? player.slowFallGravity : player.baseGravity;
// Reduce jump power slightly (making precise jumping harder)
player.baseJumpPower = Math.max(25, 30 - difficultyMultiplier * 0.8);
player.powerUpJumpPower = Math.max(38, 45 - difficultyMultiplier * 1.0);
player.jumpPower = player.powerUpActive ? player.powerUpJumpPower : player.baseJumpPower;
// Reduce movement speed slightly for more precise control requirements
player.speed = Math.max(8, 12 - difficultyMultiplier * 0.5);
player.runSpeed = Math.max(14, 20 - difficultyMultiplier * 0.8);
} else {
// Reset to normal values for easier levels
player.baseGravity = 0.8;
player.gravity = player.slowFallActive ? player.slowFallGravity : player.baseGravity;
player.baseJumpPower = 30;
player.powerUpJumpPower = 45;
player.jumpPower = player.powerUpActive ? player.powerUpJumpPower : player.baseJumpPower;
player.speed = 12;
player.runSpeed = 20;
}
}
// Create initial level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
// Control buttons
var leftButton = LK.gui.bottomLeft.addChild(new ControlButton('left'));
leftButton.x = 110;
leftButton.y = -110;
var rightButton = LK.gui.bottomLeft.addChild(new ControlButton('right'));
rightButton.x = 310;
rightButton.y = -110;
var runButton = LK.gui.bottomLeft.addChild(new ControlButton('run'));
runButton.x = 510;
runButton.y = -110;
var jumpButton = LK.gui.bottomRight.addChild(new ControlButton('jump'));
jumpButton.x = -110;
jumpButton.y = -110;
// Control button labels
var leftLabel = new Text2('←', {
size: 60,
fill: 0xFFFFFF
});
leftLabel.anchor.set(0.5, 0.5);
leftButton.addChild(leftLabel);
var rightLabel = new Text2('→', {
size: 60,
fill: 0xFFFFFF
});
rightLabel.anchor.set(0.5, 0.5);
rightButton.addChild(rightLabel);
var runLabel = new Text2('RUN', {
size: 30,
fill: 0xFFFFFF
});
runLabel.anchor.set(0.5, 0.5);
runButton.addChild(runLabel);
var jumpLabel = new Text2('↑', {
size: 60,
fill: 0xFFFFFF
});
jumpLabel.anchor.set(0.5, 0.5);
jumpButton.addChild(jumpLabel);
// Menu button in top-right corner
var menuButton = LK.gui.topRight.addChild(new MenuButton());
menuButton.x = -120; // Position away from right edge
menuButton.y = 120; // Position below top menu area
// Power menu button
var powerMenuButton = LK.gui.bottomRight.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
powerMenuButton.x = -220;
powerMenuButton.y = -220;
powerMenuButton.interactive = true;
// Add power icon (lightning bolt)
var powerIcon = new Text2('⚡', {
size: 40,
fill: 0xFFD700
});
powerIcon.anchor.set(0.5, 0.5);
powerMenuButton.addChild(powerIcon);
powerMenuButton.down = function () {
tween(powerMenuButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
powerMenuButton.up = function () {
tween(powerMenuButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
showPowerMenu();
}
});
};
// Level display
var levelText = new Text2('Level ' + currentLevel, {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 120; // Position below the top menu
// Power-up status display
var powerUpText = new Text2('', {
size: 40,
fill: 0xf39c12
});
powerUpText.anchor.set(0.5, 0);
LK.gui.top.addChild(powerUpText);
powerUpText.y = 200;
// Slow fall status display
var slowFallText = new Text2('', {
size: 40,
fill: 0x3498db
});
slowFallText.anchor.set(0.5, 0);
LK.gui.top.addChild(slowFallText);
slowFallText.y = 250;
// Points display
var pointsText = new Text2('Points: 0', {
size: 50,
fill: 0xFFFFFF
});
pointsText.anchor.set(0.5, 0);
LK.gui.top.addChild(pointsText);
pointsText.y = 300;
// High score display
var highScoreText = new Text2('Best: ' + highScore, {
size: 35,
fill: 0xf39c12
});
highScoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(highScoreText);
highScoreText.y = 360;
function checkCollisions() {
var playerBottom = player.y;
var playerTop = player.y - 180;
var playerLeft = player.x - 90;
var playerRight = player.x + 90;
// Check ground collision
if (playerBottom >= ground.y - 50) {
if (player.velocityY > 0) {
player.y = ground.y - 50;
player.velocityY = 0;
player.onGround = true;
}
}
// Check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.platformWidth / 2;
var platformRight = platform.x + platform.platformWidth / 2;
var platformTop = platform.y - platform.platformHeight / 2;
var platformBottom = platform.y + platform.platformHeight / 2;
// Check if player is horizontally aligned with platform
if (playerRight > platformLeft && playerLeft < platformRight) {
// Check if player is falling onto platform from above
if (player.velocityY > 0 && playerBottom >= platformTop && playerTop < platformTop) {
player.y = platformTop;
player.velocityY = 0;
player.onGround = true;
}
}
}
// Check power-up collisions
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.collected) {
var powerUpLeft = powerUp.x - 20;
var powerUpRight = powerUp.x + 20;
var powerUpTop = powerUp.y - 20;
var powerUpBottom = powerUp.y + 20;
// Check if player intersects with power-up
if (playerRight > powerUpLeft && playerLeft < powerUpRight && playerBottom > powerUpTop && playerTop < powerUpBottom) {
powerUp.collected = true;
player.collectPowerUp();
// Add 10 points for collecting power-up
gamePoints += 10;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Check slow fall power-up collisions
for (var i = slowFallPowerUps.length - 1; i >= 0; i--) {
var slowFallPowerUp = slowFallPowerUps[i];
if (!slowFallPowerUp.collected) {
var slowFallLeft = slowFallPowerUp.x - 20;
var slowFallRight = slowFallPowerUp.x + 20;
var slowFallTop = slowFallPowerUp.y - 20;
var slowFallBottom = slowFallPowerUp.y + 20;
// Check if player intersects with slow fall power-up (slime)
if (playerRight > slowFallLeft && playerLeft < slowFallRight && playerBottom > slowFallTop && playerTop < slowFallBottom) {
slowFallPowerUp.collected = true;
// Play slime sound effect
LK.getSound('Voz').play();
// Player character sound and animation when touching slime
// Create bouncy squash animation for player
tween(player.children[0], {
scaleX: 1.4,
scaleY: 0.7,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player.children[0], {
scaleX: 0.9,
scaleY: 1.3,
rotation: Math.random() * 0.2 - 0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player.children[0], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0
}, {
duration: 180,
easing: tween.easeOut
});
}
});
}
});
// Create slime bounce animation
tween(slowFallPowerUp.children[0], {
scaleX: 1.5,
scaleY: 0.8,
rotation: Math.random() * 0.4 - 0.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[0], {
scaleX: 0.8,
scaleY: 1.4,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[0], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
}
});
// Add jiggle animation to the feather text
tween(slowFallPowerUp.children[1], {
scaleX: 1.3,
scaleY: 1.3,
rotation: Math.random() * 0.5 - 0.25
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[1], {
scaleX: 0.9,
scaleY: 0.9,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[1], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
}
});
player.collectSlowFallPowerUp();
// Add 10 points for collecting slow fall power-up
gamePoints += 10;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
// Destroy slime after animation completes
LK.setTimeout(function () {
slowFallPowerUp.destroy();
slowFallPowerUps.splice(slowFallPowerUps.indexOf(slowFallPowerUp), 1);
}, 500);
}
}
}
}
game.update = function () {
// Check collisions first to set onGround flag
checkCollisions();
// Handle input
player.setRunning(runButton.isPressed);
if (leftButton.isPressed) {
player.moveLeft();
} else if (rightButton.isPressed) {
player.moveRight();
} else {
player.stopHorizontalMovement();
}
if (jumpButton.isPressed) {
player.jump();
}
// Update power-up display
if (player.powerUpActive) {
var secondsLeft = Math.ceil(player.powerUpTimer / 60);
powerUpText.setText('★ Super Jump: ' + secondsLeft + 's');
} else {
powerUpText.setText('');
}
// Update slow fall display
if (player.slowFallActive) {
var secondsLeft = Math.ceil(player.slowFallTimer / 60);
slowFallText.setText('🪶 Slow Fall: ' + secondsLeft + 's');
} else {
slowFallText.setText('');
}
// Camera follows player
var targetY = -player.y + 1366; // Center player vertically on screen
game.y = targetY;
// Check if player reached platform 15
var platform15 = null;
for (var i = 0; i < platforms.length; i++) {
if (platforms[i].platformNumber === 15) {
platform15 = platforms[i];
break;
}
}
if (platform15) {
var playerBottom = player.y;
var playerLeft = player.x - 90;
var playerRight = player.x + 90;
var platform15Left = platform15.x - platform15.platformWidth / 2;
var platform15Right = platform15.x + platform15.platformWidth / 2;
var platform15Top = platform15.y - platform15.platformHeight / 2;
// Check if player is on platform 15
if (playerRight > platform15Left && playerLeft < platform15Right && playerBottom >= platform15Top && playerBottom <= platform15Top + 50) {
// Player reached platform 15 - advance to next level
// Add 20 points for completing a level
gamePoints += 20;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
currentLevel++;
if (currentLevel > 10) {
// Update final score before showing you win
LK.setScore(gamePoints);
// After 10 levels, show you win
LK.showYouWin();
} else {
// Reset power usage flags for new level
superJumpUsed = false;
slowFallModeUsed = false;
// Create next level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
levelText.setText('Level ' + currentLevel);
// Reset player position for new level
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
player.velocityX = 0;
player.velocityY = 0;
// Change sky color every few levels for visual variety
if (currentLevel % 3 === 0) {
var randomSkyIndex = getRandomSkyColor();
changeSkyColor(randomSkyIndex);
}
// Flash screen green to indicate level completion
LK.effects.flashScreen(0x00ff00, 500);
}
}
}
// Check if player fell off screen
if (player.y > 2800) {
// Set final score and show game over
LK.setScore(gamePoints);
LK.showGameOver();
}
};
// Play background music with saved volume
if (musicVolume > 0) {
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 500
}
});
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
musicVolume: 1
});
/****
* Classes
****/
var ControlButton = Container.expand(function (type) {
var self = Container.call(this);
self.buttonType = type;
self.isPressed = false;
var buttonGraphics;
if (type === 'jump') {
buttonGraphics = self.attachAsset('jumpButton', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'run') {
buttonGraphics = self.attachAsset('runButton', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
buttonGraphics = self.attachAsset(type === 'left' ? 'leftButton' : 'rightButton', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Add larger transparent hitbox for easier touch detection
var hitboxSize = 240; // Larger than visual button (180px)
var hitbox = LK.getAsset('jumpButton', {
anchorX: 0.5,
anchorY: 0.5,
width: hitboxSize,
height: hitboxSize,
alpha: 0 // Invisible
});
self.addChild(hitbox);
self.down = function (x, y, obj) {
self.isPressed = true;
// Scale down and change alpha for press effect
tween(buttonGraphics, {
scaleX: 0.85,
scaleY: 0.85,
alpha: 0.7
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
self.isPressed = false;
// Scale back up and restore alpha for release effect
tween(buttonGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
};
// Add idle floating animation
self.animationTimer = Math.random() * 100; // Random start offset
self.update = function () {
if (!self.isPressed) {
// Gentle floating animation when not pressed
self.animationTimer += 0.05;
var floatOffset = Math.sin(self.animationTimer) * 3;
buttonGraphics.y = floatOffset;
// Subtle breathing scale effect
var breathingScale = 1.0 + Math.sin(self.animationTimer * 2) * 0.02;
if (!buttonGraphics._tweening) {
buttonGraphics.scaleX = breathingScale;
buttonGraphics.scaleY = breathingScale;
}
}
};
return self;
});
var MenuButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Add menu icon (three lines)
var line1 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line1.anchor.set(0.5, 0.5);
line1.y = -15;
self.addChild(line1);
var line2 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line2.anchor.set(0.5, 0.5);
self.addChild(line2);
var line3 = new Text2('—', {
size: 24,
fill: 0xFFFFFF
});
line3.anchor.set(0.5, 0.5);
line3.y = 15;
self.addChild(line3);
self.down = function (x, y, obj) {
// Scale down for press effect
tween(buttonGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
// Show menu
showMenu();
};
self.up = function (x, y, obj) {
// Scale back up
tween(buttonGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
};
return self;
});
var MenuOverlay = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var background = LK.getAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
alpha: 0.8
});
background.interactive = true;
self.addChild(background);
// Menu panel
var menuPanel = self.attachAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5
});
// Menu title
var titleText = new Text2('MENU', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
// Restart Level button
var restartButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
restartButton.y = -150;
restartButton.interactive = true;
var restartText = new Text2('RESTART LEVEL', {
size: 36,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartButton.addChild(restartText);
restartButton.down = function () {
tween(restartButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButton.up = function () {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show final score before restart
LK.setScore(gamePoints);
// Reset points for new game
gamePoints = 0;
pointsText.setText('Points: 0');
// Reset power usage flags
superJumpUsed = false;
slowFallModeUsed = false;
// Restart current level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
player.velocityX = 0;
player.velocityY = 0;
player.powerUpActive = false;
player.slowFallActive = false;
player.jumpPower = player.baseJumpPower;
player.gravity = player.baseGravity;
hideMenu();
}
});
};
// Music Volume Controls
var volumeText = new Text2('MUSIC VOLUME', {
size: 32,
fill: 0xFFFFFF
});
volumeText.anchor.set(0.5, 0.5);
volumeText.y = -100;
self.addChild(volumeText);
var volumeDisplayText = new Text2(Math.round(musicVolume * 100) + '%', {
size: 28,
fill: 0xf39c12
});
volumeDisplayText.anchor.set(0.5, 0.5);
volumeDisplayText.y = -60;
self.addChild(volumeDisplayText);
// Volume Down Button
var volumeDownButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeDownButton.x = -100;
volumeDownButton.y = -20;
volumeDownButton.interactive = true;
var volumeDownText = new Text2('−', {
size: 40,
fill: 0xFFFFFF
});
volumeDownText.anchor.set(0.5, 0.5);
volumeDownButton.addChild(volumeDownText);
volumeDownButton.down = function () {
tween(volumeDownButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
volumeDownButton.up = function () {
tween(volumeDownButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
decreaseMusicVolume();
volumeDisplayText.setText(Math.round(musicVolume * 100) + '%');
}
});
};
// Volume Up Button
var volumeUpButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeUpButton.x = 100;
volumeUpButton.y = -20;
volumeUpButton.interactive = true;
var volumeUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
volumeUpText.anchor.set(0.5, 0.5);
volumeUpButton.addChild(volumeUpText);
volumeUpButton.down = function () {
tween(volumeUpButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
volumeUpButton.up = function () {
tween(volumeUpButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
increaseMusicVolume();
volumeDisplayText.setText(Math.round(musicVolume * 100) + '%');
}
});
};
// Sky Color Controls
var skyColorText = new Text2('SKY COLOR', {
size: 32,
fill: 0xFFFFFF
});
skyColorText.anchor.set(0.5, 0.5);
skyColorText.y = 40;
self.addChild(skyColorText);
// Previous Sky Color Button
var skyPrevButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
skyPrevButton.x = -100;
skyPrevButton.y = 80;
skyPrevButton.interactive = true;
var skyPrevText = new Text2('←', {
size: 40,
fill: 0xFFFFFF
});
skyPrevText.anchor.set(0.5, 0.5);
skyPrevButton.addChild(skyPrevText);
skyPrevButton.down = function () {
tween(skyPrevButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
skyPrevButton.up = function () {
tween(skyPrevButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
var prevIndex = currentSkyColorIndex - 1;
if (prevIndex < 0) {
prevIndex = skyColors.length - 1;
}
changeSkyColor(prevIndex);
}
});
};
// Next Sky Color Button
var skyNextButton = self.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
skyNextButton.x = 100;
skyNextButton.y = 80;
skyNextButton.interactive = true;
var skyNextText = new Text2('→', {
size: 40,
fill: 0xFFFFFF
});
skyNextText.anchor.set(0.5, 0.5);
skyNextButton.addChild(skyNextText);
skyNextButton.down = function () {
tween(skyNextButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
skyNextButton.up = function () {
tween(skyNextButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
cycleSkyColor();
}
});
};
// Random Sky Color Button
var skyRandomButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
skyRandomButton.y = 140;
skyRandomButton.interactive = true;
var skyRandomText = new Text2('RANDOM SKY', {
size: 28,
fill: 0xFFFFFF
});
skyRandomText.anchor.set(0.5, 0.5);
skyRandomButton.addChild(skyRandomText);
skyRandomButton.down = function () {
tween(skyRandomButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
skyRandomButton.up = function () {
tween(skyRandomButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
var randomIndex = getRandomSkyColor();
changeSkyColor(randomIndex);
}
});
};
// Cycle Sky Colors Button
var cycleSkyButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
cycleSkyButton.y = 200;
cycleSkyButton.interactive = true;
var cycleSkyText = new Text2('CYCLE SKY COLORS', {
size: 28,
fill: 0xFFFFFF
});
cycleSkyText.anchor.set(0.5, 0.5);
cycleSkyButton.addChild(cycleSkyText);
cycleSkyButton.down = function () {
tween(cycleSkyButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
cycleSkyButton.up = function () {
tween(cycleSkyButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start automatic sky color cycling
startSkyCycling();
}
});
};
// Close button
var closeButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 260;
closeButton.interactive = true;
var closeText = new Text2('CLOSE', {
size: 36,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
hideMenu();
}
});
};
// Background click to close
background.down = function () {
hideMenu();
};
return self;
});
var Platform = Container.expand(function (width, height, number) {
var self = Container.call(this);
self.platformWidth = width || 300;
self.platformHeight = height || 40;
self.platformNumber = number || 0;
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.platformWidth / 300,
scaleY: self.platformHeight / 40
});
// Add number text if platform has a number
if (self.platformNumber > 0) {
var numberText = new Text2(self.platformNumber.toString(), {
size: 30,
fill: 0x000000
});
numberText.anchor.set(0.5, 0.5);
self.addChild(numberText);
}
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 12;
self.runSpeed = 20;
self.isRunning = false;
self.jumpPower = 30;
self.baseJumpPower = 30;
self.powerUpJumpPower = 45;
self.powerUpActive = false;
self.powerUpTimer = 0;
self.slowFallActive = false;
self.slowFallTimer = 0;
self.gravity = 0.8;
self.baseGravity = 0.8;
self.slowFallGravity = 0.25;
self.onGround = false;
self.canDoubleJump = false;
self.hasDoubleJumped = false;
self.parachute = null;
self.boots = null;
self.maxFallSpeed = 15;
// Animation states
self.animationState = 'idle'; // 'idle', 'falling', 'jumping'
self.lastOnGround = true;
self.animationTimer = 0;
self.moveLeft = function () {
self.velocityX = self.isRunning ? -self.runSpeed : -self.speed;
};
self.moveRight = function () {
self.velocityX = self.isRunning ? self.runSpeed : self.speed;
};
self.setRunning = function (running) {
self.isRunning = running;
};
self.jump = function () {
if (self.onGround) {
self.velocityY = -self.jumpPower;
self.onGround = false;
self.canDoubleJump = true;
self.hasDoubleJumped = false;
// Play voice sound when jumping
LK.getSound('Voz').play();
} else if (self.canDoubleJump && !self.hasDoubleJumped) {
// Double jump
self.velocityY = -self.jumpPower * 0.9; // Slightly weaker than first jump
self.hasDoubleJumped = true;
self.canDoubleJump = false;
// Play voice sound when double jumping
LK.getSound('Voz').play();
// Flash player purple to show double jump
LK.effects.flashObject(self, 0x9b59b6, 200);
}
};
self.stopHorizontalMovement = function () {
self.velocityX = 0;
};
self.collectPowerUp = function () {
self.powerUpActive = true;
self.powerUpTimer = 300; // 5 seconds at 60fps
self.jumpPower = self.powerUpJumpPower;
// Flash player green to show power-up is active
LK.effects.flashObject(self, 0x00ff00, 300);
// Create boots visual effect
self.boots = LK.getAsset('boots', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0
});
self.addChild(self.boots);
self.boots.x = 0;
self.boots.y = 0; // Position at player's feet
// Animate boots appearing
tween(self.boots, {
alpha: 1.0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
};
self.collectSlowFallPowerUp = function () {
self.slowFallActive = true;
self.slowFallTimer = 300; // 5 seconds at 60fps
self.gravity = self.slowFallGravity;
// Flash player blue to show slow fall is active
LK.effects.flashObject(self, 0x3498db, 300);
// Add gentle blue tint while active
tween(playerGraphics, {
tint: 0xadd8e6
}, {
duration: 300,
easing: tween.easeOut
});
// Create parachute
self.parachute = LK.getAsset('parachute', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0
});
self.addChild(self.parachute);
self.parachute.x = 0;
self.parachute.y = -200; // Position above player
// Animate parachute appearing
tween(self.parachute, {
alpha: 0.8,
y: -180
}, {
duration: 500,
easing: tween.easeOut
});
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Limit fall speed
if (self.velocityY > self.maxFallSpeed) {
self.velocityY = self.maxFallSpeed;
}
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Flip sprite based on movement direction
if (self.velocityX > 0) {
// Moving right - face right (normal)
playerGraphics.scaleX = Math.abs(playerGraphics.scaleX);
} else if (self.velocityX < 0) {
// Moving left - face left (flipped)
playerGraphics.scaleX = -Math.abs(playerGraphics.scaleX);
}
// Update animation timer
self.animationTimer += 0.1;
// Determine animation state
var newAnimationState = 'idle';
if (!self.onGround && self.velocityY < -5) {
newAnimationState = 'jumping';
} else if (!self.onGround && self.velocityY > 5) {
newAnimationState = 'falling';
} else if (self.onGround && self.velocityX !== 0) {
newAnimationState = 'walking';
} else if (self.onGround) {
newAnimationState = 'idle';
}
// Apply animations based on state transitions
if (self.animationState !== newAnimationState) {
// State changed, apply new animation
if (newAnimationState === 'jumping') {
// Jump animation - stretch upward
tween(playerGraphics, {
scaleY: 1.3,
scaleX: 0.8,
rotation: self.velocityX > 0 ? 0.1 : self.velocityX < 0 ? -0.1 : 0
}, {
duration: 200,
easing: tween.easeOut
});
} else if (newAnimationState === 'falling') {
// Fall animation - compress and tilt
tween(playerGraphics, {
scaleY: 0.7,
scaleX: 1.2,
rotation: self.velocityX > 0 ? 0.2 : self.velocityX < 0 ? -0.2 : 0
}, {
duration: 300,
easing: tween.easeOut
});
} else if (newAnimationState === 'idle' && !self.lastOnGround && self.onGround) {
// Landing animation - squash and recover
tween(playerGraphics, {
scaleY: 0.6,
scaleX: 1.4,
rotation: 0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
} else if (newAnimationState === 'walking') {
// Walking animation - return to normal scale for bouncing
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
} else if (newAnimationState === 'idle') {
// Return to idle animation
tween(playerGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Continuous animations based on state
if (newAnimationState === 'idle' && self.onGround) {
// Gentle breathing effect
var breathingScale = 1.0 + Math.sin(self.animationTimer * 2) * 0.02;
if (!playerGraphics._tweening) {
// Only apply if not currently tweening
playerGraphics.scaleY = breathingScale;
}
} else if (newAnimationState === 'walking' && self.onGround) {
// Walking animation - bouncing effect (slower)
var walkingBounce = 1.0 + Math.sin(self.animationTimer * 4) * 0.15;
var walkingTilt = Math.sin(self.animationTimer * 4) * 0.05;
if (!playerGraphics._tweening) {
// Only apply if not currently tweening
playerGraphics.scaleY = walkingBounce;
playerGraphics.rotation = walkingTilt * (self.velocityX > 0 ? 1 : -1);
}
}
// Update states for next frame
self.animationState = newAnimationState;
self.lastOnGround = self.onGround;
// Keep player within screen bounds horizontally
if (self.x < 90) {
self.x = 90;
}
if (self.x > 1958) {
self.x = 1958;
}
// Handle power-up timer
if (self.powerUpActive) {
self.powerUpTimer--;
if (self.powerUpTimer <= 0) {
self.powerUpActive = false;
self.jumpPower = self.baseJumpPower;
// Flash player red to show power-up expired
LK.effects.flashObject(self, 0xff0000, 200);
// Remove boots with animation
if (self.boots) {
tween(self.boots, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.boots) {
self.removeChild(self.boots);
self.boots = null;
}
}
});
}
}
}
// Handle slow fall timer
if (self.slowFallActive) {
self.slowFallTimer--;
// Animate parachute swaying
if (self.parachute) {
var swayAmount = Math.sin(self.animationTimer * 3) * 15;
self.parachute.x = swayAmount;
self.parachute.rotation = Math.sin(self.animationTimer * 2) * 0.1;
}
if (self.slowFallTimer <= 0) {
self.slowFallActive = false;
self.gravity = self.baseGravity;
// Flash player red to show slow fall expired and remove tint
LK.effects.flashObject(self, 0xff0000, 200);
tween(playerGraphics, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
// Remove parachute with animation
if (self.parachute) {
tween(self.parachute, {
alpha: 0,
y: -220
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parachute) {
self.removeChild(self.parachute);
self.parachute = null;
}
}
});
}
}
}
// Reset double jump when landing
if (self.onGround && !self.lastOnGround) {
self.canDoubleJump = false;
self.hasDoubleJumped = false;
}
// Reset onGround flag
self.onGround = false;
};
return self;
});
var PowerMenuOverlay = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var background = LK.getAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
alpha: 0.8
});
background.interactive = true;
self.addChild(background);
// Menu panel
var menuPanel = self.attachAsset('menuOverlay', {
anchorX: 0.5,
anchorY: 0.5
});
// Menu title
var titleText = new Text2('POWER MENU', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
// Super Jump Button
var superJumpButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
superJumpButton.y = -150;
superJumpButton.interactive = true;
var superJumpText = new Text2('SUPER JUMP', {
size: 36,
fill: 0xFFFFFF
});
superJumpText.anchor.set(0.5, 0.5);
superJumpButton.addChild(superJumpText);
superJumpButton.down = function () {
tween(superJumpButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
superJumpButton.up = function () {
tween(superJumpButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check if super jump has already been used
if (!superJumpUsed) {
// Activate super jump mode
activateSuperJumpMode();
superJumpUsed = true;
// Update button appearance to show it's used
superJumpText.setText('USED');
superJumpButton.alpha = 0.5;
superJumpButton.interactive = false;
}
hidePowerMenu();
}
});
};
// Slow Fall Button
var slowFallButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
slowFallButton.y = -50;
slowFallButton.interactive = true;
var slowFallButtonText = new Text2('SLOW FALL MODE', {
size: 36,
fill: 0xFFFFFF
});
slowFallButtonText.anchor.set(0.5, 0.5);
slowFallButton.addChild(slowFallButtonText);
slowFallButton.down = function () {
tween(slowFallButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
slowFallButton.up = function () {
tween(slowFallButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check if slow fall mode has already been used
if (!slowFallModeUsed) {
// Activate slow fall mode
activateSlowFallMode();
slowFallModeUsed = true;
// Update button appearance to show it's used
slowFallButtonText.setText('USED');
slowFallButton.alpha = 0.5;
slowFallButton.interactive = false;
}
hidePowerMenu();
}
});
};
// Close button
var closeButton = self.addChild(LK.getAsset('menuButtonBg', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 50;
closeButton.interactive = true;
var closeText = new Text2('CLOSE', {
size: 36,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
hidePowerMenu();
}
});
};
// Background click to close
background.down = function () {
hidePowerMenu();
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.collected = false;
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual indicator (star symbol)
var starText = new Text2('★', {
size: 30,
fill: 0xFFFFFF
});
starText.anchor.set(0.5, 0.5);
self.addChild(starText);
// Floating animation
self.floatOffset = 0;
self.update = function () {
// Create floating effect
self.floatOffset += 0.1;
powerupGraphics.y = Math.sin(self.floatOffset) * 10;
starText.y = Math.sin(self.floatOffset) * 10;
// Rotate the star
starText.rotation += 0.05;
};
return self;
});
var SlowFallPowerUp = Container.expand(function () {
var self = Container.call(this);
self.collected = false;
var powerupGraphics = self.attachAsset('slowfallpowerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint it blue to distinguish from jump power-up
powerupGraphics.tint = 0x3498db;
// Add visual indicator (feather symbol)
var featherText = new Text2('🪶', {
size: 30,
fill: 0xFFFFFF
});
featherText.anchor.set(0.5, 0.5);
self.addChild(featherText);
// Floating animation with slower movement
self.floatOffset = 0;
self.update = function () {
// Create gentle floating effect
self.floatOffset += 0.05;
var floatY = Math.sin(self.floatOffset) * 15;
powerupGraphics.y = floatY;
featherText.y = floatY;
// Gentle rotation
featherText.rotation += 0.02;
// Subtle pulsing effect using tween
if (LK.ticks % 120 === 0) {
tween(powerupGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.easeInOut
});
tween(powerupGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
var currentLevel = 1;
var menuOverlay = null;
var isMenuOpen = false;
var powerMenuOverlay = null;
var isPowerMenuOpen = false;
var superJumpUsed = false;
var slowFallModeUsed = false;
var powerMenuOpened = false;
var musicVolume = storage.musicVolume || 1.0;
var gamePoints = 0;
var highScore = storage.highScore || 0;
// Sky color system
var skyColors = [0x87ceeb,
// Sky blue (default)
0xff6b6b,
// Sunset red
0x4ecdc4,
// Turquoise
0x45b7d1,
// Ocean blue
0xf9ca24,
// Golden yellow
0x6c5ce7,
// Purple
0xa29bfe,
// Light purple
0xfd79a8,
// Pink
0x00b894,
// Emerald
0xe17055 // Orange
];
var currentSkyColorIndex = 0;
var skyTransitionActive = false;
var skyCyclingActive = false;
var skyCyclingTimer = null;
function increaseMusicVolume() {
musicVolume = Math.min(1.0, musicVolume + 0.1);
storage.musicVolume = musicVolume;
LK.stopMusic();
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 300
}
});
}
function decreaseMusicVolume() {
musicVolume = Math.max(0.0, musicVolume - 0.1);
storage.musicVolume = musicVolume;
if (musicVolume === 0) {
LK.stopMusic();
} else {
LK.stopMusic();
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 300
}
});
}
}
function changeSkyColor(newColorIndex) {
if (skyTransitionActive) {
return;
}
if (newColorIndex < 0 || newColorIndex >= skyColors.length) {
return;
}
skyTransitionActive = true;
currentSkyColorIndex = newColorIndex;
// Create smooth color transition using tween
var startColor = game.backgroundColor;
var endColor = skyColors[newColorIndex];
// Animate background color change
var colorTransition = {
r: startColor >> 16 & 0xFF,
g: startColor >> 8 & 0xFF,
b: startColor & 0xFF
};
var targetColor = {
r: endColor >> 16 & 0xFF,
g: endColor >> 8 & 0xFF,
b: endColor & 0xFF
};
tween(colorTransition, targetColor, {
duration: 2000,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
var r = Math.round(colorTransition.r);
var g = Math.round(colorTransition.g);
var b = Math.round(colorTransition.b);
var newColor = r << 16 | g << 8 | b;
game.setBackgroundColor(newColor);
},
onFinish: function onFinish() {
skyTransitionActive = false;
game.setBackgroundColor(endColor);
}
});
}
function getRandomSkyColor() {
var randomIndex;
do {
randomIndex = Math.floor(Math.random() * skyColors.length);
} while (randomIndex === currentSkyColorIndex);
return randomIndex;
}
function cycleSkyColor() {
var nextIndex = (currentSkyColorIndex + 1) % skyColors.length;
changeSkyColor(nextIndex);
}
function startSkyCycling() {
if (skyCyclingActive) {
// Stop cycling if already active
stopSkyCycling();
return;
}
skyCyclingActive = true;
// Change sky color every 2 seconds
function cycleNext() {
if (skyCyclingActive) {
var nextIndex = (currentSkyColorIndex + 1) % skyColors.length;
changeSkyColor(nextIndex);
skyCyclingTimer = LK.setTimeout(cycleNext, 3000); // 3 seconds between changes
}
}
// Start first cycle
skyCyclingTimer = LK.setTimeout(cycleNext, 1000); // 1 second delay before first change
}
function stopSkyCycling() {
skyCyclingActive = false;
if (skyCyclingTimer) {
LK.clearTimeout(skyCyclingTimer);
skyCyclingTimer = null;
}
}
function showPowerMenu() {
if (isPowerMenuOpen || powerMenuOpened) {
return;
}
powerMenuOpened = true;
isPowerMenuOpen = true;
powerMenuOverlay = LK.gui.center.addChild(new PowerMenuOverlay());
// Animate menu appearing
powerMenuOverlay.alpha = 0;
powerMenuOverlay.scaleX = 0.8;
powerMenuOverlay.scaleY = 0.8;
tween(powerMenuOverlay, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
function hidePowerMenu() {
if (!isPowerMenuOpen || !powerMenuOverlay) {
return;
}
tween(powerMenuOverlay, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (powerMenuOverlay) {
powerMenuOverlay.destroy();
powerMenuOverlay = null;
}
isPowerMenuOpen = false;
}
});
}
function activateSuperJumpMode() {
// Give player super jump for 10 seconds
player.jumpPower = player.powerUpJumpPower * 1.5; // Even stronger than normal power-up
player.powerUpActive = true;
player.powerUpTimer = 600; // 10 seconds at 60fps
// Flash player golden to show super jump mode
LK.effects.flashObject(player, 0xFFD700, 500);
// Create special golden boots visual effect
if (player.boots) {
player.removeChild(player.boots);
}
player.boots = LK.getAsset('boots', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
tint: 0xFFD700
});
player.addChild(player.boots);
player.boots.x = 0;
player.boots.y = 0;
// Animate boots appearing
tween(player.boots, {
alpha: 1.0,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 300,
easing: tween.easeOut
});
}
function activateSlowFallMode() {
// Give player slow fall for 10 seconds
player.gravity = player.slowFallGravity * 0.5; // Even slower than normal slow fall
player.slowFallActive = true;
player.slowFallTimer = 600; // 10 seconds at 60fps
// Flash player blue to show slow fall mode
LK.effects.flashObject(player, 0x3498db, 500);
// Create special enhanced parachute
if (player.parachute) {
player.removeChild(player.parachute);
}
player.parachute = LK.getAsset('parachute', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
tint: 0x3498db
});
player.addChild(player.parachute);
player.parachute.x = 0;
player.parachute.y = -200;
// Animate parachute appearing
tween(player.parachute, {
alpha: 0.9,
y: -180,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
easing: tween.easeOut
});
}
function showMenu() {
if (isMenuOpen) {
return;
}
isMenuOpen = true;
menuOverlay = LK.gui.center.addChild(new MenuOverlay());
// Animate menu appearing
menuOverlay.alpha = 0;
menuOverlay.scaleX = 0.8;
menuOverlay.scaleY = 0.8;
tween(menuOverlay, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
function hideMenu() {
if (!isMenuOpen || !menuOverlay) {
return;
}
// Stop sky cycling when menu closes
stopSkyCycling();
tween(menuOverlay, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuOverlay) {
menuOverlay.destroy();
menuOverlay = null;
}
isMenuOpen = false;
}
});
}
var player = game.addChild(new Player());
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
var platforms = [];
var powerUps = [];
var slowFallPowerUps = [];
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 1.0,
scaleY: 1.7 // Extend ground 70% more downward
}));
ground.x = 1024;
ground.y = 2732;
// Create platforms with numbers 1-15
var platformData = [{
x: 400,
y: 2400,
width: 200,
number: 1
}, {
x: 800,
y: 2200,
width: 250,
number: 2
}, {
x: 1200,
y: 2000,
width: 200,
number: 3
}, {
x: 600,
y: 1800,
width: 300,
number: 4
}, {
x: 1400,
y: 1600,
width: 200,
number: 5
}, {
x: 300,
y: 1400,
width: 250,
number: 6
}, {
x: 1000,
y: 1200,
width: 300,
number: 7
}, {
x: 1600,
y: 1000,
width: 200,
number: 8
}, {
x: 400,
y: 800,
width: 250,
number: 9
}, {
x: 1200,
y: 600,
width: 200,
number: 10
}, {
x: 800,
y: 400,
width: 300,
number: 11
}, {
x: 500,
y: 200,
width: 180,
number: 12
}, {
x: 1400,
y: 100,
width: 220,
number: 13
}, {
x: 200,
y: -100,
width: 250,
number: 14
}, {
x: 1000,
y: -300,
width: 200,
number: 15
}];
function createLevel(levelNumber) {
// Clear existing platforms
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].destroy();
}
platforms = [];
// Clear existing power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
powerUps = [];
// Clear existing slow fall power-ups
for (var i = slowFallPowerUps.length - 1; i >= 0; i--) {
slowFallPowerUps[i].destroy();
}
slowFallPowerUps = [];
// Enhanced difficulty scaling for levels after 5
var isHardMode = levelNumber > 5;
var difficultyMultiplier = isHardMode ? levelNumber - 5 : 0;
// Platform sizing - much smaller after level 5
var basePlatformWidth = isHardMode ? Math.max(120, 200 - difficultyMultiplier * 15) : Math.max(150, 250 - (levelNumber - 1) * 10);
var platformHeight = isHardMode ? Math.max(25, 40 - difficultyMultiplier * 2) : 40;
// Vertical spacing - increased gaps after level 5
var baseY = 2400;
var yStep = isHardMode ? Math.min(280, 200 + difficultyMultiplier * 15) : 200;
// Generate new platform layout for each level
var _loop = function _loop() {
platformNumber = i + 1;
// Calculate platform width with additional randomness for hard mode
var platformWidth = basePlatformWidth;
if (isHardMode && platformNumber > 1 && platformNumber < 15) {
// Add random variation to platform sizes (±20 pixels)
platformWidth += (Math.random() - 0.5) * 40;
platformWidth = Math.max(100, Math.min(platformWidth, 200)); // Clamp between 100-200
}
platform = game.addChild(new Platform(platformWidth, platformHeight, platformNumber));
// Positioning logic - more challenging after level 5
var minX, maxX, randomX;
if (isHardMode) {
// Hard mode: More precise positioning requirements
minX = 150 + platformWidth / 2;
maxX = 1898 - platformWidth / 2;
// Create more challenging horizontal gaps between platforms
if (i > 0) {
var lastPlatform = platforms[platforms.length - 1];
var minGap = 200 + difficultyMultiplier * 20; // Minimum gap increases with difficulty
var maxGap = 400 + difficultyMultiplier * 30; // Maximum gap increases with difficulty
// Try to place platform at challenging but reachable distance
var preferredDistance = minGap + Math.random() * (maxGap - minGap);
var direction = Math.random() > 0.5 ? 1 : -1; // Random direction
randomX = lastPlatform.x + direction * preferredDistance;
randomX = Math.max(minX, Math.min(maxX, randomX)); // Keep within bounds
} else {
randomX = minX + Math.random() * (maxX - minX);
}
} else {
// Normal mode: Original positioning
minX = 200;
maxX = 1848;
randomX = minX + Math.random() * (maxX - minX);
}
platform.x = randomX;
platform.y = baseY - i * yStep;
platforms.push(platform);
// Make the last platform (platform 15) shine with golden glow
if (platformNumber === 15) {
// Golden color
// Create pulsing glow effect
var _createPulsingGlow = function createPulsingGlow() {
tween(platform.children[0], {
alpha: 0.6,
scaleX: platform.children[0].scaleX * 1.1,
scaleY: platform.children[0].scaleY * 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(platform.children[0], {
alpha: 1.0,
scaleX: platform.children[0].scaleX / 1.1,
scaleY: platform.children[0].scaleY / 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: _createPulsingGlow // Loop the animation
});
}
});
}; // Start the pulsing animation with a delay to make it more noticeable
// Add sparkling effect with tint changes
var createSparkleEffect = function createSparkleEffect() {
var sparkleColors = [0xFFD700, 0xFFF700, 0xFFFF00, 0xFFD700]; // Golden to bright yellow
var currentColorIndex = 0;
function nextSparkle() {
currentColorIndex = (currentColorIndex + 1) % sparkleColors.length;
tween(platform.children[0], {
tint: sparkleColors[currentColorIndex]
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(nextSparkle, Math.random() * 800 + 400); // Random delay between sparkles
}
});
}
nextSparkle();
}; // Start sparkling effect
// Add golden tint to make it special
platform.children[0].tint = 0xFFD700;
LK.setTimeout(function () {
_createPulsingGlow();
}, 500);
LK.setTimeout(function () {
createSparkleEffect();
}, 1000);
}
// Spawn power-up randomly - reduced chance in hard mode
var powerUpChance = isHardMode ? Math.max(0.02, 0.07 - difficultyMultiplier * 0.01) : 0.07;
if (Math.random() < powerUpChance && platformNumber !== 1 && platformNumber !== 15) {
powerUp = game.addChild(new PowerUp());
powerUp.x = platform.x;
powerUp.y = platform.y - 60; // Position above platform
powerUps.push(powerUp);
}
// Spawn slow fall power-up randomly - reduced chance in hard mode
var slowFallChance = isHardMode ? Math.max(0.02, 0.07 - difficultyMultiplier * 0.01) : 0.07;
if (Math.random() < slowFallChance && platformNumber !== 1 && platformNumber !== 15) {
slowFallPowerUp = game.addChild(new SlowFallPowerUp());
slowFallPowerUp.x = platform.x + 50; // Offset slightly to avoid overlap
slowFallPowerUp.y = platform.y - 60; // Position above platform
slowFallPowerUps.push(slowFallPowerUp);
}
},
platformNumber,
platform,
minX,
maxX,
randomX,
powerUp,
slowFallPowerUp;
for (var i = 0; i < 15; i++) {
_loop();
}
}
// Apply difficulty modifiers to player stats for hard mode
function applyDifficultyModifiers(levelNumber) {
var isHardMode = levelNumber > 5;
if (isHardMode) {
var difficultyMultiplier = levelNumber - 5;
// Increase gravity slightly (making falls faster and jumps shorter)
player.baseGravity = Math.min(1.2, 0.8 + difficultyMultiplier * 0.05);
player.gravity = player.slowFallActive ? player.slowFallGravity : player.baseGravity;
// Reduce jump power slightly (making precise jumping harder)
player.baseJumpPower = Math.max(25, 30 - difficultyMultiplier * 0.8);
player.powerUpJumpPower = Math.max(38, 45 - difficultyMultiplier * 1.0);
player.jumpPower = player.powerUpActive ? player.powerUpJumpPower : player.baseJumpPower;
// Reduce movement speed slightly for more precise control requirements
player.speed = Math.max(8, 12 - difficultyMultiplier * 0.5);
player.runSpeed = Math.max(14, 20 - difficultyMultiplier * 0.8);
} else {
// Reset to normal values for easier levels
player.baseGravity = 0.8;
player.gravity = player.slowFallActive ? player.slowFallGravity : player.baseGravity;
player.baseJumpPower = 30;
player.powerUpJumpPower = 45;
player.jumpPower = player.powerUpActive ? player.powerUpJumpPower : player.baseJumpPower;
player.speed = 12;
player.runSpeed = 20;
}
}
// Create initial level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
// Control buttons
var leftButton = LK.gui.bottomLeft.addChild(new ControlButton('left'));
leftButton.x = 110;
leftButton.y = -110;
var rightButton = LK.gui.bottomLeft.addChild(new ControlButton('right'));
rightButton.x = 310;
rightButton.y = -110;
var runButton = LK.gui.bottomLeft.addChild(new ControlButton('run'));
runButton.x = 510;
runButton.y = -110;
var jumpButton = LK.gui.bottomRight.addChild(new ControlButton('jump'));
jumpButton.x = -110;
jumpButton.y = -110;
// Control button labels
var leftLabel = new Text2('←', {
size: 60,
fill: 0xFFFFFF
});
leftLabel.anchor.set(0.5, 0.5);
leftButton.addChild(leftLabel);
var rightLabel = new Text2('→', {
size: 60,
fill: 0xFFFFFF
});
rightLabel.anchor.set(0.5, 0.5);
rightButton.addChild(rightLabel);
var runLabel = new Text2('RUN', {
size: 30,
fill: 0xFFFFFF
});
runLabel.anchor.set(0.5, 0.5);
runButton.addChild(runLabel);
var jumpLabel = new Text2('↑', {
size: 60,
fill: 0xFFFFFF
});
jumpLabel.anchor.set(0.5, 0.5);
jumpButton.addChild(jumpLabel);
// Menu button in top-right corner
var menuButton = LK.gui.topRight.addChild(new MenuButton());
menuButton.x = -120; // Position away from right edge
menuButton.y = 120; // Position below top menu area
// Power menu button
var powerMenuButton = LK.gui.bottomRight.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
}));
powerMenuButton.x = -220;
powerMenuButton.y = -220;
powerMenuButton.interactive = true;
// Add power icon (lightning bolt)
var powerIcon = new Text2('⚡', {
size: 40,
fill: 0xFFD700
});
powerIcon.anchor.set(0.5, 0.5);
powerMenuButton.addChild(powerIcon);
powerMenuButton.down = function () {
tween(powerMenuButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
powerMenuButton.up = function () {
tween(powerMenuButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
showPowerMenu();
}
});
};
// Level display
var levelText = new Text2('Level ' + currentLevel, {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 120; // Position below the top menu
// Power-up status display
var powerUpText = new Text2('', {
size: 40,
fill: 0xf39c12
});
powerUpText.anchor.set(0.5, 0);
LK.gui.top.addChild(powerUpText);
powerUpText.y = 200;
// Slow fall status display
var slowFallText = new Text2('', {
size: 40,
fill: 0x3498db
});
slowFallText.anchor.set(0.5, 0);
LK.gui.top.addChild(slowFallText);
slowFallText.y = 250;
// Points display
var pointsText = new Text2('Points: 0', {
size: 50,
fill: 0xFFFFFF
});
pointsText.anchor.set(0.5, 0);
LK.gui.top.addChild(pointsText);
pointsText.y = 300;
// High score display
var highScoreText = new Text2('Best: ' + highScore, {
size: 35,
fill: 0xf39c12
});
highScoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(highScoreText);
highScoreText.y = 360;
function checkCollisions() {
var playerBottom = player.y;
var playerTop = player.y - 180;
var playerLeft = player.x - 90;
var playerRight = player.x + 90;
// Check ground collision
if (playerBottom >= ground.y - 50) {
if (player.velocityY > 0) {
player.y = ground.y - 50;
player.velocityY = 0;
player.onGround = true;
}
}
// Check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.platformWidth / 2;
var platformRight = platform.x + platform.platformWidth / 2;
var platformTop = platform.y - platform.platformHeight / 2;
var platformBottom = platform.y + platform.platformHeight / 2;
// Check if player is horizontally aligned with platform
if (playerRight > platformLeft && playerLeft < platformRight) {
// Check if player is falling onto platform from above
if (player.velocityY > 0 && playerBottom >= platformTop && playerTop < platformTop) {
player.y = platformTop;
player.velocityY = 0;
player.onGround = true;
}
}
}
// Check power-up collisions
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.collected) {
var powerUpLeft = powerUp.x - 20;
var powerUpRight = powerUp.x + 20;
var powerUpTop = powerUp.y - 20;
var powerUpBottom = powerUp.y + 20;
// Check if player intersects with power-up
if (playerRight > powerUpLeft && playerLeft < powerUpRight && playerBottom > powerUpTop && playerTop < powerUpBottom) {
powerUp.collected = true;
player.collectPowerUp();
// Add 10 points for collecting power-up
gamePoints += 10;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Check slow fall power-up collisions
for (var i = slowFallPowerUps.length - 1; i >= 0; i--) {
var slowFallPowerUp = slowFallPowerUps[i];
if (!slowFallPowerUp.collected) {
var slowFallLeft = slowFallPowerUp.x - 20;
var slowFallRight = slowFallPowerUp.x + 20;
var slowFallTop = slowFallPowerUp.y - 20;
var slowFallBottom = slowFallPowerUp.y + 20;
// Check if player intersects with slow fall power-up (slime)
if (playerRight > slowFallLeft && playerLeft < slowFallRight && playerBottom > slowFallTop && playerTop < slowFallBottom) {
slowFallPowerUp.collected = true;
// Play slime sound effect
LK.getSound('Voz').play();
// Player character sound and animation when touching slime
// Create bouncy squash animation for player
tween(player.children[0], {
scaleX: 1.4,
scaleY: 0.7,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player.children[0], {
scaleX: 0.9,
scaleY: 1.3,
rotation: Math.random() * 0.2 - 0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player.children[0], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0
}, {
duration: 180,
easing: tween.easeOut
});
}
});
}
});
// Create slime bounce animation
tween(slowFallPowerUp.children[0], {
scaleX: 1.5,
scaleY: 0.8,
rotation: Math.random() * 0.4 - 0.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[0], {
scaleX: 0.8,
scaleY: 1.4,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[0], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
}
});
// Add jiggle animation to the feather text
tween(slowFallPowerUp.children[1], {
scaleX: 1.3,
scaleY: 1.3,
rotation: Math.random() * 0.5 - 0.25
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[1], {
scaleX: 0.9,
scaleY: 0.9,
rotation: Math.random() * 0.3 - 0.15
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slowFallPowerUp.children[1], {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
}
});
player.collectSlowFallPowerUp();
// Add 10 points for collecting slow fall power-up
gamePoints += 10;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
// Destroy slime after animation completes
LK.setTimeout(function () {
slowFallPowerUp.destroy();
slowFallPowerUps.splice(slowFallPowerUps.indexOf(slowFallPowerUp), 1);
}, 500);
}
}
}
}
game.update = function () {
// Check collisions first to set onGround flag
checkCollisions();
// Handle input
player.setRunning(runButton.isPressed);
if (leftButton.isPressed) {
player.moveLeft();
} else if (rightButton.isPressed) {
player.moveRight();
} else {
player.stopHorizontalMovement();
}
if (jumpButton.isPressed) {
player.jump();
}
// Update power-up display
if (player.powerUpActive) {
var secondsLeft = Math.ceil(player.powerUpTimer / 60);
powerUpText.setText('★ Super Jump: ' + secondsLeft + 's');
} else {
powerUpText.setText('');
}
// Update slow fall display
if (player.slowFallActive) {
var secondsLeft = Math.ceil(player.slowFallTimer / 60);
slowFallText.setText('🪶 Slow Fall: ' + secondsLeft + 's');
} else {
slowFallText.setText('');
}
// Camera follows player
var targetY = -player.y + 1366; // Center player vertically on screen
game.y = targetY;
// Check if player reached platform 15
var platform15 = null;
for (var i = 0; i < platforms.length; i++) {
if (platforms[i].platformNumber === 15) {
platform15 = platforms[i];
break;
}
}
if (platform15) {
var playerBottom = player.y;
var playerLeft = player.x - 90;
var playerRight = player.x + 90;
var platform15Left = platform15.x - platform15.platformWidth / 2;
var platform15Right = platform15.x + platform15.platformWidth / 2;
var platform15Top = platform15.y - platform15.platformHeight / 2;
// Check if player is on platform 15
if (playerRight > platform15Left && playerLeft < platform15Right && playerBottom >= platform15Top && playerBottom <= platform15Top + 50) {
// Player reached platform 15 - advance to next level
// Add 20 points for completing a level
gamePoints += 20;
pointsText.setText('Points: ' + gamePoints);
// Check for new high score
if (gamePoints > highScore) {
highScore = gamePoints;
storage.highScore = highScore;
highScoreText.setText('Best: ' + highScore);
// Flash screen gold for new high score
LK.effects.flashScreen(0xFFD700, 300);
}
currentLevel++;
if (currentLevel > 10) {
// Update final score before showing you win
LK.setScore(gamePoints);
// After 10 levels, show you win
LK.showYouWin();
} else {
// Reset power usage flags for new level
superJumpUsed = false;
slowFallModeUsed = false;
// Create next level
createLevel(currentLevel);
applyDifficultyModifiers(currentLevel);
levelText.setText('Level ' + currentLevel);
// Reset player position for new level
player.x = 400; // Platform 1 x position
player.y = 2350; // Just above platform 1
player.velocityX = 0;
player.velocityY = 0;
// Change sky color every few levels for visual variety
if (currentLevel % 3 === 0) {
var randomSkyIndex = getRandomSkyColor();
changeSkyColor(randomSkyIndex);
}
// Flash screen green to indicate level completion
LK.effects.flashScreen(0x00ff00, 500);
}
}
}
// Check if player fell off screen
if (player.y > 2800) {
// Set final score and show game over
LK.setScore(gamePoints);
LK.showGameOver();
}
};
// Play background music with saved volume
if (musicVolume > 0) {
LK.playMusic('Musica', {
fade: {
start: 0,
end: musicVolume,
duration: 500
}
});
}
Poder de saltó. In-Game asset. 2d. High contrast. No shadows
Slow fall. In-Game asset. 2d. High contrast. No shadows
Paracaídas. In-Game asset. 2d. High contrast. No shadows
Flecha hacia la derecha. In-Game asset. 2d. High contrast. No shadows
Botas de super salto. In-Game asset. 2d. High contrast. No shadows
Cubo de slime con cara feliz. In-Game asset. 2d. High contrast. No shadows