User prompt
that only basic enemies can appear in the first wave.
User prompt
golden enemies to have 50 health
User prompt
the basic turret does 15 damage
User prompt
The life of the enemies is expressed in a number.
User prompt
that the basic towers only fire one bullet
User prompt
once the wave has started, you can no longer place any towers until the end of the wave.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'reload')' in or related to this line: 'location.reload();' Line Number: 786
User prompt
basic enemies have a little more life.
User prompt
killing the basic enemies will give you 5 coins ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
that at the end of the wave you get a message that you have passed the wave. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
that at the start of the wave a message is displayed that the wave has started ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the charcwater appears after 10 shots from the splash tower
User prompt
the charcwater lasts on the ground for 5 seconds and all enemies passing over it will take some damage. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
that the splash tower leaves the asset watercharc when firing that does damage
User prompt
that the game over menu is more decorated and colourful.
User prompt
the price of the splash tower to be raised to 130 coins
User prompt
when the pause button is pressed, a button to exit the game should appear
User prompt
that there is a pause menu with a button to exit the game and one to remove or activate the music.
User prompt
Please fix the bug: 'Cannot set properties of null (setting 'down')' in or related to this line: 'pauseButton.down = function () {' Line Number: 789
User prompt
there should be a pause menu to restart the game, exit the game and remove music.
User prompt
when firing the splash tower, the bullet that fires is the asset waterball.
User prompt
music to play louder
User prompt
music to play louder
User prompt
that there be quiet music
User prompt
the buttons to choose the tower should have an animation when you put them on ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (damage, target, assetType) {
var self = Container.call(this);
var bulletAsset = assetType || 'bullet';
var bulletGraphics = self.attachAsset(bulletAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = damage || 10;
self.target = target;
self.speed = 8;
self.update = function () {
if (!self.target || !self.target.parent) {
self.destroy();
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 < 10) {
self.target.takeDamage(self.damage);
// If this is a splash bullet, create persistent water damage area
if (self.isSplash) {
// Apply initial splash damage to nearby enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var splashDx = enemy.x - self.target.x;
var splashDy = enemy.y - self.target.y;
var splashDistance = Math.sqrt(splashDx * splashDx + splashDy * splashDy);
if (splashDistance <= 80 && enemy !== self.target) {
enemy.takeDamage(Math.floor(self.damage * 0.5)); // Half damage for splash
}
}
// Only create persistent water damage area if flag is set (after 10 shots)
if (self.createWaterDamage) {
var waterDamage = new WaterDamage(self.target.x, self.target.y, Math.floor(self.damage * 0.3));
waterDamageAreas.push(waterDamage);
game.addChild(waterDamage);
}
}
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
};
return self;
});
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
self.enemyType = enemyType || 'basic';
self.pathIndex = 0;
self.health = 30;
self.maxHealth = 30;
self.speed = 2;
self.reward = 10;
self.slowed = false;
self.slowDuration = 0;
var enemyGraphics;
if (self.enemyType === 'basic') {
enemyGraphics = self.attachAsset('basicEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 30;
self.maxHealth = 30;
self.speed = 2;
self.reward = 10;
} else if (self.enemyType === 'fast') {
enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 15;
self.maxHealth = 15;
self.speed = 4;
self.reward = 15;
} else if (self.enemyType === 'tank') {
enemyGraphics = self.attachAsset('tankEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 60;
self.maxHealth = 60;
self.speed = 1;
self.reward = 25;
} else if (self.enemyType === 'gold') {
enemyGraphics = self.attachAsset('goldEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 50;
self.maxHealth = 50;
self.speed = 3;
self.reward = 100; // High reward!
}
// Create health bar background
var healthBarBg = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.1
});
healthBarBg.y = -enemyGraphics.height / 2 - 20;
healthBarBg.tint = 0x000000;
self.addChild(healthBarBg);
// Create health bar foreground
var healthBarFg = LK.getAsset('grassTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.1
});
healthBarFg.y = -enemyGraphics.height / 2 - 20;
healthBarFg.tint = 0x00FF00;
self.addChild(healthBarFg);
// Create health text to display current health as number
var healthText = new Text2(self.health.toString(), {
size: 30,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0.5);
healthText.y = -enemyGraphics.height / 2 - 20;
self.addChild(healthText);
self.healthBarBg = healthBarBg;
self.healthBarFg = healthBarFg;
self.healthText = healthText;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFg.scaleX = 0.4 * healthPercent;
// Update health text to show current health number
self.healthText.setText(Math.max(0, self.health).toString());
// Change color based on health
if (healthPercent > 0.6) {
self.healthBarFg.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBarFg.tint = 0xFFFF00; // Yellow
} else {
self.healthBarFg.tint = 0xFF0000; // Red
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Calculate bonus multiplier based on kill streak
var bonusMultiplier = 1;
if (killStreak >= 10) bonusMultiplier = 2;else if (killStreak >= 5) bonusMultiplier = 1.5;
// Basic enemies give 5 coins, others use their reward value
var coinReward = self.enemyType === 'basic' ? 5 : self.reward;
coins += Math.floor(coinReward * bonusMultiplier);
enemiesKilled++;
killStreak++;
LK.getSound('enemyDeath').play();
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
updateUI();
};
self.update = function () {
if (self.slowed) {
self.slowDuration--;
if (self.slowDuration <= 0) {
self.slowed = false;
}
}
if (self.pathIndex >= pathPoints.length - 1) {
// Game over immediately when any enemy reaches the end
showCustomGameOver();
return;
}
var currentSpeed = self.slowed ? self.speed * 0.5 : self.speed;
var target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * currentSpeed;
self.y += Math.sin(angle) * currentSpeed;
}
};
// Initialize health bar display
self.updateHealthBar();
return self;
});
var Tower = Container.expand(function (towerType) {
var self = Container.call(this);
self.towerType = towerType || 'basic';
self.level = 1;
self.range = 120;
self.damage = 10;
self.fireRate = 60;
self.cost = 50;
self.upgradeCost = 30;
self.lastShot = 0;
self.shotCount = 0; // Track number of shots for splash tower
var towerGraphics;
if (self.towerType === 'basic') {
towerGraphics = self.attachAsset('basicTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 15;
self.range = 120;
self.fireRate = 60;
self.cost = 50;
} else if (self.towerType === 'splash') {
towerGraphics = self.attachAsset('splashTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 15;
self.range = 100;
self.fireRate = 90;
self.cost = 130;
} else if (self.towerType === 'slow') {
towerGraphics = self.attachAsset('slowTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 5;
self.range = 140;
self.fireRate = 30;
self.cost = 70;
} else if (self.towerType === 'sniper') {
towerGraphics = self.attachAsset('sniperTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 40;
self.range = 200;
self.fireRate = 120;
self.cost = 120;
}
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;
if (self.towerType === 'basic') {
// Fire single bullet for basic tower
var bullet = new Bullet(self.damage, target);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
} else if (self.towerType === 'splash') {
// Splash tower fires waterball bullets and leaves watercharc damage
var bullet = new Bullet(self.damage, target, 'waterball');
bullet.x = self.x;
bullet.y = self.y;
bullet.isSplash = true; // Mark as splash bullet
self.shotCount++; // Increment shot counter
// Only create water damage after 10 shots
if (self.shotCount >= 10) {
bullet.createWaterDamage = true;
self.shotCount = 0; // Reset counter
}
bullets.push(bullet);
game.addChild(bullet);
} else {
// Other tower types fire single bullet
var bullet = new Bullet(self.damage, target);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
}
self.lastShot = LK.ticks;
LK.getSound('shoot').play();
};
self.upgrade = function () {
if (coins >= self.upgradeCost && self.level < 3) {
coins -= self.upgradeCost;
self.level++;
self.damage = Math.floor(self.damage * 1.5);
self.range += 20;
self.upgradeCost = Math.floor(self.upgradeCost * 1.5);
updateUI();
}
};
self.update = function () {
var target = self.findTarget();
if (target) {
self.shoot(target);
}
};
self.down = function (x, y, obj) {
selectedTower = self;
showTowerMenu = true;
updateUI();
};
return self;
});
var WaterDamage = Container.expand(function (x, y, damage) {
var self = Container.call(this);
var waterGraphics = self.attachAsset('watercharc', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.damage = damage || 5; // Damage per tick
self.radius = 80; // Damage radius
self.lifetime = 300; // 5 seconds at 60fps
self.damageInterval = 30; // Damage every 0.5 seconds
self.lastDamageTick = 0;
waterGraphics.alpha = 0.7;
waterGraphics.tint = 0x00AAFF;
// Animate the water area appearance
waterGraphics.scaleX = 0.5;
waterGraphics.scaleY = 0.5;
tween(waterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
self.update = function () {
self.lifetime--;
// Apply damage to enemies in range at intervals
if (LK.ticks - self.lastDamageTick >= self.damageInterval) {
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.radius) {
enemy.takeDamage(self.damage);
}
}
self.lastDamageTick = LK.ticks;
}
// Fade out as lifetime decreases
if (self.lifetime < 60) {
// Start fading in last second
waterGraphics.alpha = 0.7 * (self.lifetime / 60);
}
// Remove when lifetime expires
if (self.lifetime <= 0) {
self.destroy();
// Remove from waterDamageAreas array
for (var j = waterDamageAreas.length - 1; j >= 0; j--) {
if (waterDamageAreas[j] === self) {
waterDamageAreas.splice(j, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
var gridSize = 100;
var gridWidth = 20;
var gridHeight = 27;
var pathPoints = [{
x: 0,
y: 400
}, {
x: 300,
y: 400
}, {
x: 300,
y: 800
}, {
x: 700,
y: 800
}, {
x: 700,
y: 1200
}, {
x: 1100,
y: 1200
}, {
x: 1100,
y: 1600
}, {
x: 1500,
y: 1600
}, {
x: 1500,
y: 2000
}, {
x: 2048,
y: 2000
}];
var gameGrid = [];
var towers = [];
var enemies = [];
var bullets = [];
var waterDamageAreas = [];
var coins = 100;
var lives = 20;
var wave = 1;
var enemiesKilled = 0;
var killStreak = 0;
var lastLives = 20;
var enemiesSpawned = 0;
var enemiesPerWave = 10;
var spawnTimer = 0;
var waveInProgress = false;
var selectedTower = null;
var showTowerMenu = false;
var towerMenuButtons = [];
// Create grid
for (var y = 0; y < gridHeight; y++) {
gameGrid[y] = [];
for (var x = 0; x < gridWidth; x++) {
gameGrid[y][x] = {
x: x * gridSize + 50,
y: y * gridSize + 50,
occupied: false,
isPath: false
};
}
}
// Mark path tiles
for (var i = 0; i < pathPoints.length - 1; i++) {
var start = pathPoints[i];
var end = pathPoints[i + 1];
var steps = Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / gridSize;
for (var step = 0; step <= steps; step++) {
var x = Math.floor((start.x + (end.x - start.x) * step / steps) / gridSize);
var y = Math.floor((start.y + (end.y - start.y) * step / steps) / gridSize);
if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) {
gameGrid[y][x].isPath = true;
}
}
}
// Create visual grid
for (var y = 0; y < gridHeight; y++) {
for (var x = 0; x < gridWidth; x++) {
var tile;
if (gameGrid[y][x].isPath) {
tile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
tile = LK.getAsset('grassTile', {
anchorX: 0.5,
anchorY: 0.5
});
}
tile.x = gameGrid[y][x].x;
tile.y = gameGrid[y][x].y;
tile.alpha = 0.3;
game.addChild(tile);
}
}
// UI Elements
var coinsText = new Text2('Coins: ' + coins, {
size: 60,
fill: 0xFFD700
});
coinsText.anchor.set(1, 0);
LK.gui.topRight.addChild(coinsText);
var livesText = new Text2('Lives: ' + lives, {
size: 50,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.topRight.addChild(livesText);
var waveText = new Text2('Wave: ' + wave, {
size: 50,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var startWaveButton = new Text2('🚀 START WAVE 🚀', {
size: 80,
fill: 0x00FF00
});
startWaveButton.anchor.set(0.5, 1);
LK.gui.bottom.addChild(startWaveButton);
// Add colorful tween animation to make it more eye-catching
function animateStartButton() {
tween(startWaveButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
onFinish: function onFinish() {
tween(startWaveButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
onFinish: animateStartButton
});
}
});
}
animateStartButton();
// Start playing background music with maximum volume
LK.playMusic('bgmusic', {
volume: 1.0
});
// Tower selection buttons
var basicTowerButton = new Text2('Basic ($50)', {
size: 40,
fill: 0xFFFFFF
});
basicTowerButton.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(basicTowerButton);
var splashTowerButton = new Text2('Splash ($130)', {
size: 40,
fill: 0xFFFFFF
});
splashTowerButton.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(splashTowerButton);
var slowTowerButton = new Text2('Slow ($70)', {
size: 40,
fill: 0xFFFFFF
});
slowTowerButton.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(slowTowerButton);
var sniperTowerButton = new Text2('Sniper ($120)', {
size: 40,
fill: 0xFFFFFF
});
sniperTowerButton.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(sniperTowerButton);
// Position tower buttons
basicTowerButton.y = -200;
splashTowerButton.y = -150;
slowTowerButton.y = -100;
sniperTowerButton.y = -50;
coinsText.y = 50;
livesText.y = 100;
var selectedTowerType = 'basic';
var isPaused = false;
var pauseMenu = null;
var pauseButton = null;
var restartButton = null;
var exitButton = null;
var musicButton = null;
var musicEnabled = true;
var gameOverMenu = null;
function showCustomGameOver() {
if (gameOverMenu) return; // Already showing
isPaused = true;
// Create game over menu container
gameOverMenu = new Container();
// Create animated background with gradient effect
var background1 = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 45
});
background1.tint = 0x1a1a2e;
background1.alpha = 0.95;
background1.x = 1024;
background1.y = 1366;
gameOverMenu.addChild(background1);
// Create decorative border elements
var borderTop = LK.getAsset('grassTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 30,
scaleY: 1
});
borderTop.tint = 0xe74c3c;
borderTop.x = 1024;
borderTop.y = 300;
gameOverMenu.addChild(borderTop);
var borderBottom = LK.getAsset('grassTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 30,
scaleY: 1
});
borderBottom.tint = 0xe74c3c;
borderBottom.x = 1024;
borderBottom.y = 2400;
gameOverMenu.addChild(borderBottom);
// Create large "GAME OVER" title with shadow effect
var shadowText = new Text2('GAME OVER', {
size: 140,
fill: 0x000000
});
shadowText.anchor.set(0.5, 0.5);
shadowText.x = 1029; // Slight offset for shadow
shadowText.y = 605;
gameOverMenu.addChild(shadowText);
var titleText = new Text2('GAME OVER', {
size: 140,
fill: 0xe74c3c
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
gameOverMenu.addChild(titleText);
// Create colorful stats display
var statsContainer = new Container();
// Stats background
var statsBg = LK.getAsset('slowTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 8
});
statsBg.tint = 0x16213e;
statsBg.alpha = 0.8;
statsBg.x = 1024;
statsBg.y = 1000;
statsContainer.addChild(statsBg);
// Wave reached text
var waveReachedText = new Text2('Wave Reached: ' + wave, {
size: 60,
fill: 0x3498db
});
waveReachedText.anchor.set(0.5, 0.5);
waveReachedText.x = 1024;
waveReachedText.y = 850;
statsContainer.addChild(waveReachedText);
// Enemies killed text
var killsText = new Text2('Enemies Defeated: ' + enemiesKilled, {
size: 60,
fill: 0x2ecc71
});
killsText.anchor.set(0.5, 0.5);
killsText.x = 1024;
killsText.y = 950;
statsContainer.addChild(killsText);
// Final score text
var finalScore = wave * 100 + enemiesKilled * 10;
var scoreText = new Text2('Final Score: ' + finalScore, {
size: 60,
fill: 0xf39c12
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 1024;
scoreText.y = 1050;
statsContainer.addChild(scoreText);
// Best streak text
var streakText = new Text2('Best Streak: ' + killStreak, {
size: 60,
fill: 0x9b59b6
});
streakText.anchor.set(0.5, 0.5);
streakText.x = 1024;
streakText.y = 1150;
statsContainer.addChild(streakText);
gameOverMenu.addChild(statsContainer);
// Create animated restart button with glow effect
var restartBg = LK.getAsset('basicTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
restartBg.tint = 0x27ae60;
restartBg.x = 1024;
restartBg.y = 1400;
gameOverMenu.addChild(restartBg);
var restartGameButton = new Text2('🔄 PLAY AGAIN', {
size: 70,
fill: 0xffffff
});
restartGameButton.anchor.set(0.5, 0.5);
restartGameButton.x = 1024;
restartGameButton.y = 1400;
gameOverMenu.addChild(restartGameButton);
// Create animated exit button
var exitBg = LK.getAsset('sniperTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
exitBg.tint = 0xc0392b;
exitBg.x = 1024;
exitBg.y = 1600;
gameOverMenu.addChild(exitBg);
var exitGameButton = new Text2('❌ EXIT GAME', {
size: 70,
fill: 0xffffff
});
exitGameButton.anchor.set(0.5, 0.5);
exitGameButton.x = 1024;
exitGameButton.y = 1600;
gameOverMenu.addChild(exitGameButton);
// Add floating decorative elements
for (var i = 0; i < 8; i++) {
var decoration = LK.getAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
decoration.tint = [0xe74c3c, 0x3498db, 0x2ecc71, 0xf39c12, 0x9b59b6][i % 5];
decoration.alpha = 0.6;
decoration.x = 200 + i * 225;
decoration.y = 400 + Math.sin(i) * 100;
gameOverMenu.addChild(decoration);
// Animate decorations
tween(decoration, {
y: decoration.y + 50,
rotation: Math.PI * 2
}, {
duration: 2000 + i * 200,
loop: true,
yoyo: true
});
}
// Add button event handlers
restartGameButton.down = function () {
tween(restartGameButton, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0x2ecc71
}, {
duration: 100,
onFinish: function onFinish() {
LK.showGameOver();
}
});
};
exitGameButton.down = function () {
tween(exitGameButton, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0xe74c3c
}, {
duration: 100,
onFinish: function onFinish() {
LK.showGameOver();
}
});
};
// Animate title text with pulsing effect
function animateTitle() {
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xff6b6b
}, {
duration: 1000,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xe74c3c
}, {
duration: 1000,
onFinish: animateTitle
});
}
});
}
animateTitle();
// Animate stats container entrance
statsContainer.alpha = 0;
statsContainer.scaleX = 0.5;
statsContainer.scaleY = 0.5;
tween(statsContainer, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
delay: 500
});
game.addChild(gameOverMenu);
}
// Create pause button in top right corner
pauseButton = new Text2('⏸', {
size: 60,
fill: 0xFFFFFF
});
pauseButton.anchor.set(0, 0);
pauseButton.x = 150; // Offset from top right to avoid overlap with coins
pauseButton.y = 0;
LK.gui.topRight.addChild(pauseButton);
function createPauseMenu() {
if (pauseMenu) return; // Already created
// Create semi-transparent background
pauseMenu = new Container();
var background = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 30,
scaleY: 40
});
background.tint = 0x000000;
background.alpha = 0.7;
background.x = 1024;
background.y = 1366;
pauseMenu.addChild(background);
// Create menu title
var titleText = new Text2('PAUSED', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
pauseMenu.addChild(titleText);
// Create restart button
restartButton = new Text2('RESTART', {
size: 60,
fill: 0x00FF00
});
restartButton.anchor.set(0.5, 0.5);
restartButton.x = 1024;
restartButton.y = 1000;
pauseMenu.addChild(restartButton);
// Create exit button
exitButton = new Text2('EXIT', {
size: 60,
fill: 0xFF0000
});
exitButton.anchor.set(0.5, 0.5);
exitButton.x = 1024;
exitButton.y = 1200;
pauseMenu.addChild(exitButton);
// Create music toggle button
musicButton = new Text2(musicEnabled ? 'MUSIC: ON' : 'MUSIC: OFF', {
size: 60,
fill: 0xFFFFFF
});
musicButton.tint = musicEnabled ? 0x00FFFF : 0x888888;
musicButton.anchor.set(0.5, 0.5);
musicButton.x = 1024;
musicButton.y = 1400;
pauseMenu.addChild(musicButton);
// Create resume button
var resumeButton = new Text2('RESUME', {
size: 60,
fill: 0xFFFF00
});
resumeButton.anchor.set(0.5, 0.5);
resumeButton.x = 1024;
resumeButton.y = 1600;
pauseMenu.addChild(resumeButton);
// Add event handlers
restartButton.down = function () {
LK.showGameOver(); // Restart the game
};
exitButton.down = function () {
showCustomGameOver(); // Exit to custom game over screen
};
musicButton.down = function () {
musicEnabled = !musicEnabled;
if (musicEnabled) {
LK.playMusic('bgmusic', {
volume: 1.0
});
musicButton.setText('MUSIC: ON');
musicButton.tint = 0x00FFFF;
} else {
LK.stopMusic();
musicButton.setText('MUSIC: OFF');
musicButton.tint = 0x888888;
}
};
resumeButton.down = function () {
togglePause();
};
game.addChild(pauseMenu);
}
function togglePause() {
isPaused = !isPaused;
if (isPaused) {
createPauseMenu();
pauseMenu.visible = true;
} else {
if (pauseMenu) {
pauseMenu.visible = false;
}
}
}
function showExitButton() {
isPaused = true;
if (!exitButton) {
// Create exit button if it doesn't exist
exitButton = new Text2('EXIT GAME', {
size: 60,
fill: 0xFF0000
});
exitButton.anchor.set(0.5, 0.5);
exitButton.x = 1024;
exitButton.y = 1366;
exitButton.down = function () {
showCustomGameOver(); // Exit to custom game over screen
};
game.addChild(exitButton);
} else {
exitButton.visible = true;
}
}
function updateUI() {
var coinDisplay = 'Coins: ' + coins;
if (killStreak >= 5) {
var multiplier = killStreak >= 10 ? '2x' : '1.5x';
coinDisplay += ' (Streak: ' + killStreak + ' - ' + multiplier + ' bonus!)';
}
coinsText.setText(coinDisplay);
livesText.setText('Lives: ' + lives);
waveText.setText('Wave: ' + wave);
if (showTowerMenu && selectedTower) {
// Show upgrade option
}
}
function getGridPosition(x, y) {
var gridX = Math.floor(x / gridSize);
var gridY = Math.floor(y / gridSize);
if (gridX >= 0 && gridX < gridWidth && gridY >= 0 && gridY < gridHeight) {
return gameGrid[gridY][gridX];
}
return null;
}
function canPlaceTower(gridPos) {
return gridPos && !gridPos.occupied && !gridPos.isPath;
}
function spawnEnemy() {
var enemyType = 'basic';
var rand = Math.random();
// 5% chance for gold enemy (high reward, low health)
if (rand < 0.05) {
enemyType = 'gold';
} else if (wave > 5) {
if (rand < 0.3) enemyType = 'fast';else if (rand < 0.6) enemyType = 'tank';
} else if (wave > 2) {
if (rand < 0.2) enemyType = 'fast';
}
var enemy = new Enemy(enemyType);
enemy.x = pathPoints[0].x;
enemy.y = pathPoints[0].y;
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function startWave() {
if (waveInProgress) return;
waveInProgress = true;
enemiesSpawned = 0;
enemiesPerWave = 10 + wave * 2;
spawnTimer = 0;
showTowerMenu = false;
selectedTower = null;
// Display wave start message
showWaveStartMessage();
}
function showWaveStartMessage() {
// Create wave message container
var waveMessage = new Container();
waveMessage.x = 1024;
waveMessage.y = 1366;
// Create background for message
var messageBg = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 3
});
messageBg.tint = 0x2c3e50;
messageBg.alpha = 0.9;
waveMessage.addChild(messageBg);
// Create wave start text
var waveStartText = new Text2('WAVE ' + wave + ' STARTED!', {
size: 80,
fill: 0xf39c12
});
waveStartText.anchor.set(0.5, 0.5);
waveMessage.addChild(waveStartText);
// Create decorative elements
var leftDecoration = LK.getAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
leftDecoration.tint = 0xe74c3c;
leftDecoration.x = -300;
waveMessage.addChild(leftDecoration);
var rightDecoration = LK.getAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
rightDecoration.tint = 0x3498db;
rightDecoration.x = 300;
waveMessage.addChild(rightDecoration);
// Add to game
game.addChild(waveMessage);
// Initial state for animation
waveMessage.alpha = 0;
waveMessage.scaleX = 0.5;
waveMessage.scaleY = 0.5;
waveStartText.scaleX = 0.8;
waveStartText.scaleY = 0.8;
// Animate message entrance
tween(waveMessage, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
// Animate text pulsing
tween(waveStartText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waveStartText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300
});
}
});
// Animate decorations spinning
tween(leftDecoration, {
rotation: Math.PI * 2
}, {
duration: 1000
});
tween(rightDecoration, {
rotation: -Math.PI * 2
}, {
duration: 1000
});
// Remove message after 2 seconds
LK.setTimeout(function () {
tween(waveMessage, {
alpha: 0,
scaleY: 0
}, {
duration: 400,
onFinish: function onFinish() {
waveMessage.destroy();
}
});
}, 2000);
}
function showWaveCompletionMessage() {
// Create wave completion message container
var completionMessage = new Container();
completionMessage.x = 1024;
completionMessage.y = 1366;
// Create background for message
var messageBg = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 14,
scaleY: 4
});
messageBg.tint = 0x27ae60;
messageBg.alpha = 0.9;
completionMessage.addChild(messageBg);
// Create wave completion text
var completionText = new Text2('WAVE ' + (wave - 1) + ' COMPLETED!', {
size: 70,
fill: 0xffffff
});
completionText.anchor.set(0.5, 0.5);
completionMessage.addChild(completionText);
// Create bonus text
var bonusText = new Text2('BONUS: +' + (50 + Math.floor(coins * 0.1)) + ' COINS', {
size: 50,
fill: 0xf1c40f
});
bonusText.anchor.set(0.5, 0.5);
bonusText.y = 60;
completionMessage.addChild(bonusText);
// Create decorative victory elements
var leftStar = LK.getAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
leftStar.tint = 0xf39c12;
leftStar.x = -350;
completionMessage.addChild(leftStar);
var rightStar = LK.getAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
rightStar.tint = 0x9b59b6;
rightStar.x = 350;
completionMessage.addChild(rightStar);
// Add sparkle effects
for (var i = 0; i < 6; i++) {
var sparkle = LK.getAsset('watercharc', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2
});
sparkle.tint = [0xe74c3c, 0x3498db, 0x2ecc71, 0xf39c12, 0x9b59b6, 0xe67e22][i];
sparkle.alpha = 0.8;
sparkle.x = -200 + i * 80;
sparkle.y = -80 + Math.sin(i) * 40;
completionMessage.addChild(sparkle);
// Animate sparkles with rotation and scaling
tween(sparkle, {
rotation: Math.PI * 2,
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 1500,
easing: tween.easeInOut
});
}
// Add to game
game.addChild(completionMessage);
// Initial state for animation
completionMessage.alpha = 0;
completionMessage.scaleX = 0.3;
completionMessage.scaleY = 0.3;
completionText.scaleX = 0.5;
completionText.scaleY = 0.5;
// Animate message entrance with bounce effect
tween(completionMessage, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Animate main text with celebration effect
tween(completionText, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0x2ecc71
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(completionText, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 400
});
}
});
// Animate bonus text pulsing
tween(bonusText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bonusText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300
});
}
});
// Animate stars spinning and scaling
tween(leftStar, {
rotation: Math.PI * 3,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 2000,
easing: tween.easeInOut
});
tween(rightStar, {
rotation: -Math.PI * 3,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 2000,
easing: tween.easeInOut
});
// Remove message after 2.5 seconds
LK.setTimeout(function () {
tween(completionMessage, {
alpha: 0,
scaleY: 0
}, {
duration: 500,
onFinish: function onFinish() {
completionMessage.destroy();
}
});
}, 2500);
}
// Event handlers
startWaveButton.down = function () {
// Add touch animation - scale down then back up
tween(startWaveButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00AAFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(startWaveButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
startWave();
};
basicTowerButton.down = function () {
// Add touch animation - scale down and tint, then back up
tween(basicTowerButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00FF00
}, {
duration: 100,
onFinish: function onFinish() {
tween(basicTowerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
selectedTowerType = 'basic';
showTowerMenu = false;
};
splashTowerButton.down = function () {
// Add touch animation - scale down and tint, then back up
tween(splashTowerButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0xe74c3c
}, {
duration: 100,
onFinish: function onFinish() {
tween(splashTowerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
selectedTowerType = 'splash';
showTowerMenu = false;
};
slowTowerButton.down = function () {
// Add touch animation - scale down and tint, then back up
tween(slowTowerButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x9b59b6
}, {
duration: 100,
onFinish: function onFinish() {
tween(slowTowerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
selectedTowerType = 'slow';
showTowerMenu = false;
};
sniperTowerButton.down = function () {
// Add touch animation - scale down and tint, then back up
tween(sniperTowerButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x2ecc71
}, {
duration: 100,
onFinish: function onFinish() {
tween(sniperTowerButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
selectedTowerType = 'sniper';
showTowerMenu = false;
};
pauseButton.down = function () {
// Add touch animation
tween(pauseButton, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00AAFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(pauseButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
showExitButton();
};
game.down = function (x, y, obj) {
if (showTowerMenu) {
showTowerMenu = false;
selectedTower = null;
return;
}
// Prevent tower placement during wave
if (waveInProgress) {
return;
}
var gridPos = getGridPosition(x, y);
if (canPlaceTower(gridPos)) {
var tower = new Tower(selectedTowerType);
if (coins >= tower.cost) {
coins -= tower.cost;
tower.x = gridPos.x;
tower.y = gridPos.y;
gridPos.occupied = true;
towers.push(tower);
game.addChild(tower);
updateUI();
}
}
};
game.update = function () {
// Don't update game logic if paused
if (isPaused) {
return;
}
// Spawn enemies during wave
if (waveInProgress && enemiesSpawned < enemiesPerWave) {
spawnTimer++;
if (spawnTimer >= 60) {
spawnEnemy();
spawnTimer = 0;
}
}
// Reset kill streak if lives were lost
if (lives < lastLives) {
killStreak = 0;
lastLives = lives;
}
// Check if wave is complete
if (waveInProgress && enemiesSpawned >= enemiesPerWave && enemies.length === 0) {
waveInProgress = false;
wave++;
// Wave completion bonus + interest on current money
var waveBonus = 50;
var interestBonus = Math.floor(coins * 0.1); // 10% interest
coins += waveBonus + interestBonus;
// Display wave completion message
showWaveCompletionMessage();
updateUI();
}
// Clean up bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet.parent) {
bullets.splice(i, 1);
}
}
// Clean up water damage areas
for (var i = waterDamageAreas.length - 1; i >= 0; i--) {
var waterArea = waterDamageAreas[i];
if (!waterArea.parent) {
waterDamageAreas.splice(i, 1);
}
}
// Check win condition
if (wave > 20) {
LK.showYouWin();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -96,10 +96,10 @@
enemyGraphics = self.attachAsset('goldEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
- self.health = 10;
- self.maxHealth = 10;
+ self.health = 50;
+ self.maxHealth = 50;
self.speed = 3;
self.reward = 100; // High reward!
}
// Create health bar background
a tower of a tower defence. In-Game asset. 2d. High contrast. No shadows
slime. In-Game asset. 2d. High contrast. No shadows
splash tower of tower defense. In-Game asset. 2d. High contrast. No shadows
water bullet. In-Game asset. 2d. High contrast. No shadows
puddle of water. In-Game asset. 2d. High contrast. No shadows
slow tower of tower defense. In-Game asset. 2d. High contrast. No shadows
ice ball. In-Game asset. 2d. High contrast. No shadows
the sniper tower of tower defense. In-Game asset. 2d. High contrast. No shadows
sniper bullet. In-Game asset. 2d. High contrast. No shadows
floor. In-Game asset. 2d. High contrast. No shadows
fast enemy. In-Game asset. 2d. High contrast. No shadows
tank. In-Game asset. 2d. High contrast. No shadows