User prompt
quiero que las torres disparen a los enemigos
Code edit (1 edits merged)
Please save this source code
User prompt
Noob Tower Defense
User prompt
quiero un tower defens en el que llegan noobs y tienes que colocar torres para defender, los noob tendran que pasar por un camino que llega desde donde aparecen hasta la base la cual tendra vida
User prompt
si pero explicamelo en español
User prompt
quiero crear un tower defense
User prompt
en español porfavor
Initial prompt
hola, quiero crear un tower defense
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bullet = Container.expand(function (startX, startY, target, damage) { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.x = startX; self.y = startY; self.target = target; self.damage = damage; self.speed = 8; self.update = function () { if (!self.target || self.target.parent === null) { // Target destroyed, remove bullet self.destroy(); var index = bullets.indexOf(self); if (index > -1) bullets.splice(index, 1); return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 20) { // Hit target self.target.takeDamage(self.damage); self.destroy(); var index = bullets.indexOf(self); if (index > -1) bullets.splice(index, 1); } else { // Move towards target var moveX = dx / distance * self.speed; var moveY = dy / distance * self.speed; self.x += moveX; self.y += moveY; } }; return self; }); var Noob = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'basic'; var assetId = 'noob'; self.maxHealth = 100; self.speed = 2; self.reward = 10; if (self.type === 'fast') { assetId = 'fastNoob'; self.maxHealth = 60; self.speed = 4; self.reward = 15; } else if (self.type === 'strong') { assetId = 'strongNoob'; self.maxHealth = 200; self.speed = 1.5; self.reward = 25; } var noobGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.health = self.maxHealth; self.pathIndex = 0; self.targetX = pathPoints[0].x; self.targetY = pathPoints[0].y; self.update = function () { // Move towards current target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { // Reached current target, move to next self.pathIndex++; if (self.pathIndex >= pathPoints.length) { // Reached base baseHealth -= 20; self.destroy(); var index = noobs.indexOf(self); if (index > -1) noobs.splice(index, 1); return; } self.targetX = pathPoints[self.pathIndex].x; self.targetY = pathPoints[self.pathIndex].y; } else { // Move towards target var moveX = dx / distance * self.speed; var moveY = dy / distance * self.speed; self.x += moveX; self.y += moveY; } }; self.takeDamage = function (damage) { self.health -= damage; LK.getSound('enemyHit').play(); // Flash red when hit tween(noobGraphics, { tint: 0xFF0000 }, { duration: 100, onFinish: function onFinish() { tween(noobGraphics, { tint: 0xFFFFFF }, { duration: 100 }); } }); if (self.health <= 0) { currency += self.reward; LK.getSound('enemyDeath').play(); self.destroy(); var index = noobs.indexOf(self); if (index > -1) noobs.splice(index, 1); } }; return self; }); var Tower = Container.expand(function (gridX, gridY, towerType) { var self = Container.call(this); self.gridX = gridX; self.gridY = gridY; self.level = 1; self.towerType = towerType || 'basic'; var typeData = towerTypes[self.towerType]; self.damage = typeData.damage; self.range = typeData.range; self.attackSpeed = self.towerType === 'rapid' ? 30 : 60; // frames between attacks self.cost = typeData.cost; self.upgradeCost = Math.floor(typeData.cost * 1.5); self.lastAttack = 0; var towerGraphics = self.attachAsset(typeData.asset, { anchorX: 0.5, anchorY: 0.5 }); self.x = gridX * 128 + 64; self.y = gridY * 128 + 64; self.update = function () { self.lastAttack++; if (self.lastAttack >= self.attackSpeed) { // Look for enemies in range var target = null; var closestDistance = self.range; for (var i = 0; i < noobs.length; i++) { var noob = noobs[i]; var dx = noob.x - self.x; var dy = noob.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < closestDistance) { target = noob; closestDistance = distance; } } if (target) { self.shoot(target); self.lastAttack = 0; } } }; self.shoot = function (target) { var bullet = new Bullet(self.x, self.y, target, self.damage); game.addChild(bullet); bullets.push(bullet); LK.getSound('shoot').play(); }; self.upgrade = function () { if (self.level < 3 && currency >= self.upgradeCost) { currency -= self.upgradeCost; self.level++; self.damage += 15; self.range += 50; self.upgradeCost = Math.floor(self.upgradeCost * 1.5); if (self.level >= 2) { towerGraphics.removeChild(); towerGraphics = self.attachAsset('upgradedTower', { anchorX: 0.5, anchorY: 0.5 }); } // Visual upgrade effect tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } }; self.down = function (x, y, obj) { if (selectedTower !== self) { selectedTower = self; updateUI(); } else { self.upgrade(); updateUI(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F3542 }); /**** * Game Code ****/ // Game variables // Path tiles // Noobs // Towers // Projectiles // Base // UI Elements // Sounds var pathPoints = [{ x: 0, y: 1366 }, { x: 600, y: 1366 }, { x: 600, y: 800 }, { x: 1400, y: 800 }, { x: 1400, y: 1900 }, { x: 600, y: 1900 }, { x: 600, y: 1366 }, { x: 1500, y: 1366 }, { x: 2048, y: 1366 }]; var noobs = []; var towers = []; var bullets = []; var currency = 100; var baseHealth = 100; var wave = 1; var enemiesInWave = 5; var enemiesSpawned = 0; var waveComplete = true; var spawnTimer = 0; var selectedTower = null; // Create path visualization function createPath() { for (var i = 0; i < pathPoints.length - 1; i++) { var start = pathPoints[i]; var end = pathPoints[i + 1]; // Create tiles between points var steps = Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / 128; for (var j = 0; j <= steps; j++) { var x = start.x + (end.x - start.x) * (j / steps); var y = start.y + (end.y - start.y) * (j / steps); var pathTile = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0.5 }); pathTile.x = x; pathTile.y = y; game.addChild(pathTile); } } // Initialize path tiles data for tower placement checking createPathTiles(); } // Create grass background function createBackground() { for (var x = 0; x < 16; x++) { for (var y = 0; y < 22; y++) { var grassTile = LK.getAsset('grassTile', { anchorX: 0, anchorY: 0 }); grassTile.x = x * 128; grassTile.y = y * 128; game.addChild(grassTile); } } } // Create base var base = LK.getAsset('base', { anchorX: 0.5, anchorY: 0.5 }); base.x = pathPoints[pathPoints.length - 1].x; base.y = pathPoints[pathPoints.length - 1].y; // UI Elements var currencyText = new Text2('Currency: 100', { size: 80, fill: 0xFFD700 }); currencyText.anchor.set(0, 1); currencyText.x = -700; currencyText.y = -70; var healthText = new Text2('Base Health: 100', { size: 80, fill: 0xFF6B6B }); healthText.anchor.set(0, 1); healthText.x = -700; healthText.y = -160; var waveText = new Text2('Wave: 1', { size: 80, fill: 0x4ECDC4 }); waveText.anchor.set(0, 1); waveText.x = -700; waveText.y = -250; var towerInfoText = new Text2('Tap the PLACE TOWER button, then tap empty space to build', { size: 40, fill: 0xFFFFFF }); towerInfoText.anchor.set(0.5, 0); towerInfoText.x = 130; towerInfoText.y = 50; // Tower selection variables var selectedTowerType = null; var towerTypes = { basic: { cost: 50, damage: 25, range: 250, asset: 'basicTower', name: 'Basic Tower' }, cannon: { cost: 100, damage: 50, range: 220, asset: 'upgradedTower', name: 'Cannon Tower' }, rapid: { cost: 75, damage: 15, range: 280, asset: 'basicTower', name: 'Rapid Tower' } }; // Tower selection variables var canPlaceTowers = false; // Tower selection UI var towerSelectionContainer = new Container(); var towerButtons = []; var towerTypeNames = ['basic', 'cannon', 'rapid']; // Create horizontal background panel for all tower buttons var verticalBackground = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0 }); verticalBackground.x = 200; // Moved even more to the left verticalBackground.y = -470; // Position relative to top of expanded panel verticalBackground.width = 1900; // Increase width just a little bit more for horizontal layout extending further left verticalBackground.height = 620; // Increased height further downward for vertical expansion verticalBackground.alpha = 0.9; towerSelectionContainer.addChild(verticalBackground); // Create darker border for the vertical background panel var borderThickness = 8; // Top border var topBorder = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0 }); topBorder.x = verticalBackground.x; topBorder.y = verticalBackground.y; topBorder.width = verticalBackground.width + borderThickness * 2; topBorder.height = borderThickness; topBorder.tint = 0x3d2914; // Darker brown color towerSelectionContainer.addChild(topBorder); // Bottom border var bottomBorder = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0 }); bottomBorder.x = verticalBackground.x; bottomBorder.y = verticalBackground.y + verticalBackground.height; bottomBorder.width = verticalBackground.width + borderThickness * 2; bottomBorder.height = borderThickness; bottomBorder.tint = 0x3d2914; // Darker brown color towerSelectionContainer.addChild(bottomBorder); // Left border var leftBorder = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0 }); leftBorder.x = verticalBackground.x - verticalBackground.width / 2 - borderThickness / 2; leftBorder.y = verticalBackground.y; leftBorder.width = borderThickness; leftBorder.height = verticalBackground.height; leftBorder.tint = 0x3d2914; // Darker brown color towerSelectionContainer.addChild(leftBorder); // Right border var rightBorder = LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0 }); rightBorder.x = verticalBackground.x + verticalBackground.width / 2 + borderThickness / 2; rightBorder.y = verticalBackground.y; rightBorder.width = borderThickness; rightBorder.height = verticalBackground.height; rightBorder.tint = 0x3d2914; // Darker brown color towerSelectionContainer.addChild(rightBorder); // Create tower selection buttons for (var i = 0; i < towerTypeNames.length; i++) { var towerType = towerTypeNames[i]; var button = LK.getAsset('towerButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); button.x = 150 + i * 220; // Moved buttons slightly to the left button.y = -200; // Fixed vertical position at bottom button.towerType = towerType; button.selected = towerType === selectedTowerType; towerButtons.push(button); towerSelectionContainer.addChild(button); // Add tower type text below button var buttonText = new Text2(towerTypes[towerType].name, { size: 32, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.x = button.x; buttonText.y = button.y + 85; towerSelectionContainer.addChild(buttonText); // Add cost text below button var costText = new Text2('$' + towerTypes[towerType].cost, { size: 26, fill: 0xFFD700 }); costText.anchor.set(0.5, 0.5); costText.x = button.x; costText.y = button.y + 115; towerSelectionContainer.addChild(costText); } // Add event handlers to tower buttons after they are created for (var i = 0; i < towerButtons.length; i++) { var button = towerButtons[i]; button.interactive = true; // Create a closure to capture the correct towerType for each button (function (btn, type) { btn.down = function (x, y, obj) { // Check if player can afford this tower type if (currency >= towerTypes[type].cost) { selectedTowerType = type; selectedTower = null; updateUI(); } }; })(button, button.towerType); } // Position UI elements at bottom LK.gui.bottom.addChild(towerSelectionContainer); LK.gui.bottom.addChild(currencyText); LK.gui.bottom.addChild(healthText); LK.gui.bottom.addChild(waveText); LK.gui.top.addChild(towerInfoText); function updateUI() { currencyText.setText('Currency: ' + currency); healthText.setText('Base Health: ' + baseHealth); waveText.setText('Wave: ' + wave); if (selectedTower) { towerInfoText.setText('Tower Level ' + selectedTower.level + ' | Upgrade Cost: ' + selectedTower.upgradeCost + ' | Tap again to upgrade'); } else if (selectedTowerType) { towerInfoText.setText('Selected: ' + towerTypes[selectedTowerType].name + ' (Cost: ' + towerTypes[selectedTowerType].cost + ') - Tap empty space to build'); } else { towerInfoText.setText('Tap the PLACE TOWER button, then tap empty space to build'); } updateTowerSelectionUI(); } function updateTowerSelectionUI() { for (var i = 0; i < towerButtons.length; i++) { var button = towerButtons[i]; if (selectedTowerType && button.towerType === selectedTowerType) { button.tint = 0x00FF00; // Green for selected } else if (currency >= towerTypes[button.towerType].cost) { button.tint = 0xFFFFFF; // White for affordable } else { button.tint = 0x666666; // Gray for unaffordable } } } function startNextWave() { wave++; enemiesInWave = Math.floor(5 + wave * 1.5); enemiesSpawned = 0; waveComplete = false; spawnTimer = 0; selectedTower = null; updateUI(); } function spawnEnemy() { var enemyType = 'basic'; if (wave > 3 && Math.random() < 0.3) { enemyType = 'fast'; } if (wave > 5 && Math.random() < 0.2) { enemyType = 'strong'; } var noob = new Noob(enemyType); noob.x = pathPoints[0].x; noob.y = pathPoints[0].y; noobs.push(noob); game.addChild(noob); enemiesSpawned++; } // Create a set to store all path grid positions var pathTiles = []; function createPathTiles() { pathTiles = []; for (var i = 0; i < pathPoints.length - 1; i++) { var start = pathPoints[i]; var end = pathPoints[i + 1]; // Create tiles between points var steps = Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / 128; for (var j = 0; j <= steps; j++) { var x = start.x + (end.x - start.x) * (j / steps); var y = start.y + (end.y - start.y) * (j / steps); var gridX = Math.floor(x / 128); var gridY = Math.floor(y / 128); // Add to path tiles if not already added var found = false; for (var k = 0; k < pathTiles.length; k++) { if (pathTiles[k].x === gridX && pathTiles[k].y === gridY) { found = true; break; } } if (!found) { pathTiles.push({ x: gridX, y: gridY }); } } } } function canPlaceTower(gridX, gridY) { // Check if position is on path or too close to path for (var i = 0; i < pathTiles.length; i++) { var pathTileX = pathTiles[i].x; var pathTileY = pathTiles[i].y; var distance = Math.sqrt((gridX - pathTileX) * (gridX - pathTileX) + (gridY - pathTileY) * (gridY - pathTileY)); // Prevent placement if within 1.0 grid units of path if (distance < 1.0) { return false; } } // Check if tower already exists for (var i = 0; i < towers.length; i++) { if (towers[i].gridX === gridX && towers[i].gridY === gridY) { return false; } } return true; } // Initialize game elements createBackground(); createPath(); game.addChild(base); // Game event handlers game.down = function (x, y, obj) { // Only handle tower placement if we have a selected tower type and we're clicking on the game area (not UI) if (selectedTowerType && y < 2200) { // Make sure we're not clicking on bottom UI area var gridX = Math.floor(x / 128); var gridY = Math.floor(y / 128); var towerCost = towerTypes[selectedTowerType].cost; if (canPlaceTower(gridX, gridY) && currency >= towerCost) { var tower = new Tower(gridX, gridY, selectedTowerType); towers.push(tower); game.addChild(tower); currency -= towerCost; selectedTower = tower; selectedTowerType = null; // Clear selection after placing updateUI(); } else { selectedTower = null; updateUI(); } } }; game.update = function () { // Check game over if (baseHealth <= 0) { LK.showGameOver(); return; } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.parent) { bullet.update(); } } // Spawn enemies if (!waveComplete) { spawnTimer++; if (spawnTimer >= 90 && enemiesSpawned < enemiesInWave) { spawnEnemy(); spawnTimer = 0; } if (enemiesSpawned >= enemiesInWave && noobs.length === 0) { waveComplete = true; currency += 20; // Wave completion bonus updateUI(); } } else if (LK.ticks % 180 === 0) { // Auto-start next wave after 3 seconds startNextWave(); } // Update UI periodically if (LK.ticks % 30 === 0) { updateUI(); } }; // Start first wave updateUI(); startNextWave();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (startX, startY, target, damage) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 8;
self.update = function () {
if (!self.target || self.target.parent === null) {
// Target destroyed, remove bullet
self.destroy();
var index = bullets.indexOf(self);
if (index > -1) bullets.splice(index, 1);
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
// Hit target
self.target.takeDamage(self.damage);
self.destroy();
var index = bullets.indexOf(self);
if (index > -1) bullets.splice(index, 1);
} else {
// Move towards target
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
};
return self;
});
var Noob = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var assetId = 'noob';
self.maxHealth = 100;
self.speed = 2;
self.reward = 10;
if (self.type === 'fast') {
assetId = 'fastNoob';
self.maxHealth = 60;
self.speed = 4;
self.reward = 15;
} else if (self.type === 'strong') {
assetId = 'strongNoob';
self.maxHealth = 200;
self.speed = 1.5;
self.reward = 25;
}
var noobGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = self.maxHealth;
self.pathIndex = 0;
self.targetX = pathPoints[0].x;
self.targetY = pathPoints[0].y;
self.update = function () {
// Move towards current target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
// Reached current target, move to next
self.pathIndex++;
if (self.pathIndex >= pathPoints.length) {
// Reached base
baseHealth -= 20;
self.destroy();
var index = noobs.indexOf(self);
if (index > -1) noobs.splice(index, 1);
return;
}
self.targetX = pathPoints[self.pathIndex].x;
self.targetY = pathPoints[self.pathIndex].y;
} else {
// Move towards target
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('enemyHit').play();
// Flash red when hit
tween(noobGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(noobGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
currency += self.reward;
LK.getSound('enemyDeath').play();
self.destroy();
var index = noobs.indexOf(self);
if (index > -1) noobs.splice(index, 1);
}
};
return self;
});
var Tower = Container.expand(function (gridX, gridY, towerType) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.level = 1;
self.towerType = towerType || 'basic';
var typeData = towerTypes[self.towerType];
self.damage = typeData.damage;
self.range = typeData.range;
self.attackSpeed = self.towerType === 'rapid' ? 30 : 60; // frames between attacks
self.cost = typeData.cost;
self.upgradeCost = Math.floor(typeData.cost * 1.5);
self.lastAttack = 0;
var towerGraphics = self.attachAsset(typeData.asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = gridX * 128 + 64;
self.y = gridY * 128 + 64;
self.update = function () {
self.lastAttack++;
if (self.lastAttack >= self.attackSpeed) {
// Look for enemies in range
var target = null;
var closestDistance = self.range;
for (var i = 0; i < noobs.length; i++) {
var noob = noobs[i];
var dx = noob.x - self.x;
var dy = noob.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range && distance < closestDistance) {
target = noob;
closestDistance = distance;
}
}
if (target) {
self.shoot(target);
self.lastAttack = 0;
}
}
};
self.shoot = function (target) {
var bullet = new Bullet(self.x, self.y, target, self.damage);
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('shoot').play();
};
self.upgrade = function () {
if (self.level < 3 && currency >= self.upgradeCost) {
currency -= self.upgradeCost;
self.level++;
self.damage += 15;
self.range += 50;
self.upgradeCost = Math.floor(self.upgradeCost * 1.5);
if (self.level >= 2) {
towerGraphics.removeChild();
towerGraphics = self.attachAsset('upgradedTower', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Visual upgrade effect
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
};
self.down = function (x, y, obj) {
if (selectedTower !== self) {
selectedTower = self;
updateUI();
} else {
self.upgrade();
updateUI();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F3542
});
/****
* Game Code
****/
// Game variables
// Path tiles
// Noobs
// Towers
// Projectiles
// Base
// UI Elements
// Sounds
var pathPoints = [{
x: 0,
y: 1366
}, {
x: 600,
y: 1366
}, {
x: 600,
y: 800
}, {
x: 1400,
y: 800
}, {
x: 1400,
y: 1900
}, {
x: 600,
y: 1900
}, {
x: 600,
y: 1366
}, {
x: 1500,
y: 1366
}, {
x: 2048,
y: 1366
}];
var noobs = [];
var towers = [];
var bullets = [];
var currency = 100;
var baseHealth = 100;
var wave = 1;
var enemiesInWave = 5;
var enemiesSpawned = 0;
var waveComplete = true;
var spawnTimer = 0;
var selectedTower = null;
// Create path visualization
function createPath() {
for (var i = 0; i < pathPoints.length - 1; i++) {
var start = pathPoints[i];
var end = pathPoints[i + 1];
// Create tiles between points
var steps = Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / 128;
for (var j = 0; j <= steps; j++) {
var x = start.x + (end.x - start.x) * (j / steps);
var y = start.y + (end.y - start.y) * (j / steps);
var pathTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5
});
pathTile.x = x;
pathTile.y = y;
game.addChild(pathTile);
}
}
// Initialize path tiles data for tower placement checking
createPathTiles();
}
// Create grass background
function createBackground() {
for (var x = 0; x < 16; x++) {
for (var y = 0; y < 22; y++) {
var grassTile = LK.getAsset('grassTile', {
anchorX: 0,
anchorY: 0
});
grassTile.x = x * 128;
grassTile.y = y * 128;
game.addChild(grassTile);
}
}
}
// Create base
var base = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
base.x = pathPoints[pathPoints.length - 1].x;
base.y = pathPoints[pathPoints.length - 1].y;
// UI Elements
var currencyText = new Text2('Currency: 100', {
size: 80,
fill: 0xFFD700
});
currencyText.anchor.set(0, 1);
currencyText.x = -700;
currencyText.y = -70;
var healthText = new Text2('Base Health: 100', {
size: 80,
fill: 0xFF6B6B
});
healthText.anchor.set(0, 1);
healthText.x = -700;
healthText.y = -160;
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0x4ECDC4
});
waveText.anchor.set(0, 1);
waveText.x = -700;
waveText.y = -250;
var towerInfoText = new Text2('Tap the PLACE TOWER button, then tap empty space to build', {
size: 40,
fill: 0xFFFFFF
});
towerInfoText.anchor.set(0.5, 0);
towerInfoText.x = 130;
towerInfoText.y = 50;
// Tower selection variables
var selectedTowerType = null;
var towerTypes = {
basic: {
cost: 50,
damage: 25,
range: 250,
asset: 'basicTower',
name: 'Basic Tower'
},
cannon: {
cost: 100,
damage: 50,
range: 220,
asset: 'upgradedTower',
name: 'Cannon Tower'
},
rapid: {
cost: 75,
damage: 15,
range: 280,
asset: 'basicTower',
name: 'Rapid Tower'
}
};
// Tower selection variables
var canPlaceTowers = false;
// Tower selection UI
var towerSelectionContainer = new Container();
var towerButtons = [];
var towerTypeNames = ['basic', 'cannon', 'rapid'];
// Create horizontal background panel for all tower buttons
var verticalBackground = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0
});
verticalBackground.x = 200; // Moved even more to the left
verticalBackground.y = -470; // Position relative to top of expanded panel
verticalBackground.width = 1900; // Increase width just a little bit more for horizontal layout extending further left
verticalBackground.height = 620; // Increased height further downward for vertical expansion
verticalBackground.alpha = 0.9;
towerSelectionContainer.addChild(verticalBackground);
// Create darker border for the vertical background panel
var borderThickness = 8;
// Top border
var topBorder = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0
});
topBorder.x = verticalBackground.x;
topBorder.y = verticalBackground.y;
topBorder.width = verticalBackground.width + borderThickness * 2;
topBorder.height = borderThickness;
topBorder.tint = 0x3d2914; // Darker brown color
towerSelectionContainer.addChild(topBorder);
// Bottom border
var bottomBorder = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0
});
bottomBorder.x = verticalBackground.x;
bottomBorder.y = verticalBackground.y + verticalBackground.height;
bottomBorder.width = verticalBackground.width + borderThickness * 2;
bottomBorder.height = borderThickness;
bottomBorder.tint = 0x3d2914; // Darker brown color
towerSelectionContainer.addChild(bottomBorder);
// Left border
var leftBorder = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0
});
leftBorder.x = verticalBackground.x - verticalBackground.width / 2 - borderThickness / 2;
leftBorder.y = verticalBackground.y;
leftBorder.width = borderThickness;
leftBorder.height = verticalBackground.height;
leftBorder.tint = 0x3d2914; // Darker brown color
towerSelectionContainer.addChild(leftBorder);
// Right border
var rightBorder = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0
});
rightBorder.x = verticalBackground.x + verticalBackground.width / 2 + borderThickness / 2;
rightBorder.y = verticalBackground.y;
rightBorder.width = borderThickness;
rightBorder.height = verticalBackground.height;
rightBorder.tint = 0x3d2914; // Darker brown color
towerSelectionContainer.addChild(rightBorder);
// Create tower selection buttons
for (var i = 0; i < towerTypeNames.length; i++) {
var towerType = towerTypeNames[i];
var button = LK.getAsset('towerButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
button.x = 150 + i * 220; // Moved buttons slightly to the left
button.y = -200; // Fixed vertical position at bottom
button.towerType = towerType;
button.selected = towerType === selectedTowerType;
towerButtons.push(button);
towerSelectionContainer.addChild(button);
// Add tower type text below button
var buttonText = new Text2(towerTypes[towerType].name, {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = button.x;
buttonText.y = button.y + 85;
towerSelectionContainer.addChild(buttonText);
// Add cost text below button
var costText = new Text2('$' + towerTypes[towerType].cost, {
size: 26,
fill: 0xFFD700
});
costText.anchor.set(0.5, 0.5);
costText.x = button.x;
costText.y = button.y + 115;
towerSelectionContainer.addChild(costText);
}
// Add event handlers to tower buttons after they are created
for (var i = 0; i < towerButtons.length; i++) {
var button = towerButtons[i];
button.interactive = true;
// Create a closure to capture the correct towerType for each button
(function (btn, type) {
btn.down = function (x, y, obj) {
// Check if player can afford this tower type
if (currency >= towerTypes[type].cost) {
selectedTowerType = type;
selectedTower = null;
updateUI();
}
};
})(button, button.towerType);
}
// Position UI elements at bottom
LK.gui.bottom.addChild(towerSelectionContainer);
LK.gui.bottom.addChild(currencyText);
LK.gui.bottom.addChild(healthText);
LK.gui.bottom.addChild(waveText);
LK.gui.top.addChild(towerInfoText);
function updateUI() {
currencyText.setText('Currency: ' + currency);
healthText.setText('Base Health: ' + baseHealth);
waveText.setText('Wave: ' + wave);
if (selectedTower) {
towerInfoText.setText('Tower Level ' + selectedTower.level + ' | Upgrade Cost: ' + selectedTower.upgradeCost + ' | Tap again to upgrade');
} else if (selectedTowerType) {
towerInfoText.setText('Selected: ' + towerTypes[selectedTowerType].name + ' (Cost: ' + towerTypes[selectedTowerType].cost + ') - Tap empty space to build');
} else {
towerInfoText.setText('Tap the PLACE TOWER button, then tap empty space to build');
}
updateTowerSelectionUI();
}
function updateTowerSelectionUI() {
for (var i = 0; i < towerButtons.length; i++) {
var button = towerButtons[i];
if (selectedTowerType && button.towerType === selectedTowerType) {
button.tint = 0x00FF00; // Green for selected
} else if (currency >= towerTypes[button.towerType].cost) {
button.tint = 0xFFFFFF; // White for affordable
} else {
button.tint = 0x666666; // Gray for unaffordable
}
}
}
function startNextWave() {
wave++;
enemiesInWave = Math.floor(5 + wave * 1.5);
enemiesSpawned = 0;
waveComplete = false;
spawnTimer = 0;
selectedTower = null;
updateUI();
}
function spawnEnemy() {
var enemyType = 'basic';
if (wave > 3 && Math.random() < 0.3) {
enemyType = 'fast';
}
if (wave > 5 && Math.random() < 0.2) {
enemyType = 'strong';
}
var noob = new Noob(enemyType);
noob.x = pathPoints[0].x;
noob.y = pathPoints[0].y;
noobs.push(noob);
game.addChild(noob);
enemiesSpawned++;
}
// Create a set to store all path grid positions
var pathTiles = [];
function createPathTiles() {
pathTiles = [];
for (var i = 0; i < pathPoints.length - 1; i++) {
var start = pathPoints[i];
var end = pathPoints[i + 1];
// Create tiles between points
var steps = Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / 128;
for (var j = 0; j <= steps; j++) {
var x = start.x + (end.x - start.x) * (j / steps);
var y = start.y + (end.y - start.y) * (j / steps);
var gridX = Math.floor(x / 128);
var gridY = Math.floor(y / 128);
// Add to path tiles if not already added
var found = false;
for (var k = 0; k < pathTiles.length; k++) {
if (pathTiles[k].x === gridX && pathTiles[k].y === gridY) {
found = true;
break;
}
}
if (!found) {
pathTiles.push({
x: gridX,
y: gridY
});
}
}
}
}
function canPlaceTower(gridX, gridY) {
// Check if position is on path or too close to path
for (var i = 0; i < pathTiles.length; i++) {
var pathTileX = pathTiles[i].x;
var pathTileY = pathTiles[i].y;
var distance = Math.sqrt((gridX - pathTileX) * (gridX - pathTileX) + (gridY - pathTileY) * (gridY - pathTileY));
// Prevent placement if within 1.0 grid units of path
if (distance < 1.0) {
return false;
}
}
// Check if tower already exists
for (var i = 0; i < towers.length; i++) {
if (towers[i].gridX === gridX && towers[i].gridY === gridY) {
return false;
}
}
return true;
}
// Initialize game elements
createBackground();
createPath();
game.addChild(base);
// Game event handlers
game.down = function (x, y, obj) {
// Only handle tower placement if we have a selected tower type and we're clicking on the game area (not UI)
if (selectedTowerType && y < 2200) {
// Make sure we're not clicking on bottom UI area
var gridX = Math.floor(x / 128);
var gridY = Math.floor(y / 128);
var towerCost = towerTypes[selectedTowerType].cost;
if (canPlaceTower(gridX, gridY) && currency >= towerCost) {
var tower = new Tower(gridX, gridY, selectedTowerType);
towers.push(tower);
game.addChild(tower);
currency -= towerCost;
selectedTower = tower;
selectedTowerType = null; // Clear selection after placing
updateUI();
} else {
selectedTower = null;
updateUI();
}
}
};
game.update = function () {
// Check game over
if (baseHealth <= 0) {
LK.showGameOver();
return;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.parent) {
bullet.update();
}
}
// Spawn enemies
if (!waveComplete) {
spawnTimer++;
if (spawnTimer >= 90 && enemiesSpawned < enemiesInWave) {
spawnEnemy();
spawnTimer = 0;
}
if (enemiesSpawned >= enemiesInWave && noobs.length === 0) {
waveComplete = true;
currency += 20; // Wave completion bonus
updateUI();
}
} else if (LK.ticks % 180 === 0) {
// Auto-start next wave after 3 seconds
startNextWave();
}
// Update UI periodically
if (LK.ticks % 30 === 0) {
updateUI();
}
};
// Start first wave
updateUI();
startNextWave();