User prompt
make an smaller enemy who is like the normal enemy but is faster and smaller and make the small enemy yellow
User prompt
make that first three enemy are spawning are normal enemys
User prompt
make the no jump enemy like the falling enemy
User prompt
make an second falling enemy were you dont jump and when you jump and hit the second falling enemy you lose one heart
User prompt
make that the shooting enemy roll like the normal enemy
User prompt
make an warning red stripe before the shooting enemy comes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
no make that the enemy flyes fast and shoot no bullets
User prompt
make the shoting enemy faster
User prompt
make an new enemy who i shotting from the right side
User prompt
remove the wings from the heart
User prompt
change y position from normal enemy by -2
User prompt
make sound yeah to 3.0
User prompt
play sound yeah when player become a heart more
User prompt
make sound aua louder
User prompt
louder
User prompt
if losing one heart then play sound aua
User prompt
when the player double jumps stop sound jump
User prompt
play sound jump when player jumps
User prompt
make the y position from th enemy same as player when the player is on ground
User prompt
let me pick the collor for the sky
User prompt
darker brown
User prompt
make the sky in the same brown as dirt
User prompt
make the sky brown ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
remove portal
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Define a class for flying bird enemies var Bird = Container.expand(function () { var self = Container.call(this); var birdGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Apply a tint to make it look different from regular enemies birdGraphics.tint = 0x00FFFF; // Create a hitbox for the bird self.hitArea = new Rectangle(-30, -30, 60, 60); self.speed = 6; self.verticalSpeed = 0; self.amplitude = 100; // How high the bird flies up and down self.frequency = 0.05; // How fast the bird completes a wave cycle self.initialY = 0; // Will store the initial Y position self.time = 0; // Time counter for sine wave movement self.update = function () { // Store last position for collision detection if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; } // Bird moves regardless of collisions with other enemies // Move bird horizontally self.x -= self.speed; // Update time counter self.time += self.frequency; // Apply sine wave vertical movement self.y = self.initialY + Math.sin(self.time) * self.amplitude; // Rotate bird slightly to match flight direction self.rotation = Math.sin(self.time) * 0.2; // Remove bird if it's off screen if (self.x < -50) { // Remove from enemies array when reaching the left side for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); } // Update last positions self.lastX = self.x; self.lastY = self.y; }; return self; }); // Define a class for enemies var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Create a much smaller hitbox for the enemy (reduce the collision area) self.hitArea = new Rectangle(-30, -30, 60, 60); self.speed = 8; self.update = function () { // Store last position for collision detection if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; } // Enemy moves regardless of collisions with other enemies self.x -= self.speed; // Make the enemy roll by rotating it in the opposite direction self.rotation -= 0.1; if (self.x < -50) { // Remove from enemies array when reaching the left side for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); } // Update last positions self.lastX = self.x; self.lastY = self.y; }; }); // Define a class for enemies that fall from the sky var FallingEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Apply a purple tint to make it visually distinct enemyGraphics.tint = 0x9900FF; // Create a hitbox for the falling enemy self.hitArea = new Rectangle(-35, -35, 70, 70); self.fallSpeed = 10; self.rotationSpeed = 0.08; self.update = function () { // Store last position for collision detection if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; } // FallingEnemy moves regardless of collisions with other enemies // Move enemy down self.y += self.fallSpeed; // Rotate enemy as it falls self.rotation += self.rotationSpeed; // Remove if off screen if (self.y > 2732 + 100) { // Remove from enemies array when reaching the bottom for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); } // Update last positions self.lastX = self.x; self.lastY = self.y; }; return self; }); // Define a class for heart display var Heart = Container.expand(function () { var self = Container.call(this); // Create a heart using the heart asset var heartShape = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); // Animate heart slightly self.animate = function () { tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOutQuad, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOutQuad, onFinish: self.animate }); } }); }; return self; }); // Define a class for heart pickups that fly in the sky var HeartPickup = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); // Add visual effects to make the heart look more like a pickup heartGraphics.tint = 0xFF8FB8; // Lighter pink color // Create a hitbox for the heart self.hitArea = new Rectangle(-35, -35, 70, 70); // Movement properties self.speed = 3 + Math.random() * 2; // Random speed between 3-5 self.floatAmplitude = 40 + Math.random() * 30; // Random float height self.floatSpeed = 0.03 + Math.random() * 0.02; // Random float speed self.initialY = 0; self.time = Math.random() * Math.PI * 2; // Random starting position in float cycle // Add wing decorations to make it look like it's flying var leftWing = self.attachAsset('wings', { anchorX: 0.5, anchorY: 0.5, x: -45, scaleX: 0.8, scaleY: 0.8, rotation: 0 // Make wings look up }); var rightWing = self.attachAsset('wings', { anchorX: 0.5, anchorY: 0.5, x: 45, scaleX: -0.8, // Flip horizontally scaleY: 0.8, rotation: 0 // Make wings look up }); // Animate wings self.animateWings = function () { tween(leftWing, { rotation: 0.2, y: -5 }, { duration: 400, easing: tween.easeInOutQuad, onFinish: function onFinish() { tween(leftWing, { rotation: 0, y: 0 }, { duration: 400, easing: tween.easeInOutQuad, onFinish: self.animateWings }); } }); tween(rightWing, { rotation: -0.2, y: -5 }, { duration: 400, easing: tween.easeInOutQuad, onFinish: function onFinish() { tween(rightWing, { rotation: 0, y: 0 }, { duration: 400, easing: tween.easeInOutQuad }); } }); }; // Start wing animation self.animateWings(); self.update = function () { // Store last position for collision detection if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; } // Move heart horizontally self.x -= self.speed; // Apply floating movement self.time += self.floatSpeed; self.y = self.initialY + Math.sin(self.time) * self.floatAmplitude; // Remove heart if it's off screen if (self.x < -100) { // Remove from hearts array for (var i = 0; i < heartPickups.length; i++) { if (heartPickups[i] === self) { heartPickups.splice(i, 1); break; } } self.destroy(); } // Update last positions self.lastX = self.x; self.lastY = self.y; }; return self; }); //<Assets used in the game will automatically appear here> // Define a class for the player character var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Create a smaller hitbox for the player to make collisions more precise self.hitArea = new Rectangle(-50, -30, 100, 60); self.speed = 5; self.jumpHeight = 40; self.isJumping = false; self.velocityY = 0; self.invulnerable = false; self.jumpsRemaining = 2; // Allow for double jump (initial + 1 more in air) self.update = function () { if (self.isJumping) { self.y += self.velocityY; self.velocityY += 0.9; // Gravity effect if (self.y >= 2732 / 2) { // Ground level self.y = 2732 / 2; self.isJumping = false; self.velocityY = 0; self.jumpsRemaining = 2; // Reset jumps when landing // Add landing animation - slight squash effect tween(self, { scaleX: 1.3, scaleY: 0.7 }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { // Return to normal scale tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOutElastic }); } }); } } // Check for falling enemies above the player for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy instanceof FallingEnemy && enemy.y > self.y - 400 && enemy.y < self.y && Math.abs(enemy.x - self.x) < 100 && self.isJumping && self.velocityY < 0) { // If player is jumping upward into a falling enemy, destroy it enemies.splice(i, 1); enemy.destroy(); // Give bonus score // Check if score was reset to 0 and restart music if (LK.getScore() === 0) { LK.stopMusic(); LK.playMusic('epicMusic', { loop: true, fade: { start: 0, end: 0.8, duration: 2000 } }); } LK.setScore(LK.getScore() + 5); scoreText.setText(LK.getScore()); // Add visual effect for killing enemy LK.effects.flashObject(self, 0x00ff00, 500); break; } } }; self.jump = function () { // Allow jumping if either on ground or have jumps remaining if (!self.isJumping || self.jumpsRemaining > 0) { // If already jumping, this is a double jump if (self.isJumping) { self.jumpsRemaining--; // Second jump has significantly less height self.velocityY = -self.jumpHeight * 0.6; } else { // First jump self.isJumping = true; self.jumpsRemaining = 1; // One more jump available after initial jump self.velocityY = -self.jumpHeight; } // Add a jump animation - squash before stretching up tween(self, { scaleX: 1.2, scaleY: 0.8 }, { duration: 150, easing: tween.easeOutQuad, onFinish: function onFinish() { // Stretch when jumping up tween(self, { scaleX: 0.9, scaleY: 1.3 }, { duration: 300, easing: tween.easeOutQuad, onFinish: function onFinish() { // Return to normal scale gradually tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 400, easing: tween.easeInOutQuad }); } }); } }); } }; }); // Portal class removed as it's no longer needed // Define a class for slow, big enemies var SlowEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Make it slightly larger but smaller than before enemyGraphics.scale.set(1.8, 1.8); // Apply a reddish tint to make it look more threatening enemyGraphics.tint = 0xFF5555; // Create a hitbox that matches the new smaller size self.hitArea = new Rectangle(-55, -55, 110, 110); // Faster speed compared to previous value self.speed = 5; self.update = function () { // Store last position for collision detection if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; } // SlowEnemy moves regardless of collisions with other enemies // Move enemy slowly self.x -= self.speed; // Make the enemy roll but slower than regular enemies self.rotation -= 0.04; // Remove if off screen if (self.x < -100) { // Remove from enemies array when reaching the left side for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); } // Update last positions self.lastX = self.x; self.lastY = self.y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Using same asset as enemy but will be tinted differently var background = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; // Add a second background for the empty space var background2 = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0 })); background2.x = background.width; background2.y = 0; // Initialize player var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2732 / 2; // Enemies will spawn from the right edge without a portal // Initialize enemies var enemies = []; var enemySpawnInterval = 100; var enemySpawnCounter = 0; // Create a new Text2 object to display the score var scoreText = new Text2('0', { size: 100, fill: 0xFFFFFF }); // Add instruction text var instructionText = new Text2('Tap once to jump, tap again for double jump!', { size: 64, fill: 0xFFFFFF }); LK.gui.bottom.addChild(instructionText); instructionText.x = 2048 / 2; instructionText.y = -100; instructionText.anchor.set(0.5, 0.5); // Fade out instruction after 5 seconds LK.setTimeout(function () { tween(instructionText, { alpha: 0 }, { duration: 1000, easing: tween.easeInCubic }); }, 5000); // Add the score text to the game GUI at the top center of the screen LK.gui.top.addChild(scoreText); scoreText.x = 2048 / 2; scoreText.y = 0; // Initialize lives counter var lives = 3; var hearts = []; var heartsContainer = new Container(); game.addChild(heartsContainer); // Position hearts container in the middle of the screen heartsContainer.x = 2048 / 2; heartsContainer.y = 150; // Create heart display function updateHeartDisplay() { // Clear existing hearts while (hearts.length > 0) { var heart = hearts.pop(); heart.destroy(); } // Create new hearts based on current lives for (var i = 0; i < lives; i++) { var heart = new Heart(); heart.x = (i - (lives - 1) / 2) * 100; // Distribute hearts evenly heart.y = 0; hearts.push(heart); heartsContainer.addChild(heart); heart.animate(); } } // Initial heart display updateHeartDisplay(); // Play epic background music with fade-in effect LK.playMusic('epicMusic', { fade: { start: 0, end: 0.8, duration: 2000 } }); // Add listener for game reset to restart music LK.on('gameReset', function () { // Restart the music when game resets from the beginning (second 0) LK.stopMusic(); // Stop current music to ensure we start from the beginning LK.playMusic('epicMusic', { loop: true, fade: { start: 0, end: 0.8, duration: 2000 } }); }); // Add listener for game over to restart music LK.on('gameOver', function () { // Stop current music to ensure we start from the beginning LK.stopMusic(); // Restart the music from the beginning LK.playMusic('epicMusic', { loop: true, fade: { start: 0, end: 0.8, duration: 2000 } }); }); // Initialize array for heart pickups var heartPickups = []; // Variables for heart spawn control var heartSpawnInterval = 600; // Less frequent than enemies var heartSpawnCounter = 0; // Handle game updates game.update = function () { player.update(); // No portal to update // Spawn hearts occasionally heartSpawnCounter++; if (heartSpawnCounter >= heartSpawnInterval) { // Only spawn heart if player has less than maximum lives if (lives < 3) { var heartPickup = new HeartPickup(); heartPickup.x = 2048 + 100; // Start right of screen heartPickup.y = player.y; // Spawn at the same y position as the player heartPickup.initialY = heartPickup.y; heartPickups.push(heartPickup); game.addChild(heartPickup); // Add spawn effect heartPickup.scale.set(0.1, 0.1); tween(heartPickup, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeOutElastic }); } // Reset heart spawn counter and randomize next interval heartSpawnInterval = Math.floor(Math.random() * 400) + 600; // Between 600-1000 heartSpawnCounter = 0; } // Update all heart pickups for (var i = heartPickups.length - 1; i >= 0; i--) { heartPickups[i].update(); // Check if player collected the heart if (player.intersects(heartPickups[i])) { // Regenerate one heart if not at max if (lives < 3) { lives++; updateHeartDisplay(); // Show healing effect LK.effects.flashObject(player, 0x00FF00, 500); // Show text effect var healText = new Text2('+1', { size: 80, fill: 0x00FF00 }); healText.anchor.set(0.5, 0.5); healText.x = player.x; healText.y = player.y - 100; game.addChild(healText); // Animate and remove text tween(healText, { y: healText.y - 150, alpha: 0 }, { duration: 1000, easing: tween.easeOutCubic, onFinish: function onFinish() { healText.destroy(); } }); } // Remove heart pickup heartPickups[i].destroy(); heartPickups.splice(i, 1); } } // Spawn enemies enemySpawnCounter++; if (enemySpawnCounter >= enemySpawnInterval) { // Enemies spawn without portal effects // Track if a slow enemy is present in the game var hasSlowEnemy = false; for (var i = 0; i < enemies.length; i++) { if (enemies[i] instanceof SlowEnemy) { hasSlowEnemy = true; break; } } // Randomly decide between enemy types var spawnChance = Math.random(); // If a slow enemy is present, don't spawn normal enemies if (hasSlowEnemy && spawnChance < 0.4) { // Redirect to either bird or falling enemy spawnChance = 0.4 + spawnChance * 0.6; // Scale between 0.4 and 0.7 } if (spawnChance < 0.4) { // 40% chance for regular enemy (only if no slow enemy is present) var enemy = new Enemy(); enemy.x = 2048; // Right edge of screen enemy.y = 2732 / 2; // Middle of screen enemies.push(enemy); game.addChild(enemy); // Apply rolling animation with tween in the opposite direction tween(enemy, { rotation: -Math.PI * 4 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { // Continuously roll the enemy in the opposite direction tween(enemy, { rotation: enemy.rotation - Math.PI * 4 }, { duration: 2000, easing: tween.linear }); } }); } else if (spawnChance < 0.65) { // 25% chance for bird var bird = new Bird(); bird.x = 2048; // Right edge of screen bird.y = Math.random() * (2732 / 2 - 400) + 400; // Random position between 400 and half the screen height bird.initialY = bird.y; // Set the initial Y position for the sine wave enemies.push(bird); game.addChild(bird); // Apply flapping wing animation tween(bird, { scaleY: 0.85 }, { duration: 300, easing: tween.easeInOutQuad, onFinish: function onFinish() { // Flap wings function that will call itself repeatedly function flapWings() { tween(bird, { scaleY: 1.15 }, { duration: 300, easing: tween.easeInOutQuad, onFinish: function onFinish() { tween(bird, { scaleY: 0.85 }, { duration: 300, easing: tween.easeInOutQuad, onFinish: flapWings }); } }); } flapWings(); } }); } else if (spawnChance < 0.85) { // 20% chance for slow, big enemy var slowEnemy = new SlowEnemy(); slowEnemy.x = 2048; // Right edge of screen slowEnemy.y = 2732 / 2; // Middle of screen enemies.push(slowEnemy); game.addChild(slowEnemy); // Apply slow stomping animation tween(slowEnemy, { rotation: -Math.PI * 2 }, { duration: 4000, easing: tween.linear, onFinish: function onFinish() { // Continuously roll the enemy in the opposite direction but slower tween(slowEnemy, { rotation: slowEnemy.rotation - Math.PI * 2 }, { duration: 4000, easing: tween.linear }); } }); } else { // 15% chance for falling enemy var fallingEnemy = new FallingEnemy(); // Position falling enemy at the player's x position at the top of the screen fallingEnemy.x = player.x; fallingEnemy.y = -100; // Start above the screen enemies.push(fallingEnemy); game.addChild(fallingEnemy); // Apply spinning animation tween(fallingEnemy, { rotation: Math.PI * 4 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { // Continuously spin the enemy tween(fallingEnemy, { rotation: fallingEnemy.rotation + Math.PI * 4 }, { duration: 2000, easing: tween.linear }); } }); } // Randomize the spawn interval for the next enemy enemySpawnInterval = Math.floor(Math.random() * 150) + 50; enemySpawnCounter = 0; } // Update enemies for (var j = enemies.length - 1; j >= 0; j--) { if (enemies[j]) { // Check if enemy exists before accessing enemies[j].update(); if (enemies[j] && player.intersects(enemies[j]) && !player.invulnerable) { // Handle collision lives--; updateHeartDisplay(); // Make player invulnerable temporarily player.invulnerable = true; player.alpha = 0.5; // Flash the screen red LK.effects.flashScreen(0xff0000, 500); // Remove the enemy enemies[j].destroy(); enemies.splice(j, 1); // Check if player has run out of lives if (lives <= 0) { // Stop and restart music from the beginning before showing game over LK.stopMusic(); LK.playMusic('epicMusic', { loop: true, fade: { start: 0, end: 0.8, duration: 2000 } }); LK.showGameOver(); } else { // Make player vulnerable again after a short time LK.setTimeout(function () { player.invulnerable = false; player.alpha = 1; }, 1500); } } else if (enemies[j] && player.x > enemies[j].x && !enemies[j].passed) { enemies[j].passed = true; LK.setScore(LK.getScore() + 1); scoreText.setText(LK.getScore()); } } // Close the enemy existence check } }; // Handle player jump game.down = function (x, y, obj) { player.jump(); }; // Import tween plugin for animations
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Define a class for flying bird enemies
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply a tint to make it look different from regular enemies
birdGraphics.tint = 0x00FFFF;
// Create a hitbox for the bird
self.hitArea = new Rectangle(-30, -30, 60, 60);
self.speed = 6;
self.verticalSpeed = 0;
self.amplitude = 100; // How high the bird flies up and down
self.frequency = 0.05; // How fast the bird completes a wave cycle
self.initialY = 0; // Will store the initial Y position
self.time = 0; // Time counter for sine wave movement
self.update = function () {
// Store last position for collision detection
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
}
// Bird moves regardless of collisions with other enemies
// Move bird horizontally
self.x -= self.speed;
// Update time counter
self.time += self.frequency;
// Apply sine wave vertical movement
self.y = self.initialY + Math.sin(self.time) * self.amplitude;
// Rotate bird slightly to match flight direction
self.rotation = Math.sin(self.time) * 0.2;
// Remove bird if it's off screen
if (self.x < -50) {
// Remove from enemies array when reaching the left side
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
}
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Define a class for enemies
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Create a much smaller hitbox for the enemy (reduce the collision area)
self.hitArea = new Rectangle(-30, -30, 60, 60);
self.speed = 8;
self.update = function () {
// Store last position for collision detection
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
}
// Enemy moves regardless of collisions with other enemies
self.x -= self.speed;
// Make the enemy roll by rotating it in the opposite direction
self.rotation -= 0.1;
if (self.x < -50) {
// Remove from enemies array when reaching the left side
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
}
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
});
// Define a class for enemies that fall from the sky
var FallingEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply a purple tint to make it visually distinct
enemyGraphics.tint = 0x9900FF;
// Create a hitbox for the falling enemy
self.hitArea = new Rectangle(-35, -35, 70, 70);
self.fallSpeed = 10;
self.rotationSpeed = 0.08;
self.update = function () {
// Store last position for collision detection
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
}
// FallingEnemy moves regardless of collisions with other enemies
// Move enemy down
self.y += self.fallSpeed;
// Rotate enemy as it falls
self.rotation += self.rotationSpeed;
// Remove if off screen
if (self.y > 2732 + 100) {
// Remove from enemies array when reaching the bottom
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
}
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Define a class for heart display
var Heart = Container.expand(function () {
var self = Container.call(this);
// Create a heart using the heart asset
var heartShape = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
// Animate heart slightly
self.animate = function () {
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOutQuad,
onFinish: self.animate
});
}
});
};
return self;
});
// Define a class for heart pickups that fly in the sky
var HeartPickup = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual effects to make the heart look more like a pickup
heartGraphics.tint = 0xFF8FB8; // Lighter pink color
// Create a hitbox for the heart
self.hitArea = new Rectangle(-35, -35, 70, 70);
// Movement properties
self.speed = 3 + Math.random() * 2; // Random speed between 3-5
self.floatAmplitude = 40 + Math.random() * 30; // Random float height
self.floatSpeed = 0.03 + Math.random() * 0.02; // Random float speed
self.initialY = 0;
self.time = Math.random() * Math.PI * 2; // Random starting position in float cycle
// Add wing decorations to make it look like it's flying
var leftWing = self.attachAsset('wings', {
anchorX: 0.5,
anchorY: 0.5,
x: -45,
scaleX: 0.8,
scaleY: 0.8,
rotation: 0 // Make wings look up
});
var rightWing = self.attachAsset('wings', {
anchorX: 0.5,
anchorY: 0.5,
x: 45,
scaleX: -0.8,
// Flip horizontally
scaleY: 0.8,
rotation: 0 // Make wings look up
});
// Animate wings
self.animateWings = function () {
tween(leftWing, {
rotation: 0.2,
y: -5
}, {
duration: 400,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(leftWing, {
rotation: 0,
y: 0
}, {
duration: 400,
easing: tween.easeInOutQuad,
onFinish: self.animateWings
});
}
});
tween(rightWing, {
rotation: -0.2,
y: -5
}, {
duration: 400,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(rightWing, {
rotation: 0,
y: 0
}, {
duration: 400,
easing: tween.easeInOutQuad
});
}
});
};
// Start wing animation
self.animateWings();
self.update = function () {
// Store last position for collision detection
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
}
// Move heart horizontally
self.x -= self.speed;
// Apply floating movement
self.time += self.floatSpeed;
self.y = self.initialY + Math.sin(self.time) * self.floatAmplitude;
// Remove heart if it's off screen
if (self.x < -100) {
// Remove from hearts array
for (var i = 0; i < heartPickups.length; i++) {
if (heartPickups[i] === self) {
heartPickups.splice(i, 1);
break;
}
}
self.destroy();
}
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
//<Assets used in the game will automatically appear here>
// Define a class for the player character
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Create a smaller hitbox for the player to make collisions more precise
self.hitArea = new Rectangle(-50, -30, 100, 60);
self.speed = 5;
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.invulnerable = false;
self.jumpsRemaining = 2; // Allow for double jump (initial + 1 more in air)
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.9; // Gravity effect
if (self.y >= 2732 / 2) {
// Ground level
self.y = 2732 / 2;
self.isJumping = false;
self.velocityY = 0;
self.jumpsRemaining = 2; // Reset jumps when landing
// Add landing animation - slight squash effect
tween(self, {
scaleX: 1.3,
scaleY: 0.7
}, {
duration: 200,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
// Return to normal scale
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOutElastic
});
}
});
}
}
// Check for falling enemies above the player
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (enemy instanceof FallingEnemy && enemy.y > self.y - 400 && enemy.y < self.y && Math.abs(enemy.x - self.x) < 100 && self.isJumping && self.velocityY < 0) {
// If player is jumping upward into a falling enemy, destroy it
enemies.splice(i, 1);
enemy.destroy();
// Give bonus score
// Check if score was reset to 0 and restart music
if (LK.getScore() === 0) {
LK.stopMusic();
LK.playMusic('epicMusic', {
loop: true,
fade: {
start: 0,
end: 0.8,
duration: 2000
}
});
}
LK.setScore(LK.getScore() + 5);
scoreText.setText(LK.getScore());
// Add visual effect for killing enemy
LK.effects.flashObject(self, 0x00ff00, 500);
break;
}
}
};
self.jump = function () {
// Allow jumping if either on ground or have jumps remaining
if (!self.isJumping || self.jumpsRemaining > 0) {
// If already jumping, this is a double jump
if (self.isJumping) {
self.jumpsRemaining--;
// Second jump has significantly less height
self.velocityY = -self.jumpHeight * 0.6;
} else {
// First jump
self.isJumping = true;
self.jumpsRemaining = 1; // One more jump available after initial jump
self.velocityY = -self.jumpHeight;
}
// Add a jump animation - squash before stretching up
tween(self, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
// Stretch when jumping up
tween(self, {
scaleX: 0.9,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
// Return to normal scale gradually
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOutQuad
});
}
});
}
});
}
};
});
// Portal class removed as it's no longer needed
// Define a class for slow, big enemies
var SlowEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Make it slightly larger but smaller than before
enemyGraphics.scale.set(1.8, 1.8);
// Apply a reddish tint to make it look more threatening
enemyGraphics.tint = 0xFF5555;
// Create a hitbox that matches the new smaller size
self.hitArea = new Rectangle(-55, -55, 110, 110);
// Faster speed compared to previous value
self.speed = 5;
self.update = function () {
// Store last position for collision detection
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
}
// SlowEnemy moves regardless of collisions with other enemies
// Move enemy slowly
self.x -= self.speed;
// Make the enemy roll but slower than regular enemies
self.rotation -= 0.04;
// Remove if off screen
if (self.x < -100) {
// Remove from enemies array when reaching the left side
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
}
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Using same asset as enemy but will be tinted differently
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Add a second background for the empty space
var background2 = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0
}));
background2.x = background.width;
background2.y = 0;
// Initialize player
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 / 2;
// Enemies will spawn from the right edge without a portal
// Initialize enemies
var enemies = [];
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
// Create a new Text2 object to display the score
var scoreText = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
// Add instruction text
var instructionText = new Text2('Tap once to jump, tap again for double jump!', {
size: 64,
fill: 0xFFFFFF
});
LK.gui.bottom.addChild(instructionText);
instructionText.x = 2048 / 2;
instructionText.y = -100;
instructionText.anchor.set(0.5, 0.5);
// Fade out instruction after 5 seconds
LK.setTimeout(function () {
tween(instructionText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeInCubic
});
}, 5000);
// Add the score text to the game GUI at the top center of the screen
LK.gui.top.addChild(scoreText);
scoreText.x = 2048 / 2;
scoreText.y = 0;
// Initialize lives counter
var lives = 3;
var hearts = [];
var heartsContainer = new Container();
game.addChild(heartsContainer);
// Position hearts container in the middle of the screen
heartsContainer.x = 2048 / 2;
heartsContainer.y = 150;
// Create heart display
function updateHeartDisplay() {
// Clear existing hearts
while (hearts.length > 0) {
var heart = hearts.pop();
heart.destroy();
}
// Create new hearts based on current lives
for (var i = 0; i < lives; i++) {
var heart = new Heart();
heart.x = (i - (lives - 1) / 2) * 100; // Distribute hearts evenly
heart.y = 0;
hearts.push(heart);
heartsContainer.addChild(heart);
heart.animate();
}
}
// Initial heart display
updateHeartDisplay();
// Play epic background music with fade-in effect
LK.playMusic('epicMusic', {
fade: {
start: 0,
end: 0.8,
duration: 2000
}
});
// Add listener for game reset to restart music
LK.on('gameReset', function () {
// Restart the music when game resets from the beginning (second 0)
LK.stopMusic(); // Stop current music to ensure we start from the beginning
LK.playMusic('epicMusic', {
loop: true,
fade: {
start: 0,
end: 0.8,
duration: 2000
}
});
});
// Add listener for game over to restart music
LK.on('gameOver', function () {
// Stop current music to ensure we start from the beginning
LK.stopMusic();
// Restart the music from the beginning
LK.playMusic('epicMusic', {
loop: true,
fade: {
start: 0,
end: 0.8,
duration: 2000
}
});
});
// Initialize array for heart pickups
var heartPickups = [];
// Variables for heart spawn control
var heartSpawnInterval = 600; // Less frequent than enemies
var heartSpawnCounter = 0;
// Handle game updates
game.update = function () {
player.update();
// No portal to update
// Spawn hearts occasionally
heartSpawnCounter++;
if (heartSpawnCounter >= heartSpawnInterval) {
// Only spawn heart if player has less than maximum lives
if (lives < 3) {
var heartPickup = new HeartPickup();
heartPickup.x = 2048 + 100; // Start right of screen
heartPickup.y = player.y; // Spawn at the same y position as the player
heartPickup.initialY = heartPickup.y;
heartPickups.push(heartPickup);
game.addChild(heartPickup);
// Add spawn effect
heartPickup.scale.set(0.1, 0.1);
tween(heartPickup, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeOutElastic
});
}
// Reset heart spawn counter and randomize next interval
heartSpawnInterval = Math.floor(Math.random() * 400) + 600; // Between 600-1000
heartSpawnCounter = 0;
}
// Update all heart pickups
for (var i = heartPickups.length - 1; i >= 0; i--) {
heartPickups[i].update();
// Check if player collected the heart
if (player.intersects(heartPickups[i])) {
// Regenerate one heart if not at max
if (lives < 3) {
lives++;
updateHeartDisplay();
// Show healing effect
LK.effects.flashObject(player, 0x00FF00, 500);
// Show text effect
var healText = new Text2('+1', {
size: 80,
fill: 0x00FF00
});
healText.anchor.set(0.5, 0.5);
healText.x = player.x;
healText.y = player.y - 100;
game.addChild(healText);
// Animate and remove text
tween(healText, {
y: healText.y - 150,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOutCubic,
onFinish: function onFinish() {
healText.destroy();
}
});
}
// Remove heart pickup
heartPickups[i].destroy();
heartPickups.splice(i, 1);
}
}
// Spawn enemies
enemySpawnCounter++;
if (enemySpawnCounter >= enemySpawnInterval) {
// Enemies spawn without portal effects
// Track if a slow enemy is present in the game
var hasSlowEnemy = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof SlowEnemy) {
hasSlowEnemy = true;
break;
}
}
// Randomly decide between enemy types
var spawnChance = Math.random();
// If a slow enemy is present, don't spawn normal enemies
if (hasSlowEnemy && spawnChance < 0.4) {
// Redirect to either bird or falling enemy
spawnChance = 0.4 + spawnChance * 0.6; // Scale between 0.4 and 0.7
}
if (spawnChance < 0.4) {
// 40% chance for regular enemy (only if no slow enemy is present)
var enemy = new Enemy();
enemy.x = 2048; // Right edge of screen
enemy.y = 2732 / 2; // Middle of screen
enemies.push(enemy);
game.addChild(enemy);
// Apply rolling animation with tween in the opposite direction
tween(enemy, {
rotation: -Math.PI * 4
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
// Continuously roll the enemy in the opposite direction
tween(enemy, {
rotation: enemy.rotation - Math.PI * 4
}, {
duration: 2000,
easing: tween.linear
});
}
});
} else if (spawnChance < 0.65) {
// 25% chance for bird
var bird = new Bird();
bird.x = 2048; // Right edge of screen
bird.y = Math.random() * (2732 / 2 - 400) + 400; // Random position between 400 and half the screen height
bird.initialY = bird.y; // Set the initial Y position for the sine wave
enemies.push(bird);
game.addChild(bird);
// Apply flapping wing animation
tween(bird, {
scaleY: 0.85
}, {
duration: 300,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
// Flap wings function that will call itself repeatedly
function flapWings() {
tween(bird, {
scaleY: 1.15
}, {
duration: 300,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(bird, {
scaleY: 0.85
}, {
duration: 300,
easing: tween.easeInOutQuad,
onFinish: flapWings
});
}
});
}
flapWings();
}
});
} else if (spawnChance < 0.85) {
// 20% chance for slow, big enemy
var slowEnemy = new SlowEnemy();
slowEnemy.x = 2048; // Right edge of screen
slowEnemy.y = 2732 / 2; // Middle of screen
enemies.push(slowEnemy);
game.addChild(slowEnemy);
// Apply slow stomping animation
tween(slowEnemy, {
rotation: -Math.PI * 2
}, {
duration: 4000,
easing: tween.linear,
onFinish: function onFinish() {
// Continuously roll the enemy in the opposite direction but slower
tween(slowEnemy, {
rotation: slowEnemy.rotation - Math.PI * 2
}, {
duration: 4000,
easing: tween.linear
});
}
});
} else {
// 15% chance for falling enemy
var fallingEnemy = new FallingEnemy();
// Position falling enemy at the player's x position at the top of the screen
fallingEnemy.x = player.x;
fallingEnemy.y = -100; // Start above the screen
enemies.push(fallingEnemy);
game.addChild(fallingEnemy);
// Apply spinning animation
tween(fallingEnemy, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
// Continuously spin the enemy
tween(fallingEnemy, {
rotation: fallingEnemy.rotation + Math.PI * 4
}, {
duration: 2000,
easing: tween.linear
});
}
});
}
// Randomize the spawn interval for the next enemy
enemySpawnInterval = Math.floor(Math.random() * 150) + 50;
enemySpawnCounter = 0;
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
if (enemies[j]) {
// Check if enemy exists before accessing
enemies[j].update();
if (enemies[j] && player.intersects(enemies[j]) && !player.invulnerable) {
// Handle collision
lives--;
updateHeartDisplay();
// Make player invulnerable temporarily
player.invulnerable = true;
player.alpha = 0.5;
// Flash the screen red
LK.effects.flashScreen(0xff0000, 500);
// Remove the enemy
enemies[j].destroy();
enemies.splice(j, 1);
// Check if player has run out of lives
if (lives <= 0) {
// Stop and restart music from the beginning before showing game over
LK.stopMusic();
LK.playMusic('epicMusic', {
loop: true,
fade: {
start: 0,
end: 0.8,
duration: 2000
}
});
LK.showGameOver();
} else {
// Make player vulnerable again after a short time
LK.setTimeout(function () {
player.invulnerable = false;
player.alpha = 1;
}, 1500);
}
} else if (enemies[j] && player.x > enemies[j].x && !enemies[j].passed) {
enemies[j].passed = true;
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
} // Close the enemy existence check
}
};
// Handle player jump
game.down = function (x, y, obj) {
player.jump();
};
// Import tween plugin for animations