/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.isCollected = false;
// Add rotating animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isAlive) {
// Restart rotation animation
tween(coinGraphics, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.easeInOut
});
}
}
});
self.collect = function () {
if (self.isCollected) return;
self.isCollected = true;
self.isAlive = false;
// Play sun pickup sound (reuse existing sound)
LK.getSound('sunPickup').play();
// Add score
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Create sparkle effect
for (var i = 0; i < 8; i++) {
var sparkle = LK.getAsset('centerCircle', {
width: 15,
height: 15,
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
tint: 0xFFD700
});
game.addChild(sparkle);
var angle = i / 8 * Math.PI * 2;
var distance = 60 + Math.random() * 30;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
self.visible = false;
};
return self;
});
var Dragon = Container.expand(function () {
var self = Container.call(this);
var dragonGraphics = self.attachAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = -3;
self.isAlive = true;
self.hasDroppedEgg = false;
self.update = function () {
if (!self.isAlive) return;
// Move horizontally from right to left
self.x += self.velocityX;
// Drop egg when dragon reaches middle of screen
if (!self.hasDroppedEgg && self.x <= 1024) {
self.hasDroppedEgg = true;
var egg = game.addChild(new DragonEgg());
egg.x = self.x;
egg.y = self.y + 50;
dragonEggs.push(egg);
}
// Remove dragon when it goes off screen
if (self.x < -200) {
self.isAlive = false;
self.visible = false;
}
};
return self;
});
var DragonEgg = Container.expand(function () {
var self = Container.call(this);
var eggGraphics = self.attachAsset('dragonEgg', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.5;
self.isAlive = true;
self.update = function () {
if (!self.isAlive) return;
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = 0;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var eggBottom = self.y + 30;
var platformTop = platform.y - 20;
if (eggBottom - self.velocityY <= platformTop) {
self.y = platformTop - 30;
self.velocityY = 0;
}
}
}
// Remove egg if it goes off screen
if (self.y > 2200) {
self.isAlive = false;
self.visible = false;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 2;
self.velocityY = 0;
self.gravity = 0.8;
self.isAlive = true;
self.direction = -1; // Always move left initially
self.patrolDistance = 300;
self.startX = 0;
self.isTracking = false;
self.update = function () {
if (!self.isAlive) return;
// Apply gravity
self.velocityY += self.gravity;
// Seek player behavior
if (player) {
var distanceToPlayer = Math.abs(player.x - self.x);
var verticalDistance = Math.abs(player.y - self.y);
// Only seek if player is within detection range
if (distanceToPlayer < 400 && verticalDistance < 200) {
// Make enemy look at player and move towards them
if (player.x < self.x) {
self.direction = -1;
self.velocityX = Math.min(self.velocityX + 0.2, self.maxSpeed || 3);
} else {
self.direction = 1;
self.velocityX = Math.min(self.velocityX + 0.2, self.maxSpeed || 3);
}
// Eye tracking effect - tween enemy slightly towards player
if (!self.isTracking) {
self.isTracking = true;
var targetTint = 0xFF4444; // Red tint when tracking
tween(enemyGraphics, {
tint: targetTint
}, {
duration: 300
});
}
} else {
// Return to normal advancing behavior (move left)
if (self.isTracking) {
self.isTracking = false;
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
// Use the enemy's set velocity or default to 2
self.velocityX = self.velocityX || 2;
self.direction = -1; // Always move left when not tracking
}
}
// Move horizontally
self.x += self.velocityX * self.direction;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = 0;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var enemyBottom = self.y + 30;
var platformTop = platform.y - 20;
if (enemyBottom - self.velocityY <= platformTop) {
self.y = platformTop - 30;
self.velocityY = 0;
}
}
}
// Remove enemies that go off screen (left side)
if (self.x < -100) {
self.isAlive = false;
self.visible = false;
}
// Keep enemy in bounds (right side only)
if (self.x > 2018) {
self.x = 2018;
self.direction = -1;
}
};
self.defeat = function () {
self.isAlive = false;
self.visible = false;
LK.getSound('enemyDestroy').play();
LK.setScore(LK.getScore() + 100);
scoreTxt.setText(LK.getScore());
showCrashMessage();
};
return self;
});
var FlyingEnemy = Container.expand(function () {
var self = Container.call(this);
var flyingEnemyGraphics = self.attachAsset('flyingEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 1;
self.velocityY = 1;
self.isAlive = true;
self.direction = -1;
self.verticalDirection = 1;
self.amplitude = 100;
self.startY = 0;
self.isTracking = false;
self.update = function () {
if (!self.isAlive) return;
// Vertical sine wave movement
self.y += self.velocityY * self.verticalDirection;
if (Math.abs(self.y - self.startY) > self.amplitude) {
self.verticalDirection *= -1;
}
// Seek player behavior
if (player) {
var distanceToPlayer = Math.abs(player.x - self.x);
var verticalDistance = Math.abs(player.y - self.y);
if (distanceToPlayer < 350 && verticalDistance < 250) {
if (player.x < self.x) {
self.direction = -1;
self.velocityX = Math.min(self.velocityX + 0.15, self.maxSpeed || 2.5);
} else {
self.direction = 1;
self.velocityX = Math.min(self.velocityX + 0.15, self.maxSpeed || 2.5);
}
if (!self.isTracking) {
self.isTracking = true;
var targetTint = 0xFF8844;
tween(flyingEnemyGraphics, {
tint: targetTint
}, {
duration: 300
});
}
} else {
if (self.isTracking) {
self.isTracking = false;
tween(flyingEnemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
self.velocityX = self.velocityX || 1.5;
self.direction = -1;
}
}
// Move horizontally
self.x += self.velocityX * self.direction;
// Remove enemies that go off screen
if (self.x < -100) {
self.isAlive = false;
self.visible = false;
}
// Keep enemy in bounds (right side)
if (self.x > 2018) {
self.x = 2018;
self.direction = -1;
}
};
self.defeat = function () {
self.isAlive = false;
self.visible = false;
LK.getSound('enemyDestroy').play();
LK.setScore(LK.getScore() + 100);
scoreTxt.setText(LK.getScore());
showCrashMessage();
};
return self;
});
var Goal = Container.expand(function () {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var HoleEnemy = Container.expand(function () {
var self = Container.call(this);
var holeGraphics = self.attachAsset('holeEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.isClosing = false;
self.fireParticles = [];
self.closeAndSpawnFire = function () {
if (self.isClosing) return;
self.isClosing = true;
self.isAlive = false;
// Close the hole (scale down)
tween(holeGraphics, {
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
// Spawn fire particles after closing
for (var i = 0; i < 8; i++) {
var fire = LK.getAsset('fire', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.5 + Math.random() * 0.5,
scaleY: 0.5 + Math.random() * 0.5
});
game.addChild(fire);
self.fireParticles.push(fire);
// Animate fire particles outward
var angle = i / 8 * Math.PI * 2;
var distance = 50 + Math.random() * 30;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance - 20;
tween(fire, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
fire.destroy();
}
});
}
}
});
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.jumpPower = 25;
self.gravity = 0.8;
self.isGrounded = false;
self.isJumping = false;
self.isMoving = false;
self.runningAnimationActive = false;
self.update = function () {
// Check if player is moving horizontally
var currentlyMoving = Math.abs(self.velocityX) > 0.5;
// Start running animation if moving and not already animating
if (currentlyMoving && !self.runningAnimationActive) {
self.startRunningAnimation();
} else if (!currentlyMoving && self.runningAnimationActive) {
self.stopRunningAnimation();
}
self.isMoving = currentlyMoving;
// Apply gravity
self.velocityY += self.gravity;
// Apply velocities
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 40) {
self.y = groundLevel - 40;
self.velocityY = 0;
self.isGrounded = true;
self.isJumping = false;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var playerBottom = self.y + 40;
var platformTop = platform.y - 20;
if (playerBottom - self.velocityY <= platformTop) {
self.y = platformTop - 40;
self.velocityY = 0;
self.isGrounded = true;
self.isJumping = false;
}
}
}
// Keep player in bounds
if (self.x < 40) self.x = 40;
if (self.x > 2008) self.x = 2008;
// Apply friction
self.velocityX *= 0.85;
// Auto-movement logic
if (autoMovementEnabled && goal) {
// Calculate direction to goal
var distanceToGoal = goal.x - self.x;
var verticalDistance = goal.y - self.y;
// Move towards goal horizontally
if (Math.abs(distanceToGoal) > 50) {
if (distanceToGoal > 0) {
self.velocityX = autoMovementSpeed;
} else {
self.velocityX = -autoMovementSpeed;
}
}
// Update last position for tracking (but no auto-jump)
lastPlayerX = self.x;
}
};
self.jump = function () {
if (self.isGrounded) {
self.velocityY = -self.jumpPower;
self.isGrounded = false;
self.isJumping = true;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX = -self.speed;
};
self.moveRight = function () {
self.velocityX = self.speed;
};
self.startRunningAnimation = function () {
if (self.runningAnimationActive) return;
self.runningAnimationActive = true;
// Create running animation cycle
self.runCycle();
};
self.stopRunningAnimation = function () {
if (!self.runningAnimationActive) return;
self.runningAnimationActive = false;
// Stop any running tweens and reset to normal position
tween.stop(playerGraphics);
tween(playerGraphics, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
};
self.runCycle = function () {
if (!self.runningAnimationActive) return;
// Simulate running with slight rotation and scaling
// Left step - lean slightly left
tween(playerGraphics, {
rotation: -0.1,
scaleX: 0.95,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.runningAnimationActive) return;
// Right step - lean slightly right
tween(playerGraphics, {
rotation: 0.1,
scaleX: 1.05,
scaleY: 0.95
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue the cycle
self.runCycle();
}
});
}
});
};
return self;
});
var Sun = Container.expand(function () {
var self = Container.call(this);
var sunGraphics = self.attachAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.lifeTimer = 0;
self.maxLifeTime = 420; // 7 seconds at 60 FPS
self.isCollected = false;
// Position sun randomly near center of screen
self.x = 900 + Math.random() * 248; // Random position around center (1024 ± 124)
self.y = 1200 + Math.random() * 400; // Random Y position in middle area
// Add pulsing animation
tween(sunGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sunGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isAlive) {
// Restart pulsing animation
tween(sunGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
});
self.update = function () {
if (!self.isAlive) return;
self.lifeTimer++;
// Start fading out after 6 seconds
if (self.lifeTimer > 360) {
var fadeAmount = (self.lifeTimer - 360) / 60; // Fade over 1 second
sunGraphics.alpha = 1 - fadeAmount;
}
// Remove after 3 seconds
if (self.lifeTimer >= self.maxLifeTime) {
self.isAlive = false;
self.visible = false;
}
};
self.collect = function () {
if (self.isCollected) return;
self.isCollected = true;
self.isAlive = false;
// Play sun pickup sound
LK.getSound('sunPickup').play();
// Add extra life
lives++;
livesTxt.setText('Lives: ' + lives);
// Create sparkle effect
for (var i = 0; i < 12; i++) {
var sparkle = LK.getAsset('centerCircle', {
width: 20,
height: 20,
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
tint: 0xFFD700
});
game.addChild(sparkle);
var angle = i / 12 * Math.PI * 2;
var distance = 80 + Math.random() * 40;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
self.visible = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB,
orientation: 'landscape'
});
/****
* Game Code
****/
var player;
var enemies = [];
var flyingEnemies = [];
var holeEnemies = [];
var suns = [];
var dragons = [];
var dragonEggs = [];
var platforms = [];
var coins = [];
var goal;
var ground;
var background;
var currentLevel = 1;
var lives = 3;
var groundLevel = 2000;
var leftPressed = false;
var rightPressed = false;
var lastTouchX = 0;
var lastTouchY = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
levelTxt.x = 0;
levelTxt.y = 50;
LK.gui.top.addChild(levelTxt);
var livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(1, 0);
livesTxt.x = -50;
livesTxt.y = 50;
LK.gui.topRight.addChild(livesTxt);
function createLevel(levelNum) {
// Clear existing level
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = flyingEnemies.length - 1; i >= 0; i--) {
flyingEnemies[i].destroy();
flyingEnemies.splice(i, 1);
}
for (var i = holeEnemies.length - 1; i >= 0; i--) {
holeEnemies[i].destroy();
holeEnemies.splice(i, 1);
}
for (var i = suns.length - 1; i >= 0; i--) {
suns[i].destroy();
suns.splice(i, 1);
}
for (var i = dragons.length - 1; i >= 0; i--) {
dragons[i].destroy();
dragons.splice(i, 1);
}
for (var i = dragonEggs.length - 1; i >= 0; i--) {
dragonEggs[i].destroy();
dragonEggs.splice(i, 1);
}
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].destroy();
platforms.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
if (goal) {
goal.destroy();
goal = null;
}
// Hide any existing "Bien echo" message
var existingMessage = LK.gui.center.children.find(function (child) {
return child.text === 'Bien echo';
});
if (existingMessage) {
existingMessage.destroy();
}
// Create background if not exists
if (!background) {
background = game.addChild(LK.getAsset('countryside', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 1024; // Center horizontally
background.y = 1366; // Center vertically for landscape
}
// Create ground if not exists
if (!ground) {
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
}));
ground.x = 1024; // Center horizontally
ground.y = groundLevel + 50; // Position at ground level
}
// Create player if not exists
if (!player) {
player = game.addChild(new Player());
}
// Reset player position
player.x = 200;
player.y = groundLevel - 100;
player.velocityX = 0;
player.velocityY = 0;
// Reset auto-movement variables
lastPlayerX = player.x;
// Create platforms based on level - different layouts for each level
var platformConfigs = [
// Level 1 - Simple staircase
[{
x: 500,
y: 1850
}, {
x: 750,
y: 1750
}, {
x: 1000,
y: 1650
}, {
x: 1250,
y: 1550
}],
// Level 2 - Zigzag pattern
[{
x: 400,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 900,
y: 1800
}, {
x: 1150,
y: 1650
}, {
x: 1400,
y: 1550
}],
// Level 3 - Dense low platforms
[{
x: 350,
y: 1800
}, {
x: 550,
y: 1700
}, {
x: 750,
y: 1850
}, {
x: 950,
y: 1650
}, {
x: 1150,
y: 1550
}, {
x: 1350,
y: 1450
}],
// Level 4 - High platforms with gaps
[{
x: 450,
y: 1800
}, {
x: 700,
y: 1700
}, {
x: 950,
y: 1850
}, {
x: 1200,
y: 1600
}],
// Level 5 - Vertical tower
[{
x: 650,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 900,
y: 1650
}, {
x: 1150,
y: 1700
}, {
x: 1400,
y: 1600
}],
// Level 6 - Scattered platforms
[{
x: 400,
y: 1800
}, {
x: 600,
y: 1700
}, {
x: 800,
y: 1850
}, {
x: 1000,
y: 1650
}, {
x: 1200,
y: 1550
}, {
x: 1400,
y: 1450
}],
// Level 7 - Long jumps
[{
x: 550,
y: 1750
}, {
x: 850,
y: 1650
}, {
x: 1150,
y: 1550
}],
// Level 8 - Complex maze
[{
x: 450,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 850,
y: 1850
}, {
x: 1050,
y: 1650
}, {
x: 1250,
y: 1800
}, {
x: 1450,
y: 1550
}],
// Level 9 - Pyramid structure
[{
x: 900,
y: 1850
}, {
x: 750,
y: 1750
}, {
x: 1050,
y: 1750
}, {
x: 600,
y: 1650
}, {
x: 1200,
y: 1650
}, {
x: 900,
y: 1550
}],
// Level 10 - Final challenge
[{
x: 350,
y: 1800
}, {
x: 550,
y: 1700
}, {
x: 750,
y: 1750
}, {
x: 950,
y: 1650
}, {
x: 1150,
y: 1700
}, {
x: 1350,
y: 1600
}, {
x: 1550,
y: 1500
}]];
var levelPlatforms = platformConfigs[Math.min(levelNum - 1, platformConfigs.length - 1)];
var _loop = function _loop() {
platform = game.addChild(new Platform());
platform.x = levelPlatforms[i].x;
platform.y = levelPlatforms[i].y;
platforms.push(platform);
// Add vertical movement to each platform
moveDistance = 150; // How far up/down to move
moveDuration = 2000 + i * 300; // Different speeds for each platform
initialY = platform.y; // Create alternating movement - some go up first, others down first
targetY = i % 2 === 0 ? initialY - moveDistance : initialY + moveDistance; // Start the movement animation
function animatePlatform(plat, startY, endY, duration) {
tween(plat, {
y: endY
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Reverse the movement when finished
animatePlatform(plat, endY, startY, duration);
}
});
}
animatePlatform(platform, initialY, targetY, moveDuration);
},
platform,
moveDistance,
moveDuration,
initialY,
targetY;
for (var i = 0; i < levelPlatforms.length; i++) {
_loop();
}
// Create enemies - spawn from right side
var enemyCount = levelNum + 2; // Unlimited enemy increase per level
var enemySpeed = 2 + (levelNum - 1) * 0.5; // Speed increases by 0.5 per level
for (var i = 0; i < enemyCount; i++) {
var enemy = game.addChild(new Enemy());
enemy.x = 2048 + i * 200; // Start from right side of screen
enemy.y = groundLevel - 100;
enemy.startX = enemy.x;
enemy.velocityX = enemySpeed; // Set speed based on level
enemy.maxSpeed = enemySpeed + 1; // Set max speed for tracking
enemies.push(enemy);
}
// Create flying enemies - spawn from right side at random heights
var flyingEnemyCount = 1; // Only one flying enemy per level
var flyingEnemySpeed = 1.5 + (levelNum - 1) * 0.3;
for (var i = 0; i < flyingEnemyCount; i++) {
var flyingEnemy = game.addChild(new FlyingEnemy());
flyingEnemy.x = 2048 + i * 300;
// Random Y position between groundLevel - 800 and groundLevel - 200
flyingEnemy.y = groundLevel - 200 - Math.random() * 600;
flyingEnemy.startY = flyingEnemy.y;
flyingEnemy.velocityX = flyingEnemySpeed;
flyingEnemy.maxSpeed = flyingEnemySpeed + 0.5;
flyingEnemies.push(flyingEnemy);
}
// Create hole enemies starting from level 2
if (levelNum >= 2) {
var holeEnemyCount = 1; // Only one hole enemy per level
for (var i = 0; i < holeEnemyCount; i++) {
var holeEnemy = game.addChild(new HoleEnemy());
// Position hole enemies on the ground at random X positions
holeEnemy.x = 300 + Math.random() * 1400;
holeEnemy.y = groundLevel - 20; // Just above ground level
holeEnemies.push(holeEnemy);
}
}
// Create goal
goal = game.addChild(new Goal());
goal.x = 1900;
goal.y = groundLevel - 75;
// Create sun power-up on specific levels (every 3rd level starting from level 3)
if (levelNum % 3 === 0 && levelNum >= 3) {
var sun = game.addChild(new Sun());
// Position sun at the right side of screen
sun.x = 1800;
sun.y = groundLevel - 300 - Math.random() * 400;
suns.push(sun);
}
// Create random coins throughout the level
var coinCount = 3 + Math.floor(Math.random() * 5); // 3-7 coins per level
for (var i = 0; i < coinCount; i++) {
var coin = game.addChild(new Coin());
// Random position across the level
coin.x = 300 + Math.random() * 1400;
coin.y = groundLevel - 150 - Math.random() * 800;
coins.push(coin);
}
// Create dragon that flies across screen and drops egg
var dragon = game.addChild(new Dragon());
dragon.x = 2200; // Start from right side off screen
dragon.y = groundLevel - 600 - Math.random() * 200; // Random height in sky
dragons.push(dragon);
// Update level display
levelTxt.setText('Level: ' + levelNum);
}
function nextLevel() {
currentLevel++;
LK.setScore(LK.getScore() + 500);
scoreTxt.setText(LK.getScore());
LK.getSound('levelComplete').play();
// Display "Bien echo" message
var congratsText = new Text2('Bien echo', {
size: 120,
fill: 0xFFD700
});
congratsText.anchor.set(0.5, 0.5);
congratsText.x = 0;
congratsText.y = 0;
LK.gui.center.addChild(congratsText);
// Remove the message after 2 seconds
LK.setTimeout(function () {
congratsText.destroy();
}, 2000);
if (currentLevel > 10) {
LK.showYouWin();
} else {
createLevel(currentLevel);
}
}
function showCrashMessage() {
// Remove existing crash message if any
if (crashText) {
crashText.destroy();
}
// Create crash message
crashText = new Text2('CRASHH', {
size: 100,
fill: 0xFF0000
});
crashText.anchor.set(0.5, 0.5);
crashText.x = 0;
crashText.y = 0;
LK.gui.center.addChild(crashText);
// Remove message after 1 second
LK.setTimeout(function () {
if (crashText) {
crashText.destroy();
crashText = null;
}
}, 1000);
}
function loseLife() {
lives--;
livesTxt.setText('Lives: ' + lives);
LK.getSound('playerDeath').play();
if (lives <= 0) {
LK.showGameOver();
} else {
// Reset player position
player.x = 200;
player.y = groundLevel - 100;
player.velocityX = 0;
player.velocityY = 0;
}
}
// Touch controls
game.down = function (x, y, obj) {
lastTouchX = x;
lastTouchY = y;
// Jump on tap
if (player) {
player.jump();
}
};
game.move = function (x, y, obj) {
if (!player) return;
var deltaX = x - lastTouchX;
// Movement based on drag direction
if (Math.abs(deltaX) > 20) {
if (deltaX > 0) {
rightPressed = true;
leftPressed = false;
} else {
leftPressed = true;
rightPressed = false;
}
}
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
leftPressed = false;
rightPressed = false;
};
game.update = function () {
if (!player) return;
// Handle movement (only if auto-movement is disabled)
if (!autoMovementEnabled) {
if (leftPressed) {
player.moveLeft();
}
if (rightPressed) {
player.moveRight();
}
}
// Enemy collision detection
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.isAlive) continue;
if (player.intersects(enemy)) {
// Check if player is falling on enemy from above
if (player.velocityY > 0 && player.y < enemy.y - 10) {
enemy.defeat();
player.velocityY = -10; // Bounce effect
} else {
// Player touched enemy from side - player dies
loseLife();
}
}
}
// Flying enemy collision detection
for (var i = 0; i < flyingEnemies.length; i++) {
var flyingEnemy = flyingEnemies[i];
if (!flyingEnemy.isAlive) continue;
if (player.intersects(flyingEnemy)) {
// Check if player is falling on flying enemy from above
if (player.velocityY > 0 && player.y < flyingEnemy.y - 10) {
flyingEnemy.defeat();
player.velocityY = -12; // Stronger bounce effect
} else {
// Player touched flying enemy from side - push player back
var pushDirection = player.x < flyingEnemy.x ? -1 : 1;
var pushForce = 200;
player.velocityX = pushDirection * 8; // Push player horizontally
player.velocityY = -5; // Small upward push
// Play sound effect
LK.getSound('flyingEnemyHit').play();
// Add visual feedback with tween
tween(player, {
x: player.x + pushDirection * pushForce
}, {
duration: 300,
easing: tween.easeOut
});
}
}
}
// Hole enemy collision detection
for (var i = 0; i < holeEnemies.length; i++) {
var holeEnemy = holeEnemies[i];
if (!holeEnemy.isAlive) continue;
if (player.intersects(holeEnemy)) {
// Close hole and spawn fire effect
holeEnemy.closeAndSpawnFire();
// Player touched hole enemy - player dies
loseLife();
}
}
// Sun collision detection
for (var i = 0; i < suns.length; i++) {
var sun = suns[i];
if (!sun.isAlive) continue;
if (player.intersects(sun)) {
sun.collect();
}
}
// Coin collision detection
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
if (!coin.isAlive) continue;
if (player.intersects(coin)) {
coin.collect();
}
}
// Dragon egg collision detection
for (var i = 0; i < dragonEggs.length; i++) {
var dragonEgg = dragonEggs[i];
if (!dragonEgg.isAlive) continue;
if (player.intersects(dragonEgg)) {
// Make dragon egg disappear
dragonEgg.isAlive = false;
dragonEgg.visible = false;
// Create spectacular light effect - big display
for (var j = 0; j < 40; j++) {
var light = LK.getAsset('centerCircle', {
width: 50 + Math.random() * 40,
height: 50 + Math.random() * 40,
anchorX: 0.5,
anchorY: 0.5,
x: dragonEgg.x,
y: dragonEgg.y,
tint: [0xFFD700, 0xFF6B00, 0xFF1493, 0x00CED1, 0x9370DB, 0x32CD32, 0xFF69B4, 0xFFA500, 0x87CEEB, 0xDDA0DD][j % 10]
});
game.addChild(light);
// Calculate random direction for each light with wide spread
var angle = j / 40 * Math.PI * 2 + Math.random() * 1.5;
var distance = 400 + Math.random() * 300;
var targetX = dragonEgg.x + Math.cos(angle) * distance;
var targetY = dragonEgg.y + Math.sin(angle) * distance;
// Animate light outward with fade, scale and rotation
tween(light, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.random() * Math.PI * 6
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
light.destroy();
}
});
}
// Player loses a life when touching dragon egg
loseLife();
}
}
// Goal collision
if (goal && player.intersects(goal)) {
// Create colored lights effect - big spectacular display
for (var j = 0; j < 30; j++) {
var light = LK.getAsset('centerCircle', {
width: 40 + Math.random() * 30,
height: 40 + Math.random() * 30,
anchorX: 0.5,
anchorY: 0.5,
x: goal.x,
y: goal.y,
tint: [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0xFF8000, 0x8000FF, 0x00FF80][j % 10]
});
game.addChild(light);
// Calculate random direction for each light with more spread
var angle = j / 30 * Math.PI * 2 + Math.random() * 1.0;
var distance = 300 + Math.random() * 200;
var targetX = goal.x + Math.cos(angle) * distance;
var targetY = goal.y + Math.sin(angle) * distance;
// Animate light outward with fade and rotation
tween(light, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.random() * Math.PI * 4
}, {
duration: 1200 + Math.random() * 800,
easing: tween.easeOut,
onFinish: function onFinish() {
light.destroy();
}
});
}
nextLevel();
}
// Fall off screen
if (player.y > 2200) {
loseLife();
}
};
// Auto-movement variables
var autoMovementEnabled = true;
var autoMovementSpeed = 4;
var lastPlayerX = 0;
// Crash message variable
var crashText;
// Initialize first level
createLevel(1);
; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.isCollected = false;
// Add rotating animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isAlive) {
// Restart rotation animation
tween(coinGraphics, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.easeInOut
});
}
}
});
self.collect = function () {
if (self.isCollected) return;
self.isCollected = true;
self.isAlive = false;
// Play sun pickup sound (reuse existing sound)
LK.getSound('sunPickup').play();
// Add score
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Create sparkle effect
for (var i = 0; i < 8; i++) {
var sparkle = LK.getAsset('centerCircle', {
width: 15,
height: 15,
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
tint: 0xFFD700
});
game.addChild(sparkle);
var angle = i / 8 * Math.PI * 2;
var distance = 60 + Math.random() * 30;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
self.visible = false;
};
return self;
});
var Dragon = Container.expand(function () {
var self = Container.call(this);
var dragonGraphics = self.attachAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = -3;
self.isAlive = true;
self.hasDroppedEgg = false;
self.update = function () {
if (!self.isAlive) return;
// Move horizontally from right to left
self.x += self.velocityX;
// Drop egg when dragon reaches middle of screen
if (!self.hasDroppedEgg && self.x <= 1024) {
self.hasDroppedEgg = true;
var egg = game.addChild(new DragonEgg());
egg.x = self.x;
egg.y = self.y + 50;
dragonEggs.push(egg);
}
// Remove dragon when it goes off screen
if (self.x < -200) {
self.isAlive = false;
self.visible = false;
}
};
return self;
});
var DragonEgg = Container.expand(function () {
var self = Container.call(this);
var eggGraphics = self.attachAsset('dragonEgg', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.5;
self.isAlive = true;
self.update = function () {
if (!self.isAlive) return;
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = 0;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var eggBottom = self.y + 30;
var platformTop = platform.y - 20;
if (eggBottom - self.velocityY <= platformTop) {
self.y = platformTop - 30;
self.velocityY = 0;
}
}
}
// Remove egg if it goes off screen
if (self.y > 2200) {
self.isAlive = false;
self.visible = false;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 2;
self.velocityY = 0;
self.gravity = 0.8;
self.isAlive = true;
self.direction = -1; // Always move left initially
self.patrolDistance = 300;
self.startX = 0;
self.isTracking = false;
self.update = function () {
if (!self.isAlive) return;
// Apply gravity
self.velocityY += self.gravity;
// Seek player behavior
if (player) {
var distanceToPlayer = Math.abs(player.x - self.x);
var verticalDistance = Math.abs(player.y - self.y);
// Only seek if player is within detection range
if (distanceToPlayer < 400 && verticalDistance < 200) {
// Make enemy look at player and move towards them
if (player.x < self.x) {
self.direction = -1;
self.velocityX = Math.min(self.velocityX + 0.2, self.maxSpeed || 3);
} else {
self.direction = 1;
self.velocityX = Math.min(self.velocityX + 0.2, self.maxSpeed || 3);
}
// Eye tracking effect - tween enemy slightly towards player
if (!self.isTracking) {
self.isTracking = true;
var targetTint = 0xFF4444; // Red tint when tracking
tween(enemyGraphics, {
tint: targetTint
}, {
duration: 300
});
}
} else {
// Return to normal advancing behavior (move left)
if (self.isTracking) {
self.isTracking = false;
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
// Use the enemy's set velocity or default to 2
self.velocityX = self.velocityX || 2;
self.direction = -1; // Always move left when not tracking
}
}
// Move horizontally
self.x += self.velocityX * self.direction;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = 0;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var enemyBottom = self.y + 30;
var platformTop = platform.y - 20;
if (enemyBottom - self.velocityY <= platformTop) {
self.y = platformTop - 30;
self.velocityY = 0;
}
}
}
// Remove enemies that go off screen (left side)
if (self.x < -100) {
self.isAlive = false;
self.visible = false;
}
// Keep enemy in bounds (right side only)
if (self.x > 2018) {
self.x = 2018;
self.direction = -1;
}
};
self.defeat = function () {
self.isAlive = false;
self.visible = false;
LK.getSound('enemyDestroy').play();
LK.setScore(LK.getScore() + 100);
scoreTxt.setText(LK.getScore());
showCrashMessage();
};
return self;
});
var FlyingEnemy = Container.expand(function () {
var self = Container.call(this);
var flyingEnemyGraphics = self.attachAsset('flyingEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 1;
self.velocityY = 1;
self.isAlive = true;
self.direction = -1;
self.verticalDirection = 1;
self.amplitude = 100;
self.startY = 0;
self.isTracking = false;
self.update = function () {
if (!self.isAlive) return;
// Vertical sine wave movement
self.y += self.velocityY * self.verticalDirection;
if (Math.abs(self.y - self.startY) > self.amplitude) {
self.verticalDirection *= -1;
}
// Seek player behavior
if (player) {
var distanceToPlayer = Math.abs(player.x - self.x);
var verticalDistance = Math.abs(player.y - self.y);
if (distanceToPlayer < 350 && verticalDistance < 250) {
if (player.x < self.x) {
self.direction = -1;
self.velocityX = Math.min(self.velocityX + 0.15, self.maxSpeed || 2.5);
} else {
self.direction = 1;
self.velocityX = Math.min(self.velocityX + 0.15, self.maxSpeed || 2.5);
}
if (!self.isTracking) {
self.isTracking = true;
var targetTint = 0xFF8844;
tween(flyingEnemyGraphics, {
tint: targetTint
}, {
duration: 300
});
}
} else {
if (self.isTracking) {
self.isTracking = false;
tween(flyingEnemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
self.velocityX = self.velocityX || 1.5;
self.direction = -1;
}
}
// Move horizontally
self.x += self.velocityX * self.direction;
// Remove enemies that go off screen
if (self.x < -100) {
self.isAlive = false;
self.visible = false;
}
// Keep enemy in bounds (right side)
if (self.x > 2018) {
self.x = 2018;
self.direction = -1;
}
};
self.defeat = function () {
self.isAlive = false;
self.visible = false;
LK.getSound('enemyDestroy').play();
LK.setScore(LK.getScore() + 100);
scoreTxt.setText(LK.getScore());
showCrashMessage();
};
return self;
});
var Goal = Container.expand(function () {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var HoleEnemy = Container.expand(function () {
var self = Container.call(this);
var holeGraphics = self.attachAsset('holeEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.isClosing = false;
self.fireParticles = [];
self.closeAndSpawnFire = function () {
if (self.isClosing) return;
self.isClosing = true;
self.isAlive = false;
// Close the hole (scale down)
tween(holeGraphics, {
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
// Spawn fire particles after closing
for (var i = 0; i < 8; i++) {
var fire = LK.getAsset('fire', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.5 + Math.random() * 0.5,
scaleY: 0.5 + Math.random() * 0.5
});
game.addChild(fire);
self.fireParticles.push(fire);
// Animate fire particles outward
var angle = i / 8 * Math.PI * 2;
var distance = 50 + Math.random() * 30;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance - 20;
tween(fire, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
fire.destroy();
}
});
}
}
});
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.jumpPower = 25;
self.gravity = 0.8;
self.isGrounded = false;
self.isJumping = false;
self.isMoving = false;
self.runningAnimationActive = false;
self.update = function () {
// Check if player is moving horizontally
var currentlyMoving = Math.abs(self.velocityX) > 0.5;
// Start running animation if moving and not already animating
if (currentlyMoving && !self.runningAnimationActive) {
self.startRunningAnimation();
} else if (!currentlyMoving && self.runningAnimationActive) {
self.stopRunningAnimation();
}
self.isMoving = currentlyMoving;
// Apply gravity
self.velocityY += self.gravity;
// Apply velocities
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision
if (self.y >= groundLevel - 40) {
self.y = groundLevel - 40;
self.velocityY = 0;
self.isGrounded = true;
self.isJumping = false;
}
// Platform collision
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var playerBottom = self.y + 40;
var platformTop = platform.y - 20;
if (playerBottom - self.velocityY <= platformTop) {
self.y = platformTop - 40;
self.velocityY = 0;
self.isGrounded = true;
self.isJumping = false;
}
}
}
// Keep player in bounds
if (self.x < 40) self.x = 40;
if (self.x > 2008) self.x = 2008;
// Apply friction
self.velocityX *= 0.85;
// Auto-movement logic
if (autoMovementEnabled && goal) {
// Calculate direction to goal
var distanceToGoal = goal.x - self.x;
var verticalDistance = goal.y - self.y;
// Move towards goal horizontally
if (Math.abs(distanceToGoal) > 50) {
if (distanceToGoal > 0) {
self.velocityX = autoMovementSpeed;
} else {
self.velocityX = -autoMovementSpeed;
}
}
// Update last position for tracking (but no auto-jump)
lastPlayerX = self.x;
}
};
self.jump = function () {
if (self.isGrounded) {
self.velocityY = -self.jumpPower;
self.isGrounded = false;
self.isJumping = true;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX = -self.speed;
};
self.moveRight = function () {
self.velocityX = self.speed;
};
self.startRunningAnimation = function () {
if (self.runningAnimationActive) return;
self.runningAnimationActive = true;
// Create running animation cycle
self.runCycle();
};
self.stopRunningAnimation = function () {
if (!self.runningAnimationActive) return;
self.runningAnimationActive = false;
// Stop any running tweens and reset to normal position
tween.stop(playerGraphics);
tween(playerGraphics, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
};
self.runCycle = function () {
if (!self.runningAnimationActive) return;
// Simulate running with slight rotation and scaling
// Left step - lean slightly left
tween(playerGraphics, {
rotation: -0.1,
scaleX: 0.95,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.runningAnimationActive) return;
// Right step - lean slightly right
tween(playerGraphics, {
rotation: 0.1,
scaleX: 1.05,
scaleY: 0.95
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue the cycle
self.runCycle();
}
});
}
});
};
return self;
});
var Sun = Container.expand(function () {
var self = Container.call(this);
var sunGraphics = self.attachAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAlive = true;
self.lifeTimer = 0;
self.maxLifeTime = 420; // 7 seconds at 60 FPS
self.isCollected = false;
// Position sun randomly near center of screen
self.x = 900 + Math.random() * 248; // Random position around center (1024 ± 124)
self.y = 1200 + Math.random() * 400; // Random Y position in middle area
// Add pulsing animation
tween(sunGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sunGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isAlive) {
// Restart pulsing animation
tween(sunGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
});
self.update = function () {
if (!self.isAlive) return;
self.lifeTimer++;
// Start fading out after 6 seconds
if (self.lifeTimer > 360) {
var fadeAmount = (self.lifeTimer - 360) / 60; // Fade over 1 second
sunGraphics.alpha = 1 - fadeAmount;
}
// Remove after 3 seconds
if (self.lifeTimer >= self.maxLifeTime) {
self.isAlive = false;
self.visible = false;
}
};
self.collect = function () {
if (self.isCollected) return;
self.isCollected = true;
self.isAlive = false;
// Play sun pickup sound
LK.getSound('sunPickup').play();
// Add extra life
lives++;
livesTxt.setText('Lives: ' + lives);
// Create sparkle effect
for (var i = 0; i < 12; i++) {
var sparkle = LK.getAsset('centerCircle', {
width: 20,
height: 20,
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
tint: 0xFFD700
});
game.addChild(sparkle);
var angle = i / 12 * Math.PI * 2;
var distance = 80 + Math.random() * 40;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
self.visible = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB,
orientation: 'landscape'
});
/****
* Game Code
****/
var player;
var enemies = [];
var flyingEnemies = [];
var holeEnemies = [];
var suns = [];
var dragons = [];
var dragonEggs = [];
var platforms = [];
var coins = [];
var goal;
var ground;
var background;
var currentLevel = 1;
var lives = 3;
var groundLevel = 2000;
var leftPressed = false;
var rightPressed = false;
var lastTouchX = 0;
var lastTouchY = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
levelTxt.x = 0;
levelTxt.y = 50;
LK.gui.top.addChild(levelTxt);
var livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(1, 0);
livesTxt.x = -50;
livesTxt.y = 50;
LK.gui.topRight.addChild(livesTxt);
function createLevel(levelNum) {
// Clear existing level
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = flyingEnemies.length - 1; i >= 0; i--) {
flyingEnemies[i].destroy();
flyingEnemies.splice(i, 1);
}
for (var i = holeEnemies.length - 1; i >= 0; i--) {
holeEnemies[i].destroy();
holeEnemies.splice(i, 1);
}
for (var i = suns.length - 1; i >= 0; i--) {
suns[i].destroy();
suns.splice(i, 1);
}
for (var i = dragons.length - 1; i >= 0; i--) {
dragons[i].destroy();
dragons.splice(i, 1);
}
for (var i = dragonEggs.length - 1; i >= 0; i--) {
dragonEggs[i].destroy();
dragonEggs.splice(i, 1);
}
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].destroy();
platforms.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
if (goal) {
goal.destroy();
goal = null;
}
// Hide any existing "Bien echo" message
var existingMessage = LK.gui.center.children.find(function (child) {
return child.text === 'Bien echo';
});
if (existingMessage) {
existingMessage.destroy();
}
// Create background if not exists
if (!background) {
background = game.addChild(LK.getAsset('countryside', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 1024; // Center horizontally
background.y = 1366; // Center vertically for landscape
}
// Create ground if not exists
if (!ground) {
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
}));
ground.x = 1024; // Center horizontally
ground.y = groundLevel + 50; // Position at ground level
}
// Create player if not exists
if (!player) {
player = game.addChild(new Player());
}
// Reset player position
player.x = 200;
player.y = groundLevel - 100;
player.velocityX = 0;
player.velocityY = 0;
// Reset auto-movement variables
lastPlayerX = player.x;
// Create platforms based on level - different layouts for each level
var platformConfigs = [
// Level 1 - Simple staircase
[{
x: 500,
y: 1850
}, {
x: 750,
y: 1750
}, {
x: 1000,
y: 1650
}, {
x: 1250,
y: 1550
}],
// Level 2 - Zigzag pattern
[{
x: 400,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 900,
y: 1800
}, {
x: 1150,
y: 1650
}, {
x: 1400,
y: 1550
}],
// Level 3 - Dense low platforms
[{
x: 350,
y: 1800
}, {
x: 550,
y: 1700
}, {
x: 750,
y: 1850
}, {
x: 950,
y: 1650
}, {
x: 1150,
y: 1550
}, {
x: 1350,
y: 1450
}],
// Level 4 - High platforms with gaps
[{
x: 450,
y: 1800
}, {
x: 700,
y: 1700
}, {
x: 950,
y: 1850
}, {
x: 1200,
y: 1600
}],
// Level 5 - Vertical tower
[{
x: 650,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 900,
y: 1650
}, {
x: 1150,
y: 1700
}, {
x: 1400,
y: 1600
}],
// Level 6 - Scattered platforms
[{
x: 400,
y: 1800
}, {
x: 600,
y: 1700
}, {
x: 800,
y: 1850
}, {
x: 1000,
y: 1650
}, {
x: 1200,
y: 1550
}, {
x: 1400,
y: 1450
}],
// Level 7 - Long jumps
[{
x: 550,
y: 1750
}, {
x: 850,
y: 1650
}, {
x: 1150,
y: 1550
}],
// Level 8 - Complex maze
[{
x: 450,
y: 1850
}, {
x: 650,
y: 1750
}, {
x: 850,
y: 1850
}, {
x: 1050,
y: 1650
}, {
x: 1250,
y: 1800
}, {
x: 1450,
y: 1550
}],
// Level 9 - Pyramid structure
[{
x: 900,
y: 1850
}, {
x: 750,
y: 1750
}, {
x: 1050,
y: 1750
}, {
x: 600,
y: 1650
}, {
x: 1200,
y: 1650
}, {
x: 900,
y: 1550
}],
// Level 10 - Final challenge
[{
x: 350,
y: 1800
}, {
x: 550,
y: 1700
}, {
x: 750,
y: 1750
}, {
x: 950,
y: 1650
}, {
x: 1150,
y: 1700
}, {
x: 1350,
y: 1600
}, {
x: 1550,
y: 1500
}]];
var levelPlatforms = platformConfigs[Math.min(levelNum - 1, platformConfigs.length - 1)];
var _loop = function _loop() {
platform = game.addChild(new Platform());
platform.x = levelPlatforms[i].x;
platform.y = levelPlatforms[i].y;
platforms.push(platform);
// Add vertical movement to each platform
moveDistance = 150; // How far up/down to move
moveDuration = 2000 + i * 300; // Different speeds for each platform
initialY = platform.y; // Create alternating movement - some go up first, others down first
targetY = i % 2 === 0 ? initialY - moveDistance : initialY + moveDistance; // Start the movement animation
function animatePlatform(plat, startY, endY, duration) {
tween(plat, {
y: endY
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Reverse the movement when finished
animatePlatform(plat, endY, startY, duration);
}
});
}
animatePlatform(platform, initialY, targetY, moveDuration);
},
platform,
moveDistance,
moveDuration,
initialY,
targetY;
for (var i = 0; i < levelPlatforms.length; i++) {
_loop();
}
// Create enemies - spawn from right side
var enemyCount = levelNum + 2; // Unlimited enemy increase per level
var enemySpeed = 2 + (levelNum - 1) * 0.5; // Speed increases by 0.5 per level
for (var i = 0; i < enemyCount; i++) {
var enemy = game.addChild(new Enemy());
enemy.x = 2048 + i * 200; // Start from right side of screen
enemy.y = groundLevel - 100;
enemy.startX = enemy.x;
enemy.velocityX = enemySpeed; // Set speed based on level
enemy.maxSpeed = enemySpeed + 1; // Set max speed for tracking
enemies.push(enemy);
}
// Create flying enemies - spawn from right side at random heights
var flyingEnemyCount = 1; // Only one flying enemy per level
var flyingEnemySpeed = 1.5 + (levelNum - 1) * 0.3;
for (var i = 0; i < flyingEnemyCount; i++) {
var flyingEnemy = game.addChild(new FlyingEnemy());
flyingEnemy.x = 2048 + i * 300;
// Random Y position between groundLevel - 800 and groundLevel - 200
flyingEnemy.y = groundLevel - 200 - Math.random() * 600;
flyingEnemy.startY = flyingEnemy.y;
flyingEnemy.velocityX = flyingEnemySpeed;
flyingEnemy.maxSpeed = flyingEnemySpeed + 0.5;
flyingEnemies.push(flyingEnemy);
}
// Create hole enemies starting from level 2
if (levelNum >= 2) {
var holeEnemyCount = 1; // Only one hole enemy per level
for (var i = 0; i < holeEnemyCount; i++) {
var holeEnemy = game.addChild(new HoleEnemy());
// Position hole enemies on the ground at random X positions
holeEnemy.x = 300 + Math.random() * 1400;
holeEnemy.y = groundLevel - 20; // Just above ground level
holeEnemies.push(holeEnemy);
}
}
// Create goal
goal = game.addChild(new Goal());
goal.x = 1900;
goal.y = groundLevel - 75;
// Create sun power-up on specific levels (every 3rd level starting from level 3)
if (levelNum % 3 === 0 && levelNum >= 3) {
var sun = game.addChild(new Sun());
// Position sun at the right side of screen
sun.x = 1800;
sun.y = groundLevel - 300 - Math.random() * 400;
suns.push(sun);
}
// Create random coins throughout the level
var coinCount = 3 + Math.floor(Math.random() * 5); // 3-7 coins per level
for (var i = 0; i < coinCount; i++) {
var coin = game.addChild(new Coin());
// Random position across the level
coin.x = 300 + Math.random() * 1400;
coin.y = groundLevel - 150 - Math.random() * 800;
coins.push(coin);
}
// Create dragon that flies across screen and drops egg
var dragon = game.addChild(new Dragon());
dragon.x = 2200; // Start from right side off screen
dragon.y = groundLevel - 600 - Math.random() * 200; // Random height in sky
dragons.push(dragon);
// Update level display
levelTxt.setText('Level: ' + levelNum);
}
function nextLevel() {
currentLevel++;
LK.setScore(LK.getScore() + 500);
scoreTxt.setText(LK.getScore());
LK.getSound('levelComplete').play();
// Display "Bien echo" message
var congratsText = new Text2('Bien echo', {
size: 120,
fill: 0xFFD700
});
congratsText.anchor.set(0.5, 0.5);
congratsText.x = 0;
congratsText.y = 0;
LK.gui.center.addChild(congratsText);
// Remove the message after 2 seconds
LK.setTimeout(function () {
congratsText.destroy();
}, 2000);
if (currentLevel > 10) {
LK.showYouWin();
} else {
createLevel(currentLevel);
}
}
function showCrashMessage() {
// Remove existing crash message if any
if (crashText) {
crashText.destroy();
}
// Create crash message
crashText = new Text2('CRASHH', {
size: 100,
fill: 0xFF0000
});
crashText.anchor.set(0.5, 0.5);
crashText.x = 0;
crashText.y = 0;
LK.gui.center.addChild(crashText);
// Remove message after 1 second
LK.setTimeout(function () {
if (crashText) {
crashText.destroy();
crashText = null;
}
}, 1000);
}
function loseLife() {
lives--;
livesTxt.setText('Lives: ' + lives);
LK.getSound('playerDeath').play();
if (lives <= 0) {
LK.showGameOver();
} else {
// Reset player position
player.x = 200;
player.y = groundLevel - 100;
player.velocityX = 0;
player.velocityY = 0;
}
}
// Touch controls
game.down = function (x, y, obj) {
lastTouchX = x;
lastTouchY = y;
// Jump on tap
if (player) {
player.jump();
}
};
game.move = function (x, y, obj) {
if (!player) return;
var deltaX = x - lastTouchX;
// Movement based on drag direction
if (Math.abs(deltaX) > 20) {
if (deltaX > 0) {
rightPressed = true;
leftPressed = false;
} else {
leftPressed = true;
rightPressed = false;
}
}
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
leftPressed = false;
rightPressed = false;
};
game.update = function () {
if (!player) return;
// Handle movement (only if auto-movement is disabled)
if (!autoMovementEnabled) {
if (leftPressed) {
player.moveLeft();
}
if (rightPressed) {
player.moveRight();
}
}
// Enemy collision detection
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.isAlive) continue;
if (player.intersects(enemy)) {
// Check if player is falling on enemy from above
if (player.velocityY > 0 && player.y < enemy.y - 10) {
enemy.defeat();
player.velocityY = -10; // Bounce effect
} else {
// Player touched enemy from side - player dies
loseLife();
}
}
}
// Flying enemy collision detection
for (var i = 0; i < flyingEnemies.length; i++) {
var flyingEnemy = flyingEnemies[i];
if (!flyingEnemy.isAlive) continue;
if (player.intersects(flyingEnemy)) {
// Check if player is falling on flying enemy from above
if (player.velocityY > 0 && player.y < flyingEnemy.y - 10) {
flyingEnemy.defeat();
player.velocityY = -12; // Stronger bounce effect
} else {
// Player touched flying enemy from side - push player back
var pushDirection = player.x < flyingEnemy.x ? -1 : 1;
var pushForce = 200;
player.velocityX = pushDirection * 8; // Push player horizontally
player.velocityY = -5; // Small upward push
// Play sound effect
LK.getSound('flyingEnemyHit').play();
// Add visual feedback with tween
tween(player, {
x: player.x + pushDirection * pushForce
}, {
duration: 300,
easing: tween.easeOut
});
}
}
}
// Hole enemy collision detection
for (var i = 0; i < holeEnemies.length; i++) {
var holeEnemy = holeEnemies[i];
if (!holeEnemy.isAlive) continue;
if (player.intersects(holeEnemy)) {
// Close hole and spawn fire effect
holeEnemy.closeAndSpawnFire();
// Player touched hole enemy - player dies
loseLife();
}
}
// Sun collision detection
for (var i = 0; i < suns.length; i++) {
var sun = suns[i];
if (!sun.isAlive) continue;
if (player.intersects(sun)) {
sun.collect();
}
}
// Coin collision detection
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
if (!coin.isAlive) continue;
if (player.intersects(coin)) {
coin.collect();
}
}
// Dragon egg collision detection
for (var i = 0; i < dragonEggs.length; i++) {
var dragonEgg = dragonEggs[i];
if (!dragonEgg.isAlive) continue;
if (player.intersects(dragonEgg)) {
// Make dragon egg disappear
dragonEgg.isAlive = false;
dragonEgg.visible = false;
// Create spectacular light effect - big display
for (var j = 0; j < 40; j++) {
var light = LK.getAsset('centerCircle', {
width: 50 + Math.random() * 40,
height: 50 + Math.random() * 40,
anchorX: 0.5,
anchorY: 0.5,
x: dragonEgg.x,
y: dragonEgg.y,
tint: [0xFFD700, 0xFF6B00, 0xFF1493, 0x00CED1, 0x9370DB, 0x32CD32, 0xFF69B4, 0xFFA500, 0x87CEEB, 0xDDA0DD][j % 10]
});
game.addChild(light);
// Calculate random direction for each light with wide spread
var angle = j / 40 * Math.PI * 2 + Math.random() * 1.5;
var distance = 400 + Math.random() * 300;
var targetX = dragonEgg.x + Math.cos(angle) * distance;
var targetY = dragonEgg.y + Math.sin(angle) * distance;
// Animate light outward with fade, scale and rotation
tween(light, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.random() * Math.PI * 6
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
light.destroy();
}
});
}
// Player loses a life when touching dragon egg
loseLife();
}
}
// Goal collision
if (goal && player.intersects(goal)) {
// Create colored lights effect - big spectacular display
for (var j = 0; j < 30; j++) {
var light = LK.getAsset('centerCircle', {
width: 40 + Math.random() * 30,
height: 40 + Math.random() * 30,
anchorX: 0.5,
anchorY: 0.5,
x: goal.x,
y: goal.y,
tint: [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0xFF8000, 0x8000FF, 0x00FF80][j % 10]
});
game.addChild(light);
// Calculate random direction for each light with more spread
var angle = j / 30 * Math.PI * 2 + Math.random() * 1.0;
var distance = 300 + Math.random() * 200;
var targetX = goal.x + Math.cos(angle) * distance;
var targetY = goal.y + Math.sin(angle) * distance;
// Animate light outward with fade and rotation
tween(light, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.random() * Math.PI * 4
}, {
duration: 1200 + Math.random() * 800,
easing: tween.easeOut,
onFinish: function onFinish() {
light.destroy();
}
});
}
nextLevel();
}
// Fall off screen
if (player.y > 2200) {
loseLife();
}
};
// Auto-movement variables
var autoMovementEnabled = true;
var autoMovementSpeed = 4;
var lastPlayerX = 0;
// Crash message variable
var crashText;
// Initialize first level
createLevel(1);
;
un fuego. In-Game asset. 2d. High contrast. No shadows. un fuego. un fuego
un fuego con ojos y boca, de expresion enojado. In-Game asset. 2d. High contrast. No shadows
un castillo simple. In-Game asset. 2d. High contrast. No shadows. castillo simple
una nube. In-Game asset. 2d. High contrast. No shadows
fuego con alas, ojo y boca. In-Game asset. 2d. High contrast. No shadows
camino de tierra. In-Game asset. 2d. High contrast. No shadows
cielo con castillos y nubes de fondo, que se vea borroso. In-Game asset. 2d. High contrast. No shadows
un oyo de tierra con estacas puntiagudas, de aspecto amenazador. In-Game asset. 2d. High contrast. No shadows
un sol con la leyenda "1 UP". In-Game asset. 2d. High contrast. No shadows
un huevo de colores. In-Game asset. 2d. High contrast. No shadows. un huevo de colores
humo gris. In-Game asset. 2d. High contrast. No shadows
un muñeco con gorra y pantalones. In-Game asset. 2d. High contrast. No shadows