User prompt
enemies spawn at the beginning and move towards the end of the path, so fix the progress of the enemies
User prompt
Aliens spawn at the beginning and move towards the end of the path, so fix the progress of the aliens
User prompt
Let the enemies spawn at the beginning of the brown road
Code edit (1 edits merged)
Please save this source code
User prompt
Fortress Guardian
Initial prompt
make a tower defense game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basicEnemy';
self.enemyGraphic = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
switch (self.type) {
case 'basicEnemy':
self.maxHealth = 100;
self.speed = 1.5;
self.goldValue = 10;
break;
case 'fastEnemy':
self.maxHealth = 75;
self.speed = 2.5;
self.goldValue = 15;
break;
case 'tankEnemy':
self.maxHealth = 250;
self.speed = 0.8;
self.goldValue = 25;
break;
case 'bossEnemy':
self.maxHealth = 500;
self.speed = 1.0;
self.goldValue = 100;
break;
default:
self.maxHealth = 100;
self.speed = 1.5;
self.goldValue = 10;
}
self.health = self.maxHealth;
self.currentPathIndex = 0;
self.reachedEnd = false;
// Health bar
self.healthBarBackground = new Container();
self.healthBarBackground.width = self.enemyGraphic.width * 1.2;
self.healthBarBackground.height = 10;
self.healthBarBackground.x = -self.healthBarBackground.width / 2;
self.healthBarBackground.y = -self.enemyGraphic.height / 2 - 15;
self.addChild(self.healthBarBackground);
self.healthBar = new Container();
self.healthBar.width = self.healthBarBackground.width;
self.healthBar.height = self.healthBarBackground.height;
self.healthBar.x = self.healthBarBackground.x;
self.healthBar.y = self.healthBarBackground.y;
self.addChild(self.healthBar);
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.width = self.healthBarBackground.width * healthPercentage;
// Change color based on health percentage
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
};
self.takeDamage = function (amount) {
self.health -= amount;
self.updateHealthBar();
// Briefly flash the enemy when taking damage
tween(self.enemyGraphic, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.enemyGraphic, {
alpha: 1
}, {
duration: 100
});
}
});
if (self.health <= 0) {
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.moveAlongPath = function (path) {
if (self.currentPathIndex >= path.length) {
self.reachedEnd = true;
return true;
}
var targetX = path[self.currentPathIndex].x;
var targetY = path[self.currentPathIndex].y;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 5) {
self.currentPathIndex++;
return false;
}
var normalizedX = dx / distance;
var normalizedY = dy / distance;
self.x += normalizedX * self.speed;
self.y += normalizedY * self.speed;
return false;
};
self.updateHealthBar();
return self;
});
var MapTile = Container.expand(function (tileType) {
var self = Container.call(this);
self.tileType = tileType || 'grass';
self.canPlaceTower = self.tileType === 'grass';
var tileGraphic = self.attachAsset(self.tileType, {
anchorX: 0.5,
anchorY: 0.5
});
self.setHighlight = function (highlight) {
if (highlight && self.canPlaceTower) {
tileGraphic.alpha = 0.8;
} else {
tileGraphic.alpha = 1.0;
}
};
return self;
});
var Projectile = Container.expand(function (targetEnemy, damage, speed, type) {
var self = Container.call(this);
self.targetEnemy = targetEnemy;
self.damage = damage || 25;
self.speed = speed || 10;
self.projectileType = type || 'projectile';
var projectileGraphic = self.attachAsset(self.projectileType, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (!self.targetEnemy || !self.targetEnemy.parent) {
self.destroy();
return;
}
var dx = self.targetEnemy.x - self.x;
var dy = self.targetEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 15) {
// Hit enemy
if (self.targetEnemy.takeDamage(self.damage)) {
// Enemy is dead
gameState.gold += self.targetEnemy.goldValue;
gameState.score += self.targetEnemy.goldValue;
updateGoldText();
updateScoreText();
LK.getSound('enemyDeath').play();
var enemyIndex = gameState.enemies.indexOf(self.targetEnemy);
if (enemyIndex !== -1) {
self.targetEnemy.destroy();
gameState.enemies.splice(enemyIndex, 1);
}
}
self.destroy();
return;
}
// Move toward enemy
var normalizedX = dx / distance;
var normalizedY = dy / distance;
self.x += normalizedX * self.speed;
self.y += normalizedY * self.speed;
// Rotate projectile to face direction of travel
self.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
return self;
});
var Tower = Container.expand(function (type) {
var self = Container.call(this);
self.towerType = type || 'baseTower';
self.baseTower = self.attachAsset('baseTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.towerGraphic = self.attachAsset(self.towerType, {
anchorX: 0.5,
anchorY: 0.5,
y: -10
});
// Tower properties based on type
switch (self.towerType) {
case 'cannonTower':
self.damage = 40;
self.range = 200;
self.attackSpeed = 1.5; // Attacks per second
self.cost = 100;
self.projectileSpeed = 8;
self.targetingStrategy = 'first'; // Target first enemy in path
break;
case 'archerTower':
self.damage = 20;
self.range = 300;
self.attackSpeed = 3; // Attacks per second
self.cost = 150;
self.projectileSpeed = 15;
self.targetingStrategy = 'first';
break;
case 'magicTower':
self.damage = 30;
self.range = 250;
self.attackSpeed = 2; // Attacks per second
self.cost = 200;
self.projectileSpeed = 10;
self.targetingStrategy = 'strongest'; // Target enemy with most health
break;
default:
self.damage = 25;
self.range = 200;
self.attackSpeed = 1; // Attacks per second
self.cost = 50;
self.projectileSpeed = 8;
self.targetingStrategy = 'first';
}
self.level = 1;
self.attackCooldown = 0;
self.rangeIndicator = null;
self.selected = false;
// Show range indicator when tower is selected
self.showRange = function (show) {
if (show && !self.rangeIndicator) {
self.rangeIndicator = self.attachAsset('rangeIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
scaleX: self.range / 300,
// Scale to match tower's range
scaleY: self.range / 300
});
self.rangeIndicator.zIndex = -1;
} else if (!show && self.rangeIndicator) {
self.removeChild(self.rangeIndicator);
self.rangeIndicator = null;
}
};
self.upgrade = function () {
if (self.level >= 3) return false; // Max level reached
var upgradeCost = self.cost * self.level;
if (gameState.gold < upgradeCost) return false; // Not enough gold
gameState.gold -= upgradeCost;
self.level++;
// Upgrade stats
self.damage *= 1.5;
self.range *= 1.2;
self.attackSpeed *= 1.2;
// Update visuals for upgraded tower
self.towerGraphic.scale.set(1 + (self.level - 1) * 0.2);
// Update range indicator if visible
if (self.rangeIndicator) {
self.removeChild(self.rangeIndicator);
self.showRange(true);
}
updateGoldText();
return true;
};
self.findTarget = function (enemies) {
var target = null;
var maxPriority = -1;
var minDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range) {
var priority = 0;
switch (self.targetingStrategy) {
case 'first':
priority = enemy.currentPathIndex + (1 - distance / self.range);
break;
case 'strongest':
priority = enemy.health;
break;
case 'closest':
priority = self.range - distance;
break;
}
if (priority > maxPriority || priority === maxPriority && distance < minDistance) {
maxPriority = priority;
minDistance = distance;
target = enemy;
}
}
}
return target;
};
self.attackEnemy = function (enemy) {
if (!enemy) return;
// Create projectile
var projectile = new Projectile(enemy, self.damage, self.projectileSpeed);
projectile.x = self.x;
projectile.y = self.y;
game.addChild(projectile);
gameState.projectiles.push(projectile);
LK.getSound('projectileShot').play();
// Reset cooldown
self.attackCooldown = 60 / self.attackSpeed;
// Tower attack animation
tween(self.towerGraphic, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.towerGraphic, {
scaleX: 1 + (self.level - 1) * 0.2,
scaleY: 1 + (self.level - 1) * 0.2
}, {
duration: 100
});
}
});
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
} else {
var target = self.findTarget(gameState.enemies);
if (target) {
self.attackEnemy(target);
}
}
};
self.down = function (x, y, obj) {
// Select this tower, deselect others
selectTower(self);
};
return self;
});
var TowerButton = Container.expand(function (towerType, cost) {
var self = Container.call(this);
self.towerType = towerType;
self.cost = cost;
var button = self.attachAsset('uiButton', {
anchorX: 0.5,
anchorY: 0.5
});
var towerPreview = self.attachAsset(towerType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var costText = new Text2(cost.toString(), {
size: 24,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 30;
self.addChild(costText);
self.setEnabled = function (enabled) {
button.alpha = enabled ? 1.0 : 0.5;
towerPreview.alpha = enabled ? 1.0 : 0.5;
self.enabled = enabled;
};
self.down = function (x, y, obj) {
if (!self.enabled) return;
// Set the selected tower type for placement
gameState.selectedTowerType = self.towerType;
gameState.placingTower = true;
// Deselect any selected tower
if (gameState.selectedTower) {
gameState.selectedTower.showRange(false);
gameState.selectedTower = null;
}
// Show tower placeholders
for (var i = 0; i < gameState.map.length; i++) {
for (var j = 0; j < gameState.map[i].length; j++) {
var tile = gameState.map[i][j];
if (tile.canPlaceTower && !tile.tower) {
tile.setHighlight(true);
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2B5329 // Green background for the game
});
/****
* Game Code
****/
// Music
// Sounds
// Map and UI assets
// Enemy assets
// Tower assets
// Game state variables
var gameState = {
gold: 200,
lives: 10,
score: 0,
wave: 0,
enemyCount: 0,
waveInProgress: false,
selectedTower: null,
selectedTowerType: null,
placingTower: false,
map: [],
towers: [],
enemies: [],
projectiles: [],
path: [],
tileSize: 100,
mapWidth: 10,
mapHeight: 10
};
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 36,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var goldText = new Text2('Gold: ' + gameState.gold, {
size: 36,
fill: 0xFFD700
});
goldText.anchor.set(0, 0);
goldText.x = 150;
LK.gui.topLeft.addChild(goldText);
var livesText = new Text2('Lives: ' + gameState.lives, {
size: 36,
fill: 0xFF0000
});
livesText.anchor.set(1, 0);
livesText.x = -150;
LK.gui.topRight.addChild(livesText);
var waveText = new Text2('Wave: ' + gameState.wave, {
size: 36,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.y = 50;
LK.gui.top.addChild(waveText);
var nextWaveButton = new Container();
var nextWaveButtonGraphic = nextWaveButton.attachAsset('uiButton', {
anchorX: 0.5,
anchorY: 0.5
});
var nextWaveButtonText = new Text2('Next Wave', {
size: 30,
fill: 0xFFFFFF
});
nextWaveButtonText.anchor.set(0.5, 0.5);
nextWaveButton.addChild(nextWaveButtonText);
nextWaveButton.x = 0;
nextWaveButton.y = -100;
LK.gui.bottom.addChild(nextWaveButton);
// Create tower buttons UI
var towerButtonsContainer = new Container();
towerButtonsContainer.y = -200;
LK.gui.bottom.addChild(towerButtonsContainer);
var towerButtons = [{
type: 'cannonTower',
cost: 100
}, {
type: 'archerTower',
cost: 150
}, {
type: 'magicTower',
cost: 200
}];
var buttonSpacing = 220;
for (var i = 0; i < towerButtons.length; i++) {
var button = new TowerButton(towerButtons[i].type, towerButtons[i].cost);
button.x = (i - (towerButtons.length - 1) / 2) * buttonSpacing;
towerButtonsContainer.addChild(button);
}
// Tower upgrade button and sell button
var upgradeButton = new Container();
var upgradeButtonGraphic = upgradeButton.attachAsset('uiButton', {
anchorX: 0.5,
anchorY: 0.5
});
var upgradeButtonText = new Text2('Upgrade', {
size: 30,
fill: 0xFFFFFF
});
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButton.addChild(upgradeButtonText);
upgradeButton.visible = false;
upgradeButton.x = -120;
upgradeButton.y = -300;
LK.gui.bottom.addChild(upgradeButton);
var sellButton = new Container();
var sellButtonGraphic = sellButton.attachAsset('uiButton', {
anchorX: 0.5,
anchorY: 0.5
});
var sellButtonText = new Text2('Sell', {
size: 30,
fill: 0xFFFFFF
});
sellButtonText.anchor.set(0.5, 0.5);
sellButton.addChild(sellButtonText);
sellButton.visible = false;
sellButton.x = 120;
sellButton.y = -300;
LK.gui.bottom.addChild(sellButton);
// Update functions for UI elements
function updateScoreText() {
scoreText.setText('Score: ' + gameState.score);
}
function updateGoldText() {
goldText.setText('Gold: ' + gameState.gold);
// Update tower buttons enabled/disabled state based on gold
for (var i = 0; i < towerButtonsContainer.children.length; i++) {
var button = towerButtonsContainer.children[i];
button.setEnabled(gameState.gold >= button.cost);
}
}
function updateLivesText() {
livesText.setText('Lives: ' + gameState.lives);
}
function updateWaveText() {
waveText.setText('Wave: ' + gameState.wave);
}
// Generate the game map with path
function generateMap() {
// Define map layout
var layout = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 1, 1, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 1, 1, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 2]];
var startX = 0;
var startY = 0;
var endX = 0;
var endY = 0;
// X offset to center map on screen
var offsetX = (2048 - gameState.mapWidth * gameState.tileSize) / 2;
var offsetY = (2732 - gameState.mapHeight * gameState.tileSize) / 2 - 150; // Offset to account for UI
// Create map tiles based on layout
for (var i = 0; i < gameState.mapHeight; i++) {
gameState.map[i] = [];
for (var j = 0; j < gameState.mapWidth; j++) {
var tileType = layout[i][j] === 1 ? 'path' : 'grass';
// Handle start point (entry point)
if (layout[i][j] === 1 && (i === 0 || j === 0 || i === gameState.mapHeight - 1 || j === gameState.mapWidth - 1)) {
if (gameState.path.length === 0) {
startX = j * gameState.tileSize + offsetX + gameState.tileSize / 2;
startY = i * gameState.tileSize + offsetY + gameState.tileSize / 2;
}
}
// Handle end point (base)
if (layout[i][j] === 2) {
tileType = 'baseStructure';
endX = j * gameState.tileSize + offsetX + gameState.tileSize / 2;
endY = i * gameState.tileSize + offsetY + gameState.tileSize / 2;
}
var tile = new MapTile(tileType);
tile.x = j * gameState.tileSize + offsetX + gameState.tileSize / 2;
tile.y = i * gameState.tileSize + offsetY + gameState.tileSize / 2;
tile.gridX = j;
tile.gridY = i;
tile.tower = null;
gameState.map[i][j] = tile;
game.addChild(tile);
// Add to path if it's a path tile
if (tileType === 'path') {
gameState.path.push({
x: tile.x,
y: tile.y,
tile: tile
});
}
}
}
// Sort path from start to end (using a simplified approach for this straight path)
// This is a simplification - a real game would need a proper path finding algorithm
gameState.path.sort(function (a, b) {
var distA = Math.sqrt(Math.pow(a.x - startX, 2) + Math.pow(a.y - startY, 2));
var distB = Math.sqrt(Math.pow(b.x - startX, 2) + Math.pow(b.y - startY, 2));
return distA - distB;
});
// The first point should be off-screen for enemy spawn
gameState.path.unshift({
x: startX - gameState.tileSize,
y: startY,
offScreen: true
});
// The last point is the base
gameState.path.push({
x: endX,
y: endY,
isBase: true
});
}
// Start a new wave of enemies
function startWave() {
if (gameState.waveInProgress) return;
gameState.wave++;
updateWaveText();
gameState.waveInProgress = true;
gameState.enemyCount = 5 + gameState.wave * 2; // More enemies per wave
LK.getSound('waveStart').play();
var spawnInterval = LK.setInterval(function () {
spawnEnemy();
gameState.enemyCount--;
if (gameState.enemyCount <= 0) {
LK.clearInterval(spawnInterval);
// Wave is considered over when all enemies are spawned
// The actual check for wave completion is in the update function
}
}, 1500 - gameState.wave * 100); // Spawn faster in later waves
}
// Spawn an enemy
function spawnEnemy() {
var enemyTypes = ['basicEnemy'];
// Add more enemy types as waves progress
if (gameState.wave >= 3) enemyTypes.push('fastEnemy');
if (gameState.wave >= 5) enemyTypes.push('tankEnemy');
if (gameState.wave >= 10 && gameState.wave % 5 === 0) enemyTypes.push('bossEnemy');
var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
// Always spawn a boss on wave 5, 10, 15, etc.
if (gameState.wave % 5 === 0 && gameState.enemyCount === 0) {
randomType = 'bossEnemy';
}
var enemy = new Enemy(randomType);
// Spawn at the start of the path
// Find the first actual path tile (index 1), as index 0 is off-screen
var startPoint = gameState.path[1];
enemy.x = startPoint.x;
enemy.y = startPoint.y;
gameState.enemies.push(enemy);
game.addChild(enemy);
}
// Check if wave is complete
function checkWaveComplete() {
if (gameState.waveInProgress && gameState.enemyCount <= 0 && gameState.enemies.length === 0) {
gameState.waveInProgress = false;
gameState.gold += 50 + gameState.wave * 10; // Bonus gold for completing wave
updateGoldText();
}
}
// Place a tower on the map
function placeTower(gridX, gridY) {
var tile = gameState.map[gridY][gridX];
if (!tile.canPlaceTower || tile.tower) return false;
var towerCost = 0;
switch (gameState.selectedTowerType) {
case 'cannonTower':
towerCost = 100;
break;
case 'archerTower':
towerCost = 150;
break;
case 'magicTower':
towerCost = 200;
break;
default:
towerCost = 100;
}
if (gameState.gold < towerCost) return false;
var tower = new Tower(gameState.selectedTowerType);
tower.x = tile.x;
tower.y = tile.y;
tower.gridX = gridX;
tower.gridY = gridY;
tile.tower = tower;
gameState.towers.push(tower);
game.addChild(tower);
gameState.gold -= towerCost;
updateGoldText();
LK.getSound('buildTower').play();
// Clear tower placement mode
clearTowerPlacement();
return true;
}
// Select a tower
function selectTower(tower) {
// Deselect previously selected tower
if (gameState.selectedTower) {
gameState.selectedTower.showRange(false);
}
// Clear tower placement mode
clearTowerPlacement();
// Select new tower
gameState.selectedTower = tower;
tower.showRange(true);
// Show upgrade and sell buttons
upgradeButton.visible = true;
sellButton.visible = true;
}
// Clear tower placement mode
function clearTowerPlacement() {
gameState.placingTower = false;
gameState.selectedTowerType = null;
// Remove highlights from all tiles
for (var i = 0; i < gameState.map.length; i++) {
for (var j = 0; j < gameState.map[i].length; j++) {
gameState.map[i][j].setHighlight(false);
}
}
}
// Handle game over
function checkGameOver() {
if (gameState.lives <= 0) {
// Update high score
if (gameState.score > storage.highScore) {
storage.highScore = gameState.score;
}
// Game over
LK.getSound('gameOver').play();
LK.showGameOver();
}
}
// Event handlers
nextWaveButton.down = function () {
if (!gameState.waveInProgress) {
startWave();
}
};
upgradeButton.down = function () {
if (gameState.selectedTower) {
if (gameState.selectedTower.upgrade()) {
// Success - tower was upgraded
} else {
// Failed to upgrade (either max level or not enough gold)
}
}
};
sellButton.down = function () {
if (gameState.selectedTower) {
// Refund 70% of tower cost
var refundAmount = Math.floor(gameState.selectedTower.cost * 0.7);
gameState.gold += refundAmount;
updateGoldText();
// Remove tower from map and arrays
var tile = gameState.map[gameState.selectedTower.gridY][gameState.selectedTower.gridX];
tile.tower = null;
var towerIndex = gameState.towers.indexOf(gameState.selectedTower);
if (towerIndex !== -1) {
gameState.towers.splice(towerIndex, 1);
}
gameState.selectedTower.destroy();
gameState.selectedTower = null;
// Hide buttons
upgradeButton.visible = false;
sellButton.visible = false;
}
};
game.down = function (x, y, obj) {
if (gameState.placingTower) {
// Find which tile was clicked
for (var i = 0; i < gameState.map.length; i++) {
for (var j = 0; j < gameState.map[i].length; j++) {
var tile = gameState.map[i][j];
var dx = tile.x - x;
var dy = tile.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < gameState.tileSize / 2) {
if (placeTower(j, i)) {
return; // Tower placed successfully
}
}
}
}
// Clicked outside valid tile, cancel placement
clearTowerPlacement();
} else {
// Check if clicked on a tower
var towerClicked = false;
for (var i = 0; i < gameState.towers.length; i++) {
var tower = gameState.towers[i];
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < gameState.tileSize / 2) {
selectTower(tower);
towerClicked = true;
break;
}
}
// If clicked outside tower, deselect current tower
if (!towerClicked && gameState.selectedTower) {
gameState.selectedTower.showRange(false);
gameState.selectedTower = null;
upgradeButton.visible = false;
sellButton.visible = false;
}
}
};
// Main update function
game.update = function () {
// Update all towers
for (var i = 0; i < gameState.towers.length; i++) {
gameState.towers[i].update();
}
// Update all projectiles
for (var i = gameState.projectiles.length - 1; i >= 0; i--) {
gameState.projectiles[i].update();
// Check if projectile needs to be removed
if (!gameState.projectiles[i].parent) {
gameState.projectiles.splice(i, 1);
}
}
// Update all enemies
for (var i = gameState.enemies.length - 1; i >= 0; i--) {
var enemy = gameState.enemies[i];
var reachedEnd = enemy.moveAlongPath(gameState.path);
if (reachedEnd) {
// Enemy reached the base, player loses a life
gameState.lives--;
updateLivesText();
LK.getSound('playerDamage').play();
// Remove enemy
enemy.destroy();
gameState.enemies.splice(i, 1);
// Flash screen
LK.effects.flashScreen(0xFF0000, 500);
// Check for game over
checkGameOver();
}
}
// Check if wave is complete
checkWaveComplete();
// Update UI button states
nextWaveButton.alpha = gameState.waveInProgress ? 0.5 : 1.0;
};
// Initialize game
function initGame() {
// Reset game state
gameState.gold = 200;
gameState.lives = 10;
gameState.score = 0;
gameState.wave = 0;
gameState.waveInProgress = false;
gameState.selectedTower = null;
gameState.selectedTowerType = null;
gameState.placingTower = false;
gameState.map = [];
gameState.towers = [];
gameState.enemies = [];
gameState.projectiles = [];
gameState.path = [];
// Update UI
updateScoreText();
updateGoldText();
updateLivesText();
updateWaveText();
// Generate map
generateMap();
// Hide upgrade and sell buttons
upgradeButton.visible = false;
sellButton.visible = false;
// Play background music
LK.playMusic('bgMusic');
}
// Start the game
initGame(); ===================================================================
--- original.js
+++ change.js
@@ -631,9 +631,10 @@
randomType = 'bossEnemy';
}
var enemy = new Enemy(randomType);
// Spawn at the start of the path
- var startPoint = gameState.path[0];
+ // Find the first actual path tile (index 1), as index 0 is off-screen
+ var startPoint = gameState.path[1];
enemy.x = startPoint.x;
enemy.y = startPoint.y;
gameState.enemies.push(enemy);
game.addChild(enemy);
a archer robot. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a robotic heart. In-Game asset. 2d. High contrast. No shadows
a alien with space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a king alien with space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a cannon robot. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a fast alien with space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a magic wizard robot. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a tank alien with space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat