/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // AnaBase (player base) var AnaBase = Container.expand(function () { var self = Container.call(this); var base = self.attachAsset('anaBase', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 100; self.maxHp = 100; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = 120; self.hpBar.set(1); return self; }); // EnemyBase (enemy base) var EnemyBase = Container.expand(function () { var self = Container.call(this); var base = self.attachAsset('enemyBase', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 100; self.maxHp = 100; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = 120; self.hpBar.set(1); return self; }); // Enemy Gunner Bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 14; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // Enemy soldier (Araba) var EnemyCar = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemyCar', { anchorX: 0.5, anchorY: 1 }); self.hp = 50; self.maxHp = 50; self.atk = 20; self.speed = 5; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -60; self.hpBar.set(1); self.update = function () { self.x -= self.speed; }; return self; }); // Enemy Car Bullet var EnemyCarBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyCarBullet', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 20; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // Enemy soldier (Mermi sıkan) var EnemyGunner = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemySoldier2', { anchorX: 0.5, anchorY: 1 }); self.hp = 30; self.maxHp = 30; self.atk = 14; self.speed = 3.5; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -90; self.hpBar.set(1); self.update = function () { self.x -= self.speed; // --- EnemyGunner Firing Logic --- if (!self.fireTimer) self.fireTimer = 0; self.fireTimer++; var fireInterval = 60; if (self.fireTimer >= fireInterval) { // Find closest player soldier, else aim at anaBase var target = null; var minDist = 99999; if (typeof playerSoldiers !== "undefined") { for (var ps = 0; ps < playerSoldiers.length; ps++) { var p = playerSoldiers[ps]; var dx = p.x - self.x; var dy = p.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; target = p; } } } if (!target && typeof anaBase !== "undefined") { target = anaBase; } if (target) { var b = new EnemyBullet(); b.x = self.x; b.y = self.y - 70; var tx = target.x; var ty = target.y; var dx = tx - b.x; var dy = ty - b.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; b.vx = dx / dist * 18; b.vy = dy / dist * 18; b.damage = self.atk || 14; if (typeof enemyBullets !== "undefined" && typeof game !== "undefined") { enemyBullets.push(b); game.addChild(b); } self.fireTimer = 0; } } }; return self; }); // Enemy soldier (Jet) var EnemyJet = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemyJet', { anchorX: 0.5, anchorY: 1 }); self.hp = 80; self.maxHp = 80; self.atk = 60; self.speed = 8; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -40; self.hpBar.set(1); self.update = function () { self.x -= self.speed; }; return self; }); // Enemy Jet Missile var EnemyJetMissile = Container.expand(function () { var self = Container.call(this); var missile = self.attachAsset('enemyJetMissile', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 60; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // Enemy StoneThrower Bullet var EnemyStone = Container.expand(function () { var self = Container.call(this); var stone = self.attachAsset('enemyStone', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 10; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // Enemy soldier (Taş atan) var EnemyStoneThrower = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemySoldier1', { anchorX: 0.5, anchorY: 1 }); self.hp = 20; self.maxHp = 20; self.atk = 8; self.speed = 3; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -80; self.hpBar.set(1); self.update = function () { self.x -= self.speed; }; return self; }); // Enemy soldier (Tank) var EnemyTank = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemyTank', { anchorX: 0.5, anchorY: 1 }); self.hp = 120; self.maxHp = 120; self.atk = 40; self.speed = 2.2; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -70; self.hpBar.set(1); self.update = function () { self.x -= self.speed; }; return self; }); // Enemy Tank Shell var EnemyTankShell = Container.expand(function () { var self = Container.call(this); var shell = self.attachAsset('enemyTankShell', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 40; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // FireEffect animation (short-lived fire burst) var FireEffect = Container.expand(function () { var self = Container.call(this); // Use fireBurst image as fire burst var fire = self.attachAsset('fireBurst', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7 + Math.random() * 0.5, scaleY: 0.7 + Math.random() * 0.5, alpha: 0.85 }); // Animate: scale up and fade out quickly var duration = 320 + Math.random() * 120; tween(self, { scaleX: fire.scaleX * 1.5, scaleY: fire.scaleY * 1.5, alpha: 0 }, { duration: duration, easing: tween.easeOut, onComplete: function onComplete() { self.destroy(); } }); return self; }); // HealthBar class for bases and soldiers var HealthBar = Container.expand(function () { var self = Container.call(this); var bg = self.attachAsset('hpBarBg', { anchorX: 0.5, anchorY: 0.5 }); var fg = self.attachAsset('hpBarFg', { anchorX: 0.5, anchorY: 0.5 }); self.set = function (percent) { if (percent < 0) percent = 0; if (percent > 1) percent = 1; fg.width = 120 * percent; }; return self; }); // Player soldier bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 12; self.update = function () { if (self.lastX === undefined) self.lastX = self.x; if (self.lastY === undefined) self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lastX = self.x; self.lastY = self.y; }; return self; }); // Player soldier var PlayerSoldier = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('playerSoldier', { anchorX: 0.5, anchorY: 1 }); self.hp = 20; self.maxHp = 20; self.atk = 8; self.speed = 3; self.hpBar = self.addChild(new HealthBar()); self.hpBar.y = -80; self.hpBar.set(1); self.update = function () { self.x += self.speed; }; return self; }); // Slingshot (player control) var Slingshot = Container.expand(function () { var self = Container.call(this); var sling = self.attachAsset('slingshot', { anchorX: 0.5, anchorY: 1 }); sling.x -= GAME_WIDTH * 0.03; sling.y += GAME_HEIGHT * 0.05; self.stoneReady = true; self.stone = null; self.aimLine = null; self.aimStart = { x: 0, y: 0 }; self.aimEnd = { x: 0, y: 0 }; return self; }); // Stone (slingshot projectile) var Stone = Container.expand(function () { var self = Container.call(this); var stone = self.attachAsset('stone', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.damage = 20; self.update = function () { // Gravity effect if (self.lastY === undefined) self.lastY = self.y; if (self.lastVy === undefined) self.lastVy = self.vy; var gravity = 2.2 * 0.5 * 0.9; // %50 azaltıldı, ardından %10 daha azaltıldı self.vy += gravity; self.x += self.vx; self.y += self.vy; self.lastY = self.y; self.lastVy = self.vy; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf7f7f7 }); /**** * Game Code ****/ // Music icon image asset (80x80, transparent background, music note icon) // Ateş efekti için özel resim dosyası // Arkaplan resmi (2048x2732, tam ekran) // Savaş uçağı // Tank // Araba // Mermi sıkan // Taş atan // Health bar foreground // Health bar background // Slingshot // Stone (slingshot projectile) // Enemy soldier // Player soldier // EnemyBase (enemy base) // AnaBase (player base) // --- Arkaplan resmi ekle --- var backgroundImg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(backgroundImg); // Game constants // StoneThrower bullet // Gunner bullet // Car bullet // Tank shell // Jet missile var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var BASE_OFFSET_X = 220; var BASE_OFFSET_Y = 200; var GROUND_Y = GAME_HEIGHT - 300; var SLING_X = BASE_OFFSET_X; var SLING_Y = GROUND_Y - 110; var ENEMY_BASE_X = GAME_WIDTH - BASE_OFFSET_X; var ENEMY_BASE_Y = GROUND_Y; var MAX_LEVEL = 50; // Game state // Game state var anaBase, enemyBase, slingshot; var playerSoldiers = []; var enemySoldiers = []; var stones = []; var enemyBullets = []; // All enemy bullets (all types) var playerBullets = []; // All player bullets var level = storage.level || 1; var score = storage.score || 0; var upgradePoints = storage.upgradePoints || 0; // --- Freeze logic for firing phase --- var freezeAllSoldiers = false; var freezeWho = null; // "player" or "enemy" or null function isFiringPhase() { // If there are any playerBullets or enemyBullets, or stones, freeze all soldiers // But only if both sides still have soldiers var playerAlive = playerSoldiers.length > 0; var enemyAlive = enemySoldiers.length > 0; var firingObjects = playerBullets.length > 0 || enemyBullets.length > 0 || stones.length > 0; return firingObjects && playerAlive && enemyAlive; } var isDraggingSling = false; var dragStart = { x: 0, y: 0 }; var dragEnd = { x: 0, y: 0 }; var lastTouchId = null; var spawnTimers = { player: 0, enemy: 0 }; var enemySpawnInterval = 120; var playerSpawnInterval = 120; var enemySoldierStats = { hp: 20, atk: 8, speed: 3 }; var playerSoldierStats = { hp: 20, atk: 9.6, speed: 3 }; var enemyBaseStats = { hp: 100 }; var anaBaseStats = { hp: 130 }; var levelTxt, scoreTxt, upgradeTxt; // UI levelTxt = new Text2('Level: ' + level, { size: 80, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); levelTxt.anchor.set(0.5, 0); // Add Reset button to the left of levelTxt var resetBtn = new Text2('Reset', { size: 70, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); resetBtn.anchor.set(0.5, 0); resetBtn.x = -260 - GAME_WIDTH * 0.05; // Shifted 5% to the left resetBtn.y = 0; levelTxt.addChild(resetBtn); // Reset handler resetBtn.interactive = true; resetBtn.buttonMode = true; resetBtn.down = function (x, y, obj) { // Reset all game state level = 1; score = 0; upgradePoints = 0; enemyBaseStats.hp = 100; anaBaseStats.hp = 130; playerSoldierStats.hp = 20; playerSoldierStats.atk = 9.6; playerSoldierStats.speed = 3; enemySoldierStats.hp = 20; enemySoldierStats.atk = 8; enemySoldierStats.speed = 3; enemySpawnInterval = 120; playerSpawnInterval = 120; // Remove all soldiers and stones for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy(); for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy(); for (var i = 0; i < stones.length; i++) stones[i].destroy(); playerSoldiers = []; enemySoldiers = []; stones = []; // Reset bases anaBase.hp = anaBaseStats.hp; anaBase.maxHp = anaBaseStats.hp; enemyBase.hp = enemyBaseStats.hp; enemyBase.maxHp = enemyBaseStats.hp; // Save progress storage.level = level; storage.score = score; storage.upgradePoints = upgradePoints; // Update UI immediately levelTxt.setText('Level: ' + level); scoreTxt.setText('Score: ' + score); anaBase.hpBar.set(anaBase.hp / anaBase.maxHp); enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp); showUpgradeMsg("Game Reset!"); }; LK.gui.top.addChild(levelTxt); scoreTxt = new Text2('Score: ' + score, { size: 80, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = GAME_WIDTH * 0.25; // Shifted 25% to the right LK.gui.top.addChild(scoreTxt); upgradeTxt = new Text2('', { size: 60, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); upgradeTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(upgradeTxt); // --- 10 Upgrade Features UI --- var upgradeFeatures = [{ name: "AnaBase HP +20", cost: Math.round(30 * 1.2), apply: function apply() { anaBaseStats.hp += 20; anaBase.maxHp = anaBaseStats.hp; anaBase.hp = anaBaseStats.hp; } }, { name: "Soldier HP +6", cost: Math.round(20 * 1.2), apply: function apply() { playerSoldierStats.hp += 6; } }, { name: "Soldier Atk +2", cost: Math.round(20 * 1.2), apply: function apply() { playerSoldierStats.atk += 2; } }, { name: "Soldier Speed +0.5", cost: Math.round(20 * 1.2), apply: function apply() { playerSoldierStats.speed += 0.5; } }, { name: "Enemy Soldier HP -4", cost: Math.round(25 * 1.2), apply: function apply() { enemySoldierStats.hp = Math.max(4, enemySoldierStats.hp - 4); } }, { name: "Enemy Soldier Atk -1", cost: Math.round(25 * 1.2), apply: function apply() { enemySoldierStats.atk = Math.max(1, enemySoldierStats.atk - 1); } }, { name: "Slingshot Stone Dmg +5", cost: Math.round(20 * 1.2), apply: function apply() { Stone.prototype.damage = (Stone.prototype.damage || 20) + 5; } }, { name: "Slingshot Stone Speed +4", cost: Math.round(20 * 1.2), apply: function apply() { _fireStone.stoneSpeed = (_fireStone.stoneSpeed || 32) + 4; } }, { name: "Soldier Limit +1", cost: Math.round(40 * 1.2), apply: function apply() { if (!game.maxPlayerSoldiers) game.maxPlayerSoldiers = 6; game.maxPlayerSoldiers++; } }, { name: "Base HP Restore +10", cost: Math.round(30 * 1.2), apply: function apply() { anaBase.hp = Math.min(anaBase.maxHp, anaBase.hp + 10); } }, // --- NEW UPGRADE FEATURES --- { name: "Faster Soldier Spawn", cost: Math.round(50 * 1.2), apply: function apply() { playerSpawnInterval = Math.max(30, playerSpawnInterval - 10); } }, { name: "Faster Enemy Spawn (for challenge!)", cost: Math.round(40 * 1.2), apply: function apply() { enemySpawnInterval = Math.max(30, enemySpawnInterval - 10); } }, { name: "Stone Gravity -10%", cost: Math.round(35 * 1.2), apply: function apply() { if (!Stone.prototype.gravity) Stone.prototype.gravity = 2.2 * 0.5 * 0.9; Stone.prototype.gravity *= 0.9; } }]; // Track upgrades purchased and levels var upgradesPurchased = []; var upgradesLevel = []; // new: track level for each upgrade for (var i = 0; i < 10; i++) { upgradesPurchased[i] = 0; upgradesLevel[i] = 0; } // UI: Create upgrade buttons below the reset button, aligned to the left edge var upgradeButtons = []; var musicOn = true; var musicIcon = LK.getAsset('musicIcon', { width: 80, height: 80, anchorX: 0.5, anchorY: 0, x: resetBtn.x, y: resetBtn.y + resetBtn.height + 40 // Reset butonunun 2 satır altı }); musicIcon.interactive = true; musicIcon.buttonMode = true; musicIcon.tint = 0x00ccff; // Açık mavi: müzik açık musicIcon.down = function (x, y, obj) { musicOn = !musicOn; if (musicOn) { LK.playMusic('Backgroundmusic'); musicIcon.tint = 0x00ccff; } else { LK.stopMusic(); musicIcon.tint = 0x888888; } }; LK.gui.top.addChild(musicIcon); // --- How to play? button and popup --- var howToPlayBtn = new Text2('How to play?', { size: 54, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); howToPlayBtn.anchor.set(0.5, 0); howToPlayBtn.x = musicIcon.x; howToPlayBtn.y = musicIcon.y + musicIcon.height + 18; howToPlayBtn.interactive = true; howToPlayBtn.buttonMode = true; var howToPlayPopup = null; howToPlayBtn.down = function (x, y, obj) { if (howToPlayPopup) { howToPlayPopup.destroy(); howToPlayPopup = null; return; } // Create popup container howToPlayPopup = new Container(); // Background // Dynamically size the background to fit the content var popupContentWidth = 1200; var popupContentHeight = 900; // Calculate content bounds (title + info + closeBtn) var titleHeight = 120; var infoHeight = 480; var closeBtnHeight = 100; var verticalPadding = 120; popupContentHeight = titleHeight + infoHeight + closeBtnHeight + verticalPadding; // Increase background height by 30% popupContentHeight = Math.round(popupContentHeight * 1.3); popupContentWidth = 1200; var popupBg = LK.getAsset('hpBarBg', { width: popupContentWidth, height: popupContentHeight, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, tint: 0x222222, alpha: 0.98 }); howToPlayPopup.addChild(popupBg); // Title var title = new Text2('How to Play', { size: 90, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); title.anchor.set(0.5, 0); title.x = GAME_WIDTH / 2; title.y = GAME_HEIGHT / 2 - popupContentHeight / 2 + 40; howToPlayPopup.addChild(title); // Instructions var info = new Text2("Defend your base and defeat the enemy!\n\n" + "- Drag the slingshot to launch stones at enemies and the enemy base.\n" + "- Tap the bottom left to spawn your soldiers (max 6).\n" + "- Your soldiers will automatically move and attack.\n" + "- Upgrade your base and soldiers using your score points.\n" + "- Defeat all enemy soldiers and destroy the enemy base to win the level.\n" + "- If your base is destroyed, you lose!\n\n" + "Good luck, Commander!", { size: 54, fill: "#fff", wordWrap: true, wordWrapWidth: 1100, align: "left", shadow: true, shadowColor: "#222", shadowBlur: 6, shadowOffsetX: 2, shadowOffsetY: 2 }); info.anchor.set(0.5, 0); info.x = GAME_WIDTH / 2; info.y = title.y + title.height + 40; howToPlayPopup.addChild(info); // Close button var closeBtn = new Text2('Close', { size: 60, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); closeBtn.anchor.set(0.5, 0); // Place close button at the bottom center of the background closeBtn.x = GAME_WIDTH / 2; closeBtn.y = GAME_HEIGHT / 2 + popupContentHeight / 2 - closeBtn.height - 40; closeBtn.interactive = true; closeBtn.buttonMode = true; closeBtn.down = function (x, y, obj) { if (howToPlayPopup) { howToPlayPopup.destroy(); howToPlayPopup = null; } }; howToPlayPopup.addChild(closeBtn); game.addChild(howToPlayPopup); }; LK.gui.top.addChild(howToPlayBtn); var upgradeStartY = resetBtn.y + resetBtn.height + 20; // Reset butonunun hemen altına hizala var upgradeLeftX = 0; // Tam sol kenara hizalı (platform menüsüne çakışmaz, 0'dan başlat) // Upgrade feature buttons are hidden from the main screen UI as requested. // Patch fireStone to use upgradeable speed var origFireStone = _fireStone; _fireStone = function fireStone(fromX, fromY, toX, toY) { var s = new Stone(); s.x = fromX; s.y = fromY; var dx = fromX - toX; var dy = fromY - toY; var dist = Math.sqrt(dx * dx + dy * dy); var speed = _fireStone.stoneSpeed || 32; s.vx = dx / dist * speed; s.vy = dy / dist * speed; // Patch damage if upgraded if (typeof Stone.prototype.damage === "number") s.damage = Stone.prototype.damage; stones.push(s); game.addChild(s); }; // Start background music by default LK.playMusic('Backgroundmusic'); // Add bases anaBase = new AnaBase(); anaBase.x = BASE_OFFSET_X; anaBase.y = GROUND_Y; game.addChild(anaBase); enemyBase = new EnemyBase(); enemyBase.x = ENEMY_BASE_X; enemyBase.y = ENEMY_BASE_Y; game.addChild(enemyBase); // Add slingshot slingshot = new Slingshot(); slingshot.x = SLING_X; slingshot.y = SLING_Y; game.addChild(slingshot); // --- Store button and popup --- var storeBtn = new Text2('Store', { size: 84, // 70 (resetBtn) * 1.2 = 84 fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); storeBtn.anchor.set(0.5, 1); // Place 3 lines (approx 3x 60px) above slingshot storeBtn.x = slingshot.x; storeBtn.y = slingshot.y - 236 - 60 * 3; // slingshot.height + 3 lines above storeBtn.interactive = true; storeBtn.buttonMode = true; var storePopup = null; storeBtn.down = function (x, y, obj) { if (storePopup) { storePopup.destroy(); storePopup = null; return; } // Create popup container storePopup = new Container(); // Background var popupContentWidth = 1200 * 0.9; var popupContentHeight = 900 * 0.9; var titleHeight = 120 * 0.9; var btnHeight = 80 * 0.9; var btnSpacing = 24; // vertical space between buttons var infoHeight = (btnHeight + btnSpacing) * upgradeFeatures.length; var closeBtnHeight = 100 * 0.9; var verticalPadding = 120 * 0.9; popupContentHeight = titleHeight + infoHeight + closeBtnHeight + verticalPadding; popupContentHeight = Math.round(popupContentHeight * 1.2); var popupBg = LK.getAsset('hpBarBg', { width: popupContentWidth, height: popupContentHeight, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, tint: 0x222222, alpha: 0.98 }); storePopup.addChild(popupBg); // Title var title = new Text2('Store', { size: 108 * 0.9 * 0.95 * 0.95 * 0.95, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); title.anchor.set(0.5, 0); title.x = GAME_WIDTH / 2; title.y = GAME_HEIGHT / 2 - popupContentHeight / 2 + 40 * 0.9; storePopup.addChild(title); // Upgrade buttons (centered, evenly spaced) var startY = title.y + title.height + 40 * 0.9; var btnWidth = popupContentWidth * 0.82; for (var i = 0; i < upgradeFeatures.length; i++) { (function (idx) { var upg = upgradeFeatures[idx]; var btnLevel = typeof upgradesLevel[idx] === "number" ? upgradesLevel[idx] : 0; var btnFontSize = 84 * 0.9 * 0.95 * 0.95 * 0.95; var btnWordWrap = false; var btnWordWrapWidth = btnWidth; if (upg.name.indexOf("Faster Enemy Spawn") !== -1) { btnFontSize = btnFontSize * 0.75; // Further reduce font size to fit panel btnWordWrap = false; // Prevent line wrapping btnWordWrapWidth = btnWidth; // Use full width, but no wrap } var btn = new Text2("Lv. " + btnLevel + " " + upg.name + " (" + upg.cost + ")", { size: btnFontSize, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2, wordWrap: btnWordWrap, wordWrapWidth: btnWordWrapWidth, align: "center" }); btn.anchor.set(0.5, 0); btn.x = GAME_WIDTH / 2; btn.y = startY + idx * (btnHeight + btnSpacing); btn.interactive = true; btn.buttonMode = true; btn.down = function (x, y, obj) { if (score >= upg.cost) { score -= upg.cost; upg.apply(); upgradesLevel[idx] = (upgradesLevel[idx] || 0) + 1; upgradesPurchased[idx] = 1; upg.cost = upg.cost * 2; btn.setText("Lv. " + upgradesLevel[idx] + " " + upg.name + " (" + upg.cost + ")"); if (upgradeButtons[idx]) { upgradeButtons[idx].setText("Lv. " + upgradesLevel[idx] + " " + upg.name + " (" + upg.cost + ")"); } showUpgradeMsg(upg.name + " level " + upgradesLevel[idx] + "!"); scoreTxt.setText('Score: ' + score); storage.score = score; } else { showUpgradeMsg("Not enough points!"); } }; storePopup.addChild(btn); })(i); } // Close button var closeBtn = new Text2('Close', { size: 60, fill: "#fff", shadow: true, shadowColor: "#222", shadowBlur: 8, shadowOffsetX: 2, shadowOffsetY: 2 }); closeBtn.anchor.set(0.5, 0); closeBtn.x = GAME_WIDTH / 2; closeBtn.y = GAME_HEIGHT / 2 + popupContentHeight / 2 - closeBtn.height - 40 * 0.9; closeBtn.interactive = true; closeBtn.buttonMode = true; closeBtn.down = function (x, y, obj) { if (storePopup) { storePopup.destroy(); storePopup = null; } }; storePopup.addChild(closeBtn); game.addChild(storePopup); }; game.addChild(storeBtn); // Helper: spawn player soldier function spawnPlayerSoldier() { var s = new PlayerSoldier(); s.hp = playerSoldierStats.hp; s.maxHp = playerSoldierStats.hp; s.atk = playerSoldierStats.atk; s.speed = playerSoldierStats.speed; s.x = anaBase.x + 100; s.y = GROUND_Y + 10; playerSoldiers.push(s); game.addChild(s); } // Helper: spawn enemy soldier function spawnEnemySoldier() { var s; // 1-4: StoneThrower, 5-10: Gunner, 11-15: Car, 16-20: Tank, 21-30: Jet if (level >= 1 && level <= 4) { s = new EnemyStoneThrower(); } else if (level >= 5 && level <= 10) { s = new EnemyGunner(); } else if (level >= 11 && level <= 15) { s = new EnemyCar(); } else if (level >= 16 && level <= 20) { s = new EnemyTank(); } else if (level >= 21 && level < 50) { // Randomly pick one of the enemy types for levels 21-49 var enemyTypes = [EnemyStoneThrower, EnemyGunner, EnemyCar, EnemyTank, EnemyJet]; var idx = Math.floor(Math.random() * enemyTypes.length); s = new enemyTypes[idx](); } else if (level === 50) { // Final level: only Jet for extra challenge s = new EnemyJet(); } else { s = new EnemyStoneThrower(); } s.x = enemyBase.x - 100; s.y = GROUND_Y + 10; enemySoldiers.push(s); game.addChild(s); } // Helper: fire stone function _fireStone(fromX, fromY, toX, toY) { var s = new Stone(); s.x = fromX; s.y = fromY; // Atış yönünü tersine çevir: sapanı geriye çek, taş ileri fırlasın var dx = fromX - toX; var dy = fromY - toY; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 32; // Daha yavaş gitmesi için azaltıldı s.vx = dx / dist * speed; s.vy = dy / dist * speed; stones.push(s); game.addChild(s); } // Helper: show upgrade message function showUpgradeMsg(msg) { upgradeTxt.setText(msg); tween(upgradeTxt, { alpha: 1 }, { duration: 0 }); tween(upgradeTxt, { alpha: 0 }, { duration: 1200, easing: tween.easeOut }); } // Touch/drag logic for slingshot game.down = function (x, y, obj) { // Only allow drag if touch is near slingshot if (Math.abs(x - slingshot.x) < 120 && Math.abs(y - slingshot.y) < 160) { isDraggingSling = true; dragStart.x = x; dragStart.y = y; dragEnd.x = x; dragEnd.y = y; } }; game.move = function (x, y, obj) { if (isDraggingSling) { dragEnd.x = x; dragEnd.y = y; } }; game.up = function (x, y, obj) { if (isDraggingSling) { // Fire stone if drag is long enough var dx = dragEnd.x - slingshot.x; var dy = dragEnd.y - slingshot.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 80 && stones.length < 2) { _fireStone(slingshot.x, slingshot.y - 60, dragEnd.x, dragEnd.y); // fireStone fonksiyonu artık ters vektörle çalışıyor } } isDraggingSling = false; }; // Tap to spawn player soldier (bottom left, not on slingshot) game.on('down', function (x, y, obj) { if (x < 300 && y > GROUND_Y + 60) { if (playerSoldiers.length < 6) { spawnPlayerSoldier(); } } }); // Upgrade logic (tap bottom right) game.on('down', function (x, y, obj) { if (x > GAME_WIDTH - 300 && y > GROUND_Y + 60) { if (upgradePoints > 0) { // Cycle upgrades: base hp, soldier hp, soldier atk, soldier speed var upg = (score + level) % 4; if (upg === 0) { anaBaseStats.hp += 20; anaBase.maxHp = anaBaseStats.hp; anaBase.hp = anaBaseStats.hp; showUpgradeMsg("AnaBase HP +20"); } else if (upg === 1) { playerSoldierStats.hp += 6; showUpgradeMsg("Soldier HP +6"); } else if (upg === 2) { playerSoldierStats.atk += 2; showUpgradeMsg("Soldier Atk +2"); } else { playerSoldierStats.speed += 0.5; showUpgradeMsg("Soldier Speed +0.5"); } upgradePoints--; } } }); // Main update loop game.update = function () { // Update UI levelTxt.setText('Level: ' + level); scoreTxt.setText('Score: ' + score); // Update health bars anaBase.hpBar.set(anaBase.hp / anaBase.maxHp); enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp); // Draw slingshot pulled band and stone visual if (isDraggingSling) { // Remove previous drag visuals if any if (slingshot.dragStone) { slingshot.dragStone.destroy(); slingshot.dragStone = null; } if (slingshot.bandLeft) { slingshot.bandLeft.destroy(); slingshot.bandLeft = null; } if (slingshot.bandRight) { slingshot.bandRight.destroy(); slingshot.bandRight = null; } // Calculate band anchor points (left/right of slingshot top) var slingTopX = slingshot.x; var slingTopY = slingshot.y - 110; var bandOffset = 22; var leftX = slingTopX - bandOffset; var rightX = slingTopX + bandOffset; var bandY = slingTopY + 10; // Place a thin rectangle as band (left) slingshot.bandLeft = LK.getAsset('hpBarFg', { width: Math.max(8, Math.sqrt((dragEnd.x - leftX) * (dragEnd.x - leftX) + (dragEnd.y - bandY) * (dragEnd.y - bandY))), height: 8, anchorX: 0, anchorY: 0.5, x: leftX, y: bandY, rotation: Math.atan2(dragEnd.y - bandY, dragEnd.x - leftX) }); game.addChild(slingshot.bandLeft); // Place a thin rectangle as band (right) slingshot.bandRight = LK.getAsset('hpBarFg', { width: Math.max(8, Math.sqrt((dragEnd.x - rightX) * (dragEnd.x - rightX) + (dragEnd.y - bandY) * (dragEnd.y - bandY))), height: 8, anchorX: 0, anchorY: 0.5, x: rightX, y: bandY, rotation: Math.atan2(dragEnd.y - bandY, dragEnd.x - rightX) }); game.addChild(slingshot.bandRight); // Place the stone at dragEnd slingshot.dragStone = LK.getAsset('stone', { anchorX: 0.5, anchorY: 0.5, x: dragEnd.x, y: dragEnd.y }); game.addChild(slingshot.dragStone); } else { // Remove drag visuals if not dragging if (slingshot.dragStone) { slingshot.dragStone.destroy(); slingshot.dragStone = null; } if (slingshot.bandLeft) { slingshot.bandLeft.destroy(); slingshot.bandLeft = null; } if (slingshot.bandRight) { slingshot.bandRight.destroy(); slingshot.bandRight = null; } } // Spawn player soldiers automatically spawnTimers.player++; if (spawnTimers.player >= playerSpawnInterval) { if (playerSoldiers.length < 6) { spawnPlayerSoldier(); } spawnTimers.player = 0; } // Spawn enemy soldiers automatically spawnTimers.enemy++; if (spawnTimers.enemy >= enemySpawnInterval) { if (enemySoldiers.length < 6) { spawnEnemySoldier(); } spawnTimers.enemy = 0; } // --- Freeze logic: check if firing phase is active --- freezeAllSoldiers = isFiringPhase(); // Update player soldiers for (var i = playerSoldiers.length - 1; i >= 0; i--) { var s = playerSoldiers[i]; // --- Freeze all player soldiers if firing phase is active --- if (freezeAllSoldiers) { // No movement, no firing, no attacking base, but still allow dying from bullets continue; } // Asker dondurma: eğer bir düşmanla çarpışıyorsa hareket etmesin var frozen = false; for (var j = enemySoldiers.length - 1; j >= 0; j--) { var e = enemySoldiers[j]; if (Math.abs(s.x - e.x) < 80 && Math.abs(s.y - e.y) < 60) { // Fight! s.hp -= e.atk * 0.03; e.hp -= s.atk * 0.03; s.hpBar.set(s.hp / s.maxHp); e.hpBar.set(e.hp / e.maxHp); frozen = true; if (e.hp <= 0) { score += 10; enemySoldiers.splice(j, 1); e.destroy(); } if (s.hp <= 0) { playerSoldiers.splice(i, 1); s.destroy(); break; } // Eğer ikisi de hayattaysa, dondurulmuş kalmaya devam etsin if (s.hp > 0 && e.hp > 0) { frozen = true; } } } // Hareketi engelle: Eğer çarpışıyorsa update çağrılmasın, çarpışmıyorsa hareket etsin if (!frozen) { // Çarpışma kontrolü: Önümüzde bir düşman var mı? var blocked = false; // Önce kendi askerlerimizi kontrol et, öndekiyle çakışıyorsak ilerleme for (var j = 0; j < playerSoldiers.length; j++) { var s2 = playerSoldiers[j]; if (s2 === s) continue; if (Math.abs(s.y - s2.y) < 60 && s2.x > s.x && s2.x - s.x < 80 && s2.x - s.x > 0 // 80px mesafeden yakınsa ) { blocked = true; break; } } // Sonra düşman askerlerini kontrol et if (!blocked) { for (var j = 0; j < enemySoldiers.length; j++) { var e = enemySoldiers[j]; if (e === s) continue; // Sadece ileriye doğru olan ve çakışan askerleri engelle if (Math.abs(s.y - e.y) < 60 && e.x > s.x && // Sadece önündeki düşman e.x - s.x < 80 && e.x - s.x > 0 // 80px mesafeden yakınsa ) { blocked = true; break; } } } if (!blocked) { s.update(); // Clamp to not go past enemy base if (s.x > enemyBase.x - 120) s.x = enemyBase.x - 120; // --- Player Firing Logic --- if (!s.fireTimer) s.fireTimer = 0; s.fireTimer++; var fireInterval = 60; if (s.fireTimer >= fireInterval) { // En yakın düşman askeri bul, yoksa enemyBase'e ateş et var target = null; var minDist = 99999; for (var es = 0; es < enemySoldiers.length; es++) { var e = enemySoldiers[es]; var dx = e.x - s.x; var dy = e.y - s.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; target = e; } } if (!target) { target = enemyBase; } // Mermi oluştur ve ateşle var b = new PlayerBullet(); b.x = s.x; b.y = s.y - 70 - GAME_HEIGHT * 0.05; // %5 yukarı kaldırıldı // Hedefe yönel var tx = target.x; var ty = target.y; var dx = tx - b.x; var dy = ty - b.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; b.vx = dx / dist * 22; b.vy = dy / dist * 22; b.damage = s.atk || 8; playerBullets.push(b); game.addChild(b); s.fireTimer = 0; } } } // If at enemy base, attack base if (s.lastAtEnemyBase === undefined) s.lastAtEnemyBase = false; var atEnemyBase = Math.abs(s.x - enemyBase.x) < 120; if (!s.lastAtEnemyBase && atEnemyBase) { // Just arrived at enemy base s.attackedBase = false; } if (!s.attackedBase && atEnemyBase) { enemyBase.hp -= s.atk * 0.15; if (enemyBase.hp < 0) enemyBase.hp = 0; s.attackedBase = true; } s.lastAtEnemyBase = atEnemyBase; } // Update enemy soldiers for (var i = enemySoldiers.length - 1; i >= 0; i--) { var e = enemySoldiers[i]; // --- Freeze all enemy soldiers if firing phase is active --- if (freezeAllSoldiers) { // No movement, no firing, no attacking base, but still allow dying from bullets continue; } // Asker dondurma: eğer bir oyuncu askeriyle çarpışıyorsa hareket etmesin var frozen = false; for (var j = playerSoldiers.length - 1; j >= 0; j--) { var s = playerSoldiers[j]; if (Math.abs(e.x - s.x) < 80 && Math.abs(e.y - s.y) < 60) { // Fight! e.hp -= s.atk * 0.03; s.hp -= e.atk * 0.03; e.hpBar.set(e.hp / e.maxHp); s.hpBar.set(s.hp / s.maxHp); frozen = true; if (s.hp <= 0) { playerSoldiers.splice(j, 1); s.destroy(); } if (e.hp <= 0) { score += 10; enemySoldiers.splice(i, 1); e.destroy(); break; } // Eğer ikisi de hayattaysa, dondurulmuş kalmaya devam etsin if (e.hp > 0 && s.hp > 0) { frozen = true; } } } // Hareketi engelle: Eğer çarpışıyorsa update çağrılmasın, çarpışmıyorsa hareket etsin if (!frozen) { // Çarpışma kontrolü: Önümüzde bir oyuncu askeri var mı? var blocked = false; // Önce kendi düşman askerlerini kontrol et, öndekiyle çakışıyorsak ilerleme for (var j = 0; j < enemySoldiers.length; j++) { var e2 = enemySoldiers[j]; if (e2 === e) continue; if (Math.abs(e.y - e2.y) < 60 && e2.x < e.x && e.x - e2.x < 80 && e.x - e2.x > 0 // 80px mesafeden yakınsa ) { blocked = true; break; } } // Sonra oyuncu askerlerini kontrol et if (!blocked) { for (var j = 0; j < playerSoldiers.length; j++) { var s = playerSoldiers[j]; if (Math.abs(e.y - s.y) < 60 && s.x > e.x && s.x - e.x < 80 && s.x - e.x > 0 // 80px mesafeden yakınsa ) { blocked = true; break; } } } if (!blocked) { e.update(); // Clamp to not go past anaBase if (e.x < anaBase.x + 120) e.x = anaBase.x + 120; } // --- Enemy Firing Logic --- if (!e.fireTimer) e.fireTimer = 0; e.fireTimer++; var fireInterval = 90; // default var BulletClass = null; var bulletSpeed = 0; var bulletDamage = 0; var bulletYOffset = 0; if (e.constructor === EnemyStoneThrower) { fireInterval = 120; BulletClass = EnemyStone; bulletSpeed = 12; bulletDamage = 10; bulletYOffset = -60; } else if (e.constructor === EnemyGunner) { fireInterval = 60; BulletClass = EnemyBullet; bulletSpeed = 18; bulletDamage = 14; bulletYOffset = -70; } else if (e.constructor === EnemyCar) { fireInterval = 80; BulletClass = EnemyCarBullet; bulletSpeed = 20; bulletDamage = 20; bulletYOffset = -40; } else if (e.constructor === EnemyTank) { fireInterval = 100; BulletClass = EnemyTankShell; bulletSpeed = 14; bulletDamage = 40; bulletYOffset = -50; } else if (e.constructor === EnemyJet) { fireInterval = 70; BulletClass = EnemyJetMissile; bulletSpeed = 28; bulletDamage = 60; bulletYOffset = -20; } if (BulletClass && e.fireTimer >= fireInterval) { // Find closest player soldier, else aim at anaBase var target = null; var minDist = 99999; for (var ps = 0; ps < playerSoldiers.length; ps++) { var p = playerSoldiers[ps]; var dx = p.x - e.x; var dy = p.y - e.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; target = p; } } if (!target) { target = anaBase; } // Fire bullet var b = new BulletClass(); b.x = e.x; b.y = e.y + bulletYOffset; // Calculate direction var tx = target.x; var ty = target.y; var dx = tx - b.x; var dy = ty - b.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; b.vx = dx / dist * bulletSpeed; b.vy = dy / dist * bulletSpeed; b.damage = bulletDamage; enemyBullets.push(b); game.addChild(b); e.fireTimer = 0; } } // If at anaBase, attack base if (e.lastAtAnaBase === undefined) e.lastAtAnaBase = false; var atAnaBase = Math.abs(e.x - anaBase.x) < 120; if (!e.lastAtAnaBase && atAnaBase) { // Just arrived at ana base e.attackedBase = false; } if (!e.attackedBase && atAnaBase) { anaBase.hp -= e.atk * 0.05; // Her asker %5 oranında base canı azaltır if (anaBase.hp < 0) anaBase.hp = 0; e.attackedBase = true; } e.lastAtAnaBase = atAnaBase; } // Update stones (slingshot projectiles) for (var i = stones.length - 1; i >= 0; i--) { var st = stones[i]; st.update(); // Remove if out of bounds if (st.x < 0 || st.x > GAME_WIDTH || st.y < 0 || st.y > GAME_HEIGHT) { stones.splice(i, 1); st.destroy(); continue; } // Hit enemy soldiers var hit = false; for (var j = enemySoldiers.length - 1; j >= 0; j--) { var e = enemySoldiers[j]; if (st.intersects(e)) { e.hp -= st.damage; e.hpBar.set(e.hp / e.maxHp); // Fire effect at collision point var fireFx = new FireEffect(); fireFx.x = st.x; fireFx.y = st.y; game.addChild(fireFx); if (e.hp <= 0) { score += 10; enemySoldiers.splice(j, 1); e.destroy(); } hit = true; break; } } // Hit enemy base if (!hit && Math.abs(st.x - enemyBase.x) < 120 && Math.abs(st.y - enemyBase.y) < 120) { enemyBase.hp -= st.damage; if (enemyBase.hp < 0) enemyBase.hp = 0; // Fire effect at base hit var fireFx = new FireEffect(); fireFx.x = st.x; fireFx.y = st.y; game.addChild(fireFx); hit = true; } if (hit) { stones.splice(i, 1); st.destroy(); } } // --- Enemy Bullets update --- for (var i = enemyBullets.length - 1; i >= 0; i--) { var b = enemyBullets[i]; b.update(); // Remove if out of bounds if (b.x < 0 || b.x > GAME_WIDTH || b.y < 0 || b.y > GAME_HEIGHT) { enemyBullets.splice(i, 1); b.destroy(); continue; } // Hit player soldiers var hit = false; for (var j = playerSoldiers.length - 1; j >= 0; j--) { var s = playerSoldiers[j]; if (b.intersects(s)) { s.hp -= b.damage; s.hpBar.set(s.hp / s.maxHp); // Fire effect at collision point var fireFx = new FireEffect(); fireFx.x = b.x; fireFx.y = b.y; game.addChild(fireFx); if (s.hp <= 0) { playerSoldiers.splice(j, 1); s.destroy(); } hit = true; break; } } // Hit anaBase if (!hit && Math.abs(b.x - anaBase.x) < 120 && Math.abs(b.y - anaBase.y) < 120) { anaBase.hp -= b.damage; if (anaBase.hp < 0) anaBase.hp = 0; // Fire effect at base hit var fireFx = new FireEffect(); fireFx.x = b.x; fireFx.y = b.y; game.addChild(fireFx); hit = true; } if (hit) { enemyBullets.splice(i, 1); b.destroy(); } } // --- Player Bullets update --- for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); // Remove if out of bounds if (b.x < 0 || b.x > GAME_WIDTH || b.y < 0 || b.y > GAME_HEIGHT) { playerBullets.splice(i, 1); b.destroy(); continue; } // Hit enemy soldiers var hit = false; for (var j = enemySoldiers.length - 1; j >= 0; j--) { var e = enemySoldiers[j]; if (b.intersects(e)) { e.hp -= b.damage; e.hpBar.set(e.hp / e.maxHp); // Fire effect at collision point var fireFx = new FireEffect(); fireFx.x = b.x; fireFx.y = b.y; game.addChild(fireFx); if (e.hp <= 0) { score += 10; enemySoldiers.splice(j, 1); e.destroy(); } hit = true; break; } } // Hit enemy base if (!hit && Math.abs(b.x - enemyBase.x) < 120 && Math.abs(b.y - enemyBase.y) < 120) { enemyBase.hp -= b.damage; if (enemyBase.hp < 0) enemyBase.hp = 0; // Fire effect at base hit var fireFx = new FireEffect(); fireFx.x = b.x; fireFx.y = b.y; game.addChild(fireFx); hit = true; } if (hit) { playerBullets.splice(i, 1); b.destroy(); } } // Check lose condition if (anaBase.hp <= 0) { // Flash and show game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); // --- FULL RESET: clear all arrays and state --- // Remove all player soldiers for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy(); for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy(); for (var i = 0; i < stones.length; i++) stones[i].destroy(); for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy(); for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy(); playerSoldiers = []; enemySoldiers = []; stones = []; enemyBullets = []; playerBullets = []; // Reset stats and progress level = 1; score = 0; upgradePoints = 0; enemyBaseStats.hp = 100; anaBaseStats.hp = 130; playerSoldierStats.hp = 20; playerSoldierStats.atk = 9.6; playerSoldierStats.speed = 3; enemySoldierStats.hp = 20; enemySoldierStats.atk = 8; enemySoldierStats.speed = 3; enemySpawnInterval = 120; playerSpawnInterval = 120; // Reset bases anaBase.hp = anaBaseStats.hp; anaBase.maxHp = anaBaseStats.hp; enemyBase.hp = enemyBaseStats.hp; enemyBase.maxHp = enemyBaseStats.hp; // Save progress storage.level = level; storage.score = score; storage.upgradePoints = upgradePoints; // Update UI immediately levelTxt.setText('Level: ' + level); scoreTxt.setText('Score: ' + score); anaBase.hpBar.set(anaBase.hp / anaBase.maxHp); enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp); showUpgradeMsg("Game Reset!"); return; } // Check win/level up if (enemyBase.lastWasDead === undefined) enemyBase.lastWasDead = false; var enemyBaseIsDead = enemyBase.hp <= 0; if (!enemyBase.lastWasDead && enemyBaseIsDead) { level++; if (level > MAX_LEVEL) { LK.showYouWin(); return; } // Increase difficulty enemyBaseStats.hp = Math.round(enemyBaseStats.hp * 1.3); enemySoldierStats.hp = Math.round(enemySoldierStats.hp * 1.3); enemySoldierStats.atk = Math.round(enemySoldierStats.atk * 1.3); enemySoldierStats.speed = Math.round(enemySoldierStats.speed * 1.3 * 100) / 100; enemySpawnInterval = Math.max(60, enemySpawnInterval - 4); playerSpawnInterval = Math.max(60, playerSpawnInterval - 2); upgradePoints++; showUpgradeMsg("Level " + level + "! Upgrade Point +1"); // Reset enemyBase.hp = enemyBaseStats.hp; enemyBase.maxHp = enemyBaseStats.hp; anaBase.hp = anaBaseStats.hp; anaBase.maxHp = anaBaseStats.hp; for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy(); for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy(); for (var i = 0; i < stones.length; i++) stones[i].destroy(); playerSoldiers = []; enemySoldiers = []; stones = []; } enemyBase.lastWasDead = enemyBaseIsDead; // Save progress storage.level = level; storage.score = score; storage.upgradePoints = upgradePoints; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// AnaBase (player base)
var AnaBase = Container.expand(function () {
var self = Container.call(this);
var base = self.attachAsset('anaBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 100;
self.maxHp = 100;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = 120;
self.hpBar.set(1);
return self;
});
// EnemyBase (enemy base)
var EnemyBase = Container.expand(function () {
var self = Container.call(this);
var base = self.attachAsset('enemyBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 100;
self.maxHp = 100;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = 120;
self.hpBar.set(1);
return self;
});
// Enemy Gunner Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 14;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy soldier (Araba)
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemyCar', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 50;
self.maxHp = 50;
self.atk = 20;
self.speed = 5;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -60;
self.hpBar.set(1);
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Enemy Car Bullet
var EnemyCarBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyCarBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 20;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy soldier (Mermi sıkan)
var EnemyGunner = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemySoldier2', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 30;
self.maxHp = 30;
self.atk = 14;
self.speed = 3.5;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -90;
self.hpBar.set(1);
self.update = function () {
self.x -= self.speed;
// --- EnemyGunner Firing Logic ---
if (!self.fireTimer) self.fireTimer = 0;
self.fireTimer++;
var fireInterval = 60;
if (self.fireTimer >= fireInterval) {
// Find closest player soldier, else aim at anaBase
var target = null;
var minDist = 99999;
if (typeof playerSoldiers !== "undefined") {
for (var ps = 0; ps < playerSoldiers.length; ps++) {
var p = playerSoldiers[ps];
var dx = p.x - self.x;
var dy = p.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
target = p;
}
}
}
if (!target && typeof anaBase !== "undefined") {
target = anaBase;
}
if (target) {
var b = new EnemyBullet();
b.x = self.x;
b.y = self.y - 70;
var tx = target.x;
var ty = target.y;
var dx = tx - b.x;
var dy = ty - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
b.vx = dx / dist * 18;
b.vy = dy / dist * 18;
b.damage = self.atk || 14;
if (typeof enemyBullets !== "undefined" && typeof game !== "undefined") {
enemyBullets.push(b);
game.addChild(b);
}
self.fireTimer = 0;
}
}
};
return self;
});
// Enemy soldier (Jet)
var EnemyJet = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemyJet', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 80;
self.maxHp = 80;
self.atk = 60;
self.speed = 8;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -40;
self.hpBar.set(1);
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Enemy Jet Missile
var EnemyJetMissile = Container.expand(function () {
var self = Container.call(this);
var missile = self.attachAsset('enemyJetMissile', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 60;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy StoneThrower Bullet
var EnemyStone = Container.expand(function () {
var self = Container.call(this);
var stone = self.attachAsset('enemyStone', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 10;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy soldier (Taş atan)
var EnemyStoneThrower = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemySoldier1', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 20;
self.maxHp = 20;
self.atk = 8;
self.speed = 3;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -80;
self.hpBar.set(1);
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Enemy soldier (Tank)
var EnemyTank = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemyTank', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 120;
self.maxHp = 120;
self.atk = 40;
self.speed = 2.2;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -70;
self.hpBar.set(1);
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Enemy Tank Shell
var EnemyTankShell = Container.expand(function () {
var self = Container.call(this);
var shell = self.attachAsset('enemyTankShell', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 40;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// FireEffect animation (short-lived fire burst)
var FireEffect = Container.expand(function () {
var self = Container.call(this);
// Use fireBurst image as fire burst
var fire = self.attachAsset('fireBurst', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7 + Math.random() * 0.5,
scaleY: 0.7 + Math.random() * 0.5,
alpha: 0.85
});
// Animate: scale up and fade out quickly
var duration = 320 + Math.random() * 120;
tween(self, {
scaleX: fire.scaleX * 1.5,
scaleY: fire.scaleY * 1.5,
alpha: 0
}, {
duration: duration,
easing: tween.easeOut,
onComplete: function onComplete() {
self.destroy();
}
});
return self;
});
// HealthBar class for bases and soldiers
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('hpBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var fg = self.attachAsset('hpBarFg', {
anchorX: 0.5,
anchorY: 0.5
});
self.set = function (percent) {
if (percent < 0) percent = 0;
if (percent > 1) percent = 1;
fg.width = 120 * percent;
};
return self;
});
// Player soldier bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 12;
self.update = function () {
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Player soldier
var PlayerSoldier = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('playerSoldier', {
anchorX: 0.5,
anchorY: 1
});
self.hp = 20;
self.maxHp = 20;
self.atk = 8;
self.speed = 3;
self.hpBar = self.addChild(new HealthBar());
self.hpBar.y = -80;
self.hpBar.set(1);
self.update = function () {
self.x += self.speed;
};
return self;
});
// Slingshot (player control)
var Slingshot = Container.expand(function () {
var self = Container.call(this);
var sling = self.attachAsset('slingshot', {
anchorX: 0.5,
anchorY: 1
});
sling.x -= GAME_WIDTH * 0.03;
sling.y += GAME_HEIGHT * 0.05;
self.stoneReady = true;
self.stone = null;
self.aimLine = null;
self.aimStart = {
x: 0,
y: 0
};
self.aimEnd = {
x: 0,
y: 0
};
return self;
});
// Stone (slingshot projectile)
var Stone = Container.expand(function () {
var self = Container.call(this);
var stone = self.attachAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = 20;
self.update = function () {
// Gravity effect
if (self.lastY === undefined) self.lastY = self.y;
if (self.lastVy === undefined) self.lastVy = self.vy;
var gravity = 2.2 * 0.5 * 0.9; // %50 azaltıldı, ardından %10 daha azaltıldı
self.vy += gravity;
self.x += self.vx;
self.y += self.vy;
self.lastY = self.y;
self.lastVy = self.vy;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf7f7f7
});
/****
* Game Code
****/
// Music icon image asset (80x80, transparent background, music note icon)
// Ateş efekti için özel resim dosyası
// Arkaplan resmi (2048x2732, tam ekran)
// Savaş uçağı
// Tank
// Araba
// Mermi sıkan
// Taş atan
// Health bar foreground
// Health bar background
// Slingshot
// Stone (slingshot projectile)
// Enemy soldier
// Player soldier
// EnemyBase (enemy base)
// AnaBase (player base)
// --- Arkaplan resmi ekle ---
var backgroundImg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(backgroundImg);
// Game constants
// StoneThrower bullet
// Gunner bullet
// Car bullet
// Tank shell
// Jet missile
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BASE_OFFSET_X = 220;
var BASE_OFFSET_Y = 200;
var GROUND_Y = GAME_HEIGHT - 300;
var SLING_X = BASE_OFFSET_X;
var SLING_Y = GROUND_Y - 110;
var ENEMY_BASE_X = GAME_WIDTH - BASE_OFFSET_X;
var ENEMY_BASE_Y = GROUND_Y;
var MAX_LEVEL = 50; // Game state
// Game state
var anaBase, enemyBase, slingshot;
var playerSoldiers = [];
var enemySoldiers = [];
var stones = [];
var enemyBullets = []; // All enemy bullets (all types)
var playerBullets = []; // All player bullets
var level = storage.level || 1;
var score = storage.score || 0;
var upgradePoints = storage.upgradePoints || 0;
// --- Freeze logic for firing phase ---
var freezeAllSoldiers = false;
var freezeWho = null; // "player" or "enemy" or null
function isFiringPhase() {
// If there are any playerBullets or enemyBullets, or stones, freeze all soldiers
// But only if both sides still have soldiers
var playerAlive = playerSoldiers.length > 0;
var enemyAlive = enemySoldiers.length > 0;
var firingObjects = playerBullets.length > 0 || enemyBullets.length > 0 || stones.length > 0;
return firingObjects && playerAlive && enemyAlive;
}
var isDraggingSling = false;
var dragStart = {
x: 0,
y: 0
};
var dragEnd = {
x: 0,
y: 0
};
var lastTouchId = null;
var spawnTimers = {
player: 0,
enemy: 0
};
var enemySpawnInterval = 120;
var playerSpawnInterval = 120;
var enemySoldierStats = {
hp: 20,
atk: 8,
speed: 3
};
var playerSoldierStats = {
hp: 20,
atk: 9.6,
speed: 3
};
var enemyBaseStats = {
hp: 100
};
var anaBaseStats = {
hp: 130
};
var levelTxt, scoreTxt, upgradeTxt;
// UI
levelTxt = new Text2('Level: ' + level, {
size: 80,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
levelTxt.anchor.set(0.5, 0);
// Add Reset button to the left of levelTxt
var resetBtn = new Text2('Reset', {
size: 70,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
resetBtn.anchor.set(0.5, 0);
resetBtn.x = -260 - GAME_WIDTH * 0.05; // Shifted 5% to the left
resetBtn.y = 0;
levelTxt.addChild(resetBtn);
// Reset handler
resetBtn.interactive = true;
resetBtn.buttonMode = true;
resetBtn.down = function (x, y, obj) {
// Reset all game state
level = 1;
score = 0;
upgradePoints = 0;
enemyBaseStats.hp = 100;
anaBaseStats.hp = 130;
playerSoldierStats.hp = 20;
playerSoldierStats.atk = 9.6;
playerSoldierStats.speed = 3;
enemySoldierStats.hp = 20;
enemySoldierStats.atk = 8;
enemySoldierStats.speed = 3;
enemySpawnInterval = 120;
playerSpawnInterval = 120;
// Remove all soldiers and stones
for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy();
for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy();
for (var i = 0; i < stones.length; i++) stones[i].destroy();
playerSoldiers = [];
enemySoldiers = [];
stones = [];
// Reset bases
anaBase.hp = anaBaseStats.hp;
anaBase.maxHp = anaBaseStats.hp;
enemyBase.hp = enemyBaseStats.hp;
enemyBase.maxHp = enemyBaseStats.hp;
// Save progress
storage.level = level;
storage.score = score;
storage.upgradePoints = upgradePoints;
// Update UI immediately
levelTxt.setText('Level: ' + level);
scoreTxt.setText('Score: ' + score);
anaBase.hpBar.set(anaBase.hp / anaBase.maxHp);
enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp);
showUpgradeMsg("Game Reset!");
};
LK.gui.top.addChild(levelTxt);
scoreTxt = new Text2('Score: ' + score, {
size: 80,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.x = GAME_WIDTH * 0.25; // Shifted 25% to the right
LK.gui.top.addChild(scoreTxt);
upgradeTxt = new Text2('', {
size: 60,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
upgradeTxt.anchor.set(0.5, 0);
LK.gui.bottom.addChild(upgradeTxt);
// --- 10 Upgrade Features UI ---
var upgradeFeatures = [{
name: "AnaBase HP +20",
cost: Math.round(30 * 1.2),
apply: function apply() {
anaBaseStats.hp += 20;
anaBase.maxHp = anaBaseStats.hp;
anaBase.hp = anaBaseStats.hp;
}
}, {
name: "Soldier HP +6",
cost: Math.round(20 * 1.2),
apply: function apply() {
playerSoldierStats.hp += 6;
}
}, {
name: "Soldier Atk +2",
cost: Math.round(20 * 1.2),
apply: function apply() {
playerSoldierStats.atk += 2;
}
}, {
name: "Soldier Speed +0.5",
cost: Math.round(20 * 1.2),
apply: function apply() {
playerSoldierStats.speed += 0.5;
}
}, {
name: "Enemy Soldier HP -4",
cost: Math.round(25 * 1.2),
apply: function apply() {
enemySoldierStats.hp = Math.max(4, enemySoldierStats.hp - 4);
}
}, {
name: "Enemy Soldier Atk -1",
cost: Math.round(25 * 1.2),
apply: function apply() {
enemySoldierStats.atk = Math.max(1, enemySoldierStats.atk - 1);
}
}, {
name: "Slingshot Stone Dmg +5",
cost: Math.round(20 * 1.2),
apply: function apply() {
Stone.prototype.damage = (Stone.prototype.damage || 20) + 5;
}
}, {
name: "Slingshot Stone Speed +4",
cost: Math.round(20 * 1.2),
apply: function apply() {
_fireStone.stoneSpeed = (_fireStone.stoneSpeed || 32) + 4;
}
}, {
name: "Soldier Limit +1",
cost: Math.round(40 * 1.2),
apply: function apply() {
if (!game.maxPlayerSoldiers) game.maxPlayerSoldiers = 6;
game.maxPlayerSoldiers++;
}
}, {
name: "Base HP Restore +10",
cost: Math.round(30 * 1.2),
apply: function apply() {
anaBase.hp = Math.min(anaBase.maxHp, anaBase.hp + 10);
}
},
// --- NEW UPGRADE FEATURES ---
{
name: "Faster Soldier Spawn",
cost: Math.round(50 * 1.2),
apply: function apply() {
playerSpawnInterval = Math.max(30, playerSpawnInterval - 10);
}
}, {
name: "Faster Enemy Spawn (for challenge!)",
cost: Math.round(40 * 1.2),
apply: function apply() {
enemySpawnInterval = Math.max(30, enemySpawnInterval - 10);
}
}, {
name: "Stone Gravity -10%",
cost: Math.round(35 * 1.2),
apply: function apply() {
if (!Stone.prototype.gravity) Stone.prototype.gravity = 2.2 * 0.5 * 0.9;
Stone.prototype.gravity *= 0.9;
}
}];
// Track upgrades purchased and levels
var upgradesPurchased = [];
var upgradesLevel = []; // new: track level for each upgrade
for (var i = 0; i < 10; i++) {
upgradesPurchased[i] = 0;
upgradesLevel[i] = 0;
}
// UI: Create upgrade buttons below the reset button, aligned to the left edge
var upgradeButtons = [];
var musicOn = true;
var musicIcon = LK.getAsset('musicIcon', {
width: 80,
height: 80,
anchorX: 0.5,
anchorY: 0,
x: resetBtn.x,
y: resetBtn.y + resetBtn.height + 40 // Reset butonunun 2 satır altı
});
musicIcon.interactive = true;
musicIcon.buttonMode = true;
musicIcon.tint = 0x00ccff; // Açık mavi: müzik açık
musicIcon.down = function (x, y, obj) {
musicOn = !musicOn;
if (musicOn) {
LK.playMusic('Backgroundmusic');
musicIcon.tint = 0x00ccff;
} else {
LK.stopMusic();
musicIcon.tint = 0x888888;
}
};
LK.gui.top.addChild(musicIcon);
// --- How to play? button and popup ---
var howToPlayBtn = new Text2('How to play?', {
size: 54,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
howToPlayBtn.anchor.set(0.5, 0);
howToPlayBtn.x = musicIcon.x;
howToPlayBtn.y = musicIcon.y + musicIcon.height + 18;
howToPlayBtn.interactive = true;
howToPlayBtn.buttonMode = true;
var howToPlayPopup = null;
howToPlayBtn.down = function (x, y, obj) {
if (howToPlayPopup) {
howToPlayPopup.destroy();
howToPlayPopup = null;
return;
}
// Create popup container
howToPlayPopup = new Container();
// Background
// Dynamically size the background to fit the content
var popupContentWidth = 1200;
var popupContentHeight = 900;
// Calculate content bounds (title + info + closeBtn)
var titleHeight = 120;
var infoHeight = 480;
var closeBtnHeight = 100;
var verticalPadding = 120;
popupContentHeight = titleHeight + infoHeight + closeBtnHeight + verticalPadding;
// Increase background height by 30%
popupContentHeight = Math.round(popupContentHeight * 1.3);
popupContentWidth = 1200;
var popupBg = LK.getAsset('hpBarBg', {
width: popupContentWidth,
height: popupContentHeight,
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
tint: 0x222222,
alpha: 0.98
});
howToPlayPopup.addChild(popupBg);
// Title
var title = new Text2('How to Play', {
size: 90,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
title.anchor.set(0.5, 0);
title.x = GAME_WIDTH / 2;
title.y = GAME_HEIGHT / 2 - popupContentHeight / 2 + 40;
howToPlayPopup.addChild(title);
// Instructions
var info = new Text2("Defend your base and defeat the enemy!\n\n" + "- Drag the slingshot to launch stones at enemies and the enemy base.\n" + "- Tap the bottom left to spawn your soldiers (max 6).\n" + "- Your soldiers will automatically move and attack.\n" + "- Upgrade your base and soldiers using your score points.\n" + "- Defeat all enemy soldiers and destroy the enemy base to win the level.\n" + "- If your base is destroyed, you lose!\n\n" + "Good luck, Commander!", {
size: 54,
fill: "#fff",
wordWrap: true,
wordWrapWidth: 1100,
align: "left",
shadow: true,
shadowColor: "#222",
shadowBlur: 6,
shadowOffsetX: 2,
shadowOffsetY: 2
});
info.anchor.set(0.5, 0);
info.x = GAME_WIDTH / 2;
info.y = title.y + title.height + 40;
howToPlayPopup.addChild(info);
// Close button
var closeBtn = new Text2('Close', {
size: 60,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
closeBtn.anchor.set(0.5, 0);
// Place close button at the bottom center of the background
closeBtn.x = GAME_WIDTH / 2;
closeBtn.y = GAME_HEIGHT / 2 + popupContentHeight / 2 - closeBtn.height - 40;
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (howToPlayPopup) {
howToPlayPopup.destroy();
howToPlayPopup = null;
}
};
howToPlayPopup.addChild(closeBtn);
game.addChild(howToPlayPopup);
};
LK.gui.top.addChild(howToPlayBtn);
var upgradeStartY = resetBtn.y + resetBtn.height + 20; // Reset butonunun hemen altına hizala
var upgradeLeftX = 0; // Tam sol kenara hizalı (platform menüsüne çakışmaz, 0'dan başlat)
// Upgrade feature buttons are hidden from the main screen UI as requested.
// Patch fireStone to use upgradeable speed
var origFireStone = _fireStone;
_fireStone = function fireStone(fromX, fromY, toX, toY) {
var s = new Stone();
s.x = fromX;
s.y = fromY;
var dx = fromX - toX;
var dy = fromY - toY;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = _fireStone.stoneSpeed || 32;
s.vx = dx / dist * speed;
s.vy = dy / dist * speed;
// Patch damage if upgraded
if (typeof Stone.prototype.damage === "number") s.damage = Stone.prototype.damage;
stones.push(s);
game.addChild(s);
};
// Start background music by default
LK.playMusic('Backgroundmusic');
// Add bases
anaBase = new AnaBase();
anaBase.x = BASE_OFFSET_X;
anaBase.y = GROUND_Y;
game.addChild(anaBase);
enemyBase = new EnemyBase();
enemyBase.x = ENEMY_BASE_X;
enemyBase.y = ENEMY_BASE_Y;
game.addChild(enemyBase);
// Add slingshot
slingshot = new Slingshot();
slingshot.x = SLING_X;
slingshot.y = SLING_Y;
game.addChild(slingshot);
// --- Store button and popup ---
var storeBtn = new Text2('Store', {
size: 84,
// 70 (resetBtn) * 1.2 = 84
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
storeBtn.anchor.set(0.5, 1);
// Place 3 lines (approx 3x 60px) above slingshot
storeBtn.x = slingshot.x;
storeBtn.y = slingshot.y - 236 - 60 * 3; // slingshot.height + 3 lines above
storeBtn.interactive = true;
storeBtn.buttonMode = true;
var storePopup = null;
storeBtn.down = function (x, y, obj) {
if (storePopup) {
storePopup.destroy();
storePopup = null;
return;
}
// Create popup container
storePopup = new Container();
// Background
var popupContentWidth = 1200 * 0.9;
var popupContentHeight = 900 * 0.9;
var titleHeight = 120 * 0.9;
var btnHeight = 80 * 0.9;
var btnSpacing = 24; // vertical space between buttons
var infoHeight = (btnHeight + btnSpacing) * upgradeFeatures.length;
var closeBtnHeight = 100 * 0.9;
var verticalPadding = 120 * 0.9;
popupContentHeight = titleHeight + infoHeight + closeBtnHeight + verticalPadding;
popupContentHeight = Math.round(popupContentHeight * 1.2);
var popupBg = LK.getAsset('hpBarBg', {
width: popupContentWidth,
height: popupContentHeight,
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
tint: 0x222222,
alpha: 0.98
});
storePopup.addChild(popupBg);
// Title
var title = new Text2('Store', {
size: 108 * 0.9 * 0.95 * 0.95 * 0.95,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
title.anchor.set(0.5, 0);
title.x = GAME_WIDTH / 2;
title.y = GAME_HEIGHT / 2 - popupContentHeight / 2 + 40 * 0.9;
storePopup.addChild(title);
// Upgrade buttons (centered, evenly spaced)
var startY = title.y + title.height + 40 * 0.9;
var btnWidth = popupContentWidth * 0.82;
for (var i = 0; i < upgradeFeatures.length; i++) {
(function (idx) {
var upg = upgradeFeatures[idx];
var btnLevel = typeof upgradesLevel[idx] === "number" ? upgradesLevel[idx] : 0;
var btnFontSize = 84 * 0.9 * 0.95 * 0.95 * 0.95;
var btnWordWrap = false;
var btnWordWrapWidth = btnWidth;
if (upg.name.indexOf("Faster Enemy Spawn") !== -1) {
btnFontSize = btnFontSize * 0.75; // Further reduce font size to fit panel
btnWordWrap = false; // Prevent line wrapping
btnWordWrapWidth = btnWidth; // Use full width, but no wrap
}
var btn = new Text2("Lv. " + btnLevel + " " + upg.name + " (" + upg.cost + ")", {
size: btnFontSize,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2,
wordWrap: btnWordWrap,
wordWrapWidth: btnWordWrapWidth,
align: "center"
});
btn.anchor.set(0.5, 0);
btn.x = GAME_WIDTH / 2;
btn.y = startY + idx * (btnHeight + btnSpacing);
btn.interactive = true;
btn.buttonMode = true;
btn.down = function (x, y, obj) {
if (score >= upg.cost) {
score -= upg.cost;
upg.apply();
upgradesLevel[idx] = (upgradesLevel[idx] || 0) + 1;
upgradesPurchased[idx] = 1;
upg.cost = upg.cost * 2;
btn.setText("Lv. " + upgradesLevel[idx] + " " + upg.name + " (" + upg.cost + ")");
if (upgradeButtons[idx]) {
upgradeButtons[idx].setText("Lv. " + upgradesLevel[idx] + " " + upg.name + " (" + upg.cost + ")");
}
showUpgradeMsg(upg.name + " level " + upgradesLevel[idx] + "!");
scoreTxt.setText('Score: ' + score);
storage.score = score;
} else {
showUpgradeMsg("Not enough points!");
}
};
storePopup.addChild(btn);
})(i);
}
// Close button
var closeBtn = new Text2('Close', {
size: 60,
fill: "#fff",
shadow: true,
shadowColor: "#222",
shadowBlur: 8,
shadowOffsetX: 2,
shadowOffsetY: 2
});
closeBtn.anchor.set(0.5, 0);
closeBtn.x = GAME_WIDTH / 2;
closeBtn.y = GAME_HEIGHT / 2 + popupContentHeight / 2 - closeBtn.height - 40 * 0.9;
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (storePopup) {
storePopup.destroy();
storePopup = null;
}
};
storePopup.addChild(closeBtn);
game.addChild(storePopup);
};
game.addChild(storeBtn);
// Helper: spawn player soldier
function spawnPlayerSoldier() {
var s = new PlayerSoldier();
s.hp = playerSoldierStats.hp;
s.maxHp = playerSoldierStats.hp;
s.atk = playerSoldierStats.atk;
s.speed = playerSoldierStats.speed;
s.x = anaBase.x + 100;
s.y = GROUND_Y + 10;
playerSoldiers.push(s);
game.addChild(s);
}
// Helper: spawn enemy soldier
function spawnEnemySoldier() {
var s;
// 1-4: StoneThrower, 5-10: Gunner, 11-15: Car, 16-20: Tank, 21-30: Jet
if (level >= 1 && level <= 4) {
s = new EnemyStoneThrower();
} else if (level >= 5 && level <= 10) {
s = new EnemyGunner();
} else if (level >= 11 && level <= 15) {
s = new EnemyCar();
} else if (level >= 16 && level <= 20) {
s = new EnemyTank();
} else if (level >= 21 && level < 50) {
// Randomly pick one of the enemy types for levels 21-49
var enemyTypes = [EnemyStoneThrower, EnemyGunner, EnemyCar, EnemyTank, EnemyJet];
var idx = Math.floor(Math.random() * enemyTypes.length);
s = new enemyTypes[idx]();
} else if (level === 50) {
// Final level: only Jet for extra challenge
s = new EnemyJet();
} else {
s = new EnemyStoneThrower();
}
s.x = enemyBase.x - 100;
s.y = GROUND_Y + 10;
enemySoldiers.push(s);
game.addChild(s);
}
// Helper: fire stone
function _fireStone(fromX, fromY, toX, toY) {
var s = new Stone();
s.x = fromX;
s.y = fromY;
// Atış yönünü tersine çevir: sapanı geriye çek, taş ileri fırlasın
var dx = fromX - toX;
var dy = fromY - toY;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 32; // Daha yavaş gitmesi için azaltıldı
s.vx = dx / dist * speed;
s.vy = dy / dist * speed;
stones.push(s);
game.addChild(s);
}
// Helper: show upgrade message
function showUpgradeMsg(msg) {
upgradeTxt.setText(msg);
tween(upgradeTxt, {
alpha: 1
}, {
duration: 0
});
tween(upgradeTxt, {
alpha: 0
}, {
duration: 1200,
easing: tween.easeOut
});
}
// Touch/drag logic for slingshot
game.down = function (x, y, obj) {
// Only allow drag if touch is near slingshot
if (Math.abs(x - slingshot.x) < 120 && Math.abs(y - slingshot.y) < 160) {
isDraggingSling = true;
dragStart.x = x;
dragStart.y = y;
dragEnd.x = x;
dragEnd.y = y;
}
};
game.move = function (x, y, obj) {
if (isDraggingSling) {
dragEnd.x = x;
dragEnd.y = y;
}
};
game.up = function (x, y, obj) {
if (isDraggingSling) {
// Fire stone if drag is long enough
var dx = dragEnd.x - slingshot.x;
var dy = dragEnd.y - slingshot.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 80 && stones.length < 2) {
_fireStone(slingshot.x, slingshot.y - 60, dragEnd.x, dragEnd.y);
// fireStone fonksiyonu artık ters vektörle çalışıyor
}
}
isDraggingSling = false;
};
// Tap to spawn player soldier (bottom left, not on slingshot)
game.on('down', function (x, y, obj) {
if (x < 300 && y > GROUND_Y + 60) {
if (playerSoldiers.length < 6) {
spawnPlayerSoldier();
}
}
});
// Upgrade logic (tap bottom right)
game.on('down', function (x, y, obj) {
if (x > GAME_WIDTH - 300 && y > GROUND_Y + 60) {
if (upgradePoints > 0) {
// Cycle upgrades: base hp, soldier hp, soldier atk, soldier speed
var upg = (score + level) % 4;
if (upg === 0) {
anaBaseStats.hp += 20;
anaBase.maxHp = anaBaseStats.hp;
anaBase.hp = anaBaseStats.hp;
showUpgradeMsg("AnaBase HP +20");
} else if (upg === 1) {
playerSoldierStats.hp += 6;
showUpgradeMsg("Soldier HP +6");
} else if (upg === 2) {
playerSoldierStats.atk += 2;
showUpgradeMsg("Soldier Atk +2");
} else {
playerSoldierStats.speed += 0.5;
showUpgradeMsg("Soldier Speed +0.5");
}
upgradePoints--;
}
}
});
// Main update loop
game.update = function () {
// Update UI
levelTxt.setText('Level: ' + level);
scoreTxt.setText('Score: ' + score);
// Update health bars
anaBase.hpBar.set(anaBase.hp / anaBase.maxHp);
enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp);
// Draw slingshot pulled band and stone visual
if (isDraggingSling) {
// Remove previous drag visuals if any
if (slingshot.dragStone) {
slingshot.dragStone.destroy();
slingshot.dragStone = null;
}
if (slingshot.bandLeft) {
slingshot.bandLeft.destroy();
slingshot.bandLeft = null;
}
if (slingshot.bandRight) {
slingshot.bandRight.destroy();
slingshot.bandRight = null;
}
// Calculate band anchor points (left/right of slingshot top)
var slingTopX = slingshot.x;
var slingTopY = slingshot.y - 110;
var bandOffset = 22;
var leftX = slingTopX - bandOffset;
var rightX = slingTopX + bandOffset;
var bandY = slingTopY + 10;
// Place a thin rectangle as band (left)
slingshot.bandLeft = LK.getAsset('hpBarFg', {
width: Math.max(8, Math.sqrt((dragEnd.x - leftX) * (dragEnd.x - leftX) + (dragEnd.y - bandY) * (dragEnd.y - bandY))),
height: 8,
anchorX: 0,
anchorY: 0.5,
x: leftX,
y: bandY,
rotation: Math.atan2(dragEnd.y - bandY, dragEnd.x - leftX)
});
game.addChild(slingshot.bandLeft);
// Place a thin rectangle as band (right)
slingshot.bandRight = LK.getAsset('hpBarFg', {
width: Math.max(8, Math.sqrt((dragEnd.x - rightX) * (dragEnd.x - rightX) + (dragEnd.y - bandY) * (dragEnd.y - bandY))),
height: 8,
anchorX: 0,
anchorY: 0.5,
x: rightX,
y: bandY,
rotation: Math.atan2(dragEnd.y - bandY, dragEnd.x - rightX)
});
game.addChild(slingshot.bandRight);
// Place the stone at dragEnd
slingshot.dragStone = LK.getAsset('stone', {
anchorX: 0.5,
anchorY: 0.5,
x: dragEnd.x,
y: dragEnd.y
});
game.addChild(slingshot.dragStone);
} else {
// Remove drag visuals if not dragging
if (slingshot.dragStone) {
slingshot.dragStone.destroy();
slingshot.dragStone = null;
}
if (slingshot.bandLeft) {
slingshot.bandLeft.destroy();
slingshot.bandLeft = null;
}
if (slingshot.bandRight) {
slingshot.bandRight.destroy();
slingshot.bandRight = null;
}
}
// Spawn player soldiers automatically
spawnTimers.player++;
if (spawnTimers.player >= playerSpawnInterval) {
if (playerSoldiers.length < 6) {
spawnPlayerSoldier();
}
spawnTimers.player = 0;
}
// Spawn enemy soldiers automatically
spawnTimers.enemy++;
if (spawnTimers.enemy >= enemySpawnInterval) {
if (enemySoldiers.length < 6) {
spawnEnemySoldier();
}
spawnTimers.enemy = 0;
}
// --- Freeze logic: check if firing phase is active ---
freezeAllSoldiers = isFiringPhase();
// Update player soldiers
for (var i = playerSoldiers.length - 1; i >= 0; i--) {
var s = playerSoldiers[i];
// --- Freeze all player soldiers if firing phase is active ---
if (freezeAllSoldiers) {
// No movement, no firing, no attacking base, but still allow dying from bullets
continue;
}
// Asker dondurma: eğer bir düşmanla çarpışıyorsa hareket etmesin
var frozen = false;
for (var j = enemySoldiers.length - 1; j >= 0; j--) {
var e = enemySoldiers[j];
if (Math.abs(s.x - e.x) < 80 && Math.abs(s.y - e.y) < 60) {
// Fight!
s.hp -= e.atk * 0.03;
e.hp -= s.atk * 0.03;
s.hpBar.set(s.hp / s.maxHp);
e.hpBar.set(e.hp / e.maxHp);
frozen = true;
if (e.hp <= 0) {
score += 10;
enemySoldiers.splice(j, 1);
e.destroy();
}
if (s.hp <= 0) {
playerSoldiers.splice(i, 1);
s.destroy();
break;
}
// Eğer ikisi de hayattaysa, dondurulmuş kalmaya devam etsin
if (s.hp > 0 && e.hp > 0) {
frozen = true;
}
}
}
// Hareketi engelle: Eğer çarpışıyorsa update çağrılmasın, çarpışmıyorsa hareket etsin
if (!frozen) {
// Çarpışma kontrolü: Önümüzde bir düşman var mı?
var blocked = false;
// Önce kendi askerlerimizi kontrol et, öndekiyle çakışıyorsak ilerleme
for (var j = 0; j < playerSoldiers.length; j++) {
var s2 = playerSoldiers[j];
if (s2 === s) continue;
if (Math.abs(s.y - s2.y) < 60 && s2.x > s.x && s2.x - s.x < 80 && s2.x - s.x > 0 // 80px mesafeden yakınsa
) {
blocked = true;
break;
}
}
// Sonra düşman askerlerini kontrol et
if (!blocked) {
for (var j = 0; j < enemySoldiers.length; j++) {
var e = enemySoldiers[j];
if (e === s) continue;
// Sadece ileriye doğru olan ve çakışan askerleri engelle
if (Math.abs(s.y - e.y) < 60 && e.x > s.x &&
// Sadece önündeki düşman
e.x - s.x < 80 && e.x - s.x > 0 // 80px mesafeden yakınsa
) {
blocked = true;
break;
}
}
}
if (!blocked) {
s.update();
// Clamp to not go past enemy base
if (s.x > enemyBase.x - 120) s.x = enemyBase.x - 120;
// --- Player Firing Logic ---
if (!s.fireTimer) s.fireTimer = 0;
s.fireTimer++;
var fireInterval = 60;
if (s.fireTimer >= fireInterval) {
// En yakın düşman askeri bul, yoksa enemyBase'e ateş et
var target = null;
var minDist = 99999;
for (var es = 0; es < enemySoldiers.length; es++) {
var e = enemySoldiers[es];
var dx = e.x - s.x;
var dy = e.y - s.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
target = e;
}
}
if (!target) {
target = enemyBase;
}
// Mermi oluştur ve ateşle
var b = new PlayerBullet();
b.x = s.x;
b.y = s.y - 70 - GAME_HEIGHT * 0.05; // %5 yukarı kaldırıldı
// Hedefe yönel
var tx = target.x;
var ty = target.y;
var dx = tx - b.x;
var dy = ty - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
b.vx = dx / dist * 22;
b.vy = dy / dist * 22;
b.damage = s.atk || 8;
playerBullets.push(b);
game.addChild(b);
s.fireTimer = 0;
}
}
}
// If at enemy base, attack base
if (s.lastAtEnemyBase === undefined) s.lastAtEnemyBase = false;
var atEnemyBase = Math.abs(s.x - enemyBase.x) < 120;
if (!s.lastAtEnemyBase && atEnemyBase) {
// Just arrived at enemy base
s.attackedBase = false;
}
if (!s.attackedBase && atEnemyBase) {
enemyBase.hp -= s.atk * 0.15;
if (enemyBase.hp < 0) enemyBase.hp = 0;
s.attackedBase = true;
}
s.lastAtEnemyBase = atEnemyBase;
}
// Update enemy soldiers
for (var i = enemySoldiers.length - 1; i >= 0; i--) {
var e = enemySoldiers[i];
// --- Freeze all enemy soldiers if firing phase is active ---
if (freezeAllSoldiers) {
// No movement, no firing, no attacking base, but still allow dying from bullets
continue;
}
// Asker dondurma: eğer bir oyuncu askeriyle çarpışıyorsa hareket etmesin
var frozen = false;
for (var j = playerSoldiers.length - 1; j >= 0; j--) {
var s = playerSoldiers[j];
if (Math.abs(e.x - s.x) < 80 && Math.abs(e.y - s.y) < 60) {
// Fight!
e.hp -= s.atk * 0.03;
s.hp -= e.atk * 0.03;
e.hpBar.set(e.hp / e.maxHp);
s.hpBar.set(s.hp / s.maxHp);
frozen = true;
if (s.hp <= 0) {
playerSoldiers.splice(j, 1);
s.destroy();
}
if (e.hp <= 0) {
score += 10;
enemySoldiers.splice(i, 1);
e.destroy();
break;
}
// Eğer ikisi de hayattaysa, dondurulmuş kalmaya devam etsin
if (e.hp > 0 && s.hp > 0) {
frozen = true;
}
}
}
// Hareketi engelle: Eğer çarpışıyorsa update çağrılmasın, çarpışmıyorsa hareket etsin
if (!frozen) {
// Çarpışma kontrolü: Önümüzde bir oyuncu askeri var mı?
var blocked = false;
// Önce kendi düşman askerlerini kontrol et, öndekiyle çakışıyorsak ilerleme
for (var j = 0; j < enemySoldiers.length; j++) {
var e2 = enemySoldiers[j];
if (e2 === e) continue;
if (Math.abs(e.y - e2.y) < 60 && e2.x < e.x && e.x - e2.x < 80 && e.x - e2.x > 0 // 80px mesafeden yakınsa
) {
blocked = true;
break;
}
}
// Sonra oyuncu askerlerini kontrol et
if (!blocked) {
for (var j = 0; j < playerSoldiers.length; j++) {
var s = playerSoldiers[j];
if (Math.abs(e.y - s.y) < 60 && s.x > e.x && s.x - e.x < 80 && s.x - e.x > 0 // 80px mesafeden yakınsa
) {
blocked = true;
break;
}
}
}
if (!blocked) {
e.update();
// Clamp to not go past anaBase
if (e.x < anaBase.x + 120) e.x = anaBase.x + 120;
}
// --- Enemy Firing Logic ---
if (!e.fireTimer) e.fireTimer = 0;
e.fireTimer++;
var fireInterval = 90; // default
var BulletClass = null;
var bulletSpeed = 0;
var bulletDamage = 0;
var bulletYOffset = 0;
if (e.constructor === EnemyStoneThrower) {
fireInterval = 120;
BulletClass = EnemyStone;
bulletSpeed = 12;
bulletDamage = 10;
bulletYOffset = -60;
} else if (e.constructor === EnemyGunner) {
fireInterval = 60;
BulletClass = EnemyBullet;
bulletSpeed = 18;
bulletDamage = 14;
bulletYOffset = -70;
} else if (e.constructor === EnemyCar) {
fireInterval = 80;
BulletClass = EnemyCarBullet;
bulletSpeed = 20;
bulletDamage = 20;
bulletYOffset = -40;
} else if (e.constructor === EnemyTank) {
fireInterval = 100;
BulletClass = EnemyTankShell;
bulletSpeed = 14;
bulletDamage = 40;
bulletYOffset = -50;
} else if (e.constructor === EnemyJet) {
fireInterval = 70;
BulletClass = EnemyJetMissile;
bulletSpeed = 28;
bulletDamage = 60;
bulletYOffset = -20;
}
if (BulletClass && e.fireTimer >= fireInterval) {
// Find closest player soldier, else aim at anaBase
var target = null;
var minDist = 99999;
for (var ps = 0; ps < playerSoldiers.length; ps++) {
var p = playerSoldiers[ps];
var dx = p.x - e.x;
var dy = p.y - e.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dist;
target = p;
}
}
if (!target) {
target = anaBase;
}
// Fire bullet
var b = new BulletClass();
b.x = e.x;
b.y = e.y + bulletYOffset;
// Calculate direction
var tx = target.x;
var ty = target.y;
var dx = tx - b.x;
var dy = ty - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
b.vx = dx / dist * bulletSpeed;
b.vy = dy / dist * bulletSpeed;
b.damage = bulletDamage;
enemyBullets.push(b);
game.addChild(b);
e.fireTimer = 0;
}
}
// If at anaBase, attack base
if (e.lastAtAnaBase === undefined) e.lastAtAnaBase = false;
var atAnaBase = Math.abs(e.x - anaBase.x) < 120;
if (!e.lastAtAnaBase && atAnaBase) {
// Just arrived at ana base
e.attackedBase = false;
}
if (!e.attackedBase && atAnaBase) {
anaBase.hp -= e.atk * 0.05; // Her asker %5 oranında base canı azaltır
if (anaBase.hp < 0) anaBase.hp = 0;
e.attackedBase = true;
}
e.lastAtAnaBase = atAnaBase;
}
// Update stones (slingshot projectiles)
for (var i = stones.length - 1; i >= 0; i--) {
var st = stones[i];
st.update();
// Remove if out of bounds
if (st.x < 0 || st.x > GAME_WIDTH || st.y < 0 || st.y > GAME_HEIGHT) {
stones.splice(i, 1);
st.destroy();
continue;
}
// Hit enemy soldiers
var hit = false;
for (var j = enemySoldiers.length - 1; j >= 0; j--) {
var e = enemySoldiers[j];
if (st.intersects(e)) {
e.hp -= st.damage;
e.hpBar.set(e.hp / e.maxHp);
// Fire effect at collision point
var fireFx = new FireEffect();
fireFx.x = st.x;
fireFx.y = st.y;
game.addChild(fireFx);
if (e.hp <= 0) {
score += 10;
enemySoldiers.splice(j, 1);
e.destroy();
}
hit = true;
break;
}
}
// Hit enemy base
if (!hit && Math.abs(st.x - enemyBase.x) < 120 && Math.abs(st.y - enemyBase.y) < 120) {
enemyBase.hp -= st.damage;
if (enemyBase.hp < 0) enemyBase.hp = 0;
// Fire effect at base hit
var fireFx = new FireEffect();
fireFx.x = st.x;
fireFx.y = st.y;
game.addChild(fireFx);
hit = true;
}
if (hit) {
stones.splice(i, 1);
st.destroy();
}
}
// --- Enemy Bullets update ---
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
// Remove if out of bounds
if (b.x < 0 || b.x > GAME_WIDTH || b.y < 0 || b.y > GAME_HEIGHT) {
enemyBullets.splice(i, 1);
b.destroy();
continue;
}
// Hit player soldiers
var hit = false;
for (var j = playerSoldiers.length - 1; j >= 0; j--) {
var s = playerSoldiers[j];
if (b.intersects(s)) {
s.hp -= b.damage;
s.hpBar.set(s.hp / s.maxHp);
// Fire effect at collision point
var fireFx = new FireEffect();
fireFx.x = b.x;
fireFx.y = b.y;
game.addChild(fireFx);
if (s.hp <= 0) {
playerSoldiers.splice(j, 1);
s.destroy();
}
hit = true;
break;
}
}
// Hit anaBase
if (!hit && Math.abs(b.x - anaBase.x) < 120 && Math.abs(b.y - anaBase.y) < 120) {
anaBase.hp -= b.damage;
if (anaBase.hp < 0) anaBase.hp = 0;
// Fire effect at base hit
var fireFx = new FireEffect();
fireFx.x = b.x;
fireFx.y = b.y;
game.addChild(fireFx);
hit = true;
}
if (hit) {
enemyBullets.splice(i, 1);
b.destroy();
}
}
// --- Player Bullets update ---
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Remove if out of bounds
if (b.x < 0 || b.x > GAME_WIDTH || b.y < 0 || b.y > GAME_HEIGHT) {
playerBullets.splice(i, 1);
b.destroy();
continue;
}
// Hit enemy soldiers
var hit = false;
for (var j = enemySoldiers.length - 1; j >= 0; j--) {
var e = enemySoldiers[j];
if (b.intersects(e)) {
e.hp -= b.damage;
e.hpBar.set(e.hp / e.maxHp);
// Fire effect at collision point
var fireFx = new FireEffect();
fireFx.x = b.x;
fireFx.y = b.y;
game.addChild(fireFx);
if (e.hp <= 0) {
score += 10;
enemySoldiers.splice(j, 1);
e.destroy();
}
hit = true;
break;
}
}
// Hit enemy base
if (!hit && Math.abs(b.x - enemyBase.x) < 120 && Math.abs(b.y - enemyBase.y) < 120) {
enemyBase.hp -= b.damage;
if (enemyBase.hp < 0) enemyBase.hp = 0;
// Fire effect at base hit
var fireFx = new FireEffect();
fireFx.x = b.x;
fireFx.y = b.y;
game.addChild(fireFx);
hit = true;
}
if (hit) {
playerBullets.splice(i, 1);
b.destroy();
}
}
// Check lose condition
if (anaBase.hp <= 0) {
// Flash and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
// --- FULL RESET: clear all arrays and state ---
// Remove all player soldiers
for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy();
for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy();
for (var i = 0; i < stones.length; i++) stones[i].destroy();
for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
playerSoldiers = [];
enemySoldiers = [];
stones = [];
enemyBullets = [];
playerBullets = [];
// Reset stats and progress
level = 1;
score = 0;
upgradePoints = 0;
enemyBaseStats.hp = 100;
anaBaseStats.hp = 130;
playerSoldierStats.hp = 20;
playerSoldierStats.atk = 9.6;
playerSoldierStats.speed = 3;
enemySoldierStats.hp = 20;
enemySoldierStats.atk = 8;
enemySoldierStats.speed = 3;
enemySpawnInterval = 120;
playerSpawnInterval = 120;
// Reset bases
anaBase.hp = anaBaseStats.hp;
anaBase.maxHp = anaBaseStats.hp;
enemyBase.hp = enemyBaseStats.hp;
enemyBase.maxHp = enemyBaseStats.hp;
// Save progress
storage.level = level;
storage.score = score;
storage.upgradePoints = upgradePoints;
// Update UI immediately
levelTxt.setText('Level: ' + level);
scoreTxt.setText('Score: ' + score);
anaBase.hpBar.set(anaBase.hp / anaBase.maxHp);
enemyBase.hpBar.set(enemyBase.hp / enemyBase.maxHp);
showUpgradeMsg("Game Reset!");
return;
}
// Check win/level up
if (enemyBase.lastWasDead === undefined) enemyBase.lastWasDead = false;
var enemyBaseIsDead = enemyBase.hp <= 0;
if (!enemyBase.lastWasDead && enemyBaseIsDead) {
level++;
if (level > MAX_LEVEL) {
LK.showYouWin();
return;
}
// Increase difficulty
enemyBaseStats.hp = Math.round(enemyBaseStats.hp * 1.3);
enemySoldierStats.hp = Math.round(enemySoldierStats.hp * 1.3);
enemySoldierStats.atk = Math.round(enemySoldierStats.atk * 1.3);
enemySoldierStats.speed = Math.round(enemySoldierStats.speed * 1.3 * 100) / 100;
enemySpawnInterval = Math.max(60, enemySpawnInterval - 4);
playerSpawnInterval = Math.max(60, playerSpawnInterval - 2);
upgradePoints++;
showUpgradeMsg("Level " + level + "! Upgrade Point +1");
// Reset
enemyBase.hp = enemyBaseStats.hp;
enemyBase.maxHp = enemyBaseStats.hp;
anaBase.hp = anaBaseStats.hp;
anaBase.maxHp = anaBaseStats.hp;
for (var i = 0; i < playerSoldiers.length; i++) playerSoldiers[i].destroy();
for (var i = 0; i < enemySoldiers.length; i++) enemySoldiers[i].destroy();
for (var i = 0; i < stones.length; i++) stones[i].destroy();
playerSoldiers = [];
enemySoldiers = [];
stones = [];
}
enemyBase.lastWasDead = enemyBaseIsDead;
// Save progress
storage.level = level;
storage.score = score;
storage.upgradePoints = upgradePoints;
};
Yukarda gece gökyüzü, aşağıda çölün sadeliği, gerçekçi, uzaktan görünüm, yazısız, background, yüksek boyutta. In-Game asset. High contrast. No shadows
Askeri üs - gerçekçi, yazısız, yandan görünüm. In-Game asset. 2d. High contrast. No shadows
Ateş, gerçekçi, yazısız. In-Game asset. 2d. High contrast. No shadows
Mermi, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Taş çağında asker, yazısız, gerçekçi, yandan görünüm. In-Game asset. High contrast. No shadows
Komando, yazısız, gerçekçi, yandan görünüm. In-Game asset. 2d. High contrast. No shadows
Komando, yazısız, gerçekçi, yandan görünüm, bütün vücudu görünsün. In-Game asset. High contrast. No shadows
Zırhlı savaş arabası, gerçekçi, yazısız, yandan görümüm. In-Game asset. High contrast. No shadows
Sapan, yandan görünüm, gerçekçi, yazısız. In-Game asset. High contrast. No shadows
Savaş uçağı, gerçekçi, yazısız, yandan görünüm. In-Game asset. High contrast. No shadows
Füze, gerçekçi, yandan görünüm, yazısız. In-Game asset. High contrast. No shadows
Savaş tankı, gerçekçi, yandan görünüm, yazısız. In-Game asset. High contrast. No shadows
Bomba, gerçekçi, yandan görünüm, yazısız. In-Game asset. High contrast. No shadows
Music, icon, yazısız, gerçekçi. In-Game asset. High contrast. No shadows