User prompt
Move little more down
User prompt
Move little down
User prompt
Move twice more left
User prompt
More left move
User prompt
Move to more left
User prompt
Target objective not visible on screen
User prompt
Show target objective in middle corner of screen
User prompt
Show target objective in upper left side of screen
User prompt
Show target objective in upper left corner
User prompt
When objective achieved go to next level
User prompt
When objective achieved go to level 2
User prompt
Game over if objective not reached in specified level time
User prompt
Game over when time of 1 minute over in a level
User prompt
Timer for each level 1 minute. If objective not reached in that time then game over. If reached then progress to level 2. Keep option for saving progress ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Kindly show level before its star like level 1.
User prompt
Please fix the bug: 'storage.getItem is not a function. (In 'storage.getItem('bestLevel')', 'storage.getItem' is undefined)' in or related to this line: 'var bestLevel = storage.getItem('bestLevel') || 1;' Line Number: 239 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.get is not a function. (In 'storage.get('bestLevel')', 'storage.get' is undefined)' in or related to this line: 'var bestLevel = storage.get('bestLevel') || 1;' Line Number: 239
User prompt
Kindly show paratroopers falling from a plane. Duration of each level to be 1 minute. 10 paratroopers to be saved on level 1 and then increase as per difficulty
User prompt
Want to have few changes
Code edit (1 edits merged)
Please save this source code
User prompt
Paratrooper Drop Rescue
Initial prompt
Paratroopers fall from plane. By touching his body parachute opens . With advancing levels speed and no of paratroopers falling increases and also some obstacles like birds , kites flying comes in way. Make a 20 level game.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); self.speed = 0; self.dir = 1; // 1 = right, -1 = left self.isActive = true; var bird = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.isActive) return; self.x += self.speed * self.dir; }; self.crash = function () { if (!self.isActive) return; self.isActive = false; LK.getSound('bird_hit').play(); tween(self, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { self.visible = false; } }); }; return self; }); // Kite class var Kite = Container.expand(function () { var self = Container.call(this); self.speed = 0; self.dir = 1; self.isActive = true; var kite = self.attachAsset('kite', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.isActive) return; self.x += self.speed * self.dir; }; self.crash = function () { if (!self.isActive) return; self.isActive = false; tween(self, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { self.visible = false; } }); }; return self; }); // Paratrooper class var Paratrooper = Container.expand(function () { var self = Container.call(this); // State: 0 = falling, 1 = parachute open, 2 = landed, 3 = crashed, 4 = rescued self.state = 0; self.speed = 0; self.hasParachute = false; self.isActive = true; // Attach body var body = self.attachAsset('paratrooper_body', { anchorX: 0.5, anchorY: 0.0 }); body.y = 0; // Attach parachute (hidden at first) var chute = self.attachAsset('parachute', { anchorX: 0.5, anchorY: 1.0, y: 0 }); chute.visible = false; // For tap detection self.down = function (x, y, obj) { if (self.state === 0 && self.isActive) { self.openParachute(); } }; // Open parachute self.openParachute = function () { if (self.state !== 0) return; self.state = 1; self.hasParachute = true; chute.visible = true; // Slow down self.speed = self.speed * 0.28; // Animate parachute pop chute.scaleY = 0.1; tween(chute, { scaleY: 1 }, { duration: 200, easing: tween.bounceOut }); LK.getSound('parachute_open').play(); }; // Crash animation self.crash = function () { if (!self.isActive) return; self.isActive = false; self.state = 3; // Flash red LK.effects.flashObject(self, 0xff0000, 600); LK.getSound('crash').play(); // Fade out tween(self, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { self.visible = false; } }); }; // Rescue animation self.rescue = function () { if (!self.isActive) return; self.isActive = false; self.state = 4; // Flash green LK.effects.flashObject(self, 0x00ff00, 400); // Fade out tween(self, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { self.visible = false; } }); }; // Bird/kite collision self.hitHazard = function () { if (self.state === 0 && self.isActive) { self.crash(); } }; self.update = function () { if (!self.isActive) return; self.y += self.speed; }; return self; }); // Plane class (for visual, not interactive) var Plane = Container.expand(function () { var self = Container.call(this); var plane = self.attachAsset('plane', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // Game constants // Paratrooper body (box), parachute (ellipse), bird (ellipse), kite (box), ground (box), plane (box) var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var GROUND_HEIGHT = 60; var LEVELS = 20; // Level config: Each level increases paratroopers, speed, and hazards var levelConfigs = []; for (var i = 0; i < LEVELS; i++) { // Level 1: 10 paratroopers, then +2 per level var paratroopersToRescue = 10 + i * 2; // Level duration: 1 minute (60 seconds * 60 FPS = 3600 ticks) var levelDurationTicks = 60 * 60; // Calculate spawn interval so all paratroopers spawn within the level duration var spawnInterval = Math.floor(levelDurationTicks / paratroopersToRescue); // Clamp spawnInterval to a minimum of 10 ticks for high levels spawnInterval = Math.max(spawnInterval, 10); levelConfigs.push({ paratroopers: paratroopersToRescue, speed: 9 + i * 1.2, hazards: i < 3 ? 0 : Math.min(1 + Math.floor((i - 2) / 2), 4), hazardSpeed: 7 + i * 0.7, hazardTypes: i < 6 ? ['bird'] : i < 12 ? ['bird', 'kite'] : ['bird', 'kite'], spawnInterval: spawnInterval, levelDurationTicks: levelDurationTicks }); } // State // Load saved progress if available, otherwise start at level 1 var currentLevel = storage.currentLevel || 1; var bestLevel = storage.bestLevel || 1; var paratroopers = []; var hazards = []; var rescuedCount = 0; var lostCount = 0; var totalToRescue = 0; var isLevelActive = false; var plane = null; var ground = null; var levelText = null; var rescuedText = null; var lostText = null; var bestLevelText = null; var levelTimeout = null; var spawnTick = 0; var hazardTick = 0; var dragNode = null; // Add ground ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: GAME_HEIGHT - GROUND_HEIGHT }); game.addChild(ground); // Add level text levelText = new Text2('Level 1', { size: 90, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); // Add objective text (upper left side, not in top left corner) var objectiveText = new Text2('', { size: 70, fill: 0xFFFFAA }); // Anchor to left, top objectiveText.anchor.set(0, 0); // Place at x=2 to avoid top left menu, y=0 (moved twice more left) objectiveText.x = 2; objectiveText.y = 50; LK.gui.top.addChild(objectiveText); // Add rescued/lost text rescuedText = new Text2('Rescued: 0', { size: 70, fill: 0xFFFFFF }); rescuedText.anchor.set(0, 0); LK.gui.top.addChild(rescuedText); lostText = new Text2('Lost: 0', { size: 70, fill: 0xFF4444 }); lostText.anchor.set(1, 0); LK.gui.topRight.addChild(lostText); // Add best level text bestLevelText = new Text2('Best: ' + bestLevel, { size: 60, fill: 0xFFFF00 }); bestLevelText.anchor.set(0.5, 0); LK.gui.bottom.addChild(bestLevelText); // Start music LK.playMusic('bgmusic'); // Show level number before starting, wait for tap to begin function showLevelIntro(level, callback) { // Hide timer and texts if visible if (levelTimerText) levelTimerText.visible = false; levelText.setText('Level ' + level); levelText.alpha = 1; levelText.visible = true; // Overlay to block input except tap to continue var introOverlay = new Container(); introOverlay.interactive = true; introOverlay.hitArea = { x: 0, y: 0, width: GAME_WIDTH, height: GAME_HEIGHT }; // Add a "Tap to Start" text var tapText = new Text2('Tap to Start', { size: 100, fill: 0xffffff }); tapText.anchor.set(0.5, 0.5); tapText.x = GAME_WIDTH / 2; tapText.y = GAME_HEIGHT / 2 + 180; introOverlay.addChild(tapText); // Add overlay to game game.addChild(introOverlay); // Only allow tap after a short delay to avoid accidental skip var canTap = false; LK.setTimeout(function () { canTap = true; }, 400); introOverlay.down = function () { if (!canTap) return; // Animate out tween(levelText, { alpha: 0 }, { duration: 400 }); tween(tapText, { alpha: 0 }, { duration: 400 }); LK.setTimeout(function () { introOverlay.destroy(); if (callback) callback(); }, 420); }; } // Start first level after intro showLevelIntro(currentLevel, function () { startLevel(currentLevel); }); var levelTimerText = null; var levelTimerTimeout = null; function startLevel(level) { // Update best level if needed if (level > bestLevel) { bestLevel = level; storage.bestLevel = bestLevel; if (bestLevelText) bestLevelText.setText('Best: ' + bestLevel); } // Save progress storage.currentLevel = level; // Reset state for (var i = 0; i < paratroopers.length; i++) { paratroopers[i].destroy(); } for (var i = 0; i < hazards.length; i++) { hazards[i].destroy(); } paratroopers = []; hazards = []; rescuedCount = 0; lostCount = 0; isLevelActive = true; spawnTick = 0; hazardTick = 0; totalToRescue = levelConfigs[level - 1].paratroopers; if (objectiveText) { objectiveText.setText('Rescue ' + totalToRescue + ' Paratroopers'); } levelText.setText('Level ' + level); rescuedText.setText('Rescued: 0'); lostText.setText('Lost: 0'); // Animate level text levelText.alpha = 1; tween(levelText, { alpha: 0 }, { duration: 1200 }); // Plane flyby if (plane) plane.destroy(); plane = new Plane(); plane.y = 180; plane.x = -200; game.addChild(plane); tween(plane, { x: GAME_WIDTH + 200 }, { duration: 1800, easing: tween.linear, onFinish: function onFinish() { plane.destroy(); plane = null; } }); // Add or reset timer text if (!levelTimerText) { levelTimerText = new Text2('01:00', { size: 80, fill: 0xFFFFFF }); levelTimerText.anchor.set(0.5, 0); LK.gui.top.addChild(levelTimerText); } // Place timer below level text levelTimerText.y = levelText.height + 10; levelTimerText.setText('01:00'); // Clear any previous timer if (levelTimerTimeout) { LK.clearTimeout(levelTimerTimeout); levelTimerTimeout = null; } // Start timer countdown var ticksLeft = levelConfigs[level - 1].levelDurationTicks; if (levelTimerText) levelTimerText.visible = true; function updateTimer() { if (!isLevelActive) return; ticksLeft--; var seconds = Math.floor(ticksLeft / 60); var ms = ticksLeft % 60; var timeStr = (seconds < 10 ? '0' : '') + seconds + ':' + (ms < 10 ? '0' : '') + ms; if (levelTimerText) levelTimerText.setText(timeStr); if (ticksLeft > 0 && isLevelActive) { levelTimerTimeout = LK.setTimeout(updateTimer, 1000 / 60); } else if (isLevelActive) { // Time's up, end level isLevelActive = false; // If not all rescued, game over, else win/next if (rescuedCount === totalToRescue) { LK.getSound('levelup').play(); if (currentLevel < LEVELS) { currentLevel++; LK.setTimeout(function () { startLevel(currentLevel); }, 1200); } else { LK.showYouWin(); } } else { LK.showGameOver(); } } } updateTimer(); } // Paratrooper spawn function spawnParatrooper() { var config = levelConfigs[currentLevel - 1]; var p = new Paratrooper(); // Random x, avoid edges var margin = 120; p.x = margin + Math.random() * (GAME_WIDTH - 2 * margin); p.y = 220; p.speed = config.speed + Math.random() * 2; p.state = 0; p.hasParachute = false; p.isActive = true; paratroopers.push(p); game.addChild(p); } // Hazard spawn function spawnHazard() { var config = levelConfigs[currentLevel - 1]; var type = config.hazardTypes[Math.floor(Math.random() * config.hazardTypes.length)]; var h = null; var y = 400 + Math.random() * (GAME_HEIGHT - GROUND_HEIGHT - 800); var dir = Math.random() < 0.5 ? 1 : -1; var speed = config.hazardSpeed + Math.random() * 2; var x = dir === 1 ? -100 : GAME_WIDTH + 100; if (type === 'bird') { h = new Bird(); } else { h = new Kite(); } h.x = x; h.y = y; h.dir = dir; h.speed = speed; h.isActive = true; hazards.push(h); game.addChild(h); } // Game move handler (for drag, but not used in this game) game.move = function (x, y, obj) { // No drag in this game }; // Game down handler (for tap on paratroopers) game.down = function (x, y, obj) { // Find topmost paratrooper under tap for (var i = paratroopers.length - 1; i >= 0; i--) { var p = paratroopers[i]; if (p.isActive && p.state === 0 && p.visible) { // Check if tap is inside body var local = p.toLocal({ x: x, y: y }); var body = p.children[0]; if (local.x >= body.x - body.width / 2 && local.x <= body.x + body.width / 2 && local.y >= body.y && local.y <= body.y + body.height) { p.openParachute(); break; } } } }; // Game update game.update = function () { if (!isLevelActive) return; var config = levelConfigs[currentLevel - 1]; // Spawn paratroopers if (paratroopers.length < totalToRescue && LK.ticks % config.spawnInterval === 0) { spawnParatrooper(); } // Spawn hazards if (config.hazards > 0 && hazards.length < config.hazards && LK.ticks % (80 + Math.floor(Math.random() * 40)) === 0) { spawnHazard(); } // Update paratroopers for (var i = paratroopers.length - 1; i >= 0; i--) { var p = paratroopers[i]; p.update(); // Check for ground collision if (p.isActive && p.y + 90 >= GAME_HEIGHT - GROUND_HEIGHT) { if (p.state === 1) { // Landed safely p.rescue(); rescuedCount++; rescuedText.setText('Rescued: ' + rescuedCount); } else if (p.state === 0) { // Crashed p.crash(); lostCount++; lostText.setText('Lost: ' + lostCount); // Flash screen LK.effects.flashScreen(0xff0000, 400); } // Remove after animation LK.setTimeout(function (paratrooper) { return function () { paratrooper.destroy(); }; }(p), 700); paratroopers.splice(i, 1); continue; } // Check for hazard collision for (var j = hazards.length - 1; j >= 0; j--) { var h = hazards[j]; if (h.isActive && p.isActive && p.state === 0 && p.intersects(h)) { p.hitHazard(); h.crash(); lostCount++; lostText.setText('Lost: ' + lostCount); LK.effects.flashScreen(0xff0000, 400); LK.setTimeout(function (paratrooper) { return function () { paratrooper.destroy(); }; }(p), 700); paratroopers.splice(i, 1); break; } } } // Update hazards for (var i = hazards.length - 1; i >= 0; i--) { var h = hazards[i]; h.update(); // Remove if off screen if (h.dir === 1 && h.x > GAME_WIDTH + 120 || h.dir === -1 && h.x < -120) { h.destroy(); hazards.splice(i, 1); } } // Level end condition // If all paratroopers rescued before timer ends, go to next level immediately if (isLevelActive && rescuedCount === totalToRescue) { isLevelActive = false; LK.getSound('levelup').play(); if (currentLevel < LEVELS) { currentLevel++; LK.setTimeout(function () { startLevel(currentLevel); }, 1200); } else { LK.showYouWin(); } return; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.dir = 1; // 1 = right, -1 = left
self.isActive = true;
var bird = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (!self.isActive) return;
self.x += self.speed * self.dir;
};
self.crash = function () {
if (!self.isActive) return;
self.isActive = false;
LK.getSound('bird_hit').play();
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.visible = false;
}
});
};
return self;
});
// Kite class
var Kite = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.dir = 1;
self.isActive = true;
var kite = self.attachAsset('kite', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (!self.isActive) return;
self.x += self.speed * self.dir;
};
self.crash = function () {
if (!self.isActive) return;
self.isActive = false;
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.visible = false;
}
});
};
return self;
});
// Paratrooper class
var Paratrooper = Container.expand(function () {
var self = Container.call(this);
// State: 0 = falling, 1 = parachute open, 2 = landed, 3 = crashed, 4 = rescued
self.state = 0;
self.speed = 0;
self.hasParachute = false;
self.isActive = true;
// Attach body
var body = self.attachAsset('paratrooper_body', {
anchorX: 0.5,
anchorY: 0.0
});
body.y = 0;
// Attach parachute (hidden at first)
var chute = self.attachAsset('parachute', {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
chute.visible = false;
// For tap detection
self.down = function (x, y, obj) {
if (self.state === 0 && self.isActive) {
self.openParachute();
}
};
// Open parachute
self.openParachute = function () {
if (self.state !== 0) return;
self.state = 1;
self.hasParachute = true;
chute.visible = true;
// Slow down
self.speed = self.speed * 0.28;
// Animate parachute pop
chute.scaleY = 0.1;
tween(chute, {
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
LK.getSound('parachute_open').play();
};
// Crash animation
self.crash = function () {
if (!self.isActive) return;
self.isActive = false;
self.state = 3;
// Flash red
LK.effects.flashObject(self, 0xff0000, 600);
LK.getSound('crash').play();
// Fade out
tween(self, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
self.visible = false;
}
});
};
// Rescue animation
self.rescue = function () {
if (!self.isActive) return;
self.isActive = false;
self.state = 4;
// Flash green
LK.effects.flashObject(self, 0x00ff00, 400);
// Fade out
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.visible = false;
}
});
};
// Bird/kite collision
self.hitHazard = function () {
if (self.state === 0 && self.isActive) {
self.crash();
}
};
self.update = function () {
if (!self.isActive) return;
self.y += self.speed;
};
return self;
});
// Plane class (for visual, not interactive)
var Plane = Container.expand(function () {
var self = Container.call(this);
var plane = self.attachAsset('plane', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Game constants
// Paratrooper body (box), parachute (ellipse), bird (ellipse), kite (box), ground (box), plane (box)
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GROUND_HEIGHT = 60;
var LEVELS = 20;
// Level config: Each level increases paratroopers, speed, and hazards
var levelConfigs = [];
for (var i = 0; i < LEVELS; i++) {
// Level 1: 10 paratroopers, then +2 per level
var paratroopersToRescue = 10 + i * 2;
// Level duration: 1 minute (60 seconds * 60 FPS = 3600 ticks)
var levelDurationTicks = 60 * 60;
// Calculate spawn interval so all paratroopers spawn within the level duration
var spawnInterval = Math.floor(levelDurationTicks / paratroopersToRescue);
// Clamp spawnInterval to a minimum of 10 ticks for high levels
spawnInterval = Math.max(spawnInterval, 10);
levelConfigs.push({
paratroopers: paratroopersToRescue,
speed: 9 + i * 1.2,
hazards: i < 3 ? 0 : Math.min(1 + Math.floor((i - 2) / 2), 4),
hazardSpeed: 7 + i * 0.7,
hazardTypes: i < 6 ? ['bird'] : i < 12 ? ['bird', 'kite'] : ['bird', 'kite'],
spawnInterval: spawnInterval,
levelDurationTicks: levelDurationTicks
});
}
// State
// Load saved progress if available, otherwise start at level 1
var currentLevel = storage.currentLevel || 1;
var bestLevel = storage.bestLevel || 1;
var paratroopers = [];
var hazards = [];
var rescuedCount = 0;
var lostCount = 0;
var totalToRescue = 0;
var isLevelActive = false;
var plane = null;
var ground = null;
var levelText = null;
var rescuedText = null;
var lostText = null;
var bestLevelText = null;
var levelTimeout = null;
var spawnTick = 0;
var hazardTick = 0;
var dragNode = null;
// Add ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GAME_HEIGHT - GROUND_HEIGHT
});
game.addChild(ground);
// Add level text
levelText = new Text2('Level 1', {
size: 90,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
// Add objective text (upper left side, not in top left corner)
var objectiveText = new Text2('', {
size: 70,
fill: 0xFFFFAA
});
// Anchor to left, top
objectiveText.anchor.set(0, 0);
// Place at x=2 to avoid top left menu, y=0 (moved twice more left)
objectiveText.x = 2;
objectiveText.y = 50;
LK.gui.top.addChild(objectiveText);
// Add rescued/lost text
rescuedText = new Text2('Rescued: 0', {
size: 70,
fill: 0xFFFFFF
});
rescuedText.anchor.set(0, 0);
LK.gui.top.addChild(rescuedText);
lostText = new Text2('Lost: 0', {
size: 70,
fill: 0xFF4444
});
lostText.anchor.set(1, 0);
LK.gui.topRight.addChild(lostText);
// Add best level text
bestLevelText = new Text2('Best: ' + bestLevel, {
size: 60,
fill: 0xFFFF00
});
bestLevelText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(bestLevelText);
// Start music
LK.playMusic('bgmusic');
// Show level number before starting, wait for tap to begin
function showLevelIntro(level, callback) {
// Hide timer and texts if visible
if (levelTimerText) levelTimerText.visible = false;
levelText.setText('Level ' + level);
levelText.alpha = 1;
levelText.visible = true;
// Overlay to block input except tap to continue
var introOverlay = new Container();
introOverlay.interactive = true;
introOverlay.hitArea = {
x: 0,
y: 0,
width: GAME_WIDTH,
height: GAME_HEIGHT
};
// Add a "Tap to Start" text
var tapText = new Text2('Tap to Start', {
size: 100,
fill: 0xffffff
});
tapText.anchor.set(0.5, 0.5);
tapText.x = GAME_WIDTH / 2;
tapText.y = GAME_HEIGHT / 2 + 180;
introOverlay.addChild(tapText);
// Add overlay to game
game.addChild(introOverlay);
// Only allow tap after a short delay to avoid accidental skip
var canTap = false;
LK.setTimeout(function () {
canTap = true;
}, 400);
introOverlay.down = function () {
if (!canTap) return;
// Animate out
tween(levelText, {
alpha: 0
}, {
duration: 400
});
tween(tapText, {
alpha: 0
}, {
duration: 400
});
LK.setTimeout(function () {
introOverlay.destroy();
if (callback) callback();
}, 420);
};
}
// Start first level after intro
showLevelIntro(currentLevel, function () {
startLevel(currentLevel);
});
var levelTimerText = null;
var levelTimerTimeout = null;
function startLevel(level) {
// Update best level if needed
if (level > bestLevel) {
bestLevel = level;
storage.bestLevel = bestLevel;
if (bestLevelText) bestLevelText.setText('Best: ' + bestLevel);
}
// Save progress
storage.currentLevel = level;
// Reset state
for (var i = 0; i < paratroopers.length; i++) {
paratroopers[i].destroy();
}
for (var i = 0; i < hazards.length; i++) {
hazards[i].destroy();
}
paratroopers = [];
hazards = [];
rescuedCount = 0;
lostCount = 0;
isLevelActive = true;
spawnTick = 0;
hazardTick = 0;
totalToRescue = levelConfigs[level - 1].paratroopers;
if (objectiveText) {
objectiveText.setText('Rescue ' + totalToRescue + ' Paratroopers');
}
levelText.setText('Level ' + level);
rescuedText.setText('Rescued: 0');
lostText.setText('Lost: 0');
// Animate level text
levelText.alpha = 1;
tween(levelText, {
alpha: 0
}, {
duration: 1200
});
// Plane flyby
if (plane) plane.destroy();
plane = new Plane();
plane.y = 180;
plane.x = -200;
game.addChild(plane);
tween(plane, {
x: GAME_WIDTH + 200
}, {
duration: 1800,
easing: tween.linear,
onFinish: function onFinish() {
plane.destroy();
plane = null;
}
});
// Add or reset timer text
if (!levelTimerText) {
levelTimerText = new Text2('01:00', {
size: 80,
fill: 0xFFFFFF
});
levelTimerText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTimerText);
}
// Place timer below level text
levelTimerText.y = levelText.height + 10;
levelTimerText.setText('01:00');
// Clear any previous timer
if (levelTimerTimeout) {
LK.clearTimeout(levelTimerTimeout);
levelTimerTimeout = null;
}
// Start timer countdown
var ticksLeft = levelConfigs[level - 1].levelDurationTicks;
if (levelTimerText) levelTimerText.visible = true;
function updateTimer() {
if (!isLevelActive) return;
ticksLeft--;
var seconds = Math.floor(ticksLeft / 60);
var ms = ticksLeft % 60;
var timeStr = (seconds < 10 ? '0' : '') + seconds + ':' + (ms < 10 ? '0' : '') + ms;
if (levelTimerText) levelTimerText.setText(timeStr);
if (ticksLeft > 0 && isLevelActive) {
levelTimerTimeout = LK.setTimeout(updateTimer, 1000 / 60);
} else if (isLevelActive) {
// Time's up, end level
isLevelActive = false;
// If not all rescued, game over, else win/next
if (rescuedCount === totalToRescue) {
LK.getSound('levelup').play();
if (currentLevel < LEVELS) {
currentLevel++;
LK.setTimeout(function () {
startLevel(currentLevel);
}, 1200);
} else {
LK.showYouWin();
}
} else {
LK.showGameOver();
}
}
}
updateTimer();
}
// Paratrooper spawn
function spawnParatrooper() {
var config = levelConfigs[currentLevel - 1];
var p = new Paratrooper();
// Random x, avoid edges
var margin = 120;
p.x = margin + Math.random() * (GAME_WIDTH - 2 * margin);
p.y = 220;
p.speed = config.speed + Math.random() * 2;
p.state = 0;
p.hasParachute = false;
p.isActive = true;
paratroopers.push(p);
game.addChild(p);
}
// Hazard spawn
function spawnHazard() {
var config = levelConfigs[currentLevel - 1];
var type = config.hazardTypes[Math.floor(Math.random() * config.hazardTypes.length)];
var h = null;
var y = 400 + Math.random() * (GAME_HEIGHT - GROUND_HEIGHT - 800);
var dir = Math.random() < 0.5 ? 1 : -1;
var speed = config.hazardSpeed + Math.random() * 2;
var x = dir === 1 ? -100 : GAME_WIDTH + 100;
if (type === 'bird') {
h = new Bird();
} else {
h = new Kite();
}
h.x = x;
h.y = y;
h.dir = dir;
h.speed = speed;
h.isActive = true;
hazards.push(h);
game.addChild(h);
}
// Game move handler (for drag, but not used in this game)
game.move = function (x, y, obj) {
// No drag in this game
};
// Game down handler (for tap on paratroopers)
game.down = function (x, y, obj) {
// Find topmost paratrooper under tap
for (var i = paratroopers.length - 1; i >= 0; i--) {
var p = paratroopers[i];
if (p.isActive && p.state === 0 && p.visible) {
// Check if tap is inside body
var local = p.toLocal({
x: x,
y: y
});
var body = p.children[0];
if (local.x >= body.x - body.width / 2 && local.x <= body.x + body.width / 2 && local.y >= body.y && local.y <= body.y + body.height) {
p.openParachute();
break;
}
}
}
};
// Game update
game.update = function () {
if (!isLevelActive) return;
var config = levelConfigs[currentLevel - 1];
// Spawn paratroopers
if (paratroopers.length < totalToRescue && LK.ticks % config.spawnInterval === 0) {
spawnParatrooper();
}
// Spawn hazards
if (config.hazards > 0 && hazards.length < config.hazards && LK.ticks % (80 + Math.floor(Math.random() * 40)) === 0) {
spawnHazard();
}
// Update paratroopers
for (var i = paratroopers.length - 1; i >= 0; i--) {
var p = paratroopers[i];
p.update();
// Check for ground collision
if (p.isActive && p.y + 90 >= GAME_HEIGHT - GROUND_HEIGHT) {
if (p.state === 1) {
// Landed safely
p.rescue();
rescuedCount++;
rescuedText.setText('Rescued: ' + rescuedCount);
} else if (p.state === 0) {
// Crashed
p.crash();
lostCount++;
lostText.setText('Lost: ' + lostCount);
// Flash screen
LK.effects.flashScreen(0xff0000, 400);
}
// Remove after animation
LK.setTimeout(function (paratrooper) {
return function () {
paratrooper.destroy();
};
}(p), 700);
paratroopers.splice(i, 1);
continue;
}
// Check for hazard collision
for (var j = hazards.length - 1; j >= 0; j--) {
var h = hazards[j];
if (h.isActive && p.isActive && p.state === 0 && p.intersects(h)) {
p.hitHazard();
h.crash();
lostCount++;
lostText.setText('Lost: ' + lostCount);
LK.effects.flashScreen(0xff0000, 400);
LK.setTimeout(function (paratrooper) {
return function () {
paratrooper.destroy();
};
}(p), 700);
paratroopers.splice(i, 1);
break;
}
}
}
// Update hazards
for (var i = hazards.length - 1; i >= 0; i--) {
var h = hazards[i];
h.update();
// Remove if off screen
if (h.dir === 1 && h.x > GAME_WIDTH + 120 || h.dir === -1 && h.x < -120) {
h.destroy();
hazards.splice(i, 1);
}
}
// Level end condition
// If all paratroopers rescued before timer ends, go to next level immediately
if (isLevelActive && rescuedCount === totalToRescue) {
isLevelActive = false;
LK.getSound('levelup').play();
if (currentLevel < LEVELS) {
currentLevel++;
LK.setTimeout(function () {
startLevel(currentLevel);
}, 1200);
} else {
LK.showYouWin();
}
return;
}
};