User prompt
create and assign the background music for the game
User prompt
convert the environment to maze
User prompt
set minimum score points at each level to pass\
User prompt
convert the environment to maze
User prompt
fix the game over bug that popup automatically
User prompt
make the game more challenging
User prompt
make the player input like first we have to hold and draw the mouse input on that path which will be shown on the screen after the input is complete then player has to move only on that way ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
optimize the mouse hold and drag input smoother
User prompt
fix the game over bug
User prompt
fix the game over bug
User prompt
create and assign some of the assets near the wall
User prompt
add a building asset for each wall so it will look like a house
User prompt
add a health bar to the firefighter if he directly collide with fire reduce the health with little
User prompt
scale the exit gate asset liitle bit bigger ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add building assets in the game to make it more realistic
User prompt
Please fix the bug: 'Timeout.tick error: distance is not a function' in or related to this line: 'var tooCloseToFirefighter = distance(pickupX, pickupY, firefighter.x, firefighter.y) < 200;' Line Number: 956
User prompt
Please fix the bug: 'distance is not a function' in or related to this line: 'var tooCloseToFirefighter = distance(pickupX, pickupY, firefighter.x, firefighter.y) < 200;' Line Number: 950
User prompt
Please fix the bug: 'distance is not a function' in or related to this line: 'var tooCloseToFirefighter = distance(pickupX, pickupY, firefighter.x, firefighter.y) < 200;' Line Number: 944
User prompt
Please fix the bug: 'distance is not a function' in or related to this line: 'var tooCloseToFirefighter = distance(pickupX, pickupY, firefighter.x, firefighter.y) < 200;' Line Number: 942
User prompt
add more water pickups across the game so the firefighter can pickup
User prompt
reduce the water reducing amount which gets emptier quickly
User prompt
spawn those across the game that'll help the firefighter to refill the status
User prompt
add water pickup to collect refill the water status
User prompt
dont squash the walls
User prompt
make the walls in horizontal
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, highestLevel: 1 }); /**** * Classes ****/ var GameObject = Container.expand(function (id, width, height) { var self = Container.call(this); self.id = id; self.width = width; self.height = height; self.isDestroyed = false; self.destroy = function () { self.isDestroyed = true; Container.prototype.destroy.call(self); }; return self; }); var WaterPickup = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'waterPickup', 60, 60); var graphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); self.x = x; self.y = y; self.waterAmount = 75; // Increased water amount // Make water pickup pulse to draw attention function pulseAnimation() { tween(graphics.scale, { x: 3.3, y: 3.3 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(graphics.scale, { x: 3.0, y: 3.0 }, { duration: 800, easing: tween.easeInOut, onFinish: pulseAnimation }); } }); } pulseAnimation(); return self; }); var WaterParticle = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'water', 20, 20); var graphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.lifespan = 30; // frames self.velocity = { x: Math.random() * 6 - 3, y: -8 - Math.random() * 3 }; self.update = function () { self.x += self.velocity.x; self.y += self.velocity.y; self.lifespan--; // Apply gravity self.velocity.y += 0.3; // Fade out graphics.alpha = self.lifespan / 30; // Check collision with fires for (var i = fires.length - 1; i >= 0; i--) { var fire = fires[i]; if (self.intersects(fire)) { fire.intensity -= 5; if (fire.intensity <= 0) { LK.getSound('extinguish').play(); LK.setScore(LK.getScore() + 50); updateScoreText(); fires.splice(i, 1); fire.destroy(); } self.lifespan = 0; break; } } if (self.lifespan <= 0) { self.destroy(); for (var i = 0; i < waterParticles.length; i++) { if (waterParticles[i] === self) { waterParticles.splice(i, 1); break; } } } }; return self; }); var Wall = GameObject.expand(function (x, y, width, height) { var self = GameObject.call(this, 'wall', width, height); var graphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, width: width, height: height }); self.x = x; self.y = y; return self; }); var Smoke = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'smoke', 200, 200); var graphics = self.attachAsset('smoke', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); self.x = x; self.y = y; self.lifespan = 120 + Math.floor(Math.random() * 60); // 2-3 seconds var scale = 0.3 + Math.random() * 0.3; graphics.scale.set(scale, scale); self.update = function () { self.y -= 0.5; self.x += Math.random() * 0.6 - 0.3; self.lifespan--; // Grow and fade var lifePercent = self.lifespan / 180; graphics.scale.set(scale * (2 - lifePercent), scale * (2 - lifePercent)); graphics.alpha = 0.3 * lifePercent; if (self.lifespan <= 0) { self.destroy(); for (var i = 0; i < smokeParticles.length; i++) { if (smokeParticles[i] === self) { smokeParticles.splice(i, 1); break; } } } }; return self; }); var Firefighter = GameObject.expand(function () { var self = GameObject.call(this, 'firefighter', 100, 150); var graphics = self.attachAsset('firefighter', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.waterLevel = 100; self.maxWaterLevel = 100; self.waterUseRate = 0.5; self.waterRefillRate = 3; self.isRefilling = false; self.isSprayingWater = false; self.carryingCivilian = null; self.direction = { x: 0, y: 0 }; self.update = function () { // Handle movement if (self.direction.x !== 0 || self.direction.y !== 0) { var newX = self.x + self.direction.x * self.speed; var newY = self.y + self.direction.y * self.speed; // Check for collisions with walls var wouldCollide = false; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; if (willCollide(newX, newY, self.width, self.height, wall.x, wall.y, wall.width, wall.height)) { wouldCollide = true; break; } } if (!wouldCollide) { self.x = newX; self.y = newY; // Keep within game bounds self.x = Math.max(self.width / 2, Math.min(self.x, 2048 - self.width / 2)); self.y = Math.max(self.height / 2, Math.min(self.y, 2732 - self.height / 2)); // If carrying a civilian, update their position if (self.carryingCivilian) { self.carryingCivilian.x = self.x; self.carryingCivilian.y = self.y - 80; } } } // Check for water refill at fire station if (fireStation && self.intersects(fireStation)) { self.isRefilling = true; if (self.waterLevel < self.maxWaterLevel) { self.waterLevel = Math.min(self.maxWaterLevel, self.waterLevel + self.waterRefillRate); updateWaterBar(); } } else { self.isRefilling = false; } // Check for water pickup collision for (var i = waterPickups.length - 1; i >= 0; i--) { if (self.intersects(waterPickups[i])) { // Refill water self.waterLevel = Math.min(self.maxWaterLevel, self.waterLevel + waterPickups[i].waterAmount); updateWaterBar(); // Add score LK.setScore(LK.getScore() + 25); updateScoreText(); // Show pickup effect LK.effects.flashObject(self, 0x0000ff, 500); // Create water particle burst effect for (var j = 0; j < 8; j++) { var angle = j * Math.PI / 4; var particleX = self.x + Math.cos(angle) * 50; var particleY = self.y + Math.sin(angle) * 50; var particle = new WaterParticle(particleX, particleY); particle.velocity.x = Math.cos(angle) * 4; particle.velocity.y = Math.sin(angle) * 4; game.addChild(particle); waterParticles.push(particle); } // Play sound LK.getSound('spray').play(); // Remove pickup waterPickups[i].destroy(); waterPickups.splice(i, 1); } } // Handle water spraying if (self.isSprayingWater && self.waterLevel > 0) { self.waterLevel = Math.max(0, self.waterLevel - self.waterUseRate); updateWaterBar(); // Create water particle createWaterParticle(self.x, self.y); } // Check exit collision when carrying civilian if (self.carryingCivilian && exit && self.intersects(exit)) { LK.getSound('rescue').play(); civiliansRescued++; self.carryingCivilian.isRescued = true; self.carryingCivilian = null; // Update the score LK.setScore(LK.getScore() + 100); updateScoreText(); // Check if all civilians are rescued checkLevelComplete(); } }; return self; }); var FireStation = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'fireStation', 800, 600); var graphics = self.attachAsset('fireStation', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; return self; }); var Fire = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'fire', 60, 80); var graphics = self.attachAsset('fire', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.intensity = 100; // 0-100 self.spreadTimer = 0; self.spreadRate = 5; // seconds // Randomly vary the size var scale = 0.8 + Math.random() * 0.4; graphics.scale.set(scale, scale); self.update = function () { if (self.intensity <= 0) { self.destroy(); return; } // Animate the fire if (LK.ticks % 5 === 0) { var scaleVar = Math.random() * 0.2 - 0.1; graphics.scale.set(scale + scaleVar, scale + scaleVar); } // Attempt to spread fire self.spreadTimer++; if (self.spreadTimer > self.spreadRate * 60) { // Convert seconds to frames at 60fps self.spreadTimer = 0; if (Math.random() < 0.3 && fires.length < maxFires) { var angle = Math.random() * Math.PI * 2; var distance = 100 + Math.random() * 100; var newX = self.x + Math.cos(angle) * distance; var newY = self.y + Math.sin(angle) * distance; // Keep within game bounds newX = Math.max(30, Math.min(newX, 2048 - 30)); newY = Math.max(30, Math.min(newY, 2732 - 30)); // Check if too close to existing fire or wall var tooClose = false; // Check walls for (var i = 0; i < walls.length; i++) { if (willCollide(newX, newY, 60, 80, walls[i].x, walls[i].y, walls[i].width, walls[i].height)) { tooClose = true; break; } } if (!tooClose) { createFire(newX, newY); LK.getSound('burn').play(); } } } }; return self; }); var Exit = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'exit', 150, 100); var graphics = self.attachAsset('exit', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; // Make exit pulse to draw attention function pulseAnimation() { tween(graphics.scale, { x: 1.3, y: 1.3 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(graphics.scale, { x: 1.2, y: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: pulseAnimation }); } }); } pulseAnimation(); return self; }); var Civilian = GameObject.expand(function (x, y) { var self = GameObject.call(this, 'civilian', 80, 120); var graphics = self.attachAsset('civilian', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.isRescued = false; self.healthTimer = 0; self.maxHealthTimer = 5 * 60; // 5 seconds at 60fps self.update = function () { // Check if close to fire var nearFire = false; for (var i = 0; i < fires.length; i++) { var fire = fires[i]; var dx = self.x - fire.x; var dy = self.y - fire.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { nearFire = true; break; } } if (nearFire) { // Start losing health when near fire self.healthTimer++; if (self.healthTimer >= self.maxHealthTimer) { LK.effects.flashScreen(0xff0000, 500); LK.showGameOver(); } } else { // Recover when away from fire self.healthTimer = Math.max(0, self.healthTimer - 1); } // Visual feedback on health var healthPercent = 1 - self.healthTimer / self.maxHealthTimer; graphics.alpha = 0.5 + healthPercent * 0.5; // Animate when in danger if (nearFire && LK.ticks % 10 === 0) { tween(graphics, { rotation: Math.random() * 0.2 - 0.1 }, { duration: 300 }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x333333 }); /**** * Game Code ****/ // Game state variables var level = storage.currentLevel || 1; var firefighter; var fires = []; var civilians = []; var walls = []; var waterParticles = []; var smokeParticles = []; var waterPickups = []; var waterPickupTimer; var fireStation; var exit; var maxFires; var civiliansRescued = 0; var totalCivilians = 0; var gameTime = 90; // seconds var gameTimer; var controlPad; var actionButton; var timeBarFill; var waterBarFill; var joystickActive = false; var joystickOrigin = { x: 0, y: 0 }; var joystickPosition = { x: 0, y: 0 }; // Interface elements var scoreTxt; var levelTxt; var timeBarContainer; var timeBarBg; var waterBarContainer; var waterBarBg; var instructionsContainer; var instructionsTxt; // Initialize game function initGame() { // Reset game state LK.setScore(0); civiliansRescued = 0; // Clear previous game objects cleanupLevel(); // Set up the level setupLevel(level); // Create UI createUI(); // Play background music LK.playMusic('gameplay', { fade: { start: 0, end: 0.4, duration: 1000 } }); // Start game timer startGameTimer(); // Show initial instructions showInstructions(); // Start water pickup spawning if (waterPickupTimer) { LK.clearInterval(waterPickupTimer); } // Create multiple initial water pickups based on level var initialPickups = 2 + Math.floor(level / 2); for (var i = 0; i < initialPickups; i++) { createWaterPickup(); } // Spawn new water pickups periodically waterPickupTimer = LK.setInterval(function () { // Limit the number of pickups based on level if (waterPickups.length < 3 + Math.floor(level)) { createWaterPickup(); } }, 15000); // New water pickup every 15 seconds (increased frequency) } function cleanupLevel() { // Clear all game objects if (firefighter) { firefighter.destroy(); } for (var i = 0; i < fires.length; i++) { fires[i].destroy(); } fires = []; for (var i = 0; i < civilians.length; i++) { civilians[i].destroy(); } civilians = []; for (var i = 0; i < walls.length; i++) { walls[i].destroy(); } walls = []; for (var i = 0; i < waterParticles.length; i++) { waterParticles[i].destroy(); } waterParticles = []; for (var i = 0; i < smokeParticles.length; i++) { smokeParticles[i].destroy(); } smokeParticles = []; for (var i = 0; i < waterPickups.length; i++) { waterPickups[i].destroy(); } waterPickups = []; if (waterPickupTimer) { LK.clearInterval(waterPickupTimer); waterPickupTimer = null; } if (fireStation) { fireStation.destroy(); fireStation = null; } if (exit) { exit.destroy(); exit = null; } if (gameTimer) { LK.clearInterval(gameTimer); gameTimer = null; } } function setupLevel(level) { // Define distance function first so it can be used in this method function distance(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } // Level configuration var levelConfig = { 1: { layout: 'basic', civilians: 2, initialFires: 3, maxFires: 6, time: 90 }, 2: { layout: 'apartment', civilians: 3, initialFires: 4, maxFires: 8, time: 120 }, 3: { layout: 'office', civilians: 4, initialFires: 5, maxFires: 10, time: 180 } }; // Use level 3 config for any level beyond 3 var config = levelConfig[level] || levelConfig[3]; config.initialFires += Math.floor((level - 3) / 2); // Increase fires for levels beyond 3 config.civilians += Math.floor((level - 3) / 2); // Increase civilians for levels beyond 3 config.time = Math.min(300, config.time + (level - 3) * 30); // Increase time (max 5 minutes) maxFires = config.maxFires; totalCivilians = config.civilians; gameTime = config.time; // Create level layout createLayout(config.layout); // Create initial fires for (var i = 0; i < config.initialFires; i++) { var fireX, fireY; var validPosition = false; // Find a valid position for the fire while (!validPosition) { fireX = 300 + Math.random() * (2048 - 600); fireY = 300 + Math.random() * (2732 - 600); // Check if too close to firefighter, fire station, or exit var dx1 = fireX - 200; var dy1 = fireY - 2500; var tooCloseToFirefighter = Math.sqrt(dx1 * dx1 + dy1 * dy1) < 300; var tooCloseToFireStation = fireStation && Math.sqrt(Math.pow(fireX - fireStation.x, 2) + Math.pow(fireY - fireStation.y, 2)) < 400; var tooCloseToExit = exit && Math.sqrt(Math.pow(fireX - exit.x, 2) + Math.pow(fireY - exit.y, 2)) < 400; // Check if inside any wall var insideWall = false; for (var j = 0; j < walls.length; j++) { if (willCollide(fireX, fireY, 60, 80, walls[j].x, walls[j].y, walls[j].width, walls[j].height)) { insideWall = true; break; } } validPosition = !tooCloseToFirefighter && !tooCloseToFireStation && !tooCloseToExit && !insideWall; } createFire(fireX, fireY); } // Create civilians for (var i = 0; i < config.civilians; i++) { var civX, civY; var validPosition = false; while (!validPosition) { civX = 300 + Math.random() * (2048 - 600); civY = 300 + Math.random() * (2732 - 600); // Not too close to fire station or exit var tooCloseToFireStation = fireStation && distance(civX, civY, fireStation.x, fireStation.y) < 300; var tooCloseToExit = exit && distance(civX, civY, exit.x, exit.y) < 300; // Check if inside any wall var insideWall = false; for (var j = 0; j < walls.length; j++) { if (willCollide(civX, civY, 80, 120, walls[j].x, walls[j].y, walls[j].width, walls[j].height)) { insideWall = true; break; } } // Must be somewhat close to at least one fire var nearFire = false; for (var j = 0; j < fires.length; j++) { if (distance(civX, civY, fires[j].x, fires[j].y) < 500) { nearFire = true; break; } } validPosition = !tooCloseToFireStation && !tooCloseToExit && !insideWall && nearFire; } createCivilian(civX, civY); } // Create firefighter firefighter = new Firefighter(); firefighter.x = 200; firefighter.y = 2500; game.addChild(firefighter); } function createLayout(layoutType) { // Create fire station fireStation = new FireStation(200, 2500); game.addChild(fireStation); // Create exit exit = new Exit(1800, 200); game.addChild(exit); // Create walls based on layout type switch (layoutType) { case 'basic': // Simple wall layout createWall(1024, 1366, 800, 50); // Center horizontal wall createWall(600, 1000, 600, 50); // Left horizontal wall createWall(1400, 1700, 600, 50); // Right horizontal wall break; case 'apartment': // Apartment-like layout createWall(300, 800, 600, 50); // Upper left horizontal createWall(1300, 800, 500, 50); // Upper right horizontal createWall(500, 1400, 600, 50); // Lower left horizontal createWall(1300, 1400, 600, 50); // Lower right horizontal createWall(800, 800, 40, 600); // Center vertical createWall(1100, 1800, 40, 800); // Lower center vertical break; case 'office': // Office building layout createWall(500, 600, 1000, 50); // Top horizontal createWall(800, 1000, 600, 50); // Middle horizontal 1 createWall(1300, 1400, 400, 50); // Middle horizontal 2 createWall(1000, 1800, 1000, 50); // Bottom horizontal createWall(500, 600, 40, 800); // Left vertical createWall(1500, 600, 40, 800); // Right vertical createWall(1000, 1400, 40, 400); // Bottom vertical break; default: // Random maze-like layout var wallCount = 6 + Math.floor(Math.random() * 6); // 6-12 walls for (var i = 0; i < wallCount; i++) { var horizontal = Math.random() > 0.5; var x, y, width, height; if (horizontal) { width = 400 + Math.random() * 800; height = 40; x = 200 + Math.random() * (2048 - 400 - width); y = 400 + Math.random() * (2732 - 800); } else { width = 40; height = 400 + Math.random() * 800; x = 400 + Math.random() * (2048 - 800); y = 200 + Math.random() * (2732 - 400 - height); } // Don't block firefighter start or exit var blocksFirefighter = willCollide(x, y, width, height, 200, 2500, 200, 200); var blocksExit = willCollide(x, y, width, height, 1800, 200, 150, 100); if (!blocksFirefighter && !blocksExit) { createWall(x, y, width, height); } } break; } } function createUI() { // Score text scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); LK.gui.topRight.addChild(scoreTxt); // Level text levelTxt = new Text2('Level: ' + level, { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.top.addChild(levelTxt); // Time bar timeBarContainer = new Container(); timeBarBg = timeBarContainer.attachAsset('timeBarBg', { anchorX: 0, anchorY: 0.5 }); timeBarFill = timeBarContainer.attachAsset('timeBar', { anchorX: 0, anchorY: 0.5 }); timeBarFill.width = 400; // Start full timeBarContainer.addChild(timeBarBg); timeBarContainer.addChild(timeBarFill); var timeLabel = new Text2('TIME', { size: 30, fill: 0xFFFFFF }); timeLabel.anchor.set(0.5, 0.5); timeLabel.x = 200; timeBarContainer.addChild(timeLabel); timeBarContainer.x = -200; timeBarContainer.y = 100; LK.gui.top.addChild(timeBarContainer); // Water bar waterBarContainer = new Container(); waterBarBg = waterBarContainer.attachAsset('waterBarBg', { anchorX: 0, anchorY: 0.5 }); waterBarFill = waterBarContainer.attachAsset('waterBar', { anchorX: 0, anchorY: 0.5 }); waterBarFill.width = 400; // Start full waterBarContainer.addChild(waterBarBg); waterBarContainer.addChild(waterBarFill); var waterLabel = new Text2('WATER', { size: 30, fill: 0xFFFFFF }); waterLabel.anchor.set(0.5, 0.5); waterLabel.x = 200; waterBarContainer.addChild(waterLabel); waterBarContainer.x = -200; waterBarContainer.y = 160; LK.gui.top.addChild(waterBarContainer); // Instructions container instructionsContainer = new Container(); var instructionsBg = instructionsContainer.attachAsset('waterBarBg', { anchorX: 0.5, anchorY: 0.5, width: 1600, height: 400, alpha: 0.8 }); instructionsTxt = new Text2('Drag to move firefighter\nTap and hold to spray water\nRescue civilians and extinguish fires!', { size: 70, fill: 0xFFFFFF }); instructionsTxt.anchor.set(0.5, 0.5); instructionsContainer.addChild(instructionsTxt); instructionsContainer.x = 1024; instructionsContainer.y = 1366; instructionsContainer.visible = false; game.addChild(instructionsContainer); } function showInstructions() { instructionsContainer.visible = true; LK.setTimeout(function () { instructionsContainer.visible = false; }, 5000); } function startGameTimer() { var timeRemaining = gameTime; updateTimeBar(timeRemaining / gameTime); gameTimer = LK.setInterval(function () { timeRemaining--; updateTimeBar(timeRemaining / gameTime); if (timeRemaining <= 0) { LK.clearInterval(gameTimer); LK.effects.flashScreen(0xff0000, 500); LK.showGameOver(); } }, 1000); } function updateTimeBar(percentage) { timeBarFill.width = Math.max(0, 400 * percentage); // Change color as time runs out if (percentage < 0.2) { timeBarFill.tint = 0xff0000; // Red } else if (percentage < 0.5) { timeBarFill.tint = 0xffff00; // Yellow } else { timeBarFill.tint = 0xff9900; // Orange } } function updateWaterBar() { var percentage = firefighter.waterLevel / firefighter.maxWaterLevel; waterBarFill.width = Math.max(0, 400 * percentage); // Change color as water runs out if (percentage < 0.2) { waterBarFill.tint = 0xff0000; // Red } else if (percentage < 0.5) { waterBarFill.tint = 0xff9900; // Orange } else { waterBarFill.tint = 0x0000ff; // Blue } } function updateScoreText() { scoreTxt.setText('Score: ' + LK.getScore()); } function checkLevelComplete() { if (civiliansRescued >= totalCivilians) { // Level complete LK.clearInterval(gameTimer); LK.getSound('levelComplete').play(); // Award time bonus var timeRemaining = timeBarFill.width / 400 * gameTime; var timeBonus = Math.floor(timeRemaining * 10); LK.setScore(LK.getScore() + timeBonus); // Update highest level reached level++; storage.currentLevel = level; if (level > storage.highestLevel) { storage.highestLevel = level; } // Show win screen LK.showYouWin(); } } // Helper functions function createFire(x, y) { var fire = new Fire(x, y); game.addChild(fire); fires.push(fire); return fire; } function createCivilian(x, y) { var civilian = new Civilian(x, y); game.addChild(civilian); civilians.push(civilian); return civilian; } function createWall(x, y, width, height) { var wall = new Wall(x, y, width, height); game.addChild(wall); walls.push(wall); return wall; } function createWaterParticle(x, y) { // Create water spray in the direction the firefighter is facing var particleX = x + Math.random() * 40 - 20; var particleY = y - 50; // Spray from the top of the firefighter var particle = new WaterParticle(particleX, particleY); game.addChild(particle); waterParticles.push(particle); // Create smoke occasionally if (LK.ticks % 10 === 0) { createSmokeParticle(x, y); } // Play spray sound occasionally if (LK.ticks % 30 === 0) { LK.getSound('spray').play(); } return particle; } function createSmokeParticle(x, y) { var smoke = new Smoke(x + Math.random() * 60 - 30, y - 50); game.addChild(smoke); smokeParticles.push(smoke); return smoke; } function createWaterPickup() { // Use the global distance function instead of defining it here // Find a valid position for the water pickup var pickupX, pickupY; var validPosition = false; var preferredPlacement = Math.random(); while (!validPosition) { // Try to place water pickups strategically if (fires.length > 0 && preferredPlacement < 0.5) { // Place near fires (but not too close) var randomFire = fires[Math.floor(Math.random() * fires.length)]; var angle = Math.random() * Math.PI * 2; var dist = 250 + Math.random() * 150; pickupX = randomFire.x + Math.cos(angle) * dist; pickupY = randomFire.y + Math.sin(angle) * dist; } else if (civilians.length > 0 && preferredPlacement >= 0.5 && preferredPlacement < 0.8) { // Place near civilians that need rescue var unrescuedCivilians = civilians.filter(function (civ) { return !civ.isRescued; }); if (unrescuedCivilians.length > 0) { var randomCivilian = unrescuedCivilians[Math.floor(Math.random() * unrescuedCivilians.length)]; var angle = Math.random() * Math.PI * 2; var dist = 200 + Math.random() * 100; pickupX = randomCivilian.x + Math.cos(angle) * dist; pickupY = randomCivilian.y + Math.sin(angle) * dist; } else { pickupX = 300 + Math.random() * (2048 - 600); pickupY = 300 + Math.random() * (2732 - 600); } } else { // Random placement pickupX = 300 + Math.random() * (2048 - 600); pickupY = 300 + Math.random() * (2732 - 600); } // Keep within game bounds pickupX = Math.max(100, Math.min(pickupX, 2048 - 100)); pickupY = Math.max(100, Math.min(pickupY, 2732 - 100)); // Check if too close to firefighter or other objects var tooCloseToFirefighter = distance(pickupX, pickupY, firefighter.x, firefighter.y) < 200; var tooCloseToFireStation = fireStation && distance(pickupX, pickupY, fireStation.x, fireStation.y) < 300; var tooCloseToExit = exit && distance(pickupX, pickupY, exit.x, exit.y) < 300; // Check if inside any wall var insideWall = false; for (var j = 0; j < walls.length; j++) { if (willCollide(pickupX, pickupY, 60, 60, walls[j].x, walls[j].y, walls[j].width, walls[j].height)) { insideWall = true; break; } } // Check if not too close to existing pickups var tooCloseToPickup = false; for (var j = 0; j < waterPickups.length; j++) { if (distance(pickupX, pickupY, waterPickups[j].x, waterPickups[j].y) < 300) { tooCloseToPickup = true; break; } } validPosition = !tooCloseToFirefighter && !tooCloseToFireStation && !tooCloseToExit && !insideWall && !tooCloseToPickup; } var waterPickup = new WaterPickup(pickupX, pickupY); game.addChild(waterPickup); waterPickups.push(waterPickup); return waterPickup; } function distance(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } function willCollide(x1, y1, w1, h1, x2, y2, w2, h2) { return !(x1 + w1 / 2 < x2 - w2 / 2 || x1 - w1 / 2 > x2 + w2 / 2 || y1 + h1 / 2 < y2 - h2 / 2 || y1 - h1 / 2 > y2 + h2 / 2); } // Input handlers game.down = function (x, y, obj) { // Start dragging joystickActive = true; joystickOrigin.x = x; joystickOrigin.y = y; joystickPosition.x = x; joystickPosition.y = y; // If tapping close to the firefighter, start spraying water var dx = x - firefighter.x; var dy = y - firefighter.y; var distToFirefighter = Math.sqrt(dx * dx + dy * dy); if (distToFirefighter < 200) { firefighter.isSprayingWater = true; } // Check for civilian pickup if (!firefighter.carryingCivilian) { for (var i = 0; i < civilians.length; i++) { var civilian = civilians[i]; if (!civilian.isRescued && distance(firefighter.x, firefighter.y, civilian.x, civilian.y) < 100) { firefighter.carryingCivilian = civilian; LK.getSound('rescue').play(); break; } } } }; game.move = function (x, y, obj) { if (joystickActive) { joystickPosition.x = x; joystickPosition.y = y; var dx = x - joystickOrigin.x; var dy = y - joystickOrigin.y; // Calculate direction vector var length = Math.sqrt(dx * dx + dy * dy); if (length > 0) { firefighter.direction.x = dx / length; firefighter.direction.y = dy / length; } } }; game.up = function (x, y, obj) { joystickActive = false; firefighter.direction.x = 0; firefighter.direction.y = 0; firefighter.isSprayingWater = false; }; // Main game update loop game.update = function () { // Update firefighter if (firefighter) { firefighter.update(); } // Update fires for (var i = fires.length - 1; i >= 0; i--) { if (fires[i].isDestroyed) { fires.splice(i, 1); } else { fires[i].update(); } } // Update civilians for (var i = 0; i < civilians.length; i++) { if (!civilians[i].isRescued) { civilians[i].update(); } } // Update water particles for (var i = waterParticles.length - 1; i >= 0; i--) { if (waterParticles[i].isDestroyed) { waterParticles.splice(i, 1); } else { waterParticles[i].update(); } } // Update smoke particles for (var i = smokeParticles.length - 1; i >= 0; i--) { if (smokeParticles[i].isDestroyed) { smokeParticles.splice(i, 1); } else { smokeParticles[i].update(); } } // Create smoke from fires if (LK.ticks % 30 === 0) { for (var i = 0; i < fires.length; i++) { if (Math.random() < 0.3) { createSmokeParticle(fires[i].x, fires[i].y); } } } }; // Initialize the game initGame();
===================================================================
--- original.js
+++ change.js
@@ -104,58 +104,18 @@
}
};
return self;
});
-var Wall = GameObject.expand(function (x, y, width, height, material) {
+var Wall = GameObject.expand(function (x, y, width, height) {
var self = GameObject.call(this, 'wall', width, height);
- // Different wall materials
- var materials = {
- 'concrete': {
- tint: 0x808080,
- alpha: 1.0
- },
- 'wood': {
- tint: 0xcd853f,
- alpha: 1.0
- },
- 'brick': {
- tint: 0xb22222,
- alpha: 1.0
- },
- 'glass': {
- tint: 0xadd8e6,
- alpha: 0.7
- }
- };
- // Default to concrete if no material specified
- material = materials[material] || materials.concrete;
var graphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
width: width,
- height: height,
- tint: material.tint,
- alpha: material.alpha
+ height: height
});
self.x = x;
self.y = y;
- // Add texture variation to walls
- if (width > 100 && height > 100) {
- // For large wall surfaces, add texture details
- var detailCount = Math.floor(width * height / 10000);
- for (var i = 0; i < detailCount; i++) {
- var detail = self.attachAsset('wall', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: width * 0.1,
- height: height * 0.1,
- tint: material.tint - 0x111111,
- alpha: material.alpha * 0.8,
- x: (Math.random() - 0.5) * width * 0.7,
- y: (Math.random() - 0.5) * height * 0.7
- });
- }
- }
return self;
});
var Smoke = GameObject.expand(function (x, y) {
var self = GameObject.call(this, 'smoke', 200, 200);
@@ -370,17 +330,17 @@
self.y = y;
// Make exit pulse to draw attention
function pulseAnimation() {
tween(graphics.scale, {
- x: 1.1,
- y: 1.1
+ x: 1.3,
+ y: 1.3
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(graphics.scale, {
- x: 1.0,
- y: 1.0
+ x: 1.2,
+ y: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: pulseAnimation
@@ -439,53 +399,8 @@
}
};
return self;
});
-var BuildingTile = GameObject.expand(function (x, y, type) {
- var self = GameObject.call(this, 'buildingTile', 200, 200);
- // Different building element types with their specific properties
- var tileTypes = {
- 'floor': {
- color: 0x8b4513,
- alpha: 0.9
- },
- 'ceiling': {
- color: 0xa0522d,
- alpha: 0.85
- },
- 'woodenWall': {
- color: 0xcd853f,
- alpha: 1.0
- },
- 'concreteWall': {
- color: 0x808080,
- alpha: 1.0
- },
- 'window': {
- color: 0xadd8e6,
- alpha: 0.7
- },
- 'door': {
- color: 0x654321,
- alpha: 1.0
- }
- };
- // Use predefined type or default to floor
- type = tileTypes[type] || tileTypes.floor;
- // Create a shape for the building element
- var graphics = self.attachAsset('wall', {
- anchorX: 0.5,
- anchorY: 0.5,
- tint: type.color,
- alpha: type.alpha
- });
- // Different scale based on the building element size
- var scale = 0.3 + Math.random() * 0.1;
- graphics.scale.set(scale, scale);
- self.x = x;
- self.y = y;
- return self;
-});
/****
* Initialize Game
****/
@@ -733,94 +648,33 @@
game.addChild(exit);
// Create walls based on layout type
switch (layoutType) {
case 'basic':
- // Simple house layout with building elements
- // Floor and ceiling tiles
- for (var x = 700; x <= 1300; x += 180) {
- for (var y = 1100; y <= 1600; y += 180) {
- game.addChild(new BuildingTile(x, y, 'floor'));
- }
- game.addChild(new BuildingTile(x, 1000, 'ceiling'));
- game.addChild(new BuildingTile(x, 1700, 'ceiling'));
- }
- // Main walls
+ // Simple wall layout
createWall(1024, 1366, 800, 50); // Center horizontal wall
createWall(600, 1000, 600, 50); // Left horizontal wall
createWall(1400, 1700, 600, 50); // Right horizontal wall
- // Add windows and doors to walls
- game.addChild(new BuildingTile(800, 1000, 'window'));
- game.addChild(new BuildingTile(1200, 1000, 'window'));
- game.addChild(new BuildingTile(1000, 1700, 'door'));
break;
case 'apartment':
- // Apartment-like layout with building elements
- // Create floor and ceiling tiles
- for (var x = 300; x <= 1600; x += 180) {
- for (var y = 850; y <= 1350; y += 180) {
- game.addChild(new BuildingTile(x, y, 'floor'));
- }
- game.addChild(new BuildingTile(x, 750, 'ceiling'));
- game.addChild(new BuildingTile(x, 1450, 'ceiling'));
- }
- // Main walls
+ // Apartment-like layout
createWall(300, 800, 600, 50); // Upper left horizontal
createWall(1300, 800, 500, 50); // Upper right horizontal
createWall(500, 1400, 600, 50); // Lower left horizontal
createWall(1300, 1400, 600, 50); // Lower right horizontal
createWall(800, 800, 40, 600); // Center vertical
createWall(1100, 1800, 40, 800); // Lower center vertical
- // Add windows
- game.addChild(new BuildingTile(500, 800, 'window'));
- game.addChild(new BuildingTile(1400, 800, 'window'));
- // Add doors to room dividers
- game.addChild(new BuildingTile(800, 1000, 'door'));
- game.addChild(new BuildingTile(1100, 1600, 'door'));
break;
case 'office':
- // Office building layout with building elements
- // Create floor and ceiling grid
- for (var x = 500; x <= 1500; x += 180) {
- for (var y = 650; y <= 1750; y += 180) {
- game.addChild(new BuildingTile(x, y, 'floor'));
- }
- // Ceiling elements
- game.addChild(new BuildingTile(x, 550, 'ceiling'));
- game.addChild(new BuildingTile(x, 1850, 'ceiling'));
- }
- // Main structural walls
+ // Office building layout
createWall(500, 600, 1000, 50); // Top horizontal
createWall(800, 1000, 600, 50); // Middle horizontal 1
createWall(1300, 1400, 400, 50); // Middle horizontal 2
createWall(1000, 1800, 1000, 50); // Bottom horizontal
createWall(500, 600, 40, 800); // Left vertical
createWall(1500, 600, 40, 800); // Right vertical
createWall(1000, 1400, 40, 400); // Bottom vertical
- // Add windows to exterior walls
- game.addChild(new BuildingTile(700, 600, 'window'));
- game.addChild(new BuildingTile(1300, 600, 'window'));
- game.addChild(new BuildingTile(500, 900, 'window'));
- game.addChild(new BuildingTile(1500, 900, 'window'));
- // Add office doors
- game.addChild(new BuildingTile(800, 900, 'door'));
- game.addChild(new BuildingTile(1300, 1300, 'door'));
- game.addChild(new BuildingTile(1000, 1600, 'door'));
break;
default:
- // Random building layout with structured elements
- // Create a base floor grid
- for (var x = 400; x <= 1600; x += 250) {
- for (var y = 500; y <= 2000; y += 250) {
- // Only create floor/ceiling in areas that make sense as interior spaces
- if (Math.random() < 0.7) {
- game.addChild(new BuildingTile(x, y, 'floor'));
- // Occasionally add ceiling elements
- if (Math.random() < 0.3) {
- game.addChild(new BuildingTile(x, y - 50, 'ceiling'));
- }
- }
- }
- }
// Random maze-like layout
var wallCount = 6 + Math.floor(Math.random() * 6); // 6-12 walls
for (var i = 0; i < wallCount; i++) {
var horizontal = Math.random() > 0.5;
@@ -840,21 +694,8 @@
var blocksFirefighter = willCollide(x, y, width, height, 200, 2500, 200, 200);
var blocksExit = willCollide(x, y, width, height, 1800, 200, 150, 100);
if (!blocksFirefighter && !blocksExit) {
createWall(x, y, width, height);
- // Add windows and doors to some walls
- if (horizontal && width > 300 && Math.random() < 0.4) {
- // Add windows along horizontal walls
- var numWindows = Math.floor(width / 250);
- for (var w = 1; w <= numWindows; w++) {
- if (Math.random() < 0.7) {
- game.addChild(new BuildingTile(x - width / 2 + w * (width / (numWindows + 1)), y, 'window'));
- }
- }
- } else if (!horizontal && height > 300 && Math.random() < 0.4) {
- // Add doors to some vertical walls
- game.addChild(new BuildingTile(x, y + height / 4, Math.random() < 0.7 ? 'door' : 'window'));
- }
}
}
break;
}
@@ -1016,27 +857,10 @@
game.addChild(civilian);
civilians.push(civilian);
return civilian;
}
-function createWall(x, y, width, height, material) {
- // Choose appropriate material based on dimensions and position
- if (!material) {
- if (width > height * 5) {
- // Very wide walls are likely ceilings or floors
- material = 'concrete';
- } else if (height > width * 5) {
- // Very tall walls are likely structural supports
- material = 'concrete';
- } else if (width < 60 || height < 60) {
- // Thin walls are likely wooden dividers
- material = 'wood';
- } else {
- // Other walls get random materials
- var materials = ['concrete', 'wood', 'brick'];
- material = materials[Math.floor(Math.random() * materials.length)];
- }
- }
- var wall = new Wall(x, y, width, height, material);
+function createWall(x, y, width, height) {
+ var wall = new Wall(x, y, width, height);
game.addChild(wall);
walls.push(wall);
return wall;
}
full size civilian Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
fire. Single Game Texture. In-Game asset. 2d. Blank background. No shadows
firestation. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
horizontal wall. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
smoke. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
water drop Single Game Texture. In-Game asset. 2d. Blank background. No shadows
firefighter using fire extinguisher Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Exit Gate. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows