User prompt
Boss zombinin sağlık barını biraz büyüt.
User prompt
Sağlık barını biraz büyüt.
User prompt
Boss zombinin üzerine sağlık barı ekle.
User prompt
Please fix the bug: 'Uncaught ReferenceError: showInsufficientBalanceWarning is not defined' in or related to this line: 'showInsufficientBalanceWarning(upgradePanel, child, 70);' Line Number: 1392
User prompt
Zombilerin üzerinde küçük bir can barı görünsün.
User prompt
Yine butonlar çalışmıyor. Ne yapılması gerekiyor ise yap. Gerekirse yeni kod yaz.
User prompt
Bu durumu düzelt.
User prompt
Yazıyı 1 satır yukarı kaldır. Ayrıca yazıyı "Don't forget about the main building upgrades!" diye değiştir.
User prompt
Wave yazısının 2 alt satırına "Click on the base image for upgrades" diye küçük bir yazı yaz.
User prompt
Eğer bakiye yetersiz ise, tıklayınca buton üzerinde küçük bir "The balance is insufficient" uyarısı spawn olsun.
User prompt
Base panelinde bulunan Tower Butonunun 2 satır yukarısına, kulelerin saldırı gücünü artırmak için yükseltme butonu ekle. Aynı bizim asker saldırı gücü arttığı gibi. Ayrıca 2 satır üzerine yine Tower Saldırı Hızı artırmak için de buton ekle. Max 5 seviye olsun saldırı hızı.
User prompt
Fire Rate yükseltmesi en fazla 8 seviye olsun.
User prompt
How to play butonunun close tuşu bağımsız olarak, panel başlığının üst satırına taşı.
User prompt
How to play butonunun close tuşu 2.5 satır aşağı insin.
User prompt
How to play paneli içerisine, Boss hakkında bilgi yazısı ekle.
User prompt
Bu zombi boss'u, her 5 ve katları wave'de gelsin. Örn: 5-10-15-20-25.... Gibi.
User prompt
Zombi grubunu, tek bir zombi olarak oluştur. Yani Boss gibi. 20 zombi gücünde olan normal zombilere göre %50 daha büyük olan Boss şeklinde bir zombi türü olsun.
User prompt
Zombiler sıralı halde değil. Karışık halde gelsinler. Sadece aralarında %3'luk boşluk olsun.
User prompt
Toplu halde gelen zombiler 10 adet değil, 20 adet olsun. Her birinin arasında %3 oranında boşluk olsun.
User prompt
Her 5 wave'de anlık güç ile, 10 adet zombi grubu gelsin. Gelen zombiler ayrı yerlerden değil de, aynı yerden gelsin. Gelmeden önce "Zombie invasion!" şeklinde kırmızı uyarı yazısı topluluğu yok edene kadar wave yazısının 4 satır altında spawn olsun.
User prompt
Ses açma kapatma tuşu bütün sesleri açsın kapatsın. Sadece arkaplan sesini değil.
User prompt
Arkaplanın göre resim dosyası oluştur.
User prompt
Base panelinin arkaplan resmini %20 oranında altı uzat.
User prompt
Base panelinin arkaplan resmini, panel boyutunca büyüt.
User prompt
Türkçe yazıları, İngilizce olarak çevir.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Base = Container.expand(function () { var self = Container.call(this); var baseGraphics = self.attachAsset('base', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.takeDamage = function (damage) { self.health -= damage; tween(baseGraphics, { tint: 0xff0000 }, { duration: 100, onFinish: function onFinish() { tween(baseGraphics, { tint: 0xffffff }, { duration: 100 }); } }); if (self.health <= 0) { LK.showGameOver(); } }; self.down = function (x, y, obj) { if (!upgradePanel.visible) { upgradePanel.visible = true; } else { upgradePanel.visible = false; } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 1; self.dx = 0; self.dy = 0; self.setDirection = function (targetX, targetY) { var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.dx = dx / distance * self.speed; self.dy = dy / distance * self.speed; self.rotation = Math.atan2(dy, dx); if (bulletGraphics) { bulletGraphics.rotation = self.rotation; } } }; self.update = function () { self.x += self.dx; self.y += self.dy; if (typeof self.rotation !== "undefined" && bulletGraphics) { bulletGraphics.rotation = self.rotation; } }; return self; }); var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.fireRate = 40; self.fireCooldown = 0; self.update = function () { if (self.fireCooldown > 0) { self.fireCooldown--; } // Find closest zombie for automatic shooting if (self.fireCooldown === 0 && zombies.length > 0) { var closestZombie = null; var closestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestZombie = zombie; } } if (closestZombie) { self.shoot(closestZombie.x, closestZombie.y); } } }; self.shoot = function (targetX, targetY) { if (self.fireCooldown > 0) return; var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.setDirection(targetX, targetY); bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.fireCooldown = self.fireRate; }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.value = 10; self.lifetime = 300; self.update = function () { self.lifetime--; coinGraphics.alpha = Math.min(1, self.lifetime / 100); }; return self; }); var Drone = Container.expand(function () { var self = Container.call(this); var vacuumField = self.attachAsset('vacuumField', { anchorX: 0.5, anchorY: 0.5, alpha: 0.1, scaleX: 0.445, scaleY: 0.445 }); var droneGraphics = self.attachAsset('drone', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.target = null; self.collectRange = 22; // Reduced from 50 to achieve 80% area reduction self.vacuumRange = 89; // Reduced from 200 to achieve 80% area reduction self.vacuumPower = 0.15; // Strength of vacuum pull self.floatOffset = 0; self.floatSpeed = 0.05; self.vx = 0; self.vy = 0; self.update = function () { // Floating animation self.floatOffset += self.floatSpeed; droneGraphics.y = Math.sin(self.floatOffset) * 10; // Vacuum field pulsing animation vacuumField.scaleX = 0.445 + Math.sin(self.floatOffset * 2) * 0.045; vacuumField.scaleY = 0.445 + Math.sin(self.floatOffset * 2) * 0.045; vacuumField.alpha = 0.05 + Math.sin(self.floatOffset * 3) * 0.03; // Find closest coin var closestCoin = null; var closestDistance = Infinity; for (var i = 0; i < coins.length; i++) { var coin = coins[i]; var dx = coin.x - self.x; var dy = coin.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestCoin = coin; } } self.target = closestCoin; // Calculate desired velocity towards target var desiredVx = 0; var desiredVy = 0; if (self.target) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.collectRange) { desiredVx = dx / distance * self.speed; desiredVy = dy / distance * self.speed; } } else { // Return to base when no coins var dx = base.x - self.x; var dy = base.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 150) { desiredVx = dx / distance * self.speed; desiredVy = dy / distance * self.speed; } } // Smoothly interpolate current velocity towards desired velocity self.vx = self.vx * 0.85 + desiredVx * 0.15; self.vy = self.vy * 0.85 + desiredVy * 0.15; // Apply smoothed velocity self.x += self.vx; self.y += self.vy; // Rotate drone based on movement direction if (Math.abs(self.vx) > 0.1 || Math.abs(self.vy) > 0.1) { droneGraphics.rotation = Math.atan2(self.vy, self.vx); } // Apply vacuum effect to nearby coins for (var i = 0; i < coins.length; i++) { var coin = coins[i]; var dx = self.x - coin.x; var dy = self.y - coin.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.vacuumRange && distance > 0) { // Pull coins towards drone var pullStrength = (1 - distance / self.vacuumRange) * self.vacuumPower; coin.x += dx / distance * pullStrength * distance; coin.y += dy / distance * pullStrength * distance; } } }; return self; }); var HowToPlayPanel = Container.expand(function () { var self = Container.call(this); // Background panel var bg = self.attachAsset('upgradePanel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.5 }); bg.tint = 0x222222; // Title var title = new Text2('How to Play', { size: 60, fill: 0xFFFF00 }); title.anchor.set(0.5, 0.5); title.y = -400; self.addChild(title); // Game info text var infoText = new Text2('Welcome to Zombie Defense!\n\n' + '• Tap anywhere to shoot zombies\n' + '• Collect coins from defeated zombies\n' + '• Click the base to open upgrade menu\n' + '• Build towers and traps for defense\n' + '• Survive as many waves as possible!\n\n' + 'Upgrades:\n' + '• Towers - Auto-shoot nearby zombies\n' + '• Traps - Damage zombies on contact\n' + '• Base Repair - Restore base health\n' + '• Fire Power - Increase damage\n' + '• Fire Rate - Shoot faster\n' + '• Auto Repair - Towers repair at 50% HP\n\n' + 'Tips:\n' + '• Drone automatically collects coins\n' + '• Each wave gets harder\n' + '• Coin rewards increase each wave', { size: 32, fill: 0xFFFFFF, align: 'left', wordWrap: true, wordWrapWidth: 700 }); infoText.anchor.set(0.5, 0); infoText.y = -320; self.addChild(infoText); // Close button var closeBtn = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: 480, scaleX: 0.4, scaleY: 0.6 }); var closeTxt = new Text2('Close', { size: 40, fill: 0xFFFFFF }); closeTxt.anchor.set(0.5, 0.5); closeTxt.y = 480; self.addChild(closeTxt); closeBtn.down = function () { self.visible = false; }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); var towerIndex = Math.floor(Math.random() * 10) + 1; var towerGraphics = self.attachAsset('tower' + towerIndex, { anchorX: 0.5, anchorY: 0.5 }); // Health bar self.maxHealth = 20; self.health = self.maxHealth; self.healthBar = new Text2('', { size: 24, fill: 0x00ff00 }); self.healthBar.anchor.set(0.5, 1); self.healthBar.y = -50; self.addChild(self.healthBar); self.updateHealthBar = function () { self.healthBar.setText(self.health + '/' + self.maxHealth); if (self.health > self.maxHealth * 0.5) { self.healthBar.fill = 0x00ff00; } else if (self.health > self.maxHealth * 0.25) { self.healthBar.fill = 0xffff00; } else { self.healthBar.fill = 0xff0000; } }; self.updateHealthBar(); // Repair button self.repairCost = 30; self.repairButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: 60, scaleX: 0.5, scaleY: 0.5 }); self.repairText = new Text2('Tamir: ' + self.repairCost, { size: 28, fill: 0xffffff }); self.repairText.anchor.set(0.5, 0.5); self.repairText.y = 60; self.addChild(self.repairText); self.repairButton.visible = false; self.repairText.visible = false; self.down = function (x, y, obj) { // Show repair button if tower is damaged if (self.health < self.maxHealth) { self.repairButton.visible = true; self.repairText.visible = true; } }; self.repairButton.down = function () { if (coinAmount >= self.repairCost && self.health < self.maxHealth) { coinAmount -= self.repairCost; self.health = self.maxHealth; self.updateHealthBar(); self.repairButton.visible = false; self.repairText.visible = false; } }; self.fireRate = 60; self.fireCooldown = 0; self.range = 300; self.damage = 1; self.takeDamage = function (dmg) { self.health -= dmg; self.updateHealthBar(); if (self.health <= 0) { self.destroy(); var idx = towers.indexOf(self); if (idx !== -1) towers.splice(idx, 1); // Clean up from autoRepairActive array var autoIdx = autoRepairActive.indexOf(self); if (autoIdx !== -1) autoRepairActive.splice(autoIdx, 1); } }; self.update = function () { if (self.fireCooldown > 0) { self.fireCooldown--; return; } var closestZombie = null; var closestDistance = self.range; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestZombie = zombie; } } if (closestZombie) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.setDirection(closestZombie.x, closestZombie.y); bullet.damage = self.damage; bullets.push(bullet); game.addChild(bullet); self.fireCooldown = self.fireRate; } // Hide repair button if not needed if (self.health >= self.maxHealth) { self.repairButton.visible = false; self.repairText.visible = false; } // --- AUTO REPAIR LOGIC --- if (self.autoRepair && self.health < self.maxHealth * 0.5) { // Only repair if not already at max and below 50% if (!self.repairIcon) { self.repairIcon = new Text2('🔧', { size: 48, fill: 0x00ffcc }); self.repairIcon.anchor.set(0.5, 0.5); self.repairIcon.y = -80; self.addChild(self.repairIcon); } // Check if we have enough coins for auto-repair (100 coins per repair) if (coinAmount >= 100) { coinAmount -= 100; // Deduct 100 coins for auto-repair self.health = self.maxHealth; self.updateHealthBar(); } else { // Not enough coins - show red repair icon to indicate failed repair attempt self.repairIcon.fill = 0xff0000; } } else if (self.repairIcon) { self.removeChild(self.repairIcon); self.repairIcon = null; } }; return self; }); var Trap = Container.expand(function () { var self = Container.call(this); var trapIndex = Math.floor(Math.random() * 5) + 1; var trapGraphics = self.attachAsset('trap' + trapIndex, { anchorX: 0.5, anchorY: 0.5 }); // Health bar self.maxHealth = 10; self.health = self.maxHealth; self.healthBar = new Text2('', { size: 20, fill: 0x00ff00 }); self.healthBar.anchor.set(0.5, 1); self.healthBar.y = -35; self.addChild(self.healthBar); self.updateHealthBar = function () { self.healthBar.setText(self.health + '/' + self.maxHealth); if (self.health > self.maxHealth * 0.5) { self.healthBar.fill = 0x00ff00; } else if (self.health > self.maxHealth * 0.25) { self.healthBar.fill = 0xffff00; } else { self.healthBar.fill = 0xff0000; } }; self.updateHealthBar(); self.takeDamage = function (dmg) { self.health -= dmg; self.updateHealthBar(); if (self.health <= 0) { self.destroy(); var idx = traps.indexOf(self); if (idx !== -1) traps.splice(idx, 1); } }; self.damage = 2; self.cooldown = 0; self.maxCooldown = 120; self.update = function () { if (self.cooldown > 0) { self.cooldown--; trapGraphics.alpha = 0.5; return; } trapGraphics.alpha = 1; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); self.cooldown = self.maxCooldown; break; } } }; return self; }); var UpgradePanel = Container.expand(function () { var self = Container.call(this); var panelGraphics = self.attachAsset('upgradePanel', { anchorX: 0.5, anchorY: 0.5 }); var towerButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: -200 }); var trapButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: -50 }); var healthButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: 100 }); var closeButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, y: 250, scaleX: 0.3, scaleY: 0.8 }); self.towerText = new Text2('Tower - ' + towerCost + ' coins', { size: 40, fill: 0xFFFFFF }); self.towerText.anchor.set(0.5, 0.5); self.towerText.y = -200; self.addChild(self.towerText); self.trapText = new Text2('Trap - ' + trapCost + ' coins', { size: 40, fill: 0xFFFFFF }); self.trapText.anchor.set(0.5, 0.5); self.trapText.y = -50; self.addChild(self.trapText); self.healthText = new Text2('Repair Base - ' + healthCost + ' coins', { size: 40, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.healthText.y = 100; self.addChild(self.healthText); self.closeText = new Text2('Close', { size: 40, fill: 0xFFFFFF }); self.closeText.anchor.set(0.5, 0.5); self.closeText.y = 250; self.addChild(self.closeText); towerButton.down = function () { if (coinAmount >= towerCost) { coinAmount -= towerCost; towerCost *= 2; self.towerText.setText('Tower - ' + towerCost + ' coins'); var tower = new Tower(); var angle = Math.random() * Math.PI * 2; var distance = 250 + Math.random() * 100; tower.x = base.x + Math.cos(angle) * distance; tower.y = base.y + Math.sin(angle) * distance; // Inherit auto-repair if already enabled if (typeof autoRepairActive !== "undefined" && autoRepairActive.length > 0) { tower.autoRepair = true; autoRepairActive.push(tower); } towers.push(tower); game.addChild(tower); LK.getSound('build').play(); self.visible = false; } }; trapButton.down = function () { if (coinAmount >= trapCost) { coinAmount -= trapCost; trapCost *= 2; self.trapText.setText('Trap - ' + trapCost + ' coins'); var trap = new Trap(); var angle = Math.random() * Math.PI * 2; var distance = 200 + Math.random() * 150; trap.x = base.x + Math.cos(angle) * distance; trap.y = base.y + Math.sin(angle) * distance; traps.push(trap); game.addChild(trap); LK.getSound('build').play(); self.visible = false; } }; healthButton.down = function () { if (coinAmount >= healthCost && base.health < base.maxHealth) { coinAmount -= healthCost; healthCost *= 2; self.healthText.setText('Repair Base - ' + healthCost + ' coins'); base.health = Math.min(base.health + 20, base.maxHealth); self.visible = false; } }; closeButton.down = function () { self.visible = false; }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var zombieIndex = Math.floor(Math.random() * 10) + 1; var zombieGraphics = self.attachAsset('zombie' + zombieIndex, { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = 1.5; self.damage = 1; self.value = 10; self.update = function () { // Priority: nearest tower, then nearest trap, then base var target = null; var minDist = Infinity; // Find closest alive tower for (var i = 0; i < towers.length; i++) { var t = towers[i]; if (t.health > 0) { var dx = t.x - self.x; var dy = t.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; target = t; } } } // If no tower, find closest alive trap if (!target) { for (var i = 0; i < traps.length; i++) { var tr = traps[i]; if (tr.health > 0) { var dx = tr.x - self.x; var dy = tr.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; target = tr; } } } } // If no tower or trap, target base if (!target) { target = base; } var dx = target.x - self.x; var dy = target.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; // Rotate zombie to face movement direction zombieGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } }; self.takeDamage = function (damage) { self.health -= damage; tween(zombieGraphics, { tint: 0xff0000 }, { duration: 100, onFinish: function onFinish() { tween(zombieGraphics, { tint: 0xffffff }, { duration: 100 }); } }); if (self.health <= 0) { return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Music toggle button images (simple on/off icons) // Background music asset var zombies = []; var bullets = []; var coins = []; var towers = []; var traps = []; var base; var character; var upgradePanel; var drone; var coinAmount = 0; var towerCost = 50; var trapCost = 30; var healthCost = 20; var wave = 1; var zombiesInWave = 5; var zombiesSpawned = 0; var waveDelay = 180; var spawnTimer = 0; // Coin drop multiplier, increases by 50% after each wave var coinDropMultiplier = 1.0; // Upgrade costs var firepowerCost = 100; var firerateCost = 100; var autoRepairCost = 100; base = game.addChild(new Base()); base.x = 1024; base.y = 1366; character = game.addChild(new Character()); character.x = base.x; character.y = base.y - 150; drone = game.addChild(new Drone()); drone.x = base.x + 100; drone.y = base.y; upgradePanel = new UpgradePanel(); upgradePanel.x = 0; upgradePanel.y = 0; upgradePanel.visible = false; LK.gui.center.addChild(upgradePanel); var howToPlayPanel = new HowToPlayPanel(); howToPlayPanel.visible = false; LK.gui.center.addChild(howToPlayPanel); var coinText = new Text2('Coins: 0', { size: 60, fill: 0xFFFF00 }); coinText.anchor.set(0.5, 0); LK.gui.top.addChild(coinText); // Add reset button var resetButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.5, x: -350, y: 30 }); var resetText = new Text2('Reset', { size: 30, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetText.x = -350; resetText.y = 30; LK.gui.top.addChild(resetButton); LK.gui.top.addChild(resetText); // Add How to Play button var howToPlayButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.5, x: 350, y: 30 }); var howToPlayText = new Text2('How to play?', { size: 28, fill: 0xFFFFFF }); howToPlayText.anchor.set(0.5, 0.5); howToPlayText.x = 350; howToPlayText.y = 30; LK.gui.top.addChild(howToPlayButton); LK.gui.top.addChild(howToPlayText); howToPlayButton.down = function () { howToPlayPanel.visible = true; }; // --- Music Toggle Button --- // 3 rows to the right of How to Play button (row = 100px, so +300px) var musicButtonX = 350 + 300; var musicButtonY = 30; var musicOnIcon = LK.getAsset('musicOnIcon', { anchorX: 0.5, anchorY: 0.5, x: musicButtonX, y: musicButtonY }); var musicOffIcon = LK.getAsset('musicOffIcon', { anchorX: 0.5, anchorY: 0.5, x: musicButtonX, y: musicButtonY }); musicOnIcon.visible = true; musicOffIcon.visible = false; LK.gui.top.addChild(musicOnIcon); LK.gui.top.addChild(musicOffIcon); var musicPlaying = true; LK.playMusic('bgmusic', { volume: 0.2 }); function updateMusicButton() { musicOnIcon.visible = musicPlaying; musicOffIcon.visible = !musicPlaying; } musicOnIcon.down = function () { LK.stopMusic(); musicPlaying = false; updateMusicButton(); }; musicOffIcon.down = function () { LK.playMusic('bgmusic', { volume: 0.2 }); musicPlaying = true; updateMusicButton(); }; resetButton.down = function () { // Clear all zombies for (var i = zombies.length - 1; i >= 0; i--) { zombies[i].destroy(); } zombies = []; // Clear all bullets for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); } bullets = []; // Clear all coins for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); } coins = []; // Clear all towers for (var i = towers.length - 1; i >= 0; i--) { towers[i].destroy(); } towers = []; autoRepairActive = []; // Clear all traps for (var i = traps.length - 1; i >= 0; i--) { traps[i].destroy(); } traps = []; // Reset game variables coinAmount = 0; towerCost = 50; trapCost = 30; healthCost = 20; wave = 1; zombiesInWave = 5; zombiesSpawned = 0; waveDelay = 180; spawnTimer = 0; coinDropMultiplier = 1.0; firepowerCost = 100; firerateCost = 100; autoRepairCost = 100; // Reset base health base.health = base.maxHealth; // Reset base repair button text baseRepairText.setText('Repair'); // Reset character stats character.fireRate = 40; character.damage = 1; // Reset upgrade panel texts upgradePanel.towerText.setText('Tower - ' + towerCost + ' coins'); upgradePanel.trapText.setText('Trap - ' + trapCost + ' coins'); upgradePanel.healthText.setText('Repair Base - ' + healthCost + ' coins'); firepowerText.setText('Fire Power + (100)'); firerateText.setText('Fire Rate + (100)'); autoRepairText.setText('Auto Repair: Off (100 x tower)'); // Hide upgrade panel upgradePanel.visible = false; }; var waveText = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); waveText.y = 70; LK.gui.top.addChild(waveText); var healthText = new Text2('Base Health: 100', { size: 50, fill: 0x00FF00 }); healthText.anchor.set(0.5, 1); LK.gui.bottom.addChild(healthText); // Add info text above repair button var baseRepairInfoText = new Text2('10 HP = 50 coins, multiples allowed', { size: 22, fill: 0xcccccc }); baseRepairInfoText.anchor.set(0.5, 0.5); baseRepairInfoText.x = 0; baseRepairInfoText.y = -150; LK.gui.bottom.addChild(baseRepairInfoText); // Add repair button above Base Health text, moved 1 row up var baseRepairButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.5, x: 0, y: -90 }); var baseRepairText = new Text2('Repair', { size: 30, fill: 0xFFFFFF }); baseRepairText.anchor.set(0.5, 0.5); baseRepairText.x = 0; baseRepairText.y = -90; LK.gui.bottom.addChild(baseRepairButton); LK.gui.bottom.addChild(baseRepairText); baseRepairButton.down = function () { // Calculate how much health is missing var missingHealth = base.maxHealth - base.health; if (missingHealth > 0 && coinAmount >= 50) { // Calculate how much we can repair (10 HP per 50 coins) var repairAmount = Math.min(10, missingHealth); var cost = 50; // Check if we need multiple repairs to fully heal var totalRepairs = Math.ceil(missingHealth / 10); var totalCost = totalRepairs * 50; // If player has enough coins for full repair, do it if (coinAmount >= totalCost) { coinAmount -= totalCost; base.health = base.maxHealth; } else { // Otherwise repair as much as possible in 10 HP increments var possibleRepairs = Math.floor(coinAmount / 50); var actualRepairAmount = possibleRepairs * 10; actualRepairAmount = Math.min(actualRepairAmount, missingHealth); coinAmount -= possibleRepairs * 50; base.health = Math.min(base.health + actualRepairAmount, base.maxHealth); } } }; // --- BASE UPGRADE PANEL (moved inside base upgrade popup) --- // Panel width/height and button size/spacing match main upgradePanel var panelWidth = 600; var panelHeight = 420; var bottomPanel = new Container(); var panelBg = LK.getAsset('upgradePanel', { anchorX: 0.5, anchorY: 0.5, width: panelWidth, height: panelHeight, x: 0, y: 0 }); bottomPanel.addChild(panelBg); // Use same button size as main upgradePanel (upgradeButton asset, no scale) var buttonWidth = 500; var buttonHeight = 100; var buttonSpacing = 20; var startY = -panelHeight / 2 + buttonHeight / 2 + 20; // Firepower Upgrade Button var firepowerButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: startY, width: buttonWidth, height: buttonHeight }); var firepowerText = new Text2('Fire Power + (100)', { size: 40, fill: 0xffffff }); firepowerText.anchor.set(0.5, 0.5); firepowerText.x = 0; firepowerText.y = startY; bottomPanel.addChild(firepowerButton); bottomPanel.addChild(firepowerText); // Fire Rate Upgrade Button var firerateButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: startY + buttonHeight + buttonSpacing, width: buttonWidth, height: buttonHeight }); var firerateText = new Text2('Fire Rate + (100)', { size: 40, fill: 0xffffff }); firerateText.anchor.set(0.5, 0.5); firerateText.x = 0; firerateText.y = startY + buttonHeight + buttonSpacing; bottomPanel.addChild(firerateButton); bottomPanel.addChild(firerateText); // Auto Repair Toggle Button var autoRepairActive = []; var autoRepairButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: startY + 2 * (buttonHeight + buttonSpacing), width: buttonWidth, height: buttonHeight }); var autoRepairText = new Text2('Auto Repair: Off (100 x tower)', { size: 30, // Reduced size to fit better in button fill: 0xffffff }); autoRepairText.anchor.set(0.5, 0.5); autoRepairText.x = 0; autoRepairText.y = startY + 2 * (buttonHeight + buttonSpacing); bottomPanel.addChild(autoRepairButton); bottomPanel.addChild(autoRepairText); // Close Button (moved to bottom, same size as others) var closeButtonY = startY + 3 * (buttonHeight + buttonSpacing); var closeButton = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: closeButtonY, width: buttonWidth, height: buttonHeight }); var closeText = new Text2('Close', { size: 40, fill: 0xffffff }); closeText.anchor.set(0.5, 0.5); closeText.x = 0; closeText.y = closeButtonY; bottomPanel.addChild(closeButton); bottomPanel.addChild(closeText); // Center and align bottomPanel background and content inside upgradePanel bottomPanel.x = 0; bottomPanel.y = panelHeight / 2 + 40; // Place just below main upgradePanel content, visually aligned panelBg.x = 0; panelBg.y = 0; // Center all buttons/texts horizontally (already x:0), ensure vertical stacking is visually centered firepowerButton.x = 0; firepowerText.x = 0; firerateButton.x = 0; firerateText.x = 0; autoRepairButton.x = 0; autoRepairText.x = 0; closeButton.x = 0; closeText.x = 0; // Add to upgradePanel upgradePanel.addChild(bottomPanel); // Close logic for new closeButton closeButton.down = function () { upgradePanel.visible = false; }; // --- BUTTON LOGIC (now inside base upgrade panel) --- firepowerButton.down = function () { if (coinAmount >= firepowerCost) { coinAmount -= firepowerCost; firepowerCost *= 2; firepowerText.setText('Fire Power + (' + firepowerCost + ')'); // Upgrade character and all towers character.damage = (character.damage || 1) + 1; for (var i = 0; i < towers.length; i++) { towers[i].damage = (towers[i].damage || 1) + 1; } } }; firerateButton.down = function () { if (coinAmount >= firerateCost) { coinAmount -= firerateCost; firerateCost *= 2; firerateText.setText('Fire Rate + (' + firerateCost + ')'); // Upgrade character and all towers character.fireRate = Math.max(5, Math.floor(character.fireRate * 0.85)); for (var i = 0; i < towers.length; i++) { towers[i].fireRate = Math.max(5, Math.floor(towers[i].fireRate * 0.85)); } } }; autoRepairButton.down = function () { // Check if any towers have auto-repair enabled var hasAutoRepair = false; for (var i = 0; i < towers.length; i++) { if (towers[i].autoRepair) { hasAutoRepair = true; break; } } if (hasAutoRepair) { // Disable auto-repair for all towers for (var i = 0; i < towers.length; i++) { towers[i].autoRepair = false; } autoRepairActive = []; autoRepairText.setText('Auto Repair: Off (100 x tower)'); } else if (towers.length > 0) { // Enable auto-repair if we have enough coins var needed = towers.length * autoRepairCost; if (coinAmount >= needed) { coinAmount -= needed; // Mark all towers as auto-repair enabled for (var i = 0; i < towers.length; i++) { towers[i].autoRepair = true; } autoRepairActive = towers; autoRepairText.setText('Auto Repair: On'); } } }; game.down = function (x, y, obj) { if (!upgradePanel.visible) { character.shoot(x, y); } }; game.update = function () { coinText.setText('Coins: ' + coinAmount); waveText.setText('Wave: ' + wave); healthText.setText('Base Health: ' + base.health); if (base.health > 50) { healthText.fill = 0x00ff00; } else if (base.health > 20) { healthText.fill = 0xffff00; } else { healthText.fill = 0xff0000; } // Update auto-repair button text based on current state var hasAutoRepair = false; for (var i = 0; i < towers.length; i++) { if (towers[i].autoRepair) { hasAutoRepair = true; break; } } if (hasAutoRepair) { autoRepairText.setText('Auto Repair: On'); } else { autoRepairText.setText('Auto Repair: Off (100 x tower)'); } if (waveDelay > 0) { waveDelay--; } else if (zombiesSpawned < zombiesInWave) { spawnTimer++; if (spawnTimer >= 60) { spawnTimer = 0; zombiesSpawned++; var zombie = new Zombie(); var scale = Math.pow(1.15, wave - 1); zombie.health = Math.round(zombie.health * scale); zombie.speed = zombie.speed * scale; zombie.damage = Math.round(zombie.damage * scale); zombie.value = Math.round(zombie.value * scale); // Spawn zombies from outside the map edges var edge = Math.floor(Math.random() * 4); // 0: left, 1: right, 2: top, 3: bottom var spawnX, spawnY; if (edge === 0) { // left spawnX = -100; spawnY = Math.random() * 2732; } else if (edge === 1) { // right spawnX = 2048 + 100; spawnY = Math.random() * 2732; } else if (edge === 2) { // top spawnX = Math.random() * 2048; spawnY = -100; } else { // bottom spawnX = Math.random() * 2048; spawnY = 2732 + 100; } zombie.x = spawnX; zombie.y = spawnY; zombies.push(zombie); game.addChild(zombie); } } else if (zombies.length === 0) { wave++; zombiesInWave = Math.round((5 + wave * 2) * Math.pow(1.15, wave - 1)); zombiesSpawned = 0; waveDelay = 180; // Increase coin drop multiplier by 50% after each wave coinDropMultiplier *= 1.5; } for (var i = zombies.length - 1; i >= 0; i--) { var zombie = zombies[i]; var attacked = false; // Check towers for (var ti = 0; ti < towers.length; ti++) { var tower = towers[ti]; if (tower.health > 0 && zombie.intersects(tower)) { tower.takeDamage(zombie.damage); zombie.destroy(); zombies.splice(i, 1); attacked = true; break; } } if (attacked) continue; // Check traps for (var trpi = 0; trpi < traps.length; trpi++) { var trap = traps[trpi]; if (trap.health > 0 && zombie.intersects(trap)) { trap.takeDamage(zombie.damage); zombie.destroy(); zombies.splice(i, 1); attacked = true; break; } } if (attacked) continue; // Check base if (zombie.intersects(base)) { base.takeDamage(zombie.damage); zombie.destroy(); zombies.splice(i, 1); continue; } for (var j = bullets.length - 1; j >= 0; j--) { var bullet = bullets[j]; if (zombie.intersects(bullet)) { LK.getSound('zombieHit').play(); // --- Explosion effect --- // Play explosion sound exactly when explosion visual is created LK.getSound('explosion').play(); var explosion = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: bullet.x, y: bullet.y, scaleX: 0.5, scaleY: 0.5, alpha: 0.7, tint: 0xffcc00 }); game.addChild(explosion); tween(explosion, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 250, onFinish: function onFinish() { if (explosion && explosion.parent) { explosion.destroy(); } } }); // --- End explosion effect --- if (zombie.takeDamage(bullet.damage)) { var coin = new Coin(); coin.x = zombie.x; coin.y = zombie.y; // Apply coin drop multiplier coin.value = Math.round(zombie.value * coinDropMultiplier); coins.push(coin); game.addChild(coin); zombie.destroy(); zombies.splice(i, 1); } bullet.destroy(); bullets.splice(j, 1); break; } } } for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.x < -100 || bullet.x > 2148 || bullet.y < -100 || bullet.y > 2832) { bullet.destroy(); bullets.splice(i, 1); } } for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; if (coin.lifetime <= 0) { coin.destroy(); coins.splice(i, 1); continue; } var dx = character.x - coin.x; var dy = character.y - coin.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { coinAmount += coin.value; LK.getSound('coinCollect').play(); coin.destroy(); coins.splice(i, 1); continue; } // Drone coin collection var droneDx = drone.x - coin.x; var droneDy = drone.y - coin.y; var droneDistance = Math.sqrt(droneDx * droneDx + droneDy * droneDy); if (droneDistance < drone.collectRange) { coinAmount += coin.value; LK.getSound('coinCollect').play(); coin.destroy(); coins.splice(i, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Base = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.takeDamage = function (damage) {
self.health -= damage;
tween(baseGraphics, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(baseGraphics, {
tint: 0xffffff
}, {
duration: 100
});
}
});
if (self.health <= 0) {
LK.showGameOver();
}
};
self.down = function (x, y, obj) {
if (!upgradePanel.visible) {
upgradePanel.visible = true;
} else {
upgradePanel.visible = false;
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1;
self.dx = 0;
self.dy = 0;
self.setDirection = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.dx = dx / distance * self.speed;
self.dy = dy / distance * self.speed;
self.rotation = Math.atan2(dy, dx);
if (bulletGraphics) {
bulletGraphics.rotation = self.rotation;
}
}
};
self.update = function () {
self.x += self.dx;
self.y += self.dy;
if (typeof self.rotation !== "undefined" && bulletGraphics) {
bulletGraphics.rotation = self.rotation;
}
};
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireRate = 40;
self.fireCooldown = 0;
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
}
// Find closest zombie for automatic shooting
if (self.fireCooldown === 0 && zombies.length > 0) {
var closestZombie = null;
var closestDistance = Infinity;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombie;
}
}
if (closestZombie) {
self.shoot(closestZombie.x, closestZombie.y);
}
}
};
self.shoot = function (targetX, targetY) {
if (self.fireCooldown > 0) return;
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.setDirection(targetX, targetY);
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.fireCooldown = self.fireRate;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 10;
self.lifetime = 300;
self.update = function () {
self.lifetime--;
coinGraphics.alpha = Math.min(1, self.lifetime / 100);
};
return self;
});
var Drone = Container.expand(function () {
var self = Container.call(this);
var vacuumField = self.attachAsset('vacuumField', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.1,
scaleX: 0.445,
scaleY: 0.445
});
var droneGraphics = self.attachAsset('drone', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.target = null;
self.collectRange = 22; // Reduced from 50 to achieve 80% area reduction
self.vacuumRange = 89; // Reduced from 200 to achieve 80% area reduction
self.vacuumPower = 0.15; // Strength of vacuum pull
self.floatOffset = 0;
self.floatSpeed = 0.05;
self.vx = 0;
self.vy = 0;
self.update = function () {
// Floating animation
self.floatOffset += self.floatSpeed;
droneGraphics.y = Math.sin(self.floatOffset) * 10;
// Vacuum field pulsing animation
vacuumField.scaleX = 0.445 + Math.sin(self.floatOffset * 2) * 0.045;
vacuumField.scaleY = 0.445 + Math.sin(self.floatOffset * 2) * 0.045;
vacuumField.alpha = 0.05 + Math.sin(self.floatOffset * 3) * 0.03;
// Find closest coin
var closestCoin = null;
var closestDistance = Infinity;
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
var dx = coin.x - self.x;
var dy = coin.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestCoin = coin;
}
}
self.target = closestCoin;
// Calculate desired velocity towards target
var desiredVx = 0;
var desiredVy = 0;
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.collectRange) {
desiredVx = dx / distance * self.speed;
desiredVy = dy / distance * self.speed;
}
} else {
// Return to base when no coins
var dx = base.x - self.x;
var dy = base.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 150) {
desiredVx = dx / distance * self.speed;
desiredVy = dy / distance * self.speed;
}
}
// Smoothly interpolate current velocity towards desired velocity
self.vx = self.vx * 0.85 + desiredVx * 0.15;
self.vy = self.vy * 0.85 + desiredVy * 0.15;
// Apply smoothed velocity
self.x += self.vx;
self.y += self.vy;
// Rotate drone based on movement direction
if (Math.abs(self.vx) > 0.1 || Math.abs(self.vy) > 0.1) {
droneGraphics.rotation = Math.atan2(self.vy, self.vx);
}
// Apply vacuum effect to nearby coins
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
var dx = self.x - coin.x;
var dy = self.y - coin.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.vacuumRange && distance > 0) {
// Pull coins towards drone
var pullStrength = (1 - distance / self.vacuumRange) * self.vacuumPower;
coin.x += dx / distance * pullStrength * distance;
coin.y += dy / distance * pullStrength * distance;
}
}
};
return self;
});
var HowToPlayPanel = Container.expand(function () {
var self = Container.call(this);
// Background panel
var bg = self.attachAsset('upgradePanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.5
});
bg.tint = 0x222222;
// Title
var title = new Text2('How to Play', {
size: 60,
fill: 0xFFFF00
});
title.anchor.set(0.5, 0.5);
title.y = -400;
self.addChild(title);
// Game info text
var infoText = new Text2('Welcome to Zombie Defense!\n\n' + '• Tap anywhere to shoot zombies\n' + '• Collect coins from defeated zombies\n' + '• Click the base to open upgrade menu\n' + '• Build towers and traps for defense\n' + '• Survive as many waves as possible!\n\n' + 'Upgrades:\n' + '• Towers - Auto-shoot nearby zombies\n' + '• Traps - Damage zombies on contact\n' + '• Base Repair - Restore base health\n' + '• Fire Power - Increase damage\n' + '• Fire Rate - Shoot faster\n' + '• Auto Repair - Towers repair at 50% HP\n\n' + 'Tips:\n' + '• Drone automatically collects coins\n' + '• Each wave gets harder\n' + '• Coin rewards increase each wave', {
size: 32,
fill: 0xFFFFFF,
align: 'left',
wordWrap: true,
wordWrapWidth: 700
});
infoText.anchor.set(0.5, 0);
infoText.y = -320;
self.addChild(infoText);
// Close button
var closeBtn = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: 480,
scaleX: 0.4,
scaleY: 0.6
});
var closeTxt = new Text2('Close', {
size: 40,
fill: 0xFFFFFF
});
closeTxt.anchor.set(0.5, 0.5);
closeTxt.y = 480;
self.addChild(closeTxt);
closeBtn.down = function () {
self.visible = false;
};
return self;
});
var Tower = Container.expand(function () {
var self = Container.call(this);
var towerIndex = Math.floor(Math.random() * 10) + 1;
var towerGraphics = self.attachAsset('tower' + towerIndex, {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar
self.maxHealth = 20;
self.health = self.maxHealth;
self.healthBar = new Text2('', {
size: 24,
fill: 0x00ff00
});
self.healthBar.anchor.set(0.5, 1);
self.healthBar.y = -50;
self.addChild(self.healthBar);
self.updateHealthBar = function () {
self.healthBar.setText(self.health + '/' + self.maxHealth);
if (self.health > self.maxHealth * 0.5) {
self.healthBar.fill = 0x00ff00;
} else if (self.health > self.maxHealth * 0.25) {
self.healthBar.fill = 0xffff00;
} else {
self.healthBar.fill = 0xff0000;
}
};
self.updateHealthBar();
// Repair button
self.repairCost = 30;
self.repairButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: 60,
scaleX: 0.5,
scaleY: 0.5
});
self.repairText = new Text2('Tamir: ' + self.repairCost, {
size: 28,
fill: 0xffffff
});
self.repairText.anchor.set(0.5, 0.5);
self.repairText.y = 60;
self.addChild(self.repairText);
self.repairButton.visible = false;
self.repairText.visible = false;
self.down = function (x, y, obj) {
// Show repair button if tower is damaged
if (self.health < self.maxHealth) {
self.repairButton.visible = true;
self.repairText.visible = true;
}
};
self.repairButton.down = function () {
if (coinAmount >= self.repairCost && self.health < self.maxHealth) {
coinAmount -= self.repairCost;
self.health = self.maxHealth;
self.updateHealthBar();
self.repairButton.visible = false;
self.repairText.visible = false;
}
};
self.fireRate = 60;
self.fireCooldown = 0;
self.range = 300;
self.damage = 1;
self.takeDamage = function (dmg) {
self.health -= dmg;
self.updateHealthBar();
if (self.health <= 0) {
self.destroy();
var idx = towers.indexOf(self);
if (idx !== -1) towers.splice(idx, 1);
// Clean up from autoRepairActive array
var autoIdx = autoRepairActive.indexOf(self);
if (autoIdx !== -1) autoRepairActive.splice(autoIdx, 1);
}
};
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
return;
}
var closestZombie = null;
var closestDistance = self.range;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombie;
}
}
if (closestZombie) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.setDirection(closestZombie.x, closestZombie.y);
bullet.damage = self.damage;
bullets.push(bullet);
game.addChild(bullet);
self.fireCooldown = self.fireRate;
}
// Hide repair button if not needed
if (self.health >= self.maxHealth) {
self.repairButton.visible = false;
self.repairText.visible = false;
}
// --- AUTO REPAIR LOGIC ---
if (self.autoRepair && self.health < self.maxHealth * 0.5) {
// Only repair if not already at max and below 50%
if (!self.repairIcon) {
self.repairIcon = new Text2('🔧', {
size: 48,
fill: 0x00ffcc
});
self.repairIcon.anchor.set(0.5, 0.5);
self.repairIcon.y = -80;
self.addChild(self.repairIcon);
}
// Check if we have enough coins for auto-repair (100 coins per repair)
if (coinAmount >= 100) {
coinAmount -= 100; // Deduct 100 coins for auto-repair
self.health = self.maxHealth;
self.updateHealthBar();
} else {
// Not enough coins - show red repair icon to indicate failed repair attempt
self.repairIcon.fill = 0xff0000;
}
} else if (self.repairIcon) {
self.removeChild(self.repairIcon);
self.repairIcon = null;
}
};
return self;
});
var Trap = Container.expand(function () {
var self = Container.call(this);
var trapIndex = Math.floor(Math.random() * 5) + 1;
var trapGraphics = self.attachAsset('trap' + trapIndex, {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar
self.maxHealth = 10;
self.health = self.maxHealth;
self.healthBar = new Text2('', {
size: 20,
fill: 0x00ff00
});
self.healthBar.anchor.set(0.5, 1);
self.healthBar.y = -35;
self.addChild(self.healthBar);
self.updateHealthBar = function () {
self.healthBar.setText(self.health + '/' + self.maxHealth);
if (self.health > self.maxHealth * 0.5) {
self.healthBar.fill = 0x00ff00;
} else if (self.health > self.maxHealth * 0.25) {
self.healthBar.fill = 0xffff00;
} else {
self.healthBar.fill = 0xff0000;
}
};
self.updateHealthBar();
self.takeDamage = function (dmg) {
self.health -= dmg;
self.updateHealthBar();
if (self.health <= 0) {
self.destroy();
var idx = traps.indexOf(self);
if (idx !== -1) traps.splice(idx, 1);
}
};
self.damage = 2;
self.cooldown = 0;
self.maxCooldown = 120;
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
trapGraphics.alpha = 0.5;
return;
}
trapGraphics.alpha = 1;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
self.cooldown = self.maxCooldown;
break;
}
}
};
return self;
});
var UpgradePanel = Container.expand(function () {
var self = Container.call(this);
var panelGraphics = self.attachAsset('upgradePanel', {
anchorX: 0.5,
anchorY: 0.5
});
var towerButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: -200
});
var trapButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
var healthButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: 100
});
var closeButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
y: 250,
scaleX: 0.3,
scaleY: 0.8
});
self.towerText = new Text2('Tower - ' + towerCost + ' coins', {
size: 40,
fill: 0xFFFFFF
});
self.towerText.anchor.set(0.5, 0.5);
self.towerText.y = -200;
self.addChild(self.towerText);
self.trapText = new Text2('Trap - ' + trapCost + ' coins', {
size: 40,
fill: 0xFFFFFF
});
self.trapText.anchor.set(0.5, 0.5);
self.trapText.y = -50;
self.addChild(self.trapText);
self.healthText = new Text2('Repair Base - ' + healthCost + ' coins', {
size: 40,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = 100;
self.addChild(self.healthText);
self.closeText = new Text2('Close', {
size: 40,
fill: 0xFFFFFF
});
self.closeText.anchor.set(0.5, 0.5);
self.closeText.y = 250;
self.addChild(self.closeText);
towerButton.down = function () {
if (coinAmount >= towerCost) {
coinAmount -= towerCost;
towerCost *= 2;
self.towerText.setText('Tower - ' + towerCost + ' coins');
var tower = new Tower();
var angle = Math.random() * Math.PI * 2;
var distance = 250 + Math.random() * 100;
tower.x = base.x + Math.cos(angle) * distance;
tower.y = base.y + Math.sin(angle) * distance;
// Inherit auto-repair if already enabled
if (typeof autoRepairActive !== "undefined" && autoRepairActive.length > 0) {
tower.autoRepair = true;
autoRepairActive.push(tower);
}
towers.push(tower);
game.addChild(tower);
LK.getSound('build').play();
self.visible = false;
}
};
trapButton.down = function () {
if (coinAmount >= trapCost) {
coinAmount -= trapCost;
trapCost *= 2;
self.trapText.setText('Trap - ' + trapCost + ' coins');
var trap = new Trap();
var angle = Math.random() * Math.PI * 2;
var distance = 200 + Math.random() * 150;
trap.x = base.x + Math.cos(angle) * distance;
trap.y = base.y + Math.sin(angle) * distance;
traps.push(trap);
game.addChild(trap);
LK.getSound('build').play();
self.visible = false;
}
};
healthButton.down = function () {
if (coinAmount >= healthCost && base.health < base.maxHealth) {
coinAmount -= healthCost;
healthCost *= 2;
self.healthText.setText('Repair Base - ' + healthCost + ' coins');
base.health = Math.min(base.health + 20, base.maxHealth);
self.visible = false;
}
};
closeButton.down = function () {
self.visible = false;
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieIndex = Math.floor(Math.random() * 10) + 1;
var zombieGraphics = self.attachAsset('zombie' + zombieIndex, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 1.5;
self.damage = 1;
self.value = 10;
self.update = function () {
// Priority: nearest tower, then nearest trap, then base
var target = null;
var minDist = Infinity;
// Find closest alive tower
for (var i = 0; i < towers.length; i++) {
var t = towers[i];
if (t.health > 0) {
var dx = t.x - self.x;
var dy = t.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
target = t;
}
}
}
// If no tower, find closest alive trap
if (!target) {
for (var i = 0; i < traps.length; i++) {
var tr = traps[i];
if (tr.health > 0) {
var dx = tr.x - self.x;
var dy = tr.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
target = tr;
}
}
}
}
// If no tower or trap, target base
if (!target) {
target = base;
}
var dx = target.x - self.x;
var dy = target.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;
// Rotate zombie to face movement direction
zombieGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
tween(zombieGraphics, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(zombieGraphics, {
tint: 0xffffff
}, {
duration: 100
});
}
});
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Music toggle button images (simple on/off icons)
// Background music asset
var zombies = [];
var bullets = [];
var coins = [];
var towers = [];
var traps = [];
var base;
var character;
var upgradePanel;
var drone;
var coinAmount = 0;
var towerCost = 50;
var trapCost = 30;
var healthCost = 20;
var wave = 1;
var zombiesInWave = 5;
var zombiesSpawned = 0;
var waveDelay = 180;
var spawnTimer = 0;
// Coin drop multiplier, increases by 50% after each wave
var coinDropMultiplier = 1.0;
// Upgrade costs
var firepowerCost = 100;
var firerateCost = 100;
var autoRepairCost = 100;
base = game.addChild(new Base());
base.x = 1024;
base.y = 1366;
character = game.addChild(new Character());
character.x = base.x;
character.y = base.y - 150;
drone = game.addChild(new Drone());
drone.x = base.x + 100;
drone.y = base.y;
upgradePanel = new UpgradePanel();
upgradePanel.x = 0;
upgradePanel.y = 0;
upgradePanel.visible = false;
LK.gui.center.addChild(upgradePanel);
var howToPlayPanel = new HowToPlayPanel();
howToPlayPanel.visible = false;
LK.gui.center.addChild(howToPlayPanel);
var coinText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFFF00
});
coinText.anchor.set(0.5, 0);
LK.gui.top.addChild(coinText);
// Add reset button
var resetButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.5,
x: -350,
y: 30
});
var resetText = new Text2('Reset', {
size: 30,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetText.x = -350;
resetText.y = 30;
LK.gui.top.addChild(resetButton);
LK.gui.top.addChild(resetText);
// Add How to Play button
var howToPlayButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.5,
x: 350,
y: 30
});
var howToPlayText = new Text2('How to play?', {
size: 28,
fill: 0xFFFFFF
});
howToPlayText.anchor.set(0.5, 0.5);
howToPlayText.x = 350;
howToPlayText.y = 30;
LK.gui.top.addChild(howToPlayButton);
LK.gui.top.addChild(howToPlayText);
howToPlayButton.down = function () {
howToPlayPanel.visible = true;
};
// --- Music Toggle Button ---
// 3 rows to the right of How to Play button (row = 100px, so +300px)
var musicButtonX = 350 + 300;
var musicButtonY = 30;
var musicOnIcon = LK.getAsset('musicOnIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: musicButtonX,
y: musicButtonY
});
var musicOffIcon = LK.getAsset('musicOffIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: musicButtonX,
y: musicButtonY
});
musicOnIcon.visible = true;
musicOffIcon.visible = false;
LK.gui.top.addChild(musicOnIcon);
LK.gui.top.addChild(musicOffIcon);
var musicPlaying = true;
LK.playMusic('bgmusic', {
volume: 0.2
});
function updateMusicButton() {
musicOnIcon.visible = musicPlaying;
musicOffIcon.visible = !musicPlaying;
}
musicOnIcon.down = function () {
LK.stopMusic();
musicPlaying = false;
updateMusicButton();
};
musicOffIcon.down = function () {
LK.playMusic('bgmusic', {
volume: 0.2
});
musicPlaying = true;
updateMusicButton();
};
resetButton.down = function () {
// Clear all zombies
for (var i = zombies.length - 1; i >= 0; i--) {
zombies[i].destroy();
}
zombies = [];
// Clear all bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
// Clear all coins
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
}
coins = [];
// Clear all towers
for (var i = towers.length - 1; i >= 0; i--) {
towers[i].destroy();
}
towers = [];
autoRepairActive = [];
// Clear all traps
for (var i = traps.length - 1; i >= 0; i--) {
traps[i].destroy();
}
traps = [];
// Reset game variables
coinAmount = 0;
towerCost = 50;
trapCost = 30;
healthCost = 20;
wave = 1;
zombiesInWave = 5;
zombiesSpawned = 0;
waveDelay = 180;
spawnTimer = 0;
coinDropMultiplier = 1.0;
firepowerCost = 100;
firerateCost = 100;
autoRepairCost = 100;
// Reset base health
base.health = base.maxHealth;
// Reset base repair button text
baseRepairText.setText('Repair');
// Reset character stats
character.fireRate = 40;
character.damage = 1;
// Reset upgrade panel texts
upgradePanel.towerText.setText('Tower - ' + towerCost + ' coins');
upgradePanel.trapText.setText('Trap - ' + trapCost + ' coins');
upgradePanel.healthText.setText('Repair Base - ' + healthCost + ' coins');
firepowerText.setText('Fire Power + (100)');
firerateText.setText('Fire Rate + (100)');
autoRepairText.setText('Auto Repair: Off (100 x tower)');
// Hide upgrade panel
upgradePanel.visible = false;
};
var waveText = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.y = 70;
LK.gui.top.addChild(waveText);
var healthText = new Text2('Base Health: 100', {
size: 50,
fill: 0x00FF00
});
healthText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(healthText);
// Add info text above repair button
var baseRepairInfoText = new Text2('10 HP = 50 coins, multiples allowed', {
size: 22,
fill: 0xcccccc
});
baseRepairInfoText.anchor.set(0.5, 0.5);
baseRepairInfoText.x = 0;
baseRepairInfoText.y = -150;
LK.gui.bottom.addChild(baseRepairInfoText);
// Add repair button above Base Health text, moved 1 row up
var baseRepairButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.5,
x: 0,
y: -90
});
var baseRepairText = new Text2('Repair', {
size: 30,
fill: 0xFFFFFF
});
baseRepairText.anchor.set(0.5, 0.5);
baseRepairText.x = 0;
baseRepairText.y = -90;
LK.gui.bottom.addChild(baseRepairButton);
LK.gui.bottom.addChild(baseRepairText);
baseRepairButton.down = function () {
// Calculate how much health is missing
var missingHealth = base.maxHealth - base.health;
if (missingHealth > 0 && coinAmount >= 50) {
// Calculate how much we can repair (10 HP per 50 coins)
var repairAmount = Math.min(10, missingHealth);
var cost = 50;
// Check if we need multiple repairs to fully heal
var totalRepairs = Math.ceil(missingHealth / 10);
var totalCost = totalRepairs * 50;
// If player has enough coins for full repair, do it
if (coinAmount >= totalCost) {
coinAmount -= totalCost;
base.health = base.maxHealth;
} else {
// Otherwise repair as much as possible in 10 HP increments
var possibleRepairs = Math.floor(coinAmount / 50);
var actualRepairAmount = possibleRepairs * 10;
actualRepairAmount = Math.min(actualRepairAmount, missingHealth);
coinAmount -= possibleRepairs * 50;
base.health = Math.min(base.health + actualRepairAmount, base.maxHealth);
}
}
};
// --- BASE UPGRADE PANEL (moved inside base upgrade popup) ---
// Panel width/height and button size/spacing match main upgradePanel
var panelWidth = 600;
var panelHeight = 420;
var bottomPanel = new Container();
var panelBg = LK.getAsset('upgradePanel', {
anchorX: 0.5,
anchorY: 0.5,
width: panelWidth,
height: panelHeight,
x: 0,
y: 0
});
bottomPanel.addChild(panelBg);
// Use same button size as main upgradePanel (upgradeButton asset, no scale)
var buttonWidth = 500;
var buttonHeight = 100;
var buttonSpacing = 20;
var startY = -panelHeight / 2 + buttonHeight / 2 + 20;
// Firepower Upgrade Button
var firepowerButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: startY,
width: buttonWidth,
height: buttonHeight
});
var firepowerText = new Text2('Fire Power + (100)', {
size: 40,
fill: 0xffffff
});
firepowerText.anchor.set(0.5, 0.5);
firepowerText.x = 0;
firepowerText.y = startY;
bottomPanel.addChild(firepowerButton);
bottomPanel.addChild(firepowerText);
// Fire Rate Upgrade Button
var firerateButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: startY + buttonHeight + buttonSpacing,
width: buttonWidth,
height: buttonHeight
});
var firerateText = new Text2('Fire Rate + (100)', {
size: 40,
fill: 0xffffff
});
firerateText.anchor.set(0.5, 0.5);
firerateText.x = 0;
firerateText.y = startY + buttonHeight + buttonSpacing;
bottomPanel.addChild(firerateButton);
bottomPanel.addChild(firerateText);
// Auto Repair Toggle Button
var autoRepairActive = [];
var autoRepairButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: startY + 2 * (buttonHeight + buttonSpacing),
width: buttonWidth,
height: buttonHeight
});
var autoRepairText = new Text2('Auto Repair: Off (100 x tower)', {
size: 30,
// Reduced size to fit better in button
fill: 0xffffff
});
autoRepairText.anchor.set(0.5, 0.5);
autoRepairText.x = 0;
autoRepairText.y = startY + 2 * (buttonHeight + buttonSpacing);
bottomPanel.addChild(autoRepairButton);
bottomPanel.addChild(autoRepairText);
// Close Button (moved to bottom, same size as others)
var closeButtonY = startY + 3 * (buttonHeight + buttonSpacing);
var closeButton = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: closeButtonY,
width: buttonWidth,
height: buttonHeight
});
var closeText = new Text2('Close', {
size: 40,
fill: 0xffffff
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 0;
closeText.y = closeButtonY;
bottomPanel.addChild(closeButton);
bottomPanel.addChild(closeText);
// Center and align bottomPanel background and content inside upgradePanel
bottomPanel.x = 0;
bottomPanel.y = panelHeight / 2 + 40; // Place just below main upgradePanel content, visually aligned
panelBg.x = 0;
panelBg.y = 0;
// Center all buttons/texts horizontally (already x:0), ensure vertical stacking is visually centered
firepowerButton.x = 0;
firepowerText.x = 0;
firerateButton.x = 0;
firerateText.x = 0;
autoRepairButton.x = 0;
autoRepairText.x = 0;
closeButton.x = 0;
closeText.x = 0;
// Add to upgradePanel
upgradePanel.addChild(bottomPanel);
// Close logic for new closeButton
closeButton.down = function () {
upgradePanel.visible = false;
};
// --- BUTTON LOGIC (now inside base upgrade panel) ---
firepowerButton.down = function () {
if (coinAmount >= firepowerCost) {
coinAmount -= firepowerCost;
firepowerCost *= 2;
firepowerText.setText('Fire Power + (' + firepowerCost + ')');
// Upgrade character and all towers
character.damage = (character.damage || 1) + 1;
for (var i = 0; i < towers.length; i++) {
towers[i].damage = (towers[i].damage || 1) + 1;
}
}
};
firerateButton.down = function () {
if (coinAmount >= firerateCost) {
coinAmount -= firerateCost;
firerateCost *= 2;
firerateText.setText('Fire Rate + (' + firerateCost + ')');
// Upgrade character and all towers
character.fireRate = Math.max(5, Math.floor(character.fireRate * 0.85));
for (var i = 0; i < towers.length; i++) {
towers[i].fireRate = Math.max(5, Math.floor(towers[i].fireRate * 0.85));
}
}
};
autoRepairButton.down = function () {
// Check if any towers have auto-repair enabled
var hasAutoRepair = false;
for (var i = 0; i < towers.length; i++) {
if (towers[i].autoRepair) {
hasAutoRepair = true;
break;
}
}
if (hasAutoRepair) {
// Disable auto-repair for all towers
for (var i = 0; i < towers.length; i++) {
towers[i].autoRepair = false;
}
autoRepairActive = [];
autoRepairText.setText('Auto Repair: Off (100 x tower)');
} else if (towers.length > 0) {
// Enable auto-repair if we have enough coins
var needed = towers.length * autoRepairCost;
if (coinAmount >= needed) {
coinAmount -= needed;
// Mark all towers as auto-repair enabled
for (var i = 0; i < towers.length; i++) {
towers[i].autoRepair = true;
}
autoRepairActive = towers;
autoRepairText.setText('Auto Repair: On');
}
}
};
game.down = function (x, y, obj) {
if (!upgradePanel.visible) {
character.shoot(x, y);
}
};
game.update = function () {
coinText.setText('Coins: ' + coinAmount);
waveText.setText('Wave: ' + wave);
healthText.setText('Base Health: ' + base.health);
if (base.health > 50) {
healthText.fill = 0x00ff00;
} else if (base.health > 20) {
healthText.fill = 0xffff00;
} else {
healthText.fill = 0xff0000;
}
// Update auto-repair button text based on current state
var hasAutoRepair = false;
for (var i = 0; i < towers.length; i++) {
if (towers[i].autoRepair) {
hasAutoRepair = true;
break;
}
}
if (hasAutoRepair) {
autoRepairText.setText('Auto Repair: On');
} else {
autoRepairText.setText('Auto Repair: Off (100 x tower)');
}
if (waveDelay > 0) {
waveDelay--;
} else if (zombiesSpawned < zombiesInWave) {
spawnTimer++;
if (spawnTimer >= 60) {
spawnTimer = 0;
zombiesSpawned++;
var zombie = new Zombie();
var scale = Math.pow(1.15, wave - 1);
zombie.health = Math.round(zombie.health * scale);
zombie.speed = zombie.speed * scale;
zombie.damage = Math.round(zombie.damage * scale);
zombie.value = Math.round(zombie.value * scale);
// Spawn zombies from outside the map edges
var edge = Math.floor(Math.random() * 4); // 0: left, 1: right, 2: top, 3: bottom
var spawnX, spawnY;
if (edge === 0) {
// left
spawnX = -100;
spawnY = Math.random() * 2732;
} else if (edge === 1) {
// right
spawnX = 2048 + 100;
spawnY = Math.random() * 2732;
} else if (edge === 2) {
// top
spawnX = Math.random() * 2048;
spawnY = -100;
} else {
// bottom
spawnX = Math.random() * 2048;
spawnY = 2732 + 100;
}
zombie.x = spawnX;
zombie.y = spawnY;
zombies.push(zombie);
game.addChild(zombie);
}
} else if (zombies.length === 0) {
wave++;
zombiesInWave = Math.round((5 + wave * 2) * Math.pow(1.15, wave - 1));
zombiesSpawned = 0;
waveDelay = 180;
// Increase coin drop multiplier by 50% after each wave
coinDropMultiplier *= 1.5;
}
for (var i = zombies.length - 1; i >= 0; i--) {
var zombie = zombies[i];
var attacked = false;
// Check towers
for (var ti = 0; ti < towers.length; ti++) {
var tower = towers[ti];
if (tower.health > 0 && zombie.intersects(tower)) {
tower.takeDamage(zombie.damage);
zombie.destroy();
zombies.splice(i, 1);
attacked = true;
break;
}
}
if (attacked) continue;
// Check traps
for (var trpi = 0; trpi < traps.length; trpi++) {
var trap = traps[trpi];
if (trap.health > 0 && zombie.intersects(trap)) {
trap.takeDamage(zombie.damage);
zombie.destroy();
zombies.splice(i, 1);
attacked = true;
break;
}
}
if (attacked) continue;
// Check base
if (zombie.intersects(base)) {
base.takeDamage(zombie.damage);
zombie.destroy();
zombies.splice(i, 1);
continue;
}
for (var j = bullets.length - 1; j >= 0; j--) {
var bullet = bullets[j];
if (zombie.intersects(bullet)) {
LK.getSound('zombieHit').play();
// --- Explosion effect ---
// Play explosion sound exactly when explosion visual is created
LK.getSound('explosion').play();
var explosion = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: bullet.x,
y: bullet.y,
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.7,
tint: 0xffcc00
});
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 250,
onFinish: function onFinish() {
if (explosion && explosion.parent) {
explosion.destroy();
}
}
});
// --- End explosion effect ---
if (zombie.takeDamage(bullet.damage)) {
var coin = new Coin();
coin.x = zombie.x;
coin.y = zombie.y;
// Apply coin drop multiplier
coin.value = Math.round(zombie.value * coinDropMultiplier);
coins.push(coin);
game.addChild(coin);
zombie.destroy();
zombies.splice(i, 1);
}
bullet.destroy();
bullets.splice(j, 1);
break;
}
}
}
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.x < -100 || bullet.x > 2148 || bullet.y < -100 || bullet.y > 2832) {
bullet.destroy();
bullets.splice(i, 1);
}
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.lifetime <= 0) {
coin.destroy();
coins.splice(i, 1);
continue;
}
var dx = character.x - coin.x;
var dy = character.y - coin.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
coinAmount += coin.value;
LK.getSound('coinCollect').play();
coin.destroy();
coins.splice(i, 1);
continue;
}
// Drone coin collection
var droneDx = drone.x - coin.x;
var droneDy = drone.y - coin.y;
var droneDistance = Math.sqrt(droneDx * droneDx + droneDy * droneDy);
if (droneDistance < drone.collectRange) {
coinAmount += coin.value;
LK.getSound('coinCollect').play();
coin.destroy();
coins.splice(i, 1);
}
}
};
Askeri karakol, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Askeri Kule, gerçekçi, üstten görünüm, yazısız. In-Game asset. High contrast. No shadows
Askeri drone, üstten görünüm, gerçekçi, yazısız. In-Game asset. 2d. High contrast. No shadows
Coin, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Namusu olmayan Teknolojik askeri saldırı kulesi, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Namlusu olmayan, Teknolojik askeri kule, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Namlusu olmayan, Teknolojik askeri kule, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Tuzak üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Füze, üstten görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Patlama, gerçekçi, üstten görünüm, yazısız. In-Game asset. High contrast. No shadows