User prompt
show dirt
User prompt
make an second backround for the empty space
User prompt
Aber es tut halt irgendwie nicht funktionieren, ich weiß nicht warum.
User prompt
starte music neu wenn der score 0 ist
User prompt
mache das die music von neu startet nach dem der spieler gestorben ist
User prompt
it did nothing
User prompt
make that epic music restarts after game over
User prompt
okaay make that enemys can go trough other enemys
User prompt
make that no normal enemy spawns after the slowenemy
User prompt
make that the wings from the heart look up
User prompt
you didnt do it
User prompt
spin the wings from the heart 180 degrees ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make minimal y position spawn from the hearts same as the player
User prompt
somtimes hearts fly in the sky and when you touch them yue regenerate one heart
User prompt
to avoid losing a heart from the fallingenemy jump at the fallingenemy kills the fallingenemy
User prompt
the falling enemy allways falls from the sam x position from the player
User prompt
make an new enemy who is falling from the sky
User prompt
give the bird wings
User prompt
give the bird wings
User prompt
make the portal particles round
User prompt
make the portal smaller
User prompt
make the portal giant ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the portal biger
User prompt
make the portal to a circle
User prompt
make an portal were the enemies come out
/**** * 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; } // Check for collisions with other enemies var isColliding = false; for (var i = 0; i < enemies.length; i++) { var otherEnemy = enemies[i]; // Skip if it's the same enemy if (otherEnemy === self) { continue; } // Check for intersection if (self.intersects(otherEnemy)) { isColliding = true; break; } } // Only move if not colliding with other enemies if (!isColliding) { // 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; } // Check for collisions with other enemies var isColliding = false; for (var i = 0; i < enemies.length; i++) { var otherEnemy = enemies[i]; // Skip if it's the same enemy if (otherEnemy === self) { continue; } // Check for intersection if (self.intersects(otherEnemy)) { isColliding = true; break; } } // Only move if not colliding with other enemies if (!isColliding) { 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 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; }); //<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 }); } }); } } }; 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 }); } }); } }); } }; }); // Define a class for the portal where enemies come from var Portal = Container.expand(function () { var self = Container.call(this); // Create portal visuals (a circular shape with animation) var portalShape = self.attachAsset('hitbox', { anchorX: 0.5, anchorY: 0.5 }); // Make it circular and adjust color to look like a portal portalShape.tint = 0x9900FF; // Purple portal color portalShape.scale.set(1.5, 1.5); // Add portal animation with pulsing effect self.animate = function () { tween(portalShape, { scaleX: 1.8, scaleY: 1.8, alpha: 0.7 }, { duration: 1000, easing: tween.easeInOutQuad, onFinish: function onFinish() { tween(portalShape, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 1000, easing: tween.easeInOutQuad, onFinish: self.animate }); } }); }; // Start animation self.animate(); // Add particle effect for the portal (using the same hitbox asset with different properties) self.spawnParticle = function () { var particle = LK.getAsset('hitbox', { anchorX: 0.5, anchorY: 0.5 }); // Make particle small and purple particle.width = 20; particle.height = 20; particle.tint = 0xBB00FF; particle.alpha = 0.7; // Random position around the portal center var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 50; particle.x = self.x + Math.cos(angle) * distance; particle.y = self.y + Math.sin(angle) * distance; // Add to game game.addChild(particle); // Animate particle tween(particle, { alpha: 0, width: 5, height: 5, x: particle.x + (Math.random() - 0.5) * 100, y: particle.y + (Math.random() - 0.5) * 100 }, { duration: 1000, easing: tween.easeOutQuad, onFinish: function onFinish() { particle.destroy(); } }); }; // Emit particles regularly self.update = function () { // Spawn particles on a timer (every 10 frames) if (LK.ticks % 10 === 0) { self.spawnParticle(); } }; return self; }); // 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; } // Check for collisions with other enemies var isColliding = false; for (var i = 0; i < enemies.length; i++) { var otherEnemy = enemies[i]; // Skip if it's the same enemy if (otherEnemy === self) { continue; } // Check for intersection if (self.intersects(otherEnemy)) { isColliding = true; break; } } // Only move if not colliding with other enemies if (!isColliding) { // 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; // Initialize player var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2732 / 2; // Create a portal where enemies will spawn var portal = game.addChild(new Portal()); portal.x = 2048; // Right side of the screen portal.y = 2732 / 2; // Middle of the screen vertically // 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 } }); }); // Handle game updates game.update = function () { player.update(); // Update portal animations portal.update(); // Spawn enemies enemySpawnCounter++; if (enemySpawnCounter >= enemySpawnInterval) { // Visual effect when spawning an enemy - portal grows briefly tween(portal.children[0], { scaleX: 2.2, scaleY: 2.2 }, { duration: 300, easing: tween.easeOutQuad, onFinish: function onFinish() { // Return to normal animation cycle portal.children[0].scaleX = 1.5; portal.children[0].scaleY = 1.5; } }); // Randomly decide between regular enemy, slow big enemy, or bird var spawnChance = Math.random(); if (spawnChance < 0.5) { // 50% chance for regular enemy var enemy = new Enemy(); enemy.x = portal.x; enemy.y = portal.y; 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.8) { // 30% chance for bird var bird = new Bird(); bird.x = portal.x; 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 { // 20% chance for slow, big enemy var slowEnemy = new SlowEnemy(); slowEnemy.x = portal.x; slowEnemy.y = portal.y; 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 }); } }); } // 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) { 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;
}
// Check for collisions with other enemies
var isColliding = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
// Skip if it's the same enemy
if (otherEnemy === self) {
continue;
}
// Check for intersection
if (self.intersects(otherEnemy)) {
isColliding = true;
break;
}
}
// Only move if not colliding with other enemies
if (!isColliding) {
// 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;
}
// Check for collisions with other enemies
var isColliding = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
// Skip if it's the same enemy
if (otherEnemy === self) {
continue;
}
// Check for intersection
if (self.intersects(otherEnemy)) {
isColliding = true;
break;
}
}
// Only move if not colliding with other enemies
if (!isColliding) {
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 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;
});
//<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
});
}
});
}
}
};
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
});
}
});
}
});
}
};
});
// Define a class for the portal where enemies come from
var Portal = Container.expand(function () {
var self = Container.call(this);
// Create portal visuals (a circular shape with animation)
var portalShape = self.attachAsset('hitbox', {
anchorX: 0.5,
anchorY: 0.5
});
// Make it circular and adjust color to look like a portal
portalShape.tint = 0x9900FF; // Purple portal color
portalShape.scale.set(1.5, 1.5);
// Add portal animation with pulsing effect
self.animate = function () {
tween(portalShape, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.7
}, {
duration: 1000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(portalShape, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1
}, {
duration: 1000,
easing: tween.easeInOutQuad,
onFinish: self.animate
});
}
});
};
// Start animation
self.animate();
// Add particle effect for the portal (using the same hitbox asset with different properties)
self.spawnParticle = function () {
var particle = LK.getAsset('hitbox', {
anchorX: 0.5,
anchorY: 0.5
});
// Make particle small and purple
particle.width = 20;
particle.height = 20;
particle.tint = 0xBB00FF;
particle.alpha = 0.7;
// Random position around the portal center
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 50;
particle.x = self.x + Math.cos(angle) * distance;
particle.y = self.y + Math.sin(angle) * distance;
// Add to game
game.addChild(particle);
// Animate particle
tween(particle, {
alpha: 0,
width: 5,
height: 5,
x: particle.x + (Math.random() - 0.5) * 100,
y: particle.y + (Math.random() - 0.5) * 100
}, {
duration: 1000,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
particle.destroy();
}
});
};
// Emit particles regularly
self.update = function () {
// Spawn particles on a timer (every 10 frames)
if (LK.ticks % 10 === 0) {
self.spawnParticle();
}
};
return self;
});
// 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;
}
// Check for collisions with other enemies
var isColliding = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
// Skip if it's the same enemy
if (otherEnemy === self) {
continue;
}
// Check for intersection
if (self.intersects(otherEnemy)) {
isColliding = true;
break;
}
}
// Only move if not colliding with other enemies
if (!isColliding) {
// 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;
// Initialize player
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 / 2;
// Create a portal where enemies will spawn
var portal = game.addChild(new Portal());
portal.x = 2048; // Right side of the screen
portal.y = 2732 / 2; // Middle of the screen vertically
// 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
}
});
});
// Handle game updates
game.update = function () {
player.update();
// Update portal animations
portal.update();
// Spawn enemies
enemySpawnCounter++;
if (enemySpawnCounter >= enemySpawnInterval) {
// Visual effect when spawning an enemy - portal grows briefly
tween(portal.children[0], {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 300,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
// Return to normal animation cycle
portal.children[0].scaleX = 1.5;
portal.children[0].scaleY = 1.5;
}
});
// Randomly decide between regular enemy, slow big enemy, or bird
var spawnChance = Math.random();
if (spawnChance < 0.5) {
// 50% chance for regular enemy
var enemy = new Enemy();
enemy.x = portal.x;
enemy.y = portal.y;
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.8) {
// 30% chance for bird
var bird = new Bird();
bird.x = portal.x;
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 {
// 20% chance for slow, big enemy
var slowEnemy = new SlowEnemy();
slowEnemy.x = portal.x;
slowEnemy.y = portal.y;
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
});
}
});
}
// 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) {
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