/****
* 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