Code edit (2 edits merged)
Please save this source code
User prompt
Karakterim veya düşman can yenilediği zaman bu can yenilenmesini miktarını siyah çerçeveli yeşil yazı olarak görmek istiyorum. Ayrıca mesela ben düşmana birinci seviye bleeding uyguladıysam yani düşman 4 saniye boyunca her yarım saniyede bir azami canının %5 kadarı hasar alacaksa düşmanın 10 canı varsa mesela her yarım saniyede 0.5 hasar almalı. Ben düşmana bleeding uygulayınca düşman galiba hasar almıyor, hasar alıyorsa verdiğim hasarı gösteren yazı çıkmıyor. Ayrıca birinci seviye HP regeneration aldığımda fark ettiğim kadarıyla 5 saniyede bir can yeniliyor fakat %1 yenilemiyor. Mesela benim canım 120 ise %1 olarak 1.2 can yenilemesi gerekirken onun yerine dümdüz 1 can yeniliyor. Bunların düzeltilmesini istiyorum. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: finalDmg is not defined' in or related to this line: 'var reducedDmg = finalDmg;' Line Number: 1905
User prompt
Bunu düzeltebilir misin peki o halde?
User prompt
Şu anda hasar azaltma buff'um doğru çalışıyor mu? Az önce %10 hasar azaltma almıştım ama düşman bana hala aynı vuruyordu, düşmandan aldığım hasar azaltılmadı sanki.
User prompt
Sağlık barları şu anda elips şeklinde gözüküyor, dikdörtgen değiller. Ayrıca can azaldıkça sağ taraftan sol tarafa doğru boşalıyormuş gibi gitmeli can. Şu anda küçülen elipsler şeklinde gidiyor can ve bunu istemiyorum. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sağlık barları dikdörtgen şeklinde ve biraz daha büyük olmalı.
User prompt
Her dalga bittikten sonra yeni dalga direkt başlamasın, bir dalga bittikten sonra diğer dalganın başlaması için 3 saniye bekleme olsun. Ayrıca karakterimin canını sağlık barı olarak da karakterimin üstünde görebilmek istiyorum. Benzer şekilde düşmanların da canlarını düşmanların üstünde sağlık barı olarak görebilmek istiyorum. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Kodu implement et.
User prompt
Oyuna kritik vuruş ihtimali diye bir şey ekleyelim. Karakterim oyuna %25 kritik vuruş ihtimali ile başlasın. Düşmanların da %25 kritik vuruş ihtimali olsun. Kritik vuruşların da iki türü var, birisi düşük kritik vuruş diğeri yüksek kritik vuruş. Düşük kritik vuruşlar fazladan %20, yüksek kritik vuruşlar fazladan %40 hasar verilmesini sağlar. (Yani 10 vuran bir saldırı düşük kritik vuruş yaparsa 12 vurur, yüksek kritik vuruş yaparsa 14 vurur şeklinde...) Karakterimin normal vuruşlarında çıkan hasar yazısı siyah çerçeveli beyaz bir yazı olsun. Karakterimin düşük kritik vuruşlarında çıkan hasar yazısı siyah çerçeveli sarı bir yazı olsun. Karakterimin yüksek kritik vuruşlarında çıkan hasar yazısı siyah çerçeveli kırmızı bir yazı olsun. Critical Hit Chance+ diye 4. seçeneklerde gözükebilen yeni bir buff ekleyelim. Critical Hit Chance+, ilk alışta karakterin kritik vuruş ihtimalini %15 arttırır. Sonrasındaki her yükseltilişinde karakterin kritik vuruş şansı yüzdesini +15 arttırır. (örneğin ikinci yükseltmede karakterin kritik vuruş şansını total %30 arttırmış olur, 3. yükseltmede karakterin karakterin kritik vuruş şansını total %45 arttırmış olur şeklinde...) Şimdi bu söylediklerime göre istediklerimi oyuna implement et.
User prompt
Seçim kartları birbirine çok yakın duruyor, aralarındaki mesafeyi açmamız lazım biraz. Ayrıca 4. kartın görseli diğer kart görseline benzeyecek ama rengi diğer kart görselinin mavi renklisi olacak. Ayrıca düşmana vurduğum zaman vurduğum hasarı miktarını gösteren bir yazının çıkıp yarım saniye gözüküp yavaşça yok olmasını istiyorum. Saldırı hasarım ve mevcut can miktarım float olabilir yalnızca virgülden sonra (noktadan sonra) bir basamağını gösterecek şekilde. (örneğin saldırım 8.4 olabilir, canım 103.7/120 olabilir vesaire...) Buna göre istediklerimi koduma implement et. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Karakterim hasar aldığında "damageTaken" sesi çalınsın istiyorum. Ayrıca her seviye atladığımda artık 3 seçenek değil 4 seçenek sunsun ve 4. seçenek her zaman şunlardan birisi olsun: Damage Reduction+, Movement Speed Increase+, HP Regeneration+, Damage Reflection+, Grit Wound+, Enemy Slow+, Enemy Stun+ ya da Bleeding+. Bu saydığım şeylere buff diyebiliriz. Buffları hakkında aşağıda ne işe yaradıklarını detaylı olarak anlattım. Damage Reduction+, ilk alışta karakterin aldığı hasarı %10 azaltır. Sonrasındaki her yükseltilişinde karakterin aldığı hasarın yüzdesini +10 daha azaltır. (örneğin ikinci yükseltmede total %20 hasar azaltma, 3. yükseltmede total %30 hasar azaltma şeklinde...) Movement Speed Increase+, ilk alışta karakterin hareket hızı %20 artar. Sonrasındaki her yükseltilişinde karakterin hareket hızı yüzdesini +20 daha arttırır. (örneğin ikinci yükseltmede total %40 hareket hızı artışı, 3. yükseltmede total %60 hareket hızı artışı şeklinde...) HP Regeneration+, ilk alışta karakter her 5 saniyede bir %1 can yeniler. Sonrasındaki her yükseltilişinde can yenilenmesi yüzdesi +1 daha artar. (örneğin ikinci yükseltmede 5 saniyede bir total %2 can yenilenmesi, 3. yükseltmede 5 saniyede bir total %3 can yenilenmesi şeklinde...) Damage Reflection+, ilk alışta karakter aldığı hasarın %5 kadarını düşmana geri yansıtır. Sonrasındaki her yükseltilişinde yansıttığı hasar yüzdesi +5 daha artar. (örneğin ikinci yükseltmede total %10 hasar yansıtma, 3. yükseltmede total %15 hasar yansıtma şeklinde...) Grit Wound+, ilk alışta karakterin hasar verdiği düşmanın can yenilenmesini %10 azaltır. Sonraki her yükseltilişinde karakterin hasar verdiği düşmanın can yenilenmesi yüzdesini +10 daha azaltır. (örneğin ikinci yükseltmede total %20 düşman can yenilenmesi azaltma, 3. yükseltmede total %30 düşman can yenilenmesi azaltma şeklinde...) Enemy Slow+, ilk alışta karakterin hasar verdiği düşmanlar %10 yavaşlar. Sonrasındaki her yükseltilişinde karakterin hasar verdiği düşmanların yavaşlama yüzdesini +10 daha arttırır. (örneğin ikinci yükseltmede karakterin hasar verdiği düşmanların yavaşlaması total %20, 3. yükseltmede karakterin hasar verdiği düşmanların yavaşlaması total %30 şeklinde...) Enemy Stun, ilk alışta karakterin hasar verdiği düşmanlar 0.1 saniyeliğine sersemler ve bu süre boyunca hem hareket edemez ve hem de saldıramaz. Sonrasındaki her yükseltilişinde karakterin hasar verdiği düşmanların sersemleme süresini 0.1 saniye daha arttırır. (örneğin ikinci yükseltmede sersemletme süresi total 0.2 saniye, 3. yükseltmede sersemletme süresi total 0.3 saniye şeklinde...) Bleeding+, ilk alışta karakterin hasar verdiği düşmanlar kanama etkisine uğrayrak 4 saniye boyunca her yarım saniyede bir azami canlarının %5 kadarını hasar olarak alırlar. Sonrasındaki her yükseltilişinde kanama etkisinin 4 saniye boyuncaki her yarım saniyede bir olan düşmanın azami canına göre olan hasarı yüzdesini +1 arttırır. (örneğin ikinci yükseltmede karakterin hasar verdiği düşmanlar 4 saniye boyunca her yarım saniyede bir azami canlarının total %6 kadarını hasar olarak alırlar, 3. yükseltmede karakterin hasar verdiği düşmanlar 4 saniye boyunca her yarım saniyede bir azami canlarının total %7 kadarını hasar olarak alırlar şeklinde...) Şimdi bu söylediklerime göre istediklerimi oyuna implement et.
Code edit (1 edits merged)
Please save this source code
Code edit (3 edits merged)
Please save this source code
User prompt
6. dalgada daha büyük ya da küçük zombiler gelmedi. Sen en iyisi direkt fast zombie, tank zombie ve boss denen şeylerin hepsini kodumdan kaldır, sil. Sadece normal zombi kullanayım. Dalga arttıkça gelen zombi sayısı artacak zaten o şekilde devam edelim.
User prompt
O zaman bunu yap!
Code edit (1 edits merged)
Please save this source code
User prompt
Bomba ekrandaki tüm düşmanları bir anda öldürmesin, ekrandaki tüm düşmanlara 20 hasar versin.
User prompt
Ben bir dalgayı bitirmeden diğer dalgaya geçmek istemiyorum. Ayrıca boss 3 dakikada bir değil her 10 dalgada bir yaratılmalı o andaki dalgada yaratılan zombilere ek olarak. Bu sistemi bu şekilde yaparsak ekranda olabilecek maksimum zombi limitini de kaldırabiliriz çünkü artık dalga dalga ilerleyeceğiz.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'removeChild')' in or related to this line: 'self.dirY = dy / maxDist;' Line Number: 374
User prompt
Dalgayı görmem iyi olur, evet ekleyelim.
User prompt
Düşmanların aşağıdaki şekilde olmasını ve aşağıdaki şekilde yaratılmasını istiyorum: Zombie: Yaratılma ihtimali %70. Can 16. Hasar 8. Hareket hızı normal. Ölünce 1XP bırakır. tankZombie: Yaratılma ihtimali %20. Can 60. Hasar 6. Hareket hızı yavaş. Ölünce 1XP bırakır. fastZombie: Yaratılma ihtimali %10. Can 8. Hasar 12. Hareket hızı hızlı. Ölünce 2XP bırakır. boss: Ekranda aynı anda bulunabilen zombi sayısından bağımsız olarak her 60 saniyede bir yaratılır. Can 150. Hasar 32. Hareket hızı yavaş. Ölünce 6XP bırakır.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'removeChild')' in or related to this line: 'self.dirY = dy / maxDist;' Line Number: 375
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var bestSurvivalTime = storage.get('bestTime') || 0;' Line Number: 1503 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var bestSurvivalTime = storage.getItem('bestTime') || 0;' Line Number: 1503
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bomb = Container.expand(function () { var self = Container.call(this); self.active = true; var bombGraphics = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, tint: 0xff0000 }); self.update = function () { if (!player || !self.active) { return; } var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.active = false; // Deal 20 damage to all non-boss enemies on screen for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.type !== 'boss') { var screenDx = Math.abs(enemy.x - player.x); var screenDy = Math.abs(enemy.y - player.y); if (screenDx < 1024 && screenDy < 1366) { // Deal 20 damage, drop exp and remove if dead if (enemy.takeDamage(20)) { dropExpOrb(enemy.x, enemy.y); enemy.destroy(); enemies.splice(i, 1); } } } } LK.effects.flashScreen(0xff0000, 300); if (self.parent) { self.destroy(); } return true; } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); self.damage = 10; self.speed = 15; self.dirX = 0; self.dirY = 0; self.piercing = 1; self.hitEnemies = []; var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Seviye seçim ekranı açıkken hiçbir şey yapma if (skillSelectionActive) { return; } // Hareket this.x += this.dirX * this.speed; this.y += this.dirY * this.speed; // Ekranın çok uzağına çıktıysa sil var dx = this.x - player.x; var dy = this.y - player.y; if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) { this.destroy(); var bi = bullets.indexOf(this); if (bi >= 0) { bullets.splice(bi, 1); } return; } // “Menzil” filtresi: bu top silahının menzili WEAPONS.ball.range var maxRange = WEAPONS.ball.range * (player.weapons && player.weapons.ball ? player.weapons.ball.rngMul : 1); // (Eğer o envanterde yoksa rngMul=1 varsaydık) // Düşmana çarpma kontrolü & menzil filtresi for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; if (this.intersects(e) && isWithinRange(e, maxRange)) { damageEnemy(e, this.damage); this.destroy(); var bi2 = bullets.indexOf(this); if (bi2 >= 0) { bullets.splice(bi2, 1); } return; } } }; return self; }); // ChickenLeg pickup class var ChickenLeg = Container.expand(function () { var self = Container.call(this); self.active = true; var chickenLegGraphics = self.attachAsset('chickenLeg', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); self.update = function () { if (!player || !self.active) { return; } var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.active = false; // Heal player for 30% of max HP, but not above max HP var healAmount = Math.floor(player.maxHp * 0.3); player.hp = Math.min(player.hp + healAmount, player.maxHp); LK.effects.flashObject(player, 0x00ff00, 300); LK.getSound('pickup').play(); if (self.parent) { self.destroy(); } return true; } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); self.hp = 20; self.maxHp = 20; self.damage = 10; self.speed = 2; self.expValue = 5; self.type = 'normal'; var enemyGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.hp <= 0) { return true; // Enemy died } return false; // Enemy still alive }; self.update = function () { if (!player || skillSelectionActive) { return; } // Flip enemy graphic to face player if (self.x < player.x) { enemyGraphics.scaleX = 1; } else if (self.x > player.x) { enemyGraphics.scaleX = -1; } // 1) Oyuncuya olan vektörü bul var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // 2) Eğer düşman, oyuncuya 150 pikselden yakınsa hareket etme if (dist > 150) { // 3) Aksi halde 50px uzaktan hareket et self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Burada asla destroy() yok; sadece hareketi sınırlıyoruz }; return self; }); var TankZombie = Enemy.expand(function () { var self = Enemy.call(this); self.hp = 60; self.maxHp = 60; self.damage = 20; self.speed = 1; self.expValue = 15; self.type = 'tank'; // Use 'zombie' asset, but scale up to 2x var enemyGraphics = self.children[0]; if (enemyGraphics) { enemyGraphics.scaleX = 2; enemyGraphics.scaleY = 2; } // Flip tank zombie to face player self.update = function () { if (!player || skillSelectionActive) { return; } if (self.x < player.x) { if (enemyGraphics) enemyGraphics.scaleX = 2; } else if (self.x > player.x) { if (enemyGraphics) enemyGraphics.scaleX = -2; } // Call base Enemy update Enemy.call(self).update(); }; return self; }); // FastZombie, TankZombie, and Boss are now scale-based variants of Enemy using only the 'zombie' asset var FastZombie = Enemy.expand(function () { var self = Enemy.call(this); self.hp = 15; self.maxHp = 15; self.damage = 8; self.speed = 4; self.expValue = 8; self.type = 'fast'; // Use 'zombie' asset, but scale down to 0.5x var enemyGraphics = self.children[0]; if (enemyGraphics) { enemyGraphics.scaleX = 0.5; enemyGraphics.scaleY = 0.5; } // Flip fast zombie to face player self.update = function () { if (!player || skillSelectionActive) { return; } if (self.x < player.x) { if (enemyGraphics) enemyGraphics.scaleX = 0.5; } else if (self.x > player.x) { if (enemyGraphics) enemyGraphics.scaleX = -0.5; } // Call base Enemy update Enemy.call(self).update(); }; return self; }); var Boss = Enemy.expand(function () { var self = Enemy.call(this); self.hp = 500; self.maxHp = 500; self.damage = 30; self.speed = 1.5; self.expValue = 100; self.type = 'boss'; // Use 'zombie' asset, but scale up to 5x var enemyGraphics = self.children[0]; if (enemyGraphics) { enemyGraphics.scaleX = 5; enemyGraphics.scaleY = 5; } // Flip boss to face player self.update = function () { if (!player || skillSelectionActive) { return; } if (self.x < player.x) { if (enemyGraphics) enemyGraphics.scaleX = 5; } else if (self.x > player.x) { if (enemyGraphics) enemyGraphics.scaleX = -5; } // Call base Enemy update Enemy.call(self).update(); }; return self; }); var ExpOrb = Container.expand(function () { var self = Container.call(this); // 1) spawnTime kaydet self.spawnTime = gameTime; self.value = 1; // Each orb always gives 1 EXP self.magnetSpeed = 0; var orbGraphics = self.attachAsset('expOrb', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // ORB YAŞI (frame cinsinden) var age = gameTime - self.spawnTime; // 2) Eğer 10 saniye geçmişse (600 frame), orb’u yok et ve listeden çıkar if (age >= 600) { // yok et if (self.parent) { self.destroy(); } var idx = expOrbs.indexOf(self); if (idx >= 0) { expOrbs.splice(idx, 1); } return; } // 3) Son 5 saniyede (age >= 300), yanıp sönme uygulaması if (age >= 300) { // kalan süre var remaining = 600 - age; // 300’den 0’a kadar azalır // blink periyodu: remaining / 50’ye bağlı (en hızlı 1 frame’lik periyot) var blinkInterval = Math.ceil(remaining / 50); if (blinkInterval < 1) { blinkInterval = 1; } // yaşa göre çift/tek periyoda bölerek görünürlüğü değiştir var phase = Math.floor(age / blinkInterval); self.visible = phase % 2 === 0; } else { // son 5 saniye değilse görünür olsun self.visible = true; } // 4) Normal manyetik çekim hareketi if (!player || self.magnetSpeed === 0) { return; } var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.magnetSpeed; self.y += dy / dist * self.magnetSpeed; } }; return self; }); var Joystick = Container.expand(function () { var self = Container.call(this); self.active = false; self.dirX = 0; self.dirY = 0; var base = self.attachAsset('joystickBase', { anchorX: 0.5, anchorY: 0.5 }); base.alpha = 0.5; var knob = self.attachAsset('joystickKnob', { anchorX: 0.5, anchorY: 0.5 }); knob.alpha = 0.7; self.setKnobPosition = function (x, y) { var dx = x - base.x; var dy = y - base.y; var dist = Math.sqrt(dx * dx + dy * dy); var maxDist = 60; if (dist > maxDist) { dx = dx / dist * maxDist; dy = dy / dist * maxDist; } knob.x = dx; knob.y = dy; // Defensive: avoid division by zero if (maxDist === 0) { self.dirX = 0; self.dirY = 0; } else { self.dirX = dx / maxDist; self.dirY = dy / maxDist; } }; self.reset = function () { knob.x = 0; knob.y = 0; self.dirX = 0; self.dirY = 0; self.active = false; }; return self; }); var Magnet = Container.expand(function () { var self = Container.call(this); self.active = true; var magnetGraphics = self.attachAsset('magnet', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, tint: 0x0099ff }); self.update = function () { if (!player || !self.active) { return; } var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.active = false; // Magnetize all exp orbs on screen for (var i = 0; i < expOrbs.length; i++) { var orb = expOrbs[i]; var orbDx = Math.abs(orb.x - player.x); var orbDy = Math.abs(orb.y - player.y); if (orbDx < 1024 && orbDy < 1366) { orb.magnetSpeed = 20; } } if (self.parent) { self.destroy(); } return true; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); self.level = 1; self.exp = 0; self.expToNext = 10; self.hp = 100; self.maxHp = 100; self.damage = 10; self.fireRate = 30; self.bulletSpeed = 15; self.moveSpeed = 5; self.pickupRange = 100; self.lastFire = 0; /* ===== WEAPON INVENTORY ===== */ self.weapons = {}; // key → instance var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xff0000, 300); if (self.hp <= 0) { LK.showGameOver(); } }; self.gainExp = function (amount) { // Add exp orbs self.exp += amount; // Level up if exp orbs >= current level while (self.exp >= self.level) { self.exp -= self.level; self.levelUp(); } }; self.update = function () { // Flip player graphic based on movement direction if (self.lastX === undefined) { self.lastX = self.x; } if (self.x > self.lastX) { playerGraphics.scaleX = 1; } else if (self.x < self.lastX) { playerGraphics.scaleX = -1; } self.lastX = self.x; for (var k in self.weapons) { var inst = self.weapons[k], meta = WEAPONS[k]; if (--inst.cdCnt <= 0) { fireWeapon(k, inst, meta); inst.cdCnt = meta.cd; } } }; self.levelUp = function () { self.level++; // self.exp is now handled in gainExp, do not reset here self.expToNext = self.level * 15; self.maxHp += 10; // Do NOT restore full health on level up // self.hp = self.maxHp; // Increase movement speed by 4% per level up self.moveSpeed *= 1.04; LK.getSound('levelup').play(); showSkillSelection(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 }); /**** * Game Code ****/ /* ==== UNIVERSAL HELPERS ==== */ function isWithinRange(e, maxRange) { var dx = e.x - player.x; var dy = e.y - player.y; return dx * dx + dy * dy <= maxRange * maxRange; } function addWeapon(key) { // <-- artık global if (player && Object.keys(player.weapons).length >= 6) { return; // Zaten 6 silah varsa yeni eklemeye izin verme } var m = WEAPONS[key]; var target = player ? player : { weapons: {} }; // sınıf kurulumunda da çalışsın target.weapons[key] = { cd: m.cd, cdCnt: m.cd, dmgMul: 1, rngMul: 1, sizeMul: 1, amount: 1, upgrade: 0, enchTaken: [] }; } function rand(min, max) { return min + Math.random() * (max - min); } function distSq(a, b) { var dx = a.x - b.x, dy = a.y - b.y; return dx * dx + dy * dy; } function unitDir(from, to) { var dx = to.x - from.x, dy = to.y - from.y, d = Math.sqrt(dx * dx + dy * dy); return { dx: dx / d, dy: dy / d, len: d }; } /* ==== WEAPON META TABLE ==== */ var WEAPONS = { sword: { cd: 120, dmg: 5, range: 250, type: 'melee', ench: ["Sword Damage+", "Sword Attack Speed+", "Sword Range+", "Sword Size+"], up: ["Sword +1", "Sword +2", "Sword +3"] }, boomerang: { cd: 180, dmg: 3, range: 600, type: 'boomerang', ench: ["Boomerang Damage+", "Boomerang Attack Speed+", "Boomerang Range+", "Boomerang Size+"], up: ["Boomerang +1", "Boomerang +2", "Boomerang +3"] }, ball: { cd: 180, dmg: 3, range: 600, type: 'ball', ench: ["Ball Damage+", "Ball Attack Speed+", "Ball Range+", "Ball Size+"], up: ["Ball +1", "Ball +2", "Ball +3"] }, rocket: { cd: 240, dmg: 10, range: 600, type: 'rocket', ench: ["Rocket Damage+", "Rocket Attack Speed+", "Rocket Range+", "Rocket Size+"], up: ["Rocket +1", "Rocket +2", "Rocket +3"] }, brick: { cd: 180, dmg: 8, range: 600, type: 'brick', ench: ["Brick Damage+", "Brick Attack Speed+", "Brick Range+", "Brick Size+"], up: ["Back 75°", "Front 45°", "Back 45°"] }, lightning: { cd: 180, dmg: 14, range: 600, type: 'lightning', ench: ["Lightning Damage+", "Lightning Attack Speed+", "Lightning Range+", "Lightning Size+"], up: ["Lightning +1", "Lightning +2", "Lightning +3"] }, aura: { cd: 60, dmg: 4, range: 300, type: 'aura', ench: ["Aura Damage+", "Aura Attack Speed+", "Aura Range+", "Aura Size+"], up: ["Slow 25%", "Slow 50%", "Slow 75%"] }, molotov: { cd: 180, dmg: 8, range: 600, type: 'molotov', ench: ["Molotov Damage+", "Molotov Attack Speed+", "Molotov Range+", "Molotov Size+"], up: ["Molotov +1", "Molotov +2", "Molotov +3"] }, shuriken: { cd: 180, dmg: 3, range: 300, type: 'shuriken', ench: ["Shuriken Damage+", "Shuriken Attack Speed+", "Shuriken Range+", "Shuriken Size+"], up: ["Shuriken +1", "Shuriken +2", "Shuriken +3"] } }; var player; var enemies = []; var bullets = []; var expOrbs = []; var joystick; var gameTime = 0; var waveNumber = 1; // bossSpawned variable removed; boss is now spawned every 10th wave var selectedSkills = []; var camera = { x: 0, y: 0 }; var gameContainer; var skillSelectionActive = false; var pickups = []; var lastPickupSpawn = 0; // Initialize game world gameContainer = game.addChild(new Container()); // Tile seamless background image to cover the visible area and follow the camera var bgTileAsset = LK.getAsset('seamlessBackGround', { anchorX: 0, anchorY: 0 }); var bgTileWidth = bgTileAsset.width; var bgTileHeight = bgTileAsset.height; var bgTilesX = Math.ceil(2048 / bgTileWidth) + 2; // +2 for safe margin var bgTilesY = Math.ceil(2732 / bgTileHeight) + 2; var backgroundTiles = []; for (var i = 0; i < bgTilesX; i++) { for (var j = 0; j < bgTilesY; j++) { var tile = LK.getAsset('seamlessBackGround', { anchorX: 0, anchorY: 0 }); tile.x = i * bgTileWidth; tile.y = j * bgTileHeight; gameContainer.addChild(tile); backgroundTiles.push(tile); } } // Create player player = gameContainer.addChild(new Player()); player.x = 1024; player.y = 1366; addWeapon('sword'); // Create joystick joystick = new Joystick(); joystick.x = 0; joystick.y = -200; LK.gui.bottom.addChild(joystick); // UI Elements var timerText = new Text2('00:00', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // Add wave number display to top center var waveText = new Text2('Wave 1', { size: 80, fill: 0x00FFFF }); waveText.anchor.set(0.5, 0); waveText.y = 100; LK.gui.top.addChild(waveText); var levelText = new Text2('Level 1', { size: 60, fill: 0xFFFF00 }); levelText.anchor.set(0, 0); levelText.y = 10; levelText.x = 200; LK.gui.top.addChild(levelText); var hpText = new Text2('HP: 100/100', { size: 60, fill: 0xFF0000 }); hpText.anchor.set(1, 0); hpText.y = 10; hpText.x = -200; LK.gui.top.addChild(hpText); // Spawn functions function spawnEnemy(type, x, y) { var enemy; switch (type) { case 'fast': enemy = new FastZombie(); break; case 'tank': enemy = new TankZombie(); break; case 'boss': enemy = new Boss(); break; default: enemy = new Enemy(); } enemy.x = x; enemy.y = y; enemies.push(enemy); gameContainer.addChild(enemy); } function spawnWave() { var spawnCount = 5 + waveNumber * 2; var spawnRadius = 1500; for (var i = 0; i < spawnCount; i++) { var angle = Math.random() * Math.PI * 2; var x = player.x + Math.cos(angle) * spawnRadius; var y = player.y + Math.sin(angle) * spawnRadius; var type = 'normal'; if (waveNumber > 5 && Math.random() < 0.3) { type = 'fast'; } if (waveNumber > 10 && Math.random() < 0.2) { type = 'tank'; } spawnEnemy(type, x, y); } } function dropExpOrb(x, y) { var orb = new ExpOrb(); orb.x = x; orb.y = y; // orb.value is always 1 in ExpOrb class expOrbs.push(orb); gameContainer.addChild(orb); } /* =============================================================== */ /* NINE-WEAPON FIRE / PROJECTILES */ /* =============================================================== */ function nearestEnemy() { var best = null, bestD = 1e9; for (var i = 0; i < enemies.length; i++) { var d = distSq(player, enemies[i]); if (d < bestD) { best = enemies[i]; bestD = d; } } return best; } function damageEnemy(e, dmg) { // Play hit sound on every hit LK.getSound('hit').play(); if (e.takeDamage(dmg)) { // Play death sound (if you have a death sound asset, e.g. 'death') if (LK.getSound('death')) { LK.getSound('death').play(); } // Ölünce exp orb düşür: dropExpOrb(e.x, e.y); // Sonra düşmanı kaldır ve yok et: var idx = enemies.indexOf(e); enemies.splice(idx, 1); e.destroy(); } } /* ---- sword (melee slash) ---- */ function swingSword(inst) { var sorted = enemies.slice().sort(function (a, b) { return distSq(player, a) - distSq(player, b); }); if (sorted.length === 0) { return; } for (var n = 0; n < inst.amount; n++) { var idx = n < sorted.length ? n : 0; var target = sorted[idx]; var dir = unitDir(player, target); var arc = gameContainer.addChild(new Container()); arc.x = player.x; arc.y = player.y; arc.attachAsset('swordHit', { anchorX: 0, anchorY: 0.5, rotation: Math.atan2(dir.dy, dir.dx), scaleX: inst.sizeMul, scaleY: inst.sizeMul }); arc.life = 10; arc.dmg = WEAPONS.sword.dmg * inst.dmgMul; arc.hitList = []; arc.update = function () { if (--this.life <= 0) { if (this.parent) { this.destroy(); } return; } var maxRange = WEAPONS.sword.range * inst.rngMul; for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // hem arc.intersects hem oyuncudan menzil kontrolü if (this.hitList.indexOf(e) === -1 && this.intersects(e) && isWithinRange(e, maxRange)) { this.hitList.push(e); damageEnemy(e, this.dmg); } } }; } } /* ---- boomerang ---- */ function fireBoomerang(inst) { var target = nearestEnemy(); if (!target) { return; } var dir = unitDir(player, target); // Bu silahın menzilini WEAPONS tablosundan alıp, inst.rngMul ile ölçekleyebiliriz: var maxRange = WEAPONS.boomerang.range * inst.rngMul; for (var n = 0; n < inst.amount; n++) { var p = gameContainer.addChild(new Container()); p.attachAsset('boomerang', { anchorX: 0.5, anchorY: 0.5 }); p.x = player.x; p.y = player.y; p.dirX = dir.dx; p.dirY = dir.dy; p.speed = 12; p.dmg = WEAPONS.boomerang.dmg * inst.dmgMul; p.life = 300; p.update = function () { if (skillSelectionActive) { return; } // 1) Hareket this.x += this.dirX * this.speed; this.y += this.dirY * this.speed; // 2) “life” 150’de geri dönüş if (--this.life === 150) { var u = unitDir(this, player); this.dirX = u.dx; this.dirY = u.dy; } // 3) Boomerang ekranın çok dışına çıktıysa sil var dx = this.x - player.x; var dy = this.y - player.y; if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) { if (this.parent) { this.destroy(); } var idx = bullets.indexOf(this); if (idx >= 0) { bullets.splice(idx, 1); } return; } // 4) Düşmanlara çarpma kontrolü & menzil filtresi for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // e, oyuncudan maxRange uzaklık içindeyse vur: if (this.intersects(e) && isWithinRange(e, maxRange)) { damageEnemy(e, this.dmg); this.destroy(); var idx2 = bullets.indexOf(this); if (idx2 >= 0) { bullets.splice(idx2, 1); } return; } } // 5) “life” sıfırlandıysa sil if (this.life <= 0) { if (this.parent) { this.destroy(); } var idx3 = bullets.indexOf(this); if (idx3 >= 0) { bullets.splice(idx3, 1); } } }; bullets.push(p); } } /* ---- top (rebound ball) ---- */ function fireBall(inst) { var target = nearestEnemy(); if (!target) { return; } var dir = unitDir(player, target); for (var n = 0; n < inst.amount; n++) { var p = new Bullet(); p.x = player.x; p.y = player.y; p.dirX = dir.dx; p.dirY = dir.dy; p.damage = 12 * inst.dmgMul; p.speed = 14; bullets.push(p); gameContainer.addChild(p); } } /* ---- rocket ---- */ function fireRocket(inst) { var target = nearestEnemy(); if (!target) { return; } var dir = unitDir(player, target); // Bu silahın menzili: var maxRange = WEAPONS.rocket.range * inst.rngMul; for (var n = 0; n < inst.amount; n++) { var p = gameContainer.addChild(new Container()); p.attachAsset('rocket', { anchorX: 0.5, anchorY: 0.5 }); p.x = player.x; p.y = player.y; p.dirX = dir.dx; p.dirY = dir.dy; p.speed = 10; p.dmg = WEAPONS.rocket.dmg * inst.dmgMul; p.update = function () { if (skillSelectionActive) { return; } // 1) Hareket this.x += this.dirX * this.speed; this.y += this.dirY * this.speed; // 2) Düşmana çarpma kontrolü & menzil filtresi for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // Eğer bu e, oyuncudan maxRange uzaklık içindeyse AoE hasar uygula if (this.intersects(e) && isWithinRange(e, maxRange)) { LK.getSound('rocketBoom').play(); // a) Dairesel patlama efekti: // Yarıçapı örneğin 80px olan turuncu bir daire çiziyoruz, // yarım saniye sonra yok olmalı (30 frame = 0.5s). var explosion = gameContainer.addChild(new Container()); // Daire efektini LK.getAsset ile oluşturuyoruz: var gfx = LK.getAsset('molotovFlame', { anchorX: 0.5, anchorY: 0.5, scaleX: inst.rngMul * (80 / 70), // 70: orijinal yarıçap, 80: istenen yarıçap scaleY: inst.rngMul * (80 / 70), alpha: 0.6, tint: 0xFFAA00 }); explosion.addChild(gfx); explosion.x = this.x; explosion.y = this.y; explosion.life = 30; // 30 frame = 0.5 saniye (60FPS varsayımıyla) explosion.update = function () { if (--this.life <= 0) { this.destroy(); } else { // Her frame biraz şeffaflaştırmak için: this.children[0].alpha = this.life / 30 * 0.6; } }; // b) AoE hasar: yine sadece menzil içindekileri vur for (var k = enemies.length - 1; k >= 0; k--) { var e2 = enemies[k]; if (distSq(this, e2) < 16000 && isWithinRange(e2, maxRange)) { damageEnemy(e2, this.dmg); } } // c) Bu roketi sil if (this.parent) { this.destroy(); } var bi = bullets.indexOf(this); if (bi >= 0) { bullets.splice(bi, 1); } return; } } // 3) Ekranın dışına çıkarsa sil var dx = this.x - player.x; var dy = this.y - player.y; if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) { if (this.parent) { this.destroy(); } var bi2 = bullets.indexOf(this); if (bi2 >= 0) { bullets.splice(bi2, 1); } return; } }; bullets.push(p); } } /* ---- brick ---- */ function throwBrick(inst, angDeg) { var rad = angDeg * Math.PI / 180; var p = gameContainer.addChild(new Container()); p.attachAsset('brick', { anchorX: 0.5, anchorY: 0.5 }); p.x = player.x; p.y = player.y; p.vx = Math.cos(rad) * 14; p.vy = Math.sin(rad) * 14; p.g = 0.3; p.dmg = WEAPONS.brick.dmg * inst.dmgMul; // Bu silahın menzili: var maxRange = WEAPONS.brick.range * inst.rngMul; p.update = function () { if (skillSelectionActive) { return; } // 1) Yerçekimi ve hareket this.vy += this.g; this.x += this.vx; this.y += this.vy; // 2) Düşmana çarpma kontrolü & menzil filtresi for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; if (this.intersects(e) && isWithinRange(e, maxRange)) { damageEnemy(e, this.dmg); if (this.parent) { this.destroy(); } return; } } // 3) Belirli mesafeden uzaklaşırsa yok et var dx = this.x - player.x; var dy = this.y - player.y; if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) { if (this.parent) { this.destroy(); } return; } }; } /* ---- lightning ---- */ function castLightning(inst) { // 1) Menzildeki düşmanları filtrele var maxRange = WEAPONS.lightning.range * inst.rngMul; var candidates = enemies.filter(function (e) { var dx = e.x - player.x; var dy = e.y - player.y; return dx * dx + dy * dy <= maxRange * maxRange; }); if (candidates.length === 0) { return; } // 2) Rastgele birini seç var victim = candidates[Math.floor(Math.random() * candidates.length)]; // 3) Efekti ekle var l = gameContainer.addChild(new Container()); l.attachAsset('lightning', { anchorX: 0.5, anchorY: 1 }); l.x = victim.x; l.y = victim.y; l.life = 15; l.update = function () { if (skillSelectionActive) { return; } if (--this.life === 14) { damageEnemy(victim, WEAPONS.lightning.dmg * inst.dmgMul); } if (this.life <= 0) { if (this.parent) { this.destroy(); } } }; } /* ---- aura ---- */ var auraField = null; function ensureAura(inst) { // 1) Sadece ilk defa oluşturulacak: if (!auraField) { auraField = player.addChild(new Container()); auraField.attachAsset('auraField', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); // Oyuncunun tam ortası (yerel koordinat): auraField.x = 0; auraField.y = 0; } // 2) Hasar uygulama kısmı (oyuncudan r uzaklıktaysa vur): var r = WEAPONS.aura.range * inst.rngMul; for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; var dx = e.x - player.x; var dy = e.y - player.y; if (dx * dx + dy * dy < r * r) { damageEnemy(e, inst.dmgMul * 5); } } } /* ---- molotov ---- */ function throwMolotov(inst) { var a = Math.random() * Math.PI * 2, d = rand(300, 600), tx = player.x + Math.cos(a) * d, ty = player.y + Math.sin(a) * d; var p = gameContainer.addChild(new Container()); p.attachAsset('molotov', { anchorX: 0.5, anchorY: 0.5 }); p.x = player.x; p.y = player.y; var u = unitDir(p, { x: tx, y: ty }); p.dirX = u.dx; p.dirY = u.dy; p.speed = 16; p.life = 60; p.update = function () { if (skillSelectionActive) { return; } this.x += this.dirX * this.speed; this.y += this.dirY * this.speed; if (--this.life <= 0) { spawnFlame(tx, ty, inst); if (this.parent) { this.destroy(); } } }; bullets.push(p); } /* ---- molotov flame ---- */ function spawnFlame(x, y, inst) { var f = gameContainer.addChild(new Container()); f.attachAsset('molotovFlame', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4 }); f.x = x; f.y = y; f.life = 60; f.dmg = WEAPONS.molotov.dmg * inst.dmgMul; // Molotov alanının menzili (örnek olarak 70→çevrede yarıçap 70px) var maxFlameRange = 70 * inst.rngMul; f.update = function () { if (skillSelectionActive) { return; } // 1) Düşmana hasar kontrolü & menzil filtresi for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // “distSq(f,e) < 4900” yerine “4900 = 70^2” diyorduk. // Şimdi ek olarak oyuncudan menzil kontrolü de ekleyelim: if (distSq(f, e) < maxFlameRange * maxFlameRange && isWithinRange(e, maxFlameRange)) { damageEnemy(e, this.dmg); } } // 2) Ömür kontrolü if (--this.life <= 0) { if (this.parent) { this.destroy(); } return; } // 3) Ekranın uzağına çıktıysa sil var dx = this.x - player.x; var dy = this.y - player.y; if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) { if (this.parent) { this.destroy(); } return; } }; } /* ---- shuriken ring ---- */ var shurikenObjs = []; function maintainShurikens(inst) { if (shurikenObjs.length !== inst.amount) { shurikenObjs.forEach(function (s) { if (s.parent) { s.destroy(); } }); shurikenObjs = []; var n = inst.amount, r = WEAPONS.shuriken.range * inst.rngMul; // şuriken menzili for (var i = 0; i < n; i++) { var s = gameContainer.addChild(new Container()); s.attachAsset('shuriken', { anchorX: 0.5, anchorY: 0.5 }); s.angle = i / n * Math.PI * 2; s.update = function () { if (skillSelectionActive) { return; } this.angle += 0.15; this.x = player.x + Math.cos(this.angle) * r; this.y = player.y + Math.sin(this.angle) * r; // Her bir düşmanı kontrol et: hem shuriken çarpışma hem oyuncudan menzil for (var k = enemies.length - 1; k >= 0; k--) { var e = enemies[k]; if (this.intersects(e) && isWithinRange(e, r)) { damageEnemy(e, WEAPONS.shuriken.dmg * inst.dmgMul); } } }; shurikenObjs.push(s); } } } /* ---- ana fireWeapon anahtarı ---- */ function fireWeapon(key, inst, meta) { switch (meta.type) { case 'melee': swingSword(inst); break; case 'boomerang': fireBoomerang(inst); break; case 'ball': fireBall(inst); break; case 'rocket': fireRocket(inst); break; case 'brick': throwBrick(inst, 75); if (inst.upgrade > 0) { throwBrick(inst, -75); } if (inst.upgrade > 1) { throwBrick(inst, 45); } if (inst.upgrade > 2) { throwBrick(inst, -45); } break; case 'lightning': for (var n = 0; n < inst.amount; n++) { castLightning(inst); } break; case 'aura': ensureAura(inst); break; case 'molotov': for (var n = 0; n < inst.amount; n++) { throwMolotov(inst); } break; case 'shuriken': maintainShurikens(inst); break; } } function showSkillSelection() { skillSelectionActive = true; // 1) Yeni bir Overlay (seçim ekranı) oluşturuyoruz var ov = game.addChild(new Container()); ov.x = 1024; ov.y = 1366; var choices = []; // 2) Eğer oyuncu seviyesi 5'in katı ise (5,10,15,...) if (player.level % 5 === 0) { var ownedCount = Object.keys(player.weapons).length; // 2.a) Hâlâ < 6 silah sahibi ise: yeni silah açma seçenekleri if (ownedCount < 6) { // Kilidi açılmamış silahlar havuzunu al var pool = Object.keys(WEAPONS).filter(function (key) { return !player.weapons[key]; }); // Havuzdan rastgele 3 silah göster, her biri benzersiz while (choices.length < 3 && pool.length > 0) { var rnd = Math.floor(Math.random() * pool.length); choices.push(pool.splice(rnd, 1)[0]); } } else { // 2.b) Zaten 6 silah sahibi ise: önce silahların upgrade durumlarını kontrol et var upgradePool = []; Object.keys(player.weapons).forEach(function (key) { var inst = player.weapons[key]; if (inst.upgrade < 3) { // Eğer bu silah hâlâ < 3 aşama güçlendirilmişse, // “bu silahın bir sonraki upgrade aşaması” havuza eklenir. upgradePool.push({ w: key }); } }); if (upgradePool.length > 0) { // 2.b.i) En az bir silah yükseltmesi kalmış demektir: // Rastgele en fazla 3 tane “silah güçlendirme” seçeneği göster, her biri benzersiz while (choices.length < 3 && upgradePool.length > 0) { var rnd2 = Math.floor(Math.random() * upgradePool.length); choices.push({ w: upgradePool[rnd2].w, type: "upgrade" }); upgradePool.splice(rnd2, 1); } } else { // 2.b.ii) Tüm 6 silah zaten upgrade === 3 ise: // Bu aşamadan sonra artık sadece efsun kartı göster. // Her kart benzersiz olmalı (hem silah hem efsun kombinasyonu) var ownedKeys2 = Object.keys(player.weapons); var usedPairs = []; var attempts = 0; while (choices.length < 3 && attempts < 20) { var randomKey2 = ownedKeys2[Math.floor(Math.random() * ownedKeys2.length)]; var enchList = WEAPONS[randomKey2].ench; var rnd3 = enchList[Math.floor(Math.random() * enchList.length)]; var pairKey = randomKey2 + "|" + rnd3; if (usedPairs.indexOf(pairKey) === -1) { choices.push({ w: randomKey2, e: rnd3 }); usedPairs.push(pairKey); } attempts++; } } } } else { // 3) Seviye 5'in katı değilse: doğrudan efsun kartları göster // Her kart benzersiz olmalı (hem silah hem efsun kombinasyonu) var ownedKeys = Object.keys(player.weapons); var usedPairs2 = []; var attempts2 = 0; while (choices.length < 3 && attempts2 < 20) { var randomKey = ownedKeys[Math.floor(Math.random() * ownedKeys.length)]; var enchList = WEAPONS[randomKey].ench; var rnd4 = enchList[Math.floor(Math.random() * enchList.length)]; var pairKey2 = randomKey + "|" + rnd4; if (usedPairs2.indexOf(pairKey2) === -1) { choices.push({ w: randomKey, e: rnd4 }); usedPairs2.push(pairKey2); } attempts2++; } } // 4) choices dizisini “3 adet kart” olarak UI’da çizelim choices.forEach(function (c, idx) { var card = ov.addChild(new Container()); card.attachAsset('skillCard', { anchorX: 0.5, anchorY: 0.5 }); card.x = (idx - 1) * 450; card.y = 0; var label, fn; if (typeof c === "string") { // c, yeni kilidi açılacak silahın anahtarı (ör. "boomerang") var key = c; var own = !!player.weapons[key]; if (!own) { // Hâlâ envanterde yoksa “Unlock <silah adı>” label = "Unlock " + key; fn = function fn() { addWeapon(key); }; } else if (player.weapons[key].upgrade < 3) { // Silah zaten varsa ve upgrade < 3 ise: label = WEAPONS[key].up[player.weapons[key].upgrade]; fn = function fn() { player.weapons[key].upgrade++; player.weapons[key].amount++; }; } else { // Eğer upgrade === 3’e ulaşmışsa: label = "No Option"; fn = function fn() {}; } } else if (c.type === "upgrade") { // c = { w: "sword", type:"upgrade" } var wkey = c.w; label = WEAPONS[wkey].up[player.weapons[wkey].upgrade]; fn = function fn() { player.weapons[wkey].upgrade++; player.weapons[wkey].amount++; }; } else { // c = { w: "<silahAnahtarı>", e: "<SilahName> Damage+" veya "<SilahName> Attack Speed+" vb. } var w2 = c.w; var efsun = c.e; label = efsun; fn = function fn() { var inst = player.weapons[w2]; // Efsun metni "<SilahName> Damage+" ile bitiyorsa hasar çarpanını %10 artır: if (efsun.endsWith(" Damage+")) { inst.dmgMul *= 1.1; } // Efsun metni "<SilahName> Attack Speed+" ile bitiyorsa cd süresini %10 azalt: if (efsun.endsWith(" Attack Speed+")) { inst.cd *= 0.9; } // Efsun metni "<SilahName> Range+" ile bitiyorsa menzil çarpanını %10 artır: if (efsun.endsWith(" Range+")) { inst.rngMul *= 1.1; } // Efsun metni "<SilahName> Size+" ile bitiyorsa boyut çarpanını %10 artır: if (efsun.endsWith(" Size+")) { inst.sizeMul *= 1.1; } }; } var txt = new Text2(label, { size: 40, fill: 0xffffff }); txt.anchor.set(0.5); card.addChild(txt); card.down = function () { fn(); ov.destroy(); skillSelectionActive = false; levelText.setText('Level ' + player.level); }; }); } // Input handling game.down = function (x, y, obj) { if (skillSelectionActive) { return; } var localPos = game.toLocal({ x: x, y: y }); if (localPos.y > 2000) { joystick.active = true; joystick.setKnobPosition(0, 0); } }; game.move = function (x, y, obj) { if (!joystick.active || skillSelectionActive) { return; } var localPos = LK.gui.bottom.toLocal({ x: x, y: y }); var dx = localPos.x - joystick.x; var dy = localPos.y - joystick.y; joystick.setKnobPosition(dx, dy); }; game.up = function (x, y, obj) { joystick.reset(); }; // Game update game.update = function () { if (skillSelectionActive) { return; } gameTime++; // Update timer → geçen süreyi göster var elapsedSeconds = Math.floor(gameTime / 60); var minutes = Math.floor(elapsedSeconds / 60); var seconds = elapsedSeconds % 60; timerText.setText((minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds)); // Update UI hpText.setText('HP: ' + player.hp + '/' + player.maxHp); // Show exp orbs and required exp for next level levelText.setText('Level ' + player.level + ' EXP: ' + player.exp + '/' + player.level); // Show current wave waveText.setText('Wave ' + waveNumber); // Player movement if (joystick.active) { player.x += joystick.dirX * player.moveSpeed; player.y += joystick.dirY * player.moveSpeed; } /* Fire weapons / aura etc. */ player.update(); // Camera follow player camera.x = player.x - 1024; camera.y = player.y - 1366; gameContainer.x = -camera.x; gameContainer.y = -camera.y; // Update background tiles to always cover the visible area if (backgroundTiles && backgroundTiles.length) { var startX = Math.floor(camera.x / bgTileWidth) * bgTileWidth; var startY = Math.floor(camera.y / bgTileHeight) * bgTileHeight; var idx = 0; for (var i = 0; i < bgTilesX; i++) { for (var j = 0; j < bgTilesY; j++) { var tile = backgroundTiles[idx++]; tile.x = startX + i * bgTileWidth; tile.y = startY + j * bgTileHeight; } } } // Progress to next wave only when all enemies are cleared if (enemies.length === 0) { waveNumber++; spawnWave(); // Spawn boss every 10th wave, in addition to normal enemies if (waveNumber % 10 === 0) { spawnEnemy('boss', player.x + 400, player.y); } } // Update enemies for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - player.x; var dy = enemy.y - player.y; var distSq = dx * dx + dy * dy; // 150 piksel mesafe için distSq <= 22500 kullanıyoruz. if (distSq <= 22500) { if (enemy.lastHitTime === undefined || gameTime - enemy.lastHitTime >= 60) { player.takeDamage(enemy.damage); enemy.lastHitTime = gameTime; } } } // Update exp orbs for (var i = expOrbs.length - 1; i >= 0; i--) { var orb = expOrbs[i]; var dx = orb.x - player.x; var dy = orb.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < player.pickupRange) { orb.magnetSpeed = 10; } if (orb.intersects(player)) { player.gainExp(orb.value); orb.destroy(); expOrbs.splice(i, 1); LK.getSound('pickup').play(); } } // Spawn pickups randomly if (gameTime - lastPickupSpawn > 1800 && Math.random() < 0.1) { lastPickupSpawn = gameTime; var pickup; var angle = Math.random() * Math.PI * 2; var distance = 300 + Math.random() * 500; var pickupX = player.x + Math.cos(angle) * distance; var pickupY = player.y + Math.sin(angle) * distance; var randVal = Math.random(); if (randVal < 0.4) { pickup = new Bomb(); } else if (randVal < 0.8) { pickup = new Magnet(); } else { pickup = new ChickenLeg(); } pickup.x = pickupX; pickup.y = pickupY; pickups.push(pickup); gameContainer.addChild(pickup); } // Update pickups for (var i = pickups.length - 1; i >= 0; i--) { var pickup = pickups[i]; if (!pickup.active) { pickups.splice(i, 1); } } }; // Initial spawn spawnWave(); // Start background music at game start LK.playMusic('backGroundMusic');
===================================================================
--- original.js
+++ change.js
@@ -184,48 +184,53 @@
self.damage = 20;
self.speed = 1;
self.expValue = 15;
self.type = 'tank';
- var graphics = self.attachAsset('tankZombie', {
- anchorX: 0.5,
- anchorY: 0.5
- });
+ // Use 'zombie' asset, but scale up to 2x
+ var enemyGraphics = self.children[0];
+ if (enemyGraphics) {
+ enemyGraphics.scaleX = 2;
+ enemyGraphics.scaleY = 2;
+ }
// Flip tank zombie to face player
self.update = function () {
if (!player || skillSelectionActive) {
return;
}
if (self.x < player.x) {
- graphics.scaleX = 1;
+ if (enemyGraphics) enemyGraphics.scaleX = 2;
} else if (self.x > player.x) {
- graphics.scaleX = -1;
+ if (enemyGraphics) enemyGraphics.scaleX = -2;
}
// Call base Enemy update
Enemy.call(self).update();
};
return self;
});
+// FastZombie, TankZombie, and Boss are now scale-based variants of Enemy using only the 'zombie' asset
var FastZombie = Enemy.expand(function () {
var self = Enemy.call(this);
self.hp = 15;
self.maxHp = 15;
self.damage = 8;
self.speed = 4;
self.expValue = 8;
self.type = 'fast';
- var graphics = self.attachAsset('fastZombie', {
- anchorX: 0.5,
- anchorY: 0.5
- });
+ // Use 'zombie' asset, but scale down to 0.5x
+ var enemyGraphics = self.children[0];
+ if (enemyGraphics) {
+ enemyGraphics.scaleX = 0.5;
+ enemyGraphics.scaleY = 0.5;
+ }
// Flip fast zombie to face player
self.update = function () {
if (!player || skillSelectionActive) {
return;
}
if (self.x < player.x) {
- graphics.scaleX = 1;
+ if (enemyGraphics) enemyGraphics.scaleX = 0.5;
} else if (self.x > player.x) {
- graphics.scaleX = -1;
+ if (enemyGraphics) enemyGraphics.scaleX = -0.5;
}
// Call base Enemy update
Enemy.call(self).update();
};
@@ -238,21 +243,23 @@
self.damage = 30;
self.speed = 1.5;
self.expValue = 100;
self.type = 'boss';
- var graphics = self.attachAsset('boss', {
- anchorX: 0.5,
- anchorY: 0.5
- });
+ // Use 'zombie' asset, but scale up to 5x
+ var enemyGraphics = self.children[0];
+ if (enemyGraphics) {
+ enemyGraphics.scaleX = 5;
+ enemyGraphics.scaleY = 5;
+ }
// Flip boss to face player
self.update = function () {
if (!player || skillSelectionActive) {
return;
}
if (self.x < player.x) {
- graphics.scaleX = 1;
+ if (enemyGraphics) enemyGraphics.scaleX = 5;
} else if (self.x > player.x) {
- graphics.scaleX = -1;
+ if (enemyGraphics) enemyGraphics.scaleX = -5;
}
// Call base Enemy update
Enemy.call(self).update();
};
@@ -662,18 +669,18 @@
size: 60,
fill: 0xFFFF00
});
levelText.anchor.set(0, 0);
-levelText.y = 20;
-levelText.x = 250;
+levelText.y = 10;
+levelText.x = 200;
LK.gui.top.addChild(levelText);
var hpText = new Text2('HP: 100/100', {
size: 60,
fill: 0xFF0000
});
hpText.anchor.set(1, 0);
-hpText.y = 20;
-hpText.x = -250;
+hpText.y = 10;
+hpText.x = -200;
LK.gui.top.addChild(hpText);
// Spawn functions
function spawnEnemy(type, x, y) {
var enemy;
Survivor.io style 2D sword swing effect made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows. It should only have a slash effect, no swords. The slash effect should also be in the shape of a half moon.
Survivor.io style 2D round soccer ball made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D Survivor.io style lightning strike from a cloud in the sky to the ground, made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A red and blue Survivor.io style 2D U-shaped (with N and S) magnet made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D shuriken made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D brick made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D missile rocket made by HABBY PTE. LTD.
A 2D green radiating circular aura in the Survivor.io style made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D bomb in the style of Survivor.io, made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D circular burning effect in Survivor.io style made by HABBY PTE. LTD. (not only the surroundings but also the inside burns) In-Game asset. 2d. High contrast. No shadows
A 2D molotov in the Survivor.io style made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D greenish exp sphere made by HABBY PTE. LTD. No exp written on it. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D half-moon orange boomerang made by HABBY PTE. LTD. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D 1 chicken leg.. In-Game asset. 2d. High contrast. No shadows
2D survivor.io game style atomic boom effect front view. No text written on it.
2D. Ranged zombie. attacks with poisonous saliva. In-Game asset. 2d. High contrast. No shadows
2D. Child (small) zombie. He has a small saw in his hand.. In-Game asset. 2d. High contrast. No shadows
2D. Fat zombie. His hands are too big.. In-Game asset. 2d. High contrast. No shadows
Poisonous green circular saliva. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Small green claw slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Giant boss angry reddish zombie. 2D.. In-Game asset. 2d. High contrast. No shadows
Small saw slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Big red fist slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Kanlı kemik 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
2D character that looks like a prophet and holds a holy book in his hand.. In-Game asset. 2d. High contrast. No shadows
A background image (wallpaper) representing an old prophet-like man with white hair and beard, wearing a priest's robe (hooded) and holding a holy book (christianity, cross) in his hand, fighting against zombies.. In-Game asset. 2d. High contrast. No shadows
Zombie flesh and bone themed 2D cardboard hollow (without text) horizontal rectangular button.. In-Game asset. 2d. High contrast. No shadows
2D. Healer zombie. Like a female zombie in a healer costume.. In-Game asset. 2d. High contrast. No shadows
2D. Brain illustrated healing potion.. In-Game asset. 2d. High contrast. No shadows
A healing blood pool with circular zombie brain and bone particles. Green + (healing) symbols on top. 2D.. In-Game asset. 2d. High contrast. No shadows
2D. Survivor.io game style skill card. No text written on it. No symbols on it. Just the blank card. Green.. In-Game asset. 2d. High contrast. No shadows
2D. Cartoon. The rise of the zombie ghost spirit from the ground.. In-Game asset. 2d. High contrast. No shadows
levelup
Sound effect
hit
Sound effect
rocketBoom
Sound effect
pickup
Sound effect
backGroundMusic
Music
death
Sound effect
damageTaken
Sound effect
mainMenuMusic
Music
deathScreenMusic
Music
swordSoundEffect
Sound effect
bumerangSoundEffect
Sound effect
brickSoundEffect
Sound effect
lightningSoundEffect
Sound effect
ballSoundEffect
Sound effect
rocketSoundEffect
Sound effect
auraSoundEffect
Sound effect
molotovSoundEffect
Sound effect
molotovBoom
Sound effect
introSpeech
Sound effect
bombBoomSound
Sound effect