User prompt
düşmanlar kulelerin menziline girdiğinde kuleler düşmanları hedef alarak ateş etsin
User prompt
bazı hatalar var kontrol edip düzeltirmisin
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var localPos = towerInfoPanel.toLocal(obj.position);' Line Number: 623
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'basicTowerBtn.style.fill = coins >= 50 ? "#4444FF" : "#666666";' Line Number: 508
User prompt
Generate the first version of the source code of my game: Tower Defense Remix. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tower Defense Remix
Initial prompt
#TowerDefenseRemix
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (tower, target, towerType) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.tower = tower;
self.target = target;
self.towerType = towerType;
self.speed = 8;
// Calculate direction
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.vx = dx / distance * self.speed;
self.vy = dy / distance * self.speed;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Check collision with target
if (self.target && self.intersects(self.target)) {
self.hit();
return;
}
// Remove if off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
}
};
self.hit = function () {
LK.getSound('hit').play();
if (self.towerType === 'splash') {
// Splash damage
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.tower.splashRadius) {
var killed = enemy.takeDamage(self.tower.damage);
if (killed) {
coins += enemy.reward;
enemy.destroy();
enemies.splice(enemies.indexOf(enemy), 1);
}
}
}
// Create explosion effect
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
explosion.x = self.x;
explosion.y = self.y;
explosion.alpha = 0.7;
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
explosion.destroy();
}
});
} else {
// Regular damage
var killed = self.target.takeDamage(self.tower.damage);
if (killed) {
coins += self.target.reward;
self.target.destroy();
enemies.splice(enemies.indexOf(self.target), 1);
}
// Apply slow effect if slow tower
if (self.towerType === 'slow' && !killed) {
self.target.applySlow(self.tower.slowFactor, self.tower.slowDuration);
}
}
// Remove bullet
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
};
return self;
});
// Game variables
var Enemy = Container.expand(function (type, pathIndex) {
var self = Container.call(this);
// Enemy properties based on type
var enemyConfig = {
basic: {
asset: 'basicEnemy',
health: 100,
speed: 2,
reward: 10
},
fast: {
asset: 'fastEnemy',
health: 60,
speed: 4,
reward: 15
},
tank: {
asset: 'tankEnemy',
health: 300,
speed: 1,
reward: 25
}
};
var config = enemyConfig[type] || enemyConfig.basic;
var enemyGraphics = self.attachAsset(config.asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = config.health;
self.health = config.health;
self.speed = config.speed;
self.reward = config.reward;
self.pathIndex = pathIndex || 0;
self.slowEffect = 1;
self.slowDuration = 0;
// Health bar
var healthBarBg = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.1,
y: -40
});
healthBarBg.tint = 0x333333;
self.addChild(healthBarBg);
var healthBar = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.1,
y: -40
});
healthBar.tint = 0x00FF00;
self.addChild(healthBar);
self.healthBar = healthBar;
self.takeDamage = function (damage) {
self.health -= damage;
var healthPercent = Math.max(0, self.health / self.maxHealth);
self.healthBar.scaleX = 0.6 * healthPercent;
// Health bar color changes
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00;
} else {
self.healthBar.tint = 0xFF0000;
}
// Flash effect
tween(enemyGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
return self.health <= 0;
};
self.applySlow = function (factor, duration) {
self.slowEffect = Math.min(self.slowEffect, factor);
self.slowDuration = Math.max(self.slowDuration, duration);
};
self.update = function () {
// Update slow effect
if (self.slowDuration > 0) {
self.slowDuration--;
if (self.slowDuration <= 0) {
self.slowEffect = 1;
}
}
// Move along path
if (self.pathIndex < gamePath.length - 1) {
var currentTarget = gamePath[self.pathIndex + 1];
var dx = currentTarget.x - self.x;
var dy = currentTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length - 1) {
// Reached base
baseHealth--;
return;
}
} else {
var moveSpeed = self.speed * self.slowEffect;
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
}
};
return self;
});
var Tower = Container.expand(function (type) {
var self = Container.call(this);
// Tower configurations
var towerConfig = {
basic: {
asset: 'basicTower',
damage: 25,
range: 180,
fireRate: 60,
cost: 50,
upgradeCost: 75
},
splash: {
asset: 'splashTower',
damage: 40,
range: 150,
fireRate: 90,
cost: 100,
upgradeCost: 150,
splashRadius: 80
},
slow: {
asset: 'slowTower',
damage: 15,
range: 200,
fireRate: 45,
cost: 75,
upgradeCost: 100,
slowFactor: 0.5,
slowDuration: 120
}
};
var config = towerConfig[type] || towerConfig.basic;
var towerGraphics = self.attachAsset(config.asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.damage = config.damage;
self.range = config.range;
self.fireRate = config.fireRate;
self.cost = config.cost;
self.upgradeCost = config.upgradeCost;
self.splashRadius = config.splashRadius;
self.slowFactor = config.slowFactor;
self.slowDuration = config.slowDuration;
self.lastShot = 0;
self.level = 1;
// Range indicator (hidden by default)
var rangeIndicator = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.range / 50,
scaleY: self.range / 50
});
rangeIndicator.tint = 0x00FF00;
rangeIndicator.alpha = 0.2;
rangeIndicator.visible = false;
self.addChild(rangeIndicator);
self.rangeIndicator = rangeIndicator;
self.showRange = function () {
self.rangeIndicator.visible = true;
};
self.hideRange = function () {
self.rangeIndicator.visible = false;
};
self.canShoot = function () {
return LK.ticks - self.lastShot >= self.fireRate;
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = self.range;
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 && distance < closestDistance) {
closestEnemy = enemy;
closestDistance = distance;
}
}
return closestEnemy;
};
self.shoot = function (target) {
if (!self.canShoot()) return;
self.lastShot = LK.ticks;
// Create bullet
var bullet = new Bullet(self, target, self.type);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Rotate tower towards target
var angle = Math.atan2(target.y - self.y, target.x - self.x);
tween(towerGraphics, {
rotation: angle
}, {
duration: 200,
easing: tween.easeOut
});
};
self.upgrade = function () {
if (coins >= self.upgradeCost) {
coins -= self.upgradeCost;
self.level++;
self.damage = Math.floor(self.damage * 1.5);
self.range = Math.floor(self.range * 1.1);
self.upgradeCost = Math.floor(self.upgradeCost * 1.8);
// Visual upgrade effect
tween(towerGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(towerGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Update range indicator
self.rangeIndicator.scaleX = self.range / 50;
self.rangeIndicator.scaleY = self.range / 50;
return true;
}
return false;
};
self.down = function (x, y, obj) {
selectedTower = self;
self.showRange();
showTowerInfo(self);
};
self.update = function () {
var target = self.findTarget();
if (target) {
self.shoot(target);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d4a22
});
/****
* Game Code
****/
// Game variables
// Tower assets
// Enemy assets
// Game elements
// Sounds
var gamePath = [{
x: 100,
y: 400
}, {
x: 500,
y: 400
}, {
x: 500,
y: 800
}, {
x: 900,
y: 800
}, {
x: 900,
y: 1200
}, {
x: 1400,
y: 1200
}, {
x: 1400,
y: 1600
}, {
x: 1800,
y: 1600
}];
var enemies = [];
var towers = [];
var bullets = [];
var coins = 150;
var baseHealth = 20;
var currentWave = 1;
var enemiesSpawned = 0;
var enemiesPerWave = 5;
var waveDelay = 0;
var selectedTower = null;
var towerInfoPanel = null;
// Draw path
for (var i = 0; i < gamePath.length; i++) {
var pathTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5
});
pathTile.x = gamePath[i].x;
pathTile.y = gamePath[i].y;
pathTile.alpha = 0.6;
game.addChild(pathTile);
}
// Create base
var base = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
base.x = gamePath[gamePath.length - 1].x;
base.y = gamePath[gamePath.length - 1].y;
game.addChild(base);
// UI Elements
var coinsText = new Text2('Coins: ' + coins, {
size: 60,
fill: 0xFFD700
});
coinsText.anchor.set(0, 0);
coinsText.x = 120;
coinsText.y = 50;
LK.gui.topLeft.addChild(coinsText);
var healthText = new Text2('Base Health: ' + baseHealth, {
size: 60,
fill: 0xFF0000
});
healthText.anchor.set(1, 0);
LK.gui.topRight.addChild(healthText);
var waveText = new Text2('Wave: ' + currentWave, {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
// Tower selection buttons
var basicTowerBtn = new Text2('Basic (50)', {
size: 50,
fill: 0x4444FF
});
basicTowerBtn.anchor.set(0, 1);
basicTowerBtn.x = 50;
LK.gui.bottomLeft.addChild(basicTowerBtn);
var splashTowerBtn = new Text2('Splash (100)', {
size: 50,
fill: 0xFF4444
});
splashTowerBtn.anchor.set(0, 1);
splashTowerBtn.x = 250;
LK.gui.bottomLeft.addChild(splashTowerBtn);
var slowTowerBtn = new Text2('Slow (75)', {
size: 50,
fill: 0x44FF44
});
slowTowerBtn.anchor.set(0, 1);
slowTowerBtn.x = 450;
LK.gui.bottomLeft.addChild(slowTowerBtn);
// Selected tower type
var selectedTowerType = 'basic';
// Helper functions
function updateUI() {
coinsText.setText('Coins: ' + coins);
healthText.setText('Base Health: ' + baseHealth);
waveText.setText('Wave: ' + currentWave);
// Update button colors based on affordability
basicTowerBtn.style.fill = coins >= 50 ? "#4444FF" : "#666666";
splashTowerBtn.style.fill = coins >= 100 ? "#FF4444" : "#666666";
slowTowerBtn.style.fill = coins >= 75 ? "#44FF44" : "#666666";
}
function canPlaceTower(x, y) {
// Check if position is not on path
for (var i = 0; i < gamePath.length; i++) {
var pathPoint = gamePath[i];
var distance = Math.sqrt((x - pathPoint.x) * (x - pathPoint.x) + (y - pathPoint.y) * (y - pathPoint.y));
if (distance < 80) {
return false;
}
}
// Check if position is not too close to other towers
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
var distance = Math.sqrt((x - tower.x) * (x - tower.x) + (y - tower.y) * (y - tower.y));
if (distance < 100) {
return false;
}
}
return true;
}
function spawnEnemy() {
var enemyTypes = ['basic', 'fast', 'tank'];
var waveMultiplier = Math.floor((currentWave - 1) / 3);
// Choose enemy type based on wave
var enemyType = 'basic';
if (currentWave > 3) {
enemyType = enemyTypes[Math.floor(Math.random() * 2)]; // basic or fast
}
if (currentWave > 6) {
enemyType = enemyTypes[Math.floor(Math.random() * 3)]; // all types
}
var enemy = new Enemy(enemyType, 0);
enemy.x = gamePath[0].x;
enemy.y = gamePath[0].y;
// Scale health for later waves
enemy.maxHealth *= 1 + waveMultiplier * 0.5;
enemy.health = enemy.maxHealth;
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function showTowerInfo(tower) {
if (towerInfoPanel) {
towerInfoPanel.destroy();
}
var panel = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1.5
});
panel.tint = 0x333333;
panel.alpha = 0.8;
panel.x = tower.x;
panel.y = tower.y - 150;
game.addChild(panel);
towerInfoPanel = panel;
var infoText = new Text2('Level: ' + tower.level + '\nDamage: ' + tower.damage + '\nUpgrade: ' + tower.upgradeCost, {
size: 30,
fill: 0xFFFFFF
});
infoText.anchor.set(0.5, 0.5);
infoText.x = 0;
infoText.y = -20;
panel.addChild(infoText);
if (coins >= tower.upgradeCost) {
var upgradeBtn = new Text2('UPGRADE', {
size: 35,
fill: 0x00FF00
});
upgradeBtn.anchor.set(0.5, 0.5);
upgradeBtn.y = 30;
panel.addChild(upgradeBtn);
}
}
// Event handlers
basicTowerBtn.down = function () {
selectedTowerType = 'basic';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
if (towerInfoPanel) {
towerInfoPanel.destroy();
towerInfoPanel = null;
}
};
splashTowerBtn.down = function () {
selectedTowerType = 'splash';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
if (towerInfoPanel) {
towerInfoPanel.destroy();
towerInfoPanel = null;
}
};
slowTowerBtn.down = function () {
selectedTowerType = 'slow';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
if (towerInfoPanel) {
towerInfoPanel.destroy();
towerInfoPanel = null;
}
};
game.down = function (x, y, obj) {
// Check if clicking on upgrade button
if (towerInfoPanel && selectedTower) {
var localPos = towerInfoPanel.toLocal(obj.position);
if (Math.abs(localPos.x) < 60 && Math.abs(localPos.y - 30) < 20 && coins >= selectedTower.upgradeCost) {
selectedTower.upgrade();
showTowerInfo(selectedTower);
return;
}
}
// Hide tower info if clicking elsewhere
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
if (towerInfoPanel) {
towerInfoPanel.destroy();
towerInfoPanel = null;
}
// Try to place tower
var towerCost = selectedTowerType === 'basic' ? 50 : selectedTowerType === 'splash' ? 100 : 75;
if (coins >= towerCost && canPlaceTower(x, y)) {
var tower = new Tower(selectedTowerType);
tower.x = x;
tower.y = y;
towers.push(tower);
game.addChild(tower);
coins -= towerCost;
LK.getSound('place').play();
}
};
// Main game loop
game.update = function () {
// Spawn enemies
if (waveDelay <= 0 && enemiesSpawned < enemiesPerWave * currentWave) {
spawnEnemy();
waveDelay = 60; // 1 second between spawns
} else {
waveDelay--;
}
// Check wave completion
if (enemiesSpawned >= enemiesPerWave * currentWave && enemies.length === 0) {
currentWave++;
enemiesSpawned = 0;
coins += 25 * currentWave; // Bonus coins for completing wave
waveDelay = 180; // 3 second break between waves
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.pathIndex >= gamePath.length - 1) {
// Enemy reached base
baseHealth--;
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update towers
for (var i = 0; i < towers.length; i++) {
towers[i].update();
}
// Update bullets
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
// Check game over
if (baseHealth <= 0) {
LK.setScore(currentWave - 1);
LK.showGameOver();
}
// Update UI
updateUI();
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,673 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Bullet = Container.expand(function (tower, target, towerType) {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.tower = tower;
+ self.target = target;
+ self.towerType = towerType;
+ self.speed = 8;
+ // Calculate direction
+ var dx = target.x - self.x;
+ var dy = target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ self.vx = dx / distance * self.speed;
+ self.vy = dy / distance * self.speed;
+ self.update = function () {
+ self.x += self.vx;
+ self.y += self.vy;
+ // Check collision with target
+ if (self.target && self.intersects(self.target)) {
+ self.hit();
+ return;
+ }
+ // Remove if off screen
+ if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
+ self.destroy();
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ if (bullets[i] === self) {
+ bullets.splice(i, 1);
+ break;
+ }
+ }
+ }
+ };
+ self.hit = function () {
+ LK.getSound('hit').play();
+ if (self.towerType === 'splash') {
+ // Splash damage
+ 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.tower.splashRadius) {
+ var killed = enemy.takeDamage(self.tower.damage);
+ if (killed) {
+ coins += enemy.reward;
+ enemy.destroy();
+ enemies.splice(enemies.indexOf(enemy), 1);
+ }
+ }
+ }
+ // Create explosion effect
+ var explosion = LK.getAsset('explosion', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ explosion.x = self.x;
+ explosion.y = self.y;
+ explosion.alpha = 0.7;
+ game.addChild(explosion);
+ tween(explosion, {
+ scaleX: 2,
+ scaleY: 2,
+ alpha: 0
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ explosion.destroy();
+ }
+ });
+ } else {
+ // Regular damage
+ var killed = self.target.takeDamage(self.tower.damage);
+ if (killed) {
+ coins += self.target.reward;
+ self.target.destroy();
+ enemies.splice(enemies.indexOf(self.target), 1);
+ }
+ // Apply slow effect if slow tower
+ if (self.towerType === 'slow' && !killed) {
+ self.target.applySlow(self.tower.slowFactor, self.tower.slowDuration);
+ }
+ }
+ // Remove bullet
+ self.destroy();
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ if (bullets[i] === self) {
+ bullets.splice(i, 1);
+ break;
+ }
+ }
+ };
+ return self;
+});
+// Game variables
+var Enemy = Container.expand(function (type, pathIndex) {
+ var self = Container.call(this);
+ // Enemy properties based on type
+ var enemyConfig = {
+ basic: {
+ asset: 'basicEnemy',
+ health: 100,
+ speed: 2,
+ reward: 10
+ },
+ fast: {
+ asset: 'fastEnemy',
+ health: 60,
+ speed: 4,
+ reward: 15
+ },
+ tank: {
+ asset: 'tankEnemy',
+ health: 300,
+ speed: 1,
+ reward: 25
+ }
+ };
+ var config = enemyConfig[type] || enemyConfig.basic;
+ var enemyGraphics = self.attachAsset(config.asset, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.maxHealth = config.health;
+ self.health = config.health;
+ self.speed = config.speed;
+ self.reward = config.reward;
+ self.pathIndex = pathIndex || 0;
+ self.slowEffect = 1;
+ self.slowDuration = 0;
+ // Health bar
+ var healthBarBg = LK.getAsset('pathTile', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.6,
+ scaleY: 0.1,
+ y: -40
+ });
+ healthBarBg.tint = 0x333333;
+ self.addChild(healthBarBg);
+ var healthBar = LK.getAsset('pathTile', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.6,
+ scaleY: 0.1,
+ y: -40
+ });
+ healthBar.tint = 0x00FF00;
+ self.addChild(healthBar);
+ self.healthBar = healthBar;
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ var healthPercent = Math.max(0, self.health / self.maxHealth);
+ self.healthBar.scaleX = 0.6 * healthPercent;
+ // Health bar color changes
+ if (healthPercent > 0.6) {
+ self.healthBar.tint = 0x00FF00;
+ } else if (healthPercent > 0.3) {
+ self.healthBar.tint = 0xFFFF00;
+ } else {
+ self.healthBar.tint = 0xFF0000;
+ }
+ // Flash effect
+ tween(enemyGraphics, {
+ tint: 0xFF0000
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ tween(enemyGraphics, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 100
+ });
+ }
+ });
+ return self.health <= 0;
+ };
+ self.applySlow = function (factor, duration) {
+ self.slowEffect = Math.min(self.slowEffect, factor);
+ self.slowDuration = Math.max(self.slowDuration, duration);
+ };
+ self.update = function () {
+ // Update slow effect
+ if (self.slowDuration > 0) {
+ self.slowDuration--;
+ if (self.slowDuration <= 0) {
+ self.slowEffect = 1;
+ }
+ }
+ // Move along path
+ if (self.pathIndex < gamePath.length - 1) {
+ var currentTarget = gamePath[self.pathIndex + 1];
+ var dx = currentTarget.x - self.x;
+ var dy = currentTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 20) {
+ self.pathIndex++;
+ if (self.pathIndex >= gamePath.length - 1) {
+ // Reached base
+ baseHealth--;
+ return;
+ }
+ } else {
+ var moveSpeed = self.speed * self.slowEffect;
+ self.x += dx / distance * moveSpeed;
+ self.y += dy / distance * moveSpeed;
+ }
+ }
+ };
+ return self;
+});
+var Tower = Container.expand(function (type) {
+ var self = Container.call(this);
+ // Tower configurations
+ var towerConfig = {
+ basic: {
+ asset: 'basicTower',
+ damage: 25,
+ range: 180,
+ fireRate: 60,
+ cost: 50,
+ upgradeCost: 75
+ },
+ splash: {
+ asset: 'splashTower',
+ damage: 40,
+ range: 150,
+ fireRate: 90,
+ cost: 100,
+ upgradeCost: 150,
+ splashRadius: 80
+ },
+ slow: {
+ asset: 'slowTower',
+ damage: 15,
+ range: 200,
+ fireRate: 45,
+ cost: 75,
+ upgradeCost: 100,
+ slowFactor: 0.5,
+ slowDuration: 120
+ }
+ };
+ var config = towerConfig[type] || towerConfig.basic;
+ var towerGraphics = self.attachAsset(config.asset, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.type = type;
+ self.damage = config.damage;
+ self.range = config.range;
+ self.fireRate = config.fireRate;
+ self.cost = config.cost;
+ self.upgradeCost = config.upgradeCost;
+ self.splashRadius = config.splashRadius;
+ self.slowFactor = config.slowFactor;
+ self.slowDuration = config.slowDuration;
+ self.lastShot = 0;
+ self.level = 1;
+ // Range indicator (hidden by default)
+ var rangeIndicator = LK.getAsset('pathTile', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: self.range / 50,
+ scaleY: self.range / 50
+ });
+ rangeIndicator.tint = 0x00FF00;
+ rangeIndicator.alpha = 0.2;
+ rangeIndicator.visible = false;
+ self.addChild(rangeIndicator);
+ self.rangeIndicator = rangeIndicator;
+ self.showRange = function () {
+ self.rangeIndicator.visible = true;
+ };
+ self.hideRange = function () {
+ self.rangeIndicator.visible = false;
+ };
+ self.canShoot = function () {
+ return LK.ticks - self.lastShot >= self.fireRate;
+ };
+ self.findTarget = function () {
+ var closestEnemy = null;
+ var closestDistance = self.range;
+ 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 && distance < closestDistance) {
+ closestEnemy = enemy;
+ closestDistance = distance;
+ }
+ }
+ return closestEnemy;
+ };
+ self.shoot = function (target) {
+ if (!self.canShoot()) return;
+ self.lastShot = LK.ticks;
+ // Create bullet
+ var bullet = new Bullet(self, target, self.type);
+ bullet.x = self.x;
+ bullet.y = self.y;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ LK.getSound('shoot').play();
+ // Rotate tower towards target
+ var angle = Math.atan2(target.y - self.y, target.x - self.x);
+ tween(towerGraphics, {
+ rotation: angle
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ };
+ self.upgrade = function () {
+ if (coins >= self.upgradeCost) {
+ coins -= self.upgradeCost;
+ self.level++;
+ self.damage = Math.floor(self.damage * 1.5);
+ self.range = Math.floor(self.range * 1.1);
+ self.upgradeCost = Math.floor(self.upgradeCost * 1.8);
+ // Visual upgrade effect
+ tween(towerGraphics, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ tween(towerGraphics, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200
+ });
+ }
+ });
+ // Update range indicator
+ self.rangeIndicator.scaleX = self.range / 50;
+ self.rangeIndicator.scaleY = self.range / 50;
+ return true;
+ }
+ return false;
+ };
+ self.down = function (x, y, obj) {
+ selectedTower = self;
+ self.showRange();
+ showTowerInfo(self);
+ };
+ self.update = function () {
+ var target = self.findTarget();
+ if (target) {
+ self.shoot(target);
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2d4a22
+});
+
+/****
+* Game Code
+****/
+// Game variables
+// Tower assets
+// Enemy assets
+// Game elements
+// Sounds
+var gamePath = [{
+ x: 100,
+ y: 400
+}, {
+ x: 500,
+ y: 400
+}, {
+ x: 500,
+ y: 800
+}, {
+ x: 900,
+ y: 800
+}, {
+ x: 900,
+ y: 1200
+}, {
+ x: 1400,
+ y: 1200
+}, {
+ x: 1400,
+ y: 1600
+}, {
+ x: 1800,
+ y: 1600
+}];
+var enemies = [];
+var towers = [];
+var bullets = [];
+var coins = 150;
+var baseHealth = 20;
+var currentWave = 1;
+var enemiesSpawned = 0;
+var enemiesPerWave = 5;
+var waveDelay = 0;
+var selectedTower = null;
+var towerInfoPanel = null;
+// Draw path
+for (var i = 0; i < gamePath.length; i++) {
+ var pathTile = LK.getAsset('pathTile', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ pathTile.x = gamePath[i].x;
+ pathTile.y = gamePath[i].y;
+ pathTile.alpha = 0.6;
+ game.addChild(pathTile);
+}
+// Create base
+var base = LK.getAsset('base', {
+ anchorX: 0.5,
+ anchorY: 0.5
+});
+base.x = gamePath[gamePath.length - 1].x;
+base.y = gamePath[gamePath.length - 1].y;
+game.addChild(base);
+// UI Elements
+var coinsText = new Text2('Coins: ' + coins, {
+ size: 60,
+ fill: 0xFFD700
+});
+coinsText.anchor.set(0, 0);
+coinsText.x = 120;
+coinsText.y = 50;
+LK.gui.topLeft.addChild(coinsText);
+var healthText = new Text2('Base Health: ' + baseHealth, {
+ size: 60,
+ fill: 0xFF0000
+});
+healthText.anchor.set(1, 0);
+LK.gui.topRight.addChild(healthText);
+var waveText = new Text2('Wave: ' + currentWave, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+waveText.anchor.set(0.5, 0);
+LK.gui.top.addChild(waveText);
+// Tower selection buttons
+var basicTowerBtn = new Text2('Basic (50)', {
+ size: 50,
+ fill: 0x4444FF
+});
+basicTowerBtn.anchor.set(0, 1);
+basicTowerBtn.x = 50;
+LK.gui.bottomLeft.addChild(basicTowerBtn);
+var splashTowerBtn = new Text2('Splash (100)', {
+ size: 50,
+ fill: 0xFF4444
+});
+splashTowerBtn.anchor.set(0, 1);
+splashTowerBtn.x = 250;
+LK.gui.bottomLeft.addChild(splashTowerBtn);
+var slowTowerBtn = new Text2('Slow (75)', {
+ size: 50,
+ fill: 0x44FF44
+});
+slowTowerBtn.anchor.set(0, 1);
+slowTowerBtn.x = 450;
+LK.gui.bottomLeft.addChild(slowTowerBtn);
+// Selected tower type
+var selectedTowerType = 'basic';
+// Helper functions
+function updateUI() {
+ coinsText.setText('Coins: ' + coins);
+ healthText.setText('Base Health: ' + baseHealth);
+ waveText.setText('Wave: ' + currentWave);
+ // Update button colors based on affordability
+ basicTowerBtn.style.fill = coins >= 50 ? "#4444FF" : "#666666";
+ splashTowerBtn.style.fill = coins >= 100 ? "#FF4444" : "#666666";
+ slowTowerBtn.style.fill = coins >= 75 ? "#44FF44" : "#666666";
+}
+function canPlaceTower(x, y) {
+ // Check if position is not on path
+ for (var i = 0; i < gamePath.length; i++) {
+ var pathPoint = gamePath[i];
+ var distance = Math.sqrt((x - pathPoint.x) * (x - pathPoint.x) + (y - pathPoint.y) * (y - pathPoint.y));
+ if (distance < 80) {
+ return false;
+ }
+ }
+ // Check if position is not too close to other towers
+ for (var i = 0; i < towers.length; i++) {
+ var tower = towers[i];
+ var distance = Math.sqrt((x - tower.x) * (x - tower.x) + (y - tower.y) * (y - tower.y));
+ if (distance < 100) {
+ return false;
+ }
+ }
+ return true;
+}
+function spawnEnemy() {
+ var enemyTypes = ['basic', 'fast', 'tank'];
+ var waveMultiplier = Math.floor((currentWave - 1) / 3);
+ // Choose enemy type based on wave
+ var enemyType = 'basic';
+ if (currentWave > 3) {
+ enemyType = enemyTypes[Math.floor(Math.random() * 2)]; // basic or fast
+ }
+ if (currentWave > 6) {
+ enemyType = enemyTypes[Math.floor(Math.random() * 3)]; // all types
+ }
+ var enemy = new Enemy(enemyType, 0);
+ enemy.x = gamePath[0].x;
+ enemy.y = gamePath[0].y;
+ // Scale health for later waves
+ enemy.maxHealth *= 1 + waveMultiplier * 0.5;
+ enemy.health = enemy.maxHealth;
+ enemies.push(enemy);
+ game.addChild(enemy);
+ enemiesSpawned++;
+}
+function showTowerInfo(tower) {
+ if (towerInfoPanel) {
+ towerInfoPanel.destroy();
+ }
+ var panel = LK.getAsset('base', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 2,
+ scaleY: 1.5
+ });
+ panel.tint = 0x333333;
+ panel.alpha = 0.8;
+ panel.x = tower.x;
+ panel.y = tower.y - 150;
+ game.addChild(panel);
+ towerInfoPanel = panel;
+ var infoText = new Text2('Level: ' + tower.level + '\nDamage: ' + tower.damage + '\nUpgrade: ' + tower.upgradeCost, {
+ size: 30,
+ fill: 0xFFFFFF
+ });
+ infoText.anchor.set(0.5, 0.5);
+ infoText.x = 0;
+ infoText.y = -20;
+ panel.addChild(infoText);
+ if (coins >= tower.upgradeCost) {
+ var upgradeBtn = new Text2('UPGRADE', {
+ size: 35,
+ fill: 0x00FF00
+ });
+ upgradeBtn.anchor.set(0.5, 0.5);
+ upgradeBtn.y = 30;
+ panel.addChild(upgradeBtn);
+ }
+}
+// Event handlers
+basicTowerBtn.down = function () {
+ selectedTowerType = 'basic';
+ if (selectedTower) {
+ selectedTower.hideRange();
+ selectedTower = null;
+ }
+ if (towerInfoPanel) {
+ towerInfoPanel.destroy();
+ towerInfoPanel = null;
+ }
+};
+splashTowerBtn.down = function () {
+ selectedTowerType = 'splash';
+ if (selectedTower) {
+ selectedTower.hideRange();
+ selectedTower = null;
+ }
+ if (towerInfoPanel) {
+ towerInfoPanel.destroy();
+ towerInfoPanel = null;
+ }
+};
+slowTowerBtn.down = function () {
+ selectedTowerType = 'slow';
+ if (selectedTower) {
+ selectedTower.hideRange();
+ selectedTower = null;
+ }
+ if (towerInfoPanel) {
+ towerInfoPanel.destroy();
+ towerInfoPanel = null;
+ }
+};
+game.down = function (x, y, obj) {
+ // Check if clicking on upgrade button
+ if (towerInfoPanel && selectedTower) {
+ var localPos = towerInfoPanel.toLocal(obj.position);
+ if (Math.abs(localPos.x) < 60 && Math.abs(localPos.y - 30) < 20 && coins >= selectedTower.upgradeCost) {
+ selectedTower.upgrade();
+ showTowerInfo(selectedTower);
+ return;
+ }
+ }
+ // Hide tower info if clicking elsewhere
+ if (selectedTower) {
+ selectedTower.hideRange();
+ selectedTower = null;
+ }
+ if (towerInfoPanel) {
+ towerInfoPanel.destroy();
+ towerInfoPanel = null;
+ }
+ // Try to place tower
+ var towerCost = selectedTowerType === 'basic' ? 50 : selectedTowerType === 'splash' ? 100 : 75;
+ if (coins >= towerCost && canPlaceTower(x, y)) {
+ var tower = new Tower(selectedTowerType);
+ tower.x = x;
+ tower.y = y;
+ towers.push(tower);
+ game.addChild(tower);
+ coins -= towerCost;
+ LK.getSound('place').play();
+ }
+};
+// Main game loop
+game.update = function () {
+ // Spawn enemies
+ if (waveDelay <= 0 && enemiesSpawned < enemiesPerWave * currentWave) {
+ spawnEnemy();
+ waveDelay = 60; // 1 second between spawns
+ } else {
+ waveDelay--;
+ }
+ // Check wave completion
+ if (enemiesSpawned >= enemiesPerWave * currentWave && enemies.length === 0) {
+ currentWave++;
+ enemiesSpawned = 0;
+ coins += 25 * currentWave; // Bonus coins for completing wave
+ waveDelay = 180; // 3 second break between waves
+ }
+ // Update enemies
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ if (enemy.pathIndex >= gamePath.length - 1) {
+ // Enemy reached base
+ baseHealth--;
+ enemy.destroy();
+ enemies.splice(i, 1);
+ }
+ }
+ // Update towers
+ for (var i = 0; i < towers.length; i++) {
+ towers[i].update();
+ }
+ // Update bullets
+ for (var i = 0; i < bullets.length; i++) {
+ bullets[i].update();
+ }
+ // Check game over
+ if (baseHealth <= 0) {
+ LK.setScore(currentWave - 1);
+ LK.showGameOver();
+ }
+ // Update UI
+ updateUI();
+};
\ No newline at end of file