User prompt
After kill 2 zombie , spawn Zombie too.
User prompt
After 20 zombies are killed, spawn vampires that can shoot bullets should spawn.
User prompt
20 seconds after the game starts, zombies that can shoot bullets should spawn.
User prompt
20 seconds after the game starts, new zombies that throw fireballs should appear
User prompt
Reduce the movement speed of the zombies by half.
User prompt
Make the towers and walls form a connected octagon.
User prompt
Rotate tower number 7 to the left by 80 degrees.
User prompt
Rotate tower number 7 to the left by 35 degrees.
User prompt
Rotate tower number 1 to the left by 5 degrees.
User prompt
Rotate tower number 1 to the left by 35 angle.
User prompt
Write the numbers on top of the towers.
User prompt
Rotate towers numbered 1 by 60 angle
User prompt
Rotate towers numbered 1 and 7 by 60 angle
User prompt
Rotate towers numbered 4 by 90 angle
User prompt
Rotate towers numbered 8 by 90 angle.
User prompt
Rotate towers numbered 1, 3, 7, and 5 by 90 angle.
User prompt
Write a different number on top of each tower.
User prompt
Arrange the towers in alignment with the walls.
User prompt
Rotate the towers by 45 degrees.
User prompt
Halve the price of the soldiers. Increase the health of the walls by 10 times.
User prompt
Add the gate at the center.
User prompt
Add walls between the towers. The walls should have health. Zombies should attack the wall first. If they manage to destroy the wall, they should then attack the gate.
User prompt
The 8 towers should be arranged in an octagon shape.
User prompt
increases the number of towers to 8
User prompt
Towers should be arranged in the form of a basket. the door should be exactly in the middle.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet fired by soldiers var Bullet = Container.expand(function () { var self = Container.call(this); var bulletAsset = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 16; self.target = null; // Zombie instance self.damage = 1; self.update = function () { if (!self.target || self.target.isDead) { self.destroy(); return; } // Move towards target var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 32) { // Hit! self.target.takeDamage(self.damage); self.destroy(); return; } var step = self.speed; self.x += dx / dist * step; self.y += dy / dist * step; }; return self; }); // Gold coin dropped by zombies var Gold = Container.expand(function () { var self = Container.call(this); var goldAsset = self.attachAsset('gold', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1; self.life = 180; // 3 seconds self.update = function () { self.life--; if (self.life <= 0) { self.destroy(); } }; return self; }); // Soldier on a watchtower var Soldier = Container.expand(function () { var self = Container.call(this); var soldierAsset = self.attachAsset('soldier', { anchorX: 0.5, anchorY: 0.5 }); self.level = 1; self.fireRate = 60; // frames between shots self.fireTimer = 0; self.range = 600; self.upgradeCost = 5; self.parentTower = null; self.update = function () { if (!self.parentTower) return; self.fireTimer--; if (self.fireTimer <= 0) { // Find nearest zombie in range var nearest = null; var minDist = self.range; for (var i = 0; i < zombies.length; i++) { var z = zombies[i]; if (z.isDead) continue; var dx = z.x - self.x; var dy = z.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; nearest = z; } } if (nearest) { // Fire! var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = nearest; bullet.damage = self.level; bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.fireTimer = Math.max(20, self.fireRate - self.level * 8); } } }; self.upgrade = function () { self.level++; self.fireRate = Math.max(20, self.fireRate - 8); self.upgradeCost += 5; // Animate upgrade tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 120, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } }); }; return self; }); // Watchtower (can have a soldier) var Watchtower = Container.expand(function () { var self = Container.call(this); var towerAsset = self.attachAsset('watchtower', { anchorX: 0.5, anchorY: 1 }); self.soldier = null; self.index = 0; // For tap detection self.down = function (x, y, obj) { if (!self.soldier) { // Recruit soldier if enough gold (10) if (game.gold >= 10) { game.gold -= 10; var s = new Soldier(); s.x = self.x; s.y = self.y - 80; s.parentTower = self; self.soldier = s; soldiers.push(s); game.addChild(s); updateGoldText(); // Animate tween(s, { alpha: 0 }, { duration: 0, onFinish: function onFinish() { tween(s, { alpha: 1 }, { duration: 200 }); } }); } } else { // Upgrade soldier if (game.gold >= self.soldier.upgradeCost) { game.gold -= self.soldier.upgradeCost; self.soldier.upgrade(); updateGoldText(); } } }; return self; }); // Zombie enemy var Zombie = Container.expand(function () { var self = Container.call(this); var zombieAsset = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.maxHp = 2; self.hp = self.maxHp; self.speed = 2 + Math.random() * 1.5; self.isDead = false; self.targetX = 0; self.targetY = 0; self.takeDamage = function (dmg) { if (self.isDead) return; self.hp -= dmg; if (self.hp <= 0) { self.die(); } else { // Flash red tween(self, { tint: 0xFF0000 }, { duration: 80, onFinish: function onFinish() { tween(self, { tint: 0x4CAF50 }, { duration: 120 }); } }); } }; self.die = function () { if (self.isDead) return; self.isDead = true; LK.getSound('zombieDie').play(); // Instantly collect gold game.gold += 1; updateGoldText(); // Animate fade out tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); }; self.update = function () { if (self.isDead) return; var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 30) { // Reached gate self.isDead = true; self.destroy(); // Damage gate game.gateHp--; LK.effects.flashObject(game.castleGate, 0xFF0000, 400); if (game.gateHp <= 0) { LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } return; } var step = self.speed; self.x += dx / dist * step; self.y += dy / dist * step; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222233 }); /**** * Game Code ****/ // Play music // Castle gate (center bottom) // Watchtower base // Soldier // Zombie // Bullet // Gold coin // Sound for shooting // Sound for collecting gold // Sound for zombie death // Music LK.playMusic('castleTheme'); // Game variables var zombies = []; var bullets = []; var golds = []; var soldiers = []; var towers = []; game.gateHp = 5; game.gold = 10; game.wave = 1; game.waveTimer = 0; // Arrange towers in a basket (arc) formation and center the gate between them // Parameters for basket arc var basketCenterX = 1024; var basketCenterY = 1700; var basketRadius = 700; var basketAngleStart = Math.PI * 1.1; // leftmost var basketAngleEnd = Math.PI * 1.9; // rightmost var numTowers = 5; var towerPositions = []; for (var i = 0; i < numTowers; i++) { var t = i / (numTowers - 1); var angle = basketAngleStart + (basketAngleEnd - basketAngleStart) * t; var x = basketCenterX + Math.cos(angle) * basketRadius; var y = basketCenterY + Math.sin(angle) * basketRadius; towerPositions.push({ x: x, y: y }); } // Place the castle gate exactly in the middle between the two lowest towers var leftTower = towerPositions[0]; var rightTower = towerPositions[towerPositions.length - 1]; var gateX = (leftTower.x + rightTower.x) / 2; var gateY = (leftTower.y + rightTower.y) / 2 + 120; // visually below the arc, offset for gate height game.castleGate = LK.getAsset('castleGate', { anchorX: 0.5, anchorY: 1, x: gateX, y: gateY }); game.addChild(game.castleGate); for (var i = 0; i < towerPositions.length; i++) { var pos = towerPositions[i]; var tower = new Watchtower(); tower.x = pos.x; tower.y = pos.y; tower.index = i; towers.push(tower); game.addChild(tower); } // GUI: Gold display var goldTxt = new Text2('Gold: 10', { size: 90, fill: 0xFFD700 }); goldTxt.anchor.set(0.5, 0); LK.gui.top.addChild(goldTxt); // GUI: Gate HP display var hpTxt = new Text2('Gate: 5', { size: 90, fill: 0xFFFFFF }); hpTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(hpTxt); // GUI: Wave display var waveTxt = new Text2('Wave: 1', { size: 80, fill: 0x00BFFF }); waveTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(waveTxt); // --- Zoom Controls --- var zoomLevel = 1; var minZoom = 0.5; var maxZoom = 2.0; var zoomStep = 0.2; // Zoom In Button var zoomInBtn = new Text2('+', { size: 120, fill: 0xFFFFFF }); zoomInBtn.anchor.set(0.5, 0.5); zoomInBtn.x = 1800; zoomInBtn.y = 200; zoomInBtn.interactive = true; zoomInBtn.buttonMode = true; zoomInBtn.down = function (x, y, obj) { if (zoomLevel < maxZoom) { zoomLevel += zoomStep; if (zoomLevel > maxZoom) zoomLevel = maxZoom; game.scaleX = zoomLevel; game.scaleY = zoomLevel; } }; LK.gui.right.addChild(zoomInBtn); // Zoom Out Button var zoomOutBtn = new Text2('-', { size: 120, fill: 0xFFFFFF }); zoomOutBtn.anchor.set(0.5, 0.5); zoomOutBtn.x = 1800; zoomOutBtn.y = 350; zoomOutBtn.interactive = true; zoomOutBtn.buttonMode = true; zoomOutBtn.down = function (x, y, obj) { if (zoomLevel > minZoom) { zoomLevel -= zoomStep; if (zoomLevel < minZoom) zoomLevel = minZoom; game.scaleX = zoomLevel; game.scaleY = zoomLevel; } }; LK.gui.right.addChild(zoomOutBtn); function updateGoldText() { goldTxt.setText('Gold: ' + game.gold); } function updateHpText() { hpTxt.setText('Gate: ' + game.gateHp); } function updateWaveText() { waveTxt.setText('Wave: ' + game.wave); } // Handle buying soldiers/upgrades game.down = function (x, y, obj) { // Check if a tower was tapped for (var j = 0; j < towers.length; j++) { var t = towers[j]; var tx = t.x, ty = t.y; if (x > tx - 60 && x < tx + 60 && y > ty - 220 && y < ty) { t.down(x, y, obj); return; } } }; // Main update loop game.update = function () { // Update gate HP and gold updateHpText(); // Update all zombies for (var i = zombies.length - 1; i >= 0; i--) { var z = zombies[i]; z.update(); if (z.isDead && z.alpha === 0) { z.destroy(); zombies.splice(i, 1); } } // Update all bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); if (b.destroyed) { bullets.splice(i, 1); } } // Update all golds for (var i = golds.length - 1; i >= 0; i--) { var g = golds[i]; g.update(); if (g.life <= 0 || g.destroyed) { g.destroy(); golds.splice(i, 1); } } // Update all soldiers for (var i = 0; i < soldiers.length; i++) { soldiers[i].update(); } // Spawn new wave every 180 ticks (3 seconds) game.waveTimer++; if (game.waveTimer >= 180) { game.waveTimer = 0; spawnWave(); } }; function spawnWave() { var n = 2 + Math.floor(game.wave * 0.7); for (var i = 0; i < n; i++) { var z = new Zombie(); // Spawn from random edge var edge = Math.floor(Math.random() * 4); var zx, zy; if (edge === 0) { // left zx = -60; zy = 1000 + Math.random() * 1200; } else if (edge === 1) { // right zx = 2048 + 60; zy = 1000 + Math.random() * 1200; } else if (edge === 2) { // top zx = 400 + Math.random() * 1200; zy = -80; } else { // bottom (rare) zx = 400 + Math.random() * 1200; zy = 2732 + 80; } z.x = zx; z.y = zy; // Gate is at the middle of the basket (centered between lowest towers) z.targetX = game.castleGate.x; z.targetY = game.castleGate.y; // Decrease zombie speed (slower base, slower scaling) z.maxHp = 2 + Math.floor(game.wave / 2); z.hp = z.maxHp; z.speed = 1 + Math.random() * 0.7 + game.wave * 0.07; zombies.push(z); game.addChild(z); } game.wave++; updateWaveText(); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet fired by soldiers
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 16;
self.target = null; // Zombie instance
self.damage = 1;
self.update = function () {
if (!self.target || self.target.isDead) {
self.destroy();
return;
}
// Move towards target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 32) {
// Hit!
self.target.takeDamage(self.damage);
self.destroy();
return;
}
var step = self.speed;
self.x += dx / dist * step;
self.y += dy / dist * step;
};
return self;
});
// Gold coin dropped by zombies
var Gold = Container.expand(function () {
var self = Container.call(this);
var goldAsset = self.attachAsset('gold', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1;
self.life = 180; // 3 seconds
self.update = function () {
self.life--;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
// Soldier on a watchtower
var Soldier = Container.expand(function () {
var self = Container.call(this);
var soldierAsset = self.attachAsset('soldier', {
anchorX: 0.5,
anchorY: 0.5
});
self.level = 1;
self.fireRate = 60; // frames between shots
self.fireTimer = 0;
self.range = 600;
self.upgradeCost = 5;
self.parentTower = null;
self.update = function () {
if (!self.parentTower) return;
self.fireTimer--;
if (self.fireTimer <= 0) {
// Find nearest zombie in range
var nearest = null;
var minDist = self.range;
for (var i = 0; i < zombies.length; i++) {
var z = zombies[i];
if (z.isDead) continue;
var dx = z.x - self.x;
var dy = z.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
nearest = z;
}
}
if (nearest) {
// Fire!
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = nearest;
bullet.damage = self.level;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.fireTimer = Math.max(20, self.fireRate - self.level * 8);
}
}
};
self.upgrade = function () {
self.level++;
self.fireRate = Math.max(20, self.fireRate - 8);
self.upgradeCost += 5;
// Animate upgrade
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 120,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
};
return self;
});
// Watchtower (can have a soldier)
var Watchtower = Container.expand(function () {
var self = Container.call(this);
var towerAsset = self.attachAsset('watchtower', {
anchorX: 0.5,
anchorY: 1
});
self.soldier = null;
self.index = 0;
// For tap detection
self.down = function (x, y, obj) {
if (!self.soldier) {
// Recruit soldier if enough gold (10)
if (game.gold >= 10) {
game.gold -= 10;
var s = new Soldier();
s.x = self.x;
s.y = self.y - 80;
s.parentTower = self;
self.soldier = s;
soldiers.push(s);
game.addChild(s);
updateGoldText();
// Animate
tween(s, {
alpha: 0
}, {
duration: 0,
onFinish: function onFinish() {
tween(s, {
alpha: 1
}, {
duration: 200
});
}
});
}
} else {
// Upgrade soldier
if (game.gold >= self.soldier.upgradeCost) {
game.gold -= self.soldier.upgradeCost;
self.soldier.upgrade();
updateGoldText();
}
}
};
return self;
});
// Zombie enemy
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieAsset = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHp = 2;
self.hp = self.maxHp;
self.speed = 2 + Math.random() * 1.5;
self.isDead = false;
self.targetX = 0;
self.targetY = 0;
self.takeDamage = function (dmg) {
if (self.isDead) return;
self.hp -= dmg;
if (self.hp <= 0) {
self.die();
} else {
// Flash red
tween(self, {
tint: 0xFF0000
}, {
duration: 80,
onFinish: function onFinish() {
tween(self, {
tint: 0x4CAF50
}, {
duration: 120
});
}
});
}
};
self.die = function () {
if (self.isDead) return;
self.isDead = true;
LK.getSound('zombieDie').play();
// Instantly collect gold
game.gold += 1;
updateGoldText();
// Animate fade out
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
};
self.update = function () {
if (self.isDead) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 30) {
// Reached gate
self.isDead = true;
self.destroy();
// Damage gate
game.gateHp--;
LK.effects.flashObject(game.castleGate, 0xFF0000, 400);
if (game.gateHp <= 0) {
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
return;
}
var step = self.speed;
self.x += dx / dist * step;
self.y += dy / dist * step;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222233
});
/****
* Game Code
****/
// Play music
// Castle gate (center bottom)
// Watchtower base
// Soldier
// Zombie
// Bullet
// Gold coin
// Sound for shooting
// Sound for collecting gold
// Sound for zombie death
// Music
LK.playMusic('castleTheme');
// Game variables
var zombies = [];
var bullets = [];
var golds = [];
var soldiers = [];
var towers = [];
game.gateHp = 5;
game.gold = 10;
game.wave = 1;
game.waveTimer = 0;
// Arrange towers in a basket (arc) formation and center the gate between them
// Parameters for basket arc
var basketCenterX = 1024;
var basketCenterY = 1700;
var basketRadius = 700;
var basketAngleStart = Math.PI * 1.1; // leftmost
var basketAngleEnd = Math.PI * 1.9; // rightmost
var numTowers = 5;
var towerPositions = [];
for (var i = 0; i < numTowers; i++) {
var t = i / (numTowers - 1);
var angle = basketAngleStart + (basketAngleEnd - basketAngleStart) * t;
var x = basketCenterX + Math.cos(angle) * basketRadius;
var y = basketCenterY + Math.sin(angle) * basketRadius;
towerPositions.push({
x: x,
y: y
});
}
// Place the castle gate exactly in the middle between the two lowest towers
var leftTower = towerPositions[0];
var rightTower = towerPositions[towerPositions.length - 1];
var gateX = (leftTower.x + rightTower.x) / 2;
var gateY = (leftTower.y + rightTower.y) / 2 + 120; // visually below the arc, offset for gate height
game.castleGate = LK.getAsset('castleGate', {
anchorX: 0.5,
anchorY: 1,
x: gateX,
y: gateY
});
game.addChild(game.castleGate);
for (var i = 0; i < towerPositions.length; i++) {
var pos = towerPositions[i];
var tower = new Watchtower();
tower.x = pos.x;
tower.y = pos.y;
tower.index = i;
towers.push(tower);
game.addChild(tower);
}
// GUI: Gold display
var goldTxt = new Text2('Gold: 10', {
size: 90,
fill: 0xFFD700
});
goldTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(goldTxt);
// GUI: Gate HP display
var hpTxt = new Text2('Gate: 5', {
size: 90,
fill: 0xFFFFFF
});
hpTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(hpTxt);
// GUI: Wave display
var waveTxt = new Text2('Wave: 1', {
size: 80,
fill: 0x00BFFF
});
waveTxt.anchor.set(0.5, 0);
LK.gui.bottom.addChild(waveTxt);
// --- Zoom Controls ---
var zoomLevel = 1;
var minZoom = 0.5;
var maxZoom = 2.0;
var zoomStep = 0.2;
// Zoom In Button
var zoomInBtn = new Text2('+', {
size: 120,
fill: 0xFFFFFF
});
zoomInBtn.anchor.set(0.5, 0.5);
zoomInBtn.x = 1800;
zoomInBtn.y = 200;
zoomInBtn.interactive = true;
zoomInBtn.buttonMode = true;
zoomInBtn.down = function (x, y, obj) {
if (zoomLevel < maxZoom) {
zoomLevel += zoomStep;
if (zoomLevel > maxZoom) zoomLevel = maxZoom;
game.scaleX = zoomLevel;
game.scaleY = zoomLevel;
}
};
LK.gui.right.addChild(zoomInBtn);
// Zoom Out Button
var zoomOutBtn = new Text2('-', {
size: 120,
fill: 0xFFFFFF
});
zoomOutBtn.anchor.set(0.5, 0.5);
zoomOutBtn.x = 1800;
zoomOutBtn.y = 350;
zoomOutBtn.interactive = true;
zoomOutBtn.buttonMode = true;
zoomOutBtn.down = function (x, y, obj) {
if (zoomLevel > minZoom) {
zoomLevel -= zoomStep;
if (zoomLevel < minZoom) zoomLevel = minZoom;
game.scaleX = zoomLevel;
game.scaleY = zoomLevel;
}
};
LK.gui.right.addChild(zoomOutBtn);
function updateGoldText() {
goldTxt.setText('Gold: ' + game.gold);
}
function updateHpText() {
hpTxt.setText('Gate: ' + game.gateHp);
}
function updateWaveText() {
waveTxt.setText('Wave: ' + game.wave);
}
// Handle buying soldiers/upgrades
game.down = function (x, y, obj) {
// Check if a tower was tapped
for (var j = 0; j < towers.length; j++) {
var t = towers[j];
var tx = t.x,
ty = t.y;
if (x > tx - 60 && x < tx + 60 && y > ty - 220 && y < ty) {
t.down(x, y, obj);
return;
}
}
};
// Main update loop
game.update = function () {
// Update gate HP and gold
updateHpText();
// Update all zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
z.update();
if (z.isDead && z.alpha === 0) {
z.destroy();
zombies.splice(i, 1);
}
}
// Update all bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
if (b.destroyed) {
bullets.splice(i, 1);
}
}
// Update all golds
for (var i = golds.length - 1; i >= 0; i--) {
var g = golds[i];
g.update();
if (g.life <= 0 || g.destroyed) {
g.destroy();
golds.splice(i, 1);
}
}
// Update all soldiers
for (var i = 0; i < soldiers.length; i++) {
soldiers[i].update();
}
// Spawn new wave every 180 ticks (3 seconds)
game.waveTimer++;
if (game.waveTimer >= 180) {
game.waveTimer = 0;
spawnWave();
}
};
function spawnWave() {
var n = 2 + Math.floor(game.wave * 0.7);
for (var i = 0; i < n; i++) {
var z = new Zombie();
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
var zx, zy;
if (edge === 0) {
// left
zx = -60;
zy = 1000 + Math.random() * 1200;
} else if (edge === 1) {
// right
zx = 2048 + 60;
zy = 1000 + Math.random() * 1200;
} else if (edge === 2) {
// top
zx = 400 + Math.random() * 1200;
zy = -80;
} else {
// bottom (rare)
zx = 400 + Math.random() * 1200;
zy = 2732 + 80;
}
z.x = zx;
z.y = zy;
// Gate is at the middle of the basket (centered between lowest towers)
z.targetX = game.castleGate.x;
z.targetY = game.castleGate.y;
// Decrease zombie speed (slower base, slower scaling)
z.maxHp = 2 + Math.floor(game.wave / 2);
z.hp = z.maxHp;
z.speed = 1 + Math.random() * 0.7 + game.wave * 0.07;
zombies.push(z);
game.addChild(z);
}
game.wave++;
updateWaveText();
}
Green zombie. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Gold coin with dollar icon. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Arrow. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Add fingers to left hand. Make the bow and arrow wooden color.
Make it a rectangle.
Castle wall. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Smurf home. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
zombie with fire in hand. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat