/****
* 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);
}
}; /****
* 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);
}
};