User prompt
Towers should be destroyed after taking 4 hits, playing a destruction sound. The main building should be destroyed after 10 hits, ending the game and showing a “You Lost, Restart” screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The arrows shot by the character should play an arrow impact sound upon hitting.
User prompt
The main hero should shoot arrows, with a shooting range three times the range of the towers. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When enemies touch the tower, the tower should blink red to indicate damage. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Isometric stylized tower defense game scene at the climax of battle, central fantasy tower heavily damaged with cracks and smoke, hero character collapsed on the ground or surrounded by enemies, visual indicators of game over state, enemies overrun the area, dramatic lighting, red alert glow, magical projectiles and arrows in the air, muzzle flashes and fire bursts from cannons, cartoon-style explosion effects, vibrant and intense fantasy colors, stylized hand-painted textures, battlefield filled with action and destruction ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Isometric fantasy battle scene, stylized monsters charging toward the nearest target, some attacking a central hero with a sword, others moving toward archer and cannon towers, glowing red eyes, dust clouds and motion lines to show movement, vivid colors, stylized cartoon shading, hand-painted textures, fantasy battlefield environment with grass and rocky ground, dynamic action moment ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
with a large magical attack radius visualized as glowing circular aura around the tower, extended range indicators, arrows or energy beams reaching far enemies, wide attack radius effects ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Top-down view of a stylized game environment with animated grass, replacing plain green background with lush, hand-painted grass textures, gentle wind effect causing grass to sway, vibrant and saturated colors, loopable animation frames, isometric or top-down angle, perfect for fantasy strategy or tower defense games, seamless tileable design, cartoon-inspired shading ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Crystal Citadel Defense
Initial prompt
Isometric fantasy tower defense game scene, a stylized central magic tower standing in the middle of a battlefield, surrounded by attacking fantasy monsters (goblins, trolls, skeletons), vibrant colors, stylized lighting, fantasy environment with rocky terrain and grass patches, small defense towers (archer and cannon types) placed around, gold coins scattered on the ground, magical attack effects from the main tower, hero character fighting in the middle, action-packed moment, high detail, game asset style, perfect for use in Unity or Godot, top-down isometric view
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var CrystalTower = Container.expand(function () { var self = Container.call(this); self.health = 500; self.maxHealth = 500; self.range = 200; self.damage = 40; self.fireRate = 30; self.lastShot = 0; var graphics = self.attachAsset('crystalTower', { anchorX: 0.5, anchorY: 1 }); self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xff0000, 500); if (self.health <= 0) { LK.showGameOver(); } }; self.findTarget = function () { var closest = 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 < closestDistance) { closest = enemy; closestDistance = distance; } } return closest; }; self.shoot = function (target) { if (LK.ticks - self.lastShot >= self.fireRate) { var projectile = new TowerProjectile(); projectile.x = self.x; projectile.y = self.y - 60; projectile.target = target; projectile.damage = self.damage; game.addChild(projectile); towerProjectiles.push(projectile); self.lastShot = LK.ticks; LK.getSound('towerShoot').play(); } }; self.update = function () { var target = self.findTarget(); if (target) { self.shoot(target); } }; return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.enemyType = type || 'goblin'; self.health = 100; self.maxHealth = 100; self.speed = 1; self.goldValue = 10; if (self.enemyType === 'goblin') { self.health = 80; self.maxHealth = 80; self.speed = 1.5; self.goldValue = 15; var graphics = self.attachAsset('goblin', { anchorX: 0.5, anchorY: 1 }); } else if (self.enemyType === 'troll') { self.health = 200; self.maxHealth = 200; self.speed = 0.8; self.goldValue = 30; var graphics = self.attachAsset('troll', { anchorX: 0.5, anchorY: 1 }); } else if (self.enemyType === 'skeleton') { self.health = 120; self.maxHealth = 120; self.speed = 1.2; self.goldValue = 20; var graphics = self.attachAsset('skeleton', { anchorX: 0.5, anchorY: 1 }); } self.targetX = 1024; self.targetY = 1366; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { var coin = new GoldCoin(); coin.x = self.x; coin.y = self.y; coin.value = self.goldValue; game.addChild(coin); goldCoins.push(coin); LK.getSound('enemyDeath').play(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); }; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { crystalTower.takeDamage(20); self.die(); } }; return self; }); var GoldCoin = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('goldCoin', { anchorX: 0.5, anchorY: 0.5 }); self.value = 10; self.collected = false; self.collect = function () { if (!self.collected) { self.collected = true; gold += self.value; goldText.setText('Gold: ' + gold); LK.getSound('coinCollect').play(); for (var i = goldCoins.length - 1; i >= 0; i--) { if (goldCoins[i] === self) { goldCoins.splice(i, 1); break; } } self.destroy(); } }; self.down = function (x, y, obj) { self.collect(); }; return self; }); var Hero = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 1 }); self.speed = 3; self.range = 100; self.damage = 35; self.fireRate = 20; self.lastShot = 0; self.findTarget = function () { var closest = 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 < closestDistance) { closest = enemy; closestDistance = distance; } } return closest; }; self.shoot = function (target) { if (LK.ticks - self.lastShot >= self.fireRate) { var projectile = new HeroProjectile(); projectile.x = self.x; projectile.y = self.y - 25; projectile.target = target; projectile.damage = self.damage; game.addChild(projectile); heroProjectiles.push(projectile); self.lastShot = LK.ticks; } }; self.update = function () { var target = self.findTarget(); if (target) { self.shoot(target); } }; return self; }); var HeroProjectile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('heroProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.target = null; self.damage = 35; self.update = function () { if (!self.target || self.target.destroyed) { self.destroy(); for (var i = heroProjectiles.length - 1; i >= 0; i--) { if (heroProjectiles[i] === self) { heroProjectiles.splice(i, 1); break; } } 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 < 20) { self.target.takeDamage(self.damage); self.destroy(); for (var i = heroProjectiles.length - 1; i >= 0; i--) { if (heroProjectiles[i] === self) { heroProjectiles.splice(i, 1); break; } } } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); var Tower = Container.expand(function (type) { var self = Container.call(this); self.towerType = type || 'archer'; self.range = 150; self.damage = 25; self.fireRate = 60; self.lastShot = 0; if (self.towerType === 'archer') { self.range = 180; self.damage = 30; self.fireRate = 45; var graphics = self.attachAsset('archerTower', { anchorX: 0.5, anchorY: 1 }); } else if (self.towerType === 'cannon') { self.range = 120; self.damage = 60; self.fireRate = 90; var graphics = self.attachAsset('cannonTower', { anchorX: 0.5, anchorY: 1 }); } self.findTarget = function () { var closest = 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 < closestDistance) { closest = enemy; closestDistance = distance; } } return closest; }; self.shoot = function (target) { if (LK.ticks - self.lastShot >= self.fireRate) { var projectile = new TowerProjectile(); projectile.x = self.x; projectile.y = self.y - 40; projectile.target = target; projectile.damage = self.damage; game.addChild(projectile); towerProjectiles.push(projectile); self.lastShot = LK.ticks; LK.getSound('towerShoot').play(); } }; self.update = function () { var target = self.findTarget(); if (target) { self.shoot(target); } }; return self; }); var TowerProjectile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('towerProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.target = null; self.damage = 25; self.update = function () { if (!self.target || self.target.destroyed) { self.destroy(); for (var i = towerProjectiles.length - 1; i >= 0; i--) { if (towerProjectiles[i] === self) { towerProjectiles.splice(i, 1); break; } } 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 < 20) { self.target.takeDamage(self.damage); self.destroy(); for (var i = towerProjectiles.length - 1; i >= 0; i--) { if (towerProjectiles[i] === self) { towerProjectiles.splice(i, 1); break; } } } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a4d1a }); /**** * Game Code ****/ var enemies = []; var towers = []; var towerProjectiles = []; var heroProjectiles = []; var goldCoins = []; var crystalTower; var hero; var gold = 100; var wave = 1; var enemiesInWave = 5; var enemySpawnTimer = 0; var enemiesSpawned = 0; var waveComplete = false; var draggedHero = false; // Create crystal tower at center crystalTower = new CrystalTower(); crystalTower.x = 1024; crystalTower.y = 1366; game.addChild(crystalTower); // Create hero hero = new Hero(); hero.x = 900; hero.y = 1200; game.addChild(hero); // UI Elements var goldText = new Text2('Gold: ' + gold, { size: 60, fill: 0xFFD700 }); goldText.anchor.set(0, 0); LK.gui.topRight.addChild(goldText); goldText.x = -200; goldText.y = 20; var waveText = new Text2('Wave: ' + wave, { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(0, 0); LK.gui.top.addChild(waveText); waveText.x = -100; waveText.y = 20; var healthText = new Text2('Tower HP: ' + crystalTower.health, { size: 50, fill: 0x00FFFF }); healthText.anchor.set(0, 0); LK.gui.bottom.addChild(healthText); healthText.x = -150; healthText.y = -80; // Tower placement UI var archerButton = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5 }); archerButton.x = 150; archerButton.y = -150; LK.gui.bottom.addChild(archerButton); var archerText = new Text2('Archer\n50g', { size: 30, fill: 0xFFFFFF }); archerText.anchor.set(0.5, 0.5); archerButton.addChild(archerText); var cannonButton = LK.getAsset('uiPanel', { anchorX: 0.5, anchorY: 0.5 }); cannonButton.x = 400; cannonButton.y = -150; LK.gui.bottom.addChild(cannonButton); var cannonText = new Text2('Cannon\n80g', { size: 30, fill: 0xFFFFFF }); cannonText.anchor.set(0.5, 0.5); cannonButton.addChild(cannonText); // Tower placement handlers archerButton.down = function (x, y, obj) { if (gold >= 50) { placingTowerType = 'archer'; placingTowerCost = 50; } }; cannonButton.down = function (x, y, obj) { if (gold >= 80) { placingTowerType = 'cannon'; placingTowerCost = 80; } }; var placingTowerType = null; var placingTowerCost = 0; function spawnEnemy() { var enemyTypes = ['goblin', 'goblin', 'skeleton']; if (wave >= 3) enemyTypes.push('troll'); if (wave >= 5) enemyTypes.push('troll', 'troll'); var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(randomType); // Spawn from random edge var side = Math.floor(Math.random() * 4); if (side === 0) { // Top enemy.x = Math.random() * 2048; enemy.y = 0; } else if (side === 1) { // Right enemy.x = 2048; enemy.y = Math.random() * 2732; } else if (side === 2) { // Bottom enemy.x = Math.random() * 2048; enemy.y = 2732; } else { // Left enemy.x = 0; enemy.y = Math.random() * 2732; } game.addChild(enemy); enemies.push(enemy); enemiesSpawned++; } function checkWaveComplete() { if (enemiesSpawned >= enemiesInWave && enemies.length === 0) { waveComplete = true; wave++; enemiesInWave += 2; enemiesSpawned = 0; waveComplete = false; waveText.setText('Wave: ' + wave); if (wave > 10) { LK.showYouWin(); } } } game.down = function (x, y, obj) { if (placingTowerType) { // Check if position is valid (not too close to crystal tower or other towers) var tooClose = false; var dx = x - crystalTower.x; var dy = y - crystalTower.y; if (Math.sqrt(dx * dx + dy * dy) < 200) { tooClose = true; } for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var dx = x - tower.x; var dy = y - tower.y; if (Math.sqrt(dx * dx + dy * dy) < 120) { tooClose = true; break; } } if (!tooClose) { var newTower = new Tower(placingTowerType); newTower.x = x; newTower.y = y; game.addChild(newTower); towers.push(newTower); gold -= placingTowerCost; goldText.setText('Gold: ' + gold); LK.getSound('towerPlace').play(); } placingTowerType = null; placingTowerCost = 0; } else { // Check if clicking on hero to start drag var dx = x - hero.x; var dy = y - hero.y; if (Math.sqrt(dx * dx + dy * dy) < 50) { draggedHero = true; } } }; game.move = function (x, y, obj) { if (draggedHero) { hero.x = x; hero.y = y; } }; game.up = function (x, y, obj) { draggedHero = false; }; game.update = function () { // Spawn enemies if (enemiesSpawned < enemiesInWave) { enemySpawnTimer++; if (enemySpawnTimer >= 120) { // Spawn every 2 seconds spawnEnemy(); enemySpawnTimer = 0; } } // Update health display healthText.setText('Tower HP: ' + crystalTower.health); // Check for hero collecting coins for (var i = goldCoins.length - 1; i >= 0; i--) { var coin = goldCoins[i]; var dx = coin.x - hero.x; var dy = coin.y - hero.y; if (Math.sqrt(dx * dx + dy * dy) < 40) { coin.collect(); } } checkWaveComplete(); };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,563 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var CrystalTower = Container.expand(function () {
+ var self = Container.call(this);
+ self.health = 500;
+ self.maxHealth = 500;
+ self.range = 200;
+ self.damage = 40;
+ self.fireRate = 30;
+ self.lastShot = 0;
+ var graphics = self.attachAsset('crystalTower', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ LK.effects.flashObject(self, 0xff0000, 500);
+ if (self.health <= 0) {
+ LK.showGameOver();
+ }
+ };
+ self.findTarget = function () {
+ var closest = 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 < closestDistance) {
+ closest = enemy;
+ closestDistance = distance;
+ }
+ }
+ return closest;
+ };
+ self.shoot = function (target) {
+ if (LK.ticks - self.lastShot >= self.fireRate) {
+ var projectile = new TowerProjectile();
+ projectile.x = self.x;
+ projectile.y = self.y - 60;
+ projectile.target = target;
+ projectile.damage = self.damage;
+ game.addChild(projectile);
+ towerProjectiles.push(projectile);
+ self.lastShot = LK.ticks;
+ LK.getSound('towerShoot').play();
+ }
+ };
+ self.update = function () {
+ var target = self.findTarget();
+ if (target) {
+ self.shoot(target);
+ }
+ };
+ return self;
+});
+var Enemy = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.enemyType = type || 'goblin';
+ self.health = 100;
+ self.maxHealth = 100;
+ self.speed = 1;
+ self.goldValue = 10;
+ if (self.enemyType === 'goblin') {
+ self.health = 80;
+ self.maxHealth = 80;
+ self.speed = 1.5;
+ self.goldValue = 15;
+ var graphics = self.attachAsset('goblin', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ } else if (self.enemyType === 'troll') {
+ self.health = 200;
+ self.maxHealth = 200;
+ self.speed = 0.8;
+ self.goldValue = 30;
+ var graphics = self.attachAsset('troll', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ } else if (self.enemyType === 'skeleton') {
+ self.health = 120;
+ self.maxHealth = 120;
+ self.speed = 1.2;
+ self.goldValue = 20;
+ var graphics = self.attachAsset('skeleton', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ }
+ self.targetX = 1024;
+ self.targetY = 1366;
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ if (self.health <= 0) {
+ self.die();
+ }
+ };
+ self.die = function () {
+ var coin = new GoldCoin();
+ coin.x = self.x;
+ coin.y = self.y;
+ coin.value = self.goldValue;
+ game.addChild(coin);
+ goldCoins.push(coin);
+ LK.getSound('enemyDeath').play();
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ if (enemies[i] === self) {
+ enemies.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ };
+ self.update = function () {
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 5) {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ } else {
+ crystalTower.takeDamage(20);
+ self.die();
+ }
+ };
+ return self;
+});
+var GoldCoin = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('goldCoin', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.value = 10;
+ self.collected = false;
+ self.collect = function () {
+ if (!self.collected) {
+ self.collected = true;
+ gold += self.value;
+ goldText.setText('Gold: ' + gold);
+ LK.getSound('coinCollect').play();
+ for (var i = goldCoins.length - 1; i >= 0; i--) {
+ if (goldCoins[i] === self) {
+ goldCoins.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ }
+ };
+ self.down = function (x, y, obj) {
+ self.collect();
+ };
+ return self;
+});
+var Hero = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('hero', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.speed = 3;
+ self.range = 100;
+ self.damage = 35;
+ self.fireRate = 20;
+ self.lastShot = 0;
+ self.findTarget = function () {
+ var closest = 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 < closestDistance) {
+ closest = enemy;
+ closestDistance = distance;
+ }
+ }
+ return closest;
+ };
+ self.shoot = function (target) {
+ if (LK.ticks - self.lastShot >= self.fireRate) {
+ var projectile = new HeroProjectile();
+ projectile.x = self.x;
+ projectile.y = self.y - 25;
+ projectile.target = target;
+ projectile.damage = self.damage;
+ game.addChild(projectile);
+ heroProjectiles.push(projectile);
+ self.lastShot = LK.ticks;
+ }
+ };
+ self.update = function () {
+ var target = self.findTarget();
+ if (target) {
+ self.shoot(target);
+ }
+ };
+ return self;
+});
+var HeroProjectile = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('heroProjectile', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 10;
+ self.target = null;
+ self.damage = 35;
+ self.update = function () {
+ if (!self.target || self.target.destroyed) {
+ self.destroy();
+ for (var i = heroProjectiles.length - 1; i >= 0; i--) {
+ if (heroProjectiles[i] === self) {
+ heroProjectiles.splice(i, 1);
+ break;
+ }
+ }
+ 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 < 20) {
+ self.target.takeDamage(self.damage);
+ self.destroy();
+ for (var i = heroProjectiles.length - 1; i >= 0; i--) {
+ if (heroProjectiles[i] === self) {
+ heroProjectiles.splice(i, 1);
+ break;
+ }
+ }
+ } else {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ }
+ };
+ return self;
+});
+var Tower = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.towerType = type || 'archer';
+ self.range = 150;
+ self.damage = 25;
+ self.fireRate = 60;
+ self.lastShot = 0;
+ if (self.towerType === 'archer') {
+ self.range = 180;
+ self.damage = 30;
+ self.fireRate = 45;
+ var graphics = self.attachAsset('archerTower', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ } else if (self.towerType === 'cannon') {
+ self.range = 120;
+ self.damage = 60;
+ self.fireRate = 90;
+ var graphics = self.attachAsset('cannonTower', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ }
+ self.findTarget = function () {
+ var closest = 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 < closestDistance) {
+ closest = enemy;
+ closestDistance = distance;
+ }
+ }
+ return closest;
+ };
+ self.shoot = function (target) {
+ if (LK.ticks - self.lastShot >= self.fireRate) {
+ var projectile = new TowerProjectile();
+ projectile.x = self.x;
+ projectile.y = self.y - 40;
+ projectile.target = target;
+ projectile.damage = self.damage;
+ game.addChild(projectile);
+ towerProjectiles.push(projectile);
+ self.lastShot = LK.ticks;
+ LK.getSound('towerShoot').play();
+ }
+ };
+ self.update = function () {
+ var target = self.findTarget();
+ if (target) {
+ self.shoot(target);
+ }
+ };
+ return self;
+});
+var TowerProjectile = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('towerProjectile', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.target = null;
+ self.damage = 25;
+ self.update = function () {
+ if (!self.target || self.target.destroyed) {
+ self.destroy();
+ for (var i = towerProjectiles.length - 1; i >= 0; i--) {
+ if (towerProjectiles[i] === self) {
+ towerProjectiles.splice(i, 1);
+ break;
+ }
+ }
+ 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 < 20) {
+ self.target.takeDamage(self.damage);
+ self.destroy();
+ for (var i = towerProjectiles.length - 1; i >= 0; i--) {
+ if (towerProjectiles[i] === self) {
+ towerProjectiles.splice(i, 1);
+ break;
+ }
+ }
+ } else {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x1a4d1a
+});
+
+/****
+* Game Code
+****/
+var enemies = [];
+var towers = [];
+var towerProjectiles = [];
+var heroProjectiles = [];
+var goldCoins = [];
+var crystalTower;
+var hero;
+var gold = 100;
+var wave = 1;
+var enemiesInWave = 5;
+var enemySpawnTimer = 0;
+var enemiesSpawned = 0;
+var waveComplete = false;
+var draggedHero = false;
+// Create crystal tower at center
+crystalTower = new CrystalTower();
+crystalTower.x = 1024;
+crystalTower.y = 1366;
+game.addChild(crystalTower);
+// Create hero
+hero = new Hero();
+hero.x = 900;
+hero.y = 1200;
+game.addChild(hero);
+// UI Elements
+var goldText = new Text2('Gold: ' + gold, {
+ size: 60,
+ fill: 0xFFD700
+});
+goldText.anchor.set(0, 0);
+LK.gui.topRight.addChild(goldText);
+goldText.x = -200;
+goldText.y = 20;
+var waveText = new Text2('Wave: ' + wave, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+waveText.anchor.set(0, 0);
+LK.gui.top.addChild(waveText);
+waveText.x = -100;
+waveText.y = 20;
+var healthText = new Text2('Tower HP: ' + crystalTower.health, {
+ size: 50,
+ fill: 0x00FFFF
+});
+healthText.anchor.set(0, 0);
+LK.gui.bottom.addChild(healthText);
+healthText.x = -150;
+healthText.y = -80;
+// Tower placement UI
+var archerButton = LK.getAsset('uiPanel', {
+ anchorX: 0.5,
+ anchorY: 0.5
+});
+archerButton.x = 150;
+archerButton.y = -150;
+LK.gui.bottom.addChild(archerButton);
+var archerText = new Text2('Archer\n50g', {
+ size: 30,
+ fill: 0xFFFFFF
+});
+archerText.anchor.set(0.5, 0.5);
+archerButton.addChild(archerText);
+var cannonButton = LK.getAsset('uiPanel', {
+ anchorX: 0.5,
+ anchorY: 0.5
+});
+cannonButton.x = 400;
+cannonButton.y = -150;
+LK.gui.bottom.addChild(cannonButton);
+var cannonText = new Text2('Cannon\n80g', {
+ size: 30,
+ fill: 0xFFFFFF
+});
+cannonText.anchor.set(0.5, 0.5);
+cannonButton.addChild(cannonText);
+// Tower placement handlers
+archerButton.down = function (x, y, obj) {
+ if (gold >= 50) {
+ placingTowerType = 'archer';
+ placingTowerCost = 50;
+ }
+};
+cannonButton.down = function (x, y, obj) {
+ if (gold >= 80) {
+ placingTowerType = 'cannon';
+ placingTowerCost = 80;
+ }
+};
+var placingTowerType = null;
+var placingTowerCost = 0;
+function spawnEnemy() {
+ var enemyTypes = ['goblin', 'goblin', 'skeleton'];
+ if (wave >= 3) enemyTypes.push('troll');
+ if (wave >= 5) enemyTypes.push('troll', 'troll');
+ var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
+ var enemy = new Enemy(randomType);
+ // Spawn from random edge
+ var side = Math.floor(Math.random() * 4);
+ if (side === 0) {
+ // Top
+ enemy.x = Math.random() * 2048;
+ enemy.y = 0;
+ } else if (side === 1) {
+ // Right
+ enemy.x = 2048;
+ enemy.y = Math.random() * 2732;
+ } else if (side === 2) {
+ // Bottom
+ enemy.x = Math.random() * 2048;
+ enemy.y = 2732;
+ } else {
+ // Left
+ enemy.x = 0;
+ enemy.y = Math.random() * 2732;
+ }
+ game.addChild(enemy);
+ enemies.push(enemy);
+ enemiesSpawned++;
+}
+function checkWaveComplete() {
+ if (enemiesSpawned >= enemiesInWave && enemies.length === 0) {
+ waveComplete = true;
+ wave++;
+ enemiesInWave += 2;
+ enemiesSpawned = 0;
+ waveComplete = false;
+ waveText.setText('Wave: ' + wave);
+ if (wave > 10) {
+ LK.showYouWin();
+ }
+ }
+}
+game.down = function (x, y, obj) {
+ if (placingTowerType) {
+ // Check if position is valid (not too close to crystal tower or other towers)
+ var tooClose = false;
+ var dx = x - crystalTower.x;
+ var dy = y - crystalTower.y;
+ if (Math.sqrt(dx * dx + dy * dy) < 200) {
+ tooClose = true;
+ }
+ for (var i = 0; i < towers.length; i++) {
+ var tower = towers[i];
+ var dx = x - tower.x;
+ var dy = y - tower.y;
+ if (Math.sqrt(dx * dx + dy * dy) < 120) {
+ tooClose = true;
+ break;
+ }
+ }
+ if (!tooClose) {
+ var newTower = new Tower(placingTowerType);
+ newTower.x = x;
+ newTower.y = y;
+ game.addChild(newTower);
+ towers.push(newTower);
+ gold -= placingTowerCost;
+ goldText.setText('Gold: ' + gold);
+ LK.getSound('towerPlace').play();
+ }
+ placingTowerType = null;
+ placingTowerCost = 0;
+ } else {
+ // Check if clicking on hero to start drag
+ var dx = x - hero.x;
+ var dy = y - hero.y;
+ if (Math.sqrt(dx * dx + dy * dy) < 50) {
+ draggedHero = true;
+ }
+ }
+};
+game.move = function (x, y, obj) {
+ if (draggedHero) {
+ hero.x = x;
+ hero.y = y;
+ }
+};
+game.up = function (x, y, obj) {
+ draggedHero = false;
+};
+game.update = function () {
+ // Spawn enemies
+ if (enemiesSpawned < enemiesInWave) {
+ enemySpawnTimer++;
+ if (enemySpawnTimer >= 120) {
+ // Spawn every 2 seconds
+ spawnEnemy();
+ enemySpawnTimer = 0;
+ }
+ }
+ // Update health display
+ healthText.setText('Tower HP: ' + crystalTower.health);
+ // Check for hero collecting coins
+ for (var i = goldCoins.length - 1; i >= 0; i--) {
+ var coin = goldCoins[i];
+ var dx = coin.x - hero.x;
+ var dy = coin.y - hero.y;
+ if (Math.sqrt(dx * dx + dy * dy) < 40) {
+ coin.collect();
+ }
+ }
+ checkWaveComplete();
+};
\ No newline at end of file
izometric cannon tower. In-Game asset. 2d. High contrast. No shadows. izometric
archerTower. In-Game asset. 2d. High contrast. No shadows
goblin. In-Game asset. 2d. High contrast. No shadows
goldCoin. In-Game asset. 2d. High contrast. No shadows
Archer hero. In-Game asset. 2d. High contrast. No shadows
skeleton. In-Game asset. 2d. High contrast. No shadows
troll. In-Game asset. 2d. High contrast. No shadows
single arrow image. In-Game asset. 2d. High contrast. No shadows
Create a flying dragon enemy with the following features:. In-Game asset. 2d. High contrast. No shadows
Here’s a prompt for a very distant, wide-angle view of a tree-free forest floor: **Prompt:** A very distant, wide-angle aerial view of a tree-free forest floor, showing expansive grassy plains with patches of dirt, scattered rocks, and low vegetation. The terrain stretches far into the horizon with subtle color variations and soft natural lighting, creating a vast, open, and serene natural environment without any trees.. In-Game asset. 2d. High contrast. No shadows
A stylized full-body illustration of a small hobbit holding a glowing ring in one hand, viewed from a 45-degree angle. The hobbit has curly hair, bare feet, and wears rustic, earth-toned clothing with detailed textures. The scene has warm, soft lighting emphasizing the character’s expressive face and the shining ring. The art style is cartoonish with rich colors, smooth shading, and a fantasy atmosphere.. In-Game asset. 2d. High contrast. No shadows
A magical yellow light glowing softly, with radiant beams and sparkling particles floating around. The light has a warm, enchanting aura that illuminates its surroundings with a golden hue. The atmosphere feels mystical and inviting, perfect for fantasy scenes or magical effects.. In-Game asset. 2d. High contrast. No shadows
A full-body stylized illustration of Smeagol (Gollum), showing his thin, hunched frame and large expressive eyes. He is barefoot and shirtless, wearing ragged shorts, with exaggerated cartoonish features that highlight his creepy yet pitiful nature. He clutches a glowing precious ring tightly in one hand. The art style is dark fantasy with vibrant colors, detailed skin textures, and a shadowy, mysterious background to enhance the eerie atmosphere. Perfect for full-character concept art or game design.. In-Game asset. 2d. High contrast. No shadows
A full-body stylized illustration of an orc warrior, standing in a dynamic pose. The orc has green or grayish skin, muscular build, tusks, and tribal armor made of bone, leather, and metal. The style is fantasy-themed with bold lines, exaggerated proportions, and detailed textures. The lighting is dramatic, emphasizing the orc’s strength and menace. Background is minimal or softly blurred to keep focus on the character. Suitable for fantasy RPG game concept art.. In-Game asset. 2d. High contrast. No shadows
A stylized fantasy axe with a broad, curved blade and intricate engravings. The handle is wrapped in worn leather, and the metal has a slightly weathered look, giving it a battle-worn feel. The design is bold and exaggerated, suitable for an orc warrior, with a glowing rune etched into the blade. The style is high-fantasy with clean lines, vibrant highlights, and a dramatic shadow for depth. Perfect for 2D game assets or concept art.. In-Game asset. 2d. High contrast. No shadows