/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AICell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); // self.size is set on spawnAICell for variety self.speed = 2 + Math.random(); self.targetX = Math.random() * 44000; self.targetY = Math.random() * 44000; self.alive = true; self.lastX = self.x; self.lastY = self.y; self.update = function () { if (!self.alive) { return; } // --- AI Hunt Player Logic --- // Only some AI cells hunt the player, and only one at a time var huntingPlayer = false; if (self.huntsPlayer && typeof playerCell !== "undefined" && playerCell !== null) { var pdx = playerCell.x - self.x; var pdy = playerCell.y - self.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); // Only hunt if AI is bigger than player by 20% if (self.size > playerCell.size * 1.2) { // Hunt if player is within 2000px (long range) if (pdist < 2000) { // Check if no one is currently hunting or if this AI is the current hunter if (currentHunter === null || currentHunter === self) { self.targetX = playerCell.x; self.targetY = playerCell.y; huntingPlayer = true; currentHunter = self; // Set this AI as the current hunter } } else if (currentHunter === self) { // If this AI was hunting but player moved away, stop hunting currentHunter = null; } } else if (currentHunter === self) { // If this AI was hunting but is no longer big enough, stop hunting currentHunter = null; } } // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { // Speed is constant regardless of size var speed = 7.0; self.x += dx / distance * speed; self.y += dy / distance * speed; } else { // Pick new random target self.targetX = Math.random() * 44000; self.targetY = Math.random() * 44000; } // Keep within bounds if (typeof mapSize === "undefined") { var mapSize = 44000; } if (self.x < self.size / 2) { self.x = self.size / 2; } if (self.x > mapSize - self.size / 2) { self.x = mapSize - self.size / 2; } if (self.y < self.size / 2) { self.y = self.size / 2; } if (self.y > mapSize - self.size / 2) { self.y = mapSize - self.size / 2; } self.lastX = self.x; self.lastY = self.y; }; self.grow = function (amount) { var oldSize = self.size; self.size += amount; if (self.size > 7000) self.size = 7000; var scale = self.size / 50; tween(cellGraphics, { scaleX: scale, scaleY: scale }, { duration: 200, easing: tween.easeOut }); self.speed = 7.0; }; return self; }); var Food = Container.expand(function () { var self = Container.call(this); var foodGraphics = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); self.size = 20; self.consumed = false; return self; }); var Papa = Container.expand(function () { var self = Container.call(this); var papaGraphics = self.attachAsset('papa', { anchorX: 0.5, anchorY: 0.5 }); papaGraphics.tint = 0xDEB887; // Burlywood color for potato self.size = 35; self.consumed = false; self.growthValue = 50; // All papas give 50 points return self; }); var PlayerCell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); self.size = 50; self.speed = 3; self.targetX = self.x; self.targetY = self.y; self.grow = function (amount) { var oldSize = self.size; self.size += amount; if (self.size > 7000) self.size = 7000; // Update visual scale var scale = self.size / 50; tween(cellGraphics, { scaleX: scale, scaleY: scale }, { duration: 200, easing: tween.easeOut }); // Speed remains constant regardless of size self.speed = 7.0; LK.getSound('grow').play(); LK.setScore(Math.floor(self.size)); // --- Allow player to keep moving and playing after reaching 7000 points --- // No freeze or stop logic here; player can continue to move and play at max size. }; self.update = function () { // Slither.io style drag controls: playerCell.targetX/Y is set by drag logic in game.move // Move towards target position var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { // Speed is constant regardless of size var speed = 7.0; self.x += dx / distance * speed; self.y += dy / distance * speed; } // Keep within bounds if (typeof mapSize === "undefined") { var mapSize = 44000; } if (self.x < self.size / 2) { self.x = self.size / 2; } if (self.x > mapSize - self.size / 2) { self.x = mapSize - self.size / 2; } if (self.y < self.size / 2) { self.y = self.size / 2; } if (self.y > mapSize - self.size / 2) { self.y = mapSize - self.size / 2; } }; return self; }); var PowerFood = Container.expand(function () { var self = Container.call(this); var powerFoodGraphics = self.attachAsset('powerfood', { anchorX: 0.5, anchorY: 0.5 }); powerFoodGraphics.tint = 0xFFD700; // Golden color self.size = 30; self.consumed = false; self.growthValue = 200; // More growth than regular food return self; }); var Predator = Container.expand(function () { var self = Container.call(this); var predatorGraphics = self.attachAsset('predator', { anchorX: 0.5, anchorY: 0.5 }); self.size = 80; self.speed = 4.5; // Much higher base speed for extreme challenge self.targetX = Math.random() * 8192; self.targetY = Math.random() * 8192; self.update = function () { // Cap predator size to 7000 if (self.size > 7000) self.size = 7000; // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { // Predators are faster (difficulty up) self.x += dx / distance * 2.1; self.y += dy / distance * 2.1; } else { // Pick new random target self.targetX = Math.random() * 44000; self.targetY = Math.random() * 44000; } // Chase player if close enough if (typeof playerCell !== "undefined" && playerCell !== null) { var playerDx = playerCell.x - self.x; var playerDy = playerCell.y - self.y; var playerDistance = Math.sqrt(playerDx * playerDx + playerDy * playerDy); if (playerDistance < 300 && playerCell.size < self.size) { self.x += playerDx / playerDistance * self.speed * 1.5; self.y += playerDy / playerDistance * self.speed * 1.5; } } // Keep within bounds if (typeof mapSize === "undefined") { var mapSize = 44000; } if (self.x < 0) { self.x = 0; } if (self.x > mapSize) { self.x = mapSize; } if (self.y < 0) { self.y = 0; } if (self.y > mapSize) { self.y = mapSize; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x001a33 }); /**** * Game Code ****/ var playerCell = null; var playerCell2 = null; // Second player for local mode var localMultiplayer = false; // Set to true for local mode var foods = []; var powerFoods = []; var papas = []; var predators = []; var aiCells = []; var cellsEaten = 0; var currentHunter = null; // Track which AI cell is currently hunting the player // --- Map size is now global and updated dynamically in game.update --- var mapSize = 44000; // --- Slither.io-style Start Screen --- var startScreen = new Container(); // Animated background: several moving cells var startBgCells = []; for (var i = 0; i < 12; i++) { var cell = LK.getAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); cell.scaleX = cell.scaleY = 1.2 + Math.random() * 1.8; cell.x = 400 + Math.random() * 1248; cell.y = 600 + Math.random() * 1600; cell.alpha = 0.18 + Math.random() * 0.18; cell._vx = (Math.random() - 0.5) * 1.2; cell._vy = (Math.random() - 0.5) * 1.2; startScreen.addChild(cell); startBgCells.push(cell); } // Main logo/title var titleTxt = new Text2("Célula Survival", { size: 160, fill: "#fff" }); titleTxt.anchor.set(0.5, 0); titleTxt.x = 2048 / 2; titleTxt.y = 320; startScreen.addChild(titleTxt); // Subtitle var subtitleTxt = new Text2("¡Come y sobrevive, evita a los grandes!", { size: 64, fill: "#fff" }); subtitleTxt.anchor.set(0.5, 0); subtitleTxt.x = 2048 / 2; subtitleTxt.y = 520; startScreen.addChild(subtitleTxt); // Name input label var nameLabel = new Text2("Tu nombre:", { size: 64, fill: "#fff" }); nameLabel.anchor.set(0.5, 0); nameLabel.x = 2048 / 2; nameLabel.y = 800; startScreen.addChild(nameLabel); // Simulated name input (tap to edit) var playerName = ""; var nameInput = new Text2("Toca para escribir...", { size: 80, fill: 0xFFFFCC }); nameInput.anchor.set(0.5, 0); nameInput.x = 2048 / 2; nameInput.y = 900; startScreen.addChild(nameInput); // Dice icon for random name var diceIcon = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.1, x: nameInput.x + 320, y: nameInput.y + 55, color: 0xffffff }); startScreen.addChild(diceIcon); diceIcon.interactive = true; diceIcon.buttonMode = true; // Dice icon click: set random name diceIcon.down = function (x, y, obj) { var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"]; playerName = allNames[Math.floor(Math.random() * allNames.length)]; nameInput.setText(playerName); editingName = false; }; var editingName = false; nameInput.interactive = true; nameInput.buttonMode = true; nameInput.down = function (x, y, obj) { editingName = true; nameInput.setText((playerName.length > 0 ? playerName : "") + "|"); }; // Local multiplayer toggle button var localBtn = new Text2("Modo: 1 Jugador", { size: 80, fill: 0x00CCFF }); localBtn.anchor.set(0.5, 0.5); localBtn.x = 2048 / 2; localBtn.y = 1100; localBtn.interactive = true; localBtn.buttonMode = true; startScreen.addChild(localBtn); localBtn.down = function (x, y, obj) { localMultiplayer = !localMultiplayer; localBtn.setText(localMultiplayer ? "Modo: 2 Jugadores" : "Modo: 1 Jugador"); }; // Start button var startBtn = new Text2("JUGAR", { size: 120, fill: 0x00FF99 }); startBtn.anchor.set(0.5, 0.5); startBtn.x = 2048 / 2; startBtn.y = 1200; startBtn.interactive = true; startBtn.buttonMode = true; startScreen.addChild(startBtn); // Credits (bottom) var creditsTxt = new Text2("Inspirado en Slither.io", { size: 40, fill: "#aaa" }); creditsTxt.anchor.set(0.5, 1); creditsTxt.x = 2048 / 2; creditsTxt.y = 2732 - 40; startScreen.addChild(creditsTxt); // Animate background cells startScreen.update = function () { for (var i = 0; i < startBgCells.length; i++) { var c = startBgCells[i]; c.x += c._vx; c.y += c._vy; // Bounce off edges if (c.x < 200 || c.x > 1848) c._vx *= -1; if (c.y < 400 || c.y > 2200) c._vy *= -1; } }; game.update = function (oldUpdate) { return function () { if (startScreen.visible && startScreen.update) startScreen.update(); if (typeof oldUpdate === "function") oldUpdate.apply(this, arguments); }; }(game.update); // Name input tap-to-edit logic game.down = function (x, y, obj) { // If editing name, simulate typing by adding a random letter (since we can't get real keyboard input) if (editingName) { // Simulate: tap = add random letter, long tap = backspace if (playerName.length < 10) { var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var letter = letters[Math.floor(Math.random() * letters.length)]; playerName += letter; } nameInput.setText(playerName + "|"); // If tap on left side, treat as backspace if (x < 2048 / 2 - 200 && playerName.length > 0) { playerName = playerName.substring(0, playerName.length - 1); nameInput.setText(playerName + "|"); } // If tap on right side, finish editing if (x > 2048 / 2 + 200) { editingName = false; nameInput.setText(playerName.length > 0 ? playerName : "Toca para escribir..."); } return; } }; // Start button logic startBtn.down = function (x, y, obj) { if (playerName.length === 0) { playerName = "Tú"; nameInput.setText(playerName); } // Hide start screen and start the game startScreen.visible = false; startScreen.interactive = false; startScreen.children.forEach(function (child) { child.visible = false; }); startGame(); }; game.addChild(startScreen); // --- Main game UI (hidden until start) --- var scoreTxt = new Text2('Size: 50', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Display for #1 (largest cell) score var topScoreTxt = new Text2('', { size: 48, fill: 0xFFD700 }); topScoreTxt.anchor.set(0.5, 0); topScoreTxt.y = 70; // Place below main score, avoid top 100px LK.gui.top.addChild(topScoreTxt); // Create a world container for all game objects (slither.io style) var world = new Container(); game.addChild(world); // --- Game start logic --- function startGame() { // Play background music (looping, fade in) LK.playMusic('musicId', { fade: { start: 0, end: 1, duration: 1200 } }); // Initialize player cell playerCell = new PlayerCell(); playerCell.x = 44000 / 2; playerCell.y = 44000 / 2; // Assign a name to the player cell var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"]; playerCell.randomName = playerName && playerName.length > 0 ? playerName : allNames[Math.floor(Math.random() * allNames.length)]; // If local multiplayer, spawn a second player cell if (localMultiplayer) { playerCell2 = new PlayerCell(); playerCell2.x = 44000 / 2 + 300; playerCell2.y = 44000 / 2 + 300; playerCell2.randomName = "Jugador 2"; world.addChild(playerCell2); } else { playerCell2 = null; } // Pick a random name for the #1 cell at game start, different from playerName if possible var filteredNamesForTop = allNames; if (playerName && playerName.length > 0) { filteredNamesForTop = []; for (var ni = 0; ni < allNames.length; ni++) { if (allNames[ni] !== playerName) filteredNamesForTop.push(allNames[ni]); } if (filteredNamesForTop.length === 0) filteredNamesForTop = allNames; } game.topCellRandomName = filteredNamesForTop[Math.floor(Math.random() * filteredNamesForTop.length)]; world.addChild(playerCell); } // Generate initial food function spawnFood() { var food = new Food(); food.x = Math.random() * mapSize; food.y = Math.random() * mapSize; foods.push(food); world.addChild(food); } function spawnPowerFood() { var powerFood = new PowerFood(); powerFood.x = Math.random() * mapSize; powerFood.y = Math.random() * mapSize; powerFoods.push(powerFood); world.addChild(powerFood); } function spawnPapa() { var papa = new Papa(); papa.x = Math.random() * mapSize; papa.y = Math.random() * mapSize; papas.push(papa); world.addChild(papa); } ; // Generate initial predators function spawnPredator() { var predator = new Predator(); predator.x = Math.random() * mapSize; predator.y = Math.random() * mapSize; // Assign a random name to the predator var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"]; predator.randomName = allNames[Math.floor(Math.random() * allNames.length)]; predators.push(predator); world.addChild(predator); } // Generate AI cells function spawnAICell() { var ai = new AICell(); ai.x = Math.random() * mapSize; ai.y = Math.random() * mapSize; // Assign random size: 50, 70, 90, 150, or 300 (removed 1000 to reduce large bots) var possibleSizes = [50, 70, 90, 150, 300]; var sizeIdx = Math.floor(Math.random() * possibleSizes.length); ai.size = possibleSizes[sizeIdx]; // Update scale to match new size var scale = ai.size / 50; if (ai.children && ai.children.length > 0) { var cellGraphics = ai.children[0]; cellGraphics.scaleX = scale; cellGraphics.scaleY = scale; } // Assign a random name to this AI cell var aiNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"]; ai.randomName = aiNames[Math.floor(Math.random() * aiNames.length)]; // Only some AI cells will hunt the player // 99% of AI cells will hunt the player (extreme) ai.huntsPlayer = Math.random() < 0.99; // Increase base speed for all AI cells for much more challenge ai.speed += 2.5; aiCells.push(ai); world.addChild(ai); } // Spawn giant AI cells function spawnGiantAICell() { var ai = new AICell(); ai.x = Math.random() * mapSize; ai.y = Math.random() * mapSize; // Set giant size ai.size = 1000; // Update scale to match new size var scale = ai.size / 50; if (ai.children && ai.children.length > 0) { var cellGraphics = ai.children[0]; cellGraphics.scaleX = scale; cellGraphics.scaleY = scale; } // Assign a random name to this AI cell var aiNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"]; ai.randomName = aiNames[Math.floor(Math.random() * aiNames.length)]; // Giant cells always hunt the player ai.huntsPlayer = true; aiCells.push(ai); world.addChild(ai); } // Spawn initial food, most near the player, some random for (var i = 0; i < 80; i++) { if (i < 60 && playerCell !== null) { // Near player: in a ring 300-900px from player var angle = Math.random() * Math.PI * 2; var dist = 300 + Math.random() * 600; var fx = playerCell.x + Math.cos(angle) * dist; var fy = playerCell.y + Math.sin(angle) * dist; fx = Math.max(20, Math.min(fx, mapSize - 20)); fy = Math.max(20, Math.min(fy, mapSize - 20)); var food = new Food(); food.x = fx; food.y = fy; foods.push(food); world.addChild(food); } else { spawnFood(); } } // Spawn initial power food (less common) for (var i = 0; i < 15; i++) { spawnPowerFood(); } // Spawn initial papas (potato food) for (var i = 0; i < 10; i++) { spawnPapa(); } // Spawn initial predators for (var i = 0; i < 5; i++) { spawnPredator(); } // Spawn initial AI cells for (var i = 0; i < 40; i++) { spawnAICell(); } // Spawn 2-10 giant AI cells ONLY if playerCell exists and playerCell.size >= 5000 if (playerCell && playerCell.size >= 5000) { var giantCount = 2 + Math.floor(Math.random() * 9); // Random number between 2 and 10 for (var i = 0; i < giantCount; i++) { spawnGiantAICell(); } } // Slither.io style swipe/drag controls var dragging = false; var dragTouchId = null; var lastTouchX = null; var lastTouchY = null; var dragStartX = null; var dragStartY = null; var dragPlayerStartX = null; var dragPlayerStartY = null; game.down = function (x, y, obj) { // Start dragging from anywhere except top left 100x100 if (!(x < 100 && y < 100)) { dragging = true; dragTouchId = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : null; dragStartX = x; dragStartY = y; if (playerCell !== null) { dragPlayerStartX = playerCell.x; dragPlayerStartY = playerCell.y; } else { dragPlayerStartX = 0; dragPlayerStartY = 0; } lastTouchX = x; lastTouchY = y; } }; game.move = function (x, y, obj) { if (dragging && (dragTouchId === null || obj && obj.event && obj.event.identifier === dragTouchId)) { lastTouchX = x; lastTouchY = y; // Calculate drag vector relative to drag start var dx = x - dragStartX; var dy = y - dragStartY; // Set a max drag distance for control sensitivity var maxDrag = 400; var dragLen = Math.sqrt(dx * dx + dy * dy); if (dragLen > maxDrag) { dx = dx * maxDrag / dragLen; dy = dy * maxDrag / dragLen; } // Set the target position for the player cell(s) based on drag if (localMultiplayer && playerCell2 !== null) { // Split screen: left half controls player 1, right half controls player 2 if (x < 2048 / 2) { playerCell.targetX = dragPlayerStartX + dx * 14; playerCell.targetY = dragPlayerStartY + dy * 14; } else { playerCell2.targetX = dragPlayerStartX + dx * 8; playerCell2.targetY = dragPlayerStartY + dy * 8; } } else if (playerCell !== null) { playerCell.targetX = dragPlayerStartX + dx * 14; playerCell.targetY = dragPlayerStartY + dy * 14; } } }; game.up = function (x, y, obj) { if (dragging && (dragTouchId === null || obj && obj.event && obj.event.identifier === dragTouchId)) { dragging = false; dragTouchId = null; lastTouchX = null; lastTouchY = null; dragStartX = null; dragStartY = null; dragPlayerStartX = null; dragPlayerStartY = null; } }; game.update = function () { if (!playerCell) { return; } if (localMultiplayer && !playerCell2) { return; } // Camera logic: center world on playerCell, clamp to map bounds (slither.io style) var viewWidth = 2048; var viewHeight = 2732; // Dynamically grow map size as player grows var minMapSize = 44000; var maxMapSize = 200000; mapSize = minMapSize + Math.floor((playerCell.size - 50) * 12); if (mapSize > maxMapSize) mapSize = maxMapSize; // Calculate zoom based on player size (larger player = zoomed out more) // More zoom out: lower minZoom, faster zoom out curve var baseZoom = 1.0; var minZoom = 0.12; // Allow even more zoom out for very large cells var zoomFactor = baseZoom; if (playerCell.size > 50) { // Zoom out as player gets bigger, more pronounced for very large cells zoomFactor = Math.max(minZoom, baseZoom - (playerCell.size - 50) / 500); } // Smooth zoom transition if (typeof world.lastZoom === "undefined") world.lastZoom = zoomFactor; world.lastZoom += (zoomFactor - world.lastZoom) * 0.1; // Apply zoom to world world.scaleX = world.lastZoom; world.scaleY = world.lastZoom; // Adjust view calculations for zoom var adjustedViewWidth = viewWidth / world.lastZoom; var adjustedViewHeight = viewHeight / world.lastZoom; // Calculate camera target position to center player var camTargetX = playerCell.x - adjustedViewWidth / 2; var camTargetY = playerCell.y - adjustedViewHeight / 2; // Clamp camera to map bounds camTargetX = Math.max(0, Math.min(camTargetX, mapSize - adjustedViewWidth)); camTargetY = Math.max(0, Math.min(camTargetY, mapSize - adjustedViewHeight)); // Smooth camera movement (slither.io style) if (typeof world.lastCamX === "undefined") world.lastCamX = camTargetX; if (typeof world.lastCamY === "undefined") world.lastCamY = camTargetY; world.lastCamX += (camTargetX - world.lastCamX) * 0.15; world.lastCamY += (camTargetY - world.lastCamY) * 0.15; // Move world container world.x = -Math.round(world.lastCamX * world.lastZoom); world.y = -Math.round(world.lastCamY * world.lastZoom); // AI cells update and logic for (var i = aiCells.length - 1; i >= 0; i--) { var ai = aiCells[i]; if (!ai.alive) { continue; } ai.update(); // AI eats food for (var j = foods.length - 1; j >= 0; j--) { var food = foods[j]; if (food.consumed) { continue; } var dx = ai.x - food.x; var dy = ai.y - food.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ai.size / 2 + food.size / 2) { food.consumed = true; food.destroy(); foods.splice(j, 1); ai.grow(600); // AI cells grow even faster from food (extreme) break; } } // AI eats power food for (var j = powerFoods.length - 1; j >= 0; j--) { var powerFood = powerFoods[j]; if (powerFood.consumed) { continue; } var dx = ai.x - powerFood.x; var dy = ai.y - powerFood.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ai.size / 2 + powerFood.size / 2) { powerFood.consumed = true; powerFood.destroy(); powerFoods.splice(j, 1); ai.grow(powerFood.growthValue * 5); // AI cells grow even faster from power food (extreme) break; } } // AI eats papas for (var j = papas.length - 1; j >= 0; j--) { var papa = papas[j]; if (papa.consumed) { continue; } var dx = ai.x - papa.x; var dy = ai.y - papa.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ai.size / 2 + papa.size / 2) { papa.consumed = true; papa.destroy(); papas.splice(j, 1); ai.grow(papa.growthValue * 6); // AI cells grow even faster from papas (extreme) break; } } // AI eats other AI (io style) for (var k = aiCells.length - 1; k >= 0; k--) { if (i === k) { continue; } var other = aiCells[k]; if (!other.alive) { continue; } var dx = ai.x - other.x; var dy = ai.y - other.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ai.size / 2 + other.size / 2) { // Prevent passing through if same size (within 10% margin) if (Math.abs(ai.size - other.size) < Math.max(ai.size, other.size) * 0.1) { // Move both cells away from each other along the collision vector var overlap = ai.size / 2 + other.size / 2 - distance; if (overlap > 0 && distance > 0.01) { var pushX = dx / distance * overlap / 2; var pushY = dy / distance * overlap / 2; ai.x += pushX; ai.y += pushY; other.x -= pushX; other.y -= pushY; } // Randomly allow one to eat the other if (Math.random() < 0.5) { // ai eats other if (currentHunter === other) { currentHunter = null; } other.alive = false; other.destroy(); ai.grow(other.size * 2.5); aiCells.splice(k, 1); if (k < i) { i--; } break; } else { // other eats ai if (currentHunter === ai) { currentHunter = null; } ai.alive = false; ai.destroy(); aiCells.splice(i, 1); break; } // Do not allow passing through continue; } if (ai.size > other.size * 1.2) { // Clear hunter if the eaten AI was the current hunter if (currentHunter === other) { currentHunter = null; } other.alive = false; other.destroy(); ai.grow(other.size * 2.5); // AI cells grow even faster from eating other AI (extreme) aiCells.splice(k, 1); if (k < i) { i--; } // Adjust index if needed break; } } } // AI can eat player or be eaten by player var dxp = ai.x - playerCell.x; var dyp = ai.y - playerCell.y; var distp = Math.sqrt(dxp * dxp + dyp * dyp); if (distp < ai.size / 2 + playerCell.size / 2) { // Prevent passing through if same size (within 10% margin) if (Math.abs(ai.size - playerCell.size) < Math.max(ai.size, playerCell.size) * 0.1) { // Move both cells away from each other along the collision vector var overlap = ai.size / 2 + playerCell.size / 2 - distp; if (overlap > 0 && distp > 0.01) { var pushX = dxp / distp * overlap / 2; var pushY = dyp / distp * overlap / 2; ai.x += pushX; ai.y += pushY; playerCell.x -= pushX; playerCell.y -= pushY; } // Randomly allow one to eat the other if (Math.random() < 0.5) { // Player is eaten by AI LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else { // Player eats AI if (currentHunter === ai) { currentHunter = null; } ai.alive = false; ai.destroy(); aiCells.splice(i, 1); playerCell.grow(ai.size / 2); cellsEaten++; LK.getSound('eat').play(); scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten); break; } // Do not allow passing through continue; } if (ai.size > playerCell.size * 1.2) { // Player is eaten by a larger AI cell LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else if (playerCell.size > ai.size * 1.2) { // Player eats smaller AI cell // Clear hunter if the eaten AI was the current hunter if (currentHunter === ai) { currentHunter = null; } ai.alive = false; ai.destroy(); aiCells.splice(i, 1); playerCell.grow(ai.size / 2); cellsEaten++; LK.getSound('eat').play(); scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten); break; } } } // Check food collisions for player for (var i = foods.length - 1; i >= 0; i--) { var food = foods[i]; if (food.consumed) { continue; } var dx = playerCell.x - food.x; var dy = playerCell.y - food.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < playerCell.size / 2 + food.size / 2) { // Consume food food.consumed = true; food.destroy(); foods.splice(i, 1); playerCell.grow(5); // Do not increment cellsEaten for food LK.getSound('eat').play(); // Update score display scoreTxt.setText('Size: ' + Math.floor(playerCell.size)); } // Player 2 food collision if (localMultiplayer && playerCell2) { var dx2 = playerCell2.x - food.x; var dy2 = playerCell2.y - food.y; var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); if (distance2 < playerCell2.size / 2 + food.size / 2) { food.consumed = true; food.destroy(); foods.splice(i, 1); playerCell2.grow(5); LK.getSound('eat').play(); } } } // Check power food collisions for player for (var i = powerFoods.length - 1; i >= 0; i--) { var powerFood = powerFoods[i]; if (powerFood.consumed) { continue; } var dx = playerCell.x - powerFood.x; var dy = playerCell.y - powerFood.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < playerCell.size / 2 + powerFood.size / 2) { // Consume power food powerFood.consumed = true; powerFood.destroy(); powerFoods.splice(i, 1); playerCell.grow(powerFood.growthValue); // Do not increment cellsEaten for power food LK.getSound('eat').play(); // Update score display scoreTxt.setText('Size: ' + Math.floor(playerCell.size)); } // Player 2 power food collision if (localMultiplayer && playerCell2) { var dx2 = playerCell2.x - powerFood.x; var dy2 = playerCell2.y - powerFood.y; var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); if (distance2 < playerCell2.size / 2 + powerFood.size / 2) { powerFood.consumed = true; powerFood.destroy(); powerFoods.splice(i, 1); playerCell2.grow(powerFood.growthValue); LK.getSound('eat').play(); } } } // Check papa collisions for player for (var i = papas.length - 1; i >= 0; i--) { var papa = papas[i]; if (papa.consumed) { continue; } var dx = playerCell.x - papa.x; var dy = playerCell.y - papa.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < playerCell.size / 2 + papa.size / 2) { // Consume papa papa.consumed = true; papa.destroy(); papas.splice(i, 1); playerCell.grow(papa.growthValue); // Do not increment cellsEaten for papa LK.getSound('eat').play(); // Update score display scoreTxt.setText('Size: ' + Math.floor(playerCell.size)); } // Player 2 papa collision if (localMultiplayer && playerCell2) { var dx2 = playerCell2.x - papa.x; var dy2 = playerCell2.y - papa.y; var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); if (distance2 < playerCell2.size / 2 + papa.size / 2) { papa.consumed = true; papa.destroy(); papas.splice(i, 1); playerCell2.grow(papa.growthValue); LK.getSound('eat').play(); } } } // Check predator collisions for (var i = 0; i < predators.length; i++) { var predator = predators[i]; var dx = playerCell.x - predator.x; var dy = playerCell.y - predator.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < playerCell.size / 2 + predator.size / 2) { if (predator.size > playerCell.size) { // Game over - eaten by predator LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else if (playerCell.size > predator.size * 1.2) { // Player can eat predator predator.destroy(); predators.splice(i, 1); playerCell.grow(70); cellsEaten++; LK.getSound('eat').play(); scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten); // Spawn new predator, and make all predators grow a lot if player is eaten for (var p = 0; p < predators.length; p++) { predators[p].size += 300; // All predators get much bigger (extreme) } spawnPredator(); i--; // Adjust index after removal } } // Player 2 predator collision if (localMultiplayer && playerCell2) { var dx2 = playerCell2.x - predator.x; var dy2 = playerCell2.y - predator.y; var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); if (distance2 < playerCell2.size / 2 + predator.size / 2) { if (predator.size > playerCell2.size) { LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else if (playerCell2.size > predator.size * 1.2) { predator.destroy(); predators.splice(i, 1); playerCell2.grow(70); LK.getSound('eat').play(); spawnPredator(); i--; } } } } // Spawn new food periodically, but always near the player if (LK.ticks % 120 == 0 && foods.length < 65) { // Spawn food in a ring 300-700px from player, random angle var angle = Math.random() * Math.PI * 2; var dist = 300 + Math.random() * 400; var fx = playerCell.x + Math.cos(angle) * dist; var fy = playerCell.y + Math.sin(angle) * dist; // Clamp to map bounds fx = Math.max(20, Math.min(fx, mapSize - 20)); fy = Math.max(20, Math.min(fy, mapSize - 20)); var food = new Food(); food.x = fx; food.y = fy; foods.push(food); world.addChild(food); } // Spawn power food less frequently if (LK.ticks % 300 == 0 && powerFoods.length < 20) { // Spawn power food in a ring 400-800px from player, random angle var angle = Math.random() * Math.PI * 2; var dist = 400 + Math.random() * 400; var fx = playerCell.x + Math.cos(angle) * dist; var fy = playerCell.y + Math.sin(angle) * dist; // Clamp to map bounds fx = Math.max(30, Math.min(fx, mapSize - 30)); fy = Math.max(30, Math.min(fy, mapSize - 30)); var powerFood = new PowerFood(); powerFood.x = fx; powerFood.y = fy; powerFoods.push(powerFood); world.addChild(powerFood); } // Spawn papas periodically if (LK.ticks % 200 == 0 && papas.length < 15) { // Spawn papa in a ring 350-600px from player, random angle var angle = Math.random() * Math.PI * 2; var dist = 350 + Math.random() * 250; var fx = playerCell.x + Math.cos(angle) * dist; var fy = playerCell.y + Math.sin(angle) * dist; // Clamp to map bounds fx = Math.max(35, Math.min(fx, mapSize - 35)); fy = Math.max(35, Math.min(fy, mapSize - 35)); var papa = new Papa(); papa.x = fx; papa.y = fy; papas.push(papa); world.addChild(papa); } // Add more predators as player grows (extreme: much more frequent, much higher max, much faster) if (LK.ticks % 40 == 0 && predators.length < 80) { spawnPredator(); } // Add more AI cells as the game progresses (extreme: much more frequent, much higher max, much larger) if (LK.ticks % 20 == 0 && aiCells.length < 120) { spawnAICell(); // Only spawn giant AI cells if playerCell exists and playerCell.size >= 5000 if (playerCell && playerCell.size >= 5000 && aiCells.length < 120 && LK.ticks % 100 == 0) { spawnGiantAICell(); } } // Player vs player collision (local mode) if (localMultiplayer && playerCell && playerCell2) { var dx = playerCell.x - playerCell2.x; var dy = playerCell.y - playerCell2.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < playerCell.size / 2 + playerCell2.size / 2) { // Prevent passing through if same size (within 10% margin) if (Math.abs(playerCell.size - playerCell2.size) < Math.max(playerCell.size, playerCell2.size) * 0.1) { // Move both cells away from each other along the collision vector var overlap = playerCell.size / 2 + playerCell2.size / 2 - distance; if (overlap > 0 && distance > 0.01) { var pushX = dx / distance * overlap / 2; var pushY = dy / distance * overlap / 2; playerCell.x += pushX; playerCell.y += pushY; playerCell2.x -= pushX; playerCell2.y -= pushY; } // Randomly allow one to eat the other if (Math.random() < 0.5) { // Player 1 eats player 2 LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else { // Player 2 eats player 1 LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } // Do not allow eating or passing through } else if (playerCell.size > playerCell2.size * 1.2) { // Player 1 eats player 2 LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } else if (playerCell2.size > playerCell.size * 1.2) { // Player 2 eats player 1 LK.effects.flashScreen(0xff0000, 1000); LK.stopMusic(); LK.showGameOver(); return; } } } // Find the largest cell (player, aiCells, predators) var topCell = playerCell; var topCellType = "Tú"; var topCellSize = playerCell ? playerCell.size : 0; var topCellName = null; // Check AI cells for (var i = 0; i < aiCells.length; i++) { if (aiCells[i].alive && aiCells[i].size > topCellSize) { topCell = aiCells[i]; topCellType = "Bot"; topCellSize = aiCells[i].size; topCellName = aiCells[i].randomName; } } // Check predators for (var i = 0; i < predators.length; i++) { if (predators[i].size > topCellSize) { topCell = predators[i]; topCellType = "Depredador"; topCellSize = predators[i].size; topCellName = null; } } // --- Ensure #1 always has at least 50000 points and a different random name unless already higher --- if (topCellSize < 50000) { topCellSize = 50000; // If player is not #1, show as Bot with a random name (different from playerName) // Use the random name picked at game start for consistency if (topCell !== playerCell) { topCellType = "Bot"; // Use the random name picked at game start, fallback if not set topCellName = typeof game.topCellRandomName !== "undefined" && game.topCellRandomName ? game.topCellRandomName : "Bot"; } } // Show #1 score if (topCell === playerCell) { topScoreTxt.setText("#1: Tú (" + Math.floor(topCellSize) + ")"); } else if (topCellType === "Bot" && topCellName) { topScoreTxt.setText("#1: " + topCellName + " (" + Math.floor(topCellSize) + ")"); } else { topScoreTxt.setText("#1: " + topCellType + " (" + Math.floor(topCellSize) + ")"); } // No win condition: game continues infinitely even if player is #1 };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AICell = Container.expand(function () {
var self = Container.call(this);
var cellGraphics = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
// self.size is set on spawnAICell for variety
self.speed = 2 + Math.random();
self.targetX = Math.random() * 44000;
self.targetY = Math.random() * 44000;
self.alive = true;
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
if (!self.alive) {
return;
}
// --- AI Hunt Player Logic ---
// Only some AI cells hunt the player, and only one at a time
var huntingPlayer = false;
if (self.huntsPlayer && typeof playerCell !== "undefined" && playerCell !== null) {
var pdx = playerCell.x - self.x;
var pdy = playerCell.y - self.y;
var pdist = Math.sqrt(pdx * pdx + pdy * pdy);
// Only hunt if AI is bigger than player by 20%
if (self.size > playerCell.size * 1.2) {
// Hunt if player is within 2000px (long range)
if (pdist < 2000) {
// Check if no one is currently hunting or if this AI is the current hunter
if (currentHunter === null || currentHunter === self) {
self.targetX = playerCell.x;
self.targetY = playerCell.y;
huntingPlayer = true;
currentHunter = self; // Set this AI as the current hunter
}
} else if (currentHunter === self) {
// If this AI was hunting but player moved away, stop hunting
currentHunter = null;
}
} else if (currentHunter === self) {
// If this AI was hunting but is no longer big enough, stop hunting
currentHunter = null;
}
}
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Speed is constant regardless of size
var speed = 7.0;
self.x += dx / distance * speed;
self.y += dy / distance * speed;
} else {
// Pick new random target
self.targetX = Math.random() * 44000;
self.targetY = Math.random() * 44000;
}
// Keep within bounds
if (typeof mapSize === "undefined") {
var mapSize = 44000;
}
if (self.x < self.size / 2) {
self.x = self.size / 2;
}
if (self.x > mapSize - self.size / 2) {
self.x = mapSize - self.size / 2;
}
if (self.y < self.size / 2) {
self.y = self.size / 2;
}
if (self.y > mapSize - self.size / 2) {
self.y = mapSize - self.size / 2;
}
self.lastX = self.x;
self.lastY = self.y;
};
self.grow = function (amount) {
var oldSize = self.size;
self.size += amount;
if (self.size > 7000) self.size = 7000;
var scale = self.size / 50;
tween(cellGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200,
easing: tween.easeOut
});
self.speed = 7.0;
};
return self;
});
var Food = Container.expand(function () {
var self = Container.call(this);
var foodGraphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.size = 20;
self.consumed = false;
return self;
});
var Papa = Container.expand(function () {
var self = Container.call(this);
var papaGraphics = self.attachAsset('papa', {
anchorX: 0.5,
anchorY: 0.5
});
papaGraphics.tint = 0xDEB887; // Burlywood color for potato
self.size = 35;
self.consumed = false;
self.growthValue = 50; // All papas give 50 points
return self;
});
var PlayerCell = Container.expand(function () {
var self = Container.call(this);
var cellGraphics = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
self.size = 50;
self.speed = 3;
self.targetX = self.x;
self.targetY = self.y;
self.grow = function (amount) {
var oldSize = self.size;
self.size += amount;
if (self.size > 7000) self.size = 7000;
// Update visual scale
var scale = self.size / 50;
tween(cellGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200,
easing: tween.easeOut
});
// Speed remains constant regardless of size
self.speed = 7.0;
LK.getSound('grow').play();
LK.setScore(Math.floor(self.size));
// --- Allow player to keep moving and playing after reaching 7000 points ---
// No freeze or stop logic here; player can continue to move and play at max size.
};
self.update = function () {
// Slither.io style drag controls: playerCell.targetX/Y is set by drag logic in game.move
// Move towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Speed is constant regardless of size
var speed = 7.0;
self.x += dx / distance * speed;
self.y += dy / distance * speed;
}
// Keep within bounds
if (typeof mapSize === "undefined") {
var mapSize = 44000;
}
if (self.x < self.size / 2) {
self.x = self.size / 2;
}
if (self.x > mapSize - self.size / 2) {
self.x = mapSize - self.size / 2;
}
if (self.y < self.size / 2) {
self.y = self.size / 2;
}
if (self.y > mapSize - self.size / 2) {
self.y = mapSize - self.size / 2;
}
};
return self;
});
var PowerFood = Container.expand(function () {
var self = Container.call(this);
var powerFoodGraphics = self.attachAsset('powerfood', {
anchorX: 0.5,
anchorY: 0.5
});
powerFoodGraphics.tint = 0xFFD700; // Golden color
self.size = 30;
self.consumed = false;
self.growthValue = 200; // More growth than regular food
return self;
});
var Predator = Container.expand(function () {
var self = Container.call(this);
var predatorGraphics = self.attachAsset('predator', {
anchorX: 0.5,
anchorY: 0.5
});
self.size = 80;
self.speed = 4.5; // Much higher base speed for extreme challenge
self.targetX = Math.random() * 8192;
self.targetY = Math.random() * 8192;
self.update = function () {
// Cap predator size to 7000
if (self.size > 7000) self.size = 7000;
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Predators are faster (difficulty up)
self.x += dx / distance * 2.1;
self.y += dy / distance * 2.1;
} else {
// Pick new random target
self.targetX = Math.random() * 44000;
self.targetY = Math.random() * 44000;
}
// Chase player if close enough
if (typeof playerCell !== "undefined" && playerCell !== null) {
var playerDx = playerCell.x - self.x;
var playerDy = playerCell.y - self.y;
var playerDistance = Math.sqrt(playerDx * playerDx + playerDy * playerDy);
if (playerDistance < 300 && playerCell.size < self.size) {
self.x += playerDx / playerDistance * self.speed * 1.5;
self.y += playerDy / playerDistance * self.speed * 1.5;
}
}
// Keep within bounds
if (typeof mapSize === "undefined") {
var mapSize = 44000;
}
if (self.x < 0) {
self.x = 0;
}
if (self.x > mapSize) {
self.x = mapSize;
}
if (self.y < 0) {
self.y = 0;
}
if (self.y > mapSize) {
self.y = mapSize;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001a33
});
/****
* Game Code
****/
var playerCell = null;
var playerCell2 = null; // Second player for local mode
var localMultiplayer = false; // Set to true for local mode
var foods = [];
var powerFoods = [];
var papas = [];
var predators = [];
var aiCells = [];
var cellsEaten = 0;
var currentHunter = null; // Track which AI cell is currently hunting the player
// --- Map size is now global and updated dynamically in game.update ---
var mapSize = 44000;
// --- Slither.io-style Start Screen ---
var startScreen = new Container();
// Animated background: several moving cells
var startBgCells = [];
for (var i = 0; i < 12; i++) {
var cell = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
cell.scaleX = cell.scaleY = 1.2 + Math.random() * 1.8;
cell.x = 400 + Math.random() * 1248;
cell.y = 600 + Math.random() * 1600;
cell.alpha = 0.18 + Math.random() * 0.18;
cell._vx = (Math.random() - 0.5) * 1.2;
cell._vy = (Math.random() - 0.5) * 1.2;
startScreen.addChild(cell);
startBgCells.push(cell);
}
// Main logo/title
var titleTxt = new Text2("Célula Survival", {
size: 160,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0);
titleTxt.x = 2048 / 2;
titleTxt.y = 320;
startScreen.addChild(titleTxt);
// Subtitle
var subtitleTxt = new Text2("¡Come y sobrevive, evita a los grandes!", {
size: 64,
fill: "#fff"
});
subtitleTxt.anchor.set(0.5, 0);
subtitleTxt.x = 2048 / 2;
subtitleTxt.y = 520;
startScreen.addChild(subtitleTxt);
// Name input label
var nameLabel = new Text2("Tu nombre:", {
size: 64,
fill: "#fff"
});
nameLabel.anchor.set(0.5, 0);
nameLabel.x = 2048 / 2;
nameLabel.y = 800;
startScreen.addChild(nameLabel);
// Simulated name input (tap to edit)
var playerName = "";
var nameInput = new Text2("Toca para escribir...", {
size: 80,
fill: 0xFFFFCC
});
nameInput.anchor.set(0.5, 0);
nameInput.x = 2048 / 2;
nameInput.y = 900;
startScreen.addChild(nameInput);
// Dice icon for random name
var diceIcon = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: nameInput.x + 320,
y: nameInput.y + 55,
color: 0xffffff
});
startScreen.addChild(diceIcon);
diceIcon.interactive = true;
diceIcon.buttonMode = true;
// Dice icon click: set random name
diceIcon.down = function (x, y, obj) {
var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"];
playerName = allNames[Math.floor(Math.random() * allNames.length)];
nameInput.setText(playerName);
editingName = false;
};
var editingName = false;
nameInput.interactive = true;
nameInput.buttonMode = true;
nameInput.down = function (x, y, obj) {
editingName = true;
nameInput.setText((playerName.length > 0 ? playerName : "") + "|");
};
// Local multiplayer toggle button
var localBtn = new Text2("Modo: 1 Jugador", {
size: 80,
fill: 0x00CCFF
});
localBtn.anchor.set(0.5, 0.5);
localBtn.x = 2048 / 2;
localBtn.y = 1100;
localBtn.interactive = true;
localBtn.buttonMode = true;
startScreen.addChild(localBtn);
localBtn.down = function (x, y, obj) {
localMultiplayer = !localMultiplayer;
localBtn.setText(localMultiplayer ? "Modo: 2 Jugadores" : "Modo: 1 Jugador");
};
// Start button
var startBtn = new Text2("JUGAR", {
size: 120,
fill: 0x00FF99
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = 2048 / 2;
startBtn.y = 1200;
startBtn.interactive = true;
startBtn.buttonMode = true;
startScreen.addChild(startBtn);
// Credits (bottom)
var creditsTxt = new Text2("Inspirado en Slither.io", {
size: 40,
fill: "#aaa"
});
creditsTxt.anchor.set(0.5, 1);
creditsTxt.x = 2048 / 2;
creditsTxt.y = 2732 - 40;
startScreen.addChild(creditsTxt);
// Animate background cells
startScreen.update = function () {
for (var i = 0; i < startBgCells.length; i++) {
var c = startBgCells[i];
c.x += c._vx;
c.y += c._vy;
// Bounce off edges
if (c.x < 200 || c.x > 1848) c._vx *= -1;
if (c.y < 400 || c.y > 2200) c._vy *= -1;
}
};
game.update = function (oldUpdate) {
return function () {
if (startScreen.visible && startScreen.update) startScreen.update();
if (typeof oldUpdate === "function") oldUpdate.apply(this, arguments);
};
}(game.update);
// Name input tap-to-edit logic
game.down = function (x, y, obj) {
// If editing name, simulate typing by adding a random letter (since we can't get real keyboard input)
if (editingName) {
// Simulate: tap = add random letter, long tap = backspace
if (playerName.length < 10) {
var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var letter = letters[Math.floor(Math.random() * letters.length)];
playerName += letter;
}
nameInput.setText(playerName + "|");
// If tap on left side, treat as backspace
if (x < 2048 / 2 - 200 && playerName.length > 0) {
playerName = playerName.substring(0, playerName.length - 1);
nameInput.setText(playerName + "|");
}
// If tap on right side, finish editing
if (x > 2048 / 2 + 200) {
editingName = false;
nameInput.setText(playerName.length > 0 ? playerName : "Toca para escribir...");
}
return;
}
};
// Start button logic
startBtn.down = function (x, y, obj) {
if (playerName.length === 0) {
playerName = "Tú";
nameInput.setText(playerName);
}
// Hide start screen and start the game
startScreen.visible = false;
startScreen.interactive = false;
startScreen.children.forEach(function (child) {
child.visible = false;
});
startGame();
};
game.addChild(startScreen);
// --- Main game UI (hidden until start) ---
var scoreTxt = new Text2('Size: 50', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Display for #1 (largest cell) score
var topScoreTxt = new Text2('', {
size: 48,
fill: 0xFFD700
});
topScoreTxt.anchor.set(0.5, 0);
topScoreTxt.y = 70; // Place below main score, avoid top 100px
LK.gui.top.addChild(topScoreTxt);
// Create a world container for all game objects (slither.io style)
var world = new Container();
game.addChild(world);
// --- Game start logic ---
function startGame() {
// Play background music (looping, fade in)
LK.playMusic('musicId', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// Initialize player cell
playerCell = new PlayerCell();
playerCell.x = 44000 / 2;
playerCell.y = 44000 / 2;
// Assign a name to the player cell
var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"];
playerCell.randomName = playerName && playerName.length > 0 ? playerName : allNames[Math.floor(Math.random() * allNames.length)];
// If local multiplayer, spawn a second player cell
if (localMultiplayer) {
playerCell2 = new PlayerCell();
playerCell2.x = 44000 / 2 + 300;
playerCell2.y = 44000 / 2 + 300;
playerCell2.randomName = "Jugador 2";
world.addChild(playerCell2);
} else {
playerCell2 = null;
}
// Pick a random name for the #1 cell at game start, different from playerName if possible
var filteredNamesForTop = allNames;
if (playerName && playerName.length > 0) {
filteredNamesForTop = [];
for (var ni = 0; ni < allNames.length; ni++) {
if (allNames[ni] !== playerName) filteredNamesForTop.push(allNames[ni]);
}
if (filteredNamesForTop.length === 0) filteredNamesForTop = allNames;
}
game.topCellRandomName = filteredNamesForTop[Math.floor(Math.random() * filteredNamesForTop.length)];
world.addChild(playerCell);
}
// Generate initial food
function spawnFood() {
var food = new Food();
food.x = Math.random() * mapSize;
food.y = Math.random() * mapSize;
foods.push(food);
world.addChild(food);
}
function spawnPowerFood() {
var powerFood = new PowerFood();
powerFood.x = Math.random() * mapSize;
powerFood.y = Math.random() * mapSize;
powerFoods.push(powerFood);
world.addChild(powerFood);
}
function spawnPapa() {
var papa = new Papa();
papa.x = Math.random() * mapSize;
papa.y = Math.random() * mapSize;
papas.push(papa);
world.addChild(papa);
}
;
// Generate initial predators
function spawnPredator() {
var predator = new Predator();
predator.x = Math.random() * mapSize;
predator.y = Math.random() * mapSize;
// Assign a random name to the predator
var allNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"];
predator.randomName = allNames[Math.floor(Math.random() * allNames.length)];
predators.push(predator);
world.addChild(predator);
}
// Generate AI cells
function spawnAICell() {
var ai = new AICell();
ai.x = Math.random() * mapSize;
ai.y = Math.random() * mapSize;
// Assign random size: 50, 70, 90, 150, or 300 (removed 1000 to reduce large bots)
var possibleSizes = [50, 70, 90, 150, 300];
var sizeIdx = Math.floor(Math.random() * possibleSizes.length);
ai.size = possibleSizes[sizeIdx];
// Update scale to match new size
var scale = ai.size / 50;
if (ai.children && ai.children.length > 0) {
var cellGraphics = ai.children[0];
cellGraphics.scaleX = scale;
cellGraphics.scaleY = scale;
}
// Assign a random name to this AI cell
var aiNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"];
ai.randomName = aiNames[Math.floor(Math.random() * aiNames.length)];
// Only some AI cells will hunt the player
// 99% of AI cells will hunt the player (extreme)
ai.huntsPlayer = Math.random() < 0.99;
// Increase base speed for all AI cells for much more challenge
ai.speed += 2.5;
aiCells.push(ai);
world.addChild(ai);
}
// Spawn giant AI cells
function spawnGiantAICell() {
var ai = new AICell();
ai.x = Math.random() * mapSize;
ai.y = Math.random() * mapSize;
// Set giant size
ai.size = 1000;
// Update scale to match new size
var scale = ai.size / 50;
if (ai.children && ai.children.length > 0) {
var cellGraphics = ai.children[0];
cellGraphics.scaleX = scale;
cellGraphics.scaleY = scale;
}
// Assign a random name to this AI cell
var aiNames = ["Nano", "Blob", "Zeta", "Mito", "Viru", "Giga", "Beta", "Toxi", "Rex", "Lumo", "Fago", "Proto", "Mega", "Pico", "Tera", "Vivo", "Cello", "Dino", "Mobi", "Rondo"];
ai.randomName = aiNames[Math.floor(Math.random() * aiNames.length)];
// Giant cells always hunt the player
ai.huntsPlayer = true;
aiCells.push(ai);
world.addChild(ai);
}
// Spawn initial food, most near the player, some random
for (var i = 0; i < 80; i++) {
if (i < 60 && playerCell !== null) {
// Near player: in a ring 300-900px from player
var angle = Math.random() * Math.PI * 2;
var dist = 300 + Math.random() * 600;
var fx = playerCell.x + Math.cos(angle) * dist;
var fy = playerCell.y + Math.sin(angle) * dist;
fx = Math.max(20, Math.min(fx, mapSize - 20));
fy = Math.max(20, Math.min(fy, mapSize - 20));
var food = new Food();
food.x = fx;
food.y = fy;
foods.push(food);
world.addChild(food);
} else {
spawnFood();
}
}
// Spawn initial power food (less common)
for (var i = 0; i < 15; i++) {
spawnPowerFood();
}
// Spawn initial papas (potato food)
for (var i = 0; i < 10; i++) {
spawnPapa();
}
// Spawn initial predators
for (var i = 0; i < 5; i++) {
spawnPredator();
}
// Spawn initial AI cells
for (var i = 0; i < 40; i++) {
spawnAICell();
}
// Spawn 2-10 giant AI cells ONLY if playerCell exists and playerCell.size >= 5000
if (playerCell && playerCell.size >= 5000) {
var giantCount = 2 + Math.floor(Math.random() * 9); // Random number between 2 and 10
for (var i = 0; i < giantCount; i++) {
spawnGiantAICell();
}
}
// Slither.io style swipe/drag controls
var dragging = false;
var dragTouchId = null;
var lastTouchX = null;
var lastTouchY = null;
var dragStartX = null;
var dragStartY = null;
var dragPlayerStartX = null;
var dragPlayerStartY = null;
game.down = function (x, y, obj) {
// Start dragging from anywhere except top left 100x100
if (!(x < 100 && y < 100)) {
dragging = true;
dragTouchId = obj && obj.event && obj.event.identifier !== undefined ? obj.event.identifier : null;
dragStartX = x;
dragStartY = y;
if (playerCell !== null) {
dragPlayerStartX = playerCell.x;
dragPlayerStartY = playerCell.y;
} else {
dragPlayerStartX = 0;
dragPlayerStartY = 0;
}
lastTouchX = x;
lastTouchY = y;
}
};
game.move = function (x, y, obj) {
if (dragging && (dragTouchId === null || obj && obj.event && obj.event.identifier === dragTouchId)) {
lastTouchX = x;
lastTouchY = y;
// Calculate drag vector relative to drag start
var dx = x - dragStartX;
var dy = y - dragStartY;
// Set a max drag distance for control sensitivity
var maxDrag = 400;
var dragLen = Math.sqrt(dx * dx + dy * dy);
if (dragLen > maxDrag) {
dx = dx * maxDrag / dragLen;
dy = dy * maxDrag / dragLen;
}
// Set the target position for the player cell(s) based on drag
if (localMultiplayer && playerCell2 !== null) {
// Split screen: left half controls player 1, right half controls player 2
if (x < 2048 / 2) {
playerCell.targetX = dragPlayerStartX + dx * 14;
playerCell.targetY = dragPlayerStartY + dy * 14;
} else {
playerCell2.targetX = dragPlayerStartX + dx * 8;
playerCell2.targetY = dragPlayerStartY + dy * 8;
}
} else if (playerCell !== null) {
playerCell.targetX = dragPlayerStartX + dx * 14;
playerCell.targetY = dragPlayerStartY + dy * 14;
}
}
};
game.up = function (x, y, obj) {
if (dragging && (dragTouchId === null || obj && obj.event && obj.event.identifier === dragTouchId)) {
dragging = false;
dragTouchId = null;
lastTouchX = null;
lastTouchY = null;
dragStartX = null;
dragStartY = null;
dragPlayerStartX = null;
dragPlayerStartY = null;
}
};
game.update = function () {
if (!playerCell) {
return;
}
if (localMultiplayer && !playerCell2) {
return;
}
// Camera logic: center world on playerCell, clamp to map bounds (slither.io style)
var viewWidth = 2048;
var viewHeight = 2732;
// Dynamically grow map size as player grows
var minMapSize = 44000;
var maxMapSize = 200000;
mapSize = minMapSize + Math.floor((playerCell.size - 50) * 12);
if (mapSize > maxMapSize) mapSize = maxMapSize;
// Calculate zoom based on player size (larger player = zoomed out more)
// More zoom out: lower minZoom, faster zoom out curve
var baseZoom = 1.0;
var minZoom = 0.12; // Allow even more zoom out for very large cells
var zoomFactor = baseZoom;
if (playerCell.size > 50) {
// Zoom out as player gets bigger, more pronounced for very large cells
zoomFactor = Math.max(minZoom, baseZoom - (playerCell.size - 50) / 500);
}
// Smooth zoom transition
if (typeof world.lastZoom === "undefined") world.lastZoom = zoomFactor;
world.lastZoom += (zoomFactor - world.lastZoom) * 0.1;
// Apply zoom to world
world.scaleX = world.lastZoom;
world.scaleY = world.lastZoom;
// Adjust view calculations for zoom
var adjustedViewWidth = viewWidth / world.lastZoom;
var adjustedViewHeight = viewHeight / world.lastZoom;
// Calculate camera target position to center player
var camTargetX = playerCell.x - adjustedViewWidth / 2;
var camTargetY = playerCell.y - adjustedViewHeight / 2;
// Clamp camera to map bounds
camTargetX = Math.max(0, Math.min(camTargetX, mapSize - adjustedViewWidth));
camTargetY = Math.max(0, Math.min(camTargetY, mapSize - adjustedViewHeight));
// Smooth camera movement (slither.io style)
if (typeof world.lastCamX === "undefined") world.lastCamX = camTargetX;
if (typeof world.lastCamY === "undefined") world.lastCamY = camTargetY;
world.lastCamX += (camTargetX - world.lastCamX) * 0.15;
world.lastCamY += (camTargetY - world.lastCamY) * 0.15;
// Move world container
world.x = -Math.round(world.lastCamX * world.lastZoom);
world.y = -Math.round(world.lastCamY * world.lastZoom);
// AI cells update and logic
for (var i = aiCells.length - 1; i >= 0; i--) {
var ai = aiCells[i];
if (!ai.alive) {
continue;
}
ai.update();
// AI eats food
for (var j = foods.length - 1; j >= 0; j--) {
var food = foods[j];
if (food.consumed) {
continue;
}
var dx = ai.x - food.x;
var dy = ai.y - food.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ai.size / 2 + food.size / 2) {
food.consumed = true;
food.destroy();
foods.splice(j, 1);
ai.grow(600); // AI cells grow even faster from food (extreme)
break;
}
}
// AI eats power food
for (var j = powerFoods.length - 1; j >= 0; j--) {
var powerFood = powerFoods[j];
if (powerFood.consumed) {
continue;
}
var dx = ai.x - powerFood.x;
var dy = ai.y - powerFood.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ai.size / 2 + powerFood.size / 2) {
powerFood.consumed = true;
powerFood.destroy();
powerFoods.splice(j, 1);
ai.grow(powerFood.growthValue * 5); // AI cells grow even faster from power food (extreme)
break;
}
}
// AI eats papas
for (var j = papas.length - 1; j >= 0; j--) {
var papa = papas[j];
if (papa.consumed) {
continue;
}
var dx = ai.x - papa.x;
var dy = ai.y - papa.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ai.size / 2 + papa.size / 2) {
papa.consumed = true;
papa.destroy();
papas.splice(j, 1);
ai.grow(papa.growthValue * 6); // AI cells grow even faster from papas (extreme)
break;
}
}
// AI eats other AI (io style)
for (var k = aiCells.length - 1; k >= 0; k--) {
if (i === k) {
continue;
}
var other = aiCells[k];
if (!other.alive) {
continue;
}
var dx = ai.x - other.x;
var dy = ai.y - other.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ai.size / 2 + other.size / 2) {
// Prevent passing through if same size (within 10% margin)
if (Math.abs(ai.size - other.size) < Math.max(ai.size, other.size) * 0.1) {
// Move both cells away from each other along the collision vector
var overlap = ai.size / 2 + other.size / 2 - distance;
if (overlap > 0 && distance > 0.01) {
var pushX = dx / distance * overlap / 2;
var pushY = dy / distance * overlap / 2;
ai.x += pushX;
ai.y += pushY;
other.x -= pushX;
other.y -= pushY;
}
// Randomly allow one to eat the other
if (Math.random() < 0.5) {
// ai eats other
if (currentHunter === other) {
currentHunter = null;
}
other.alive = false;
other.destroy();
ai.grow(other.size * 2.5);
aiCells.splice(k, 1);
if (k < i) {
i--;
}
break;
} else {
// other eats ai
if (currentHunter === ai) {
currentHunter = null;
}
ai.alive = false;
ai.destroy();
aiCells.splice(i, 1);
break;
}
// Do not allow passing through
continue;
}
if (ai.size > other.size * 1.2) {
// Clear hunter if the eaten AI was the current hunter
if (currentHunter === other) {
currentHunter = null;
}
other.alive = false;
other.destroy();
ai.grow(other.size * 2.5); // AI cells grow even faster from eating other AI (extreme)
aiCells.splice(k, 1);
if (k < i) {
i--;
} // Adjust index if needed
break;
}
}
}
// AI can eat player or be eaten by player
var dxp = ai.x - playerCell.x;
var dyp = ai.y - playerCell.y;
var distp = Math.sqrt(dxp * dxp + dyp * dyp);
if (distp < ai.size / 2 + playerCell.size / 2) {
// Prevent passing through if same size (within 10% margin)
if (Math.abs(ai.size - playerCell.size) < Math.max(ai.size, playerCell.size) * 0.1) {
// Move both cells away from each other along the collision vector
var overlap = ai.size / 2 + playerCell.size / 2 - distp;
if (overlap > 0 && distp > 0.01) {
var pushX = dxp / distp * overlap / 2;
var pushY = dyp / distp * overlap / 2;
ai.x += pushX;
ai.y += pushY;
playerCell.x -= pushX;
playerCell.y -= pushY;
}
// Randomly allow one to eat the other
if (Math.random() < 0.5) {
// Player is eaten by AI
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else {
// Player eats AI
if (currentHunter === ai) {
currentHunter = null;
}
ai.alive = false;
ai.destroy();
aiCells.splice(i, 1);
playerCell.grow(ai.size / 2);
cellsEaten++;
LK.getSound('eat').play();
scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten);
break;
}
// Do not allow passing through
continue;
}
if (ai.size > playerCell.size * 1.2) {
// Player is eaten by a larger AI cell
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else if (playerCell.size > ai.size * 1.2) {
// Player eats smaller AI cell
// Clear hunter if the eaten AI was the current hunter
if (currentHunter === ai) {
currentHunter = null;
}
ai.alive = false;
ai.destroy();
aiCells.splice(i, 1);
playerCell.grow(ai.size / 2);
cellsEaten++;
LK.getSound('eat').play();
scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten);
break;
}
}
}
// Check food collisions for player
for (var i = foods.length - 1; i >= 0; i--) {
var food = foods[i];
if (food.consumed) {
continue;
}
var dx = playerCell.x - food.x;
var dy = playerCell.y - food.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < playerCell.size / 2 + food.size / 2) {
// Consume food
food.consumed = true;
food.destroy();
foods.splice(i, 1);
playerCell.grow(5);
// Do not increment cellsEaten for food
LK.getSound('eat').play();
// Update score display
scoreTxt.setText('Size: ' + Math.floor(playerCell.size));
}
// Player 2 food collision
if (localMultiplayer && playerCell2) {
var dx2 = playerCell2.x - food.x;
var dy2 = playerCell2.y - food.y;
var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (distance2 < playerCell2.size / 2 + food.size / 2) {
food.consumed = true;
food.destroy();
foods.splice(i, 1);
playerCell2.grow(5);
LK.getSound('eat').play();
}
}
}
// Check power food collisions for player
for (var i = powerFoods.length - 1; i >= 0; i--) {
var powerFood = powerFoods[i];
if (powerFood.consumed) {
continue;
}
var dx = playerCell.x - powerFood.x;
var dy = playerCell.y - powerFood.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < playerCell.size / 2 + powerFood.size / 2) {
// Consume power food
powerFood.consumed = true;
powerFood.destroy();
powerFoods.splice(i, 1);
playerCell.grow(powerFood.growthValue);
// Do not increment cellsEaten for power food
LK.getSound('eat').play();
// Update score display
scoreTxt.setText('Size: ' + Math.floor(playerCell.size));
}
// Player 2 power food collision
if (localMultiplayer && playerCell2) {
var dx2 = playerCell2.x - powerFood.x;
var dy2 = playerCell2.y - powerFood.y;
var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (distance2 < playerCell2.size / 2 + powerFood.size / 2) {
powerFood.consumed = true;
powerFood.destroy();
powerFoods.splice(i, 1);
playerCell2.grow(powerFood.growthValue);
LK.getSound('eat').play();
}
}
}
// Check papa collisions for player
for (var i = papas.length - 1; i >= 0; i--) {
var papa = papas[i];
if (papa.consumed) {
continue;
}
var dx = playerCell.x - papa.x;
var dy = playerCell.y - papa.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < playerCell.size / 2 + papa.size / 2) {
// Consume papa
papa.consumed = true;
papa.destroy();
papas.splice(i, 1);
playerCell.grow(papa.growthValue);
// Do not increment cellsEaten for papa
LK.getSound('eat').play();
// Update score display
scoreTxt.setText('Size: ' + Math.floor(playerCell.size));
}
// Player 2 papa collision
if (localMultiplayer && playerCell2) {
var dx2 = playerCell2.x - papa.x;
var dy2 = playerCell2.y - papa.y;
var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (distance2 < playerCell2.size / 2 + papa.size / 2) {
papa.consumed = true;
papa.destroy();
papas.splice(i, 1);
playerCell2.grow(papa.growthValue);
LK.getSound('eat').play();
}
}
}
// Check predator collisions
for (var i = 0; i < predators.length; i++) {
var predator = predators[i];
var dx = playerCell.x - predator.x;
var dy = playerCell.y - predator.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < playerCell.size / 2 + predator.size / 2) {
if (predator.size > playerCell.size) {
// Game over - eaten by predator
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else if (playerCell.size > predator.size * 1.2) {
// Player can eat predator
predator.destroy();
predators.splice(i, 1);
playerCell.grow(70);
cellsEaten++;
LK.getSound('eat').play();
scoreTxt.setText('Size: ' + Math.floor(playerCell.size) + ' | Eaten: ' + cellsEaten);
// Spawn new predator, and make all predators grow a lot if player is eaten
for (var p = 0; p < predators.length; p++) {
predators[p].size += 300; // All predators get much bigger (extreme)
}
spawnPredator();
i--; // Adjust index after removal
}
}
// Player 2 predator collision
if (localMultiplayer && playerCell2) {
var dx2 = playerCell2.x - predator.x;
var dy2 = playerCell2.y - predator.y;
var distance2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (distance2 < playerCell2.size / 2 + predator.size / 2) {
if (predator.size > playerCell2.size) {
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else if (playerCell2.size > predator.size * 1.2) {
predator.destroy();
predators.splice(i, 1);
playerCell2.grow(70);
LK.getSound('eat').play();
spawnPredator();
i--;
}
}
}
}
// Spawn new food periodically, but always near the player
if (LK.ticks % 120 == 0 && foods.length < 65) {
// Spawn food in a ring 300-700px from player, random angle
var angle = Math.random() * Math.PI * 2;
var dist = 300 + Math.random() * 400;
var fx = playerCell.x + Math.cos(angle) * dist;
var fy = playerCell.y + Math.sin(angle) * dist;
// Clamp to map bounds
fx = Math.max(20, Math.min(fx, mapSize - 20));
fy = Math.max(20, Math.min(fy, mapSize - 20));
var food = new Food();
food.x = fx;
food.y = fy;
foods.push(food);
world.addChild(food);
}
// Spawn power food less frequently
if (LK.ticks % 300 == 0 && powerFoods.length < 20) {
// Spawn power food in a ring 400-800px from player, random angle
var angle = Math.random() * Math.PI * 2;
var dist = 400 + Math.random() * 400;
var fx = playerCell.x + Math.cos(angle) * dist;
var fy = playerCell.y + Math.sin(angle) * dist;
// Clamp to map bounds
fx = Math.max(30, Math.min(fx, mapSize - 30));
fy = Math.max(30, Math.min(fy, mapSize - 30));
var powerFood = new PowerFood();
powerFood.x = fx;
powerFood.y = fy;
powerFoods.push(powerFood);
world.addChild(powerFood);
}
// Spawn papas periodically
if (LK.ticks % 200 == 0 && papas.length < 15) {
// Spawn papa in a ring 350-600px from player, random angle
var angle = Math.random() * Math.PI * 2;
var dist = 350 + Math.random() * 250;
var fx = playerCell.x + Math.cos(angle) * dist;
var fy = playerCell.y + Math.sin(angle) * dist;
// Clamp to map bounds
fx = Math.max(35, Math.min(fx, mapSize - 35));
fy = Math.max(35, Math.min(fy, mapSize - 35));
var papa = new Papa();
papa.x = fx;
papa.y = fy;
papas.push(papa);
world.addChild(papa);
}
// Add more predators as player grows (extreme: much more frequent, much higher max, much faster)
if (LK.ticks % 40 == 0 && predators.length < 80) {
spawnPredator();
}
// Add more AI cells as the game progresses (extreme: much more frequent, much higher max, much larger)
if (LK.ticks % 20 == 0 && aiCells.length < 120) {
spawnAICell();
// Only spawn giant AI cells if playerCell exists and playerCell.size >= 5000
if (playerCell && playerCell.size >= 5000 && aiCells.length < 120 && LK.ticks % 100 == 0) {
spawnGiantAICell();
}
}
// Player vs player collision (local mode)
if (localMultiplayer && playerCell && playerCell2) {
var dx = playerCell.x - playerCell2.x;
var dy = playerCell.y - playerCell2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < playerCell.size / 2 + playerCell2.size / 2) {
// Prevent passing through if same size (within 10% margin)
if (Math.abs(playerCell.size - playerCell2.size) < Math.max(playerCell.size, playerCell2.size) * 0.1) {
// Move both cells away from each other along the collision vector
var overlap = playerCell.size / 2 + playerCell2.size / 2 - distance;
if (overlap > 0 && distance > 0.01) {
var pushX = dx / distance * overlap / 2;
var pushY = dy / distance * overlap / 2;
playerCell.x += pushX;
playerCell.y += pushY;
playerCell2.x -= pushX;
playerCell2.y -= pushY;
}
// Randomly allow one to eat the other
if (Math.random() < 0.5) {
// Player 1 eats player 2
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else {
// Player 2 eats player 1
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
}
// Do not allow eating or passing through
} else if (playerCell.size > playerCell2.size * 1.2) {
// Player 1 eats player 2
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
} else if (playerCell2.size > playerCell.size * 1.2) {
// Player 2 eats player 1
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
return;
}
}
}
// Find the largest cell (player, aiCells, predators)
var topCell = playerCell;
var topCellType = "Tú";
var topCellSize = playerCell ? playerCell.size : 0;
var topCellName = null;
// Check AI cells
for (var i = 0; i < aiCells.length; i++) {
if (aiCells[i].alive && aiCells[i].size > topCellSize) {
topCell = aiCells[i];
topCellType = "Bot";
topCellSize = aiCells[i].size;
topCellName = aiCells[i].randomName;
}
}
// Check predators
for (var i = 0; i < predators.length; i++) {
if (predators[i].size > topCellSize) {
topCell = predators[i];
topCellType = "Depredador";
topCellSize = predators[i].size;
topCellName = null;
}
}
// --- Ensure #1 always has at least 50000 points and a different random name unless already higher ---
if (topCellSize < 50000) {
topCellSize = 50000;
// If player is not #1, show as Bot with a random name (different from playerName)
// Use the random name picked at game start for consistency
if (topCell !== playerCell) {
topCellType = "Bot";
// Use the random name picked at game start, fallback if not set
topCellName = typeof game.topCellRandomName !== "undefined" && game.topCellRandomName ? game.topCellRandomName : "Bot";
}
}
// Show #1 score
if (topCell === playerCell) {
topScoreTxt.setText("#1: Tú (" + Math.floor(topCellSize) + ")");
} else if (topCellType === "Bot" && topCellName) {
topScoreTxt.setText("#1: " + topCellName + " (" + Math.floor(topCellSize) + ")");
} else {
topScoreTxt.setText("#1: " + topCellType + " (" + Math.floor(topCellSize) + ")");
}
// No win condition: game continues infinitely even if player is #1
};
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Cell Growth" and with the description "Control a growing cell that consumes food particles to increase in size while avoiding larger predators in this survival game.". No text on banner!
Alimento. In-Game asset. 2d. High contrast. No shadows
Celula. In-Game asset. 2d. High contrast. No shadows
Celula de rojos. In-Game asset. 2d. High contrast. No shadows
Pavo pierna. In-Game asset. 2d. High contrast. No shadows
Papa alimento. In-Game asset. 2d. High contrast. No shadows