/****
* 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