User prompt
haz que cuando la base enemiga este a 1 de vida aparezca un triangulo gigante que mande todas las unidades que ya habias mandado al inicio de su base y que este triangulo gigante tenga mucha, mucha, mucha vida y mucho daño y que pueda invocar a otros enemigos para que los ayuden
User prompt
añade 3 nuevos enemigos y 2 nuevas unidades y a todos los enemigos agregales mas vida
User prompt
haz que los enemigos y unidades que disparan tenga un radio de detencion mas alto y una vida mas baja y tambien puedan disparar en un eje de 360 grados
User prompt
haz que encima de los enemigos y unidades aparezca una barra de vida
User prompt
añade una unidad cube que dispare desde lejos y haz que las unidades y enemigos que disparan desde la distancia al detectar un enemigo se quedan quietas disparandoles desde lejos y cuando ven que el enemigo o unidad esta muy cerca, comienzan a atacar cuerpo a cuerpo
User prompt
haz que cuando las unidades o enemigos se dectenten entre si, dejen de ir a la base contraria y vayan a pelearse entre si
User prompt
haz que las unidades no se detengan literalmente, que solo se detengan de ir a la base enemiga y que ahora vayan a pelear con las unidades o enemigos
User prompt
aumenta el rango de deteccion de todas las unidades y enemigos
User prompt
haz que las unidades y enemigos solo se detengan cuando detecten una unidad o enemigo en su radio de deteccion
User prompt
haz que los enemigos de el mismo tipo tambien salgan de unas imagenes como las unidades de nuestro equipo y en la Wave 3 añade un nuevo enemigo que sea un triangulo que dispare
User prompt
haz que las unidades tengan un rango de deteccion para poder ver a los enemigos y que solo puedan avanzar hacia delante y esto tambien aplica para los enemigos
User prompt
haz que las unidades tengan un tiempo de recarga para colocarla de nuevo y que conforme avanzes en las oleadas aparezcan nuevos enemigos y te den nuevas unidades ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
haz que en la imagen de la unidad aparezca el precio y que la unidad salga de la imagen y que no tengas que clickear donde quieres que aparezca
User prompt
haz que las unidades normales y enemigos normales tengan la misma vida y daño y que para colocar unidades tengas que clickear una imagen de la unidad que quieres mandar y que tambien aparezca su precio
User prompt
haz que se gane Coins constantemente y que las unidades y enemigos vayan directamente a pelearse pada poder destruir las bases y que cada unidad y enemigo tenga su cantidad de vida y de daño
User prompt
haz que los enemigos tambien tengan su base y tengas que destruirla mandando a tus unidades a la base enemiga y que tus unidades no disparen, que ataquen cuerpo a cuerpo
Code edit (1 edits merged)
Please save this source code
User prompt
Cube Wars: Triangle Defense
Initial prompt
crea un juego estilo The Battle Cats pero en vertical y que sea de cubos vs triangulos
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BomberEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('bomberEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 8;
self.maxHealth = 8;
self.speed = 1.0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -55; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 2;
self.coinValue = 70;
self.attackCooldown = 0;
self.attackRate = 50;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 350;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Explode and damage nearby cubes
var explosionRange = 200;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (distance <= explosionRange) {
cube.takeDamage(3); // Explosion damage
}
}
LK.effects.flashScreen(0xff8800, 300); // Orange explosion flash
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
var Cube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('cube', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.attackCooldown = 0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -50; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.attackRate = 45; // Faster attack rate
self.cost = 50;
self.speed = 1.5;
self.damage = 1;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 400;
// Check for melee combat with triangles first
var attackedTriangle = null;
var nearestTriangle = null;
var nearestDistance = Infinity;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
var distance = Math.abs(self.x - triangle.x) + Math.abs(self.y - triangle.y);
if (self.intersects(triangle)) {
attackedTriangle = triangle;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestTriangle = triangle;
nearestDistance = distance;
}
}
// Attack triangle in melee range
if (attackedTriangle && self.attackCooldown <= 0) {
attackedTriangle.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward enemy base
if (nearestTriangle) {
// Move toward the nearest enemy to engage in combat
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward enemy base (only forward)
self.y -= self.speed;
}
}
// Check if reached enemy base
if (self.y < 100) {
enemyBaseHealth -= self.damage;
enemyBaseHealthText.setText('Enemy Base: ' + enemyBaseHealth);
if (enemyBaseHealth <= 0) {
LK.showYouWin();
}
self.destroy();
for (var j = cubes.length - 1; j >= 0; j--) {
if (cubes[j] === self) {
cubes.splice(j, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = cubes.length - 1; i >= 0; i--) {
if (cubes[i] === self) {
cubes.splice(i, 1);
break;
}
}
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.speedX = 0;
self.speedY = 3;
self.damage = 1;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Check collision with cubes
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
if (self.intersects(cube)) {
cube.takeDamage(self.damage);
self.destroy();
for (var j = enemyBullets.length - 1; j >= 0; j--) {
if (enemyBullets[j] === self) {
enemyBullets.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen
if (self.y > 2800) {
self.destroy();
for (var k = enemyBullets.length - 1; k >= 0; k--) {
if (enemyBullets[k] === self) {
enemyBullets.splice(k, 1);
break;
}
}
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 5;
self.maxHealth = 5;
self.speed = 2.5;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -45; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 1;
self.coinValue = 40;
self.attackCooldown = 0;
self.attackRate = 30;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 300;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
var GiantTriangleBoss = Container.expand(function () {
var self = Container.call(this);
var triangleGraphics = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0,
tint: 0x8B0000
});
triangleGraphics.rotation = Math.PI; // Point downward
self.health = 200; // Massive health
self.maxHealth = 200;
self.speed = 0.3;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -120; // Position above the giant unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 10; // Massive damage
self.coinValue = 500;
self.attackCooldown = 0;
self.attackRate = 30;
self.summonCooldown = 0;
self.summonRate = 300; // Summon every 5 seconds
self.hasRecalledUnits = false;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (self.summonCooldown > 0) {
self.summonCooldown--;
}
// Recall all existing units to base on first update
if (!self.hasRecalledUnits) {
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
if (triangle !== self) {
// Force all triangles to move back to enemy base
triangle.isRecalled = true;
}
}
self.hasRecalledUnits = true;
}
// Summon reinforcements
if (self.summonCooldown <= 0) {
var summonType = Math.random();
var newEnemy;
if (summonType < 0.3) {
newEnemy = new HeavyTriangle();
} else if (summonType < 0.6) {
newEnemy = new ShootingTriangle();
} else {
newEnemy = new TankEnemy();
}
// Spawn near the boss
newEnemy.x = self.x + (Math.random() - 0.5) * 400;
newEnemy.y = self.y + (Math.random() - 0.5) * 200;
newEnemy.x = Math.max(200, Math.min(1848, newEnemy.x)); // Keep on screen
newEnemy.y = Math.max(200, Math.min(600, newEnemy.y)); // Keep in upper area
triangles.push(newEnemy);
game.addChild(newEnemy);
self.summonCooldown = self.summonRate;
LK.effects.flashScreen(0x8B0000, 200); // Dark red flash when summoning
}
// Detection range for enemies
var detectionRange = 600;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
LK.effects.flashScreen(0xFF0000, 100); // Red flash on boss attack
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 150);
if (self.health <= 0) {
// Giant explosion effect
LK.effects.flashScreen(0xFFD700, 1000); // Gold victory flash
// Drop massive coin reward
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 3,
scaleY: 3
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 150,
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
// Show victory after defeating the boss
LK.showYouWin();
}
};
return self;
});
var HealerCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('healerCube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
self.health = 4;
self.maxHealth = 4;
self.attackCooldown = 0;
self.healCooldown = 0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -50; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.attackRate = 60;
self.healRate = 180; // Heal every 3 seconds
self.cost = 90;
self.speed = 1.0;
self.damage = 1;
self.healRange = 250;
self.healAmount = 2;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (self.healCooldown > 0) {
self.healCooldown--;
}
// Heal nearby cubes
if (self.healCooldown <= 0) {
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
if (cube !== self) {
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (distance <= self.healRange && cube.health < cube.maxHealth) {
cube.health = Math.min(cube.maxHealth, cube.health + self.healAmount);
cube.healthBar.updateHealth(cube.health, cube.maxHealth);
LK.effects.flashObject(cube, 0x00ff00, 200); // Green healing flash
self.healCooldown = self.healRate;
break; // Only heal one unit per cycle
}
}
}
}
// Detection range for enemies
var detectionRange = 300;
// Check for melee combat with triangles first
var attackedTriangle = null;
var nearestTriangle = null;
var nearestDistance = Infinity;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
var distance = Math.abs(self.x - triangle.x) + Math.abs(self.y - triangle.y);
if (self.intersects(triangle)) {
attackedTriangle = triangle;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestTriangle = triangle;
nearestDistance = distance;
}
}
// Attack triangle in melee range
if (attackedTriangle && self.attackCooldown <= 0) {
attackedTriangle.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward enemy base
if (nearestTriangle) {
// Move toward the nearest enemy to engage in combat
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward enemy base (only forward)
self.y -= self.speed;
}
}
// Check if reached enemy base
if (self.y < 100) {
enemyBaseHealth -= self.damage;
enemyBaseHealthText.setText('Enemy Base: ' + enemyBaseHealth);
if (enemyBaseHealth <= 0) {
LK.showYouWin();
}
self.destroy();
for (var j = cubes.length - 1; j >= 0; j--) {
if (cubes[j] === self) {
cubes.splice(j, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = cubes.length - 1; i >= 0; i--) {
if (cubes[i] === self) {
cubes.splice(i, 1);
break;
}
}
}
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5,
x: -30
});
self.updateHealth = function (currentHealth, maxHealth) {
var healthPercent = currentHealth / maxHealth;
healthBarFill.width = 60 * healthPercent;
// Change color based on health percentage
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
return self;
});
var HeavyCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.3,
scaleY: 1.3,
tint: 0x4444FF
});
self.health = 6;
self.maxHealth = 6;
self.attackCooldown = 0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -50; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.attackRate = 35; // Faster attack rate
self.cost = 120;
self.speed = 1.0;
self.damage = 2;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies (larger for heavy unit)
var detectionRange = 500;
// Check for melee combat with triangles first
var attackedTriangle = null;
var nearestTriangle = null;
var nearestDistance = Infinity;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
var distance = Math.abs(self.x - triangle.x) + Math.abs(self.y - triangle.y);
if (self.intersects(triangle)) {
attackedTriangle = triangle;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestTriangle = triangle;
nearestDistance = distance;
}
}
// Attack triangle in melee range
if (attackedTriangle && self.attackCooldown <= 0) {
attackedTriangle.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward enemy base
if (nearestTriangle) {
// Move toward the nearest enemy to engage in combat
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward enemy base (only forward)
self.y -= self.speed;
}
}
// Check if reached enemy base
if (self.y < 100) {
enemyBaseHealth -= self.damage;
enemyBaseHealthText.setText('Enemy Base: ' + enemyBaseHealth);
if (enemyBaseHealth <= 0) {
LK.showYouWin();
}
self.destroy();
for (var j = cubes.length - 1; j >= 0; j--) {
if (cubes[j] === self) {
cubes.splice(j, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = cubes.length - 1; i >= 0; i--) {
if (cubes[i] === self) {
cubes.splice(i, 1);
break;
}
}
}
};
return self;
});
var HeavyTriangle = Container.expand(function () {
var self = Container.call(this);
var triangleGraphics = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF4444
});
triangleGraphics.rotation = Math.PI; // Point downward
self.health = 10;
self.maxHealth = 10;
self.speed = 0.8;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -60; // Position above the larger unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 2;
self.coinValue = 60;
self.attackCooldown = 0;
self.attackRate = 40;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies (larger for heavy unit)
var detectionRange = 450;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
var RangedBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('rangedBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.speedX = 0;
self.speedY = -4;
self.damage = 2;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Check collision with triangles
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
if (self.intersects(triangle)) {
triangle.takeDamage(self.damage);
self.destroy();
for (var j = rangedBullets.length - 1; j >= 0; j--) {
if (rangedBullets[j] === self) {
rangedBullets.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen
if (self.y < -100) {
self.destroy();
for (var k = rangedBullets.length - 1; k >= 0; k--) {
if (rangedBullets[k] === self) {
rangedBullets.splice(k, 1);
break;
}
}
}
};
return self;
});
var RangedCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
tint: 0x00ff00
});
self.health = 2;
self.maxHealth = 2;
self.attackCooldown = 0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -50; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.attackRate = 60; // Shoots every 1 second
self.cost = 80;
self.speed = 1.2;
self.damage = 1;
self.shootRange = 800;
self.meleeRange = 120;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies (increased for ranged unit)
var detectionRange = 800;
// Check for melee combat with triangles first
var attackedTriangle = null;
var nearestTriangle = null;
var nearestDistance = Infinity;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
var distance = Math.abs(self.x - triangle.x) + Math.abs(self.y - triangle.y);
if (self.intersects(triangle)) {
attackedTriangle = triangle;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestTriangle = triangle;
nearestDistance = distance;
}
}
// Attack triangle in melee range
if (attackedTriangle && self.attackCooldown <= 0) {
attackedTriangle.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else if (nearestTriangle) {
// Check if enemy is within shooting range but not melee range
if (nearestDistance <= self.shootRange && nearestDistance > self.meleeRange) {
// Stay still and shoot with 360 degree targeting
if (self.attackCooldown <= 0) {
var bullet = new RangedBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction to target for 360 degree shooting
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.speedX = dx / distance * 4;
bullet.speedY = dy / distance * 4;
} else {
bullet.speedX = 0;
bullet.speedY = -4;
}
rangedBullets.push(bullet);
game.addChild(bullet);
self.attackCooldown = self.attackRate;
LK.getSound('shoot').play();
}
} else if (nearestDistance > self.meleeRange) {
// Move toward enemy for melee combat
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
} else {
// Move toward enemy base (only forward)
self.y -= self.speed;
}
// Check if reached enemy base
if (self.y < 100) {
enemyBaseHealth -= self.damage;
enemyBaseHealthText.setText('Enemy Base: ' + enemyBaseHealth);
if (enemyBaseHealth <= 0) {
LK.showYouWin();
}
self.destroy();
for (var j = cubes.length - 1; j >= 0; j--) {
if (cubes[j] === self) {
cubes.splice(j, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = cubes.length - 1; i >= 0; i--) {
if (cubes[i] === self) {
cubes.splice(i, 1);
break;
}
}
}
};
return self;
});
var ShieldCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('shieldCube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.health = 8;
self.maxHealth = 8;
self.attackCooldown = 0;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -60; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.attackRate = 50;
self.cost = 100;
self.speed = 0.8;
self.damage = 1;
self.tauntRange = 300; // Range to attract enemies
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 400;
// Check for melee combat with triangles first
var attackedTriangle = null;
var nearestTriangle = null;
var nearestDistance = Infinity;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
var distance = Math.abs(self.x - triangle.x) + Math.abs(self.y - triangle.y);
if (self.intersects(triangle)) {
attackedTriangle = triangle;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestTriangle = triangle;
nearestDistance = distance;
}
}
// Attack triangle in melee range
if (attackedTriangle && self.attackCooldown <= 0) {
attackedTriangle.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward enemy base
if (nearestTriangle) {
// Move toward the nearest enemy to engage in combat
var dx = nearestTriangle.x - self.x;
var dy = nearestTriangle.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward enemy base (only forward)
self.y -= self.speed;
}
}
// Check if reached enemy base
if (self.y < 100) {
enemyBaseHealth -= self.damage;
enemyBaseHealthText.setText('Enemy Base: ' + enemyBaseHealth);
if (enemyBaseHealth <= 0) {
LK.showYouWin();
}
self.destroy();
for (var j = cubes.length - 1; j >= 0; j--) {
if (cubes[j] === self) {
cubes.splice(j, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
// Shield cubes take reduced damage
var reducedDamage = Math.max(1, damage - 1);
self.health -= reducedDamage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = cubes.length - 1; i >= 0; i--) {
if (cubes[i] === self) {
cubes.splice(i, 1);
break;
}
}
}
};
return self;
});
var ShootingTriangle = Container.expand(function () {
var self = Container.call(this);
var triangleGraphics = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFF8800
});
triangleGraphics.rotation = Math.PI;
self.health = 4;
self.maxHealth = 4;
self.speed = 0.6;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -60; // Position above the larger unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 1;
self.coinValue = 80;
self.attackCooldown = 0;
self.attackRate = 120; // Shoots every 2 seconds
self.shootRange = 900;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Check for cubes in shooting range (increased range)
var targetCube = null;
var nearestDistance = Infinity;
var meleeRange = 150;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (distance <= self.shootRange && distance < nearestDistance) {
targetCube = cube;
nearestDistance = distance;
}
}
// Attack in melee range first
if (targetCube && nearestDistance <= meleeRange && self.attackCooldown <= 0) {
targetCube.takeDamage(self.damage);
self.attackCooldown = 60; // Melee attack rate
LK.getSound('hit').play();
} else if (targetCube && nearestDistance <= self.shootRange && nearestDistance > meleeRange && self.attackCooldown <= 0) {
// Stay still and shoot at distant targets with 360 degree targeting
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction to target for 360 degree shooting
var dx = targetCube.x - self.x;
var dy = targetCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.speedX = dx / distance * 3;
bullet.speedY = dy / distance * 3;
} else {
bullet.speedX = 0;
bullet.speedY = 3;
}
enemyBullets.push(bullet);
game.addChild(bullet);
self.attackCooldown = self.attackRate;
LK.getSound('shoot').play();
} else {
// Move toward targets or player base
if (targetCube && nearestDistance > meleeRange) {
// Move toward the nearest target for melee combat
var dx = targetCube.x - self.x;
var dy = targetCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
var TankEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('tankEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 15;
self.maxHealth = 15;
self.speed = 0.4;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -70; // Position above the larger unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 3;
self.coinValue = 100;
self.attackCooldown = 0;
self.attackRate = 80;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 400;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
var Triangle = Container.expand(function () {
var self = Container.call(this);
var triangleGraphics = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5
});
triangleGraphics.rotation = Math.PI; // Point downward
self.health = 5;
self.maxHealth = 5;
self.speed = 1.2;
// Add health bar
self.healthBar = new HealthBar();
self.healthBar.y = -50; // Position above the unit
self.addChild(self.healthBar);
self.healthBar.updateHealth(self.health, self.maxHealth);
self.damage = 1;
self.coinValue = 30;
self.attackCooldown = 0;
self.attackRate = 50;
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Detection range for enemies
var detectionRange = 350;
// Check for melee combat with cubes first
var attackedCube = null;
var nearestCube = null;
var nearestDistance = Infinity;
for (var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
if (self.intersects(cube)) {
attackedCube = cube;
break;
} else if (distance < nearestDistance && distance <= detectionRange) {
nearestCube = cube;
nearestDistance = distance;
}
}
// Attack cube in melee range
if (attackedCube && self.attackCooldown <= 0) {
attackedCube.takeDamage(self.damage);
self.attackCooldown = self.attackRate;
LK.getSound('hit').play();
} else {
// Engage enemies when detected, otherwise move toward player base
if (nearestCube) {
// Move toward the nearest enemy to engage in combat
var dx = nearestCube.x - self.x;
var dy = nearestCube.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Move toward player base (only forward)
self.y += self.speed;
}
}
// Check if reached player base
if (self.y > 2632) {
// Near bottom of screen
baseHealth -= self.damage;
baseHealthText.setText('Base Health: ' + baseHealth);
if (baseHealth <= 0) {
LK.showGameOver();
}
self.destroy();
for (var k = triangles.length - 1; k >= 0; k--) {
if (triangles[k] === self) {
triangles.splice(k, 1);
break;
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health, self.maxHealth);
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
// Drop coin
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
game.addChild(coin);
// Animate coin collection
tween(coin, {
y: coin.y + 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
coin.destroy();
}
});
currency += self.coinValue;
currencyText.setText('Coins: ' + currency);
LK.getSound('coin').play();
self.destroy();
for (var i = triangles.length - 1; i >= 0; i--) {
if (triangles[i] === self) {
triangles.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// Game state variables
var cubes = [];
var triangles = [];
var enemyBullets = [];
var rangedBullets = [];
var currency = 100;
var baseHealth = 20;
var enemyBaseHealth = 20;
var waveNumber = 1;
var trianglesSpawned = 0;
var trianglesPerWave = 5;
var spawnTimer = 0;
var spawnDelay = 120; // 2 seconds at 60fps
var cubeDeployDelay = 0;
var deploymentMode = false;
var enemySpawnTimer = 0;
var enemySpawnDelay = 180; // 3 seconds
// Create player base
var base = game.addChild(LK.getAsset('base', {
anchorX: 0.5,
anchorY: 1,
x: 1024,
y: 2732
}));
// Create enemy base
var enemyBase = game.addChild(LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: 0
}));
// Create UI
var currencyText = new Text2('Coins: ' + currency, {
size: 60,
fill: 0xFFD700
});
currencyText.anchor.set(0, 0);
currencyText.x = 120;
currencyText.y = 120;
LK.gui.topLeft.addChild(currencyText);
var baseHealthText = new Text2('Base Health: ' + baseHealth, {
size: 60,
fill: 0xFF4444
});
baseHealthText.anchor.set(1, 0);
LK.gui.topRight.addChild(baseHealthText);
var enemyBaseHealthText = new Text2('Enemy Base: ' + enemyBaseHealth, {
size: 60,
fill: 0xFF4444
});
enemyBaseHealthText.anchor.set(0, 0);
enemyBaseHealthText.x = 120;
enemyBaseHealthText.y = 200;
LK.gui.topLeft.addChild(enemyBaseHealthText);
var waveText = new Text2('Wave: ' + waveNumber, {
size: 60,
fill: 0x4A90E2
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var instructionText = new Text2('Tap cube button to spawn cube!', {
size: 40,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
instructionText.y = -120;
LK.gui.bottom.addChild(instructionText);
// Create enemy spawn buttons at top
var triangleSpawnButton = LK.getAsset('triangleButton', {
anchorX: 0.5,
anchorY: 0,
x: -200,
y: 20
});
LK.gui.top.addChild(triangleSpawnButton);
// Add triangle icon to enemy button
var triangleSpawnIcon = LK.getAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
triangleSpawnIcon.rotation = Math.PI;
triangleSpawnButton.addChild(triangleSpawnIcon);
// Create heavy triangle spawn button
var heavyTriangleSpawnButton = LK.getAsset('triangleButton', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 20,
tint: 0xFF4444
});
LK.gui.top.addChild(heavyTriangleSpawnButton);
// Add heavy triangle icon to enemy button
var heavyTriangleSpawnIcon = LK.getAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFF4444
});
heavyTriangleSpawnIcon.rotation = Math.PI;
heavyTriangleSpawnButton.addChild(heavyTriangleSpawnIcon);
// Create shooting triangle spawn button
var shootingTriangleSpawnButton = LK.getAsset('triangleButton', {
anchorX: 0.5,
anchorY: 0,
x: 200,
y: 20,
tint: 0xFF8800
});
LK.gui.top.addChild(shootingTriangleSpawnButton);
// Add shooting triangle icon to enemy button
var shootingTriangleSpawnIcon = LK.getAsset('triangle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
tint: 0xFF8800
});
shootingTriangleSpawnIcon.rotation = Math.PI;
shootingTriangleSpawnButton.addChild(shootingTriangleSpawnIcon);
// Create cube deployment button
var cubeButton = LK.getAsset('cubeButton', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -20
});
LK.gui.bottom.addChild(cubeButton);
// Add cube icon to button
var cubeIcon = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
cubeButton.addChild(cubeIcon);
// Add price text to button
var cubePriceText = new Text2('50', {
size: 24,
fill: 0xFFD700
});
cubePriceText.anchor.set(0.5, 0);
cubePriceText.y = 35;
cubeButton.addChild(cubePriceText);
// Add cooldown text to button
var cubeCooldownText = new Text2('', {
size: 20,
fill: 0xFF4444
});
cubeCooldownText.anchor.set(0.5, 0);
cubeCooldownText.y = 55;
cubeButton.addChild(cubeCooldownText);
// Create ranged cube deployment button
var rangedCubeButton = LK.getAsset('cubeButton', {
anchorX: 0.5,
anchorY: 1,
x: -200,
y: -20,
tint: 0x00FF00
});
LK.gui.bottom.addChild(rangedCubeButton);
// Add ranged cube icon to button
var rangedCubeIcon = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
tint: 0x00FF00
});
rangedCubeButton.addChild(rangedCubeIcon);
// Add price text to ranged cube button
var rangedCubePriceText = new Text2('80', {
size: 24,
fill: 0xFFD700
});
rangedCubePriceText.anchor.set(0.5, 0);
rangedCubePriceText.y = 35;
rangedCubeButton.addChild(rangedCubePriceText);
// Add cooldown text to ranged cube button
var rangedCubeCooldownText = new Text2('', {
size: 20,
fill: 0xFF4444
});
rangedCubeCooldownText.anchor.set(0.5, 0);
rangedCubeCooldownText.y = 55;
rangedCubeButton.addChild(rangedCubeCooldownText);
// Create heavy cube deployment button
var heavyCubeButton = LK.getAsset('cubeButton', {
anchorX: 0.5,
anchorY: 1,
x: 200,
y: -20,
tint: 0x4444FF
});
LK.gui.bottom.addChild(heavyCubeButton);
// Add heavy cube icon to button
var heavyCubeIcon = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x4444FF
});
heavyCubeButton.addChild(heavyCubeIcon);
// Add price text to heavy cube button
var heavyCubePriceText = new Text2('120', {
size: 24,
fill: 0xFFD700
});
heavyCubePriceText.anchor.set(0.5, 0);
heavyCubePriceText.y = 35;
heavyCubeButton.addChild(heavyCubePriceText);
// Add cooldown text to heavy cube button
var heavyCubeCooldownText = new Text2('', {
size: 20,
fill: 0xFF4444
});
heavyCubeCooldownText.anchor.set(0.5, 0);
heavyCubeCooldownText.y = 55;
heavyCubeButton.addChild(heavyCubeCooldownText);
// Create shield cube deployment button
var shieldCubeButton = LK.getAsset('cubeButton', {
anchorX: 0.5,
anchorY: 1,
x: -400,
y: -20,
tint: 0x00ffff
});
LK.gui.bottom.addChild(shieldCubeButton);
// Add shield cube icon to button
var shieldCubeIcon = LK.getAsset('shieldCube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
shieldCubeButton.addChild(shieldCubeIcon);
// Add price text to shield cube button
var shieldCubePriceText = new Text2('100', {
size: 24,
fill: 0xFFD700
});
shieldCubePriceText.anchor.set(0.5, 0);
shieldCubePriceText.y = 35;
shieldCubeButton.addChild(shieldCubePriceText);
// Add cooldown text to shield cube button
var shieldCubeCooldownText = new Text2('', {
size: 20,
fill: 0xFF4444
});
shieldCubeCooldownText.anchor.set(0.5, 0);
shieldCubeCooldownText.y = 55;
shieldCubeButton.addChild(shieldCubeCooldownText);
// Create healer cube deployment button
var healerCubeButton = LK.getAsset('cubeButton', {
anchorX: 0.5,
anchorY: 1,
x: 400,
y: -20,
tint: 0xffff00
});
LK.gui.bottom.addChild(healerCubeButton);
// Add healer cube icon to button
var healerCubeIcon = LK.getAsset('healerCube', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
healerCubeButton.addChild(healerCubeIcon);
// Add price text to healer cube button
var healerCubePriceText = new Text2('90', {
size: 24,
fill: 0xFFD700
});
healerCubePriceText.anchor.set(0.5, 0);
healerCubePriceText.y = 35;
healerCubeButton.addChild(healerCubePriceText);
// Add cooldown text to healer cube button
var healerCubeCooldownText = new Text2('', {
size: 20,
fill: 0xFF4444
});
healerCubeCooldownText.anchor.set(0.5, 0);
healerCubeCooldownText.y = 55;
healerCubeButton.addChild(healerCubeCooldownText);
// Ranged cube button click handler
var rangedCubeDeployDelay = 0;
rangedCubeButton.down = function (x, y, obj) {
if (currency >= 80 && rangedCubeDeployDelay <= 0 && waveNumber >= 2) {
// Spawn ranged cube directly from button position
var buttonGlobalPos = rangedCubeButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
var cube = new RangedCube();
cube.x = gameLocalPos.x;
cube.y = Math.max(gameLocalPos.y, 2400); // Keep cubes in lower part of screen
cubes.push(cube);
game.addChild(cube);
currency -= cube.cost;
currencyText.setText('Coins: ' + currency);
rangedCubeDeployDelay = 300; // 5 second cooldown
LK.getSound('deploy').play();
}
};
// Heavy cube button click handler
var heavyCubeDeployDelay = 0;
heavyCubeButton.down = function (x, y, obj) {
if (currency >= 120 && heavyCubeDeployDelay <= 0 && waveNumber >= 3) {
// Spawn heavy cube directly from button position
var buttonGlobalPos = heavyCubeButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
var cube = new HeavyCube();
cube.x = gameLocalPos.x;
cube.y = Math.max(gameLocalPos.y, 2400); // Keep cubes in lower part of screen
cubes.push(cube);
game.addChild(cube);
currency -= cube.cost;
currencyText.setText('Coins: ' + currency);
heavyCubeDeployDelay = 240; // 4 second cooldown
LK.getSound('deploy').play();
}
};
// Shield cube button click handler
var shieldCubeDeployDelay = 0;
shieldCubeButton.down = function (x, y, obj) {
if (currency >= 100 && shieldCubeDeployDelay <= 0 && waveNumber >= 2) {
// Spawn shield cube directly from button position
var buttonGlobalPos = shieldCubeButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
var cube = new ShieldCube();
cube.x = gameLocalPos.x;
cube.y = Math.max(gameLocalPos.y, 2400); // Keep cubes in lower part of screen
cubes.push(cube);
game.addChild(cube);
currency -= cube.cost;
currencyText.setText('Coins: ' + currency);
shieldCubeDeployDelay = 360; // 6 second cooldown
LK.getSound('deploy').play();
}
};
// Healer cube button click handler
var healerCubeDeployDelay = 0;
healerCubeButton.down = function (x, y, obj) {
if (currency >= 90 && healerCubeDeployDelay <= 0 && waveNumber >= 4) {
// Spawn healer cube directly from button position
var buttonGlobalPos = healerCubeButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
var cube = new HealerCube();
cube.x = gameLocalPos.x;
cube.y = Math.max(gameLocalPos.y, 2400); // Keep cubes in lower part of screen
cubes.push(cube);
game.addChild(cube);
currency -= cube.cost;
currencyText.setText('Coins: ' + currency);
healerCubeDeployDelay = 300; // 5 second cooldown
LK.getSound('deploy').play();
}
};
// Button click handler
cubeButton.down = function (x, y, obj) {
if (currency >= 50 && cubeDeployDelay <= 0) {
// Spawn cube directly from button position
var buttonGlobalPos = cubeButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
var cube = new Cube();
cube.x = gameLocalPos.x;
cube.y = Math.max(gameLocalPos.y, 2400); // Keep cubes in lower part of screen
cubes.push(cube);
game.addChild(cube);
currency -= cube.cost;
currencyText.setText('Coins: ' + currency);
cubeDeployDelay = 180; // 3 second cooldown
LK.getSound('deploy').play();
}
};
// Game event handlers
game.down = function (x, y, obj) {
// No deployment mode needed - cubes spawn directly from button
};
// Spawn triangle enemies
function spawnTriangle() {
if (trianglesSpawned < trianglesPerWave) {
var triangle;
var spawnButton;
var spawnChance = Math.random();
// Determine which type of triangle to spawn based on wave
if (waveNumber >= 6 && spawnChance < 0.15) {
triangle = new TankEnemy();
spawnButton = heavyTriangleSpawnButton;
} else if (waveNumber >= 5 && spawnChance < 0.25) {
triangle = new BomberEnemy();
spawnButton = shootingTriangleSpawnButton;
} else if (waveNumber >= 4 && spawnChance < 0.4) {
triangle = new HeavyTriangle();
spawnButton = heavyTriangleSpawnButton;
} else if (waveNumber >= 3 && spawnChance < 0.3) {
triangle = new ShootingTriangle();
spawnButton = shootingTriangleSpawnButton;
} else if (waveNumber >= 2 && spawnChance < 0.2) {
triangle = new FastEnemy();
spawnButton = triangleSpawnButton;
} else {
triangle = new Triangle();
spawnButton = triangleSpawnButton;
}
// Spawn from button position
var buttonGlobalPos = spawnButton.toGlobal({
x: 0,
y: 0
});
var gameLocalPos = game.toLocal(buttonGlobalPos);
triangle.x = gameLocalPos.x;
triangle.y = Math.max(gameLocalPos.y, 100);
// Increase difficulty with wave number for regular triangles
if (triangle instanceof Triangle && !(triangle instanceof HeavyTriangle) && !(triangle instanceof ShootingTriangle)) {
triangle.health = Math.floor(1 + waveNumber * 0.5);
triangle.maxHealth = triangle.health;
triangle.speed = 0.5 + waveNumber * 0.2;
triangle.coinValue = 20 + waveNumber * 5;
// Update health bar with new values
triangle.healthBar.updateHealth(triangle.health, triangle.maxHealth);
}
triangles.push(triangle);
game.addChild(triangle);
trianglesSpawned++;
}
}
// Main game update loop
game.update = function () {
// Generate coins constantly (every 2 seconds)
if (LK.ticks % 120 === 0) {
currency += 10;
currencyText.setText('Coins: ' + currency);
}
// Update cooldowns and display
if (cubeDeployDelay > 0) {
cubeDeployDelay--;
cubeCooldownText.setText(Math.ceil(cubeDeployDelay / 60) + 's');
cubeButton.alpha = 0.5;
} else {
cubeCooldownText.setText('');
cubeButton.alpha = currency >= 50 ? 1.0 : 0.7;
}
if (rangedCubeDeployDelay > 0) {
rangedCubeDeployDelay--;
rangedCubeCooldownText.setText(Math.ceil(rangedCubeDeployDelay / 60) + 's');
rangedCubeButton.alpha = 0.5;
} else {
rangedCubeCooldownText.setText('');
if (waveNumber >= 2) {
rangedCubeButton.alpha = currency >= 80 ? 1.0 : 0.7;
} else {
rangedCubeButton.alpha = 0.3;
}
}
if (heavyCubeDeployDelay > 0) {
heavyCubeDeployDelay--;
heavyCubeCooldownText.setText(Math.ceil(heavyCubeDeployDelay / 60) + 's');
heavyCubeButton.alpha = 0.5;
} else {
heavyCubeCooldownText.setText('');
if (waveNumber >= 3) {
heavyCubeButton.alpha = currency >= 120 ? 1.0 : 0.7;
} else {
heavyCubeButton.alpha = 0.3;
}
}
if (shieldCubeDeployDelay > 0) {
shieldCubeDeployDelay--;
shieldCubeCooldownText.setText(Math.ceil(shieldCubeDeployDelay / 60) + 's');
shieldCubeButton.alpha = 0.5;
} else {
shieldCubeCooldownText.setText('');
if (waveNumber >= 2) {
shieldCubeButton.alpha = currency >= 100 ? 1.0 : 0.7;
} else {
shieldCubeButton.alpha = 0.3;
}
}
if (healerCubeDeployDelay > 0) {
healerCubeDeployDelay--;
healerCubeCooldownText.setText(Math.ceil(healerCubeDeployDelay / 60) + 's');
healerCubeButton.alpha = 0.5;
} else {
healerCubeCooldownText.setText('');
if (waveNumber >= 4) {
healerCubeButton.alpha = currency >= 90 ? 1.0 : 0.7;
} else {
healerCubeButton.alpha = 0.3;
}
}
// Update enemy spawn button visibility based on wave
triangleSpawnButton.alpha = waveNumber >= 1 ? 1.0 : 0.3;
heavyTriangleSpawnButton.alpha = waveNumber >= 4 ? 1.0 : 0.3;
shootingTriangleSpawnButton.alpha = waveNumber >= 3 ? 1.0 : 0.3;
// Spawn triangles automatically from buttons
if (enemySpawnTimer <= 0 && trianglesSpawned < trianglesPerWave) {
spawnTriangle();
enemySpawnTimer = enemySpawnDelay - waveNumber * 5; // Faster spawning each wave
enemySpawnTimer = Math.max(enemySpawnTimer, 60); // Minimum delay
} else {
enemySpawnTimer--;
}
// Spawn triangles (legacy timer for compatibility)
if (spawnTimer <= 0 && trianglesSpawned < trianglesPerWave) {
spawnTimer = spawnDelay - waveNumber * 5; // Faster spawning each wave
spawnTimer = Math.max(spawnTimer, 30); // Minimum delay
} else {
spawnTimer--;
}
// Check for boss spawn condition
var bossExists = false;
for (var i = 0; i < triangles.length; i++) {
if (triangles[i] instanceof GiantTriangleBoss) {
bossExists = true;
break;
}
}
// Spawn boss when enemy base reaches 1 health
if (enemyBaseHealth <= 1 && !bossExists) {
var boss = new GiantTriangleBoss();
boss.x = 1024; // Center of screen
boss.y = 300; // Near enemy base
triangles.push(boss);
game.addChild(boss);
LK.effects.flashScreen(0x8B0000, 500); // Dark red warning flash
// Show warning message
var warningText = new Text2('GIANT BOSS AWAKENED!', {
size: 80,
fill: 0xFF0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Animate and remove warning text
tween(warningText, {
y: warningText.y - 200,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
warningText.destroy();
}
});
}
// Update recalled units behavior
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
if (triangle.isRecalled && !(triangle instanceof GiantTriangleBoss)) {
// Force recalled units to move back to enemy base
triangle.y -= 2; // Move upward faster than normal
if (triangle.y <= 100) {
// Remove unit when it reaches base
triangle.destroy();
triangles.splice(i, 1);
i--;
}
}
}
// Check for wave completion
if (trianglesSpawned >= trianglesPerWave && triangles.length === 0) {
waveNumber++;
trianglesSpawned = 0;
trianglesPerWave = Math.floor(5 + waveNumber * 1.5);
waveText.setText('Wave: ' + waveNumber);
// Bonus coins for completing wave
currency += 50;
currencyText.setText('Coins: ' + currency);
// Check for victory condition
if (waveNumber > 10) {
LK.showYouWin();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -376,8 +376,171 @@
}
};
return self;
});
+var GiantTriangleBoss = Container.expand(function () {
+ var self = Container.call(this);
+ var triangleGraphics = self.attachAsset('triangle', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 4.0,
+ scaleY: 4.0,
+ tint: 0x8B0000
+ });
+ triangleGraphics.rotation = Math.PI; // Point downward
+ self.health = 200; // Massive health
+ self.maxHealth = 200;
+ self.speed = 0.3;
+ // Add health bar
+ self.healthBar = new HealthBar();
+ self.healthBar.y = -120; // Position above the giant unit
+ self.addChild(self.healthBar);
+ self.healthBar.updateHealth(self.health, self.maxHealth);
+ self.damage = 10; // Massive damage
+ self.coinValue = 500;
+ self.attackCooldown = 0;
+ self.attackRate = 30;
+ self.summonCooldown = 0;
+ self.summonRate = 300; // Summon every 5 seconds
+ self.hasRecalledUnits = false;
+ self.update = function () {
+ if (self.attackCooldown > 0) {
+ self.attackCooldown--;
+ }
+ if (self.summonCooldown > 0) {
+ self.summonCooldown--;
+ }
+ // Recall all existing units to base on first update
+ if (!self.hasRecalledUnits) {
+ for (var i = 0; i < triangles.length; i++) {
+ var triangle = triangles[i];
+ if (triangle !== self) {
+ // Force all triangles to move back to enemy base
+ triangle.isRecalled = true;
+ }
+ }
+ self.hasRecalledUnits = true;
+ }
+ // Summon reinforcements
+ if (self.summonCooldown <= 0) {
+ var summonType = Math.random();
+ var newEnemy;
+ if (summonType < 0.3) {
+ newEnemy = new HeavyTriangle();
+ } else if (summonType < 0.6) {
+ newEnemy = new ShootingTriangle();
+ } else {
+ newEnemy = new TankEnemy();
+ }
+ // Spawn near the boss
+ newEnemy.x = self.x + (Math.random() - 0.5) * 400;
+ newEnemy.y = self.y + (Math.random() - 0.5) * 200;
+ newEnemy.x = Math.max(200, Math.min(1848, newEnemy.x)); // Keep on screen
+ newEnemy.y = Math.max(200, Math.min(600, newEnemy.y)); // Keep in upper area
+ triangles.push(newEnemy);
+ game.addChild(newEnemy);
+ self.summonCooldown = self.summonRate;
+ LK.effects.flashScreen(0x8B0000, 200); // Dark red flash when summoning
+ }
+ // Detection range for enemies
+ var detectionRange = 600;
+ // Check for melee combat with cubes first
+ var attackedCube = null;
+ var nearestCube = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < cubes.length; i++) {
+ var cube = cubes[i];
+ var distance = Math.abs(self.x - cube.x) + Math.abs(self.y - cube.y);
+ if (self.intersects(cube)) {
+ attackedCube = cube;
+ break;
+ } else if (distance < nearestDistance && distance <= detectionRange) {
+ nearestCube = cube;
+ nearestDistance = distance;
+ }
+ }
+ // Attack cube in melee range
+ if (attackedCube && self.attackCooldown <= 0) {
+ attackedCube.takeDamage(self.damage);
+ self.attackCooldown = self.attackRate;
+ LK.getSound('hit').play();
+ LK.effects.flashScreen(0xFF0000, 100); // Red flash on boss attack
+ } else {
+ // Engage enemies when detected, otherwise move toward player base
+ if (nearestCube) {
+ // Move toward the nearest enemy to engage in combat
+ var dx = nearestCube.x - self.x;
+ var dy = nearestCube.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 0) {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ }
+ } else {
+ // Move toward player base (only forward)
+ self.y += self.speed;
+ }
+ }
+ // Check if reached player base
+ if (self.y > 2632) {
+ // Near bottom of screen
+ baseHealth -= self.damage;
+ baseHealthText.setText('Base Health: ' + baseHealth);
+ if (baseHealth <= 0) {
+ LK.showGameOver();
+ }
+ self.destroy();
+ for (var k = triangles.length - 1; k >= 0; k--) {
+ if (triangles[k] === self) {
+ triangles.splice(k, 1);
+ break;
+ }
+ }
+ }
+ };
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ self.healthBar.updateHealth(self.health, self.maxHealth);
+ LK.effects.flashObject(self, 0xFFFFFF, 150);
+ if (self.health <= 0) {
+ // Giant explosion effect
+ LK.effects.flashScreen(0xFFD700, 1000); // Gold victory flash
+ // Drop massive coin reward
+ var coin = LK.getAsset('coin', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: self.x,
+ y: self.y,
+ scaleX: 3,
+ scaleY: 3
+ });
+ game.addChild(coin);
+ // Animate coin collection
+ tween(coin, {
+ y: coin.y + 150,
+ alpha: 0
+ }, {
+ duration: 1200,
+ onFinish: function onFinish() {
+ coin.destroy();
+ }
+ });
+ currency += self.coinValue;
+ currencyText.setText('Coins: ' + currency);
+ LK.getSound('coin').play();
+ self.destroy();
+ for (var i = triangles.length - 1; i >= 0; i--) {
+ if (triangles[i] === self) {
+ triangles.splice(i, 1);
+ break;
+ }
+ }
+ // Show victory after defeating the boss
+ LK.showYouWin();
+ }
+ };
+ return self;
+});
var HealerCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('healerCube', {
anchorX: 0.5,
@@ -1887,8 +2050,58 @@
spawnTimer = Math.max(spawnTimer, 30); // Minimum delay
} else {
spawnTimer--;
}
+ // Check for boss spawn condition
+ var bossExists = false;
+ for (var i = 0; i < triangles.length; i++) {
+ if (triangles[i] instanceof GiantTriangleBoss) {
+ bossExists = true;
+ break;
+ }
+ }
+ // Spawn boss when enemy base reaches 1 health
+ if (enemyBaseHealth <= 1 && !bossExists) {
+ var boss = new GiantTriangleBoss();
+ boss.x = 1024; // Center of screen
+ boss.y = 300; // Near enemy base
+ triangles.push(boss);
+ game.addChild(boss);
+ LK.effects.flashScreen(0x8B0000, 500); // Dark red warning flash
+ // Show warning message
+ var warningText = new Text2('GIANT BOSS AWAKENED!', {
+ size: 80,
+ fill: 0xFF0000
+ });
+ warningText.anchor.set(0.5, 0.5);
+ warningText.x = 1024;
+ warningText.y = 1366;
+ game.addChild(warningText);
+ // Animate and remove warning text
+ tween(warningText, {
+ y: warningText.y - 200,
+ alpha: 0
+ }, {
+ duration: 2000,
+ onFinish: function onFinish() {
+ warningText.destroy();
+ }
+ });
+ }
+ // Update recalled units behavior
+ for (var i = 0; i < triangles.length; i++) {
+ var triangle = triangles[i];
+ if (triangle.isRecalled && !(triangle instanceof GiantTriangleBoss)) {
+ // Force recalled units to move back to enemy base
+ triangle.y -= 2; // Move upward faster than normal
+ if (triangle.y <= 100) {
+ // Remove unit when it reaches base
+ triangle.destroy();
+ triangles.splice(i, 1);
+ i--;
+ }
+ }
+ }
// Check for wave completion
if (trianglesSpawned >= trianglesPerWave && triangles.length === 0) {
waveNumber++;
trianglesSpawned = 0;
triangulo. In-Game asset. 2d. High contrast. No shadows
cuadrado. In-Game asset. 2d. High contrast. No shadows
azul
triangulo rosa oscuro. In-Game asset. 2d. High contrast. No shadows
triangulo gris oscuro. In-Game asset. 2d. High contrast. No shadows
cuadrado celeste. In-Game asset. 2d. High contrast. No shadows
triangulo naranja con mecha de bomba. In-Game asset. 2d. High contrast. No shadows
un triangolo rojo oscuro con cuernos. In-Game asset. 2d. High contrast. No shadows