Code edit (1 edits merged)
Please save this source code
User prompt
Garden Defense: Tower Defense Grid Battle
Initial prompt
Crea un prototipo funcional de un juego de defensa de torres basado en cuadrícula inspirado en Plants vs. Zombies. El juego debe ser en 2D, con una estética limpia y mecánica de juego por oleadas. 1. Configuración de la Cuadrícula y Escenario: Tamaño del Tablero: 5 filas x 9 columnas. Área de Juego: Cada celda debe ser un cuadrado perfecto donde se pueda colocar exactamente una planta. Zona de Spawn: Los zombies aparecen fuera de la cuadrícula a la derecha (columna 10) y caminan linealmente hacia la izquierda. Condición de Derrota: Si un zombie alcanza la columna 0 (el borde izquierdo). 2. Sistema de Recursos (Soles): Generación Automática: Caen soles del cielo de forma aleatoria cada 10-15 segundos. Generación por Planta: El Girasol produce soles periódicamente. Interacción: El jugador debe hacer clic/tocar el sol para recolectarlo. Valor: Cada sol suma 25 puntos a la reserva del jugador. 3. Entidades: Plantas (Defensas): Sistema de Colocación: Menú lateral (Seed Bank) donde se seleccionan las cartas. Al seleccionar una y hacer clic en una celda vacía, se descuenta el coste y se planta. Lanzaguisantes: Coste: 100 soles. Función: Dispara un proyectil (guisante) cada 1.5 segundos en línea recta. Daño: 20 HP por impacto. Girasol: Coste: 50 soles. Función: Genera un sol (25 puntos) cada 20 segundos. No ataca. Nuez (Wall-nut): Coste: 50 soles. Función: Actúa como escudo con alta resistencia. HP: 4000 (mucho mayor que las otras plantas). 4. Entidades: Zombies (Enemigos): Zombie Normal: Movimiento: Constante hacia la izquierda. Comportamiento: Si encuentra una planta en su celda, se detiene y comienza a "comer" (hacer daño por segundo). HP: 200 puntos. Velocidad: Lenta pero constante. 5. Mecánicas de Combate y Estados: Detección de Colisión: Los proyectiles deben detectar al primer zombie en su fila. Sistema de Daño: Plantas mueren cuando su HP llega a 0. Zombies mueren cuando su HP llega a 0. HUD (Interfaz): Mostrar contador de soles actual y tiempo de recarga (cooldown) en las cartas de las plantas antes de poder usarlas de nuevo. 6. Estética Sugerida: Fondo de jardín verde. Proyectiles verdes circulares. Barra de carga para indicar cuándo una planta está lista para ser colocada.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Pea = Container.expand(function () {
var self = Container.call(this);
var peaGraphics = self.attachAsset('pea', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 20;
self.update = function () {
self.x -= self.speed;
};
return self;
});
var Peashooter = Container.expand(function () {
var self = Container.call(this);
var shooterGraphics = self.attachAsset('peashooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHp = 300;
self.hp = 300;
self.shootCooldown = 0;
self.shootInterval = 90;
self.cost = 100;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var PlantCard = Container.expand(function (type, cost, cooldown) {
var self = Container.call(this);
var cardGraphics = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
var typeText = new Text2(type, {
size: 30,
fill: 0xFFFFFF
});
typeText.anchor.set(0.5, 0.5);
typeText.x = 0;
typeText.y = -15;
self.addChild(typeText);
var costText = new Text2(cost, {
size: 25,
fill: 0xFFEB3B
});
costText.anchor.set(0.5, 0.5);
costText.x = 0;
costText.y = 15;
self.addChild(costText);
self.type = type;
self.cost = cost;
self.cooldown = 0;
self.maxCooldown = cooldown;
return self;
});
var Sun = Container.expand(function () {
var self = Container.call(this);
var sunGraphics = self.attachAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 25;
self.fallSpeed = 3;
self.collected = false;
self.update = function () {
if (!self.collected) {
self.y += self.fallSpeed;
}
};
return self;
});
var Sunflower = Container.expand(function () {
var self = Container.call(this);
var flowerGraphics = self.attachAsset('sunflower', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHp = 300;
self.hp = 300;
self.sunCooldown = 0;
self.sunInterval = 1200;
self.cost = 50;
self.update = function () {
if (self.sunCooldown > 0) {
self.sunCooldown--;
}
};
return self;
});
var Walnut = Container.expand(function () {
var self = Container.call(this);
var walnutGraphics = self.attachAsset('walnut', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHp = 4000;
self.hp = 4000;
self.cost = 50;
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHp = 200;
self.hp = 200;
self.speed = 1;
self.eatingPlant = null;
self.eatDamage = 100;
self.eatInterval = 60;
self.eatCounter = 0;
self.update = function () {
if (!self.eatingPlant) {
self.x -= self.speed;
} else {
self.eatCounter++;
if (self.eatCounter >= self.eatInterval) {
self.eatingPlant.hp -= self.eatDamage;
self.eatCounter = 0;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x558b2f
});
/****
* Game Code
****/
var grid = [];
var plants = [];
var zombies = [];
var peas = [];
var suns = [];
var selectedPlantType = null;
var sunCount = 100;
var waveCount = 1;
var zombieSpawnCounter = 0;
var sunSpawnCounter = 0;
var gameOver = false;
var GRID_ROWS = 5;
var GRID_COLS = 10;
var CELL_SIZE = 100;
var GRID_START_X = 250;
var GRID_START_Y = 400;
function initializeGrid() {
for (var row = 0; row < GRID_ROWS; row++) {
grid[row] = [];
for (var col = 0; col < GRID_COLS; col++) {
grid[row][col] = null;
var cellGraphics = game.addChild(LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
}));
cellGraphics.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
cellGraphics.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
cellGraphics.alpha = 0.3;
}
}
}
function getGridPosition(col, row) {
return {
x: GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
};
}
function getGridCell(x, y) {
var relX = x - GRID_START_X;
var relY = y - GRID_START_Y;
var col = Math.floor(relX / CELL_SIZE);
var row = Math.floor(relY / CELL_SIZE);
if (col >= 0 && col < GRID_COLS && row >= 0 && row < GRID_ROWS) {
return {
col: col,
row: row
};
}
return null;
}
function createSeedBank() {
var bankX = 100;
var bankY = 450;
var peashooterCard = game.addChild(new PlantCard('Pea', 100, 0));
peashooterCard.x = bankX;
peashooterCard.y = bankY;
peashooterCard.plantType = 'peashooter';
var sunflowerCard = game.addChild(new PlantCard('Sun', 50, 0));
sunflowerCard.x = bankX;
sunflowerCard.y = bankY + 120;
sunflowerCard.plantType = 'sunflower';
var walnutCard = game.addChild(new PlantCard('Nut', 50, 0));
walnutCard.x = bankX;
walnutCard.y = bankY + 240;
walnutCard.plantType = 'walnut';
}
function spawnZombie() {
var newZombie = game.addChild(new Zombie());
var randomRow = Math.floor(Math.random() * GRID_ROWS);
var spawnPos = getGridPosition(GRID_COLS, randomRow);
newZombie.x = spawnPos.x;
newZombie.y = spawnPos.y;
newZombie.gridRow = randomRow;
newZombie.lastX = newZombie.x;
zombies.push(newZombie);
return newZombie;
}
function spawnSun(fromFlower) {
var newSun = game.addChild(new Sun());
if (fromFlower) {
newSun.x = fromFlower.x;
newSun.y = fromFlower.y;
} else {
newSun.x = Math.random() * (GRID_START_X + GRID_COLS * CELL_SIZE - GRID_START_X) + GRID_START_X;
newSun.y = GRID_START_Y;
}
newSun.lastY = newSun.y;
suns.push(newSun);
return newSun;
}
var sunCountDisplay = new Text2('Sun: 100', {
size: 60,
fill: 0xFFEB3B
});
sunCountDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(sunCountDisplay);
var waveDisplay = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFFFF
});
waveDisplay.anchor.set(0.5, 0);
waveDisplay.y = 80;
LK.gui.top.addChild(waveDisplay);
initializeGrid();
createSeedBank();
var zombieSpawnTimer = LK.setInterval(function () {
if (!gameOver && zombies.length < 3 + waveCount) {
spawnZombie();
}
}, 3000);
var sunSpawnTimer = LK.setInterval(function () {
if (!gameOver) {
spawnSun(null);
}
}, 1200);
game.down = function (x, y, obj) {
if (gameOver) return;
var cell = getGridCell(x, y);
if (cell && grid[cell.row][cell.col] === null && selectedPlantType) {
if (sunCount >= 50) {
var plantPos = getGridPosition(cell.col, cell.row);
var newPlant;
if (selectedPlantType === 'peashooter') {
if (sunCount < 100) return;
newPlant = game.addChild(new Peashooter());
sunCount -= 100;
} else if (selectedPlantType === 'sunflower') {
newPlant = game.addChild(new Sunflower());
sunCount -= 50;
} else if (selectedPlantType === 'walnut') {
newPlant = game.addChild(new Walnut());
sunCount -= 50;
}
newPlant.x = plantPos.x;
newPlant.y = plantPos.y;
newPlant.gridCol = cell.col;
newPlant.gridRow = cell.row;
newPlant.type = selectedPlantType;
grid[cell.row][cell.col] = newPlant;
plants.push(newPlant);
LK.getSound('plantPlace').play();
sunCountDisplay.setText('Sun: ' + sunCount);
}
} else if (x < 200 && y > 400) {
var bankY = 450;
if (y > bankY - 50 && y < bankY + 50) {
selectedPlantType = 'peashooter';
} else if (y > bankY + 70 && y < bankY + 170) {
selectedPlantType = 'sunflower';
} else if (y > bankY + 190 && y < bankY + 290) {
selectedPlantType = 'walnut';
}
}
};
game.update = function () {
if (gameOver) return;
for (var p = plants.length - 1; p >= 0; p--) {
var plant = plants[p];
if (plant.hp <= 0) {
grid[plant.gridRow][plant.gridCol] = null;
plant.destroy();
plants.splice(p, 1);
continue;
}
if (plant.type === 'peashooter') {
plant.shootCooldown--;
if (plant.shootCooldown <= 0) {
var closestZombie = null;
var closestDist = 500;
for (var z = 0; z < zombies.length; z++) {
var zombie = zombies[z];
if (zombie.gridRow === plant.gridRow || Math.abs(zombie.gridRow - plant.gridRow) <= 1) {
var dist = Math.abs(zombie.x - plant.x);
if (dist < closestDist) {
closestDist = dist;
closestZombie = zombie;
}
}
}
if (closestZombie) {
var newPea = game.addChild(new Pea());
newPea.x = plant.x;
newPea.y = plant.y;
newPea.targetZombie = closestZombie;
newPea.lastX = newPea.x;
peas.push(newPea);
LK.getSound('shoot').play();
plant.shootCooldown = plant.shootInterval;
}
}
} else if (plant.type === 'sunflower') {
plant.sunCooldown--;
if (plant.sunCooldown <= 0) {
spawnSun(plant);
plant.sunCooldown = plant.sunInterval;
}
}
}
for (var s = suns.length - 1; s >= 0; s--) {
var sun = suns[s];
if (!sun.collected && sun.y > GRID_START_Y + GRID_ROWS * CELL_SIZE + 100) {
sun.destroy();
suns.splice(s, 1);
continue;
}
}
for (var pe = peas.length - 1; pe >= 0; pe--) {
var pea = peas[pe];
if (pea.x < 0 || !pea.targetZombie) {
pea.destroy();
peas.splice(pe, 1);
continue;
}
if (pea.intersects(pea.targetZombie)) {
pea.targetZombie.hp -= pea.damage;
LK.getSound('zombieHit').play();
pea.destroy();
peas.splice(pe, 1);
continue;
}
}
for (var z = zombies.length - 1; z >= 0; z--) {
var zombie = zombies[z];
if (zombie.hp <= 0) {
LK.setScore(LK.getScore() + 50);
zombie.destroy();
zombies.splice(z, 1);
continue;
}
if (zombie.x < GRID_START_X - 50) {
LK.showGameOver();
gameOver = true;
LK.clearInterval(zombieSpawnTimer);
LK.clearInterval(sunSpawnTimer);
return;
}
var plantAtRow = null;
for (var col = GRID_COLS - 1; col >= 0; col--) {
if (grid[zombie.gridRow][col] !== null) {
plantAtRow = grid[zombie.gridRow][col];
break;
}
}
if (plantAtRow && Math.abs(zombie.x - plantAtRow.x) < CELL_SIZE / 2 + 35) {
if (zombie.eatingPlant !== plantAtRow) {
zombie.eatingPlant = plantAtRow;
zombie.eatCounter = 0;
}
} else {
zombie.eatingPlant = null;
}
if (!zombie.eatingPlant) {
zombie.lastX = zombie.x;
}
}
if (zombies.length === 0 && LK.ticks % 60 === 0) {
waveCount++;
waveDisplay.setText('Wave: ' + waveCount);
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,410 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Pea = Container.expand(function () {
+ var self = Container.call(this);
+ var peaGraphics = self.attachAsset('pea', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.damage = 20;
+ self.update = function () {
+ self.x -= self.speed;
+ };
+ return self;
+});
+var Peashooter = Container.expand(function () {
+ var self = Container.call(this);
+ var shooterGraphics = self.attachAsset('peashooter', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.maxHp = 300;
+ self.hp = 300;
+ self.shootCooldown = 0;
+ self.shootInterval = 90;
+ self.cost = 100;
+ self.update = function () {
+ if (self.shootCooldown > 0) {
+ self.shootCooldown--;
+ }
+ };
+ return self;
+});
+var PlantCard = Container.expand(function (type, cost, cooldown) {
+ var self = Container.call(this);
+ var cardGraphics = self.attachAsset('gridCell', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ var typeText = new Text2(type, {
+ size: 30,
+ fill: 0xFFFFFF
+ });
+ typeText.anchor.set(0.5, 0.5);
+ typeText.x = 0;
+ typeText.y = -15;
+ self.addChild(typeText);
+ var costText = new Text2(cost, {
+ size: 25,
+ fill: 0xFFEB3B
+ });
+ costText.anchor.set(0.5, 0.5);
+ costText.x = 0;
+ costText.y = 15;
+ self.addChild(costText);
+ self.type = type;
+ self.cost = cost;
+ self.cooldown = 0;
+ self.maxCooldown = cooldown;
+ return self;
+});
+var Sun = Container.expand(function () {
+ var self = Container.call(this);
+ var sunGraphics = self.attachAsset('sun', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.value = 25;
+ self.fallSpeed = 3;
+ self.collected = false;
+ self.update = function () {
+ if (!self.collected) {
+ self.y += self.fallSpeed;
+ }
+ };
+ return self;
+});
+var Sunflower = Container.expand(function () {
+ var self = Container.call(this);
+ var flowerGraphics = self.attachAsset('sunflower', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.maxHp = 300;
+ self.hp = 300;
+ self.sunCooldown = 0;
+ self.sunInterval = 1200;
+ self.cost = 50;
+ self.update = function () {
+ if (self.sunCooldown > 0) {
+ self.sunCooldown--;
+ }
+ };
+ return self;
+});
+var Walnut = Container.expand(function () {
+ var self = Container.call(this);
+ var walnutGraphics = self.attachAsset('walnut', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.maxHp = 4000;
+ self.hp = 4000;
+ self.cost = 50;
+ return self;
+});
+var Zombie = Container.expand(function () {
+ var self = Container.call(this);
+ var zombieGraphics = self.attachAsset('zombie', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.maxHp = 200;
+ self.hp = 200;
+ self.speed = 1;
+ self.eatingPlant = null;
+ self.eatDamage = 100;
+ self.eatInterval = 60;
+ self.eatCounter = 0;
+ self.update = function () {
+ if (!self.eatingPlant) {
+ self.x -= self.speed;
+ } else {
+ self.eatCounter++;
+ if (self.eatCounter >= self.eatInterval) {
+ self.eatingPlant.hp -= self.eatDamage;
+ self.eatCounter = 0;
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x558b2f
+});
+
+/****
+* Game Code
+****/
+var grid = [];
+var plants = [];
+var zombies = [];
+var peas = [];
+var suns = [];
+var selectedPlantType = null;
+var sunCount = 100;
+var waveCount = 1;
+var zombieSpawnCounter = 0;
+var sunSpawnCounter = 0;
+var gameOver = false;
+var GRID_ROWS = 5;
+var GRID_COLS = 10;
+var CELL_SIZE = 100;
+var GRID_START_X = 250;
+var GRID_START_Y = 400;
+function initializeGrid() {
+ for (var row = 0; row < GRID_ROWS; row++) {
+ grid[row] = [];
+ for (var col = 0; col < GRID_COLS; col++) {
+ grid[row][col] = null;
+ var cellGraphics = game.addChild(LK.getAsset('gridCell', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ cellGraphics.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
+ cellGraphics.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
+ cellGraphics.alpha = 0.3;
+ }
+ }
+}
+function getGridPosition(col, row) {
+ return {
+ x: GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2,
+ y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
+ };
+}
+function getGridCell(x, y) {
+ var relX = x - GRID_START_X;
+ var relY = y - GRID_START_Y;
+ var col = Math.floor(relX / CELL_SIZE);
+ var row = Math.floor(relY / CELL_SIZE);
+ if (col >= 0 && col < GRID_COLS && row >= 0 && row < GRID_ROWS) {
+ return {
+ col: col,
+ row: row
+ };
+ }
+ return null;
+}
+function createSeedBank() {
+ var bankX = 100;
+ var bankY = 450;
+ var peashooterCard = game.addChild(new PlantCard('Pea', 100, 0));
+ peashooterCard.x = bankX;
+ peashooterCard.y = bankY;
+ peashooterCard.plantType = 'peashooter';
+ var sunflowerCard = game.addChild(new PlantCard('Sun', 50, 0));
+ sunflowerCard.x = bankX;
+ sunflowerCard.y = bankY + 120;
+ sunflowerCard.plantType = 'sunflower';
+ var walnutCard = game.addChild(new PlantCard('Nut', 50, 0));
+ walnutCard.x = bankX;
+ walnutCard.y = bankY + 240;
+ walnutCard.plantType = 'walnut';
+}
+function spawnZombie() {
+ var newZombie = game.addChild(new Zombie());
+ var randomRow = Math.floor(Math.random() * GRID_ROWS);
+ var spawnPos = getGridPosition(GRID_COLS, randomRow);
+ newZombie.x = spawnPos.x;
+ newZombie.y = spawnPos.y;
+ newZombie.gridRow = randomRow;
+ newZombie.lastX = newZombie.x;
+ zombies.push(newZombie);
+ return newZombie;
+}
+function spawnSun(fromFlower) {
+ var newSun = game.addChild(new Sun());
+ if (fromFlower) {
+ newSun.x = fromFlower.x;
+ newSun.y = fromFlower.y;
+ } else {
+ newSun.x = Math.random() * (GRID_START_X + GRID_COLS * CELL_SIZE - GRID_START_X) + GRID_START_X;
+ newSun.y = GRID_START_Y;
+ }
+ newSun.lastY = newSun.y;
+ suns.push(newSun);
+ return newSun;
+}
+var sunCountDisplay = new Text2('Sun: 100', {
+ size: 60,
+ fill: 0xFFEB3B
+});
+sunCountDisplay.anchor.set(0.5, 0);
+LK.gui.top.addChild(sunCountDisplay);
+var waveDisplay = new Text2('Wave: 1', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+waveDisplay.anchor.set(0.5, 0);
+waveDisplay.y = 80;
+LK.gui.top.addChild(waveDisplay);
+initializeGrid();
+createSeedBank();
+var zombieSpawnTimer = LK.setInterval(function () {
+ if (!gameOver && zombies.length < 3 + waveCount) {
+ spawnZombie();
+ }
+}, 3000);
+var sunSpawnTimer = LK.setInterval(function () {
+ if (!gameOver) {
+ spawnSun(null);
+ }
+}, 1200);
+game.down = function (x, y, obj) {
+ if (gameOver) return;
+ var cell = getGridCell(x, y);
+ if (cell && grid[cell.row][cell.col] === null && selectedPlantType) {
+ if (sunCount >= 50) {
+ var plantPos = getGridPosition(cell.col, cell.row);
+ var newPlant;
+ if (selectedPlantType === 'peashooter') {
+ if (sunCount < 100) return;
+ newPlant = game.addChild(new Peashooter());
+ sunCount -= 100;
+ } else if (selectedPlantType === 'sunflower') {
+ newPlant = game.addChild(new Sunflower());
+ sunCount -= 50;
+ } else if (selectedPlantType === 'walnut') {
+ newPlant = game.addChild(new Walnut());
+ sunCount -= 50;
+ }
+ newPlant.x = plantPos.x;
+ newPlant.y = plantPos.y;
+ newPlant.gridCol = cell.col;
+ newPlant.gridRow = cell.row;
+ newPlant.type = selectedPlantType;
+ grid[cell.row][cell.col] = newPlant;
+ plants.push(newPlant);
+ LK.getSound('plantPlace').play();
+ sunCountDisplay.setText('Sun: ' + sunCount);
+ }
+ } else if (x < 200 && y > 400) {
+ var bankY = 450;
+ if (y > bankY - 50 && y < bankY + 50) {
+ selectedPlantType = 'peashooter';
+ } else if (y > bankY + 70 && y < bankY + 170) {
+ selectedPlantType = 'sunflower';
+ } else if (y > bankY + 190 && y < bankY + 290) {
+ selectedPlantType = 'walnut';
+ }
+ }
+};
+game.update = function () {
+ if (gameOver) return;
+ for (var p = plants.length - 1; p >= 0; p--) {
+ var plant = plants[p];
+ if (plant.hp <= 0) {
+ grid[plant.gridRow][plant.gridCol] = null;
+ plant.destroy();
+ plants.splice(p, 1);
+ continue;
+ }
+ if (plant.type === 'peashooter') {
+ plant.shootCooldown--;
+ if (plant.shootCooldown <= 0) {
+ var closestZombie = null;
+ var closestDist = 500;
+ for (var z = 0; z < zombies.length; z++) {
+ var zombie = zombies[z];
+ if (zombie.gridRow === plant.gridRow || Math.abs(zombie.gridRow - plant.gridRow) <= 1) {
+ var dist = Math.abs(zombie.x - plant.x);
+ if (dist < closestDist) {
+ closestDist = dist;
+ closestZombie = zombie;
+ }
+ }
+ }
+ if (closestZombie) {
+ var newPea = game.addChild(new Pea());
+ newPea.x = plant.x;
+ newPea.y = plant.y;
+ newPea.targetZombie = closestZombie;
+ newPea.lastX = newPea.x;
+ peas.push(newPea);
+ LK.getSound('shoot').play();
+ plant.shootCooldown = plant.shootInterval;
+ }
+ }
+ } else if (plant.type === 'sunflower') {
+ plant.sunCooldown--;
+ if (plant.sunCooldown <= 0) {
+ spawnSun(plant);
+ plant.sunCooldown = plant.sunInterval;
+ }
+ }
+ }
+ for (var s = suns.length - 1; s >= 0; s--) {
+ var sun = suns[s];
+ if (!sun.collected && sun.y > GRID_START_Y + GRID_ROWS * CELL_SIZE + 100) {
+ sun.destroy();
+ suns.splice(s, 1);
+ continue;
+ }
+ }
+ for (var pe = peas.length - 1; pe >= 0; pe--) {
+ var pea = peas[pe];
+ if (pea.x < 0 || !pea.targetZombie) {
+ pea.destroy();
+ peas.splice(pe, 1);
+ continue;
+ }
+ if (pea.intersects(pea.targetZombie)) {
+ pea.targetZombie.hp -= pea.damage;
+ LK.getSound('zombieHit').play();
+ pea.destroy();
+ peas.splice(pe, 1);
+ continue;
+ }
+ }
+ for (var z = zombies.length - 1; z >= 0; z--) {
+ var zombie = zombies[z];
+ if (zombie.hp <= 0) {
+ LK.setScore(LK.getScore() + 50);
+ zombie.destroy();
+ zombies.splice(z, 1);
+ continue;
+ }
+ if (zombie.x < GRID_START_X - 50) {
+ LK.showGameOver();
+ gameOver = true;
+ LK.clearInterval(zombieSpawnTimer);
+ LK.clearInterval(sunSpawnTimer);
+ return;
+ }
+ var plantAtRow = null;
+ for (var col = GRID_COLS - 1; col >= 0; col--) {
+ if (grid[zombie.gridRow][col] !== null) {
+ plantAtRow = grid[zombie.gridRow][col];
+ break;
+ }
+ }
+ if (plantAtRow && Math.abs(zombie.x - plantAtRow.x) < CELL_SIZE / 2 + 35) {
+ if (zombie.eatingPlant !== plantAtRow) {
+ zombie.eatingPlant = plantAtRow;
+ zombie.eatCounter = 0;
+ }
+ } else {
+ zombie.eatingPlant = null;
+ }
+ if (!zombie.eatingPlant) {
+ zombie.lastX = zombie.x;
+ }
+ }
+ if (zombies.length === 0 && LK.ticks % 60 === 0) {
+ waveCount++;
+ waveDisplay.setText('Wave: ' + waveCount);
+ }
+};
\ No newline at end of file