User prompt
oyun boss sonrası ihtibariyle score arttıkça zorluk artar kesintisiz rakip gelmesi normal asker çıkması nadir olur daha tehlikeli rakipler
User prompt
lazer hep mausu takip etsşn basılı tutmak gerekmesin
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'var bdx = boss.x - CENTER_X;' Line Number: 518
User prompt
Please fix the bug: 'TypeError: storage.set is not a function' in or related to this line: 'storage.set('highScore', highScore);' Line Number: 569 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var highScore = storage.get('highScore') || 0;' Line Number: 288 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
boss yenildikten sonra oyun devam etsin sonsuza dek en yüksek score yazsın skor tablosu
User prompt
müzik
User prompt
aksiyon dolu bir müzik
User prompt
👑 Boss Adı: Aetherion – Zihin Parçalayıcı 👤 Görünüm: Devasa, yarı saydam ve puslu bir figür. Gövdesi karanlık enerjiyle sarılı, içinden yıldız gibi parlayan noktalar akar. Başı sürekli sağa sola yavaşça döner, birden ışık patlamalarıyla sabitlenir. Etrafında dönen 4 mini kristal uydu gibi etrafında dolaşır (bunlar vurulabilir hedeflerdir). 🧠 Yetenekleri: Destek Bağlantısı – "Dört Bağ": Her kristal, sahadaki düşmanlara bağlanarak onları destekçi yapar. Bu bağlar vurulmadıkça bağlı düşmanlar ölümsüzdür. Oyuncu önce bu kristalleri lazerle vurmalı (her biri 3 saniye sürekli hasarla kırılır). Zihin Dalgası – "Dalga Patlaması": Her 10 saniyede bir, bulunduğu noktadan genişleyen mor bir halka salar. Bu halka lazer yönünü 2 saniyeliğine ters çevirir (kontrol karışır). Oyuncu bu dalgadan uzak durmalı veya zamanlamayı ezberlemeli. Işın Yön Saptırıcı: Lazerin boss’a isabet etmesini zorlaştırmak için, boss etrafında dönen bir enerji kalkanı vardır. Lazer bu kalkanla çarpıştığında yönü %15 sapar. Doğrudan vuruş zordur, oyuncu açıyı ayarlamak zorunda kalır. Kırmızı Takviye – “Karabüyü Yaratığı”: Boss %50 cana indiğinde, arenaya sadece bir kez özel bir yaratık çağırır: Işıkla değil sadece lazer dalgasıyla hasar alır. Oyuncu E ile aktif edilen lazer dalgayı doğru zamanlamada kullanmalı. ⚔️ Zayıf Noktası: Kristaller kırıldığında zırhı kalkar, bu sürede lazer tam güç vurur. Tüm yetenekleri iptal olur ve 10 saniye tamamen savunmasız kalır. 🎨 Özel Efektler: Kristaller yok olurken parçalanarak cam gibi dağılır. Boss öldüğünde tüm ekran 2 saniyeliğine parlayarak siyah beyaz olur, sonra normal renge döner. 🔥 Boss Dövüşü Stratejisi (Oyuncu İçin): Önce 4 kristali yok et. Işın dalgası geldiğinde yön değişimine dikkat et. Zihin dalgası zamanlarını ezberle. %50 cana indiğinde E tuşunu hazır tut. Tüm sistematik ilerleme ve doğru açı ile lazer yönlendirmesi ile boss’u yenebilirsin. bu boss çok yavaş olsun
User prompt
destekleyen sadece sıradanı destekleyebilir 2 destekleyen birbirini destekleyemez
User prompt
oyun 129da bitiyo bitmemeli
User prompt
500 score yapınca boss gelir artık sadece tek rakip gelir oda boss her vurunca farklı yönden gelir lazerden sağ sol kaçmaya çalıiır
User prompt
lazer mesafesi daha uzun
Code edit (1 edits merged)
Please save this source code
User prompt
Lazer Savunması: Büyücü Kuşatması
Initial prompt
Oyun Özeti - Tam Detaylı Karakter ve Kontrol: Oyuncu, ekranın tam ortasında sabit duran bir ana karakteri yönetir. Karakterin silahı, sürekli açık ve sınırsız menzile sahip bir lazer ışınıdır. Bu lazer, oyuncu tarafından ok tuşları (klavye) veya mobil cihazlarda basılı tutup sağa/sola kaydırarak döndürülür. Lazer sürekli ateş halindedir ve silahın kapatılıp açılması yoktur. Düşman Türleri ve Davranışları: Oyunda üç tür düşman vardır: Normal Düşmanlar (Turuncu): Karaktere doğru doğrudan ilerler. Arkaya geçmez, sadece ilerleyerek saldırmaya çalışır. Lazere Temas Etmiş Düşmanlar (Kırmızı): Normal düşmanlar lazerin ilk darbesiyle kırmızıya döner, ikinci lazer darbesinde silikleşerek 2 saniye içinde yok olur. Büyücüler (Mavi): En yakın normal düşmana destek verir. Büyücü ile desteklenen düşman arasında görünür bir çizgi vardır. Desteklenen düşman bu sayede ölmez, önce büyücü öldürülmelidir. Destekçi büyücü yok edilmeden desteklenen düşmana zarar verilemez. Lazer Etkisi ve Görsel Efektler: Lazer, düşmanlara temas ettiğinde onları yavaşlatır ve hasar verir. İki darbe sonrası düşmanlar silikleşerek yok olur. Silikleşme animasyonu 2 saniye sürer. Destekçilerin çizgisi, destek verdikleri düşmanı koruduklarını net şekilde gösterir. Oyun Amacı ve Strateji: Amaç, düşman dalgalarını lazerle temizlemek. Ancak destekçileri önce yok etmek gerekir; aksi halde desteklenen düşmanlar zarar görmez. Oyuncu lazer yönünü iyi kontrol ederek hem destekçileri hem normal düşmanları sırayla etkisiz hale getirmelidir. Kontroller: Lazer Yönü: Klavyede ok tuşlarıyla, mobilde basılı tutup kaydırarak. Sabit Konum: Karakter hareket etmez, sadece lazerin yönü değiştirilir. Ekstra Mekanikler: Düşmanlar karakterin arkasına geçemez, sadece doğrudan saldırır. Lazer her zaman açık ve otomatik ateş eder, oyuncu sadece yönünü ayarlar. Özet: Orta noktada sabit duran karakter, sürekli açık lazeri ok tuşları veya dokunmatik ile yönlendirerek farklı tür düşmanları (normal ve destekli büyücüler) yok etmeye çalışır. Büyücüler, en yakın düşmanı koruyup onları hasardan korur, bu yüzden önce büyücüyü yok etmek gereklidir. Lazer temasındaki düşmanlar kırmızıya dönüşür, ikinci darbe ile silikleşip 2 saniyede ölür. Amaç tüm düşmanları taktiksel olarak temizlemektir. İstersen daha kısa veya farklı tarzda da yapabilirim.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Boss enemy class var Boss = Container.expand(function () { var self = Container.call(this); self.isBoss = true; self.state = 0; // 0: alive, 1: fading self.bossAsset = self.attachAsset('enemy_shielded', { anchorX: 0.5, anchorY: 0.5 }); self.x = CENTER_X; self.y = CENTER_Y - 700; self.speed = 12; self.targetAngle = 0; self.moveTimer = 0; self.fadeTimer = 0; self.lastLaserHit = false; self.escapeDir = 1; // 1: right, -1: left // Set boss to a new random direction (left or right of laser) self.setNewDirection = function () { // Pick a side to escape: left or right of laser self.escapeDir = Math.random() < 0.5 ? 1 : -1; // Offset angle from laser self.targetAngle = laserAngle + Math.PI / 2 * self.escapeDir; // Clamp to [-PI, PI] if (self.targetAngle > Math.PI) self.targetAngle -= 2 * Math.PI; if (self.targetAngle < -Math.PI) self.targetAngle += 2 * Math.PI; // Set moveTimer for how long to move in this direction self.moveTimer = 30 + Math.floor(Math.random() * 30); }; self.setNewDirection(); self.update = function () { if (self.state === 1) { self.fadeTimer += 1; self.alpha = 1 - self.fadeTimer / 60; if (self.fadeTimer > 60) { self.destroy(); } return; } // Move away from laser direction var moveAngle = self.targetAngle; var moveDist = self.speed; self.x += Math.cos(moveAngle) * moveDist; self.y += Math.sin(moveAngle) * moveDist; // Clamp boss inside game area if (self.x < 200) self.x = 200; if (self.x > 1848) self.x = 1848; if (self.y < 200) self.y = 200; if (self.y > 2532) self.y = 2532; self.moveTimer -= 1; if (self.moveTimer <= 0) { self.setNewDirection(); } }; // Boss takes hit self.hitByLaser = function () { if (self.state === 0) { self.state = 1; self.fadeTimer = 0; LK.getSound('enemy_down').play(); } }; return self; }); // ENEMY STATES // 0: normal // 1: shielded (red) // 2: fading (about to die) var Enemy = Container.expand(function () { var self = Container.call(this); // Default: normal enemy self.state = 0; // 0: normal, 1: shielded, 2: fading self.isWizard = false; self.isProtected = false; // If protected by wizard self.protector = null; // Wizard protecting this enemy // Asset self.enemyAsset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.shieldAsset = null; // For shield effect // For movement self.speed = 2 + Math.random() * 1.5; // Slightly random speed self.angle = 0; // Will be set on spawn self.radius = 0; // Distance from center // For fade-out self.fadeTimer = 0; // For collision self.lastLaserHit = false; // For wizard self.isWizard = false; self.shieldedEnemy = null; // For wizard: the enemy it protects // Set state (change color/asset) self.setState = function (state) { self.state = state; if (self.isWizard) { // Always wizard asset if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('wizard', { anchorX: 0.5, anchorY: 0.5 }); } else if (state === 0) { if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); } else if (state === 1) { if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('enemy_shielded', { anchorX: 0.5, anchorY: 0.5 }); } else if (state === 2) { if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('enemy_fading', { anchorX: 0.5, anchorY: 0.5 }); } }; // Show/hide shield self.setShield = function (on) { if (on && !self.shieldAsset) { self.shieldAsset = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); self.shieldAsset.alpha = 0.35; } else if (!on && self.shieldAsset) { self.shieldAsset.destroy(); self.shieldAsset = null; } }; // Called every tick self.update = function () { // Move towards center var dx = 1024 - self.x; var dy = 1366 - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var moveDist = Math.min(self.speed, dist); self.x += dx / dist * moveDist; self.y += dy / dist * moveDist; } // Fading out if (self.state === 2) { self.fadeTimer += 1; if (self.fadeTimer > 30) { // Remove after fade self.destroy(); } else { self.alpha = 1 - self.fadeTimer / 30; } } }; // For wizard: assign protected enemy self.setShieldedEnemy = function (enemy) { self.shieldedEnemy = enemy; if (enemy) { enemy.isProtected = true; enemy.protector = self; enemy.setShield(true); } }; // For wizard: remove shield from protected enemy self.removeShieldedEnemy = function () { if (self.shieldedEnemy) { self.shieldedEnemy.isProtected = false; self.shieldedEnemy.protector = null; self.shieldedEnemy.setShield(false); self.shieldedEnemy = null; } }; // For protected enemy: called if wizard dies self.removeProtection = function () { self.isProtected = false; self.protector = null; self.setShield(false); }; return self; }); // --- Dangerous Enemy Types --- // Fast enemy: moves faster, dies in 1 hit, red color // Tank enemy: moves slow, takes 3 hits, purple color // Exploder enemy: explodes on death, orange color // Tank Enemy var TankEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.tankHits = 0; // 0,1,2,3 (3rd is death) self.speed = 1.2 + Math.random() * 0.5; self.setState = function (state) { self.state = state; if (self.enemyAsset) self.enemyAsset.destroy(); if (self.tankHits === 0) { self.enemyAsset = self.attachAsset('enemy_tank', { anchorX: 0.5, anchorY: 0.5 }); } else if (self.tankHits === 1) { self.enemyAsset = self.attachAsset('enemy_tank_dmg1', { anchorX: 0.5, anchorY: 0.5 }); } else if (self.tankHits === 2) { self.enemyAsset = self.attachAsset('enemy_tank_dmg2', { anchorX: 0.5, anchorY: 0.5 }); } else { self.enemyAsset = self.attachAsset('enemy_fading', { anchorX: 0.5, anchorY: 0.5 }); } }; self.update = function () { var dx = 1024 - self.x; var dy = 1366 - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var moveDist = Math.min(self.speed, dist); self.x += dx / dist * moveDist; self.y += dy / dist * moveDist; } if (self.state === 2) { self.fadeTimer += 1; if (self.fadeTimer > 40) { self.destroy(); } else { self.alpha = 1 - self.fadeTimer / 40; } } }; return self; }); // --- Dangerous Enemy Classes --- // Fast Enemy var FastEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.speed = 5 + Math.random() * 2; self.setState = function (state) { self.state = state; if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('enemy_fast', { anchorX: 0.5, anchorY: 0.5 }); }; // Only 1 hit to die self.update = function () { var dx = 1024 - self.x; var dy = 1366 - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var moveDist = Math.min(self.speed, dist); self.x += dx / dist * moveDist; self.y += dy / dist * moveDist; } if (self.state === 2) { self.fadeTimer += 1; if (self.fadeTimer > 18) { self.destroy(); } else { self.alpha = 1 - self.fadeTimer / 18; } } }; return self; }); // Exploder Enemy var ExploderEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.speed = 2.5 + Math.random() * 1.2; self.setState = function (state) { self.state = state; if (self.enemyAsset) self.enemyAsset.destroy(); self.enemyAsset = self.attachAsset('enemy_exploder', { anchorX: 0.5, anchorY: 0.5 }); }; self.update = function () { var dx = 1024 - self.x; var dy = 1366 - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var moveDist = Math.min(self.speed, dist); self.x += dx / dist * moveDist; self.y += dy / dist * moveDist; } if (self.state === 2) { self.fadeTimer += 1; if (self.fadeTimer > 22) { self.destroy(); } else { self.alpha = 1 - self.fadeTimer / 22; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181a1b }); /**** * Game Code ****/ // Exploder enemy: explodes on death, orange color // Tank enemy: moves slow, takes 3 hits, purple color // Fast enemy: moves faster, dies in 1 hit, red color // --- Dangerous Enemy Types --- // Center of screen // Main character (center) // Lazer beam (thin, long rectangle) // Enemy: normal // Enemy: shielded (first hit) // Enemy: fading (second hit) // Enemy: wizard // Shield effect (for protected enemies) // Sound for enemy destroyed var CENTER_X = 1024; var CENTER_Y = 1366; // Main character var hero = new Container(); var heroAsset = hero.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); hero.x = CENTER_X; hero.y = CENTER_Y; game.addChild(hero); // Laser var laser = new Container(); var laserAsset = laser.attachAsset('laser', { anchorX: 0.5, anchorY: 0 }); laser.x = CENTER_X; laser.y = CENTER_Y; laser.rotation = 0; game.addChild(laser); // Laser direction (in radians) var laserAngle = 0; // 0 = up var laserTargetAngle = 0; // For smooth tweening // Touch drag control // Remove dragging logic, always follow last touch/mouse position var lastPointer = { x: CENTER_X, y: CENTER_Y }; var enemies = []; var spawnWaveTimer = 0; var waveNumber = 1; // Boss var boss = null; var bossActive = false; var bossDefeated = false; // Score var score = 0; // Import storage plugin for persistent high score // Retrieve high score from storage, or 0 if not set var highScore = storage.highScore || 0; // Score text var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // High score text var highScoreTxt = new Text2('En Yüksek: ' + highScore, { size: 60, fill: 0xFFD700 }); highScoreTxt.anchor.set(0.5, 0); highScoreTxt.y = 110; // Place below the main score LK.gui.top.addChild(highScoreTxt); // Helper: spawn a single enemy at random angle/distance function spawnEnemy(type) { var enemy; if (type === 'wizard') { enemy = new Enemy(); enemy.isWizard = true; enemy.setState(0); } else if (type === 'fast') { enemy = new FastEnemy(); enemy.setState(0); } else if (type === 'tank') { enemy = new TankEnemy(); enemy.setState(0); } else if (type === 'exploder') { enemy = new ExploderEnemy(); enemy.setState(0); } else { enemy = new Enemy(); enemy.setState(0); } // Spawn at random angle, at edge of screen var angle = Math.random() * Math.PI * 2; var dist = 1200 + Math.random() * 400; enemy.x = CENTER_X + Math.cos(angle) * dist; enemy.y = CENTER_Y + Math.sin(angle) * dist; enemy.angle = angle; enemy.radius = dist; // Set speed for normal/wizard if (type === 'wizard') { enemy.speed = 2.5 + Math.random() * 1.2; } else if (type === 'normal') { enemy.speed = 2 + Math.random() * 1.5; } game.addChild(enemy); enemies.push(enemy); return enemy; } // Helper: assign wizards to protect nearest enemy function assignWizards() { // Get all wizards var wizards = []; var normalEnemies = []; for (var i = 0; i < enemies.length; ++i) { var e = enemies[i]; if (e.isWizard) wizards.push(e);else if (!e.isProtected) normalEnemies.push(e); } // For each wizard, find nearest unprotected normal enemy (not wizard, not protected, not fading) for (var j = 0; j < wizards.length; ++j) { var wiz = wizards[j]; // Remove old shield wiz.removeShieldedEnemy(); // Find nearest normal enemy (not wizard, not protected, not fading) var minDist = 99999; var nearest = null; for (var k = 0; k < enemies.length; ++k) { var e2 = enemies[k]; if (e2 === wiz) continue; if (e2.isWizard) continue; // Only shield normal enemies if (e2.isProtected) continue; if (e2.state === 2) continue; // Fading out var dx = wiz.x - e2.x; var dy = wiz.y - e2.y; var d = dx * dx + dy * dy; if (d < minDist) { minDist = d; nearest = e2; } } if (nearest) { wiz.setShieldedEnemy(nearest); } } } // Helper: spawn a wave of enemies function spawnWave() { // After boss is defeated, scale up difficulty and spawn more dangerous enemies var postBoss = bossDefeated && score >= 500; var baseEnemies = 3 + Math.floor(waveNumber * 0.7); var numEnemies = postBoss ? Math.floor(baseEnemies * (1.2 + (score - 500) / 1000)) : baseEnemies; var numWizards = postBoss ? Math.floor(numEnemies * 0.08) : Math.min(1 + Math.floor(waveNumber / 3), Math.floor(numEnemies / 3)); // Dangerous enemy ratios var fastRatio = postBoss ? Math.min(0.25 + (score - 500) / 2000, 0.45) : 0; var tankRatio = postBoss ? Math.min(0.18 + (score - 500) / 3000, 0.32) : 0; var exploderRatio = postBoss ? Math.min(0.12 + (score - 500) / 4000, 0.22) : 0; // Normal enemies become rare var normalRatio = 1 - (fastRatio + tankRatio + exploderRatio + numWizards / numEnemies); // Clamp if (normalRatio < 0.08) normalRatio = 0.08; // Build enemy type pool var pool = []; for (var i = 0; i < Math.floor(numEnemies * fastRatio); ++i) pool.push('fast'); for (var i = 0; i < Math.floor(numEnemies * tankRatio); ++i) pool.push('tank'); for (var i = 0; i < Math.floor(numEnemies * exploderRatio); ++i) pool.push('exploder'); for (var i = 0; i < Math.floor(numEnemies * normalRatio); ++i) pool.push('normal'); // Fill up to numEnemies while (pool.length < numEnemies) pool.push('normal'); // Shuffle pool for (var i = pool.length - 1; i > 0; --i) { var ri = Math.floor(Math.random() * (i + 1)); var tmp = pool[i]; pool[i] = pool[ri]; pool[ri] = tmp; } // Spawn wizards for (var i = 0; i < numWizards; ++i) { spawnEnemy('wizard'); } // Spawn from pool for (var j = 0; j < pool.length; ++j) { spawnEnemy(pool[j]); } assignWizards(); waveNumber += 1; } // Helper: check if a point is inside the laser beam function pointInLaser(px, py) { // Laser is a rectangle from (CENTER_X, CENTER_Y) in direction laserAngle, length = laserAsset.height var dx = px - CENTER_X; var dy = py - CENTER_Y; var len = Math.sqrt(dx * dx + dy * dy); if (len < 60) return false; // Don't hit at center var angleToPoint = Math.atan2(dy, dx); var diff = Math.abs(angleToPoint - laserAngle); // Normalize diff to [0, PI] while (diff > Math.PI) diff = Math.abs(diff - 2 * Math.PI); // If within 0.13 rad (~7.5 deg) of laser direction, and within laser length if (diff < 0.13 && len < laserAsset.height) { return true; } return false; } // Helper: remove enemy from array and game function removeEnemy(enemy) { // Remove shield if wizard if (enemy.isWizard) { enemy.removeShieldedEnemy(); } // Remove protection if protected if (enemy.isProtected && enemy.protector) { enemy.protector.removeShieldedEnemy(); } for (var i = enemies.length - 1; i >= 0; --i) { if (enemies[i] === enemy) { enemies.splice(i, 1); break; } } enemy.destroy(); } // Touch/drag controls game.down = function (x, y, obj) { // Ignore top left 100x100 for menu if (x < 100 && y < 100) return; // Always update last pointer position and angle lastPointer.x = x; lastPointer.y = y; var dx = x - CENTER_X; var dy = y - CENTER_Y; var angle = Math.atan2(dy, dx); if (angle > Math.PI) angle -= 2 * Math.PI; if (angle < -Math.PI) angle += 2 * Math.PI; laserTargetAngle = angle; }; game.move = function (x, y, obj) { // Always update last pointer position lastPointer.x = x; lastPointer.y = y; // Calculate angle from center to pointer var dx = x - CENTER_X; var dy = y - CENTER_Y; var angle = Math.atan2(dy, dx); // Clamp to [-PI, PI] if (angle > Math.PI) angle -= 2 * Math.PI; if (angle < -Math.PI) angle += 2 * Math.PI; laserTargetAngle = angle; }; game.up = function (x, y, obj) { // No drag state to reset, but update pointer and angle for consistency lastPointer.x = x; lastPointer.y = y; var dx = x - CENTER_X; var dy = y - CENTER_Y; var angle = Math.atan2(dy, dx); if (angle > Math.PI) angle -= 2 * Math.PI; if (angle < -Math.PI) angle += 2 * Math.PI; laserTargetAngle = angle; }; // Main update loop game.update = function () { // Smoothly rotate laser towards target angle var diff = laserTargetAngle - laserAngle; while (diff > Math.PI) diff -= 2 * Math.PI; while (diff < -Math.PI) diff += 2 * Math.PI; laserAngle += diff * 0.18; // Smooth // Clamp if (laserAngle > Math.PI) laserAngle -= 2 * Math.PI; if (laserAngle < -Math.PI) laserAngle += 2 * Math.PI; laser.rotation = laserAngle - Math.PI / 2; // Because asset is vertical // Boss phase logic if (!bossActive && score >= 500 && !bossDefeated) { // Remove all enemies for (var i = enemies.length - 1; i >= 0; --i) { enemies[i].destroy(); } enemies = []; // Spawn boss boss = new Boss(); boss.x = CENTER_X; boss.y = CENTER_Y - 700; game.addChild(boss); bossActive = true; } if (bossActive && boss && !bossDefeated) { boss.update(); // Boss collision with laser if (boss.state === 0 && pointInLaser(boss.x, boss.y)) { boss.hitByLaser(); score += 20; scoreTxt.setText(score); // Update high score if needed if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } } // Remove boss if faded out if (boss.state === 1 && boss.fadeTimer > 60) { boss.destroy(); boss = null; bossActive = false; bossDefeated = true; // No win popup, continue game // Resume spawning waves waveNumber += 1; spawnWaveTimer = 0; // Optionally, you can spawn a new wave immediately or let the normal wave logic handle it // spawnWave(); // No return here, let the game continue } // Boss game over if reaches center if (boss) { var bdx = boss.x - CENTER_X; var bdy = boss.y - CENTER_Y; var bdist = Math.sqrt(bdx * bdx + bdy * bdy); if (bdist < 120 && boss.state === 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } return; // Only boss is active, skip rest } // Update all enemies for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // Check if reached center (game over) var dx = e.x - CENTER_X; var dy = e.y - CENTER_Y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 100 && e.state !== 2) { // Game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Laser collision var anyLaserHit = false; for (var j = enemies.length - 1; j >= 0; --j) { var e2 = enemies[j]; if (e2.state === 2) continue; // Already dying if (pointInLaser(e2.x, e2.y)) { // If protected, can't be hit if (e2.isProtected) { // Show shield effect e2.setShield(true); continue; } // Wizards: die in one hit if (e2.isWizard) { e2.setState(2); e2.fadeTimer = 0; e2.removeShieldedEnemy(); LK.getSound('wizard_down').play(); score += 5; scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } anyLaserHit = true; continue; } // Fast enemy: 1 hit to die if (e2 instanceof FastEnemy) { e2.setState(2); e2.fadeTimer = 0; LK.getSound('enemy_down').play(); score += 2; scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } anyLaserHit = true; continue; } // Tank enemy: 3 hits to die if (e2 instanceof TankEnemy) { if (e2.state !== 2) { e2.tankHits += 1; if (e2.tankHits < 3) { e2.setState(0); LK.getSound('laser_hit').play(); } else { e2.setState(2); e2.fadeTimer = 0; LK.getSound('enemy_down').play(); score += 4; scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } } anyLaserHit = true; continue; } } // Exploder enemy: 1 hit to die, but will explode (handled in removeEnemy) if (e2 instanceof ExploderEnemy) { e2.setState(2); e2.fadeTimer = 0; LK.getSound('enemy_down').play(); score += 3; scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } anyLaserHit = true; continue; } // Normal enemy: 2 hits to die if (e2.state === 0) { e2.setState(1); LK.getSound('laser_hit').play(); anyLaserHit = true; } else if (e2.state === 1) { e2.setState(2); e2.fadeTimer = 0; LK.getSound('enemy_down').play(); score += 1; scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('En Yüksek: ' + highScore); } anyLaserHit = true; } } else { // Not hit, remove shield effect if any if (!e2.isWizard && !e2.isProtected) { e2.setShield(false); } } } // Remove dead enemies for (var k = enemies.length - 1; k >= 0; --k) { var e3 = enemies[k]; // Exploder enemy: explode on death if (e3 instanceof ExploderEnemy && e3.state === 2 && e3.fadeTimer === 22) { // Check if player is close to explosion var dx = e3.x - CENTER_X; var dy = e3.y - CENTER_Y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 220) { LK.effects.flashScreen(0xff6600, 1000); LK.showGameOver(); return; } // Optionally, damage other enemies in radius (not implemented for simplicity) } if (e3.state === 2 && (e3 instanceof FastEnemy && e3.fadeTimer > 18 || e3 instanceof TankEnemy && e3.fadeTimer > 40 || e3 instanceof ExploderEnemy && e3.fadeTimer > 22 || !(e3 instanceof FastEnemy) && !(e3 instanceof TankEnemy) && !(e3 instanceof ExploderEnemy) && e3.fadeTimer > 30)) { removeEnemy(e3); } } // If all enemies gone, spawn next wave var living = 0; for (var m = 0; m < enemies.length; ++m) { if (enemies[m].state !== 2) living += 1; } if (living === 0) { spawnWaveTimer += 1; if (spawnWaveTimer > 40) { spawnWave(); spawnWaveTimer = 0; } } else { spawnWaveTimer = 0; } // (Removed wave-based win condition so game continues indefinitely) }; // Start first wave spawnWave(); scoreTxt.setText(score); // Play action-packed background music LK.playMusic('action_bgmusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Boss enemy class
var Boss = Container.expand(function () {
var self = Container.call(this);
self.isBoss = true;
self.state = 0; // 0: alive, 1: fading
self.bossAsset = self.attachAsset('enemy_shielded', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = CENTER_X;
self.y = CENTER_Y - 700;
self.speed = 12;
self.targetAngle = 0;
self.moveTimer = 0;
self.fadeTimer = 0;
self.lastLaserHit = false;
self.escapeDir = 1; // 1: right, -1: left
// Set boss to a new random direction (left or right of laser)
self.setNewDirection = function () {
// Pick a side to escape: left or right of laser
self.escapeDir = Math.random() < 0.5 ? 1 : -1;
// Offset angle from laser
self.targetAngle = laserAngle + Math.PI / 2 * self.escapeDir;
// Clamp to [-PI, PI]
if (self.targetAngle > Math.PI) self.targetAngle -= 2 * Math.PI;
if (self.targetAngle < -Math.PI) self.targetAngle += 2 * Math.PI;
// Set moveTimer for how long to move in this direction
self.moveTimer = 30 + Math.floor(Math.random() * 30);
};
self.setNewDirection();
self.update = function () {
if (self.state === 1) {
self.fadeTimer += 1;
self.alpha = 1 - self.fadeTimer / 60;
if (self.fadeTimer > 60) {
self.destroy();
}
return;
}
// Move away from laser direction
var moveAngle = self.targetAngle;
var moveDist = self.speed;
self.x += Math.cos(moveAngle) * moveDist;
self.y += Math.sin(moveAngle) * moveDist;
// Clamp boss inside game area
if (self.x < 200) self.x = 200;
if (self.x > 1848) self.x = 1848;
if (self.y < 200) self.y = 200;
if (self.y > 2532) self.y = 2532;
self.moveTimer -= 1;
if (self.moveTimer <= 0) {
self.setNewDirection();
}
};
// Boss takes hit
self.hitByLaser = function () {
if (self.state === 0) {
self.state = 1;
self.fadeTimer = 0;
LK.getSound('enemy_down').play();
}
};
return self;
});
// ENEMY STATES
// 0: normal
// 1: shielded (red)
// 2: fading (about to die)
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Default: normal enemy
self.state = 0; // 0: normal, 1: shielded, 2: fading
self.isWizard = false;
self.isProtected = false; // If protected by wizard
self.protector = null; // Wizard protecting this enemy
// Asset
self.enemyAsset = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.shieldAsset = null; // For shield effect
// For movement
self.speed = 2 + Math.random() * 1.5; // Slightly random speed
self.angle = 0; // Will be set on spawn
self.radius = 0; // Distance from center
// For fade-out
self.fadeTimer = 0;
// For collision
self.lastLaserHit = false;
// For wizard
self.isWizard = false;
self.shieldedEnemy = null; // For wizard: the enemy it protects
// Set state (change color/asset)
self.setState = function (state) {
self.state = state;
if (self.isWizard) {
// Always wizard asset
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (state === 0) {
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (state === 1) {
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('enemy_shielded', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (state === 2) {
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('enemy_fading', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
// Show/hide shield
self.setShield = function (on) {
if (on && !self.shieldAsset) {
self.shieldAsset = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.shieldAsset.alpha = 0.35;
} else if (!on && self.shieldAsset) {
self.shieldAsset.destroy();
self.shieldAsset = null;
}
};
// Called every tick
self.update = function () {
// Move towards center
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var moveDist = Math.min(self.speed, dist);
self.x += dx / dist * moveDist;
self.y += dy / dist * moveDist;
}
// Fading out
if (self.state === 2) {
self.fadeTimer += 1;
if (self.fadeTimer > 30) {
// Remove after fade
self.destroy();
} else {
self.alpha = 1 - self.fadeTimer / 30;
}
}
};
// For wizard: assign protected enemy
self.setShieldedEnemy = function (enemy) {
self.shieldedEnemy = enemy;
if (enemy) {
enemy.isProtected = true;
enemy.protector = self;
enemy.setShield(true);
}
};
// For wizard: remove shield from protected enemy
self.removeShieldedEnemy = function () {
if (self.shieldedEnemy) {
self.shieldedEnemy.isProtected = false;
self.shieldedEnemy.protector = null;
self.shieldedEnemy.setShield(false);
self.shieldedEnemy = null;
}
};
// For protected enemy: called if wizard dies
self.removeProtection = function () {
self.isProtected = false;
self.protector = null;
self.setShield(false);
};
return self;
});
// --- Dangerous Enemy Types ---
// Fast enemy: moves faster, dies in 1 hit, red color
// Tank enemy: moves slow, takes 3 hits, purple color
// Exploder enemy: explodes on death, orange color
// Tank Enemy
var TankEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
self.tankHits = 0; // 0,1,2,3 (3rd is death)
self.speed = 1.2 + Math.random() * 0.5;
self.setState = function (state) {
self.state = state;
if (self.enemyAsset) self.enemyAsset.destroy();
if (self.tankHits === 0) {
self.enemyAsset = self.attachAsset('enemy_tank', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.tankHits === 1) {
self.enemyAsset = self.attachAsset('enemy_tank_dmg1', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.tankHits === 2) {
self.enemyAsset = self.attachAsset('enemy_tank_dmg2', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.enemyAsset = self.attachAsset('enemy_fading', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.update = function () {
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var moveDist = Math.min(self.speed, dist);
self.x += dx / dist * moveDist;
self.y += dy / dist * moveDist;
}
if (self.state === 2) {
self.fadeTimer += 1;
if (self.fadeTimer > 40) {
self.destroy();
} else {
self.alpha = 1 - self.fadeTimer / 40;
}
}
};
return self;
});
// --- Dangerous Enemy Classes ---
// Fast Enemy
var FastEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
self.speed = 5 + Math.random() * 2;
self.setState = function (state) {
self.state = state;
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('enemy_fast', {
anchorX: 0.5,
anchorY: 0.5
});
};
// Only 1 hit to die
self.update = function () {
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var moveDist = Math.min(self.speed, dist);
self.x += dx / dist * moveDist;
self.y += dy / dist * moveDist;
}
if (self.state === 2) {
self.fadeTimer += 1;
if (self.fadeTimer > 18) {
self.destroy();
} else {
self.alpha = 1 - self.fadeTimer / 18;
}
}
};
return self;
});
// Exploder Enemy
var ExploderEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
self.speed = 2.5 + Math.random() * 1.2;
self.setState = function (state) {
self.state = state;
if (self.enemyAsset) self.enemyAsset.destroy();
self.enemyAsset = self.attachAsset('enemy_exploder', {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
var moveDist = Math.min(self.speed, dist);
self.x += dx / dist * moveDist;
self.y += dy / dist * moveDist;
}
if (self.state === 2) {
self.fadeTimer += 1;
if (self.fadeTimer > 22) {
self.destroy();
} else {
self.alpha = 1 - self.fadeTimer / 22;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181a1b
});
/****
* Game Code
****/
// Exploder enemy: explodes on death, orange color
// Tank enemy: moves slow, takes 3 hits, purple color
// Fast enemy: moves faster, dies in 1 hit, red color
// --- Dangerous Enemy Types ---
// Center of screen
// Main character (center)
// Lazer beam (thin, long rectangle)
// Enemy: normal
// Enemy: shielded (first hit)
// Enemy: fading (second hit)
// Enemy: wizard
// Shield effect (for protected enemies)
// Sound for enemy destroyed
var CENTER_X = 1024;
var CENTER_Y = 1366;
// Main character
var hero = new Container();
var heroAsset = hero.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
hero.x = CENTER_X;
hero.y = CENTER_Y;
game.addChild(hero);
// Laser
var laser = new Container();
var laserAsset = laser.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0
});
laser.x = CENTER_X;
laser.y = CENTER_Y;
laser.rotation = 0;
game.addChild(laser);
// Laser direction (in radians)
var laserAngle = 0; // 0 = up
var laserTargetAngle = 0; // For smooth tweening
// Touch drag control
// Remove dragging logic, always follow last touch/mouse position
var lastPointer = {
x: CENTER_X,
y: CENTER_Y
};
var enemies = [];
var spawnWaveTimer = 0;
var waveNumber = 1;
// Boss
var boss = null;
var bossActive = false;
var bossDefeated = false;
// Score
var score = 0;
// Import storage plugin for persistent high score
// Retrieve high score from storage, or 0 if not set
var highScore = storage.highScore || 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// High score text
var highScoreTxt = new Text2('En Yüksek: ' + highScore, {
size: 60,
fill: 0xFFD700
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 110; // Place below the main score
LK.gui.top.addChild(highScoreTxt);
// Helper: spawn a single enemy at random angle/distance
function spawnEnemy(type) {
var enemy;
if (type === 'wizard') {
enemy = new Enemy();
enemy.isWizard = true;
enemy.setState(0);
} else if (type === 'fast') {
enemy = new FastEnemy();
enemy.setState(0);
} else if (type === 'tank') {
enemy = new TankEnemy();
enemy.setState(0);
} else if (type === 'exploder') {
enemy = new ExploderEnemy();
enemy.setState(0);
} else {
enemy = new Enemy();
enemy.setState(0);
}
// Spawn at random angle, at edge of screen
var angle = Math.random() * Math.PI * 2;
var dist = 1200 + Math.random() * 400;
enemy.x = CENTER_X + Math.cos(angle) * dist;
enemy.y = CENTER_Y + Math.sin(angle) * dist;
enemy.angle = angle;
enemy.radius = dist;
// Set speed for normal/wizard
if (type === 'wizard') {
enemy.speed = 2.5 + Math.random() * 1.2;
} else if (type === 'normal') {
enemy.speed = 2 + Math.random() * 1.5;
}
game.addChild(enemy);
enemies.push(enemy);
return enemy;
}
// Helper: assign wizards to protect nearest enemy
function assignWizards() {
// Get all wizards
var wizards = [];
var normalEnemies = [];
for (var i = 0; i < enemies.length; ++i) {
var e = enemies[i];
if (e.isWizard) wizards.push(e);else if (!e.isProtected) normalEnemies.push(e);
}
// For each wizard, find nearest unprotected normal enemy (not wizard, not protected, not fading)
for (var j = 0; j < wizards.length; ++j) {
var wiz = wizards[j];
// Remove old shield
wiz.removeShieldedEnemy();
// Find nearest normal enemy (not wizard, not protected, not fading)
var minDist = 99999;
var nearest = null;
for (var k = 0; k < enemies.length; ++k) {
var e2 = enemies[k];
if (e2 === wiz) continue;
if (e2.isWizard) continue; // Only shield normal enemies
if (e2.isProtected) continue;
if (e2.state === 2) continue; // Fading out
var dx = wiz.x - e2.x;
var dy = wiz.y - e2.y;
var d = dx * dx + dy * dy;
if (d < minDist) {
minDist = d;
nearest = e2;
}
}
if (nearest) {
wiz.setShieldedEnemy(nearest);
}
}
}
// Helper: spawn a wave of enemies
function spawnWave() {
// After boss is defeated, scale up difficulty and spawn more dangerous enemies
var postBoss = bossDefeated && score >= 500;
var baseEnemies = 3 + Math.floor(waveNumber * 0.7);
var numEnemies = postBoss ? Math.floor(baseEnemies * (1.2 + (score - 500) / 1000)) : baseEnemies;
var numWizards = postBoss ? Math.floor(numEnemies * 0.08) : Math.min(1 + Math.floor(waveNumber / 3), Math.floor(numEnemies / 3));
// Dangerous enemy ratios
var fastRatio = postBoss ? Math.min(0.25 + (score - 500) / 2000, 0.45) : 0;
var tankRatio = postBoss ? Math.min(0.18 + (score - 500) / 3000, 0.32) : 0;
var exploderRatio = postBoss ? Math.min(0.12 + (score - 500) / 4000, 0.22) : 0;
// Normal enemies become rare
var normalRatio = 1 - (fastRatio + tankRatio + exploderRatio + numWizards / numEnemies);
// Clamp
if (normalRatio < 0.08) normalRatio = 0.08;
// Build enemy type pool
var pool = [];
for (var i = 0; i < Math.floor(numEnemies * fastRatio); ++i) pool.push('fast');
for (var i = 0; i < Math.floor(numEnemies * tankRatio); ++i) pool.push('tank');
for (var i = 0; i < Math.floor(numEnemies * exploderRatio); ++i) pool.push('exploder');
for (var i = 0; i < Math.floor(numEnemies * normalRatio); ++i) pool.push('normal');
// Fill up to numEnemies
while (pool.length < numEnemies) pool.push('normal');
// Shuffle pool
for (var i = pool.length - 1; i > 0; --i) {
var ri = Math.floor(Math.random() * (i + 1));
var tmp = pool[i];
pool[i] = pool[ri];
pool[ri] = tmp;
}
// Spawn wizards
for (var i = 0; i < numWizards; ++i) {
spawnEnemy('wizard');
}
// Spawn from pool
for (var j = 0; j < pool.length; ++j) {
spawnEnemy(pool[j]);
}
assignWizards();
waveNumber += 1;
}
// Helper: check if a point is inside the laser beam
function pointInLaser(px, py) {
// Laser is a rectangle from (CENTER_X, CENTER_Y) in direction laserAngle, length = laserAsset.height
var dx = px - CENTER_X;
var dy = py - CENTER_Y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len < 60) return false; // Don't hit at center
var angleToPoint = Math.atan2(dy, dx);
var diff = Math.abs(angleToPoint - laserAngle);
// Normalize diff to [0, PI]
while (diff > Math.PI) diff = Math.abs(diff - 2 * Math.PI);
// If within 0.13 rad (~7.5 deg) of laser direction, and within laser length
if (diff < 0.13 && len < laserAsset.height) {
return true;
}
return false;
}
// Helper: remove enemy from array and game
function removeEnemy(enemy) {
// Remove shield if wizard
if (enemy.isWizard) {
enemy.removeShieldedEnemy();
}
// Remove protection if protected
if (enemy.isProtected && enemy.protector) {
enemy.protector.removeShieldedEnemy();
}
for (var i = enemies.length - 1; i >= 0; --i) {
if (enemies[i] === enemy) {
enemies.splice(i, 1);
break;
}
}
enemy.destroy();
}
// Touch/drag controls
game.down = function (x, y, obj) {
// Ignore top left 100x100 for menu
if (x < 100 && y < 100) return;
// Always update last pointer position and angle
lastPointer.x = x;
lastPointer.y = y;
var dx = x - CENTER_X;
var dy = y - CENTER_Y;
var angle = Math.atan2(dy, dx);
if (angle > Math.PI) angle -= 2 * Math.PI;
if (angle < -Math.PI) angle += 2 * Math.PI;
laserTargetAngle = angle;
};
game.move = function (x, y, obj) {
// Always update last pointer position
lastPointer.x = x;
lastPointer.y = y;
// Calculate angle from center to pointer
var dx = x - CENTER_X;
var dy = y - CENTER_Y;
var angle = Math.atan2(dy, dx);
// Clamp to [-PI, PI]
if (angle > Math.PI) angle -= 2 * Math.PI;
if (angle < -Math.PI) angle += 2 * Math.PI;
laserTargetAngle = angle;
};
game.up = function (x, y, obj) {
// No drag state to reset, but update pointer and angle for consistency
lastPointer.x = x;
lastPointer.y = y;
var dx = x - CENTER_X;
var dy = y - CENTER_Y;
var angle = Math.atan2(dy, dx);
if (angle > Math.PI) angle -= 2 * Math.PI;
if (angle < -Math.PI) angle += 2 * Math.PI;
laserTargetAngle = angle;
};
// Main update loop
game.update = function () {
// Smoothly rotate laser towards target angle
var diff = laserTargetAngle - laserAngle;
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
laserAngle += diff * 0.18; // Smooth
// Clamp
if (laserAngle > Math.PI) laserAngle -= 2 * Math.PI;
if (laserAngle < -Math.PI) laserAngle += 2 * Math.PI;
laser.rotation = laserAngle - Math.PI / 2; // Because asset is vertical
// Boss phase logic
if (!bossActive && score >= 500 && !bossDefeated) {
// Remove all enemies
for (var i = enemies.length - 1; i >= 0; --i) {
enemies[i].destroy();
}
enemies = [];
// Spawn boss
boss = new Boss();
boss.x = CENTER_X;
boss.y = CENTER_Y - 700;
game.addChild(boss);
bossActive = true;
}
if (bossActive && boss && !bossDefeated) {
boss.update();
// Boss collision with laser
if (boss.state === 0 && pointInLaser(boss.x, boss.y)) {
boss.hitByLaser();
score += 20;
scoreTxt.setText(score);
// Update high score if needed
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
}
// Remove boss if faded out
if (boss.state === 1 && boss.fadeTimer > 60) {
boss.destroy();
boss = null;
bossActive = false;
bossDefeated = true;
// No win popup, continue game
// Resume spawning waves
waveNumber += 1;
spawnWaveTimer = 0;
// Optionally, you can spawn a new wave immediately or let the normal wave logic handle it
// spawnWave();
// No return here, let the game continue
}
// Boss game over if reaches center
if (boss) {
var bdx = boss.x - CENTER_X;
var bdy = boss.y - CENTER_Y;
var bdist = Math.sqrt(bdx * bdx + bdy * bdy);
if (bdist < 120 && boss.state === 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
return; // Only boss is active, skip rest
}
// Update all enemies
for (var i = enemies.length - 1; i >= 0; --i) {
var e = enemies[i];
e.update();
// Check if reached center (game over)
var dx = e.x - CENTER_X;
var dy = e.y - CENTER_Y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 100 && e.state !== 2) {
// Game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Laser collision
var anyLaserHit = false;
for (var j = enemies.length - 1; j >= 0; --j) {
var e2 = enemies[j];
if (e2.state === 2) continue; // Already dying
if (pointInLaser(e2.x, e2.y)) {
// If protected, can't be hit
if (e2.isProtected) {
// Show shield effect
e2.setShield(true);
continue;
}
// Wizards: die in one hit
if (e2.isWizard) {
e2.setState(2);
e2.fadeTimer = 0;
e2.removeShieldedEnemy();
LK.getSound('wizard_down').play();
score += 5;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
anyLaserHit = true;
continue;
}
// Fast enemy: 1 hit to die
if (e2 instanceof FastEnemy) {
e2.setState(2);
e2.fadeTimer = 0;
LK.getSound('enemy_down').play();
score += 2;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
anyLaserHit = true;
continue;
}
// Tank enemy: 3 hits to die
if (e2 instanceof TankEnemy) {
if (e2.state !== 2) {
e2.tankHits += 1;
if (e2.tankHits < 3) {
e2.setState(0);
LK.getSound('laser_hit').play();
} else {
e2.setState(2);
e2.fadeTimer = 0;
LK.getSound('enemy_down').play();
score += 4;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
}
anyLaserHit = true;
continue;
}
}
// Exploder enemy: 1 hit to die, but will explode (handled in removeEnemy)
if (e2 instanceof ExploderEnemy) {
e2.setState(2);
e2.fadeTimer = 0;
LK.getSound('enemy_down').play();
score += 3;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
anyLaserHit = true;
continue;
}
// Normal enemy: 2 hits to die
if (e2.state === 0) {
e2.setState(1);
LK.getSound('laser_hit').play();
anyLaserHit = true;
} else if (e2.state === 1) {
e2.setState(2);
e2.fadeTimer = 0;
LK.getSound('enemy_down').play();
score += 1;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('En Yüksek: ' + highScore);
}
anyLaserHit = true;
}
} else {
// Not hit, remove shield effect if any
if (!e2.isWizard && !e2.isProtected) {
e2.setShield(false);
}
}
}
// Remove dead enemies
for (var k = enemies.length - 1; k >= 0; --k) {
var e3 = enemies[k];
// Exploder enemy: explode on death
if (e3 instanceof ExploderEnemy && e3.state === 2 && e3.fadeTimer === 22) {
// Check if player is close to explosion
var dx = e3.x - CENTER_X;
var dy = e3.y - CENTER_Y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 220) {
LK.effects.flashScreen(0xff6600, 1000);
LK.showGameOver();
return;
}
// Optionally, damage other enemies in radius (not implemented for simplicity)
}
if (e3.state === 2 && (e3 instanceof FastEnemy && e3.fadeTimer > 18 || e3 instanceof TankEnemy && e3.fadeTimer > 40 || e3 instanceof ExploderEnemy && e3.fadeTimer > 22 || !(e3 instanceof FastEnemy) && !(e3 instanceof TankEnemy) && !(e3 instanceof ExploderEnemy) && e3.fadeTimer > 30)) {
removeEnemy(e3);
}
}
// If all enemies gone, spawn next wave
var living = 0;
for (var m = 0; m < enemies.length; ++m) {
if (enemies[m].state !== 2) living += 1;
}
if (living === 0) {
spawnWaveTimer += 1;
if (spawnWaveTimer > 40) {
spawnWave();
spawnWaveTimer = 0;
}
} else {
spawnWaveTimer = 0;
}
// (Removed wave-based win condition so game continues indefinitely)
};
// Start first wave
spawnWave();
scoreTxt.setText(score);
// Play action-packed background music
LK.playMusic('action_bgmusic');