User prompt
Please fix the bug: 'ReferenceError: Can't find variable: Obstacle' in or related to this line: 'var obstacle = game.addChild(new Obstacle('cloud'));' Line Number: 399
User prompt
obstacles other than clouds should spawn randomly and independently of each other. spawns should be rare relative to clouds. birds spawn in a parallel line from the right or left side of the screen. stars spawn diagonally. lightning follows a vertical path. wind chimes suddenly appear and disappear. obstacles should not spawn opposite direct of game flow. they should spawn on the everywhere of screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
obstacles other than clouds should spawn randomly and independently of each other. spawns should be rare relative to clouds. birds spawn in a parallel line from the right or left side of the screen. stars spawn diagonally. lightning follows a vertical path. wind chimes suddenly appear and disappear. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
every 500 meters the game can get faster or harder. remove the score, just make it distance. make the life icons hearts, not the usual heart, not the one on the card. and make the text the previous size. remove the empty unused space at the top, the space above the score.
User prompt
make the game fullscreen, no unused space. make life icons as hearts.
User prompt
write score in the empty space above the scoreboard. write distance. and let the character have 3 lives, put 3 lives, 3 lives come by default, as the character crosses the obstacle, the life goes away. for these lives, also have a life power up in the game, the probability of spawning is 0.05%. when you get that life, add a new life, maximum life 5.
User prompt
obstacles should keep spawning as long as the character moves, we should keep seeing obstacles as we move downwards.
User prompt
more obstacles. remove the line on upper of the scoreboard. camera track character
User prompt
wind should lead him and more birds more stars more lightning, all of them are obstacles ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
clouds make him stop and game should be an infinite fall game
User prompt
obstacles spawn more
User prompt
give character motion of wind matched with umbrella ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Umbrella Fall
Initial prompt
Design a simple 2D mobile game called **“Umbrella Fall”**. Concept: - The player controls a character gently descending from the sky with an open umbrella. - The goal is to avoid obstacles and reach a soft landing. - The game ends if the player hits a hazard or veers off screen. Gameplay Features: - The character constantly falls downward. - The player can swipe or tilt left/right to steer the descent. - Wind currents occasionally push the character off balance. - Obstacles: birds flying across, lightning bolts, and floating air pockets (they destabilize the umbrella). - Bonus items: falling stars or wind chimes can be collected for extra score. Visual Style: - Sky-themed aesthetic: soft clouds, sunset gradients, falling petals. - Umbrella can have unlockable colors or patterns (optional). - Soothing ambient sound or rain sound can enhance mood. Controls: - Swipe left/right or use accelerometer (device tilt) - No jump or action buttons needed. Requirements: - Simple, responsive controls for mobile - Gentle pacing with increasing difficulty over time - One-touch or tilt-only gameplay - Minimal, relaxing visual design
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AirPocket = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('airPocket', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.alpha = 0.3;
self.fallSpeed = 0; // For falling direction
self.update = function () {
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
graphics.alpha = 0.3 + Math.sin(LK.ticks * 0.1) * 0.2;
};
return self;
});
var Bird = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 5 + 3;
self.direction = Math.random() > 0.5 ? 1 : -1;
self.speedY = 0; // For falling direction
// Birds spawn from left or right edge and move in parallel lines
self.x = self.direction > 0 ? -100 : 2148; // Start from left or right edge
self.update = function () {
self.x += self.speed * self.direction;
if (self.speedY > 0) {
self.y += self.speedY; // Support falling movement
}
graphics.rotation += 0.1;
// Slight vertical bobbing
graphics.y = Math.sin(LK.ticks * 0.08) * 15;
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.alpha = 0.6;
self.speed = Math.random() * 0.5 + 0.2;
self.fallSpeed = 0; // For falling direction support
self.update = function () {
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
// Clouds are now stationary horizontally - no horizontal movement
};
return self;
});
var Collectible = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var graphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.type === 'star') {
graphics.rotation += 0.15;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.3;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.3;
} else if (self.type === 'windChime') {
graphics.x = Math.sin(LK.ticks * 0.08) * 10;
}
};
return self;
});
var LifePowerUp = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
graphics.rotation += 0.1;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.12) * 0.2;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.12) * 0.2;
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 3 + 2;
// Lightning flicker effect
tween(graphics, {
alpha: 0.3
}, {
duration: 100,
easing: tween.easeInOut
});
LK.setTimeout(function () {
tween(graphics, {
alpha: 1
}, {
duration: 50
});
}, 100);
self.update = function () {
self.y += self.speed;
// Lightning sway
graphics.x = Math.sin(LK.ticks * 0.12) * 10;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var umbrella = self.attachAsset('umbrella', {
anchorX: 0.5,
anchorY: 0.5,
y: -60
});
var character = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5,
y: 20
});
self.fallSpeed = 3;
self.horizontalSpeed = 0;
self.windEffect = 0;
self.maxHorizontalSpeed = 8;
self.update = function () {
self.y += self.fallSpeed;
// Apply horizontal movement with wind effect
self.x += self.horizontalSpeed + self.windEffect;
// Enhanced umbrella wind animation with smooth transitions
var baseRotation = Math.sin(LK.ticks * 0.05) * 0.1;
var windRotation = self.windEffect * 0.02;
var horizontalRotation = self.horizontalSpeed * 0.05;
var targetRotation = baseRotation + windRotation + horizontalRotation;
// Smooth umbrella rotation transition
if (Math.abs(umbrella.rotation - targetRotation) > 0.01) {
tween(umbrella, {
rotation: targetRotation
}, {
duration: 200,
easing: tween.easeOut
});
}
// Wind-affected umbrella bobbing with smooth motion
var targetUmbrellaY = -60 + Math.sin(LK.ticks * 0.08) * 3 + Math.abs(self.windEffect) * 0.5;
if (Math.abs(umbrella.y - targetUmbrellaY) > 1) {
tween(umbrella, {
y: targetUmbrellaY
}, {
duration: 150,
easing: tween.easeOut
});
}
// Enhanced character body physics with wind-responsive motion
var windResistance = Math.abs(self.windEffect) * 0.4;
var umbrellaInfluence = Math.abs(umbrella.rotation) * 2;
var horizontalInfluence = Math.abs(self.horizontalSpeed) * 0.3;
// Body tilting based on combined forces
var targetCharacterRotation = umbrella.rotation * 0.5 + self.windEffect * 0.03 + self.horizontalSpeed * 0.02;
var targetCharacterX = Math.sin(LK.ticks * 0.06) * 2 + self.windEffect * 0.15 + Math.sin(LK.ticks * 0.08) * windResistance;
var targetCharacterY = 20 + Math.sin(LK.ticks * 0.04) * 1.5 + windResistance * 0.8 + umbrellaInfluence * 0.3;
// Wind-affected body leaning with umbrella compensation
if (Math.abs(character.rotation - targetCharacterRotation) > 0.005) {
tween(character, {
rotation: targetCharacterRotation
}, {
duration: 200,
easing: tween.easeInOut
});
}
// Enhanced horizontal body sway with wind resistance
if (Math.abs(character.x - targetCharacterX) > 0.5) {
tween(character, {
x: targetCharacterX
}, {
duration: 180,
easing: tween.easeOut
});
}
// Vertical body motion affected by umbrella physics
if (Math.abs(character.y - targetCharacterY) > 0.8) {
tween(character, {
y: targetCharacterY
}, {
duration: 160,
easing: tween.easeInOut
});
}
// Body deformation from wind pressure and umbrella strain
var targetScaleX = 1 + Math.sin(LK.ticks * 0.03) * 0.02 + windResistance * 0.03 + Math.sin(LK.ticks * 0.1) * horizontalInfluence * 0.02;
var targetScaleY = 1 - windResistance * 0.02 + Math.sin(LK.ticks * 0.05) * 0.015 + umbrellaInfluence * 0.015;
if (Math.abs(character.scaleX - targetScaleX) > 0.01 || Math.abs(character.scaleY - targetScaleY) > 0.01) {
tween(character, {
scaleX: targetScaleX,
scaleY: targetScaleY
}, {
duration: 300,
easing: tween.easeInOut
});
}
// Additional body trembling effect during strong wind
if (Math.abs(self.windEffect) > 3) {
var trembleX = (Math.random() - 0.5) * 2;
var trembleY = (Math.random() - 0.5) * 1.5;
tween(character, {
x: character.x + trembleX,
y: character.y + trembleY
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(character, {
x: targetCharacterX,
y: targetCharacterY
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
// Keep player on screen horizontally with smooth boundary correction
if (self.x < 70) {
tween(self, {
x: 70
}, {
duration: 200,
easing: tween.easeOut
});
self.horizontalSpeed = 0;
}
if (self.x > 2048 - 70) {
tween(self, {
x: 2048 - 70
}, {
duration: 200,
easing: tween.easeOut
});
self.horizontalSpeed = 0;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xff6666;
// Stars spawn diagonally - choose random diagonal direction
var diagonalDirection = Math.random() > 0.5 ? 1 : -1;
self.speedX = diagonalDirection * (Math.random() * 2 + 2);
self.speedY = Math.random() * 2 + 3; // Moves downward in game flow
// Set starting position based on diagonal direction
if (diagonalDirection > 0) {
self.x = -50; // Start from left edge
} else {
self.x = 2098; // Start from right edge
}
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
graphics.rotation += 0.2;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.15) * 0.3;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.15) * 0.3;
};
return self;
});
var WindChime = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('windChime', {
anchorX: 0.5,
anchorY: 0.5
});
self.visible = true;
self.flickerTimer = 0;
self.fallSpeed = 0; // For falling direction
// Wind chimes spawn anywhere on screen and suddenly appear/disappear
self.x = Math.random() * (2048 - 100) + 50;
self.update = function () {
self.flickerTimer++;
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
// Sudden appear/disappear effect every second
if (self.flickerTimer % 60 === 0) {
self.visible = !self.visible;
graphics.alpha = self.visible ? 1 : 0;
}
// Gentle swaying when visible
if (self.visible) {
graphics.x = Math.sin(LK.ticks * 0.08) * 8;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Gradient sky effect
game.setBackgroundColor(0x87ceeb);
// Game variables
var player;
var obstacles = [];
var collectibles = [];
var clouds = [];
var lifePowerUps = [];
var windTimer = 0;
var spawnTimer = 0;
var difficultyTimer = 0;
var distanceFallen = 0;
var gameSpeed = 1;
var cameraY = 0;
var targetCameraY = 0;
var playerLives = 3;
var maxLives = 5;
// UI Elements
var distanceTxt = new Text2('Distance: 0m', {
size: 70,
fill: 0xF0F8FF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
distanceTxt.anchor.set(0.5, 0);
distanceTxt.y = 0;
LK.gui.top.addChild(distanceTxt);
// Lives display
var livesContainer = new Container();
var lifeHearts = [];
for (var h = 0; h < maxLives; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = h * 60 - 120;
heart.y = 0;
heart.scaleX = 1.2;
heart.scaleY = 1.5;
livesContainer.addChild(heart);
lifeHearts.push(heart);
}
livesContainer.y = 120;
LK.gui.top.addChild(livesContainer);
// Update lives display function
function updateLivesDisplay() {
for (var i = 0; i < lifeHearts.length; i++) {
if (i < playerLives) {
lifeHearts[i].alpha = 1;
} else {
lifeHearts[i].alpha = 0.3;
}
}
}
updateLivesDisplay();
// Initialize player
player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 600;
// Create initial clouds
for (var i = 0; i < 8; i++) {
var cloud = game.addChild(new Cloud());
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 2732;
clouds.push(cloud);
}
// Touch controls
var isDragging = false;
var lastTouchX = 0;
game.down = function (x, y, obj) {
isDragging = true;
lastTouchX = x;
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = x - lastTouchX;
player.horizontalSpeed = Math.max(-player.maxHorizontalSpeed, Math.min(player.maxHorizontalSpeed, deltaX * 0.3));
lastTouchX = x;
}
};
game.up = function (x, y, obj) {
isDragging = false;
// Gradually reduce horizontal speed when not dragging
tween(player, {
horizontalSpeed: 0
}, {
duration: 500,
easing: tween.easeOut
});
};
// Main game loop
game.update = function () {
// Update distance fallen
distanceFallen += player.fallSpeed;
distanceTxt.setText('Distance: ' + Math.floor(distanceFallen / 10) + 'm');
// Camera tracking - follow player with smooth movement
targetCameraY = player.y - 1366; // Keep player in center vertically
var cameraDiff = targetCameraY - cameraY;
cameraY += cameraDiff * 0.08; // Smooth camera movement
game.y = -cameraY;
// Progressive difficulty every 100 meters, easier first 500 meters
var currentDistance = Math.floor(distanceFallen / 10);
var difficultyLevel = Math.floor(currentDistance / 100);
if (currentDistance >= 500) {
// After 500m, increase difficulty more rapidly
gameSpeed = 1 + (difficultyLevel - 5) * 0.2;
player.fallSpeed = Math.min(8, 3 + (difficultyLevel - 5) * 0.3);
} else if (currentDistance >= 100) {
// First 500m: gentle difficulty increase
gameSpeed = 1 + difficultyLevel * 0.05;
player.fallSpeed = Math.min(5, 3 + difficultyLevel * 0.1);
}
// Enhanced wind effect that actively guides the player
windTimer++;
if (windTimer % 150 === 0) {
// Every 2.5 seconds - more frequent wind
var windStrength = (Math.random() - 0.5) * 8 * gameSpeed; // Stronger wind
// Visual wind burst effect on umbrella
var umbrella = player.children[0]; // Get umbrella reference
tween(umbrella, {
scaleX: 1.3 + Math.abs(windStrength) * 0.15,
scaleY: 0.8 - Math.abs(windStrength) * 0.1,
rotation: umbrella.rotation + windStrength * 0.1
}, {
duration: 150,
easing: tween.easeOut
});
// Return umbrella to normal size
LK.setTimeout(function () {
tween(umbrella, {
scaleX: 1,
scaleY: 1
}, {
duration: 600,
easing: tween.easeOut
});
}, 150);
tween(player, {
windEffect: windStrength
}, {
duration: 150
});
LK.setTimeout(function () {
tween(player, {
windEffect: windStrength * 0.3
}, {
duration: 800,
easing: tween.easeOut
});
}, 600);
// Complete wind fade after longer period
LK.setTimeout(function () {
tween(player, {
windEffect: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 1400);
}
// Continuous cloud spawning - spawn clouds regularly as primary obstacles
spawnTimer++;
var baseSpawnRate = currentDistance < 500 ? 80 : 60; // Much slower spawn for better escape routes
var cloudSpawnRate = Math.max(25, baseSpawnRate - Math.floor(difficultyLevel * 2));
if (spawnTimer % cloudSpawnRate === 0) {
// Calculate spawn position relative to player's current position
var spawnX = Math.random() * (2048 - 200) + 100;
var spawnY;
// 50% chance to spawn from above or below the player
if (Math.random() < 0.5) {
spawnY = player.y - 800 - Math.random() * 400; // Spawn above player
} else {
spawnY = player.y + 800 + Math.random() * 400; // Spawn below player
}
var cloud = game.addChild(new Cloud());
cloud.x = spawnX;
cloud.y = spawnY;
// Support falling direction for clouds
if (Math.random() < 0.3) {
cloud.fallSpeed = Math.random() * 1 + 0.5;
}
obstacles.push(cloud);
}
// Separate life power-up spawning (increased spawn rate)
if (Math.random() < 0.005 * gameSpeed) {
var lifePowerUp = game.addChild(new LifePowerUp());
lifePowerUp.x = Math.random() * (2048 - 200) + 100;
lifePowerUp.y = player.y - Math.random() * 500 - 400;
lifePowerUps.push(lifePowerUp);
}
// Separate collectible spawning (moderate frequency)
if (Math.random() < 0.002 * gameSpeed) {
var collectible = game.addChild(new Collectible('windChime'));
collectible.x = Math.random() * (2048 - 200) + 100;
collectible.y = player.y - Math.random() * 500 - 400;
collectibles.push(collectible);
}
// Independent bird spawning (moderate frequency, parallel lines from screen edges and falling direction)
var birdSpawnChance = currentDistance < 500 ? 0.001 * gameSpeed : 0.003 * gameSpeed;
if (Math.random() < birdSpawnChance) {
var bird = game.addChild(new Bird());
// 50% chance to spawn from above (falling direction) or from edges
if (Math.random() < 0.5) {
bird.x = Math.random() * 2048;
bird.y = player.y - Math.random() * 600 - 400;
bird.speedY = Math.random() * 2 + 1;
} else {
bird.y = player.y - Math.random() * 600 - 200;
}
obstacles.push(bird);
}
// Independent star spawning (moderate frequency, diagonal movement and falling direction)
var starSpawnChance = currentDistance < 500 ? 0.0008 * gameSpeed : 0.0025 * gameSpeed;
if (Math.random() < starSpawnChance) {
var star = game.addChild(new Star());
// 50% chance to spawn from above (falling direction) or diagonally
if (Math.random() < 0.5) {
star.x = Math.random() * 2048;
star.y = player.y - Math.random() * 500 - 400;
star.speedX = (Math.random() - 0.5) * 4;
star.speedY = Math.random() * 2 + 2;
} else {
star.y = player.y - Math.random() * 500 - 300;
}
obstacles.push(star);
}
// Independent lightning spawning (moderate frequency, vertical path from above)
var lightningSpawnChance = currentDistance < 500 ? 0.0005 * gameSpeed : 0.002 * gameSpeed;
if (Math.random() < lightningSpawnChance) {
var lightning = game.addChild(new Lightning());
lightning.x = Math.random() * (2048 - 100) + 50;
lightning.y = player.y - Math.random() * 700 - 400;
obstacles.push(lightning);
}
// Independent wind chime spawning (low frequency, appear/disappear anywhere and falling)
var windChimeSpawnChance = currentDistance < 500 ? 0.0005 * gameSpeed : 0.0015 * gameSpeed;
if (Math.random() < windChimeSpawnChance) {
var windChime = game.addChild(new WindChime());
// 50% chance to spawn from above (falling direction) or statically
if (Math.random() < 0.5) {
windChime.x = Math.random() * 2048;
windChime.y = player.y - Math.random() * 600 - 400;
windChime.fallSpeed = Math.random() * 1.5 + 0.5;
} else {
windChime.y = player.y - Math.random() * 600 - 200;
}
obstacles.push(windChime);
}
// Independent air pocket spawning (low frequency, spawn anywhere and falling direction)
var airPocketSpawnChance = currentDistance < 500 ? 0.0003 * gameSpeed : 0.0012 * gameSpeed;
if (Math.random() < airPocketSpawnChance) {
var airPocket = game.addChild(new AirPocket());
airPocket.x = Math.random() * (2048 - 200) + 100;
// 50% chance to spawn from above (falling direction) or statically
if (Math.random() < 0.5) {
airPocket.y = player.y - Math.random() * 500 - 400;
airPocket.fallSpeed = Math.random() * 1 + 0.3;
} else {
airPocket.y = player.y - Math.random() * 500 - 300;
}
obstacles.push(airPocket);
}
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.lastY === undefined) obstacle.lastY = obstacle.y;
if (obstacle.lastIntersecting === undefined) obstacle.lastIntersecting = false;
// Remove obstacles that are too far behind the player
if (obstacle.lastY < player.y + 1000 && obstacle.y >= player.y + 1000) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = obstacle.intersects(player);
if (!obstacle.lastIntersecting && currentIntersecting) {
// Only lose hearts after first 50 meters
if (currentDistance >= 50) {
playerLives--;
updateLivesDisplay();
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 500);
// Check if game over
if (playerLives <= 0) {
LK.showGameOver();
return;
}
} else {
// Flash screen but no heart loss for first 50 meters
LK.effects.flashScreen(0xffff00, 300);
}
// Remove the obstacle that was hit
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
obstacle.lastY = obstacle.y;
obstacle.lastIntersecting = currentIntersecting;
}
// Update and check collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
var collectible = collectibles[j];
if (collectible.lastY === undefined) collectible.lastY = collectible.y;
if (collectible.lastIntersecting === undefined) collectible.lastIntersecting = false;
// Remove collectibles that are too far behind the player
if (collectible.lastY < player.y + 1000 && collectible.y >= player.y + 1000) {
collectible.destroy();
collectibles.splice(j, 1);
continue;
}
// Check collection
var currentIntersecting = collectible.intersects(player);
if (!collectible.lastIntersecting && currentIntersecting) {
LK.getSound('collect').play();
// Visual effect
tween(collectible, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
collectible.destroy();
}
});
collectibles.splice(j, 1);
continue;
}
collectible.lastY = collectible.y;
collectible.lastIntersecting = currentIntersecting;
}
// Update and check life power-ups
for (var l = lifePowerUps.length - 1; l >= 0; l--) {
var lifePowerUp = lifePowerUps[l];
if (lifePowerUp.lastY === undefined) lifePowerUp.lastY = lifePowerUp.y;
if (lifePowerUp.lastIntersecting === undefined) lifePowerUp.lastIntersecting = false;
// Remove life power-ups that are too far behind the player
if (lifePowerUp.lastY < player.y + 1000 && lifePowerUp.y >= player.y + 1000) {
lifePowerUp.destroy();
lifePowerUps.splice(l, 1);
continue;
}
// Check collection
var currentIntersecting = lifePowerUp.intersects(player);
if (!lifePowerUp.lastIntersecting && currentIntersecting) {
if (playerLives < maxLives) {
playerLives++;
updateLivesDisplay();
LK.getSound('collect').play();
// Visual effect
tween(lifePowerUp, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
lifePowerUp.destroy();
}
});
lifePowerUps.splice(l, 1);
continue;
}
}
lifePowerUp.lastY = lifePowerUp.y;
lifePowerUp.lastIntersecting = currentIntersecting;
}
// Check collision with clouds
for (var k = 0; k < clouds.length; k++) {
var cloud = clouds[k];
if (cloud.lastIntersecting === undefined) cloud.lastIntersecting = false;
var currentIntersecting = cloud.intersects(player);
if (!cloud.lastIntersecting && currentIntersecting) {
// Only lose hearts after first 50 meters
if (currentDistance >= 50) {
playerLives--;
updateLivesDisplay();
LK.getSound('hit').play();
LK.effects.flashScreen(0xffffff, 500);
// Check if game over
if (playerLives <= 0) {
LK.showGameOver();
return;
}
} else {
// Flash screen but no heart loss for first 50 meters
LK.effects.flashScreen(0xffff88, 300);
}
}
cloud.lastIntersecting = currentIntersecting;
}
// Remove game over condition for falling off screen - infinite fall game
// Game only ends when hitting obstacles or clouds
};
// Start ambient music
LK.playMusic('ambient'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AirPocket = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('airPocket', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.alpha = 0.3;
self.fallSpeed = 0; // For falling direction
self.update = function () {
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
graphics.alpha = 0.3 + Math.sin(LK.ticks * 0.1) * 0.2;
};
return self;
});
var Bird = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 5 + 3;
self.direction = Math.random() > 0.5 ? 1 : -1;
self.speedY = 0; // For falling direction
// Birds spawn from left or right edge and move in parallel lines
self.x = self.direction > 0 ? -100 : 2148; // Start from left or right edge
self.update = function () {
self.x += self.speed * self.direction;
if (self.speedY > 0) {
self.y += self.speedY; // Support falling movement
}
graphics.rotation += 0.1;
// Slight vertical bobbing
graphics.y = Math.sin(LK.ticks * 0.08) * 15;
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.alpha = 0.6;
self.speed = Math.random() * 0.5 + 0.2;
self.fallSpeed = 0; // For falling direction support
self.update = function () {
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
// Clouds are now stationary horizontally - no horizontal movement
};
return self;
});
var Collectible = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var graphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.type === 'star') {
graphics.rotation += 0.15;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.3;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.3;
} else if (self.type === 'windChime') {
graphics.x = Math.sin(LK.ticks * 0.08) * 10;
}
};
return self;
});
var LifePowerUp = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
graphics.rotation += 0.1;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.12) * 0.2;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.12) * 0.2;
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 3 + 2;
// Lightning flicker effect
tween(graphics, {
alpha: 0.3
}, {
duration: 100,
easing: tween.easeInOut
});
LK.setTimeout(function () {
tween(graphics, {
alpha: 1
}, {
duration: 50
});
}, 100);
self.update = function () {
self.y += self.speed;
// Lightning sway
graphics.x = Math.sin(LK.ticks * 0.12) * 10;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var umbrella = self.attachAsset('umbrella', {
anchorX: 0.5,
anchorY: 0.5,
y: -60
});
var character = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5,
y: 20
});
self.fallSpeed = 3;
self.horizontalSpeed = 0;
self.windEffect = 0;
self.maxHorizontalSpeed = 8;
self.update = function () {
self.y += self.fallSpeed;
// Apply horizontal movement with wind effect
self.x += self.horizontalSpeed + self.windEffect;
// Enhanced umbrella wind animation with smooth transitions
var baseRotation = Math.sin(LK.ticks * 0.05) * 0.1;
var windRotation = self.windEffect * 0.02;
var horizontalRotation = self.horizontalSpeed * 0.05;
var targetRotation = baseRotation + windRotation + horizontalRotation;
// Smooth umbrella rotation transition
if (Math.abs(umbrella.rotation - targetRotation) > 0.01) {
tween(umbrella, {
rotation: targetRotation
}, {
duration: 200,
easing: tween.easeOut
});
}
// Wind-affected umbrella bobbing with smooth motion
var targetUmbrellaY = -60 + Math.sin(LK.ticks * 0.08) * 3 + Math.abs(self.windEffect) * 0.5;
if (Math.abs(umbrella.y - targetUmbrellaY) > 1) {
tween(umbrella, {
y: targetUmbrellaY
}, {
duration: 150,
easing: tween.easeOut
});
}
// Enhanced character body physics with wind-responsive motion
var windResistance = Math.abs(self.windEffect) * 0.4;
var umbrellaInfluence = Math.abs(umbrella.rotation) * 2;
var horizontalInfluence = Math.abs(self.horizontalSpeed) * 0.3;
// Body tilting based on combined forces
var targetCharacterRotation = umbrella.rotation * 0.5 + self.windEffect * 0.03 + self.horizontalSpeed * 0.02;
var targetCharacterX = Math.sin(LK.ticks * 0.06) * 2 + self.windEffect * 0.15 + Math.sin(LK.ticks * 0.08) * windResistance;
var targetCharacterY = 20 + Math.sin(LK.ticks * 0.04) * 1.5 + windResistance * 0.8 + umbrellaInfluence * 0.3;
// Wind-affected body leaning with umbrella compensation
if (Math.abs(character.rotation - targetCharacterRotation) > 0.005) {
tween(character, {
rotation: targetCharacterRotation
}, {
duration: 200,
easing: tween.easeInOut
});
}
// Enhanced horizontal body sway with wind resistance
if (Math.abs(character.x - targetCharacterX) > 0.5) {
tween(character, {
x: targetCharacterX
}, {
duration: 180,
easing: tween.easeOut
});
}
// Vertical body motion affected by umbrella physics
if (Math.abs(character.y - targetCharacterY) > 0.8) {
tween(character, {
y: targetCharacterY
}, {
duration: 160,
easing: tween.easeInOut
});
}
// Body deformation from wind pressure and umbrella strain
var targetScaleX = 1 + Math.sin(LK.ticks * 0.03) * 0.02 + windResistance * 0.03 + Math.sin(LK.ticks * 0.1) * horizontalInfluence * 0.02;
var targetScaleY = 1 - windResistance * 0.02 + Math.sin(LK.ticks * 0.05) * 0.015 + umbrellaInfluence * 0.015;
if (Math.abs(character.scaleX - targetScaleX) > 0.01 || Math.abs(character.scaleY - targetScaleY) > 0.01) {
tween(character, {
scaleX: targetScaleX,
scaleY: targetScaleY
}, {
duration: 300,
easing: tween.easeInOut
});
}
// Additional body trembling effect during strong wind
if (Math.abs(self.windEffect) > 3) {
var trembleX = (Math.random() - 0.5) * 2;
var trembleY = (Math.random() - 0.5) * 1.5;
tween(character, {
x: character.x + trembleX,
y: character.y + trembleY
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(character, {
x: targetCharacterX,
y: targetCharacterY
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
// Keep player on screen horizontally with smooth boundary correction
if (self.x < 70) {
tween(self, {
x: 70
}, {
duration: 200,
easing: tween.easeOut
});
self.horizontalSpeed = 0;
}
if (self.x > 2048 - 70) {
tween(self, {
x: 2048 - 70
}, {
duration: 200,
easing: tween.easeOut
});
self.horizontalSpeed = 0;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xff6666;
// Stars spawn diagonally - choose random diagonal direction
var diagonalDirection = Math.random() > 0.5 ? 1 : -1;
self.speedX = diagonalDirection * (Math.random() * 2 + 2);
self.speedY = Math.random() * 2 + 3; // Moves downward in game flow
// Set starting position based on diagonal direction
if (diagonalDirection > 0) {
self.x = -50; // Start from left edge
} else {
self.x = 2098; // Start from right edge
}
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
graphics.rotation += 0.2;
graphics.scaleX = 1 + Math.sin(LK.ticks * 0.15) * 0.3;
graphics.scaleY = 1 + Math.sin(LK.ticks * 0.15) * 0.3;
};
return self;
});
var WindChime = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('windChime', {
anchorX: 0.5,
anchorY: 0.5
});
self.visible = true;
self.flickerTimer = 0;
self.fallSpeed = 0; // For falling direction
// Wind chimes spawn anywhere on screen and suddenly appear/disappear
self.x = Math.random() * (2048 - 100) + 50;
self.update = function () {
self.flickerTimer++;
// Support falling movement
if (self.fallSpeed > 0) {
self.y += self.fallSpeed;
}
// Sudden appear/disappear effect every second
if (self.flickerTimer % 60 === 0) {
self.visible = !self.visible;
graphics.alpha = self.visible ? 1 : 0;
}
// Gentle swaying when visible
if (self.visible) {
graphics.x = Math.sin(LK.ticks * 0.08) * 8;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Gradient sky effect
game.setBackgroundColor(0x87ceeb);
// Game variables
var player;
var obstacles = [];
var collectibles = [];
var clouds = [];
var lifePowerUps = [];
var windTimer = 0;
var spawnTimer = 0;
var difficultyTimer = 0;
var distanceFallen = 0;
var gameSpeed = 1;
var cameraY = 0;
var targetCameraY = 0;
var playerLives = 3;
var maxLives = 5;
// UI Elements
var distanceTxt = new Text2('Distance: 0m', {
size: 70,
fill: 0xF0F8FF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
distanceTxt.anchor.set(0.5, 0);
distanceTxt.y = 0;
LK.gui.top.addChild(distanceTxt);
// Lives display
var livesContainer = new Container();
var lifeHearts = [];
for (var h = 0; h < maxLives; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = h * 60 - 120;
heart.y = 0;
heart.scaleX = 1.2;
heart.scaleY = 1.5;
livesContainer.addChild(heart);
lifeHearts.push(heart);
}
livesContainer.y = 120;
LK.gui.top.addChild(livesContainer);
// Update lives display function
function updateLivesDisplay() {
for (var i = 0; i < lifeHearts.length; i++) {
if (i < playerLives) {
lifeHearts[i].alpha = 1;
} else {
lifeHearts[i].alpha = 0.3;
}
}
}
updateLivesDisplay();
// Initialize player
player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 600;
// Create initial clouds
for (var i = 0; i < 8; i++) {
var cloud = game.addChild(new Cloud());
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 2732;
clouds.push(cloud);
}
// Touch controls
var isDragging = false;
var lastTouchX = 0;
game.down = function (x, y, obj) {
isDragging = true;
lastTouchX = x;
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = x - lastTouchX;
player.horizontalSpeed = Math.max(-player.maxHorizontalSpeed, Math.min(player.maxHorizontalSpeed, deltaX * 0.3));
lastTouchX = x;
}
};
game.up = function (x, y, obj) {
isDragging = false;
// Gradually reduce horizontal speed when not dragging
tween(player, {
horizontalSpeed: 0
}, {
duration: 500,
easing: tween.easeOut
});
};
// Main game loop
game.update = function () {
// Update distance fallen
distanceFallen += player.fallSpeed;
distanceTxt.setText('Distance: ' + Math.floor(distanceFallen / 10) + 'm');
// Camera tracking - follow player with smooth movement
targetCameraY = player.y - 1366; // Keep player in center vertically
var cameraDiff = targetCameraY - cameraY;
cameraY += cameraDiff * 0.08; // Smooth camera movement
game.y = -cameraY;
// Progressive difficulty every 100 meters, easier first 500 meters
var currentDistance = Math.floor(distanceFallen / 10);
var difficultyLevel = Math.floor(currentDistance / 100);
if (currentDistance >= 500) {
// After 500m, increase difficulty more rapidly
gameSpeed = 1 + (difficultyLevel - 5) * 0.2;
player.fallSpeed = Math.min(8, 3 + (difficultyLevel - 5) * 0.3);
} else if (currentDistance >= 100) {
// First 500m: gentle difficulty increase
gameSpeed = 1 + difficultyLevel * 0.05;
player.fallSpeed = Math.min(5, 3 + difficultyLevel * 0.1);
}
// Enhanced wind effect that actively guides the player
windTimer++;
if (windTimer % 150 === 0) {
// Every 2.5 seconds - more frequent wind
var windStrength = (Math.random() - 0.5) * 8 * gameSpeed; // Stronger wind
// Visual wind burst effect on umbrella
var umbrella = player.children[0]; // Get umbrella reference
tween(umbrella, {
scaleX: 1.3 + Math.abs(windStrength) * 0.15,
scaleY: 0.8 - Math.abs(windStrength) * 0.1,
rotation: umbrella.rotation + windStrength * 0.1
}, {
duration: 150,
easing: tween.easeOut
});
// Return umbrella to normal size
LK.setTimeout(function () {
tween(umbrella, {
scaleX: 1,
scaleY: 1
}, {
duration: 600,
easing: tween.easeOut
});
}, 150);
tween(player, {
windEffect: windStrength
}, {
duration: 150
});
LK.setTimeout(function () {
tween(player, {
windEffect: windStrength * 0.3
}, {
duration: 800,
easing: tween.easeOut
});
}, 600);
// Complete wind fade after longer period
LK.setTimeout(function () {
tween(player, {
windEffect: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 1400);
}
// Continuous cloud spawning - spawn clouds regularly as primary obstacles
spawnTimer++;
var baseSpawnRate = currentDistance < 500 ? 80 : 60; // Much slower spawn for better escape routes
var cloudSpawnRate = Math.max(25, baseSpawnRate - Math.floor(difficultyLevel * 2));
if (spawnTimer % cloudSpawnRate === 0) {
// Calculate spawn position relative to player's current position
var spawnX = Math.random() * (2048 - 200) + 100;
var spawnY;
// 50% chance to spawn from above or below the player
if (Math.random() < 0.5) {
spawnY = player.y - 800 - Math.random() * 400; // Spawn above player
} else {
spawnY = player.y + 800 + Math.random() * 400; // Spawn below player
}
var cloud = game.addChild(new Cloud());
cloud.x = spawnX;
cloud.y = spawnY;
// Support falling direction for clouds
if (Math.random() < 0.3) {
cloud.fallSpeed = Math.random() * 1 + 0.5;
}
obstacles.push(cloud);
}
// Separate life power-up spawning (increased spawn rate)
if (Math.random() < 0.005 * gameSpeed) {
var lifePowerUp = game.addChild(new LifePowerUp());
lifePowerUp.x = Math.random() * (2048 - 200) + 100;
lifePowerUp.y = player.y - Math.random() * 500 - 400;
lifePowerUps.push(lifePowerUp);
}
// Separate collectible spawning (moderate frequency)
if (Math.random() < 0.002 * gameSpeed) {
var collectible = game.addChild(new Collectible('windChime'));
collectible.x = Math.random() * (2048 - 200) + 100;
collectible.y = player.y - Math.random() * 500 - 400;
collectibles.push(collectible);
}
// Independent bird spawning (moderate frequency, parallel lines from screen edges and falling direction)
var birdSpawnChance = currentDistance < 500 ? 0.001 * gameSpeed : 0.003 * gameSpeed;
if (Math.random() < birdSpawnChance) {
var bird = game.addChild(new Bird());
// 50% chance to spawn from above (falling direction) or from edges
if (Math.random() < 0.5) {
bird.x = Math.random() * 2048;
bird.y = player.y - Math.random() * 600 - 400;
bird.speedY = Math.random() * 2 + 1;
} else {
bird.y = player.y - Math.random() * 600 - 200;
}
obstacles.push(bird);
}
// Independent star spawning (moderate frequency, diagonal movement and falling direction)
var starSpawnChance = currentDistance < 500 ? 0.0008 * gameSpeed : 0.0025 * gameSpeed;
if (Math.random() < starSpawnChance) {
var star = game.addChild(new Star());
// 50% chance to spawn from above (falling direction) or diagonally
if (Math.random() < 0.5) {
star.x = Math.random() * 2048;
star.y = player.y - Math.random() * 500 - 400;
star.speedX = (Math.random() - 0.5) * 4;
star.speedY = Math.random() * 2 + 2;
} else {
star.y = player.y - Math.random() * 500 - 300;
}
obstacles.push(star);
}
// Independent lightning spawning (moderate frequency, vertical path from above)
var lightningSpawnChance = currentDistance < 500 ? 0.0005 * gameSpeed : 0.002 * gameSpeed;
if (Math.random() < lightningSpawnChance) {
var lightning = game.addChild(new Lightning());
lightning.x = Math.random() * (2048 - 100) + 50;
lightning.y = player.y - Math.random() * 700 - 400;
obstacles.push(lightning);
}
// Independent wind chime spawning (low frequency, appear/disappear anywhere and falling)
var windChimeSpawnChance = currentDistance < 500 ? 0.0005 * gameSpeed : 0.0015 * gameSpeed;
if (Math.random() < windChimeSpawnChance) {
var windChime = game.addChild(new WindChime());
// 50% chance to spawn from above (falling direction) or statically
if (Math.random() < 0.5) {
windChime.x = Math.random() * 2048;
windChime.y = player.y - Math.random() * 600 - 400;
windChime.fallSpeed = Math.random() * 1.5 + 0.5;
} else {
windChime.y = player.y - Math.random() * 600 - 200;
}
obstacles.push(windChime);
}
// Independent air pocket spawning (low frequency, spawn anywhere and falling direction)
var airPocketSpawnChance = currentDistance < 500 ? 0.0003 * gameSpeed : 0.0012 * gameSpeed;
if (Math.random() < airPocketSpawnChance) {
var airPocket = game.addChild(new AirPocket());
airPocket.x = Math.random() * (2048 - 200) + 100;
// 50% chance to spawn from above (falling direction) or statically
if (Math.random() < 0.5) {
airPocket.y = player.y - Math.random() * 500 - 400;
airPocket.fallSpeed = Math.random() * 1 + 0.3;
} else {
airPocket.y = player.y - Math.random() * 500 - 300;
}
obstacles.push(airPocket);
}
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.lastY === undefined) obstacle.lastY = obstacle.y;
if (obstacle.lastIntersecting === undefined) obstacle.lastIntersecting = false;
// Remove obstacles that are too far behind the player
if (obstacle.lastY < player.y + 1000 && obstacle.y >= player.y + 1000) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = obstacle.intersects(player);
if (!obstacle.lastIntersecting && currentIntersecting) {
// Only lose hearts after first 50 meters
if (currentDistance >= 50) {
playerLives--;
updateLivesDisplay();
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 500);
// Check if game over
if (playerLives <= 0) {
LK.showGameOver();
return;
}
} else {
// Flash screen but no heart loss for first 50 meters
LK.effects.flashScreen(0xffff00, 300);
}
// Remove the obstacle that was hit
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
obstacle.lastY = obstacle.y;
obstacle.lastIntersecting = currentIntersecting;
}
// Update and check collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
var collectible = collectibles[j];
if (collectible.lastY === undefined) collectible.lastY = collectible.y;
if (collectible.lastIntersecting === undefined) collectible.lastIntersecting = false;
// Remove collectibles that are too far behind the player
if (collectible.lastY < player.y + 1000 && collectible.y >= player.y + 1000) {
collectible.destroy();
collectibles.splice(j, 1);
continue;
}
// Check collection
var currentIntersecting = collectible.intersects(player);
if (!collectible.lastIntersecting && currentIntersecting) {
LK.getSound('collect').play();
// Visual effect
tween(collectible, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
collectible.destroy();
}
});
collectibles.splice(j, 1);
continue;
}
collectible.lastY = collectible.y;
collectible.lastIntersecting = currentIntersecting;
}
// Update and check life power-ups
for (var l = lifePowerUps.length - 1; l >= 0; l--) {
var lifePowerUp = lifePowerUps[l];
if (lifePowerUp.lastY === undefined) lifePowerUp.lastY = lifePowerUp.y;
if (lifePowerUp.lastIntersecting === undefined) lifePowerUp.lastIntersecting = false;
// Remove life power-ups that are too far behind the player
if (lifePowerUp.lastY < player.y + 1000 && lifePowerUp.y >= player.y + 1000) {
lifePowerUp.destroy();
lifePowerUps.splice(l, 1);
continue;
}
// Check collection
var currentIntersecting = lifePowerUp.intersects(player);
if (!lifePowerUp.lastIntersecting && currentIntersecting) {
if (playerLives < maxLives) {
playerLives++;
updateLivesDisplay();
LK.getSound('collect').play();
// Visual effect
tween(lifePowerUp, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
lifePowerUp.destroy();
}
});
lifePowerUps.splice(l, 1);
continue;
}
}
lifePowerUp.lastY = lifePowerUp.y;
lifePowerUp.lastIntersecting = currentIntersecting;
}
// Check collision with clouds
for (var k = 0; k < clouds.length; k++) {
var cloud = clouds[k];
if (cloud.lastIntersecting === undefined) cloud.lastIntersecting = false;
var currentIntersecting = cloud.intersects(player);
if (!cloud.lastIntersecting && currentIntersecting) {
// Only lose hearts after first 50 meters
if (currentDistance >= 50) {
playerLives--;
updateLivesDisplay();
LK.getSound('hit').play();
LK.effects.flashScreen(0xffffff, 500);
// Check if game over
if (playerLives <= 0) {
LK.showGameOver();
return;
}
} else {
// Flash screen but no heart loss for first 50 meters
LK.effects.flashScreen(0xffff88, 300);
}
}
cloud.lastIntersecting = currentIntersecting;
}
// Remove game over condition for falling off screen - infinite fall game
// Game only ends when hitting obstacles or clouds
};
// Start ambient music
LK.playMusic('ambient');