/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currency: 0,
unlockedSkins: ["default"],
selectedSkin: "default",
upgrades: {
fireRate: 0,
speed: 0,
health: 0
}
});
/****
* Classes
****/
// CoinDrop: Collectible coin that moves down and can be picked up by the player
var CoinDrop = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
self.width = asset.width;
self.height = asset.height;
self.speed = 7;
self.lastWasIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Base Class
var EnemyBase = Container.expand(function () {
var self = Container.call(this);
self.type = 'base';
self.scoreValue = 1;
self.health = 1;
self.shootCooldown = 0;
self.shootRate = 90;
self.speed = 4;
self.bulletSpeed = 12;
self.lastIntersecting = false;
self.lastY = 0;
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffff00, 400); // Explosion effect (yellow flash)
LK.setScore(LK.getScore() + self.scoreValue);
addCurrency(self.scoreValue);
showScorePopup(self.x, self.y, self.scoreValue);
// Spawn debris parts
for (var i = 0; i < 8; i++) {
var part = new EnemyPart();
part.x = self.x;
part.y = self.y;
game.addChild(part);
enemyParts.push(part);
}
// Only CoinEnemy drops a coin, so do not drop a coin here for base enemies
self.destroy();
return true;
}
return false;
};
self.shoot = function () {
if (self.shootCooldown > 0) return;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
// If this is a green enemy, make its bullets faster
if (self.type === 'green') {
bullet.speed = 14;
}
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
self.shootCooldown = self.shootRate;
};
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
};
return self;
});
// Red Attacker: moves straight, shoots at player
var EnemyRed = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'red';
self.scoreValue = 2;
self.health = 1;
self.shootRate = 80;
self.speed = 6;
self.asset = self.attachAsset('enemyRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
// Shoot if player is roughly aligned
if (Math.abs(self.x - player.x) < 80 && self.shootCooldown <= 0) {
self.shoot();
}
};
return self;
});
// Green Tank: slow, high health, shoots
var EnemyGreen = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'green';
self.scoreValue = 5;
self.health = 3; // reduced from 6 to 3
self.shootRate = 60;
self.speed = 3.5;
self.asset = self.attachAsset('enemyGreen', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
// Shoots more often
if (self.shootCooldown <= 0) {
self.shoot();
}
};
return self;
});
// Blue Speedster: zig-zags, no shooting
var EnemyBlue = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'blue';
self.scoreValue = 3;
self.health = 1;
self.shootRate = 9999;
self.speed = 8;
self.asset = self.attachAsset('enemyBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.zigzagDir = Math.random() > 0.5 ? 1 : -1;
self.zigzagSpeed = 7 + Math.random() * 3;
self.zigzagPhase = Math.random() * 100;
self.update = function () {
self.y += self.speed;
self.x += Math.sin((LK.ticks + self.zigzagPhase) / 18) * self.zigzagSpeed * self.zigzagDir;
};
return self;
});
// CoinEnemy: Enemies that carry a coin and drop it when destroyed
var CoinEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'coin';
self.scoreValue = 2;
self.health = 1;
self.shootRate = 120;
self.speed = 5;
self.asset = self.attachAsset('enemyRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
// Add a coin icon on top of the enemy
self.coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 1.2,
scaleX: 0.7,
scaleY: 0.7
});
// Override takeDamage to drop a coin
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffff00, 400); // Explosion effect (yellow flash)
LK.setScore(LK.getScore() + self.scoreValue);
showScorePopup(self.x, self.y, self.scoreValue);
// Spawn debris parts
for (var i = 0; i < 8; i++) {
var part = new EnemyPart();
part.x = self.x;
part.y = self.y;
game.addChild(part);
enemyParts.push(part);
}
// Drop a coin at this position, but only once
if (!self._coinDropped) {
var coin = new CoinDrop();
coin.x = self.x;
coin.y = self.y;
coinDrops.push(coin);
game.addChild(coin);
self._coinDropped = true;
}
self.destroy();
return true;
}
return false;
};
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
// EnemyPart: Debris piece for enemy explosion
var EnemyPart = Container.expand(function () {
var self = Container.call(this);
// Use a greenCube for debris, but only red and orange colors
var colors = [0xff4444, 0xff9900];
var color = colors[Math.floor(Math.random() * colors.length)];
var part = self.attachAsset('greenCube', {
anchorX: 0.5,
anchorY: 0.5
});
part.tint = color;
// Randomize size
var scale = 0.4 + Math.random() * 0.5;
part.scaleX = scale;
part.scaleY = scale;
self.width = part.width * scale;
self.height = part.height * scale;
// Set initial velocity
self.vx = (Math.random() - 0.5) * 32;
self.vy = (Math.random() - 0.5) * 32 - 8;
self.gravity = 2.2 + Math.random() * 0.8;
self.life = 36 + Math.floor(Math.random() * 18); // 0.6s
self._age = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += self.gravity;
self._age++;
// Fade out
part.alpha = Math.max(0, 1 - self._age / self.life);
if (self._age > self.life) {
self.destroy();
}
};
return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = -8 - (storage.upgrades && storage.upgrades.fireRate ? storage.upgrades.fireRate * 1 : 0); // Slowed down from -12 to -8
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Plane
var PlayerPlane = Container.expand(function () {
var self = Container.call(this);
// Attach player plane asset
self.skin = storage.selectedSkin || 'default';
self.plane = self.attachAsset('playerPlane', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.plane.width;
self.height = self.plane.height;
self.fireCooldown = 0;
self.baseFireRate = 30; // ticks between shots
self.baseSpeed = 32; // Increased from 23 for faster movement
self.baseHealth = 8; // Increased from 5 to 8 for more player lives
self.maxHealth = self.baseHealth + (storage.upgrades && storage.upgrades.health ? storage.upgrades.health : 0);
self.health = self.maxHealth;
self.updateSkin = function () {
// For future: swap asset based on skin
// For now, only color changes
if (self.skin === 'default') {
self.plane.tint = 0x888888;
} else if (self.skin === 'gold') {
self.plane.tint = 0xffd700;
} else if (self.skin === 'blue') {
self.plane.tint = 0x2a6edb;
}
};
self.shoot = function () {
if (self.fireCooldown > 0) return;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2 + 10;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('playerShoot').play();
self.fireCooldown = self.baseFireRate - (storage.upgrades && storage.upgrades.fireRate ? storage.upgrades.fireRate * 4 : 0);
if (self.fireCooldown < 8) self.fireCooldown = 8;
};
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('playerHit').play();
updateHealthBar();
if (self.health <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
};
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) self.health = self.maxHealth;
updateHealthBar();
};
self.update = function () {
if (self.fireCooldown > 0) self.fireCooldown--;
};
self.updateSkin();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundImage: 'spaceMoonBg'
});
/****
* Game Code
****/
// --- Global Variables ---
// Player plane (default skin: gray)
// Player bullet (yellow)
// Enemy: Red Attacker
// Enemy: Blue Speedster
// Enemy: Green Tank
// Enemy bullet (red)
// Health bar background
// Health bar foreground
// Coin icon
// Sounds
// Music
var player;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var coinDrops = [];
var enemyParts = [];
var spawnTimer = 0;
var spawnInterval = 60;
var dragNode = null;
var lastPlayerX = 0;
var lastPlayerY = 0;
var healthBarBg, healthBarFg;
var scoreTxt, coinTxt, coinIcon;
var currency = storage.currency || 0;
// Track how many enemies have been destroyed for health bonus
var enemiesDestroyedSinceLastHeal = 0;
// --- GUI Elements ---
// --- Start Screen State ---
var gameState = "start"; // "start", "playing", "market"
var startScreenContainer = new Container();
startScreenContainer.width = 2048;
startScreenContainer.height = 2732;
// --- Start Screen Background ---
// 2D sunny forest background
var startBg = LK.getAsset('forestBg', {
anchorX: 0,
anchorY: 0,
scaleX: 2048 / 600,
scaleY: 2732 / 40,
x: 0,
y: 0
});
startBg.width = 2048;
startBg.height = 2732;
startScreenContainer.addChild(startBg);
// --- Top Right Coin Display (for start/market screens) ---
var coinIconTL = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIconTL.x = 2048 - 160;
coinIconTL.y = 120;
startScreenContainer.addChild(coinIconTL);
var coinTxtTL = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxtTL.anchor.set(0, 0.5);
coinTxtTL.x = 2048 - 120;
coinTxtTL.y = 120;
startScreenContainer.addChild(coinTxtTL);
// --- Start Screen Title ---
var titleTxt = new Text2("Uçak Savaşı", {
size: 160,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 700;
startScreenContainer.addChild(titleTxt);
// --- Start Button ---
var startBtn = LK.getAsset('playerPlane', {
anchorX: 0.5,
anchorY: 0.5
});
startBtn.x = 2048 / 2;
startBtn.y = 1200;
startBtn.scaleX = 1.2;
startBtn.scaleY = 1.2;
startScreenContainer.addChild(startBtn);
var startBtnTxt = new Text2("Başla", {
size: 100,
fill: "#fff"
});
startBtnTxt.anchor.set(0.5, 0.5);
startBtnTxt.x = startBtn.x;
startBtnTxt.y = startBtn.y + 180;
startScreenContainer.addChild(startBtnTxt);
// --- Add start screen to game ---
game.addChild(startScreenContainer);
// --- Hide game GUI until game starts ---
function setGameGuiVisible(visible) {
if (typeof scoreTxt !== "undefined" && scoreTxt) scoreTxt.visible = visible;
if (typeof coinIconBL !== "undefined" && coinIconBL) coinIconBL.visible = visible;
if (typeof coinTxtBL !== "undefined" && coinTxtBL) coinTxtBL.visible = visible;
if (typeof coinIcon !== "undefined" && coinIcon) coinIcon.visible = visible;
if (typeof coinTxt !== "undefined" && coinTxt) coinTxt.visible = visible;
if (typeof healthBarBg !== "undefined" && healthBarBg) healthBarBg.visible = visible;
if (typeof healthBarFg !== "undefined" && healthBarFg) healthBarFg.visible = visible;
}
setGameGuiVisible(false);
// --- GUI for in-game (unchanged) ---
scoreTxt = new Text2('0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Coin GUI for bottom left
var coinIconBL = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIconBL.x = 80;
coinIconBL.y = -80;
LK.gui.bottomLeft.addChild(coinIconBL);
var coinTxtBL = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxtBL.anchor.set(0, 0.5);
coinTxtBL.x = 120;
coinTxtBL.y = -80;
LK.gui.bottomLeft.addChild(coinTxtBL);
// (Retain top right coin for reference, but main is bottom left)
coinIcon = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIcon.x = 0;
coinIcon.y = 0;
LK.gui.topRight.addChild(coinIcon);
coinTxt = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxt.anchor.set(0, 0.5);
coinTxt.x = 40;
coinTxt.y = 0;
LK.gui.topRight.addChild(coinTxt);
// Health bar
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0.5
});
healthBarBg.x = 200;
healthBarBg.y = 120;
LK.gui.top.addChild(healthBarBg);
healthBarFg = LK.getAsset('healthBarFg', {
anchorX: 0,
anchorY: 0.5
});
healthBarFg.x = 200;
healthBarFg.y = 120;
LK.gui.top.addChild(healthBarFg);
function updateHealthBar() {
var ratio = player.health / player.maxHealth;
if (ratio < 0) ratio = 0;
healthBarFg.width = 600 * ratio;
}
// --- Player Initialization ---
player = new PlayerPlane();
player.x = 2048 / 2;
player.y = 2732 - 350;
game.addChild(player);
// Set initial follow target to player's starting position
game._lastMoveX = player.x;
game._lastMoveY = player.y;
updateHealthBar();
// --- Show/Hide Screens ---
function showStartScreen() {
gameState = "start";
startScreenContainer.visible = true;
// marketScreenContainer.visible = false;//{3P} // Removed: marketScreenContainer is not defined
setGameGuiVisible(false);
player.visible = false;
coinTxtTL.setText(currency + '');
}
function startGame() {
gameState = "playing";
startScreenContainer.visible = false;
// marketScreenContainer.visible = false;//{3T} // Removed: marketScreenContainer is not defined
setGameGuiVisible(true);
player.visible = true;
// Reset player position and health
player.x = 2048 / 2;
player.y = 2732 - 350;
player.maxHealth = player.baseHealth + (storage.upgrades && storage.upgrades.health ? storage.upgrades.health : 0); // Ensure maxHealth is recalculated
player.health = player.maxHealth;
player.skin = storage.selectedSkin || "default";
player.updateSkin();
updateHealthBar();
// Clear all bullets, enemies, coins
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
playerBullets.splice(i, 1);
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
enemyBullets.splice(i, 1);
}
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = coinDrops.length - 1; i >= 0; i--) {
coinDrops[i].destroy();
coinDrops.splice(i, 1);
}
LK.setScore(0);
scoreTxt.setText("0");
coinTxtBL.setText(currency + '');
coinTxt.setText(currency + '');
}
// --- Start/Market Button Events ---
startBtn.interactive = true;
startBtn.on('down', function (x, y, obj) {
startGame();
});
// --- Start in start screen ---
showStartScreen();
// --- Utility Functions ---
function addCurrency(amount) {
currency += amount;
storage.currency = currency;
coinTxt.setText(currency + '');
if (typeof coinTxtBL !== "undefined") {
coinTxtBL.setText(currency + '');
}
LK.getSound('coin').play();
}
function showScorePopup(x, y, value) {
var popup = new Text2('+' + value, {
size: 70,
fill: "#fff"
});
popup.anchor.set(0.5, 0.5);
popup.x = x;
popup.y = y;
game.addChild(popup);
tween(popup, {
y: y - 100,
alpha: 0
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
popup.destroy();
}
});
}
// --- Enemy Spawning ---
function spawnEnemy() {
var r = Math.random();
var enemy;
// 15% chance to spawn a CoinEnemy (only these drop coins)
// Reduce green plane spawn rate: now only 10% (was 20%)
// Slightly increase blue plane spawn rate (from 40% to 45%)
if (r < 0.15) {
enemy = new CoinEnemy();
} else if (r < 0.45) {
enemy = new EnemyRed();
} else if (r < 0.9) {
enemy = new EnemyBlue();
} else {
enemy = new EnemyGreen();
}
enemy.x = 180 + Math.random() * (2048 - 360);
enemy.y = -enemy.height / 2;
enemies.push(enemy);
game.addChild(enemy);
}
// --- Game Move/Touch Controls ---
function handleMove(x, y, obj) {
if (gameState !== "playing") return;
// Always track last move position for smooth following
game._lastMoveX = x;
game._lastMoveY = y;
// No dragNode logic needed; player always follows cursor/touch position
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameState !== "playing") return;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
if (gameState !== "playing") return;
};
// --- Game Update Loop ---
game.update = function () {
if (gameState !== "playing") return;
// --- Player follows cursor/touch position smoothly ---
if (game._lastMoveX !== undefined && game._lastMoveY !== undefined) {
// Clamp to game area
var minX = player.width / 2 + 40;
var maxX = 2048 - player.width / 2 - 40;
var minY = 200 + player.height / 2;
var maxY = 2732 - player.height / 2 - 40;
var targetX = game._lastMoveX;
var targetY = game._lastMoveY;
if (targetX < minX) targetX = minX;
if (targetX > maxX) targetX = maxX;
if (targetY < minY) targetY = minY;
if (targetY > maxY) targetY = maxY;
// Move smoothly toward target (lerp)
var speed = player.baseSpeed + (storage.upgrades && storage.upgrades.speed ? storage.upgrades.speed : 0);
// Slightly increase lerp responsiveness for snappier feel
speed *= 1.08;
var dx = targetX - player.x;
var dy = targetY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > speed) {
player.x += dx / dist * speed;
player.y += dy / dist * speed;
} else {
player.x = targetX;
player.y = targetY;
}
}
// Player update
player.update();
// Player auto-shoot
// 2 bullets per second at 60FPS: 60/2 = 30 ticks interval
if (LK.ticks % 30 === 0) {
player.shoot();
}
// Player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Track bullet creation time if not already set
if (typeof b._createdAt === "undefined") {
b._createdAt = LK.ticks;
}
// Remove if off screen
if (b.y < -50 || typeof b._createdAt !== "undefined" && LK.ticks - b._createdAt >= 180) {
b.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
var killed = e.takeDamage(1);
b.destroy();
playerBullets.splice(i, 1);
if (killed) {
e.destroy();
enemies.splice(j, 1);
// --- Health bonus for every 3 destroyed enemies ---
enemiesDestroyedSinceLastHeal++;
if (enemiesDestroyedSinceLastHeal >= 3) {
enemiesDestroyedSinceLastHeal = 0;
if (player && typeof player.heal === "function") {
player.heal(1);
}
}
// --- End health bonus ---
}
break;
}
}
}
// Enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
if (b.y > 2732 + 50) {
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (b.intersects(player)) {
player.takeDamage(1);
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Coin drops: move, check pickup, remove if off screen
for (var i = coinDrops.length - 1; i >= 0; i--) {
var c = coinDrops[i];
c.update();
// Remove if off screen
if (c.y > 2732 + 80) {
c.destroy();
coinDrops.splice(i, 1);
continue;
}
// Check pickup by player (only on the frame it starts intersecting)
if (!c.lastWasIntersecting && c.intersects(player)) {
addCurrency(1);
c.destroy();
coinDrops.splice(i, 1);
continue;
}
c.lastWasIntersecting = c.intersects(player);
}
// Enemy debris parts
if (typeof enemyParts === "undefined") enemyParts = [];
for (var i = enemyParts.length - 1; i >= 0; i--) {
var part = enemyParts[i];
if (part.parent) part.update();
if (!part.parent) {
enemyParts.splice(i, 1);
}
}
// Enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Remove if off screen
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(i, 1);
// Decrease score by 2 for each enemy that leaves the screen without being destroyed
LK.setScore(LK.getScore() - 2);
scoreTxt.setText(LK.getScore());
// If score drops below zero, trigger game over
if (LK.getScore() < 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
continue;
}
// Check collision with player
if (e.intersects(player)) {
player.takeDamage(2);
LK.effects.flashObject(e, 0xff0000, 200);
e.destroy();
enemies.splice(i, 1);
continue;
}
}
// Enemy spawn logic: increase spawn rate over time
if (spawnTimer <= 0) {
spawnEnemy();
spawnInterval = 90 - Math.floor(LK.getScore() / 10) * 4; // Increased base interval from 60 to 90 for slower spawns
if (spawnInterval < 28) spawnInterval = 28; // Minimum interval increased from 18 to 28
spawnTimer = spawnInterval;
} else {
spawnTimer--;
}
// Update score
scoreTxt.setText(LK.getScore());
// Win condition: player wins at 200 score
if (LK.getScore() >= 200) {
LK.showYouWin();
return;
}
scoreTxt.setText(LK.getScore());
};
// --- Music ---
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// --- Game Over Handler (currency gain) ---
LK.on('gameover', function () {
// Add score to currency
addCurrency(LK.getScore());
// Save currency
storage.currency = currency;
coinTxt.setText(currency + '');
coinTxtBL.setText(currency + '');
coinTxtTL.setText(currency + '');
// After a short delay, show start screen again
LK.setTimeout(function () {
showStartScreen();
}, 1200);
// Reset upgrades/skins for next run if needed (not implemented here)
});
// --- YouWin Handler (not used, but for future) ---
LK.on('youwin', function () {
// Could reward bonus currency, etc.
});
// --- Prevent elements in top left 100x100
// (All GUI elements are placed away from top left, and player cannot move there) /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currency: 0,
unlockedSkins: ["default"],
selectedSkin: "default",
upgrades: {
fireRate: 0,
speed: 0,
health: 0
}
});
/****
* Classes
****/
// CoinDrop: Collectible coin that moves down and can be picked up by the player
var CoinDrop = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
self.width = asset.width;
self.height = asset.height;
self.speed = 7;
self.lastWasIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Base Class
var EnemyBase = Container.expand(function () {
var self = Container.call(this);
self.type = 'base';
self.scoreValue = 1;
self.health = 1;
self.shootCooldown = 0;
self.shootRate = 90;
self.speed = 4;
self.bulletSpeed = 12;
self.lastIntersecting = false;
self.lastY = 0;
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffff00, 400); // Explosion effect (yellow flash)
LK.setScore(LK.getScore() + self.scoreValue);
addCurrency(self.scoreValue);
showScorePopup(self.x, self.y, self.scoreValue);
// Spawn debris parts
for (var i = 0; i < 8; i++) {
var part = new EnemyPart();
part.x = self.x;
part.y = self.y;
game.addChild(part);
enemyParts.push(part);
}
// Only CoinEnemy drops a coin, so do not drop a coin here for base enemies
self.destroy();
return true;
}
return false;
};
self.shoot = function () {
if (self.shootCooldown > 0) return;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
// If this is a green enemy, make its bullets faster
if (self.type === 'green') {
bullet.speed = 14;
}
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
self.shootCooldown = self.shootRate;
};
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
};
return self;
});
// Red Attacker: moves straight, shoots at player
var EnemyRed = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'red';
self.scoreValue = 2;
self.health = 1;
self.shootRate = 80;
self.speed = 6;
self.asset = self.attachAsset('enemyRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
// Shoot if player is roughly aligned
if (Math.abs(self.x - player.x) < 80 && self.shootCooldown <= 0) {
self.shoot();
}
};
return self;
});
// Green Tank: slow, high health, shoots
var EnemyGreen = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'green';
self.scoreValue = 5;
self.health = 3; // reduced from 6 to 3
self.shootRate = 60;
self.speed = 3.5;
self.asset = self.attachAsset('enemyGreen', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
// Shoots more often
if (self.shootCooldown <= 0) {
self.shoot();
}
};
return self;
});
// Blue Speedster: zig-zags, no shooting
var EnemyBlue = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'blue';
self.scoreValue = 3;
self.health = 1;
self.shootRate = 9999;
self.speed = 8;
self.asset = self.attachAsset('enemyBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
self.zigzagDir = Math.random() > 0.5 ? 1 : -1;
self.zigzagSpeed = 7 + Math.random() * 3;
self.zigzagPhase = Math.random() * 100;
self.update = function () {
self.y += self.speed;
self.x += Math.sin((LK.ticks + self.zigzagPhase) / 18) * self.zigzagSpeed * self.zigzagDir;
};
return self;
});
// CoinEnemy: Enemies that carry a coin and drop it when destroyed
var CoinEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this);
self.type = 'coin';
self.scoreValue = 2;
self.health = 1;
self.shootRate = 120;
self.speed = 5;
self.asset = self.attachAsset('enemyRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.asset.width;
self.height = self.asset.height;
// Add a coin icon on top of the enemy
self.coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 1.2,
scaleX: 0.7,
scaleY: 0.7
});
// Override takeDamage to drop a coin
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffff00, 400); // Explosion effect (yellow flash)
LK.setScore(LK.getScore() + self.scoreValue);
showScorePopup(self.x, self.y, self.scoreValue);
// Spawn debris parts
for (var i = 0; i < 8; i++) {
var part = new EnemyPart();
part.x = self.x;
part.y = self.y;
game.addChild(part);
enemyParts.push(part);
}
// Drop a coin at this position, but only once
if (!self._coinDropped) {
var coin = new CoinDrop();
coin.x = self.x;
coin.y = self.y;
coinDrops.push(coin);
game.addChild(coin);
self._coinDropped = true;
}
self.destroy();
return true;
}
return false;
};
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) self.shootCooldown--;
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
// EnemyPart: Debris piece for enemy explosion
var EnemyPart = Container.expand(function () {
var self = Container.call(this);
// Use a greenCube for debris, but only red and orange colors
var colors = [0xff4444, 0xff9900];
var color = colors[Math.floor(Math.random() * colors.length)];
var part = self.attachAsset('greenCube', {
anchorX: 0.5,
anchorY: 0.5
});
part.tint = color;
// Randomize size
var scale = 0.4 + Math.random() * 0.5;
part.scaleX = scale;
part.scaleY = scale;
self.width = part.width * scale;
self.height = part.height * scale;
// Set initial velocity
self.vx = (Math.random() - 0.5) * 32;
self.vy = (Math.random() - 0.5) * 32 - 8;
self.gravity = 2.2 + Math.random() * 0.8;
self.life = 36 + Math.floor(Math.random() * 18); // 0.6s
self._age = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += self.gravity;
self._age++;
// Fade out
part.alpha = Math.max(0, 1 - self._age / self.life);
if (self._age > self.life) {
self.destroy();
}
};
return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = -8 - (storage.upgrades && storage.upgrades.fireRate ? storage.upgrades.fireRate * 1 : 0); // Slowed down from -12 to -8
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Plane
var PlayerPlane = Container.expand(function () {
var self = Container.call(this);
// Attach player plane asset
self.skin = storage.selectedSkin || 'default';
self.plane = self.attachAsset('playerPlane', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.plane.width;
self.height = self.plane.height;
self.fireCooldown = 0;
self.baseFireRate = 30; // ticks between shots
self.baseSpeed = 32; // Increased from 23 for faster movement
self.baseHealth = 8; // Increased from 5 to 8 for more player lives
self.maxHealth = self.baseHealth + (storage.upgrades && storage.upgrades.health ? storage.upgrades.health : 0);
self.health = self.maxHealth;
self.updateSkin = function () {
// For future: swap asset based on skin
// For now, only color changes
if (self.skin === 'default') {
self.plane.tint = 0x888888;
} else if (self.skin === 'gold') {
self.plane.tint = 0xffd700;
} else if (self.skin === 'blue') {
self.plane.tint = 0x2a6edb;
}
};
self.shoot = function () {
if (self.fireCooldown > 0) return;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2 + 10;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('playerShoot').play();
self.fireCooldown = self.baseFireRate - (storage.upgrades && storage.upgrades.fireRate ? storage.upgrades.fireRate * 4 : 0);
if (self.fireCooldown < 8) self.fireCooldown = 8;
};
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('playerHit').play();
updateHealthBar();
if (self.health <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
};
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) self.health = self.maxHealth;
updateHealthBar();
};
self.update = function () {
if (self.fireCooldown > 0) self.fireCooldown--;
};
self.updateSkin();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundImage: 'spaceMoonBg'
});
/****
* Game Code
****/
// --- Global Variables ---
// Player plane (default skin: gray)
// Player bullet (yellow)
// Enemy: Red Attacker
// Enemy: Blue Speedster
// Enemy: Green Tank
// Enemy bullet (red)
// Health bar background
// Health bar foreground
// Coin icon
// Sounds
// Music
var player;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var coinDrops = [];
var enemyParts = [];
var spawnTimer = 0;
var spawnInterval = 60;
var dragNode = null;
var lastPlayerX = 0;
var lastPlayerY = 0;
var healthBarBg, healthBarFg;
var scoreTxt, coinTxt, coinIcon;
var currency = storage.currency || 0;
// Track how many enemies have been destroyed for health bonus
var enemiesDestroyedSinceLastHeal = 0;
// --- GUI Elements ---
// --- Start Screen State ---
var gameState = "start"; // "start", "playing", "market"
var startScreenContainer = new Container();
startScreenContainer.width = 2048;
startScreenContainer.height = 2732;
// --- Start Screen Background ---
// 2D sunny forest background
var startBg = LK.getAsset('forestBg', {
anchorX: 0,
anchorY: 0,
scaleX: 2048 / 600,
scaleY: 2732 / 40,
x: 0,
y: 0
});
startBg.width = 2048;
startBg.height = 2732;
startScreenContainer.addChild(startBg);
// --- Top Right Coin Display (for start/market screens) ---
var coinIconTL = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIconTL.x = 2048 - 160;
coinIconTL.y = 120;
startScreenContainer.addChild(coinIconTL);
var coinTxtTL = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxtTL.anchor.set(0, 0.5);
coinTxtTL.x = 2048 - 120;
coinTxtTL.y = 120;
startScreenContainer.addChild(coinTxtTL);
// --- Start Screen Title ---
var titleTxt = new Text2("Uçak Savaşı", {
size: 160,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 700;
startScreenContainer.addChild(titleTxt);
// --- Start Button ---
var startBtn = LK.getAsset('playerPlane', {
anchorX: 0.5,
anchorY: 0.5
});
startBtn.x = 2048 / 2;
startBtn.y = 1200;
startBtn.scaleX = 1.2;
startBtn.scaleY = 1.2;
startScreenContainer.addChild(startBtn);
var startBtnTxt = new Text2("Başla", {
size: 100,
fill: "#fff"
});
startBtnTxt.anchor.set(0.5, 0.5);
startBtnTxt.x = startBtn.x;
startBtnTxt.y = startBtn.y + 180;
startScreenContainer.addChild(startBtnTxt);
// --- Add start screen to game ---
game.addChild(startScreenContainer);
// --- Hide game GUI until game starts ---
function setGameGuiVisible(visible) {
if (typeof scoreTxt !== "undefined" && scoreTxt) scoreTxt.visible = visible;
if (typeof coinIconBL !== "undefined" && coinIconBL) coinIconBL.visible = visible;
if (typeof coinTxtBL !== "undefined" && coinTxtBL) coinTxtBL.visible = visible;
if (typeof coinIcon !== "undefined" && coinIcon) coinIcon.visible = visible;
if (typeof coinTxt !== "undefined" && coinTxt) coinTxt.visible = visible;
if (typeof healthBarBg !== "undefined" && healthBarBg) healthBarBg.visible = visible;
if (typeof healthBarFg !== "undefined" && healthBarFg) healthBarFg.visible = visible;
}
setGameGuiVisible(false);
// --- GUI for in-game (unchanged) ---
scoreTxt = new Text2('0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Coin GUI for bottom left
var coinIconBL = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIconBL.x = 80;
coinIconBL.y = -80;
LK.gui.bottomLeft.addChild(coinIconBL);
var coinTxtBL = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxtBL.anchor.set(0, 0.5);
coinTxtBL.x = 120;
coinTxtBL.y = -80;
LK.gui.bottomLeft.addChild(coinTxtBL);
// (Retain top right coin for reference, but main is bottom left)
coinIcon = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinIcon.x = 0;
coinIcon.y = 0;
LK.gui.topRight.addChild(coinIcon);
coinTxt = new Text2(currency + '', {
size: 80,
fill: 0xFFD700
});
coinTxt.anchor.set(0, 0.5);
coinTxt.x = 40;
coinTxt.y = 0;
LK.gui.topRight.addChild(coinTxt);
// Health bar
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0.5
});
healthBarBg.x = 200;
healthBarBg.y = 120;
LK.gui.top.addChild(healthBarBg);
healthBarFg = LK.getAsset('healthBarFg', {
anchorX: 0,
anchorY: 0.5
});
healthBarFg.x = 200;
healthBarFg.y = 120;
LK.gui.top.addChild(healthBarFg);
function updateHealthBar() {
var ratio = player.health / player.maxHealth;
if (ratio < 0) ratio = 0;
healthBarFg.width = 600 * ratio;
}
// --- Player Initialization ---
player = new PlayerPlane();
player.x = 2048 / 2;
player.y = 2732 - 350;
game.addChild(player);
// Set initial follow target to player's starting position
game._lastMoveX = player.x;
game._lastMoveY = player.y;
updateHealthBar();
// --- Show/Hide Screens ---
function showStartScreen() {
gameState = "start";
startScreenContainer.visible = true;
// marketScreenContainer.visible = false;//{3P} // Removed: marketScreenContainer is not defined
setGameGuiVisible(false);
player.visible = false;
coinTxtTL.setText(currency + '');
}
function startGame() {
gameState = "playing";
startScreenContainer.visible = false;
// marketScreenContainer.visible = false;//{3T} // Removed: marketScreenContainer is not defined
setGameGuiVisible(true);
player.visible = true;
// Reset player position and health
player.x = 2048 / 2;
player.y = 2732 - 350;
player.maxHealth = player.baseHealth + (storage.upgrades && storage.upgrades.health ? storage.upgrades.health : 0); // Ensure maxHealth is recalculated
player.health = player.maxHealth;
player.skin = storage.selectedSkin || "default";
player.updateSkin();
updateHealthBar();
// Clear all bullets, enemies, coins
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
playerBullets.splice(i, 1);
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
enemyBullets.splice(i, 1);
}
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = coinDrops.length - 1; i >= 0; i--) {
coinDrops[i].destroy();
coinDrops.splice(i, 1);
}
LK.setScore(0);
scoreTxt.setText("0");
coinTxtBL.setText(currency + '');
coinTxt.setText(currency + '');
}
// --- Start/Market Button Events ---
startBtn.interactive = true;
startBtn.on('down', function (x, y, obj) {
startGame();
});
// --- Start in start screen ---
showStartScreen();
// --- Utility Functions ---
function addCurrency(amount) {
currency += amount;
storage.currency = currency;
coinTxt.setText(currency + '');
if (typeof coinTxtBL !== "undefined") {
coinTxtBL.setText(currency + '');
}
LK.getSound('coin').play();
}
function showScorePopup(x, y, value) {
var popup = new Text2('+' + value, {
size: 70,
fill: "#fff"
});
popup.anchor.set(0.5, 0.5);
popup.x = x;
popup.y = y;
game.addChild(popup);
tween(popup, {
y: y - 100,
alpha: 0
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
popup.destroy();
}
});
}
// --- Enemy Spawning ---
function spawnEnemy() {
var r = Math.random();
var enemy;
// 15% chance to spawn a CoinEnemy (only these drop coins)
// Reduce green plane spawn rate: now only 10% (was 20%)
// Slightly increase blue plane spawn rate (from 40% to 45%)
if (r < 0.15) {
enemy = new CoinEnemy();
} else if (r < 0.45) {
enemy = new EnemyRed();
} else if (r < 0.9) {
enemy = new EnemyBlue();
} else {
enemy = new EnemyGreen();
}
enemy.x = 180 + Math.random() * (2048 - 360);
enemy.y = -enemy.height / 2;
enemies.push(enemy);
game.addChild(enemy);
}
// --- Game Move/Touch Controls ---
function handleMove(x, y, obj) {
if (gameState !== "playing") return;
// Always track last move position for smooth following
game._lastMoveX = x;
game._lastMoveY = y;
// No dragNode logic needed; player always follows cursor/touch position
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameState !== "playing") return;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
if (gameState !== "playing") return;
};
// --- Game Update Loop ---
game.update = function () {
if (gameState !== "playing") return;
// --- Player follows cursor/touch position smoothly ---
if (game._lastMoveX !== undefined && game._lastMoveY !== undefined) {
// Clamp to game area
var minX = player.width / 2 + 40;
var maxX = 2048 - player.width / 2 - 40;
var minY = 200 + player.height / 2;
var maxY = 2732 - player.height / 2 - 40;
var targetX = game._lastMoveX;
var targetY = game._lastMoveY;
if (targetX < minX) targetX = minX;
if (targetX > maxX) targetX = maxX;
if (targetY < minY) targetY = minY;
if (targetY > maxY) targetY = maxY;
// Move smoothly toward target (lerp)
var speed = player.baseSpeed + (storage.upgrades && storage.upgrades.speed ? storage.upgrades.speed : 0);
// Slightly increase lerp responsiveness for snappier feel
speed *= 1.08;
var dx = targetX - player.x;
var dy = targetY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > speed) {
player.x += dx / dist * speed;
player.y += dy / dist * speed;
} else {
player.x = targetX;
player.y = targetY;
}
}
// Player update
player.update();
// Player auto-shoot
// 2 bullets per second at 60FPS: 60/2 = 30 ticks interval
if (LK.ticks % 30 === 0) {
player.shoot();
}
// Player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Track bullet creation time if not already set
if (typeof b._createdAt === "undefined") {
b._createdAt = LK.ticks;
}
// Remove if off screen
if (b.y < -50 || typeof b._createdAt !== "undefined" && LK.ticks - b._createdAt >= 180) {
b.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
var killed = e.takeDamage(1);
b.destroy();
playerBullets.splice(i, 1);
if (killed) {
e.destroy();
enemies.splice(j, 1);
// --- Health bonus for every 3 destroyed enemies ---
enemiesDestroyedSinceLastHeal++;
if (enemiesDestroyedSinceLastHeal >= 3) {
enemiesDestroyedSinceLastHeal = 0;
if (player && typeof player.heal === "function") {
player.heal(1);
}
}
// --- End health bonus ---
}
break;
}
}
}
// Enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
if (b.y > 2732 + 50) {
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (b.intersects(player)) {
player.takeDamage(1);
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Coin drops: move, check pickup, remove if off screen
for (var i = coinDrops.length - 1; i >= 0; i--) {
var c = coinDrops[i];
c.update();
// Remove if off screen
if (c.y > 2732 + 80) {
c.destroy();
coinDrops.splice(i, 1);
continue;
}
// Check pickup by player (only on the frame it starts intersecting)
if (!c.lastWasIntersecting && c.intersects(player)) {
addCurrency(1);
c.destroy();
coinDrops.splice(i, 1);
continue;
}
c.lastWasIntersecting = c.intersects(player);
}
// Enemy debris parts
if (typeof enemyParts === "undefined") enemyParts = [];
for (var i = enemyParts.length - 1; i >= 0; i--) {
var part = enemyParts[i];
if (part.parent) part.update();
if (!part.parent) {
enemyParts.splice(i, 1);
}
}
// Enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Remove if off screen
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(i, 1);
// Decrease score by 2 for each enemy that leaves the screen without being destroyed
LK.setScore(LK.getScore() - 2);
scoreTxt.setText(LK.getScore());
// If score drops below zero, trigger game over
if (LK.getScore() < 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
continue;
}
// Check collision with player
if (e.intersects(player)) {
player.takeDamage(2);
LK.effects.flashObject(e, 0xff0000, 200);
e.destroy();
enemies.splice(i, 1);
continue;
}
}
// Enemy spawn logic: increase spawn rate over time
if (spawnTimer <= 0) {
spawnEnemy();
spawnInterval = 90 - Math.floor(LK.getScore() / 10) * 4; // Increased base interval from 60 to 90 for slower spawns
if (spawnInterval < 28) spawnInterval = 28; // Minimum interval increased from 18 to 28
spawnTimer = spawnInterval;
} else {
spawnTimer--;
}
// Update score
scoreTxt.setText(LK.getScore());
// Win condition: player wins at 200 score
if (LK.getScore() >= 200) {
LK.showYouWin();
return;
}
scoreTxt.setText(LK.getScore());
};
// --- Music ---
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// --- Game Over Handler (currency gain) ---
LK.on('gameover', function () {
// Add score to currency
addCurrency(LK.getScore());
// Save currency
storage.currency = currency;
coinTxt.setText(currency + '');
coinTxtBL.setText(currency + '');
coinTxtTL.setText(currency + '');
// After a short delay, show start screen again
LK.setTimeout(function () {
showStartScreen();
}, 1200);
// Reset upgrades/skins for next run if needed (not implemented here)
});
// --- YouWin Handler (not used, but for future) ---
LK.on('youwin', function () {
// Could reward bonus currency, etc.
});
// --- Prevent elements in top left 100x100
// (All GUI elements are placed away from top left, and player cannot move there)
coin. In-Game asset. 2d. High contrast. No shadows
mavi ufo. In-Game asset. 2d. High contrast. No shadows
bir mermi ama ters . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
yeşil 2d pixel simetrik uçak In-Game asset. 2d. High contrast. No shadows
kırmızı 2d pixel simetrik uçak In-Game asset. 2d. High contrast. No shadows
gri 2d piksel yüksek techizatlı uçak. In-Game asset. 2d. High contrast. No shadows
mermi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat