User prompt
que el jugador vaya a donde se de click en la pantalla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ahora coloca arboles aleatorios en todo el mapa
User prompt
que fuera del mapa en las zonas que sobresalen sean del mismo color de el fondo
User prompt
que la camara no vaya mas alla de los arboles del borde del mapa ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que la camara no sobresalga mas alla de los bordes del mapa ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
la camara un poco mas cerca y que la camara no sobresalga mas alla de el mapa ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que la camara este mas cerca de el jugador y lo siga hacia donde se mueva
User prompt
quiero que pongas arboles rodeando todos los bordes
User prompt
crea un mapa grande por el que se pueda mover el jugador pero solo el piso ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el jugador se vea sobre la el fondo
User prompt
quiero que el mapa sea grande pero que no se vea todo en la pantalla y se muestre solo la zona en la que esta el jugador pero que segun el movimiento del jugador la camara lo siga atravez del mapa ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
quiero que hallan edificios silumando una calle por donde el jugador no pueda pasar
User prompt
que el jugador mire primero hacia el destino y se mueva ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que mire directamente hacia el punto que se señala segun el click ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el jugador gire hacia donde se mueve ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el personaje no siga el toque de la pantalla sino que silla el click unico que de haga ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el personaje se mueva mas lento ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
elimina todo y deja solo al jugador en un plano en que pueda moverse de manera vertical y horizontal
User prompt
el jugador aun no va a donde se toca la pantalla
User prompt
que el jugador vaya a donde se toque la pantalla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el jugador se mueva segun en donde se toque la pantalla
Code edit (1 edits merged)
Please save this source code
User prompt
Survivor's Quest
Initial prompt
Quiero hacer un juego de supervivencia en el que tenemos que conseguir recursos y almacenarlos para sobrevivir a través de un escenario por el que podamos movernos vertical y horizontalmente desde un plano de vista de 45 grados.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Arrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('flecha', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 100; // Distance from player center return self; }); var Arrow2 = Container.expand(function () { var self = Container.call(this); var arrow2Graphics = self.attachAsset('flecha2', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 100; // Distance from player center return self; }); var Battery = Container.expand(function () { var self = Container.call(this); var batteryGraphics = self.attachAsset('bateria', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemigo', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 50; // Enemy movement speed - increased for faster gameplay self.chaseDelay = 1000; // Time between chase movements self.chasePlayer = function () { var deltaX = player.x - self.x; var deltaY = player.y - self.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared > 2500) { // 50 * 50 - avoid sqrt when possible var distance = Math.sqrt(distanceSquared); // Calculate movement direction var directionX = deltaX / distance; var directionY = deltaY / distance; // Move continuously towards player with dynamic speed based on avoidance var baseSpeed = 4.5; // Base movement speed - reduced by 0.5 for slower movement var moveSpeed = baseSpeed; // Increase speed when avoiding trees for more responsive movement if (avoidanceForce > 0) { moveSpeed = baseSpeed * 2.5; // 150% speed increase when avoiding trees for better evasion } // Tree avoidance logic with increased responsiveness var avoidanceX = 0; var avoidanceY = 0; var lookAheadDistance = 150; // Further increased look-ahead distance for much earlier detection var avoidanceForce = 0; // Check for trees in movement path with multiple prediction points var futureX = self.x + directionX * lookAheadDistance; var futureY = self.y + directionY * lookAheadDistance; // Also check current position for immediate threats var immediateX = self.x + directionX * 30; var immediateY = self.y + directionY * 30; // Check nearby trees for potential collisions for (var t = 0; t < allTrees.length; t++) { var tree = allTrees[t]; // Check both future and immediate positions var treeDeltaX = tree.x - futureX; var treeDeltaY = tree.y - futureY; var treeDistanceSquared = treeDeltaX * treeDeltaX + treeDeltaY * treeDeltaY; var avoidanceRadius = 100; // Reduced avoidance radius for smaller avoidance area // Also check immediate threat var immediateDeltaX = tree.x - immediateX; var immediateDeltaY = tree.y - immediateY; var immediateDistanceSquared = immediateDeltaX * immediateDeltaX + immediateDeltaY * immediateDeltaY; var immediateRadius = 80; // Reduced immediate radius for smaller close-range avoidance // Use the closer threat for avoidance calculation var useImmediate = immediateDistanceSquared < immediateRadius * immediateRadius; var finalDeltaX = useImmediate ? immediateDeltaX : treeDeltaX; var finalDeltaY = useImmediate ? immediateDeltaY : treeDeltaY; var finalDistanceSquared = useImmediate ? immediateDistanceSquared : treeDistanceSquared; var finalRadius = useImmediate ? immediateRadius : avoidanceRadius; if (finalDistanceSquared < finalRadius * finalRadius) { var treeDistance = Math.sqrt(finalDistanceSquared); if (treeDistance > 0) { // Calculate avoidance direction (perpendicular to tree direction) var avoidanceStrength = (finalRadius - treeDistance) / finalRadius; // Increase avoidance strength for immediate threats if (useImmediate) { avoidanceStrength *= 2.5; // Much stronger avoidance for immediate threats } var treeAvoidX = finalDeltaX / treeDistance * avoidanceStrength; var treeAvoidY = finalDeltaY / treeDistance * avoidanceStrength; // Add perpendicular avoidance force with increased magnitude avoidanceX += treeAvoidY * 2.0; // Further increased avoidance force for better evasion avoidanceY -= treeAvoidX * 2.0; avoidanceForce += avoidanceStrength; } } } // Normalize avoidance force if (avoidanceForce > 0) { avoidanceX /= avoidanceForce; avoidanceY /= avoidanceForce; // Increased blend factor for stronger avoidance var blendFactor = Math.min(avoidanceForce, 0.95); // Increased from 0.8 to 0.95 directionX = directionX * (1 - blendFactor) + avoidanceX * blendFactor; directionY = directionY * (1 - blendFactor) + avoidanceY * blendFactor; // Renormalize direction var newDistance = Math.sqrt(directionX * directionX + directionY * directionY); if (newDistance > 0) { directionX /= newDistance; directionY /= newDistance; } } self.x += directionX * moveSpeed; self.y += directionY * moveSpeed; // Keep enemy within bounds self.x = Math.max(80, Math.min(1968, self.x)); self.y = Math.max(120, Math.min(2612, self.y)); // Rotate to face movement direction smoothly (only every 2 frames for performance) if (LK.ticks % 2 === 0) { var targetRotation = Math.atan2(directionY, directionX) + Math.PI / 2; var rotationDiff = targetRotation - self.rotation; // Normalize rotation difference to [-PI, PI] while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI; while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI; // Smooth rotation self.rotation += rotationDiff * 0.1; } } }; return self; }); var Factory = Container.expand(function () { var self = Container.call(this); var factoryGraphics = self.attachAsset('fabrica', { anchorX: 0.5, anchorY: 0.5 }); self.spawnTimer = 0; self.spawnDelay = 480; // Spawn enemy every 8 seconds (480 frames at 60fps) self.spawnEnemy = function () { var newEnemy = new Enemy(); newEnemy.x = self.x; newEnemy.y = self.y; enemies.push(newEnemy); camera.addChild(newEnemy); }; self.update = function () { self.spawnTimer++; if (self.spawnTimer >= self.spawnDelay) { self.spawnEnemy(); self.spawnTimer = 0; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = self.attachAsset('escudo', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Wheel = Container.expand(function () { var self = Container.call(this); var wheelGraphics = self.attachAsset('rueda', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x4a7c59 }); /**** * Game Code ****/ // Create extended background that covers the entire visible area including camera zoom var extendedBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 40.96, // Double scale to cover zoomed view (2048*2/100) scaleY: 54.64, // Double scale to cover zoomed view (2732*2/100) x: -2048, // Offset to center the extended background y: -2732 // Offset to center the extended background })); // Create additional background for right side var rightBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover additional right area scaleY: 27.32, // Scale to cover full height x: 2048, // Position to the right of main map y: 0 })); // Create additional background for bottom side var bottomBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover full width scaleY: 27.32, // Scale to cover additional bottom area x: 0, y: 2732 // Position below main map })); // Create additional background for top-right corner var topRightBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover corner area scaleY: 27.32, // Scale to cover corner area x: 2048, // Position to the right y: -2732 // Position above main map })); // Create additional background for bottom-right corner var bottomRightBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover corner area scaleY: 27.32, // Scale to cover corner area x: 2048, // Position to the right y: 2732 // Position below main map })); // Create additional background for bottom-left corner var bottomLeftBackground = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover corner area scaleY: 27.32, // Scale to cover corner area x: -2048, // Position to the left y: 2732 // Position below main map })); // Create large map floor - scale the grass background to cover entire game area var mapFloor = game.addChild(LK.getAsset('fondo', { anchorX: 0, anchorY: 0, scaleX: 20.48, // Scale to cover 2048px width (2048/100) scaleY: 27.32, // Scale to cover 2732px height (2732/100) x: 0, y: 0 })); // Create trees around all borders var trees = []; // Top border trees for (var i = 0; i < 26; i++) { var topTree = game.addChild(LK.getAsset('arbol', { anchorX: 0.5, anchorY: 0.5, x: i * 80 + 40, y: 60 })); trees.push(topTree); } // Bottom border trees for (var i = 0; i < 26; i++) { var bottomTree = game.addChild(LK.getAsset('arbol', { anchorX: 0.5, anchorY: 0.5, x: i * 80 + 40, y: 2672 })); trees.push(bottomTree); } // Left border trees (excluding corners already covered) for (var i = 1; i < 33; i++) { var leftTree = game.addChild(LK.getAsset('arbol', { anchorX: 0.5, anchorY: 0.5, x: 40, y: i * 80 + 60 })); trees.push(leftTree); } // Right border trees (excluding corners already covered) for (var i = 1; i < 33; i++) { var rightTree = game.addChild(LK.getAsset('arbol', { anchorX: 0.5, anchorY: 0.5, x: 2008, y: i * 80 + 60 })); trees.push(rightTree); } // Create camera container for following player var camera = game.addChild(new Container()); camera.x = 1024; camera.y = 1366; // Move all game elements to camera container camera.addChild(extendedBackground); camera.addChild(rightBackground); camera.addChild(bottomBackground); camera.addChild(topRightBackground); camera.addChild(bottomRightBackground); camera.addChild(bottomLeftBackground); camera.addChild(mapFloor); for (var i = 0; i < trees.length; i++) { camera.addChild(trees[i]); } // Add random trees scattered throughout the map var randomTrees = []; // Define factory positions for exclusion zones var factoryPositions = [{ x: 400, y: 400 }, // top-left { x: 1648, y: 400 }, // top-right { x: 400, y: 2332 }, // bottom-left { x: 1648, y: 2332 } // bottom-right ]; var exclusionRadius = 400; // Distance to keep trees away from factories - increased for better separation for (var i = 0; i < 45; i++) { var validPosition = false; var randomX, randomY; var attempts = 0; var maxAttempts = 50; // Keep trying until we find a valid position away from factories while (!validPosition && attempts < maxAttempts) { randomX = Math.random() * (2048 - 120) + 60; // Closer to borders randomY = Math.random() * (2732 - 180) + 90; // Closer to borders validPosition = true; // Check distance from all factories for (var j = 0; j < factoryPositions.length; j++) { var factoryX = factoryPositions[j].x; var factoryY = factoryPositions[j].y; var deltaX = randomX - factoryX; var deltaY = randomY - factoryY; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var exclusionRadiusSquared = exclusionRadius * exclusionRadius; if (distanceSquared < exclusionRadiusSquared) { validPosition = false; break; } } // Check distance from existing random trees to ensure separation var minTreeDistance = 200; // Minimum distance between trees var minTreeDistanceSquared = minTreeDistance * minTreeDistance; for (var k = 0; k < randomTrees.length; k++) { var existingTree = randomTrees[k]; var treeDeltaX = randomX - existingTree.x; var treeDeltaY = randomY - existingTree.y; var treeDistanceSquared = treeDeltaX * treeDeltaX + treeDeltaY * treeDeltaY; if (treeDistanceSquared < minTreeDistanceSquared) { validPosition = false; break; } } attempts++; } // Only create tree if we found a valid position if (validPosition) { var randomTree = camera.addChild(LK.getAsset('arbol', { anchorX: 0.5, anchorY: 0.5, x: randomX, y: randomY })); randomTrees.push(randomTree); } } // Cache all trees for optimized collision detection var allTrees = trees.concat(randomTrees); // Create player and add to camera var player = camera.addChild(new Player()); player.x = 1024; player.y = 1366; // Create arrow and add to camera var arrow = camera.addChild(new Arrow()); arrow.visible = false; // Initially hidden until battery spawns // Create arrow2 for special items and add to camera var arrow2 = camera.addChild(new Arrow2()); arrow2.visible = false; // Initially hidden until special item spawns // Create 3 lightning bolts in top-left corner of screen var lightning1 = LK.gui.topLeft.addChild(LK.getAsset('rayo', { anchorX: 0.5, anchorY: 0.5, x: 150, y: 100 })); var lightning2 = LK.gui.topLeft.addChild(LK.getAsset('rayo', { anchorX: 0.5, anchorY: 0.5, x: 250, y: 100 })); var lightning3 = LK.gui.topLeft.addChild(LK.getAsset('rayo', { anchorX: 0.5, anchorY: 0.5, x: 350, y: 100 })); // Lightning management var lightningBolts = [lightning1, lightning2, lightning3]; var lightningTimer = 0; var lightningDelay = 420; // 7 seconds at 60fps var activeLightning = 3; // Start with 3 active lightning bolts // Create timer display in top center of screen var timerText = new Text2('00:00', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // Timer variables var gameTimer = 0; // Timer in frames (60fps) // Create 5 lives in top-right corner of screen var life1 = LK.gui.topRight.addChild(LK.getAsset('vida', { anchorX: 0.5, anchorY: 0.5, x: -50, y: 100 })); var life2 = LK.gui.topRight.addChild(LK.getAsset('vida', { anchorX: 0.5, anchorY: 0.5, x: -150, y: 100 })); var life3 = LK.gui.topRight.addChild(LK.getAsset('vida', { anchorX: 0.5, anchorY: 0.5, x: -250, y: 100 })); var life4 = LK.gui.topRight.addChild(LK.getAsset('vida', { anchorX: 0.5, anchorY: 0.5, x: -350, y: 100 })); // Hearts management var hearts = [life1, life2, life3, life4]; var activeHearts = 4; // Start with 4 active hearts // Create enemies array var enemies = []; // Create batteries array var batteries = []; // Battery spawn timer var batterySpawnTimer = 600; // Start ready to spawn immediately var batterySpawnDelay = 600; // Spawn battery every 10 seconds (600 frames at 60fps) // Create special items arrays var wheels = []; var shields = []; // Special item spawn timer var itemSpawnTimer = 0; var itemSpawnMinDelay = 600; // 10 seconds minimum (600 frames at 60fps) var itemSpawnMaxDelay = 900; // 15 seconds maximum (900 frames at 60fps) var itemSpawnDelay = Math.random() * (itemSpawnMaxDelay - itemSpawnMinDelay) + itemSpawnMinDelay; // Item collection cooldown tracking var itemCollectionCooldown = 0; // Timer to prevent item spawning after collection var itemCollectionCooldownDelay = 720; // 12 seconds (720 frames at 60fps) // Create factories array var factories = []; // Create factory in top-left corner var topLeftFactory = camera.addChild(new Factory()); topLeftFactory.x = 400; topLeftFactory.y = 400; factories.push(topLeftFactory); // Create factory in top-right corner var topRightFactory = camera.addChild(new Factory()); topRightFactory.x = 1648; topRightFactory.y = 400; factories.push(topRightFactory); // Create factory in bottom-left corner var bottomLeftFactory = camera.addChild(new Factory()); bottomLeftFactory.x = 400; bottomLeftFactory.y = 2332; factories.push(bottomLeftFactory); // Create factory in bottom-right corner var bottomRightFactory = camera.addChild(new Factory()); bottomRightFactory.x = 1648; bottomRightFactory.y = 2332; factories.push(bottomRightFactory); // Set camera scale for closer view camera.scaleX = 2; camera.scaleY = 2; // Start playing background music LK.playMusic('si'); // Game controls - move player toward touch position var playerSpeed = 4; // Player movement speed var basePlayerSpeed = 4; // Store original speed for wheel effect var speedBoostActive = false; // Track if speed boost is active var shieldActive = false; // Track if shield immunity is active var targetX = player.x; var targetY = player.y; var isMoving = false; function updatePlayerMovement(x, y) { // Convert screen coordinates to world coordinates accounting for camera transform var worldX = (x - camera.x) / camera.scaleX; var worldY = (y - camera.y) / camera.scaleY; targetX = worldX; targetY = worldY; isMoving = true; } game.down = function (x, y, obj) { updatePlayerMovement(x, y); }; game.move = function (x, y, obj) { updatePlayerMovement(x, y); }; game.up = function (x, y, obj) { isMoving = false; }; // Main game update loop game.update = function () { // Update and display timer gameTimer++; var seconds = Math.floor(gameTimer / 60); var minutes = Math.floor(seconds / 60); seconds = seconds % 60; var timeString = (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds; timerText.setText(timeString); // Move player toward target position if moving if (isMoving) { var deltaX = targetX - player.x; var deltaY = targetY - player.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared > 25) { // 5 * 5 - avoid sqrt when possible // Only move if not close enough to target var distance = Math.sqrt(distanceSquared); // Calculate movement direction var directionX = deltaX / distance; var directionY = deltaY / distance; // Move player toward target player.x += directionX * playerSpeed; player.y += directionY * playerSpeed; // Rotate player to face movement direction var targetRotation = Math.atan2(deltaY, deltaX) + Math.PI / 2; var rotationDiff = targetRotation - player.rotation; // Normalize rotation difference to [-PI, PI] while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI; while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI; // Smooth rotation player.rotation += rotationDiff * 0.15; } } // Check player-tree collisions before finalizing movement var playerCollisionDetected = false; var playerRadius = 25; // Player collision radius var treeRadius = 40; // Tree collision radius var combinedRadius = playerRadius + treeRadius; var combinedRadiusSquared = combinedRadius * combinedRadius; // Check collision with all trees for (var t = 0; t < allTrees.length; t++) { var tree = allTrees[t]; var deltaX = player.x - tree.x; var deltaY = player.y - tree.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < combinedRadiusSquared) { playerCollisionDetected = true; // Push player away from tree var distance = Math.sqrt(distanceSquared); if (distance > 0) { var pushDistance = combinedRadius - distance; var pushX = deltaX / distance * pushDistance; var pushY = deltaY / distance * pushDistance; player.x += pushX; player.y += pushY; } } } // Keep player within bounds, accounting for tree borders player.x = Math.max(80, Math.min(1968, player.x)); player.y = Math.max(120, Math.min(2612, player.y)); // Update camera position to follow player var targetCameraX = 1024 - player.x * camera.scaleX; var targetCameraY = 1366 - player.y * camera.scaleY; // Smooth camera following camera.x += (targetCameraX - camera.x) * 0.1; camera.y += (targetCameraY - camera.y) * 0.1; // Handle enemy collision detection - prevent enemies from overlapping (frame-skipped optimization) // Only run separation every 3 frames to reduce computational load if (LK.ticks % 3 === 0) { var maxChecks = Math.min(enemies.length * enemies.length / 4, 100); // Limit total checks var checksPerformed = 0; for (var i = 0; i < enemies.length && checksPerformed < maxChecks; i++) { for (var j = i + 1; j < enemies.length && checksPerformed < maxChecks; j++) { var enemy1 = enemies[i]; var enemy2 = enemies[j]; var deltaX = enemy2.x - enemy1.x; var deltaY = enemy2.y - enemy1.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var minDistanceSquared = 6400; // 80 * 80 - avoid sqrt when possible if (distanceSquared < minDistanceSquared && distanceSquared > 0) { var distance = Math.sqrt(distanceSquared); // Calculate separation force var separationForce = (80 - distance) / 2; var separationX = deltaX / distance * separationForce; var separationY = deltaY / distance * separationForce; // Push enemies apart enemy1.x -= separationX; enemy1.y -= separationY; enemy2.x += separationX; enemy2.y += separationY; // Keep enemies within bounds after separation enemy1.x = Math.max(80, Math.min(1968, enemy1.x)); enemy1.y = Math.max(120, Math.min(2612, enemy1.y)); enemy2.x = Math.max(80, Math.min(1968, enemy2.x)); enemy2.y = Math.max(120, Math.min(2612, enemy2.y)); } checksPerformed++; } } } // Update factories for (var i = 0; i < factories.length; i++) { factories[i].update(); } // Handle battery spawning batterySpawnTimer++; if (batterySpawnTimer >= batterySpawnDelay && batteries.length < 5) { var validPosition = false; var batteryX, batteryY; var attempts = 0; var maxAttempts = 50; // Find valid position for battery spawn while (!validPosition && attempts < maxAttempts) { batteryX = Math.random() * (2048 - 200) + 100; // Keep away from borders batteryY = Math.random() * (2732 - 240) + 120; // Keep away from borders validPosition = true; // Check distance from factories - increased exclusion radius for (var f = 0; f < factories.length; f++) { var factory = factories[f]; var deltaX = batteryX - factory.x; var deltaY = batteryY - factory.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var factoryExclusionRadius = 300; // Increased from 200px to 300px for better separation var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius; if (distanceSquared < factoryExclusionRadiusSquared) { validPosition = false; break; } } // Check distance from trees if (validPosition) { for (var t = 0; t < allTrees.length; t++) { var tree = allTrees[t]; var deltaX = batteryX - tree.x; var deltaY = batteryY - tree.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < 10000) { // 100px minimum distance from trees validPosition = false; break; } } } attempts++; } // Spawn battery if valid position found if (validPosition) { var newBattery = camera.addChild(new Battery()); newBattery.x = batteryX; newBattery.y = batteryY; batteries.push(newBattery); } batterySpawnTimer = 0; } // Handle special item spawning (wheel or shield) itemSpawnTimer++; // Update item collection cooldown if (itemCollectionCooldown > 0) { itemCollectionCooldown--; } if (itemSpawnTimer >= itemSpawnDelay && itemCollectionCooldown <= 0 && wheels.length === 0 && shields.length === 0) { var validPosition = false; var itemX, itemY; var attempts = 0; var maxAttempts = 50; // Find valid position for item spawn while (!validPosition && attempts < maxAttempts) { itemX = Math.random() * (2048 - 200) + 100; // Keep away from borders itemY = Math.random() * (2732 - 240) + 120; // Keep away from borders validPosition = true; // Check distance from factories for (var f = 0; f < factories.length; f++) { var factory = factories[f]; var deltaX = itemX - factory.x; var deltaY = itemY - factory.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var factoryExclusionRadius = 300; var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius; if (distanceSquared < factoryExclusionRadiusSquared) { validPosition = false; break; } } // Check distance from trees if (validPosition) { for (var t = 0; t < allTrees.length; t++) { var tree = allTrees[t]; var deltaX = itemX - tree.x; var deltaY = itemY - tree.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < 10000) { // 100px minimum distance from trees validPosition = false; break; } } } attempts++; } // Spawn item if valid position found if (validPosition) { // Randomly choose between wheel (0) or shield (1) var itemType = Math.floor(Math.random() * 2); if (itemType === 0) { // Spawn wheel var newWheel = camera.addChild(new Wheel()); newWheel.x = itemX; newWheel.y = itemY; wheels.push(newWheel); } else { // Spawn shield var newShield = camera.addChild(new Shield()); newShield.x = itemX; newShield.y = itemY; shields.push(newShield); } } // Reset timer with new random delay itemSpawnTimer = 0; itemSpawnDelay = Math.random() * (itemSpawnMaxDelay - itemSpawnMinDelay) + itemSpawnMinDelay; } // Check player-wheel collisions and collection for (var w = wheels.length - 1; w >= 0; w--) { var wheel = wheels[w]; var deltaX = player.x - wheel.x; var deltaY = player.y - wheel.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var collectionRadius = 50; // Collection radius for wheel var collectionRadiusSquared = collectionRadius * collectionRadius; if (distanceSquared < collectionRadiusSquared) { // Wheel collected - remove it wheel.destroy(); wheels.splice(w, 1); // Start item collection cooldown itemCollectionCooldown = itemCollectionCooldownDelay; // Apply speed boost for 10 seconds if (!speedBoostActive) { speedBoostActive = true; playerSpeed = basePlayerSpeed * 2; // Double the speed // Use tween to reset speed after 10 seconds var speedBoostTimer = { value: 1 }; tween(speedBoostTimer, { value: 0 }, { duration: 10000, // 10 seconds onFinish: function onFinish() { playerSpeed = basePlayerSpeed; // Reset to original speed speedBoostActive = false; } }); } } } // Check player-shield collisions and collection for (var s = shields.length - 1; s >= 0; s--) { var shield = shields[s]; var deltaX = player.x - shield.x; var deltaY = player.y - shield.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var collectionRadius = 50; // Collection radius for shield var collectionRadiusSquared = collectionRadius * collectionRadius; if (distanceSquared < collectionRadiusSquared) { // Shield collected - remove it shield.destroy(); shields.splice(s, 1); // Start item collection cooldown itemCollectionCooldown = itemCollectionCooldownDelay; // Apply immunity for 10 seconds if (!shieldActive) { shieldActive = true; // Visual indicator - make player semi-transparent blue tween(player, { tint: 0x0099ff }, { duration: 200 }); // Use tween to reset immunity after 10 seconds var shieldTimer = { value: 1 }; tween(shieldTimer, { value: 0 }, { duration: 10000, // 10 seconds onFinish: function onFinish() { shieldActive = false; // Reset player color tween(player, { tint: 0xffffff }, { duration: 200 }); } }); } } } // Check player-battery collisions and collection for (var b = batteries.length - 1; b >= 0; b--) { var battery = batteries[b]; var deltaX = player.x - battery.x; var deltaY = player.y - battery.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var collectionRadius = 50; // Collection radius for battery var collectionRadiusSquared = collectionRadius * collectionRadius; if (distanceSquared < collectionRadiusSquared) { // Battery collected - remove it battery.destroy(); batteries.splice(b, 1); // Add a lightning bolt back if we have less than 3 if (activeLightning < 3) { var lightningToAdd = lightningBolts[activeLightning]; lightningToAdd.visible = true; lightningToAdd.alpha = 1; lightningToAdd.scaleX = 1; lightningToAdd.scaleY = 1; activeLightning++; } // Immediately spawn a new battery when one is collected (only if less than 5) if (batteries.length < 5) { var validPosition = false; var batteryX, batteryY; var attempts = 0; var maxAttempts = 50; // Find valid position for new battery spawn while (!validPosition && attempts < maxAttempts) { batteryX = Math.random() * (2048 - 200) + 100; // Keep away from borders batteryY = Math.random() * (2732 - 240) + 120; // Keep away from borders validPosition = true; // Check distance from factories - increased exclusion radius for (var f = 0; f < factories.length; f++) { var factory = factories[f]; var deltaX = batteryX - factory.x; var deltaY = batteryY - factory.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; var factoryExclusionRadius = 300; // Increased from 200px to 300px for better separation var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius; if (distanceSquared < factoryExclusionRadiusSquared) { validPosition = false; break; } } // Check distance from trees if (validPosition) { for (var t = 0; t < allTrees.length; t++) { var tree = allTrees[t]; var deltaX = batteryX - tree.x; var deltaY = batteryY - tree.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < 10000) { // 100px minimum distance from trees validPosition = false; break; } } } attempts++; } // Spawn new battery if valid position found if (validPosition) { var newBattery = camera.addChild(new Battery()); newBattery.x = batteryX; newBattery.y = batteryY; batteries.push(newBattery); } } } } // Update arrow to point to nearest battery if (batteries.length > 0) { arrow.visible = true; // Find nearest battery var nearestBattery = null; var nearestDistance = Infinity; for (var b = 0; b < batteries.length; b++) { var battery = batteries[b]; var deltaX = battery.x - player.x; var deltaY = battery.y - player.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < nearestDistance) { nearestDistance = distanceSquared; nearestBattery = battery; } } // Position arrow around player pointing to nearest battery if (nearestBattery) { var batteryDeltaX = nearestBattery.x - player.x; var batteryDeltaY = nearestBattery.y - player.y; var batteryDistance = Math.sqrt(batteryDeltaX * batteryDeltaX + batteryDeltaY * batteryDeltaY); if (batteryDistance > 0) { // Normalize direction to battery var directionX = batteryDeltaX / batteryDistance; var directionY = batteryDeltaY / batteryDistance; // Position arrow around player at fixed radius arrow.x = player.x + directionX * arrow.radius; arrow.y = player.y + directionY * arrow.radius; // Rotate arrow to point toward battery arrow.rotation = Math.atan2(batteryDeltaY, batteryDeltaX) + Math.PI / 2; } } } else { arrow.visible = false; } // Update arrow2 to point to nearest special item (wheel or shield) var allSpecialItems = wheels.concat(shields); if (allSpecialItems.length > 0) { arrow2.visible = true; // Find nearest special item var nearestItem = null; var nearestDistance = Infinity; for (var i = 0; i < allSpecialItems.length; i++) { var item = allSpecialItems[i]; var deltaX = item.x - player.x; var deltaY = item.y - player.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < nearestDistance) { nearestDistance = distanceSquared; nearestItem = item; } } // Position arrow2 around player pointing to nearest special item if (nearestItem) { var itemDeltaX = nearestItem.x - player.x; var itemDeltaY = nearestItem.y - player.y; var itemDistance = Math.sqrt(itemDeltaX * itemDeltaX + itemDeltaY * itemDeltaY); if (itemDistance > 0) { // Normalize direction to item var directionX = itemDeltaX / itemDistance; var directionY = itemDeltaY / itemDistance; // Position arrow2 around player at fixed radius arrow2.x = player.x + directionX * arrow2.radius; arrow2.y = player.y + directionY * arrow2.radius; // Rotate arrow2 to point toward item arrow2.rotation = Math.atan2(itemDeltaY, itemDeltaX) + Math.PI / 2; } } } else { arrow2.visible = false; } // Handle lightning bolt disappearance every 20 seconds lightningTimer++; if (lightningTimer >= lightningDelay && activeLightning > 0) { var lightningToRemove = lightningBolts[activeLightning - 1]; // Animate lightning bolt disappearing with fade and scale down tween(lightningToRemove, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { lightningToRemove.visible = false; } }); activeLightning--; lightningTimer = 0; // Check if all lightning bolts are consumed if (activeLightning <= 0) { // Make player disappear tween(player, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500, easing: tween.easeOut }); // Hide arrow when player disappears arrow.visible = false; // Hide arrow2 when player disappears arrow2.visible = false; // Create explosion at player position var playerExplosion = camera.addChild(LK.getAsset('explocion', { anchorX: 0.5, anchorY: 0.5, x: player.x, y: player.y })); // Animate explosion tween(playerExplosion, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { playerExplosion.destroy(); } }); // Play explosion sound LK.getSound('explosion').play(); // Show "lost" image covering the entire screen after 1 second delay LK.setTimeout(function () { // Scale camera back to show full image tween(camera, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeOut }); // Calculate scale to fit camera dimensions (2048x2732) var cameraWidth = 2048; var cameraHeight = 2732; var lostImageWidth = 100; // Original asset width var lostImageHeight = 100; // Original asset height var scaleX = cameraWidth / lostImageWidth; var scaleY = cameraHeight / lostImageHeight; var lostImage = LK.gui.center.addChild(LK.getAsset('lost', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0, scaleX: scaleX, scaleY: scaleY })); }, 1000); // Show game over after a brief delay LK.setTimeout(function () { LK.showGameOver(); }, 2500); } } // Check enemy-player collisions using hitbox intersection for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Use intersects method to check if enemy hitbox touches player hitbox if (enemy.intersects(player) && activeHearts > 0 && !shieldActive) { // Enemy touched player - remove a heart var heartToRemove = hearts[activeHearts - 1]; // Animate heart disappearing with fade and scale down tween(heartToRemove, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { heartToRemove.visible = false; } }); activeHearts--; // Remove the enemy that hit the player enemy.destroy(); enemies.splice(i, 1); // Check if all hearts are gone if (activeHearts <= 0) { // Make player disappear tween(player, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500, easing: tween.easeOut }); // Hide arrow when player disappears arrow.visible = false; // Hide arrow2 when player disappears arrow2.visible = false; // Create explosion at player position var playerExplosion = camera.addChild(LK.getAsset('explocion', { anchorX: 0.5, anchorY: 0.5, x: player.x, y: player.y })); // Animate explosion tween(playerExplosion, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { playerExplosion.destroy(); } }); // Play explosion sound LK.getSound('explosion').play(); // Show game over after a brief delay LK.setTimeout(function () { LK.showGameOver(); }, 1500); return; // Exit update loop early since game is over } continue; // Skip to next enemy since this one was removed } } // Check enemy-tree collisions with optimized distance-based pre-filtering for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; var collisionDetected = false; var collidedTree = null; // Pre-filter trees by distance before expensive intersection check for (var j = 0; j < allTrees.length; j++) { var tree = allTrees[j]; var deltaX = enemy.x - tree.x; var deltaY = enemy.y - tree.y; var distanceSquared = deltaX * deltaX + deltaY * deltaY; // Only check intersection if close enough (tree radius ~50 + enemy radius ~30) if (distanceSquared < 6400) { // 80 * 80 if (enemy.intersects(tree)) { collisionDetected = true; collidedTree = tree; break; } } } // Handle collision - create explosion and remove enemy if (collisionDetected) { // Create explosion effect at enemy position var explosion = camera.addChild(LK.getAsset('explocion', { anchorX: 0.5, anchorY: 0.5, x: enemy.x, y: enemy.y })); // Animate explosion with scaling and fading tween(explosion, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { explosion.destroy(); } }); // Play explosion sound LK.getSound('explosion').play(); // Remove enemy enemy.destroy(); enemies.splice(i, 1); } else { // Update enemy movement if no collision enemy.chasePlayer(); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('flecha', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 100; // Distance from player center
return self;
});
var Arrow2 = Container.expand(function () {
var self = Container.call(this);
var arrow2Graphics = self.attachAsset('flecha2', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 100; // Distance from player center
return self;
});
var Battery = Container.expand(function () {
var self = Container.call(this);
var batteryGraphics = self.attachAsset('bateria', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemigo', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 50; // Enemy movement speed - increased for faster gameplay
self.chaseDelay = 1000; // Time between chase movements
self.chasePlayer = function () {
var deltaX = player.x - self.x;
var deltaY = player.y - self.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared > 2500) {
// 50 * 50 - avoid sqrt when possible
var distance = Math.sqrt(distanceSquared);
// Calculate movement direction
var directionX = deltaX / distance;
var directionY = deltaY / distance;
// Move continuously towards player with dynamic speed based on avoidance
var baseSpeed = 4.5; // Base movement speed - reduced by 0.5 for slower movement
var moveSpeed = baseSpeed;
// Increase speed when avoiding trees for more responsive movement
if (avoidanceForce > 0) {
moveSpeed = baseSpeed * 2.5; // 150% speed increase when avoiding trees for better evasion
}
// Tree avoidance logic with increased responsiveness
var avoidanceX = 0;
var avoidanceY = 0;
var lookAheadDistance = 150; // Further increased look-ahead distance for much earlier detection
var avoidanceForce = 0;
// Check for trees in movement path with multiple prediction points
var futureX = self.x + directionX * lookAheadDistance;
var futureY = self.y + directionY * lookAheadDistance;
// Also check current position for immediate threats
var immediateX = self.x + directionX * 30;
var immediateY = self.y + directionY * 30;
// Check nearby trees for potential collisions
for (var t = 0; t < allTrees.length; t++) {
var tree = allTrees[t];
// Check both future and immediate positions
var treeDeltaX = tree.x - futureX;
var treeDeltaY = tree.y - futureY;
var treeDistanceSquared = treeDeltaX * treeDeltaX + treeDeltaY * treeDeltaY;
var avoidanceRadius = 100; // Reduced avoidance radius for smaller avoidance area
// Also check immediate threat
var immediateDeltaX = tree.x - immediateX;
var immediateDeltaY = tree.y - immediateY;
var immediateDistanceSquared = immediateDeltaX * immediateDeltaX + immediateDeltaY * immediateDeltaY;
var immediateRadius = 80; // Reduced immediate radius for smaller close-range avoidance
// Use the closer threat for avoidance calculation
var useImmediate = immediateDistanceSquared < immediateRadius * immediateRadius;
var finalDeltaX = useImmediate ? immediateDeltaX : treeDeltaX;
var finalDeltaY = useImmediate ? immediateDeltaY : treeDeltaY;
var finalDistanceSquared = useImmediate ? immediateDistanceSquared : treeDistanceSquared;
var finalRadius = useImmediate ? immediateRadius : avoidanceRadius;
if (finalDistanceSquared < finalRadius * finalRadius) {
var treeDistance = Math.sqrt(finalDistanceSquared);
if (treeDistance > 0) {
// Calculate avoidance direction (perpendicular to tree direction)
var avoidanceStrength = (finalRadius - treeDistance) / finalRadius;
// Increase avoidance strength for immediate threats
if (useImmediate) {
avoidanceStrength *= 2.5; // Much stronger avoidance for immediate threats
}
var treeAvoidX = finalDeltaX / treeDistance * avoidanceStrength;
var treeAvoidY = finalDeltaY / treeDistance * avoidanceStrength;
// Add perpendicular avoidance force with increased magnitude
avoidanceX += treeAvoidY * 2.0; // Further increased avoidance force for better evasion
avoidanceY -= treeAvoidX * 2.0;
avoidanceForce += avoidanceStrength;
}
}
}
// Normalize avoidance force
if (avoidanceForce > 0) {
avoidanceX /= avoidanceForce;
avoidanceY /= avoidanceForce;
// Increased blend factor for stronger avoidance
var blendFactor = Math.min(avoidanceForce, 0.95); // Increased from 0.8 to 0.95
directionX = directionX * (1 - blendFactor) + avoidanceX * blendFactor;
directionY = directionY * (1 - blendFactor) + avoidanceY * blendFactor;
// Renormalize direction
var newDistance = Math.sqrt(directionX * directionX + directionY * directionY);
if (newDistance > 0) {
directionX /= newDistance;
directionY /= newDistance;
}
}
self.x += directionX * moveSpeed;
self.y += directionY * moveSpeed;
// Keep enemy within bounds
self.x = Math.max(80, Math.min(1968, self.x));
self.y = Math.max(120, Math.min(2612, self.y));
// Rotate to face movement direction smoothly (only every 2 frames for performance)
if (LK.ticks % 2 === 0) {
var targetRotation = Math.atan2(directionY, directionX) + Math.PI / 2;
var rotationDiff = targetRotation - self.rotation;
// Normalize rotation difference to [-PI, PI]
while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI;
while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI;
// Smooth rotation
self.rotation += rotationDiff * 0.1;
}
}
};
return self;
});
var Factory = Container.expand(function () {
var self = Container.call(this);
var factoryGraphics = self.attachAsset('fabrica', {
anchorX: 0.5,
anchorY: 0.5
});
self.spawnTimer = 0;
self.spawnDelay = 480; // Spawn enemy every 8 seconds (480 frames at 60fps)
self.spawnEnemy = function () {
var newEnemy = new Enemy();
newEnemy.x = self.x;
newEnemy.y = self.y;
enemies.push(newEnemy);
camera.addChild(newEnemy);
};
self.update = function () {
self.spawnTimer++;
if (self.spawnTimer >= self.spawnDelay) {
self.spawnEnemy();
self.spawnTimer = 0;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('escudo', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Wheel = Container.expand(function () {
var self = Container.call(this);
var wheelGraphics = self.attachAsset('rueda', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4a7c59
});
/****
* Game Code
****/
// Create extended background that covers the entire visible area including camera zoom
var extendedBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 40.96,
// Double scale to cover zoomed view (2048*2/100)
scaleY: 54.64,
// Double scale to cover zoomed view (2732*2/100)
x: -2048,
// Offset to center the extended background
y: -2732 // Offset to center the extended background
}));
// Create additional background for right side
var rightBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover additional right area
scaleY: 27.32,
// Scale to cover full height
x: 2048,
// Position to the right of main map
y: 0
}));
// Create additional background for bottom side
var bottomBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover full width
scaleY: 27.32,
// Scale to cover additional bottom area
x: 0,
y: 2732 // Position below main map
}));
// Create additional background for top-right corner
var topRightBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover corner area
scaleY: 27.32,
// Scale to cover corner area
x: 2048,
// Position to the right
y: -2732 // Position above main map
}));
// Create additional background for bottom-right corner
var bottomRightBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover corner area
scaleY: 27.32,
// Scale to cover corner area
x: 2048,
// Position to the right
y: 2732 // Position below main map
}));
// Create additional background for bottom-left corner
var bottomLeftBackground = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover corner area
scaleY: 27.32,
// Scale to cover corner area
x: -2048,
// Position to the left
y: 2732 // Position below main map
}));
// Create large map floor - scale the grass background to cover entire game area
var mapFloor = game.addChild(LK.getAsset('fondo', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Scale to cover 2048px width (2048/100)
scaleY: 27.32,
// Scale to cover 2732px height (2732/100)
x: 0,
y: 0
}));
// Create trees around all borders
var trees = [];
// Top border trees
for (var i = 0; i < 26; i++) {
var topTree = game.addChild(LK.getAsset('arbol', {
anchorX: 0.5,
anchorY: 0.5,
x: i * 80 + 40,
y: 60
}));
trees.push(topTree);
}
// Bottom border trees
for (var i = 0; i < 26; i++) {
var bottomTree = game.addChild(LK.getAsset('arbol', {
anchorX: 0.5,
anchorY: 0.5,
x: i * 80 + 40,
y: 2672
}));
trees.push(bottomTree);
}
// Left border trees (excluding corners already covered)
for (var i = 1; i < 33; i++) {
var leftTree = game.addChild(LK.getAsset('arbol', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: i * 80 + 60
}));
trees.push(leftTree);
}
// Right border trees (excluding corners already covered)
for (var i = 1; i < 33; i++) {
var rightTree = game.addChild(LK.getAsset('arbol', {
anchorX: 0.5,
anchorY: 0.5,
x: 2008,
y: i * 80 + 60
}));
trees.push(rightTree);
}
// Create camera container for following player
var camera = game.addChild(new Container());
camera.x = 1024;
camera.y = 1366;
// Move all game elements to camera container
camera.addChild(extendedBackground);
camera.addChild(rightBackground);
camera.addChild(bottomBackground);
camera.addChild(topRightBackground);
camera.addChild(bottomRightBackground);
camera.addChild(bottomLeftBackground);
camera.addChild(mapFloor);
for (var i = 0; i < trees.length; i++) {
camera.addChild(trees[i]);
}
// Add random trees scattered throughout the map
var randomTrees = [];
// Define factory positions for exclusion zones
var factoryPositions = [{
x: 400,
y: 400
},
// top-left
{
x: 1648,
y: 400
},
// top-right
{
x: 400,
y: 2332
},
// bottom-left
{
x: 1648,
y: 2332
} // bottom-right
];
var exclusionRadius = 400; // Distance to keep trees away from factories - increased for better separation
for (var i = 0; i < 45; i++) {
var validPosition = false;
var randomX, randomY;
var attempts = 0;
var maxAttempts = 50;
// Keep trying until we find a valid position away from factories
while (!validPosition && attempts < maxAttempts) {
randomX = Math.random() * (2048 - 120) + 60; // Closer to borders
randomY = Math.random() * (2732 - 180) + 90; // Closer to borders
validPosition = true;
// Check distance from all factories
for (var j = 0; j < factoryPositions.length; j++) {
var factoryX = factoryPositions[j].x;
var factoryY = factoryPositions[j].y;
var deltaX = randomX - factoryX;
var deltaY = randomY - factoryY;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var exclusionRadiusSquared = exclusionRadius * exclusionRadius;
if (distanceSquared < exclusionRadiusSquared) {
validPosition = false;
break;
}
}
// Check distance from existing random trees to ensure separation
var minTreeDistance = 200; // Minimum distance between trees
var minTreeDistanceSquared = minTreeDistance * minTreeDistance;
for (var k = 0; k < randomTrees.length; k++) {
var existingTree = randomTrees[k];
var treeDeltaX = randomX - existingTree.x;
var treeDeltaY = randomY - existingTree.y;
var treeDistanceSquared = treeDeltaX * treeDeltaX + treeDeltaY * treeDeltaY;
if (treeDistanceSquared < minTreeDistanceSquared) {
validPosition = false;
break;
}
}
attempts++;
}
// Only create tree if we found a valid position
if (validPosition) {
var randomTree = camera.addChild(LK.getAsset('arbol', {
anchorX: 0.5,
anchorY: 0.5,
x: randomX,
y: randomY
}));
randomTrees.push(randomTree);
}
}
// Cache all trees for optimized collision detection
var allTrees = trees.concat(randomTrees);
// Create player and add to camera
var player = camera.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Create arrow and add to camera
var arrow = camera.addChild(new Arrow());
arrow.visible = false; // Initially hidden until battery spawns
// Create arrow2 for special items and add to camera
var arrow2 = camera.addChild(new Arrow2());
arrow2.visible = false; // Initially hidden until special item spawns
// Create 3 lightning bolts in top-left corner of screen
var lightning1 = LK.gui.topLeft.addChild(LK.getAsset('rayo', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: 100
}));
var lightning2 = LK.gui.topLeft.addChild(LK.getAsset('rayo', {
anchorX: 0.5,
anchorY: 0.5,
x: 250,
y: 100
}));
var lightning3 = LK.gui.topLeft.addChild(LK.getAsset('rayo', {
anchorX: 0.5,
anchorY: 0.5,
x: 350,
y: 100
}));
// Lightning management
var lightningBolts = [lightning1, lightning2, lightning3];
var lightningTimer = 0;
var lightningDelay = 420; // 7 seconds at 60fps
var activeLightning = 3; // Start with 3 active lightning bolts
// Create timer display in top center of screen
var timerText = new Text2('00:00', {
size: 80,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Timer variables
var gameTimer = 0; // Timer in frames (60fps)
// Create 5 lives in top-right corner of screen
var life1 = LK.gui.topRight.addChild(LK.getAsset('vida', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: 100
}));
var life2 = LK.gui.topRight.addChild(LK.getAsset('vida', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: 100
}));
var life3 = LK.gui.topRight.addChild(LK.getAsset('vida', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: 100
}));
var life4 = LK.gui.topRight.addChild(LK.getAsset('vida', {
anchorX: 0.5,
anchorY: 0.5,
x: -350,
y: 100
}));
// Hearts management
var hearts = [life1, life2, life3, life4];
var activeHearts = 4; // Start with 4 active hearts
// Create enemies array
var enemies = [];
// Create batteries array
var batteries = [];
// Battery spawn timer
var batterySpawnTimer = 600; // Start ready to spawn immediately
var batterySpawnDelay = 600; // Spawn battery every 10 seconds (600 frames at 60fps)
// Create special items arrays
var wheels = [];
var shields = [];
// Special item spawn timer
var itemSpawnTimer = 0;
var itemSpawnMinDelay = 600; // 10 seconds minimum (600 frames at 60fps)
var itemSpawnMaxDelay = 900; // 15 seconds maximum (900 frames at 60fps)
var itemSpawnDelay = Math.random() * (itemSpawnMaxDelay - itemSpawnMinDelay) + itemSpawnMinDelay;
// Item collection cooldown tracking
var itemCollectionCooldown = 0; // Timer to prevent item spawning after collection
var itemCollectionCooldownDelay = 720; // 12 seconds (720 frames at 60fps)
// Create factories array
var factories = [];
// Create factory in top-left corner
var topLeftFactory = camera.addChild(new Factory());
topLeftFactory.x = 400;
topLeftFactory.y = 400;
factories.push(topLeftFactory);
// Create factory in top-right corner
var topRightFactory = camera.addChild(new Factory());
topRightFactory.x = 1648;
topRightFactory.y = 400;
factories.push(topRightFactory);
// Create factory in bottom-left corner
var bottomLeftFactory = camera.addChild(new Factory());
bottomLeftFactory.x = 400;
bottomLeftFactory.y = 2332;
factories.push(bottomLeftFactory);
// Create factory in bottom-right corner
var bottomRightFactory = camera.addChild(new Factory());
bottomRightFactory.x = 1648;
bottomRightFactory.y = 2332;
factories.push(bottomRightFactory);
// Set camera scale for closer view
camera.scaleX = 2;
camera.scaleY = 2;
// Start playing background music
LK.playMusic('si');
// Game controls - move player toward touch position
var playerSpeed = 4; // Player movement speed
var basePlayerSpeed = 4; // Store original speed for wheel effect
var speedBoostActive = false; // Track if speed boost is active
var shieldActive = false; // Track if shield immunity is active
var targetX = player.x;
var targetY = player.y;
var isMoving = false;
function updatePlayerMovement(x, y) {
// Convert screen coordinates to world coordinates accounting for camera transform
var worldX = (x - camera.x) / camera.scaleX;
var worldY = (y - camera.y) / camera.scaleY;
targetX = worldX;
targetY = worldY;
isMoving = true;
}
game.down = function (x, y, obj) {
updatePlayerMovement(x, y);
};
game.move = function (x, y, obj) {
updatePlayerMovement(x, y);
};
game.up = function (x, y, obj) {
isMoving = false;
};
// Main game update loop
game.update = function () {
// Update and display timer
gameTimer++;
var seconds = Math.floor(gameTimer / 60);
var minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
var timeString = (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
timerText.setText(timeString);
// Move player toward target position if moving
if (isMoving) {
var deltaX = targetX - player.x;
var deltaY = targetY - player.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared > 25) {
// 5 * 5 - avoid sqrt when possible
// Only move if not close enough to target
var distance = Math.sqrt(distanceSquared);
// Calculate movement direction
var directionX = deltaX / distance;
var directionY = deltaY / distance;
// Move player toward target
player.x += directionX * playerSpeed;
player.y += directionY * playerSpeed;
// Rotate player to face movement direction
var targetRotation = Math.atan2(deltaY, deltaX) + Math.PI / 2;
var rotationDiff = targetRotation - player.rotation;
// Normalize rotation difference to [-PI, PI]
while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI;
while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI;
// Smooth rotation
player.rotation += rotationDiff * 0.15;
}
}
// Check player-tree collisions before finalizing movement
var playerCollisionDetected = false;
var playerRadius = 25; // Player collision radius
var treeRadius = 40; // Tree collision radius
var combinedRadius = playerRadius + treeRadius;
var combinedRadiusSquared = combinedRadius * combinedRadius;
// Check collision with all trees
for (var t = 0; t < allTrees.length; t++) {
var tree = allTrees[t];
var deltaX = player.x - tree.x;
var deltaY = player.y - tree.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < combinedRadiusSquared) {
playerCollisionDetected = true;
// Push player away from tree
var distance = Math.sqrt(distanceSquared);
if (distance > 0) {
var pushDistance = combinedRadius - distance;
var pushX = deltaX / distance * pushDistance;
var pushY = deltaY / distance * pushDistance;
player.x += pushX;
player.y += pushY;
}
}
}
// Keep player within bounds, accounting for tree borders
player.x = Math.max(80, Math.min(1968, player.x));
player.y = Math.max(120, Math.min(2612, player.y));
// Update camera position to follow player
var targetCameraX = 1024 - player.x * camera.scaleX;
var targetCameraY = 1366 - player.y * camera.scaleY;
// Smooth camera following
camera.x += (targetCameraX - camera.x) * 0.1;
camera.y += (targetCameraY - camera.y) * 0.1;
// Handle enemy collision detection - prevent enemies from overlapping (frame-skipped optimization)
// Only run separation every 3 frames to reduce computational load
if (LK.ticks % 3 === 0) {
var maxChecks = Math.min(enemies.length * enemies.length / 4, 100); // Limit total checks
var checksPerformed = 0;
for (var i = 0; i < enemies.length && checksPerformed < maxChecks; i++) {
for (var j = i + 1; j < enemies.length && checksPerformed < maxChecks; j++) {
var enemy1 = enemies[i];
var enemy2 = enemies[j];
var deltaX = enemy2.x - enemy1.x;
var deltaY = enemy2.y - enemy1.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var minDistanceSquared = 6400; // 80 * 80 - avoid sqrt when possible
if (distanceSquared < minDistanceSquared && distanceSquared > 0) {
var distance = Math.sqrt(distanceSquared);
// Calculate separation force
var separationForce = (80 - distance) / 2;
var separationX = deltaX / distance * separationForce;
var separationY = deltaY / distance * separationForce;
// Push enemies apart
enemy1.x -= separationX;
enemy1.y -= separationY;
enemy2.x += separationX;
enemy2.y += separationY;
// Keep enemies within bounds after separation
enemy1.x = Math.max(80, Math.min(1968, enemy1.x));
enemy1.y = Math.max(120, Math.min(2612, enemy1.y));
enemy2.x = Math.max(80, Math.min(1968, enemy2.x));
enemy2.y = Math.max(120, Math.min(2612, enemy2.y));
}
checksPerformed++;
}
}
}
// Update factories
for (var i = 0; i < factories.length; i++) {
factories[i].update();
}
// Handle battery spawning
batterySpawnTimer++;
if (batterySpawnTimer >= batterySpawnDelay && batteries.length < 5) {
var validPosition = false;
var batteryX, batteryY;
var attempts = 0;
var maxAttempts = 50;
// Find valid position for battery spawn
while (!validPosition && attempts < maxAttempts) {
batteryX = Math.random() * (2048 - 200) + 100; // Keep away from borders
batteryY = Math.random() * (2732 - 240) + 120; // Keep away from borders
validPosition = true;
// Check distance from factories - increased exclusion radius
for (var f = 0; f < factories.length; f++) {
var factory = factories[f];
var deltaX = batteryX - factory.x;
var deltaY = batteryY - factory.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var factoryExclusionRadius = 300; // Increased from 200px to 300px for better separation
var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius;
if (distanceSquared < factoryExclusionRadiusSquared) {
validPosition = false;
break;
}
}
// Check distance from trees
if (validPosition) {
for (var t = 0; t < allTrees.length; t++) {
var tree = allTrees[t];
var deltaX = batteryX - tree.x;
var deltaY = batteryY - tree.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < 10000) {
// 100px minimum distance from trees
validPosition = false;
break;
}
}
}
attempts++;
}
// Spawn battery if valid position found
if (validPosition) {
var newBattery = camera.addChild(new Battery());
newBattery.x = batteryX;
newBattery.y = batteryY;
batteries.push(newBattery);
}
batterySpawnTimer = 0;
}
// Handle special item spawning (wheel or shield)
itemSpawnTimer++;
// Update item collection cooldown
if (itemCollectionCooldown > 0) {
itemCollectionCooldown--;
}
if (itemSpawnTimer >= itemSpawnDelay && itemCollectionCooldown <= 0 && wheels.length === 0 && shields.length === 0) {
var validPosition = false;
var itemX, itemY;
var attempts = 0;
var maxAttempts = 50;
// Find valid position for item spawn
while (!validPosition && attempts < maxAttempts) {
itemX = Math.random() * (2048 - 200) + 100; // Keep away from borders
itemY = Math.random() * (2732 - 240) + 120; // Keep away from borders
validPosition = true;
// Check distance from factories
for (var f = 0; f < factories.length; f++) {
var factory = factories[f];
var deltaX = itemX - factory.x;
var deltaY = itemY - factory.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var factoryExclusionRadius = 300;
var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius;
if (distanceSquared < factoryExclusionRadiusSquared) {
validPosition = false;
break;
}
}
// Check distance from trees
if (validPosition) {
for (var t = 0; t < allTrees.length; t++) {
var tree = allTrees[t];
var deltaX = itemX - tree.x;
var deltaY = itemY - tree.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < 10000) {
// 100px minimum distance from trees
validPosition = false;
break;
}
}
}
attempts++;
}
// Spawn item if valid position found
if (validPosition) {
// Randomly choose between wheel (0) or shield (1)
var itemType = Math.floor(Math.random() * 2);
if (itemType === 0) {
// Spawn wheel
var newWheel = camera.addChild(new Wheel());
newWheel.x = itemX;
newWheel.y = itemY;
wheels.push(newWheel);
} else {
// Spawn shield
var newShield = camera.addChild(new Shield());
newShield.x = itemX;
newShield.y = itemY;
shields.push(newShield);
}
}
// Reset timer with new random delay
itemSpawnTimer = 0;
itemSpawnDelay = Math.random() * (itemSpawnMaxDelay - itemSpawnMinDelay) + itemSpawnMinDelay;
}
// Check player-wheel collisions and collection
for (var w = wheels.length - 1; w >= 0; w--) {
var wheel = wheels[w];
var deltaX = player.x - wheel.x;
var deltaY = player.y - wheel.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var collectionRadius = 50; // Collection radius for wheel
var collectionRadiusSquared = collectionRadius * collectionRadius;
if (distanceSquared < collectionRadiusSquared) {
// Wheel collected - remove it
wheel.destroy();
wheels.splice(w, 1);
// Start item collection cooldown
itemCollectionCooldown = itemCollectionCooldownDelay;
// Apply speed boost for 10 seconds
if (!speedBoostActive) {
speedBoostActive = true;
playerSpeed = basePlayerSpeed * 2; // Double the speed
// Use tween to reset speed after 10 seconds
var speedBoostTimer = {
value: 1
};
tween(speedBoostTimer, {
value: 0
}, {
duration: 10000,
// 10 seconds
onFinish: function onFinish() {
playerSpeed = basePlayerSpeed; // Reset to original speed
speedBoostActive = false;
}
});
}
}
}
// Check player-shield collisions and collection
for (var s = shields.length - 1; s >= 0; s--) {
var shield = shields[s];
var deltaX = player.x - shield.x;
var deltaY = player.y - shield.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var collectionRadius = 50; // Collection radius for shield
var collectionRadiusSquared = collectionRadius * collectionRadius;
if (distanceSquared < collectionRadiusSquared) {
// Shield collected - remove it
shield.destroy();
shields.splice(s, 1);
// Start item collection cooldown
itemCollectionCooldown = itemCollectionCooldownDelay;
// Apply immunity for 10 seconds
if (!shieldActive) {
shieldActive = true;
// Visual indicator - make player semi-transparent blue
tween(player, {
tint: 0x0099ff
}, {
duration: 200
});
// Use tween to reset immunity after 10 seconds
var shieldTimer = {
value: 1
};
tween(shieldTimer, {
value: 0
}, {
duration: 10000,
// 10 seconds
onFinish: function onFinish() {
shieldActive = false;
// Reset player color
tween(player, {
tint: 0xffffff
}, {
duration: 200
});
}
});
}
}
}
// Check player-battery collisions and collection
for (var b = batteries.length - 1; b >= 0; b--) {
var battery = batteries[b];
var deltaX = player.x - battery.x;
var deltaY = player.y - battery.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var collectionRadius = 50; // Collection radius for battery
var collectionRadiusSquared = collectionRadius * collectionRadius;
if (distanceSquared < collectionRadiusSquared) {
// Battery collected - remove it
battery.destroy();
batteries.splice(b, 1);
// Add a lightning bolt back if we have less than 3
if (activeLightning < 3) {
var lightningToAdd = lightningBolts[activeLightning];
lightningToAdd.visible = true;
lightningToAdd.alpha = 1;
lightningToAdd.scaleX = 1;
lightningToAdd.scaleY = 1;
activeLightning++;
}
// Immediately spawn a new battery when one is collected (only if less than 5)
if (batteries.length < 5) {
var validPosition = false;
var batteryX, batteryY;
var attempts = 0;
var maxAttempts = 50;
// Find valid position for new battery spawn
while (!validPosition && attempts < maxAttempts) {
batteryX = Math.random() * (2048 - 200) + 100; // Keep away from borders
batteryY = Math.random() * (2732 - 240) + 120; // Keep away from borders
validPosition = true;
// Check distance from factories - increased exclusion radius
for (var f = 0; f < factories.length; f++) {
var factory = factories[f];
var deltaX = batteryX - factory.x;
var deltaY = batteryY - factory.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
var factoryExclusionRadius = 300; // Increased from 200px to 300px for better separation
var factoryExclusionRadiusSquared = factoryExclusionRadius * factoryExclusionRadius;
if (distanceSquared < factoryExclusionRadiusSquared) {
validPosition = false;
break;
}
}
// Check distance from trees
if (validPosition) {
for (var t = 0; t < allTrees.length; t++) {
var tree = allTrees[t];
var deltaX = batteryX - tree.x;
var deltaY = batteryY - tree.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < 10000) {
// 100px minimum distance from trees
validPosition = false;
break;
}
}
}
attempts++;
}
// Spawn new battery if valid position found
if (validPosition) {
var newBattery = camera.addChild(new Battery());
newBattery.x = batteryX;
newBattery.y = batteryY;
batteries.push(newBattery);
}
}
}
}
// Update arrow to point to nearest battery
if (batteries.length > 0) {
arrow.visible = true;
// Find nearest battery
var nearestBattery = null;
var nearestDistance = Infinity;
for (var b = 0; b < batteries.length; b++) {
var battery = batteries[b];
var deltaX = battery.x - player.x;
var deltaY = battery.y - player.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < nearestDistance) {
nearestDistance = distanceSquared;
nearestBattery = battery;
}
}
// Position arrow around player pointing to nearest battery
if (nearestBattery) {
var batteryDeltaX = nearestBattery.x - player.x;
var batteryDeltaY = nearestBattery.y - player.y;
var batteryDistance = Math.sqrt(batteryDeltaX * batteryDeltaX + batteryDeltaY * batteryDeltaY);
if (batteryDistance > 0) {
// Normalize direction to battery
var directionX = batteryDeltaX / batteryDistance;
var directionY = batteryDeltaY / batteryDistance;
// Position arrow around player at fixed radius
arrow.x = player.x + directionX * arrow.radius;
arrow.y = player.y + directionY * arrow.radius;
// Rotate arrow to point toward battery
arrow.rotation = Math.atan2(batteryDeltaY, batteryDeltaX) + Math.PI / 2;
}
}
} else {
arrow.visible = false;
}
// Update arrow2 to point to nearest special item (wheel or shield)
var allSpecialItems = wheels.concat(shields);
if (allSpecialItems.length > 0) {
arrow2.visible = true;
// Find nearest special item
var nearestItem = null;
var nearestDistance = Infinity;
for (var i = 0; i < allSpecialItems.length; i++) {
var item = allSpecialItems[i];
var deltaX = item.x - player.x;
var deltaY = item.y - player.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < nearestDistance) {
nearestDistance = distanceSquared;
nearestItem = item;
}
}
// Position arrow2 around player pointing to nearest special item
if (nearestItem) {
var itemDeltaX = nearestItem.x - player.x;
var itemDeltaY = nearestItem.y - player.y;
var itemDistance = Math.sqrt(itemDeltaX * itemDeltaX + itemDeltaY * itemDeltaY);
if (itemDistance > 0) {
// Normalize direction to item
var directionX = itemDeltaX / itemDistance;
var directionY = itemDeltaY / itemDistance;
// Position arrow2 around player at fixed radius
arrow2.x = player.x + directionX * arrow2.radius;
arrow2.y = player.y + directionY * arrow2.radius;
// Rotate arrow2 to point toward item
arrow2.rotation = Math.atan2(itemDeltaY, itemDeltaX) + Math.PI / 2;
}
}
} else {
arrow2.visible = false;
}
// Handle lightning bolt disappearance every 20 seconds
lightningTimer++;
if (lightningTimer >= lightningDelay && activeLightning > 0) {
var lightningToRemove = lightningBolts[activeLightning - 1];
// Animate lightning bolt disappearing with fade and scale down
tween(lightningToRemove, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
lightningToRemove.visible = false;
}
});
activeLightning--;
lightningTimer = 0;
// Check if all lightning bolts are consumed
if (activeLightning <= 0) {
// Make player disappear
tween(player, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeOut
});
// Hide arrow when player disappears
arrow.visible = false;
// Hide arrow2 when player disappears
arrow2.visible = false;
// Create explosion at player position
var playerExplosion = camera.addChild(LK.getAsset('explocion', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x,
y: player.y
}));
// Animate explosion
tween(playerExplosion, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
playerExplosion.destroy();
}
});
// Play explosion sound
LK.getSound('explosion').play();
// Show "lost" image covering the entire screen after 1 second delay
LK.setTimeout(function () {
// Scale camera back to show full image
tween(camera, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Calculate scale to fit camera dimensions (2048x2732)
var cameraWidth = 2048;
var cameraHeight = 2732;
var lostImageWidth = 100; // Original asset width
var lostImageHeight = 100; // Original asset height
var scaleX = cameraWidth / lostImageWidth;
var scaleY = cameraHeight / lostImageHeight;
var lostImage = LK.gui.center.addChild(LK.getAsset('lost', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: scaleX,
scaleY: scaleY
}));
}, 1000);
// Show game over after a brief delay
LK.setTimeout(function () {
LK.showGameOver();
}, 2500);
}
}
// Check enemy-player collisions using hitbox intersection
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Use intersects method to check if enemy hitbox touches player hitbox
if (enemy.intersects(player) && activeHearts > 0 && !shieldActive) {
// Enemy touched player - remove a heart
var heartToRemove = hearts[activeHearts - 1];
// Animate heart disappearing with fade and scale down
tween(heartToRemove, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
heartToRemove.visible = false;
}
});
activeHearts--;
// Remove the enemy that hit the player
enemy.destroy();
enemies.splice(i, 1);
// Check if all hearts are gone
if (activeHearts <= 0) {
// Make player disappear
tween(player, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeOut
});
// Hide arrow when player disappears
arrow.visible = false;
// Hide arrow2 when player disappears
arrow2.visible = false;
// Create explosion at player position
var playerExplosion = camera.addChild(LK.getAsset('explocion', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x,
y: player.y
}));
// Animate explosion
tween(playerExplosion, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
playerExplosion.destroy();
}
});
// Play explosion sound
LK.getSound('explosion').play();
// Show game over after a brief delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
return; // Exit update loop early since game is over
}
continue; // Skip to next enemy since this one was removed
}
}
// Check enemy-tree collisions with optimized distance-based pre-filtering
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var collisionDetected = false;
var collidedTree = null;
// Pre-filter trees by distance before expensive intersection check
for (var j = 0; j < allTrees.length; j++) {
var tree = allTrees[j];
var deltaX = enemy.x - tree.x;
var deltaY = enemy.y - tree.y;
var distanceSquared = deltaX * deltaX + deltaY * deltaY;
// Only check intersection if close enough (tree radius ~50 + enemy radius ~30)
if (distanceSquared < 6400) {
// 80 * 80
if (enemy.intersects(tree)) {
collisionDetected = true;
collidedTree = tree;
break;
}
}
}
// Handle collision - create explosion and remove enemy
if (collisionDetected) {
// Create explosion effect at enemy position
var explosion = camera.addChild(LK.getAsset('explocion', {
anchorX: 0.5,
anchorY: 0.5,
x: enemy.x,
y: enemy.y
}));
// Animate explosion with scaling and fading
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Play explosion sound
LK.getSound('explosion').play();
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
} else {
// Update enemy movement if no collision
enemy.chasePlayer();
}
}
};
robot estilo steampunk visto desde arriba totalmente no desde el frente con llantas. In-Game asset. 2d. High contrast. No shadows. vistasuperior
dame un fondo de color verde pasto. In-Game asset. 2d. High contrast. No shadows
has un robot negro tipo auto steampunk con aspecto desgastado que se mueva con llantas y este en una vista desde arriba In-Game asset. 2d. High contrast. No shadows
explosion realista. In-Game asset. 2d. High contrast. No shadows
haz un corazon con aspecto steampunk metalico desgastado. In-Game asset. 2d. High contrast. No shadows
una bateria energetica estilo steampunk. In-Game asset. 2d. High contrast. No shadows
has una flecha de señalizacion en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
has un rayo. In-Game asset. 2d. High contrast. No shadows
has que se vea en estilo steampunk
has una rueda en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
has un escudo en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
plateada
un 0 es estilo steampunk. In-Game asset. 2d. High contrast. No shadows
1 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 2 estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 3 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 4 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 5 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 6 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 7 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 8 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
numero 9 en estilo steampunk. In-Game asset. 2d. High contrast. No shadows
simbolo ":" en estilo steampunk. In-Game asset. 2d. High contrast. No shadows