User prompt
separate images for left-spawned and right-spawned enemies
Code edit (7 edits merged)
Please save this source code
User prompt
enemies should be visible
User prompt
ADD A SPAWNER TO THE LEFT AND RIGHT, SEPARATE THEM, MAKE LEFT-SPAWNED ENEMIES FACE RIGHT, RIGHT-SPAWNED ENEMIES LEFT
User prompt
left enemies should face right.
Code edit (1 edits merged)
Please save this source code
User prompt
separate the enemies from left-spawning and right-spawning, reverse the image for ONLY the ones spawning from left
User prompt
reverse the image for left-spawned enemies
User prompt
reverse the image for the left-spawned enemies
User prompt
left-spawned enemies should face right
User prompt
enemies coming from right should face left, enemies coming from left should face right, set it up
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Base class
var Base = Container.expand(function () {
var self = Container.call(this);
// Attach base asset (ellipse, blue)
var baseGraphics = self.attachAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
baseGraphics.width = 180;
baseGraphics.height = 180;
baseGraphics.color = 0x3399ff;
self.maxHp = 20;
self.hp = self.maxHp;
// Flash on hit
self.hit = function () {
LK.effects.flashObject(self, 0xff0000, 400);
};
// Repair
self.repair = function () {
self.hp = Math.min(self.maxHp, self.hp + 5);
};
// Upgrade
self.upgrade = function () {
self.maxHp += 10;
self.hp = self.maxHp;
baseGraphics.scaleX += 0.1;
baseGraphics.scaleY += 0.1;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Attach bullet asset (box, yellow)
var bulletGraphics = self.attachAsset('bullet', {
anchorX: -2,
anchorY: 2
});
bulletGraphics.width = 20;
bulletGraphics.height = 20;
bulletGraphics.color = 0xb8b031;
self.speed = 24;
self.target = null;
self.side = 1;
self.damage = 1;
self.update = function () {
if (!self.target || self.target.destroyed) {
self.destroy();
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 40) {
// Hit!
self.target.hp -= self.damage;
LK.effects.flashObject(self.target, 0xffff00, 200);
self.destroy();
return;
}
var step = self.speed;
self.x += dx / dist * step;
self.y += dy / dist * step;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach enemy asset (ellipse, red)
// Use separate images for left- and right-spawned enemies
var assetId = self.direction === -1 ? 'enemyLeft' : 'enemyRight';
var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Set size and color
enemyGraphics.width = 90;
enemyGraphics.height = 90;
enemyGraphics.color = 0xd83318;
// Enemy properties
self.speed = 3 + Math.random() * 1.5; // Will be set per wave
self.hp = 1; // Will be set per wave
self.direction = 1; // 1 for right-to-left, -1 for left-to-right
// Update method
self.update = function () {
self.x += self.speed * self.direction;
};
return self;
});
// Turret class
var Turret = Container.expand(function () {
var self = Container.call(this);
// Attach turret asset (box, green)
var turretGraphics = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 0.5
});
turretGraphics.width = 100;
turretGraphics.height = 100;
turretGraphics.color = 0x83de44;
// Turret properties
self.range = 500;
self.fireRate = 60; // frames between shots
self.cooldown = 0;
self.level = 1;
self.side = 1; // 1 = right, -1 = left
// Upgrade method
self.upgrade = function () {
if (self.level < 3) {
self.level += 1;
self.range += 100;
self.fireRate = Math.max(30, self.fireRate - 10);
turretGraphics.scaleX += 0.1;
turretGraphics.scaleY += 0.1;
}
};
// Update method
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
return;
}
// Find closest enemy in range on this side
var closest = null;
var minDist = self.range + 1;
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
if (self.side === 1 && e.x > base.x || self.side === -1 && e.x < base.x) {
var dx = e.x - self.x;
var dy = e.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist && dist <= self.range) {
minDist = dist;
closest = e;
}
}
}
if (closest) {
// Fire at enemy
var b = new Bullet();
b.x = self.x;
b.y = self.y;
b.target = closest;
b.side = self.side;
b.damage = self.level;
// Reverse bullet image for left turrets
if (self.side === -1 && b.children && b.children.length > 0) {
if (typeof b.children[0].scaleX !== "undefined") {
b.children[0].scaleX = -1 * Math.abs(b.children[0].scaleX);
}
}
bullets.push(b);
game.addChild(b);
self.cooldown = self.fireRate;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Add background image to the game scene
var backgroundImg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
game.addChild(backgroundImg);
// Game state variables
var base = new Base();
base.x = 2048 / 2;
base.y = 2732 / 2;
game.addChild(base);
var turrets = [];
var enemies = [];
var bullets = [];
var gold = 50;
var wave = 1;
var enemiesToSpawn = 0;
var enemiesSpawned = 0;
var enemiesPerWave = 6;
var waveInProgress = false;
var spawnTimer = 0;
var nextWaveTimer = 0;
var baseHealthTxt, goldTxt, waveTxt;
var selectedTurret = null;
// HP Bar for base (black outline, gray background, green foreground)
// Use shape assets for outline, background, and foreground bar
var baseHpBarOutline = LK.getAsset('baseHpBarOutline', {
anchorX: 0.5,
anchorY: 0.5,
x: base.x,
y: base.y - 190,
width: 208,
height: 40
});
var baseHpBarBg = LK.getAsset('baseHpBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: base.x,
y: base.y - 190,
width: 200,
height: 32
});
var baseHpBar = LK.getAsset('baseHpBar', {
anchorX: 0,
anchorY: 0.5,
x: base.x - 100,
y: base.y - 190,
width: 200,
height: 32
});
game.addChild(baseHpBarOutline);
game.addChild(baseHpBarBg);
game.addChild(baseHpBar);
// (ground platform removed)
// GUI
// HP text removed
goldTxt = new Text2("Gold: " + gold, {
size: 80,
fill: 0xFFD700
});
goldTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(goldTxt);
waveTxt = new Text2("Wave: " + wave, {
size: 80,
fill: "#fff"
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
// Turret placement buttons (left and right)
// Space out the buttons and texts at the bottom of the screen for better separation
var bottomY = 2732 - 180;
var leftTurretBtn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 700,
y: bottomY,
scaleX: 1.2,
scaleY: 1.2
});
var rightTurretBtn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 700,
y: bottomY,
scaleX: 1.2,
scaleY: 1.2
});
game.addChild(leftTurretBtn);
game.addChild(rightTurretBtn);
var leftTurretCostTxt = new Text2("Buy: 30", {
size: 60,
fill: "#fff"
});
leftTurretCostTxt.anchor.set(0.5, 0);
leftTurretCostTxt.x = leftTurretBtn.x;
leftTurretCostTxt.y = leftTurretBtn.y + 100;
game.addChild(leftTurretCostTxt);
var rightTurretCostTxt = new Text2("Buy: 30", {
size: 60,
fill: "#fff"
});
rightTurretCostTxt.anchor.set(0.5, 0);
rightTurretCostTxt.x = rightTurretBtn.x;
rightTurretCostTxt.y = rightTurretBtn.y + 100;
game.addChild(rightTurretCostTxt);
// Base repair and upgrade buttons
var repairBtn = LK.getAsset('repair', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 350,
y: bottomY,
scaleX: 0.7,
scaleY: 0.7
});
var upgradeBtn = LK.getAsset('upgrade', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 350,
y: bottomY,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(repairBtn);
game.addChild(upgradeBtn);
var repairCostTxt = new Text2("Repair: 15", {
size: 60,
fill: "#fff"
});
repairCostTxt.anchor.set(0.5, 0);
repairCostTxt.x = repairBtn.x;
repairCostTxt.y = repairBtn.y + 100;
game.addChild(repairCostTxt);
var upgradeCostTxt = new Text2("Upgrade: 40", {
size: 60,
fill: "#fff"
});
upgradeCostTxt.anchor.set(0.5, 0);
upgradeCostTxt.x = upgradeBtn.x;
upgradeCostTxt.y = upgradeBtn.y + 100;
game.addChild(upgradeCostTxt);
// Turret upgrade buttons (appear above turrets)
function showTurretUpgradeBtn(turret) {
if (turret.upgradeBtn) {
return;
}
var btn = LK.getAsset('turret', {
anchorX: 0.5,
anchorY: 0.5,
x: turret.x,
y: turret.y - 120,
scaleX: 0.6,
scaleY: 0.6
});
var txt = new Text2("Upgrade: 25", {
size: 50,
fill: "#fff"
});
txt.anchor.set(0.5, 0);
txt.x = btn.x;
txt.y = btn.y + 50;
btn._upgradeTxt = txt;
game.addChild(btn);
game.addChild(txt);
turret.upgradeBtn = btn;
turret.upgradeTxt = txt;
}
// Remove upgrade button
function hideTurretUpgradeBtn(turret) {
if (turret.upgradeBtn) {
turret.upgradeBtn.destroy();
turret.upgradeTxt.destroy();
turret.upgradeBtn = null;
turret.upgradeTxt = null;
}
}
// Place initial turrets
function placeTurret(side) {
// Count how many turrets already exist on this side
var count = 0;
for (var i = 0; i < turrets.length; i++) {
if (turrets[i].side === side) {
count++;
}
}
// Place the first turret at center, then alternate above/below
var x = base.x + (side === 1 ? 300 : -300);
var y = base.y;
if (count > 0) {
// Alternate above and below, spacing by 180px
var offset = 180 * Math.ceil(count / 2);
if (count % 2 === 1) {
y = base.y - offset; // above
} else {
y = base.y + offset; // below
}
}
var t = new Turret();
t.x = x;
t.y = y;
t.side = side;
// Reverse the image for the left turret
if (side === -1 && t.children && t.children.length > 0) {
// Assume the first child is the turret graphics
if (typeof t.children[0].scaleX !== "undefined") {
t.children[0].scaleX = -1 * Math.abs(t.children[0].scaleX);
}
}
turrets.push(t);
game.addChild(t);
return t;
}
// Initial turrets
placeTurret(-1);
placeTurret(1);
// Handle turret placement
leftTurretBtn.down = function (x, y, obj) {
if (gold >= 30) {
var t = placeTurret(-1);
gold -= 30;
goldTxt.setText("Gold: " + gold);
}
};
rightTurretBtn.down = function (x, y, obj) {
if (gold >= 30) {
var t = placeTurret(1);
gold -= 30;
goldTxt.setText("Gold: " + gold);
}
};
// Handle base repair/upgrade
repairBtn.down = function (x, y, obj) {
if (gold >= 15 && base.hp < base.maxHp) {
base.repair();
gold -= 15;
goldTxt.setText("Gold: " + gold);
// HP text removed, no update needed here
}
};
upgradeBtn.down = function (x, y, obj) {
if (gold >= 40) {
base.upgrade();
gold -= 40;
goldTxt.setText("Gold: " + gold);
// HP text removed, no update needed here
}
};
// Handle turret upgrade
game.down = function (x, y, obj) {
// Check if a turret was tapped
for (var i = 0; i < turrets.length; i++) {
var t = turrets[i];
if (t && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t, {
x: x,
y: y
})) {
selectedTurret = t;
showTurretUpgradeBtn(t);
return;
}
}
// Check if upgrade button was tapped
for (var i = 0; i < turrets.length; i++) {
var t = turrets[i];
if (t && t.upgradeBtn && LK.util && typeof LK.util.containsPoint === "function" && LK.util.containsPoint(t.upgradeBtn, {
x: x,
y: y
})) {
if (gold >= 25 && t.level < 3) {
t.upgrade();
gold -= 25;
goldTxt.setText("Gold: " + gold);
if (t.level >= 3) {
hideTurretUpgradeBtn(t);
}
}
return;
}
}
// Deselect turret if tap elsewhere
for (var i = 0; i < turrets.length; i++) {
hideTurretUpgradeBtn(turrets[i]);
}
selectedTurret = null;
};
// Enemy spawn logic
function startWave() {
waveInProgress = true;
enemiesToSpawn = Math.floor(enemiesPerWave + (wave - 1) * 4.5); // more enemies per wave, longer waves
enemiesSpawned = 0;
spawnTimer = 0;
waveTxt.setText("Wave: " + wave);
}
function endWave() {
waveInProgress = false;
nextWaveTimer = 120; // 2 seconds
gold += 20 + wave * 5;
goldTxt.setText("Gold: " + gold);
enemiesPerWave += 4; // increase more per wave, longer waves
wave += 1;
}
// Main update loop
game.update = function () {
// Update HP bar position and width
baseHpBarOutline.x = base.x;
baseHpBarOutline.y = base.y - 190;
baseHpBarBg.x = base.x;
baseHpBarBg.y = base.y - 190;
// Health bar shrinks left-to-right as base takes damage
var hpRatio = Math.max(0, base.hp) / base.maxHp;
baseHpBar.width = 200 * hpRatio;
baseHpBar.x = base.x - 100; // left edge stays fixed
baseHpBar.y = base.y - 190;
// Update turrets
for (var i = 0; i < turrets.length; i++) {
turrets[i].update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Check if reached base
if (e.direction === 1 && e.x >= base.x - 90 || e.direction === -1 && e.x <= base.x + 90) {
base.hp -= 1;
base.hit();
e.destroy();
enemies.splice(i, 1);
if (base.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
continue;
}
// Check if dead
if (e.hp <= 0) {
e.destroy();
enemies.splice(i, 1);
if (Math.random() < 0.4) {
// 40% chance to get gold per enemy
gold += 5;
goldTxt.setText("Gold: " + gold);
}
continue;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
if (b.destroyed) {
b.destroy();
bullets.splice(i, 1);
}
}
// Wave logic
if (waveInProgress) {
if (enemiesSpawned < enemiesToSpawn) {
if (spawnTimer <= 0) {
// Spawn enemy from left or right
var side = Math.random() < 0.5 ? -1 : 1;
var EnemyClass = Enemy;
EnemyClass.prototype.direction = side; // Set direction before instantiation for asset selection
var e = new EnemyClass();
e.direction = side;
e.x = side === 1 ? 0 : 2048;
e.y = base.y - 200 + Math.random() * 400;
// Make enemies slower and waves harder: lower base speed, increase HP and spawn more per wave
e.speed = 1.5 + wave * 0.15 + Math.random() * 0.5; // slower base, less scaling
e.hp = 2 + Math.floor(wave * 1.2); // more HP per wave
enemies.push(e);
game.addChild(e);
enemiesSpawned++;
spawnTimer = 36 + Math.floor(Math.random() * 24); // slightly slower spawn rate
} else {
spawnTimer--;
}
} else if (enemies.length === 0) {
endWave();
}
} else {
if (nextWaveTimer > 0) {
nextWaveTimer--;
if (nextWaveTimer === 0) {
startWave();
}
}
}
};
// Start first wave
startWave(); ===================================================================
--- original.js
+++ change.js
@@ -40,13 +40,13 @@
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Attach bullet asset (box, yellow)
var bulletGraphics = self.attachAsset('bullet', {
- anchorX: 0.5,
- anchorY: 0.5
+ anchorX: -2,
+ anchorY: 2
});
- bulletGraphics.width = 40;
- bulletGraphics.height = 40;
+ bulletGraphics.width = 20;
+ bulletGraphics.height = 20;
bulletGraphics.color = 0xb8b031;
self.speed = 24;
self.target = null;
self.side = 1;
@@ -75,20 +75,14 @@
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach enemy asset (ellipse, red)
- var enemyGraphics = self.attachAsset('enemy', {
+ // Use separate images for left- and right-spawned enemies
+ var assetId = self.direction === -1 ? 'enemyLeft' : 'enemyRight';
+ var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
- // Reverse the image ONLY for left-spawned enemies
- if (typeof enemyGraphics.scaleX !== "undefined") {
- if (self.direction === -1) {
- enemyGraphics.scaleX = -1 * Math.abs(enemyGraphics.scaleX); // Reverse for left-spawned
- } else {
- enemyGraphics.scaleX = Math.abs(enemyGraphics.scaleX); // Normal for right-spawned
- }
- }
// Set size and color
enemyGraphics.width = 90;
enemyGraphics.height = 90;
enemyGraphics.color = 0xd83318;
@@ -545,9 +539,11 @@
if (enemiesSpawned < enemiesToSpawn) {
if (spawnTimer <= 0) {
// Spawn enemy from left or right
var side = Math.random() < 0.5 ? -1 : 1;
- var e = new Enemy();
+ var EnemyClass = Enemy;
+ EnemyClass.prototype.direction = side; // Set direction before instantiation for asset selection
+ var e = new EnemyClass();
e.direction = side;
e.x = side === 1 ? 0 : 2048;
e.y = base.y - 200 + Math.random() * 400;
// Make enemies slower and waves harder: lower base speed, increase HP and spawn more per wave
2d turret. In-Game asset. 2d. High contrast. No shadows
a 2d turret base. In-Game asset. 2d. High contrast. No shadows
a 2d upgrade button png. In-Game asset. 2d. High contrast. No shadows
purple zombie 2d. In-Game asset. 2d. High contrast. No shadows
add a grass background, empty middle, grass and trees around. In-Game asset. 2d. High contrast. No shadows