User prompt
add a asset for the background, reverse the image for the left turret, remove the bottom ground
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ground is not defined' in or related to this line: 'game.addChild(ground);' Line Number: 216
Code edit (1 edits merged)
Please save this source code
User prompt
add a background for the market
User prompt
remove the hp text and make the hp bar work, showing the remaining health with a green bar inside of the gray one and add a platform ground
User prompt
make hp a bar, visible on the top of the base
User prompt
make the buttons and texts far from each other
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'containsPoint')' in or related to this line: 'if (t && LK.util.containsPoint(t, {' Line Number: 373
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'containsPoint')' in or related to this line: 'if (LK.util.containsPoint(t, {' Line Number: 373
User prompt
Please fix the bug: 'Uncaught TypeError: t.containsPoint is not a function' in or related to this line: 'if (t.containsPoint({' Line Number: 373
Code edit (1 edits merged)
Please save this source code
User prompt
Base Turret Defense: Horde Siege
Initial prompt
a platform, base in the middle, hordes coming from right and left of the map, we are trying to defend our base with turrets, enemy's and our base's health bar, upgrading our base and adding more turrets, gaining gold when clearing waves etc
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Base class var Base = Container.expand(function () { var self = Container.call(this); // Attach base asset (ellipse, blue) var baseGraphics = self.attachAsset('base', { anchorX: 0.5, anchorY: 0.5 }); baseGraphics.width = 180; baseGraphics.height = 180; baseGraphics.color = 0x3399ff; self.maxHp = 20; self.hp = self.maxHp; // Flash on hit self.hit = function () { LK.effects.flashObject(self, 0xff0000, 400); }; // Repair self.repair = function () { self.hp = Math.min(self.maxHp, self.hp + 5); }; // Upgrade self.upgrade = function () { self.maxHp += 10; self.hp = self.maxHp; baseGraphics.scaleX += 0.1; baseGraphics.scaleY += 0.1; }; return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (box, yellow) var bulletGraphics = self.attachAsset('bullet', { anchorX: -2, anchorY: 2 }); bulletGraphics.width = 20; bulletGraphics.height = 20; bulletGraphics.color = 0xb8b031; self.speed = 24; self.target = null; self.side = 1; self.damage = 1; self.update = function () { if (!self.target || self.target.destroyed) { self.destroy(); return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 40) { // Hit! self.target.hp -= self.damage; LK.effects.flashObject(self.target, 0xffff00, 200); self.destroy(); return; } var step = self.speed; self.x += dx / dist * step; self.y += dy / dist * step; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Attach enemy asset (ellipse, red) // Use separate images for left- and right-spawned enemies var assetId = self.direction === -1 ? 'enemyLeft' : 'enemyRight'; var enemyGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Set size and color enemyGraphics.width = 90; enemyGraphics.height = 90; enemyGraphics.color = 0xd83318; // Enemy properties self.speed = 3 + Math.random() * 1.5; // Will be set per wave self.hp = 1; // Will be set per wave self.direction = 1; // 1 for right-to-left, -1 for left-to-right // Update method self.update = function () { self.x += self.speed * self.direction; }; return self; }); // Turret class var Turret = Container.expand(function () { var self = Container.call(this); // Attach turret asset (box, green) var turretGraphics = self.attachAsset('turret', { anchorX: 0.5, anchorY: 0.5 }); turretGraphics.width = 100; turretGraphics.height = 100; turretGraphics.color = 0x83de44; // Turret properties self.range = 500; self.fireRate = 60; // frames between shots self.cooldown = 0; self.level = 1; self.side = 1; // 1 = right, -1 = left // Upgrade method self.upgrade = function () { if (self.level < 3) { self.level += 1; self.range += 100; self.fireRate = Math.max(30, self.fireRate - 10); turretGraphics.scaleX += 0.1; turretGraphics.scaleY += 0.1; } }; // Update method self.update = function () { if (self.cooldown > 0) { self.cooldown--; return; } // Find closest enemy in range on this side var closest = null; var minDist = self.range + 1; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (self.side === 1 && e.x > base.x || self.side === -1 && e.x < base.x) { var dx = e.x - self.x; var dy = e.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist && dist <= self.range) { minDist = dist; closest = e; } } } if (closest) { // Fire at enemy var b = new Bullet(); b.x = self.x; b.y = self.y; b.target = closest; b.side = self.side; b.damage = self.level; // Reverse bullet image for left turrets if (self.side === -1 && b.children && b.children.length > 0) { if (typeof b.children[0].scaleX !== "undefined") { b.children[0].scaleX = -1 * Math.abs(b.children[0].scaleX); } } bullets.push(b); game.addChild(b); self.cooldown = self.fireRate; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Add background image to the game scene var backgroundImg = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); game.addChild(backgroundImg); // Game state variables var base = new Base(); base.x = 2048 / 2; base.y = 2732 / 2; game.addChild(base); var turrets = []; var enemies = []; var bullets = []; var gold = 50; var wave = 1; var enemiesToSpawn = 0; var enemiesSpawned = 0; var enemiesPerWave = 6; var waveInProgress = false; var spawnTimer = 0; var nextWaveTimer = 0; var baseHealthTxt, goldTxt, waveTxt; var selectedTurret = null; // HP Bar for base (black outline, gray background, green foreground) // Use shape assets for outline, background, and foreground bar var baseHpBarOutline = LK.getAsset('baseHpBarOutline', { anchorX: 0.5, anchorY: 0.5, x: base.x, y: base.y - 190, width: 208, height: 40 }); var baseHpBarBg = LK.getAsset('baseHpBarBg', { anchorX: 0.5, anchorY: 0.5, x: base.x, y: base.y - 190, width: 200, height: 32 }); var baseHpBar = LK.getAsset('baseHpBar', { anchorX: 0, anchorY: 0.5, x: base.x - 100, y: base.y - 190, width: 200, height: 32 }); game.addChild(baseHpBarOutline); game.addChild(baseHpBarBg); game.addChild(baseHpBar); // (ground platform removed) // GUI // HP text removed goldTxt = new Text2("Gold: " + gold, { size: 80, fill: 0xFFD700 }); goldTxt.anchor.set(1, 0); LK.gui.topRight.addChild(goldTxt); waveTxt = new Text2("Wave: " + wave, { size: 80, fill: "#fff" }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); // Turret placement buttons (left and right) // Space out the buttons and texts at the bottom of the screen for better separation var bottomY = 2732 - 180; var leftTurretBtn = LK.getAsset('turret', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 700, y: bottomY, scaleX: 1.2, scaleY: 1.2 }); var rightTurretBtn = LK.getAsset('turret', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 700, y: bottomY, scaleX: 1.2, scaleY: 1.2 }); game.addChild(leftTurretBtn); game.addChild(rightTurretBtn); var leftTurretCostTxt = new Text2("Buy: 30", { size: 60, fill: "#fff" }); leftTurretCostTxt.anchor.set(0.5, 0); leftTurretCostTxt.x = leftTurretBtn.x; leftTurretCostTxt.y = leftTurretBtn.y + 100; game.addChild(leftTurretCostTxt); var rightTurretCostTxt = new Text2("Buy: 30", { size: 60, fill: "#fff" }); rightTurretCostTxt.anchor.set(0.5, 0); rightTurretCostTxt.x = rightTurretBtn.x; rightTurretCostTxt.y = rightTurretBtn.y + 100; game.addChild(rightTurretCostTxt); // Base repair and upgrade buttons var repairBtn = LK.getAsset('repair', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 350, y: bottomY, scaleX: 0.7, scaleY: 0.7 }); var upgradeBtn = LK.getAsset('upgrade', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 350, y: bottomY, scaleX: 0.7, scaleY: 0.7 }); game.addChild(repairBtn); game.addChild(upgradeBtn); var repairCostTxt = new Text2("Repair: 15", { size: 60, fill: "#fff" }); repairCostTxt.anchor.set(0.5, 0); repairCostTxt.x = repairBtn.x; repairCostTxt.y = repairBtn.y + 100; game.addChild(repairCostTxt); var upgradeCostTxt = new Text2("Upgrade: 40", { size: 60, fill: "#fff" }); upgradeCostTxt.anchor.set(0.5, 0); upgradeCostTxt.x = upgradeBtn.x; upgradeCostTxt.y = upgradeBtn.y + 100; game.addChild(upgradeCostTxt); // Turret upgrade buttons (appear above turrets) function showTurretUpgradeBtn(turret) { if (turret.upgradeBtn) { return; } var btn = LK.getAsset('turret', { anchorX: 0.5, anchorY: 0.5, x: turret.x, y: turret.y - 120, scaleX: 0.6, scaleY: 0.6 }); var txt = new Text2("Upgrade: 25", { size: 50, fill: "#fff" }); txt.anchor.set(0.5, 0); txt.x = btn.x; txt.y = btn.y + 50; btn._upgradeTxt = txt; game.addChild(btn); game.addChild(txt); turret.upgradeBtn = btn; turret.upgradeTxt = txt; } // Remove upgrade button function hideTurretUpgradeBtn(turret) { if (turret.upgradeBtn) { turret.upgradeBtn.destroy(); turret.upgradeTxt.destroy(); turret.upgradeBtn = null; turret.upgradeTxt = null; } } // Place initial turrets function placeTurret(side) { // Count how many turrets already exist on this side var count = 0; for (var i = 0; i < turrets.length; i++) { if (turrets[i].side === side) { count++; } } // Place the first turret at center, then alternate above/below var x = base.x + (side === 1 ? 300 : -300); var y = base.y; if (count > 0) { // Alternate above and below, spacing by 180px var offset = 180 * Math.ceil(count / 2); if (count % 2 === 1) { y = base.y - offset; // above } else { y = base.y + offset; // below } } var t = new Turret(); t.x = x; t.y = y; t.side = side; // Reverse the image for the left turret if (side === -1 && t.children && t.children.length > 0) { // Assume the first child is the turret graphics if (typeof t.children[0].scaleX !== "undefined") { t.children[0].scaleX = -1 * Math.abs(t.children[0].scaleX); } } turrets.push(t); game.addChild(t); return t; } // Initial turrets placeTurret(-1); placeTurret(1); // Handle turret placement leftTurretBtn.down = function (x, y, obj) { if (gold >= 30) { var t = placeTurret(-1); gold -= 30; goldTxt.setText("Gold: " + gold); } }; rightTurretBtn.down = function (x, y, obj) { if (gold >= 30) { var t = placeTurret(1); gold -= 30; goldTxt.setText("Gold: " + gold); } }; // Handle base repair/upgrade repairBtn.down = function (x, y, obj) { if (gold >= 15 && base.hp < base.maxHp) { base.repair(); gold -= 15; goldTxt.setText("Gold: " + gold); // HP text removed, no update needed here } }; upgradeBtn.down = function (x, y, obj) { if (gold >= 40) { base.upgrade(); gold -= 40; goldTxt.setText("Gold: " + gold); // HP text removed, no update needed here } }; // Handle turret upgrade game.down = function (x, y, obj) { // Check if a turret was tapped for (var i = 0; i < turrets.length; i++) { var t = turrets[i]; if (t && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t, { x: x, y: y })) { selectedTurret = t; showTurretUpgradeBtn(t); return; } } // Check if upgrade button was tapped for (var i = 0; i < turrets.length; i++) { var t = turrets[i]; if (t && t.upgradeBtn && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t.upgradeBtn, { x: x, y: y })) { if (gold >= 25 && t.level < 3) { t.upgrade(); gold -= 25; goldTxt.setText("Gold: " + gold); if (t.level >= 3) { hideTurretUpgradeBtn(t); } } return; } } // Deselect turret if tap elsewhere for (var i = 0; i < turrets.length; i++) { hideTurretUpgradeBtn(turrets[i]); } selectedTurret = null; }; // Enemy spawn logic function startWave() { waveInProgress = true; enemiesToSpawn = Math.floor(enemiesPerWave + (wave - 1) * 4.5); // more enemies per wave, longer waves enemiesSpawned = 0; spawnTimer = 0; waveTxt.setText("Wave: " + wave); } function endWave() { waveInProgress = false; nextWaveTimer = 120; // 2 seconds gold += 20 + wave * 5; goldTxt.setText("Gold: " + gold); enemiesPerWave += 4; // increase more per wave, longer waves wave += 1; } // Main update loop game.update = function () { // Update HP bar position and width baseHpBarOutline.x = base.x; baseHpBarOutline.y = base.y - 190; baseHpBarBg.x = base.x; baseHpBarBg.y = base.y - 190; // Health bar shrinks left-to-right as base takes damage var hpRatio = Math.max(0, base.hp) / base.maxHp; baseHpBar.width = 200 * hpRatio; baseHpBar.x = base.x - 100; // left edge stays fixed baseHpBar.y = base.y - 190; // Update turrets for (var i = 0; i < turrets.length; i++) { turrets[i].update(); } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); // Check if reached base if (e.direction === 1 && e.x >= base.x - 90 || e.direction === -1 && e.x <= base.x + 90) { base.hp -= 1; base.hit(); e.destroy(); enemies.splice(i, 1); if (base.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } continue; } // Check if dead if (e.hp <= 0) { e.destroy(); enemies.splice(i, 1); if (Math.random() < 0.4) { // 40% chance to get gold per enemy gold += 5; goldTxt.setText("Gold: " + gold); } continue; } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); if (b.destroyed) { b.destroy(); bullets.splice(i, 1); } } // Wave logic if (waveInProgress) { if (enemiesSpawned < enemiesToSpawn) { if (spawnTimer <= 0) { // Spawn enemy from left or right var side = Math.random() < 0.5 ? -1 : 1; var EnemyClass = Enemy; EnemyClass.prototype.direction = side; // Set direction before instantiation for asset selection var e = new EnemyClass(); e.direction = side; e.x = side === 1 ? 0 : 2048; e.y = base.y - 200 + Math.random() * 400; // Make enemies slower and waves harder: lower base speed, increase HP and spawn more per wave e.speed = 1.5 + wave * 0.15 + Math.random() * 0.5; // slower base, less scaling e.hp = 2 + Math.floor(wave * 1.2); // more HP per wave enemies.push(e); game.addChild(e); enemiesSpawned++; spawnTimer = 36 + Math.floor(Math.random() * 24); // slightly slower spawn rate } else { spawnTimer--; } } else if (enemies.length === 0) { endWave(); } } else { if (nextWaveTimer > 0) { nextWaveTimer--; if (nextWaveTimer === 0) { startWave(); } } } }; // Start first wave startWave();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Base class
var Base = Container.expand(function () {
var self = Container.call(this);
// Attach base asset (ellipse, blue)
var baseGraphics = self.attachAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
baseGraphics.width = 180;
baseGraphics.height = 180;
baseGraphics.color = 0x3399ff;
self.maxHp = 20;
self.hp = self.maxHp;
// Flash on hit
self.hit = function () {
LK.effects.flashObject(self, 0xff0000, 400);
};
// Repair
self.repair = function () {
self.hp = Math.min(self.maxHp, self.hp + 5);
};
// Upgrade
self.upgrade = function () {
self.maxHp += 10;
self.hp = self.maxHp;
baseGraphics.scaleX += 0.1;
baseGraphics.scaleY += 0.1;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Attach bullet asset (box, yellow)
var bulletGraphics = self.attachAsset('bullet', {
anchorX: -2,
anchorY: 2
});
bulletGraphics.width = 20;
bulletGraphics.height = 20;
bulletGraphics.color = 0xb8b031;
self.speed = 24;
self.target = null;
self.side = 1;
self.damage = 1;
self.update = function () {
if (!self.target || self.target.destroyed) {
self.destroy();
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 40) {
// Hit!
self.target.hp -= self.damage;
LK.effects.flashObject(self.target, 0xffff00, 200);
self.destroy();
return;
}
var step = self.speed;
self.x += dx / dist * step;
self.y += dy / dist * step;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach enemy asset (ellipse, red)
// Use separate images for left- and right-spawned enemies
var assetId = self.direction === -1 ? 'enemyLeft' : 'enemyRight';
var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Set size and color
enemyGraphics.width = 90;
enemyGraphics.height = 90;
enemyGraphics.color = 0xd83318;
// Enemy properties
self.speed = 3 + Math.random() * 1.5; // Will be set per wave
self.hp = 1; // Will be set per wave
self.direction = 1; // 1 for right-to-left, -1 for left-to-right
// Update method
self.update = function () {
self.x += self.speed * self.direction;
};
return self;
});
// Turret class
var Turret = Container.expand(function () {
var self = Container.call(this);
// Attach turret asset (box, green)
var turretGraphics = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 0.5
});
turretGraphics.width = 100;
turretGraphics.height = 100;
turretGraphics.color = 0x83de44;
// Turret properties
self.range = 500;
self.fireRate = 60; // frames between shots
self.cooldown = 0;
self.level = 1;
self.side = 1; // 1 = right, -1 = left
// Upgrade method
self.upgrade = function () {
if (self.level < 3) {
self.level += 1;
self.range += 100;
self.fireRate = Math.max(30, self.fireRate - 10);
turretGraphics.scaleX += 0.1;
turretGraphics.scaleY += 0.1;
}
};
// Update method
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
return;
}
// Find closest enemy in range on this side
var closest = null;
var minDist = self.range + 1;
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
if (self.side === 1 && e.x > base.x || self.side === -1 && e.x < base.x) {
var dx = e.x - self.x;
var dy = e.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist && dist <= self.range) {
minDist = dist;
closest = e;
}
}
}
if (closest) {
// Fire at enemy
var b = new Bullet();
b.x = self.x;
b.y = self.y;
b.target = closest;
b.side = self.side;
b.damage = self.level;
// Reverse bullet image for left turrets
if (self.side === -1 && b.children && b.children.length > 0) {
if (typeof b.children[0].scaleX !== "undefined") {
b.children[0].scaleX = -1 * Math.abs(b.children[0].scaleX);
}
}
bullets.push(b);
game.addChild(b);
self.cooldown = self.fireRate;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Add background image to the game scene
var backgroundImg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
game.addChild(backgroundImg);
// Game state variables
var base = new Base();
base.x = 2048 / 2;
base.y = 2732 / 2;
game.addChild(base);
var turrets = [];
var enemies = [];
var bullets = [];
var gold = 50;
var wave = 1;
var enemiesToSpawn = 0;
var enemiesSpawned = 0;
var enemiesPerWave = 6;
var waveInProgress = false;
var spawnTimer = 0;
var nextWaveTimer = 0;
var baseHealthTxt, goldTxt, waveTxt;
var selectedTurret = null;
// HP Bar for base (black outline, gray background, green foreground)
// Use shape assets for outline, background, and foreground bar
var baseHpBarOutline = LK.getAsset('baseHpBarOutline', {
anchorX: 0.5,
anchorY: 0.5,
x: base.x,
y: base.y - 190,
width: 208,
height: 40
});
var baseHpBarBg = LK.getAsset('baseHpBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: base.x,
y: base.y - 190,
width: 200,
height: 32
});
var baseHpBar = LK.getAsset('baseHpBar', {
anchorX: 0,
anchorY: 0.5,
x: base.x - 100,
y: base.y - 190,
width: 200,
height: 32
});
game.addChild(baseHpBarOutline);
game.addChild(baseHpBarBg);
game.addChild(baseHpBar);
// (ground platform removed)
// GUI
// HP text removed
goldTxt = new Text2("Gold: " + gold, {
size: 80,
fill: 0xFFD700
});
goldTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(goldTxt);
waveTxt = new Text2("Wave: " + wave, {
size: 80,
fill: "#fff"
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
// Turret placement buttons (left and right)
// Space out the buttons and texts at the bottom of the screen for better separation
var bottomY = 2732 - 180;
var leftTurretBtn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 700,
y: bottomY,
scaleX: 1.2,
scaleY: 1.2
});
var rightTurretBtn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 700,
y: bottomY,
scaleX: 1.2,
scaleY: 1.2
});
game.addChild(leftTurretBtn);
game.addChild(rightTurretBtn);
var leftTurretCostTxt = new Text2("Buy: 30", {
size: 60,
fill: "#fff"
});
leftTurretCostTxt.anchor.set(0.5, 0);
leftTurretCostTxt.x = leftTurretBtn.x;
leftTurretCostTxt.y = leftTurretBtn.y + 100;
game.addChild(leftTurretCostTxt);
var rightTurretCostTxt = new Text2("Buy: 30", {
size: 60,
fill: "#fff"
});
rightTurretCostTxt.anchor.set(0.5, 0);
rightTurretCostTxt.x = rightTurretBtn.x;
rightTurretCostTxt.y = rightTurretBtn.y + 100;
game.addChild(rightTurretCostTxt);
// Base repair and upgrade buttons
var repairBtn = LK.getAsset('repair', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 350,
y: bottomY,
scaleX: 0.7,
scaleY: 0.7
});
var upgradeBtn = LK.getAsset('upgrade', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 350,
y: bottomY,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(repairBtn);
game.addChild(upgradeBtn);
var repairCostTxt = new Text2("Repair: 15", {
size: 60,
fill: "#fff"
});
repairCostTxt.anchor.set(0.5, 0);
repairCostTxt.x = repairBtn.x;
repairCostTxt.y = repairBtn.y + 100;
game.addChild(repairCostTxt);
var upgradeCostTxt = new Text2("Upgrade: 40", {
size: 60,
fill: "#fff"
});
upgradeCostTxt.anchor.set(0.5, 0);
upgradeCostTxt.x = upgradeBtn.x;
upgradeCostTxt.y = upgradeBtn.y + 100;
game.addChild(upgradeCostTxt);
// Turret upgrade buttons (appear above turrets)
function showTurretUpgradeBtn(turret) {
if (turret.upgradeBtn) {
return;
}
var btn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: turret.x,
y: turret.y - 120,
scaleX: 0.6,
scaleY: 0.6
});
var txt = new Text2("Upgrade: 25", {
size: 50,
fill: "#fff"
});
txt.anchor.set(0.5, 0);
txt.x = btn.x;
txt.y = btn.y + 50;
btn._upgradeTxt = txt;
game.addChild(btn);
game.addChild(txt);
turret.upgradeBtn = btn;
turret.upgradeTxt = txt;
}
// Remove upgrade button
function hideTurretUpgradeBtn(turret) {
if (turret.upgradeBtn) {
turret.upgradeBtn.destroy();
turret.upgradeTxt.destroy();
turret.upgradeBtn = null;
turret.upgradeTxt = null;
}
}
// Place initial turrets
function placeTurret(side) {
// Count how many turrets already exist on this side
var count = 0;
for (var i = 0; i < turrets.length; i++) {
if (turrets[i].side === side) {
count++;
}
}
// Place the first turret at center, then alternate above/below
var x = base.x + (side === 1 ? 300 : -300);
var y = base.y;
if (count > 0) {
// Alternate above and below, spacing by 180px
var offset = 180 * Math.ceil(count / 2);
if (count % 2 === 1) {
y = base.y - offset; // above
} else {
y = base.y + offset; // below
}
}
var t = new Turret();
t.x = x;
t.y = y;
t.side = side;
// Reverse the image for the left turret
if (side === -1 && t.children && t.children.length > 0) {
// Assume the first child is the turret graphics
if (typeof t.children[0].scaleX !== "undefined") {
t.children[0].scaleX = -1 * Math.abs(t.children[0].scaleX);
}
}
turrets.push(t);
game.addChild(t);
return t;
}
// Initial turrets
placeTurret(-1);
placeTurret(1);
// Handle turret placement
leftTurretBtn.down = function (x, y, obj) {
if (gold >= 30) {
var t = placeTurret(-1);
gold -= 30;
goldTxt.setText("Gold: " + gold);
}
};
rightTurretBtn.down = function (x, y, obj) {
if (gold >= 30) {
var t = placeTurret(1);
gold -= 30;
goldTxt.setText("Gold: " + gold);
}
};
// Handle base repair/upgrade
repairBtn.down = function (x, y, obj) {
if (gold >= 15 && base.hp < base.maxHp) {
base.repair();
gold -= 15;
goldTxt.setText("Gold: " + gold);
// HP text removed, no update needed here
}
};
upgradeBtn.down = function (x, y, obj) {
if (gold >= 40) {
base.upgrade();
gold -= 40;
goldTxt.setText("Gold: " + gold);
// HP text removed, no update needed here
}
};
// Handle turret upgrade
game.down = function (x, y, obj) {
// Check if a turret was tapped
for (var i = 0; i < turrets.length; i++) {
var t = turrets[i];
if (t && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t, {
x: x,
y: y
})) {
selectedTurret = t;
showTurretUpgradeBtn(t);
return;
}
}
// Check if upgrade button was tapped
for (var i = 0; i < turrets.length; i++) {
var t = turrets[i];
if (t && t.upgradeBtn && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t.upgradeBtn, {
x: x,
y: y
})) {
if (gold >= 25 && t.level < 3) {
t.upgrade();
gold -= 25;
goldTxt.setText("Gold: " + gold);
if (t.level >= 3) {
hideTurretUpgradeBtn(t);
}
}
return;
}
}
// Deselect turret if tap elsewhere
for (var i = 0; i < turrets.length; i++) {
hideTurretUpgradeBtn(turrets[i]);
}
selectedTurret = null;
};
// Enemy spawn logic
function startWave() {
waveInProgress = true;
enemiesToSpawn = Math.floor(enemiesPerWave + (wave - 1) * 4.5); // more enemies per wave, longer waves
enemiesSpawned = 0;
spawnTimer = 0;
waveTxt.setText("Wave: " + wave);
}
function endWave() {
waveInProgress = false;
nextWaveTimer = 120; // 2 seconds
gold += 20 + wave * 5;
goldTxt.setText("Gold: " + gold);
enemiesPerWave += 4; // increase more per wave, longer waves
wave += 1;
}
// Main update loop
game.update = function () {
// Update HP bar position and width
baseHpBarOutline.x = base.x;
baseHpBarOutline.y = base.y - 190;
baseHpBarBg.x = base.x;
baseHpBarBg.y = base.y - 190;
// Health bar shrinks left-to-right as base takes damage
var hpRatio = Math.max(0, base.hp) / base.maxHp;
baseHpBar.width = 200 * hpRatio;
baseHpBar.x = base.x - 100; // left edge stays fixed
baseHpBar.y = base.y - 190;
// Update turrets
for (var i = 0; i < turrets.length; i++) {
turrets[i].update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Check if reached base
if (e.direction === 1 && e.x >= base.x - 90 || e.direction === -1 && e.x <= base.x + 90) {
base.hp -= 1;
base.hit();
e.destroy();
enemies.splice(i, 1);
if (base.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
continue;
}
// Check if dead
if (e.hp <= 0) {
e.destroy();
enemies.splice(i, 1);
if (Math.random() < 0.4) {
// 40% chance to get gold per enemy
gold += 5;
goldTxt.setText("Gold: " + gold);
}
continue;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
if (b.destroyed) {
b.destroy();
bullets.splice(i, 1);
}
}
// Wave logic
if (waveInProgress) {
if (enemiesSpawned < enemiesToSpawn) {
if (spawnTimer <= 0) {
// Spawn enemy from left or right
var side = Math.random() < 0.5 ? -1 : 1;
var EnemyClass = Enemy;
EnemyClass.prototype.direction = side; // Set direction before instantiation for asset selection
var e = new EnemyClass();
e.direction = side;
e.x = side === 1 ? 0 : 2048;
e.y = base.y - 200 + Math.random() * 400;
// Make enemies slower and waves harder: lower base speed, increase HP and spawn more per wave
e.speed = 1.5 + wave * 0.15 + Math.random() * 0.5; // slower base, less scaling
e.hp = 2 + Math.floor(wave * 1.2); // more HP per wave
enemies.push(e);
game.addChild(e);
enemiesSpawned++;
spawnTimer = 36 + Math.floor(Math.random() * 24); // slightly slower spawn rate
} else {
spawnTimer--;
}
} else if (enemies.length === 0) {
endWave();
}
} else {
if (nextWaveTimer > 0) {
nextWaveTimer--;
if (nextWaveTimer === 0) {
startWave();
}
}
}
};
// Start first wave
startWave();
2d turret. In-Game asset. 2d. High contrast. No shadows
a 2d turret base. In-Game asset. 2d. High contrast. No shadows
a 2d upgrade button png. In-Game asset. 2d. High contrast. No shadows
purple zombie 2d. In-Game asset. 2d. High contrast. No shadows
add a grass background, empty middle, grass and trees around. In-Game asset. 2d. High contrast. No shadows