User prompt
shooter enemy lerin daha hızlı ateş etmesi gerekli ateş hiç etmiyorlar
User prompt
düşmanların bulletını vurabilmeliyiz kendimizi korumak için önemli
User prompt
düşmanlar baseye çarpınca çok hasar alıyoruz 2 ila 5 hasar arası almalıyız
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return false;' Line Number: 275
User prompt
yeni bir enemy ekle hızı yavaş olsun ama arada bir bize ateş etsin.
User prompt
enemy verdiği hasar artmasına gerek yok bizin vurduğumuz hasar artmalı
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return false;' Line Number: 612
User prompt
base nin minimum hasarını 20 yapalım
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return true; // Remove bullet' Line Number: 265
User prompt
base hasar 10 olsun
User prompt
basenin taban hasarını yükseltelim
User prompt
basein hareketleri gelen düşmanlardan kaçmak üzerine olmalı
User prompt
daha büyük hareketler yapmalı şuan takılıyor gibi
User prompt
kendi hareket etmeli
User prompt
hala belirli bir eksende dönüyor haritanın her tarafına gidebilmeli
User prompt
bu değil eksen etrafında dönme hareketini söyledim
User prompt
şuanda base kendi etrafında dönüyor bunu rastgele olacak şekilde yap
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return false;' Line Number: 271
User prompt
boss bölümü her 5 bölümde bir gelmeli bir kez geliyor birdaha gelmiyor. her boss diğerinden daha güçlü olmalı
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return true; // Enemy reached base' Line Number: 606
User prompt
oyunun arka planı için bir asset oluştururmusun
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return false;' Line Number: 270
User prompt
saa yönünde değilde kendi etrafında dönüyor gibi yapmalıyız
User prompt
base ve düşmanalra gölge efekti ekleyelim ayrıca base kendi etrafında gezegen gibi dönsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'removeChild')' in or related to this line: 'return false;' Line Number: 324
/**** * 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 }); var rangeIndicator = self.attachAsset('rangeIndicator', { anchorX: 0.5, anchorY: 0.5, alpha: 0.2 }); self.health = 100; self.maxHealth = 100; self.attackPower = 10; self.attackSpeed = 45; // frames between attacks self.attackRange = 400; self.multiAttack = 1; self.lastAttack = 0; self.updateRangeIndicator = function () { var scale = self.attackRange * 2 / 800; rangeIndicator.scaleX = scale; rangeIndicator.scaleY = scale; }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { LK.showGameOver(); } updateHealthDisplay(); }; self.canAttack = function () { return LK.ticks - self.lastAttack >= self.attackSpeed; }; self.attack = function () { if (!self.canAttack()) return; var targets = []; for (var i = 0; i < enemies.length && targets.length < self.multiAttack; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.attackRange) { targets.push(enemy); } } for (var j = 0; j < targets.length; j++) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = targets[j]; bullet.damage = self.attackPower; bullets.push(bullet); game.addChild(bullet); } if (targets.length > 0) { self.lastAttack = LK.ticks; LK.getSound('shoot').play(); } }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.health = 200; self.maxHealth = 200; self.speed = 0.8; self.direction = { x: 0, y: 0 }; self.lastX = self.x; self.lastY = self.y; self.setTarget = 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.direction.x = dx / distance; self.direction.y = dy / distance; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { LK.getSound('enemyHit').play(); // Create explosion effect // Create particle explosion effect for (var p = 0; p < 15; p++) { var particle = LK.getAsset('boss', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); particle.x = self.x; particle.y = self.y; game.addChild(particle); var angle = p / 15 * Math.PI * 2; var speed = 150 + Math.random() * 100; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 600 + Math.random() * 400, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } tween(self, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Boss will be removed from enemies array in game.update } }); return true; // Boss died } return false; }; self.update = function () { // If boss is dead (health <= 0), don't move and prepare for removal if (self.health <= 0) { return true; // Remove dead boss } self.lastX = self.x; self.lastY = self.y; // Move toward base self.setTarget(base.x, base.y); self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Check if reached base var dx = self.x - base.x; var dy = self.y - base.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { base.takeDamage(); base.takeDamage(); // Boss does double damage return true; // Boss reached base } return 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 = 8; self.target = null; self.damage = 10; self.update = function () { if (!self.target || !self.target.parent) { return true; // Remove bullet if target is gone } // Move toward 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 < 20) { // Hit target var enemyDied = self.target.takeDamage(self.damage); if (enemyDied) { // Different point rewards for different enemy types if (self.target instanceof Boss) { points += 100; } else if (self.target instanceof EnemyTank) { points += 20; } else if (self.target instanceof EnemyFast) { points += 15; } else { points += 10; } updatePointsDisplay(); } LK.getSound('hit').play(); return true; // Remove bullet } if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } return false; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 20; self.maxHealth = 20; self.speed = 1; self.direction = { x: 0, y: 0 }; self.lastX = self.x; self.lastY = self.y; self.setTarget = 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.direction.x = dx / distance; self.direction.y = dy / distance; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { LK.getSound('enemyHit').play(); // Create explosion effect // Create particle explosion effect for (var p = 0; p < 8; p++) { var particle = LK.getAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); particle.x = self.x; particle.y = self.y; game.addChild(particle); var angle = p / 8 * Math.PI * 2; var speed = 100 + Math.random() * 50; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 400 + Math.random() * 200, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Enemy will be removed from enemies array in game.update } }); return true; // Enemy died } return false; }; self.update = function () { // If enemy is dead (health <= 0), don't move and prepare for removal if (self.health <= 0) { return true; // Remove dead enemy } self.lastX = self.x; self.lastY = self.y; // Move toward base self.setTarget(base.x, base.y); self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Check if reached base var dx = self.x - base.x; var dy = self.y - base.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 70) { base.takeDamage(); return true; // Enemy reached base } return false; }; return self; }); var EnemyFast = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyFast', { anchorX: 0.5, anchorY: 0.5 }); self.health = 5; self.maxHealth = 5; self.speed = 1.5; self.direction = { x: 0, y: 0 }; self.lastX = self.x; self.lastY = self.y; self.setTarget = 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.direction.x = dx / distance; self.direction.y = dy / distance; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { LK.getSound('enemyHit').play(); // Create explosion effect // Create particle explosion effect for (var p = 0; p < 6; p++) { var particle = LK.getAsset('enemyFast', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); particle.x = self.x; particle.y = self.y; game.addChild(particle); var angle = p / 6 * Math.PI * 2; var speed = 80 + Math.random() * 40; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 350 + Math.random() * 150, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Enemy will be removed from enemies array in game.update } }); return true; // Enemy died } return false; }; self.update = function () { // If enemy is dead (health <= 0), don't move and prepare for removal if (self.health <= 0) { return true; // Remove dead enemy } self.lastX = self.x; self.lastY = self.y; // Move toward base self.setTarget(base.x, base.y); self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Check if reached base var dx = self.x - base.x; var dy = self.y - base.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 70) { base.takeDamage(); return true; // Enemy reached base } return false; }; return self; }); // 3 seconds var EnemyTank = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 40; self.maxHealth = 40; self.speed = 0.5; self.direction = { x: 0, y: 0 }; self.lastX = self.x; self.lastY = self.y; self.setTarget = 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.direction.x = dx / distance; self.direction.y = dy / distance; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { LK.getSound('enemyHit').play(); // Create explosion effect // Create particle explosion effect for (var p = 0; p < 10; p++) { var particle = LK.getAsset('enemyTank', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4 }); particle.x = self.x; particle.y = self.y; game.addChild(particle); var angle = p / 10 * Math.PI * 2; var speed = 120 + Math.random() * 60; var targetX = self.x + Math.cos(angle) * speed; var targetY = self.y + Math.sin(angle) * speed; tween(particle, { x: targetX, y: targetY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500 + Math.random() * 300, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Enemy will be removed from enemies array in game.update } }); return true; // Enemy died } return false; }; self.update = function () { // If enemy is dead (health <= 0), don't move and prepare for removal if (self.health <= 0) { return true; // Remove dead enemy } self.lastX = self.x; self.lastY = self.y; // Move toward base self.setTarget(base.x, base.y); self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Check if reached base var dx = self.x - base.x; var dy = self.y - base.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 70) { base.takeDamage(); return true; // Enemy reached base } return false; }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = LK.getAsset('shield', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.25, scaleY: 0.25, alpha: 0.8 }); self.addChild(shieldGraphics); self.radius = 250; // Distance from base center self.rotationSpeed = 0.02; // Rotation speed self.angle = 0; self.update = function () { // Rotate around the base self.angle += self.rotationSpeed; self.x = base.x + Math.cos(self.angle) * self.radius; self.y = base.y + Math.sin(self.angle) * self.radius; // Check collision with enemies for (var i = enemies.length - 1; i >= 0; 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); // Shield collision radius if (distance < 50) { // Destroy enemy on contact enemy.takeDamage(enemy.health); LK.effects.flashObject(self, 0x00ff00, 200); } } }; return self; }); var UpgradeButton = Container.expand(function (type, cost, description, fontSize) { var self = Container.call(this); var buttonGraphics = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, // Reduced width for side-by-side layout scaleY: 0.7 // Reduced height for compactness }); self.type = type; self.cost = cost; self.description = description; self.level = 0; self.maxLevel = 999; // Default no limit if (typeof fontSize !== "number" || fontSize < 10) fontSize = 36; var buttonText = new Text2(description + '\n' + cost + ' pts', { size: 64, // Match pointsText/waveText/healthText size fill: 0xFFFFFF, font: "bold 64px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Match style for readability }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.updateCost = function (newCost) { self.cost = newCost; if (self.level >= self.maxLevel) { buttonText.setText(self.description + '\nMAX LEVEL'); buttonGraphics.tint = 0x808080; } else { buttonText.setText(self.description + '\n' + newCost + ' pts'); } }; self.down = function (x, y, obj) { if (points >= self.cost && self.level < self.maxLevel) { points -= self.cost; updatePointsDisplay(); self.level++; switch (self.type) { case 'power': base.attackPower += 5; powerUpgradeCost = Math.floor(powerUpgradeCost * 1.5); self.updateCost(powerUpgradeCost); break; case 'speed': base.attackSpeed = Math.max(10, base.attackSpeed - 10); speedUpgradeCost = Math.floor(speedUpgradeCost * 1.5); self.updateCost(speedUpgradeCost); break; case 'range': base.attackRange += 100; base.updateRangeIndicator(); rangeUpgradeCost = Math.floor(rangeUpgradeCost * 1.5); self.updateCost(rangeUpgradeCost); break; case 'multi': base.multiAttack += 1; multiUpgradeCost = Math.floor(multiUpgradeCost * 2); self.updateCost(multiUpgradeCost); break; case 'shield': if (!shield) { shield = new Shield(); game.addChild(shield); self.visible = false; // Hide shield button after purchase } break; } LK.effects.flashObject(self, 0xffffff, 300); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ var base = game.addChild(new Base()); base.x = 2048 / 2; base.y = 2732 / 2; base.updateRangeIndicator(); var enemies = []; var bullets = []; var points = 0; var wave = 1; var waveInProgress = false; var enemiesSpawned = 0; var enemiesPerWave = 5; var spawnTimer = 0; var waveStartDelay = 0; var shield = null; // Upgrade costs var powerUpgradeCost = 50; var speedUpgradeCost = 30; var rangeUpgradeCost = 40; var multiUpgradeCost = 100; var shieldUpgradeCost = 500; // UI Elements var healthText = new Text2('Health: 100', { size: 48, fill: 0xFFFFFF }); healthText.anchor.set(0, 0); healthText.x = 50; healthText.y = 150; LK.gui.topLeft.addChild(healthText); var pointsText = new Text2('Points: 0', { size: 64, fill: 0xFFFFFF }); pointsText.anchor.set(0.5, 0); pointsText.x = 0; pointsText.y = 120; LK.gui.top.addChild(pointsText); var waveText = new Text2('Wave: 1', { size: 48, fill: 0xFFFFFF }); waveText.anchor.set(1, 0); waveText.x = -50; waveText.y = 150; LK.gui.topRight.addChild(waveText); var statusText = new Text2('Prepare for Wave 1!', { size: 48, fill: 0xF39C12 }); statusText.anchor.set(0.5, 0); statusText.x = 0; statusText.y = 50; LK.gui.top.addChild(statusText); // New upgrade menu: horizontal, text/buttons styled to match health/wave/points, large and readable // Layout constants for new menu var upgradeMenuY = 2732 - 220; var upgradeMenuButtonCount = 5; var upgradeMenuButtonSpacing = 340; var upgradeMenuButtonStartX = (2048 - upgradeMenuButtonSpacing * (upgradeMenuButtonCount - 1)) / 2; // Button info: [type, cost, label, maxLevel, description] var upgradeMenuData = [['power', powerUpgradeCost, 'Güç', undefined, 'Saldırı gücünü artırır'], ['speed', speedUpgradeCost, 'Hız', undefined, 'Saldırı hızını artırır'], ['range', rangeUpgradeCost, 'Menzil', 4, 'Menzili artırır'], ['multi', multiUpgradeCost, 'Çoklu', 3, 'Çoklu atış sağlar'], ['shield', shieldUpgradeCost, 'Kalkan', 1, 'Kalkan ekler']]; // Store references for cost/level updates var powerButton, speedButton, rangeButton, multiButton, shieldButton; var upgradeMenuButtons = []; for (var i = 0; i < upgradeMenuButtonCount; i++) { var btnType = upgradeMenuData[i][0]; var btnCost = upgradeMenuData[i][1]; var btnLabel = upgradeMenuData[i][2]; var btnMaxLevel = upgradeMenuData[i][3]; var btnDesc = upgradeMenuData[i][4]; // Create button background using 'upgradeButton' asset, styled to match general UI var btn = new UpgradeButton(btnType, btnCost, btnLabel, Math.floor(LK.width / 18)); // Remove default children (graphics/text) for custom layout while (btn.children.length > 0) { var child = btn.children[0]; // Defensive: Only remove if child has a parent (avoid undefined parent crash) if (child && child.parent) { child.parent.removeChild(child); } else { // Fallback: forcibly remove from children array if not attached btn.children.splice(0, 1); } } var bg = btn.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.0, alpha: 0.98 }); btn.children.unshift(bg); // Position horizontally btn.x = upgradeMenuButtonStartX + i * upgradeMenuButtonSpacing; btn.y = upgradeMenuY; // Add label (large, bold, white, matching pointsText style) var labelText = new Text2(btnLabel, { size: Math.floor(LK.width / 18), fill: 0xffffff, font: "bold " + Math.floor(LK.width / 18) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" }); labelText.anchor.set(0.5, 1); labelText.x = 0; labelText.y = -10; btn.addChild(labelText); // Add cost (large, bold, yellow, matching pointsText style) var costText = new Text2(btnCost + ' pts', { size: Math.floor(LK.width / 22), fill: 0xf1c40f, font: "bold " + Math.floor(LK.width / 22) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" }); costText.anchor.set(0.5, 0); costText.x = 0; costText.y = 10; btn.addChild(costText); // Add description (smaller, white, below cost) var descText = new Text2(btnDesc, { size: Math.floor(LK.width / 32), fill: 0xffffff, font: "bold " + Math.floor(LK.width / 32) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" }); descText.anchor.set(0.5, 0); descText.x = 0; descText.y = 70; btn.addChild(descText); // Set maxLevel if needed if (typeof btnMaxLevel === "number") btn.maxLevel = btnMaxLevel; // Store reference for cost/level updates if (btnType === 'power') powerButton = btn; if (btnType === 'speed') speedButton = btn; if (btnType === 'range') rangeButton = btn; if (btnType === 'multi') multiButton = btn; if (btnType === 'shield') shieldButton = btn; upgradeMenuButtons.push(btn); game.addChild(btn); } // Patch UpgradeButton.updateCost to update the cost text inside the button UpgradeButton.prototype.updateCost = function (newCost) { this.cost = newCost; // Find costText (Text2) child for (var i = 0; i < this.children.length; i++) { var ch = this.children[i]; if (ch instanceof Text2 && ch.text && (ch.text.indexOf('pts') !== -1 || ch.text === 'MAX LEVEL')) { if (this.level >= this.maxLevel) { ch.setText('MAX LEVEL'); if (this.children[0] && this.children[0].tint !== undefined) this.children[0].tint = 0x808080; } else { ch.setText(newCost + ' pts'); if (this.children[0] && this.children[0].tint !== undefined) this.children[0].tint = 0xffffff; } } } }; function updateHealthDisplay() { healthText.setText('Health: ' + base.health); } function updatePointsDisplay() { pointsText.setText('Points: ' + points); } function startWave() { waveInProgress = true; enemiesSpawned = 0; // Boss waves have only 1 enemy (the boss) if (wave % 10 === 0) { enemiesPerWave = 1; statusText.setText('BOSS WAVE ' + wave + ' - Prepare for battle!'); } else { enemiesPerWave = Math.floor(5 + Math.pow(wave, 1.3) * 2); statusText.setText('Wave ' + wave + ' - ' + enemiesPerWave + ' enemies incoming!'); } spawnTimer = 0; waveText.setText('Wave: ' + wave); } function spawnEnemy() { var enemy; // Boss every 10 waves if (wave % 10 === 0 && enemiesSpawned === 0) { enemy = new Boss(); // Scale boss stats with wave - more aggressive scaling enemy.health = 300 + (wave / 10 - 1) * 400; enemy.maxHealth = enemy.health; enemy.speed = 1 + wave * 0.04; } else { // Progressive enemy introduction based on wave var enemyType; if (wave === 1) { // Wave 1: Only basic red enemies enemyType = 0; } else if (wave <= 5) { // Waves 2-5: Basic enemies and tanks enemyType = Math.floor(Math.random() * 2); } else { // Wave 6+: All enemy types enemyType = Math.floor(Math.random() * 3); } switch (enemyType) { case 0: enemy = new Enemy(); // Scale enemy stats with wave - more aggressive scaling enemy.health = 20 + Math.pow(wave - 1, 1.5) * 5; enemy.maxHealth = enemy.health; enemy.speed = 1 + wave * 0.2; break; case 1: enemy = new EnemyTank(); // Scale tank stats with wave - more aggressive scaling enemy.health = 60 + Math.pow(wave - 1, 1.5) * 12; enemy.maxHealth = enemy.health; enemy.speed = 0.5 + wave * 0.12; break; case 2: enemy = new EnemyFast(); // Scale fast enemy stats with wave - more aggressive scaling enemy.health = 10 + Math.pow(wave - 1, 1.5) * 2; enemy.maxHealth = enemy.health; enemy.speed = 2 + wave * 0.25; break; } } // Random spawn position at screen edges var side = Math.floor(Math.random() * 4); switch (side) { case 0: // Top enemy.x = Math.random() * 2048; enemy.y = -50; break; case 1: // Right enemy.x = 2048 + 50; enemy.y = Math.random() * 2732; break; case 2: // Bottom enemy.x = Math.random() * 2048; enemy.y = 2732 + 50; break; case 3: // Left enemy.x = -50; enemy.y = Math.random() * 2732; break; } enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } function endWave() { waveInProgress = false; wave++; waveStartDelay = 300; // 5 seconds delay statusText.setText('Wave ' + (wave - 1) + ' Complete! Next wave in 5 seconds...'); // Bonus points for surviving the wave points += wave * 10; updatePointsDisplay(); } game.down = function (x, y, obj) { // Manual shooting when tapping the screen if (waveInProgress) { base.attack(); } }; game.update = function () { // Handle wave progression if (!waveInProgress) { if (waveStartDelay > 0) { waveStartDelay--; if (waveStartDelay === 0) { startWave(); } } } else { // Spawn enemies if (enemiesSpawned < enemiesPerWave) { spawnTimer++; var spawnDelay = Math.max(10, 25 - Math.floor(wave / 2)); // Much faster spawning as waves progress if (spawnTimer >= spawnDelay) { spawnEnemy(); spawnTimer = 0; } } // Check if wave is complete if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) { endWave(); } } // Update shield if (shield) { shield.update(); } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; var shouldRemove = enemy.update(); if (shouldRemove) { enemy.destroy(); enemies.splice(i, 1); } } // Update bullets for (var j = bullets.length - 1; j >= 0; j--) { var bullet = bullets[j]; var shouldRemove = bullet.update(); if (shouldRemove) { bullet.destroy(); bullets.splice(j, 1); } } // Auto-attack if (waveInProgress) { base.attack(); } }; // Start first wave after delay waveStartDelay = 180;
/****
* 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
});
var rangeIndicator = self.attachAsset('rangeIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.2
});
self.health = 100;
self.maxHealth = 100;
self.attackPower = 10;
self.attackSpeed = 45; // frames between attacks
self.attackRange = 400;
self.multiAttack = 1;
self.lastAttack = 0;
self.updateRangeIndicator = function () {
var scale = self.attackRange * 2 / 800;
rangeIndicator.scaleX = scale;
rangeIndicator.scaleY = scale;
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
LK.showGameOver();
}
updateHealthDisplay();
};
self.canAttack = function () {
return LK.ticks - self.lastAttack >= self.attackSpeed;
};
self.attack = function () {
if (!self.canAttack()) return;
var targets = [];
for (var i = 0; i < enemies.length && targets.length < self.multiAttack; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) {
targets.push(enemy);
}
}
for (var j = 0; j < targets.length; j++) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = targets[j];
bullet.damage = self.attackPower;
bullets.push(bullet);
game.addChild(bullet);
}
if (targets.length > 0) {
self.lastAttack = LK.ticks;
LK.getSound('shoot').play();
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 200;
self.maxHealth = 200;
self.speed = 0.8;
self.direction = {
x: 0,
y: 0
};
self.lastX = self.x;
self.lastY = self.y;
self.setTarget = 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.direction.x = dx / distance;
self.direction.y = dy / distance;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
// Create explosion effect
// Create particle explosion effect
for (var p = 0; p < 15; p++) {
var particle = LK.getAsset('boss', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
var angle = p / 15 * Math.PI * 2;
var speed = 150 + Math.random() * 100;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 600 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss will be removed from enemies array in game.update
}
});
return true; // Boss died
}
return false;
};
self.update = function () {
// If boss is dead (health <= 0), don't move and prepare for removal
if (self.health <= 0) {
return true; // Remove dead boss
}
self.lastX = self.x;
self.lastY = self.y;
// Move toward base
self.setTarget(base.x, base.y);
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Check if reached base
var dx = self.x - base.x;
var dy = self.y - base.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
base.takeDamage();
base.takeDamage(); // Boss does double damage
return true; // Boss reached base
}
return 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 = 8;
self.target = null;
self.damage = 10;
self.update = function () {
if (!self.target || !self.target.parent) {
return true; // Remove bullet if target is gone
}
// Move toward 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 < 20) {
// Hit target
var enemyDied = self.target.takeDamage(self.damage);
if (enemyDied) {
// Different point rewards for different enemy types
if (self.target instanceof Boss) {
points += 100;
} else if (self.target instanceof EnemyTank) {
points += 20;
} else if (self.target instanceof EnemyFast) {
points += 15;
} else {
points += 10;
}
updatePointsDisplay();
}
LK.getSound('hit').play();
return true; // Remove bullet
}
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 20;
self.maxHealth = 20;
self.speed = 1;
self.direction = {
x: 0,
y: 0
};
self.lastX = self.x;
self.lastY = self.y;
self.setTarget = 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.direction.x = dx / distance;
self.direction.y = dy / distance;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
// Create explosion effect
// Create particle explosion effect
for (var p = 0; p < 8; p++) {
var particle = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
var angle = p / 8 * Math.PI * 2;
var speed = 100 + Math.random() * 50;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Enemy will be removed from enemies array in game.update
}
});
return true; // Enemy died
}
return false;
};
self.update = function () {
// If enemy is dead (health <= 0), don't move and prepare for removal
if (self.health <= 0) {
return true; // Remove dead enemy
}
self.lastX = self.x;
self.lastY = self.y;
// Move toward base
self.setTarget(base.x, base.y);
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Check if reached base
var dx = self.x - base.x;
var dy = self.y - base.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 70) {
base.takeDamage();
return true; // Enemy reached base
}
return false;
};
return self;
});
var EnemyFast = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyFast', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 5;
self.maxHealth = 5;
self.speed = 1.5;
self.direction = {
x: 0,
y: 0
};
self.lastX = self.x;
self.lastY = self.y;
self.setTarget = 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.direction.x = dx / distance;
self.direction.y = dy / distance;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
// Create explosion effect
// Create particle explosion effect
for (var p = 0; p < 6; p++) {
var particle = LK.getAsset('enemyFast', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
var angle = p / 6 * Math.PI * 2;
var speed = 80 + Math.random() * 40;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 350 + Math.random() * 150,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Enemy will be removed from enemies array in game.update
}
});
return true; // Enemy died
}
return false;
};
self.update = function () {
// If enemy is dead (health <= 0), don't move and prepare for removal
if (self.health <= 0) {
return true; // Remove dead enemy
}
self.lastX = self.x;
self.lastY = self.y;
// Move toward base
self.setTarget(base.x, base.y);
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Check if reached base
var dx = self.x - base.x;
var dy = self.y - base.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 70) {
base.takeDamage();
return true; // Enemy reached base
}
return false;
};
return self;
});
// 3 seconds
var EnemyTank = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 40;
self.maxHealth = 40;
self.speed = 0.5;
self.direction = {
x: 0,
y: 0
};
self.lastX = self.x;
self.lastY = self.y;
self.setTarget = 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.direction.x = dx / distance;
self.direction.y = dy / distance;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
// Create explosion effect
// Create particle explosion effect
for (var p = 0; p < 10; p++) {
var particle = LK.getAsset('enemyTank', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
particle.x = self.x;
particle.y = self.y;
game.addChild(particle);
var angle = p / 10 * Math.PI * 2;
var speed = 120 + Math.random() * 60;
var targetX = self.x + Math.cos(angle) * speed;
var targetY = self.y + Math.sin(angle) * speed;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Enemy will be removed from enemies array in game.update
}
});
return true; // Enemy died
}
return false;
};
self.update = function () {
// If enemy is dead (health <= 0), don't move and prepare for removal
if (self.health <= 0) {
return true; // Remove dead enemy
}
self.lastX = self.x;
self.lastY = self.y;
// Move toward base
self.setTarget(base.x, base.y);
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Check if reached base
var dx = self.x - base.x;
var dy = self.y - base.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 70) {
base.takeDamage();
return true; // Enemy reached base
}
return false;
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = LK.getAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.25,
scaleY: 0.25,
alpha: 0.8
});
self.addChild(shieldGraphics);
self.radius = 250; // Distance from base center
self.rotationSpeed = 0.02; // Rotation speed
self.angle = 0;
self.update = function () {
// Rotate around the base
self.angle += self.rotationSpeed;
self.x = base.x + Math.cos(self.angle) * self.radius;
self.y = base.y + Math.sin(self.angle) * self.radius;
// Check collision with enemies
for (var i = enemies.length - 1; i >= 0; 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);
// Shield collision radius
if (distance < 50) {
// Destroy enemy on contact
enemy.takeDamage(enemy.health);
LK.effects.flashObject(self, 0x00ff00, 200);
}
}
};
return self;
});
var UpgradeButton = Container.expand(function (type, cost, description, fontSize) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// Reduced width for side-by-side layout
scaleY: 0.7 // Reduced height for compactness
});
self.type = type;
self.cost = cost;
self.description = description;
self.level = 0;
self.maxLevel = 999; // Default no limit
if (typeof fontSize !== "number" || fontSize < 10) fontSize = 36;
var buttonText = new Text2(description + '\n' + cost + ' pts', {
size: 64,
// Match pointsText/waveText/healthText size
fill: 0xFFFFFF,
font: "bold 64px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Match style for readability
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.updateCost = function (newCost) {
self.cost = newCost;
if (self.level >= self.maxLevel) {
buttonText.setText(self.description + '\nMAX LEVEL');
buttonGraphics.tint = 0x808080;
} else {
buttonText.setText(self.description + '\n' + newCost + ' pts');
}
};
self.down = function (x, y, obj) {
if (points >= self.cost && self.level < self.maxLevel) {
points -= self.cost;
updatePointsDisplay();
self.level++;
switch (self.type) {
case 'power':
base.attackPower += 5;
powerUpgradeCost = Math.floor(powerUpgradeCost * 1.5);
self.updateCost(powerUpgradeCost);
break;
case 'speed':
base.attackSpeed = Math.max(10, base.attackSpeed - 10);
speedUpgradeCost = Math.floor(speedUpgradeCost * 1.5);
self.updateCost(speedUpgradeCost);
break;
case 'range':
base.attackRange += 100;
base.updateRangeIndicator();
rangeUpgradeCost = Math.floor(rangeUpgradeCost * 1.5);
self.updateCost(rangeUpgradeCost);
break;
case 'multi':
base.multiAttack += 1;
multiUpgradeCost = Math.floor(multiUpgradeCost * 2);
self.updateCost(multiUpgradeCost);
break;
case 'shield':
if (!shield) {
shield = new Shield();
game.addChild(shield);
self.visible = false; // Hide shield button after purchase
}
break;
}
LK.effects.flashObject(self, 0xffffff, 300);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var base = game.addChild(new Base());
base.x = 2048 / 2;
base.y = 2732 / 2;
base.updateRangeIndicator();
var enemies = [];
var bullets = [];
var points = 0;
var wave = 1;
var waveInProgress = false;
var enemiesSpawned = 0;
var enemiesPerWave = 5;
var spawnTimer = 0;
var waveStartDelay = 0;
var shield = null;
// Upgrade costs
var powerUpgradeCost = 50;
var speedUpgradeCost = 30;
var rangeUpgradeCost = 40;
var multiUpgradeCost = 100;
var shieldUpgradeCost = 500;
// UI Elements
var healthText = new Text2('Health: 100', {
size: 48,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
healthText.x = 50;
healthText.y = 150;
LK.gui.topLeft.addChild(healthText);
var pointsText = new Text2('Points: 0', {
size: 64,
fill: 0xFFFFFF
});
pointsText.anchor.set(0.5, 0);
pointsText.x = 0;
pointsText.y = 120;
LK.gui.top.addChild(pointsText);
var waveText = new Text2('Wave: 1', {
size: 48,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = -50;
waveText.y = 150;
LK.gui.topRight.addChild(waveText);
var statusText = new Text2('Prepare for Wave 1!', {
size: 48,
fill: 0xF39C12
});
statusText.anchor.set(0.5, 0);
statusText.x = 0;
statusText.y = 50;
LK.gui.top.addChild(statusText);
// New upgrade menu: horizontal, text/buttons styled to match health/wave/points, large and readable
// Layout constants for new menu
var upgradeMenuY = 2732 - 220;
var upgradeMenuButtonCount = 5;
var upgradeMenuButtonSpacing = 340;
var upgradeMenuButtonStartX = (2048 - upgradeMenuButtonSpacing * (upgradeMenuButtonCount - 1)) / 2;
// Button info: [type, cost, label, maxLevel, description]
var upgradeMenuData = [['power', powerUpgradeCost, 'Güç', undefined, 'Saldırı gücünü artırır'], ['speed', speedUpgradeCost, 'Hız', undefined, 'Saldırı hızını artırır'], ['range', rangeUpgradeCost, 'Menzil', 4, 'Menzili artırır'], ['multi', multiUpgradeCost, 'Çoklu', 3, 'Çoklu atış sağlar'], ['shield', shieldUpgradeCost, 'Kalkan', 1, 'Kalkan ekler']];
// Store references for cost/level updates
var powerButton, speedButton, rangeButton, multiButton, shieldButton;
var upgradeMenuButtons = [];
for (var i = 0; i < upgradeMenuButtonCount; i++) {
var btnType = upgradeMenuData[i][0];
var btnCost = upgradeMenuData[i][1];
var btnLabel = upgradeMenuData[i][2];
var btnMaxLevel = upgradeMenuData[i][3];
var btnDesc = upgradeMenuData[i][4];
// Create button background using 'upgradeButton' asset, styled to match general UI
var btn = new UpgradeButton(btnType, btnCost, btnLabel, Math.floor(LK.width / 18));
// Remove default children (graphics/text) for custom layout
while (btn.children.length > 0) {
var child = btn.children[0];
// Defensive: Only remove if child has a parent (avoid undefined parent crash)
if (child && child.parent) {
child.parent.removeChild(child);
} else {
// Fallback: forcibly remove from children array if not attached
btn.children.splice(0, 1);
}
}
var bg = btn.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.0,
alpha: 0.98
});
btn.children.unshift(bg);
// Position horizontally
btn.x = upgradeMenuButtonStartX + i * upgradeMenuButtonSpacing;
btn.y = upgradeMenuY;
// Add label (large, bold, white, matching pointsText style)
var labelText = new Text2(btnLabel, {
size: Math.floor(LK.width / 18),
fill: 0xffffff,
font: "bold " + Math.floor(LK.width / 18) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma"
});
labelText.anchor.set(0.5, 1);
labelText.x = 0;
labelText.y = -10;
btn.addChild(labelText);
// Add cost (large, bold, yellow, matching pointsText style)
var costText = new Text2(btnCost + ' pts', {
size: Math.floor(LK.width / 22),
fill: 0xf1c40f,
font: "bold " + Math.floor(LK.width / 22) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma"
});
costText.anchor.set(0.5, 0);
costText.x = 0;
costText.y = 10;
btn.addChild(costText);
// Add description (smaller, white, below cost)
var descText = new Text2(btnDesc, {
size: Math.floor(LK.width / 32),
fill: 0xffffff,
font: "bold " + Math.floor(LK.width / 32) + "px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma"
});
descText.anchor.set(0.5, 0);
descText.x = 0;
descText.y = 70;
btn.addChild(descText);
// Set maxLevel if needed
if (typeof btnMaxLevel === "number") btn.maxLevel = btnMaxLevel;
// Store reference for cost/level updates
if (btnType === 'power') powerButton = btn;
if (btnType === 'speed') speedButton = btn;
if (btnType === 'range') rangeButton = btn;
if (btnType === 'multi') multiButton = btn;
if (btnType === 'shield') shieldButton = btn;
upgradeMenuButtons.push(btn);
game.addChild(btn);
}
// Patch UpgradeButton.updateCost to update the cost text inside the button
UpgradeButton.prototype.updateCost = function (newCost) {
this.cost = newCost;
// Find costText (Text2) child
for (var i = 0; i < this.children.length; i++) {
var ch = this.children[i];
if (ch instanceof Text2 && ch.text && (ch.text.indexOf('pts') !== -1 || ch.text === 'MAX LEVEL')) {
if (this.level >= this.maxLevel) {
ch.setText('MAX LEVEL');
if (this.children[0] && this.children[0].tint !== undefined) this.children[0].tint = 0x808080;
} else {
ch.setText(newCost + ' pts');
if (this.children[0] && this.children[0].tint !== undefined) this.children[0].tint = 0xffffff;
}
}
}
};
function updateHealthDisplay() {
healthText.setText('Health: ' + base.health);
}
function updatePointsDisplay() {
pointsText.setText('Points: ' + points);
}
function startWave() {
waveInProgress = true;
enemiesSpawned = 0;
// Boss waves have only 1 enemy (the boss)
if (wave % 10 === 0) {
enemiesPerWave = 1;
statusText.setText('BOSS WAVE ' + wave + ' - Prepare for battle!');
} else {
enemiesPerWave = Math.floor(5 + Math.pow(wave, 1.3) * 2);
statusText.setText('Wave ' + wave + ' - ' + enemiesPerWave + ' enemies incoming!');
}
spawnTimer = 0;
waveText.setText('Wave: ' + wave);
}
function spawnEnemy() {
var enemy;
// Boss every 10 waves
if (wave % 10 === 0 && enemiesSpawned === 0) {
enemy = new Boss();
// Scale boss stats with wave - more aggressive scaling
enemy.health = 300 + (wave / 10 - 1) * 400;
enemy.maxHealth = enemy.health;
enemy.speed = 1 + wave * 0.04;
} else {
// Progressive enemy introduction based on wave
var enemyType;
if (wave === 1) {
// Wave 1: Only basic red enemies
enemyType = 0;
} else if (wave <= 5) {
// Waves 2-5: Basic enemies and tanks
enemyType = Math.floor(Math.random() * 2);
} else {
// Wave 6+: All enemy types
enemyType = Math.floor(Math.random() * 3);
}
switch (enemyType) {
case 0:
enemy = new Enemy();
// Scale enemy stats with wave - more aggressive scaling
enemy.health = 20 + Math.pow(wave - 1, 1.5) * 5;
enemy.maxHealth = enemy.health;
enemy.speed = 1 + wave * 0.2;
break;
case 1:
enemy = new EnemyTank();
// Scale tank stats with wave - more aggressive scaling
enemy.health = 60 + Math.pow(wave - 1, 1.5) * 12;
enemy.maxHealth = enemy.health;
enemy.speed = 0.5 + wave * 0.12;
break;
case 2:
enemy = new EnemyFast();
// Scale fast enemy stats with wave - more aggressive scaling
enemy.health = 10 + Math.pow(wave - 1, 1.5) * 2;
enemy.maxHealth = enemy.health;
enemy.speed = 2 + wave * 0.25;
break;
}
}
// Random spawn position at screen edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2048 + 50;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2732 + 50;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function endWave() {
waveInProgress = false;
wave++;
waveStartDelay = 300; // 5 seconds delay
statusText.setText('Wave ' + (wave - 1) + ' Complete! Next wave in 5 seconds...');
// Bonus points for surviving the wave
points += wave * 10;
updatePointsDisplay();
}
game.down = function (x, y, obj) {
// Manual shooting when tapping the screen
if (waveInProgress) {
base.attack();
}
};
game.update = function () {
// Handle wave progression
if (!waveInProgress) {
if (waveStartDelay > 0) {
waveStartDelay--;
if (waveStartDelay === 0) {
startWave();
}
}
} else {
// Spawn enemies
if (enemiesSpawned < enemiesPerWave) {
spawnTimer++;
var spawnDelay = Math.max(10, 25 - Math.floor(wave / 2)); // Much faster spawning as waves progress
if (spawnTimer >= spawnDelay) {
spawnEnemy();
spawnTimer = 0;
}
}
// Check if wave is complete
if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) {
endWave();
}
}
// Update shield
if (shield) {
shield.update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var shouldRemove = enemy.update();
if (shouldRemove) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update bullets
for (var j = bullets.length - 1; j >= 0; j--) {
var bullet = bullets[j];
var shouldRemove = bullet.update();
if (shouldRemove) {
bullet.destroy();
bullets.splice(j, 1);
}
}
// Auto-attack
if (waveInProgress) {
base.attack();
}
};
// Start first wave after delay
waveStartDelay = 180;
thin range circle. In-Game asset. 2d. High contrast. No shadows
yellow meteor ball no flame effect. In-Game asset. 2d. High contrast. No shadows
purple meteor ball no flame effect. In-Game asset. 2d. High contrast. No shadows
red meteor mall no flame effect. In-Game asset. 2d. High contrast. No shadows
colorful meteor ball no flame effect. In-Game asset. 2d. High contrast. No shadows
green button empty. In-Game asset. 2d. High contrast. No shadows
yuvarlak mermi roket şeklinde. In-Game asset. 2d. High contrast. No shadows
circle shape starship. In-Game asset. 2d. High contrast. No shadows