User prompt
75 coıne can yenıleme ekleyelım
User prompt
kulenın canını arttıralım ve parasını 30 yapıp otyuncu her silah guceldirdiginde kulenınde silahı guçlensın
User prompt
ve ondan sonrada 2 nın katları şeklinde gitsin ve her deferinde 100 coın daha pahalı olsun
User prompt
oyuncu 1.5 x parayı adlıktan sonra onun yerine 2x para gelsin ve o da 100 coin olsun
User prompt
checkpoint i kaldıralım
User prompt
oyundakı tum yazıları ingilizce yapalım
User prompt
arkaplana bir orman çiz
User prompt
arka plan resmini ortala
User prompt
arkaplana bir askeriye koy
User prompt
arkaplanı siyah yerine zombi salgınına ugramış ve terk edilmiş bir askeriye yapalım
User prompt
butonlardaki mavı rengi kaldır
User prompt
yon tusları ve satın alma kutularınn rengini gri yap
User prompt
yön tuşlarının arkasını gri yap
User prompt
kutulardaki resimleri eski haline getir aam duvar kalsın
User prompt
kalpleri iraz daha küçültelim mobil için
User prompt
karakterin hareketi için sanal sag sol on arka tusları ekliyelim
User prompt
mausenın 3. tuşu ile hareket ettirelim
User prompt
karakteri masuenın sol tuşu ile hareket ettirelim
User prompt
kalpleri biraz küçültelim
User prompt
kalpleri ortaya alalım
User prompt
kalpleri sola alalım
User prompt
en sola alalım
User prompt
biraz daha sola alalım
User prompt
en sol uste alalım
User prompt
biraz daha sola
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // BossZombie class var BossZombie = Container.expand(function () { var self = Container.call(this); var bossSprite = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.7, scaleY: 1.7, color: 0x8e44ad // purple tint for boss }); self.radius = bossSprite.width / 2; var bossPowerLevel = Math.floor((currentWave - 1) / 3); self.speed = 1.5 + bossPowerLevel * 0.5; self.hp = 10 + bossPowerLevel * 5; self.maxHp = self.hp; self.target = null; self.lastHitTick = 0; self.update = function () { // Move towards player var tx = player.x; var ty = player.y; // If wall/trap/tower is closer, target that var minDist = Math.sqrt((self.x - tx) * (self.x - tx) + (self.y - ty) * (self.y - ty)); var targetObj = player; for (var i = 0; i < defenses.length; i++) { var d = defenses[i]; var dist = Math.sqrt((self.x - d.x) * (self.x - d.x) + (self.y - d.y) * (self.y - d.y)); if (dist < minDist) { minDist = dist; targetObj = d; } } self.target = targetObj; var dx = targetObj.x - self.x; var dy = targetObj.y - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { dx /= len; dy /= len; self.x += dx * self.speed; self.y += dy * self.speed; } // Attack if close if (len < self.radius + targetObj.radius + 10) { if (LK.ticks - self.lastHitTick > 30) { if (targetObj === player) { player.takeDamage(2); // Boss does more damage } else if (targetObj.takeDamage) { targetObj.takeDamage(2); } self.lastHitTick = LK.ticks; } } }; self.takeDamage = function (amount) { self.hp -= amount; if (self.hp <= 0) { self.die(); } else { LK.effects.flashObject(self, 0xff00ff, 300); } }; self.die = function () { LK.getSound('zombie_die').play(); // Drop 5 coins var coinCount = 5; if (typeof coinMultiplierEnabled !== "undefined" && coinMultiplierEnabled) { coinCount = Math.round(5 * 1.5); } for (var i = 0; i < coinCount; i++) { var coin = new Coin(); // Spread coins a bit var angle = Math.PI * 2 * i / coinCount; coin.x = self.x + Math.cos(angle) * 60; coin.y = self.y + Math.sin(angle) * 60; coins.push(coin); game.addChild(coin); } self.destroy(); var idx = zombies.indexOf(self); if (idx !== -1) zombies.splice(idx, 1); zombiesKilledThisWave++; }; return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletSprite.width / 2; self.vx = 0; self.vy = 0; self.damage = 1; self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Coin class var Coin = Container.expand(function () { var self = Container.call(this); var coinSprite = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.radius = coinSprite.width * 1.5; // Even further increase hitbox radius for much easier collection // Remove vy and falling logic so coin stays at spawn position self.collected = false; self.update = function () { // No falling, coin stays at its spawn position }; self.collect = function () { if (self.collected) return; self.collected = true; LK.getSound('coin').play(); // Animate to coinText var guiPos = LK.gui.topRight.toLocal(game.toGlobal({ x: self.x, y: self.y })); var startX = self.x, startY = self.y; var endX = 2048 - 200, endY = 80; tween(self, { x: endX, y: endY, alpha: 0 }, { duration: 400, easing: tween.cubicIn, onFinish: function onFinish() { self.destroy(); var idx = coins.indexOf(self); if (idx !== -1) coins.splice(idx, 1); if (typeof coinMultiplierEnabled !== "undefined" && coinMultiplierEnabled) { coinsCollected += 1.5; } else { coinsCollected++; } coinsCollected = Math.floor(coinsCollected); updateCoinText(); } }); }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.radius = playerSprite.width / 2; self.hp = 10; self.maxHp = 10; self.shootCooldown = 0; self.shootDelay = 20; // frames self.weaponLevel = 1; self.lastShotTick = 0; // For drag self.down = function (x, y, obj) {}; self.up = function (x, y, obj) {}; self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; }; // Shoot method self.shoot = function (targetX, targetY) { if (self.shootCooldown > 0) return; var dx = targetX - self.x; var dy = targetY - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len === 0) return; dx /= len; dy /= len; var bullet = new Bullet(); bullet.x = self.x + dx * (self.radius + 30); bullet.y = self.y + dy * (self.radius + 30); bullet.vx = dx * (22 + self.weaponLevel * 2); bullet.vy = dy * (22 + self.weaponLevel * 2); bullet.damage = self.weaponLevel; // Set bullet rotation so the tip faces the direction of movement if (bullet.children && bullet.children.length > 0) { bullet.children[0].rotation = Math.atan2(bullet.vy, bullet.vx); } bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.shootCooldown = self.shootDelay; }; // Take damage self.takeDamage = function (amount) { self.hp -= amount; if (self.hp < 0) self.hp = 0; LK.effects.flashObject(self, 0xff0000, 300); updateHpBar(); if (self.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } }; return self; }); // Tower class var Tower = Container.expand(function () { var self = Container.call(this); var towerSprite = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); self.radius = Math.max(towerSprite.width, towerSprite.height) / 2; self.hp = 8; self.maxHp = 8; self.shootCooldown = 0; self.shootDelay = 40; self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.hp <= 0) { self.destroy(); var idx = defenses.indexOf(self); if (idx !== -1) defenses.splice(idx, 1); } }; self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; // Find nearest zombie var nearest = null, minDist = 99999; for (var i = 0; i < zombies.length; i++) { var z = zombies[i]; var dx = z.x - self.x; var dy = z.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; nearest = z; } } if (nearest && self.shootCooldown <= 0) { // Shoot at nearest zombie var dx = nearest.x - self.x; var dy = nearest.y - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { dx /= len; dy /= len; var bullet = new Bullet(); bullet.x = self.x + dx * (self.radius + 20); bullet.y = self.y + dy * (self.radius + 20); bullet.vx = dx * 18; bullet.vy = dy * 18; bullet.damage = 1; // Set bullet rotation so the tip faces the direction of movement if (bullet.children && bullet.children.length > 0) { bullet.children[0].rotation = Math.atan2(bullet.vy, bullet.vx); } bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.shootCooldown = self.shootDelay; } } }; return self; }); // Trap class var Trap = Container.expand(function () { var self = Container.call(this); var trapSprite = self.attachAsset('trap', { anchorX: 0.5, anchorY: 0.5 }); self.radius = Math.max(trapSprite.width, trapSprite.height) / 2; self.hp = 2; self.maxHp = 2; self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.hp <= 0) { self.destroy(); var idx = defenses.indexOf(self); if (idx !== -1) defenses.splice(idx, 1); } }; return self; }); // Wall class var Wall = Container.expand(function () { var self = Container.call(this); var wallSprite = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); self.radius = Math.max(wallSprite.width, wallSprite.height) / 2; self.hp = 6; self.maxHp = 6; self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.hp <= 0) { self.destroy(); var idx = defenses.indexOf(self); if (idx !== -1) defenses.splice(idx, 1); } }; return self; }); // Zombie class var Zombie = Container.expand(function () { var self = Container.call(this); var zombieSprite = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.radius = zombieSprite.width / 2; // Zombies get stronger only every 3 waves var zombiePowerLevel = Math.floor((currentWave - 1) / 3); self.speed = 2 + zombiePowerLevel * 0.9; self.hp = 1 + zombiePowerLevel; self.maxHp = self.hp; self.target = null; self.lastHitTick = 0; self.update = function () { // Move towards player var tx = player.x; var ty = player.y; // If wall/trap/tower is closer, target that var minDist = Math.sqrt((self.x - tx) * (self.x - tx) + (self.y - ty) * (self.y - ty)); var targetObj = player; for (var i = 0; i < defenses.length; i++) { var d = defenses[i]; var dist = Math.sqrt((self.x - d.x) * (self.x - d.x) + (self.y - d.y) * (self.y - d.y)); if (dist < minDist) { minDist = dist; targetObj = d; } } self.target = targetObj; var dx = targetObj.x - self.x; var dy = targetObj.y - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { dx /= len; dy /= len; self.x += dx * self.speed; self.y += dy * self.speed; } // Attack if close if (len < self.radius + targetObj.radius + 10) { if (LK.ticks - self.lastHitTick > 30) { if (targetObj === player) { player.takeDamage(1); } else if (targetObj.takeDamage) { targetObj.takeDamage(1); } self.lastHitTick = LK.ticks; } } }; self.takeDamage = function (amount) { self.hp -= amount; if (self.hp <= 0) { self.die(); } else { LK.effects.flashObject(self, 0xff0000, 200); } }; self.die = function () { LK.getSound('zombie_die').play(); // Drop coin var coin = new Coin(); coin.x = self.x; coin.y = self.y; coins.push(coin); game.addChild(coin); self.destroy(); var idx = zombies.indexOf(self); if (idx !== -1) zombies.splice(idx, 1); zombiesKilledThisWave++; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Global variables // Character (player) // Zombie // Bullet // Coin // Wall // Trap // Tower // Sounds var player; var zombies = []; var bullets = []; var coins = []; var defenses = []; var coinsCollected = 0; var autoCollectEnabled = false; var coinMultiplierEnabled = false; var currentWave = 1; var zombiesToSpawn = 0; var zombiesSpawnedThisWave = 0; var zombiesKilledThisWave = 0; var waveInProgress = false; var dragNode = null; var buildMode = null; // 'wall', 'trap', 'tower', 'upgrade', 'autocollect', 'coinmult' var buildPreview = null; var buildCost = { wall: 5, trap: 7, tower: 12, upgrade: 10, autocollect: 20, coinmult: 50, checkpoint: 25 }; var buildNames = { wall: "Duvar", trap: "Tuzak", tower: "Kule", upgrade: "Silah+", autocollect: "Oto-Para", coinmult: "Para x1.5", checkpoint: "Checkpoint" }; // buildDesc removed var hpBar, coinText, waveText, buildPanel, buildButtons = []; var lastTouchX = 0, lastTouchY = 0; // UI: HP Bar function updateHpBar() { if (!hpBar) return; var txt = ""; for (var i = 0; i < player.maxHp; i++) { txt += i < player.hp ? "♥ " : "♡ "; } hpBar.setText(txt); } // UI: Coin Text function updateCoinText() { if (coinText) coinText.setText("₺ " + coinsCollected); // Rebuild build panel to update overlays/locks if it exists if (typeof buildPanel !== "undefined" && buildPanel) { buildPanel.destroy(); buildButtons = []; createBuildPanel(); } } // UI: Wave Text function updateWaveText() { if (waveText) waveText.setText("Dalga: " + currentWave); } // UI: Build Panel function createBuildPanel() { buildPanel = new Container(); buildPanel.y = 0; buildPanel.x = 0; var btnW = 140, btnH = 56, gap = 18; // Dynamically build types array based on upgrade state var types = ['wall', 'trap', 'tower', 'upgrade']; // Always allow checkpoint purchase types.push('checkpoint'); if (!autoCollectEnabled) { types.push('autocollect'); } else if (!coinMultiplierEnabled) { types.push('coinmult'); } for (var i = 0; i < types.length; i++) { (function (type, idx) { var btn = new Container(); var bg = LK.getAsset('wall', { width: btnW, height: btnH, color: 0x333333, anchorX: 0, anchorY: 0 }); btn.addChild(bg); var label = buildNames[type] ? buildNames[type] : type === 'coinmult' ? "Para x1.5" : type; var cost = buildCost[type] ? buildCost[type] : type === 'coinmult' ? 50 : 0; var txt = new Text2(label + "\n₺" + cost, { size: 32, fill: "#fff" }); txt.x = btnW / 2; txt.y = 12; txt.anchor.set(0.5, 0); btn.addChild(txt); btn.x = idx * (btnW + gap) - 10; // Move each button 10px to the left (was 100px) btn.y = 0; btn.type = type; // Check if player can afford this item var canAfford = coinsCollected >= cost; if (!canAfford) { // Add a semi-transparent black overlay var overlay = LK.getAsset('wall', { width: btnW, height: btnH, color: 0x000000, anchorX: 0, anchorY: 0 }); overlay.alpha = 0.45; btn.addChild(overlay); // Add a lock icon (use a Text2 lock emoji for simplicity) var lockIcon = new Text2("🔒", { size: 38, fill: "#fff" }); lockIcon.x = btnW / 2; lockIcon.y = btnH / 2 - 18; lockIcon.anchor.set(0.5, 0.5); btn.addChild(lockIcon); // Disable interaction btn.down = function () {}; } else { btn.down = function (x, y, obj) { setBuildMode(type); }; } buildPanel.addChild(btn); buildButtons.push(btn); })(types[i], i); } buildPanel.y = -120; // Move the build panel further up by 120px (closer to bottom) buildPanel.x = -320; // Move the build panel to the right (was -540) LK.gui.bottom.addChild(buildPanel); } // Set build mode function setBuildMode(type) { buildMode = type; if (buildPreview) { buildPreview.destroy(); buildPreview = null; } if (type === 'wall') { buildPreview = new Wall(); } else if (type === 'trap') { buildPreview = new Trap(); } else if (type === 'tower') { buildPreview = new Tower(); } else if (type === 'upgrade' || type === 'autocollect') { buildPreview = null; } if (buildPreview) { buildPreview.alpha = 0.5; game.addChild(buildPreview); } } // Remove build preview function clearBuildPreview() { if (buildPreview) { buildPreview.destroy(); buildPreview = null; } buildMode = null; } // Start new wave function startWave() { zombiesToSpawn = 5 + currentWave * 2; zombiesSpawnedThisWave = 0; zombiesKilledThisWave = 0; waveInProgress = true; updateWaveText(); // Spawn boss every 3 waves if (currentWave % 3 === 0) { // Boss will be spawned after all regular zombies zombiesToSpawn += 1; } } // Spawn zombie function spawnZombie() { // Spawn at random edge var edge = Math.floor(Math.random() * 4); var zx, zy; if (edge === 0) { // top zx = 200 + Math.random() * (2048 - 400); zy = -60; } else if (edge === 1) { // right zx = 2048 + 60; zy = 200 + Math.random() * (2732 - 400); } else if (edge === 2) { // bottom zx = 200 + Math.random() * (2048 - 400); zy = 2732 + 60; } else { // left zx = -60; zy = 200 + Math.random() * (2732 - 400); } // If this is a boss wave and this is the last zombie, spawn boss var isBossWave = currentWave % 3 === 0; var isLastZombie = zombiesSpawnedThisWave === zombiesToSpawn - 1 && isBossWave; var z; if (isLastZombie) { z = new BossZombie(); } else { z = new Zombie(); } z.x = zx; z.y = zy; zombies.push(z); game.addChild(z); zombiesSpawnedThisWave++; } // Build defense function buildDefense(type, x, y) { if (coinsCollected < buildCost[type]) return false; var obj; if (type === 'wall') { obj = new Wall(); } else if (type === 'trap') { obj = new Trap(); } else if (type === 'tower') { obj = new Tower(); } if (obj) { obj.x = x; obj.y = y; defenses.push(obj); game.addChild(obj); coinsCollected -= buildCost[type]; updateCoinText(); LK.getSound('build').play(); return true; } return false; } // Upgrade weapon function upgradeWeapon() { if (coinsCollected < buildCost.upgrade) return false; player.weaponLevel++; coinsCollected -= buildCost.upgrade; updateCoinText(); LK.effects.flashObject(player, 0xffff00, 600); LK.getSound('build').play(); return true; } // Handle move (drag, build preview, collect coin) function handleMove(x, y, obj) { lastTouchX = x; lastTouchY = y; // Drag player if (dragNode === player) { // Clamp to game area var r = player.radius + 10; player.x = Math.max(r, Math.min(2048 - r, x)); player.y = Math.max(r, Math.min(2732 - r, y)); } // Build preview follows finger if (buildPreview) { buildPreview.x = x; buildPreview.y = y; } // Coin collection for (var i = coins.length - 1; i >= 0; i--) { var c = coins[i]; var dx = c.x - x, dy = c.y - y; if (!c.collected && dx * dx + dy * dy < c.radius * c.radius + 1200) { c.collect(); } } } // Handle down (start drag, build, upgrade) game.down = function (x, y, obj) { // If build mode is active if (buildMode) { if (buildMode === 'upgrade') { if (upgradeWeapon()) { clearBuildPreview(); } } else if (buildMode === 'autocollect') { if (!autoCollectEnabled && coinsCollected >= buildCost.autocollect) { coinsCollected -= buildCost.autocollect; updateCoinText(); autoCollectEnabled = true; LK.effects.flashObject(player, 0x00ffcc, 600); LK.getSound('build').play(); clearBuildPreview(); // Recreate build panel to remove autocollect and add coinmult if (buildPanel) { buildPanel.destroy(); buildButtons = []; createBuildPanel(); } } } else if (buildMode === 'coinmult') { if (!coinMultiplierEnabled && coinsCollected >= buildCost.coinmult) { coinsCollected -= buildCost.coinmult; updateCoinText(); coinMultiplierEnabled = true; LK.effects.flashObject(player, 0xffe066, 600); LK.getSound('build').play(); clearBuildPreview(); // Recreate build panel to remove coinmult if (buildPanel) { buildPanel.destroy(); buildButtons = []; createBuildPanel(); } } } else if (buildMode === 'checkpoint') { if (coinsCollected >= buildCost.checkpoint) { coinsCollected -= buildCost.checkpoint; updateCoinText(); LK.effects.flashObject(player, 0x66ff66, 600); LK.getSound('build').play(); clearBuildPreview(); // Save checkpoint data (player position, wave, coins, upgrades, etc.) if (typeof storage !== "undefined") { storage.set("checkpoint", { playerX: player.x, playerY: player.y, currentWave: currentWave, coinsCollected: coinsCollected, weaponLevel: player.weaponLevel, autoCollectEnabled: autoCollectEnabled, coinMultiplierEnabled: coinMultiplierEnabled }); } } } else { // Place defense if possible if (buildPreview) { // Don't allow build on player or on top of other defenses var canBuild = true; var dx = player.x - x, dy = player.y - y; if (dx * dx + dy * dy < (player.radius + buildPreview.radius + 40) * (player.radius + buildPreview.radius + 40)) { canBuild = false; } for (var i = 0; i < defenses.length; i++) { var d = defenses[i]; var ddx = d.x - x, ddy = d.y - y; if (ddx * ddx + ddy * ddy < (d.radius + buildPreview.radius + 30) * (d.radius + buildPreview.radius + 30)) { canBuild = false; break; } } if (canBuild && buildDefense(buildMode, x, y)) { clearBuildPreview(); } } } return; } // Only handle mouse/touch events with event object var event = obj && obj.event ? obj.event : null; var isLeftClick = false; var isMiddleClick = false; // Mouse events if (event && typeof event.button !== "undefined") { // 0: left, 1: middle if (event.button === 0) isLeftClick = true; if (event.button === 1) isMiddleClick = true; } else { // Touch events: treat as left click (drag/shoot) isLeftClick = true; } if (isMiddleClick) { // Teleport player to clicked position, clamp to game area var r = player.radius + 10; player.x = Math.max(r, Math.min(2048 - r, x)); player.y = Math.max(r, Math.min(2732 - r, y)); } else if (isLeftClick) { // If click/touch is on player, start drag var dx = player.x - x, dy = player.y - y; if (dx * dx + dy * dy < player.radius * player.radius + 2000) { dragNode = player; } else { // Otherwise, shoot player.shoot(x, y); } } handleMove(x, y, obj); }; // Prevent context menu on right click for the canvas if (typeof window !== "undefined" && typeof document !== "undefined") { var canvas = document.querySelector('canvas'); if (canvas) { canvas.oncontextmenu = function (e) { e.preventDefault(); return false; }; } } // Handle up (stop drag, clear build preview) game.up = function (x, y, obj) { dragNode = null; // If build preview exists, clear it if not placed if (buildPreview && buildMode) { clearBuildPreview(); } }; // Handle move game.move = handleMove; // Game update game.update = function () { // Player update player.update(); // Zombies update for (var i = zombies.length - 1; i >= 0; i--) { zombies[i].update(); } // Bullets update for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove if out of bounds if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with zombies for (var j = zombies.length - 1; j >= 0; j--) { var z = zombies[j]; var dx = z.x - b.x, dy = z.y - b.y; if (dx * dx + dy * dy < (z.radius + b.radius) * (z.radius + b.radius)) { z.takeDamage(b.damage); b.destroy(); bullets.splice(i, 1); break; } } } // Coins update for (var i = coins.length - 1; i >= 0; i--) { coins[i].update(); if (autoCollectEnabled && !coins[i].collected) { coins[i].collect(); } } // Defenses update for (var i = defenses.length - 1; i >= 0; i--) { if (defenses[i].update) defenses[i].update(); } // Wave logic if (waveInProgress) { // Spawn zombies if (zombiesSpawnedThisWave < zombiesToSpawn && LK.ticks % Math.max(20, 60 - currentWave * 2) === 0) { spawnZombie(); } // Check wave end if (zombiesKilledThisWave >= zombiesToSpawn && zombies.length === 0) { waveInProgress = false; // Give 5 coins every 5 waves at the end of the wave if (currentWave % 5 === 0) { coinsCollected += 5; updateCoinText(); } // Next wave after 4 seconds (4000 ms) LK.setTimeout(function () { currentWave++; startWave(); }, 4000); } } }; // --- Game Initialization --- // Place player at center player = new Player(); player.x = 2048 / 2; player.y = 2732 / 2; game.addChild(player); // UI: HP Bar hpBar = new Text2("", { size: 80, fill: 0xFF4444 }); // Move hearts further to the left, but still leave space for menu (x=60) hpBar.anchor.set(0, 0); LK.gui.top.addChild(hpBar); hpBar.x = 60; hpBar.y = 20; updateHpBar(); // UI: Coin Text coinText = new Text2("₺ 0", { size: 70, fill: 0xFFE066 }); coinText.anchor.set(1, 0); LK.gui.topRight.addChild(coinText); coinText.x = -40; coinText.y = 20; // UI: Wave Text waveText = new Text2("Dalga: 1", { size: 60, fill: "#fff" }); waveText.anchor.set(0, 0); LK.gui.top.addChild(waveText); waveText.x = 60; waveText.y = 120; // UI: Build Panel createBuildPanel(); // Start first wave startWave(); updateCoinText(); updateWaveText();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// BossZombie class
var BossZombie = Container.expand(function () {
var self = Container.call(this);
var bossSprite = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.7,
scaleY: 1.7,
color: 0x8e44ad // purple tint for boss
});
self.radius = bossSprite.width / 2;
var bossPowerLevel = Math.floor((currentWave - 1) / 3);
self.speed = 1.5 + bossPowerLevel * 0.5;
self.hp = 10 + bossPowerLevel * 5;
self.maxHp = self.hp;
self.target = null;
self.lastHitTick = 0;
self.update = function () {
// Move towards player
var tx = player.x;
var ty = player.y;
// If wall/trap/tower is closer, target that
var minDist = Math.sqrt((self.x - tx) * (self.x - tx) + (self.y - ty) * (self.y - ty));
var targetObj = player;
for (var i = 0; i < defenses.length; i++) {
var d = defenses[i];
var dist = Math.sqrt((self.x - d.x) * (self.x - d.x) + (self.y - d.y) * (self.y - d.y));
if (dist < minDist) {
minDist = dist;
targetObj = d;
}
}
self.target = targetObj;
var dx = targetObj.x - self.x;
var dy = targetObj.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
dx /= len;
dy /= len;
self.x += dx * self.speed;
self.y += dy * self.speed;
}
// Attack if close
if (len < self.radius + targetObj.radius + 10) {
if (LK.ticks - self.lastHitTick > 30) {
if (targetObj === player) {
player.takeDamage(2); // Boss does more damage
} else if (targetObj.takeDamage) {
targetObj.takeDamage(2);
}
self.lastHitTick = LK.ticks;
}
}
};
self.takeDamage = function (amount) {
self.hp -= amount;
if (self.hp <= 0) {
self.die();
} else {
LK.effects.flashObject(self, 0xff00ff, 300);
}
};
self.die = function () {
LK.getSound('zombie_die').play();
// Drop 5 coins
var coinCount = 5;
if (typeof coinMultiplierEnabled !== "undefined" && coinMultiplierEnabled) {
coinCount = Math.round(5 * 1.5);
}
for (var i = 0; i < coinCount; i++) {
var coin = new Coin();
// Spread coins a bit
var angle = Math.PI * 2 * i / coinCount;
coin.x = self.x + Math.cos(angle) * 60;
coin.y = self.y + Math.sin(angle) * 60;
coins.push(coin);
game.addChild(coin);
}
self.destroy();
var idx = zombies.indexOf(self);
if (idx !== -1) zombies.splice(idx, 1);
zombiesKilledThisWave++;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width / 2;
self.vx = 0;
self.vy = 0;
self.damage = 1;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Coin class
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinSprite = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = coinSprite.width * 1.5; // Even further increase hitbox radius for much easier collection
// Remove vy and falling logic so coin stays at spawn position
self.collected = false;
self.update = function () {
// No falling, coin stays at its spawn position
};
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('coin').play();
// Animate to coinText
var guiPos = LK.gui.topRight.toLocal(game.toGlobal({
x: self.x,
y: self.y
}));
var startX = self.x,
startY = self.y;
var endX = 2048 - 200,
endY = 80;
tween(self, {
x: endX,
y: endY,
alpha: 0
}, {
duration: 400,
easing: tween.cubicIn,
onFinish: function onFinish() {
self.destroy();
var idx = coins.indexOf(self);
if (idx !== -1) coins.splice(idx, 1);
if (typeof coinMultiplierEnabled !== "undefined" && coinMultiplierEnabled) {
coinsCollected += 1.5;
} else {
coinsCollected++;
}
coinsCollected = Math.floor(coinsCollected);
updateCoinText();
}
});
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = playerSprite.width / 2;
self.hp = 10;
self.maxHp = 10;
self.shootCooldown = 0;
self.shootDelay = 20; // frames
self.weaponLevel = 1;
self.lastShotTick = 0;
// For drag
self.down = function (x, y, obj) {};
self.up = function (x, y, obj) {};
self.update = function () {
if (self.shootCooldown > 0) self.shootCooldown--;
};
// Shoot method
self.shoot = function (targetX, targetY) {
if (self.shootCooldown > 0) return;
var dx = targetX - self.x;
var dy = targetY - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) return;
dx /= len;
dy /= len;
var bullet = new Bullet();
bullet.x = self.x + dx * (self.radius + 30);
bullet.y = self.y + dy * (self.radius + 30);
bullet.vx = dx * (22 + self.weaponLevel * 2);
bullet.vy = dy * (22 + self.weaponLevel * 2);
bullet.damage = self.weaponLevel;
// Set bullet rotation so the tip faces the direction of movement
if (bullet.children && bullet.children.length > 0) {
bullet.children[0].rotation = Math.atan2(bullet.vy, bullet.vx);
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = self.shootDelay;
};
// Take damage
self.takeDamage = function (amount) {
self.hp -= amount;
if (self.hp < 0) self.hp = 0;
LK.effects.flashObject(self, 0xff0000, 300);
updateHpBar();
if (self.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
};
return self;
});
// Tower class
var Tower = Container.expand(function () {
var self = Container.call(this);
var towerSprite = self.attachAsset('tower', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = Math.max(towerSprite.width, towerSprite.height) / 2;
self.hp = 8;
self.maxHp = 8;
self.shootCooldown = 0;
self.shootDelay = 40;
self.takeDamage = function (amount) {
self.hp -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hp <= 0) {
self.destroy();
var idx = defenses.indexOf(self);
if (idx !== -1) defenses.splice(idx, 1);
}
};
self.update = function () {
if (self.shootCooldown > 0) self.shootCooldown--;
// Find nearest zombie
var nearest = null,
minDist = 99999;
for (var i = 0; i < zombies.length; i++) {
var z = zombies[i];
var dx = z.x - self.x;
var dy = z.y - self.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
nearest = z;
}
}
if (nearest && self.shootCooldown <= 0) {
// Shoot at nearest zombie
var dx = nearest.x - self.x;
var dy = nearest.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
dx /= len;
dy /= len;
var bullet = new Bullet();
bullet.x = self.x + dx * (self.radius + 20);
bullet.y = self.y + dy * (self.radius + 20);
bullet.vx = dx * 18;
bullet.vy = dy * 18;
bullet.damage = 1;
// Set bullet rotation so the tip faces the direction of movement
if (bullet.children && bullet.children.length > 0) {
bullet.children[0].rotation = Math.atan2(bullet.vy, bullet.vx);
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = self.shootDelay;
}
}
};
return self;
});
// Trap class
var Trap = Container.expand(function () {
var self = Container.call(this);
var trapSprite = self.attachAsset('trap', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = Math.max(trapSprite.width, trapSprite.height) / 2;
self.hp = 2;
self.maxHp = 2;
self.takeDamage = function (amount) {
self.hp -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hp <= 0) {
self.destroy();
var idx = defenses.indexOf(self);
if (idx !== -1) defenses.splice(idx, 1);
}
};
return self;
});
// Wall class
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallSprite = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = Math.max(wallSprite.width, wallSprite.height) / 2;
self.hp = 6;
self.maxHp = 6;
self.takeDamage = function (amount) {
self.hp -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hp <= 0) {
self.destroy();
var idx = defenses.indexOf(self);
if (idx !== -1) defenses.splice(idx, 1);
}
};
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieSprite = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = zombieSprite.width / 2;
// Zombies get stronger only every 3 waves
var zombiePowerLevel = Math.floor((currentWave - 1) / 3);
self.speed = 2 + zombiePowerLevel * 0.9;
self.hp = 1 + zombiePowerLevel;
self.maxHp = self.hp;
self.target = null;
self.lastHitTick = 0;
self.update = function () {
// Move towards player
var tx = player.x;
var ty = player.y;
// If wall/trap/tower is closer, target that
var minDist = Math.sqrt((self.x - tx) * (self.x - tx) + (self.y - ty) * (self.y - ty));
var targetObj = player;
for (var i = 0; i < defenses.length; i++) {
var d = defenses[i];
var dist = Math.sqrt((self.x - d.x) * (self.x - d.x) + (self.y - d.y) * (self.y - d.y));
if (dist < minDist) {
minDist = dist;
targetObj = d;
}
}
self.target = targetObj;
var dx = targetObj.x - self.x;
var dy = targetObj.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
dx /= len;
dy /= len;
self.x += dx * self.speed;
self.y += dy * self.speed;
}
// Attack if close
if (len < self.radius + targetObj.radius + 10) {
if (LK.ticks - self.lastHitTick > 30) {
if (targetObj === player) {
player.takeDamage(1);
} else if (targetObj.takeDamage) {
targetObj.takeDamage(1);
}
self.lastHitTick = LK.ticks;
}
}
};
self.takeDamage = function (amount) {
self.hp -= amount;
if (self.hp <= 0) {
self.die();
} else {
LK.effects.flashObject(self, 0xff0000, 200);
}
};
self.die = function () {
LK.getSound('zombie_die').play();
// Drop coin
var coin = new Coin();
coin.x = self.x;
coin.y = self.y;
coins.push(coin);
game.addChild(coin);
self.destroy();
var idx = zombies.indexOf(self);
if (idx !== -1) zombies.splice(idx, 1);
zombiesKilledThisWave++;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Global variables
// Character (player)
// Zombie
// Bullet
// Coin
// Wall
// Trap
// Tower
// Sounds
var player;
var zombies = [];
var bullets = [];
var coins = [];
var defenses = [];
var coinsCollected = 0;
var autoCollectEnabled = false;
var coinMultiplierEnabled = false;
var currentWave = 1;
var zombiesToSpawn = 0;
var zombiesSpawnedThisWave = 0;
var zombiesKilledThisWave = 0;
var waveInProgress = false;
var dragNode = null;
var buildMode = null; // 'wall', 'trap', 'tower', 'upgrade', 'autocollect', 'coinmult'
var buildPreview = null;
var buildCost = {
wall: 5,
trap: 7,
tower: 12,
upgrade: 10,
autocollect: 20,
coinmult: 50,
checkpoint: 25
};
var buildNames = {
wall: "Duvar",
trap: "Tuzak",
tower: "Kule",
upgrade: "Silah+",
autocollect: "Oto-Para",
coinmult: "Para x1.5",
checkpoint: "Checkpoint"
};
// buildDesc removed
var hpBar,
coinText,
waveText,
buildPanel,
buildButtons = [];
var lastTouchX = 0,
lastTouchY = 0;
// UI: HP Bar
function updateHpBar() {
if (!hpBar) return;
var txt = "";
for (var i = 0; i < player.maxHp; i++) {
txt += i < player.hp ? "♥ " : "♡ ";
}
hpBar.setText(txt);
}
// UI: Coin Text
function updateCoinText() {
if (coinText) coinText.setText("₺ " + coinsCollected);
// Rebuild build panel to update overlays/locks if it exists
if (typeof buildPanel !== "undefined" && buildPanel) {
buildPanel.destroy();
buildButtons = [];
createBuildPanel();
}
}
// UI: Wave Text
function updateWaveText() {
if (waveText) waveText.setText("Dalga: " + currentWave);
}
// UI: Build Panel
function createBuildPanel() {
buildPanel = new Container();
buildPanel.y = 0;
buildPanel.x = 0;
var btnW = 140,
btnH = 56,
gap = 18;
// Dynamically build types array based on upgrade state
var types = ['wall', 'trap', 'tower', 'upgrade'];
// Always allow checkpoint purchase
types.push('checkpoint');
if (!autoCollectEnabled) {
types.push('autocollect');
} else if (!coinMultiplierEnabled) {
types.push('coinmult');
}
for (var i = 0; i < types.length; i++) {
(function (type, idx) {
var btn = new Container();
var bg = LK.getAsset('wall', {
width: btnW,
height: btnH,
color: 0x333333,
anchorX: 0,
anchorY: 0
});
btn.addChild(bg);
var label = buildNames[type] ? buildNames[type] : type === 'coinmult' ? "Para x1.5" : type;
var cost = buildCost[type] ? buildCost[type] : type === 'coinmult' ? 50 : 0;
var txt = new Text2(label + "\n₺" + cost, {
size: 32,
fill: "#fff"
});
txt.x = btnW / 2;
txt.y = 12;
txt.anchor.set(0.5, 0);
btn.addChild(txt);
btn.x = idx * (btnW + gap) - 10; // Move each button 10px to the left (was 100px)
btn.y = 0;
btn.type = type;
// Check if player can afford this item
var canAfford = coinsCollected >= cost;
if (!canAfford) {
// Add a semi-transparent black overlay
var overlay = LK.getAsset('wall', {
width: btnW,
height: btnH,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
overlay.alpha = 0.45;
btn.addChild(overlay);
// Add a lock icon (use a Text2 lock emoji for simplicity)
var lockIcon = new Text2("🔒", {
size: 38,
fill: "#fff"
});
lockIcon.x = btnW / 2;
lockIcon.y = btnH / 2 - 18;
lockIcon.anchor.set(0.5, 0.5);
btn.addChild(lockIcon);
// Disable interaction
btn.down = function () {};
} else {
btn.down = function (x, y, obj) {
setBuildMode(type);
};
}
buildPanel.addChild(btn);
buildButtons.push(btn);
})(types[i], i);
}
buildPanel.y = -120; // Move the build panel further up by 120px (closer to bottom)
buildPanel.x = -320; // Move the build panel to the right (was -540)
LK.gui.bottom.addChild(buildPanel);
}
// Set build mode
function setBuildMode(type) {
buildMode = type;
if (buildPreview) {
buildPreview.destroy();
buildPreview = null;
}
if (type === 'wall') {
buildPreview = new Wall();
} else if (type === 'trap') {
buildPreview = new Trap();
} else if (type === 'tower') {
buildPreview = new Tower();
} else if (type === 'upgrade' || type === 'autocollect') {
buildPreview = null;
}
if (buildPreview) {
buildPreview.alpha = 0.5;
game.addChild(buildPreview);
}
}
// Remove build preview
function clearBuildPreview() {
if (buildPreview) {
buildPreview.destroy();
buildPreview = null;
}
buildMode = null;
}
// Start new wave
function startWave() {
zombiesToSpawn = 5 + currentWave * 2;
zombiesSpawnedThisWave = 0;
zombiesKilledThisWave = 0;
waveInProgress = true;
updateWaveText();
// Spawn boss every 3 waves
if (currentWave % 3 === 0) {
// Boss will be spawned after all regular zombies
zombiesToSpawn += 1;
}
}
// Spawn zombie
function spawnZombie() {
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
var zx, zy;
if (edge === 0) {
// top
zx = 200 + Math.random() * (2048 - 400);
zy = -60;
} else if (edge === 1) {
// right
zx = 2048 + 60;
zy = 200 + Math.random() * (2732 - 400);
} else if (edge === 2) {
// bottom
zx = 200 + Math.random() * (2048 - 400);
zy = 2732 + 60;
} else {
// left
zx = -60;
zy = 200 + Math.random() * (2732 - 400);
}
// If this is a boss wave and this is the last zombie, spawn boss
var isBossWave = currentWave % 3 === 0;
var isLastZombie = zombiesSpawnedThisWave === zombiesToSpawn - 1 && isBossWave;
var z;
if (isLastZombie) {
z = new BossZombie();
} else {
z = new Zombie();
}
z.x = zx;
z.y = zy;
zombies.push(z);
game.addChild(z);
zombiesSpawnedThisWave++;
}
// Build defense
function buildDefense(type, x, y) {
if (coinsCollected < buildCost[type]) return false;
var obj;
if (type === 'wall') {
obj = new Wall();
} else if (type === 'trap') {
obj = new Trap();
} else if (type === 'tower') {
obj = new Tower();
}
if (obj) {
obj.x = x;
obj.y = y;
defenses.push(obj);
game.addChild(obj);
coinsCollected -= buildCost[type];
updateCoinText();
LK.getSound('build').play();
return true;
}
return false;
}
// Upgrade weapon
function upgradeWeapon() {
if (coinsCollected < buildCost.upgrade) return false;
player.weaponLevel++;
coinsCollected -= buildCost.upgrade;
updateCoinText();
LK.effects.flashObject(player, 0xffff00, 600);
LK.getSound('build').play();
return true;
}
// Handle move (drag, build preview, collect coin)
function handleMove(x, y, obj) {
lastTouchX = x;
lastTouchY = y;
// Drag player
if (dragNode === player) {
// Clamp to game area
var r = player.radius + 10;
player.x = Math.max(r, Math.min(2048 - r, x));
player.y = Math.max(r, Math.min(2732 - r, y));
}
// Build preview follows finger
if (buildPreview) {
buildPreview.x = x;
buildPreview.y = y;
}
// Coin collection
for (var i = coins.length - 1; i >= 0; i--) {
var c = coins[i];
var dx = c.x - x,
dy = c.y - y;
if (!c.collected && dx * dx + dy * dy < c.radius * c.radius + 1200) {
c.collect();
}
}
}
// Handle down (start drag, build, upgrade)
game.down = function (x, y, obj) {
// If build mode is active
if (buildMode) {
if (buildMode === 'upgrade') {
if (upgradeWeapon()) {
clearBuildPreview();
}
} else if (buildMode === 'autocollect') {
if (!autoCollectEnabled && coinsCollected >= buildCost.autocollect) {
coinsCollected -= buildCost.autocollect;
updateCoinText();
autoCollectEnabled = true;
LK.effects.flashObject(player, 0x00ffcc, 600);
LK.getSound('build').play();
clearBuildPreview();
// Recreate build panel to remove autocollect and add coinmult
if (buildPanel) {
buildPanel.destroy();
buildButtons = [];
createBuildPanel();
}
}
} else if (buildMode === 'coinmult') {
if (!coinMultiplierEnabled && coinsCollected >= buildCost.coinmult) {
coinsCollected -= buildCost.coinmult;
updateCoinText();
coinMultiplierEnabled = true;
LK.effects.flashObject(player, 0xffe066, 600);
LK.getSound('build').play();
clearBuildPreview();
// Recreate build panel to remove coinmult
if (buildPanel) {
buildPanel.destroy();
buildButtons = [];
createBuildPanel();
}
}
} else if (buildMode === 'checkpoint') {
if (coinsCollected >= buildCost.checkpoint) {
coinsCollected -= buildCost.checkpoint;
updateCoinText();
LK.effects.flashObject(player, 0x66ff66, 600);
LK.getSound('build').play();
clearBuildPreview();
// Save checkpoint data (player position, wave, coins, upgrades, etc.)
if (typeof storage !== "undefined") {
storage.set("checkpoint", {
playerX: player.x,
playerY: player.y,
currentWave: currentWave,
coinsCollected: coinsCollected,
weaponLevel: player.weaponLevel,
autoCollectEnabled: autoCollectEnabled,
coinMultiplierEnabled: coinMultiplierEnabled
});
}
}
} else {
// Place defense if possible
if (buildPreview) {
// Don't allow build on player or on top of other defenses
var canBuild = true;
var dx = player.x - x,
dy = player.y - y;
if (dx * dx + dy * dy < (player.radius + buildPreview.radius + 40) * (player.radius + buildPreview.radius + 40)) {
canBuild = false;
}
for (var i = 0; i < defenses.length; i++) {
var d = defenses[i];
var ddx = d.x - x,
ddy = d.y - y;
if (ddx * ddx + ddy * ddy < (d.radius + buildPreview.radius + 30) * (d.radius + buildPreview.radius + 30)) {
canBuild = false;
break;
}
}
if (canBuild && buildDefense(buildMode, x, y)) {
clearBuildPreview();
}
}
}
return;
}
// Only handle mouse/touch events with event object
var event = obj && obj.event ? obj.event : null;
var isLeftClick = false;
var isMiddleClick = false;
// Mouse events
if (event && typeof event.button !== "undefined") {
// 0: left, 1: middle
if (event.button === 0) isLeftClick = true;
if (event.button === 1) isMiddleClick = true;
} else {
// Touch events: treat as left click (drag/shoot)
isLeftClick = true;
}
if (isMiddleClick) {
// Teleport player to clicked position, clamp to game area
var r = player.radius + 10;
player.x = Math.max(r, Math.min(2048 - r, x));
player.y = Math.max(r, Math.min(2732 - r, y));
} else if (isLeftClick) {
// If click/touch is on player, start drag
var dx = player.x - x,
dy = player.y - y;
if (dx * dx + dy * dy < player.radius * player.radius + 2000) {
dragNode = player;
} else {
// Otherwise, shoot
player.shoot(x, y);
}
}
handleMove(x, y, obj);
};
// Prevent context menu on right click for the canvas
if (typeof window !== "undefined" && typeof document !== "undefined") {
var canvas = document.querySelector('canvas');
if (canvas) {
canvas.oncontextmenu = function (e) {
e.preventDefault();
return false;
};
}
}
// Handle up (stop drag, clear build preview)
game.up = function (x, y, obj) {
dragNode = null;
// If build preview exists, clear it if not placed
if (buildPreview && buildMode) {
clearBuildPreview();
}
};
// Handle move
game.move = handleMove;
// Game update
game.update = function () {
// Player update
player.update();
// Zombies update
for (var i = zombies.length - 1; i >= 0; i--) {
zombies[i].update();
}
// Bullets update
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if out of bounds
if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
for (var j = zombies.length - 1; j >= 0; j--) {
var z = zombies[j];
var dx = z.x - b.x,
dy = z.y - b.y;
if (dx * dx + dy * dy < (z.radius + b.radius) * (z.radius + b.radius)) {
z.takeDamage(b.damage);
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Coins update
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].update();
if (autoCollectEnabled && !coins[i].collected) {
coins[i].collect();
}
}
// Defenses update
for (var i = defenses.length - 1; i >= 0; i--) {
if (defenses[i].update) defenses[i].update();
}
// Wave logic
if (waveInProgress) {
// Spawn zombies
if (zombiesSpawnedThisWave < zombiesToSpawn && LK.ticks % Math.max(20, 60 - currentWave * 2) === 0) {
spawnZombie();
}
// Check wave end
if (zombiesKilledThisWave >= zombiesToSpawn && zombies.length === 0) {
waveInProgress = false;
// Give 5 coins every 5 waves at the end of the wave
if (currentWave % 5 === 0) {
coinsCollected += 5;
updateCoinText();
}
// Next wave after 4 seconds (4000 ms)
LK.setTimeout(function () {
currentWave++;
startWave();
}, 4000);
}
}
};
// --- Game Initialization ---
// Place player at center
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// UI: HP Bar
hpBar = new Text2("", {
size: 80,
fill: 0xFF4444
});
// Move hearts further to the left, but still leave space for menu (x=60)
hpBar.anchor.set(0, 0);
LK.gui.top.addChild(hpBar);
hpBar.x = 60;
hpBar.y = 20;
updateHpBar();
// UI: Coin Text
coinText = new Text2("₺ 0", {
size: 70,
fill: 0xFFE066
});
coinText.anchor.set(1, 0);
LK.gui.topRight.addChild(coinText);
coinText.x = -40;
coinText.y = 20;
// UI: Wave Text
waveText = new Text2("Dalga: 1", {
size: 60,
fill: "#fff"
});
waveText.anchor.set(0, 0);
LK.gui.top.addChild(waveText);
waveText.x = 60;
waveText.y = 120;
// UI: Build Panel
createBuildPanel();
// Start first wave
startWave();
updateCoinText();
updateWaveText();
9mm ammo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
içinde c yazan sarı renkli bir madeni para. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
clash of clans klan kalesi. In-Game asset. 2d. High contrast. No shadows
the zombie. In-Game asset. 2d. High contrast. No shadows
gray block. In-Game asset. 2d. High contrast. No shadows
trap. In-Game asset. 2d. High contrast. No shadows
arazi pxelart sadece yeşillikle dolu. In-Game asset. 2d. High contrast. No shadows
elinde silahı olan bir asker. In-Game asset. 2d. High contrast. No shadows