User prompt
Bu 3 lü atışı bir ödül sonucu ver normal atış tekli ve dikey yönlü olsun
User prompt
Oyuncunun atışını 3 lü ve etrafa yayılan şekilde yap
User prompt
Oyuncuya 3 can hakkı ver
User prompt
Düşmanların hızını azalt
Code edit (1 edits merged)
Please save this source code
User prompt
Space Impact: Uzay Savaşı
Initial prompt
Space impact tarzı oyun yapmak istiyorum
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bomb Class var Bomb = Container.expand(function () { var self = Container.call(this); var bomb = self.attachAsset('heroBullet', { anchorX: 0.5, anchorY: 0.5 }); // bomb visual size is now handled by asset size (20% larger) self.speed = -20; // Upwards, slower than normal bullet self.radius = 220; // Bomb explosion radius self.exploded = false; self.update = function () { self.y += self.speed; // Explode at top or on first enemy hit if (!self.exploded && self.y < 600) { self.explode(); } }; self.explode = function () { if (self.exploded) return; self.exploded = true; // Bomb explosion effect: only flash bomb object (not screen) LK.effects.flashObject(self, 0xffff00, 300); // Only destroy enemies within bomb radius for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // Calculate distance from bomb center to enemy center var dx = self.x - e.x; var dy = self.y - e.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= self.radius) { e.flash(); e.destroy(); enemies.splice(i, 1); LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); } } // Remove bomb after short delay var _self = self; LK.setTimeout(function () { _self.destroy(); if (bombs.indexOf(_self) !== -1) bombs.splice(bombs.indexOf(_self), 1); }, 200); }; return self; }); // Enemy Class var Enemy = Container.expand(function () { var self = Container.call(this); var enemy = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.width = enemy.width; self.height = enemy.height; self.speed = 3 + Math.random() * 2; // Downwards, slower and less random self.type = 0; // 0: normal, 1: zigzag, 2: shooter self.dir = Math.random() < 0.5 ? -1 : 1; // for zigzag self.shootCooldown = 0; self.update = function () { if (self.type === 1) { // Zigzag self.x += self.dir * 12 * Math.sin(LK.ticks / 20 + self._zigzagSeed); } self.y += self.speed; // Shooter if (self.type === 2) { self.shootCooldown--; if (self.shootCooldown <= 0) { self.shootCooldown = 90 + Math.floor(Math.random() * 60); spawnEnemyBullet(self.x, self.y + self.height / 2); } } }; // For zigzag self._zigzagSeed = Math.random() * 1000; // Flash on hit self.flash = function () { tween(enemy, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(enemy, { tint: 0xff3333 }, { duration: 120 }); } }); }; enemy.tint = 0xff3333; return self; }); // Enemy Bullet Class var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 18; // Downwards self.update = function () { self.y += self.speed; }; return self; }); // Hero Bullet Class var HeroBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('heroBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -32; // Upwards self.angle = 0; // Default straight up, can be set externally self.update = function () { // Move in direction of angle (angle 0 = straight up) self.x += Math.sin(self.angle) * Math.abs(self.speed); self.y += Math.cos(self.angle) * self.speed; }; return self; }); // Hero Ship Class var HeroShip = Container.expand(function () { var self = Container.call(this); // Attach ship asset (box, blue) var ship = self.attachAsset('heroShip', { anchorX: 0.5, anchorY: 0.5 }); // Ship properties self.width = ship.width; self.height = ship.height; self.cooldown = 0; // fire cooldown // Ship hit flash self.flash = function () { tween(ship, { tint: 0xff0000 }, { duration: 100, onFinish: function onFinish() { tween(ship, { tint: 0x3399ff }, { duration: 200 }); } }); }; // Ship reset color ship.tint = 0x3399ff; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000010 }); /**** * Game Code ****/ // Score text // Add background image var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048 * 1.2, height: 2732 * 1.2 }); game.addChild(background); // Score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Game variables var hero = null; var heroBullets = []; var bombs = []; var bombCooldown = 0; var enemies = []; var enemyBullets = []; var dragNode = null; var lastHeroX = 0; var lastHeroY = 0; var spawnTimer = 0; var wave = 1; var nextWaveScore = 10; var gameOver = false; var lastBombScore = 0; var firingModeIcon = undefined; // Icon for bullet type // Spread shot power-up state var spreadShotActive = false; var spreadShotTimer = 0; // New: Firing mode state // 0: single, 1: vertical 3-way, 2: wide 3-way var firingModes = [0]; // Array of active firing modes, 0 always present var firingModeTimers = [0]; // Timers for each mode (0 = infinite for base) var firingMode = 0; // Current selected mode var firingModeSwitchCooldown = 0; // Prevent rapid switching // Player lives var heroLives = 3; var livesTxt = new Text2('♥♥♥', { size: 100, fill: 0xFF4444 }); livesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(livesTxt); livesTxt.x = 2048 / 2 - 400; // Helper: spawn hero bullet function spawnHeroBullet(x, y, angle) { var b = new HeroBullet(); b.x = x; b.y = y - hero.height / 2; // If angle is provided, set it for spread, otherwise 0 (straight up) b.angle = angle || 0; heroBullets.push(b); game.addChild(b); } // Helper: spawn bomb function spawnBomb(x, y) { var b = new Bomb(); b.x = x; b.y = y - hero.height / 2; bombs.push(b); game.addChild(b); } // Helper: activate spread shot power-up for a duration (in frames) function activateSpreadShot(duration) { spreadShotActive = true; spreadShotTimer = duration; } // Helper: activate vertical 3-way shot for a duration (in frames) function activateVertical3Way(duration) { // Add or refresh vertical 3-way mode in firingModes var idx = firingModes.indexOf(1); if (idx === -1) { firingModes.push(1); firingModeTimers.push(duration); } else { firingModeTimers[idx] = duration; } } // Helper: activate wide 3-way spread shot for a duration (in frames) function activateWide3Way(duration) { // Add or refresh wide 3-way mode in firingModes var idx = firingModes.indexOf(2); if (idx === -1) { firingModes.push(2); firingModeTimers.push(duration); } else { firingModeTimers[idx] = duration; } } // Helper: spawn enemy bullet function spawnEnemyBullet(x, y) { var b = new EnemyBullet(); b.x = x; b.y = y; enemyBullets.push(b); game.addChild(b); } // Helper: spawn enemy function spawnEnemy(type, x, y) { var e = new Enemy(); e.x = x; e.y = y; e.type = type; // Enemy health scales with score: base 1, +1 every 200 points e.health = 1 + Math.floor(LK.getScore() / 200); if (type === 2) { e.shootCooldown = 60 + Math.floor(Math.random() * 60); } enemies.push(e); game.addChild(e); } // Helper: spawn wave function spawnWave(waveNum) { // After 200 points, fix enemy count to the value at 200 points (waveNum at 200 points) var maxWaveForCount = Math.floor(LK.getScore() / 200) + 1; var cappedWaveNum = waveNum; if (LK.getScore() >= 200) { cappedWaveNum = maxWaveForCount; if (cappedWaveNum > 13) cappedWaveNum = 13; // Prevent excessive enemy count if score is very high } var count = 3 + Math.min(cappedWaveNum, 13); // 3 + waveNum, but capped var spacing = 2048 / (count + 1); for (var i = 0; i < count; i++) { var type = 0; if (cappedWaveNum >= 2 && i % 3 === 0) type = 1; // zigzag if (cappedWaveNum >= 3 && i % 4 === 0) type = 2; // shooter spawnEnemy(type, spacing * (i + 1), -150 - Math.random() * 200); } } // Reset game state function resetGame() { // Remove all for (var i = 0; i < heroBullets.length; i++) heroBullets[i].destroy(); for (var i = 0; i < ((_bombs = bombs) === null || _bombs === void 0 ? void 0 : _bombs.length); i++) { var _bombs; bombs[i].destroy(); } for (var i = 0; i < enemies.length; i++) enemies[i].destroy(); for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy(); heroBullets = []; bombs = []; bombCooldown = 0; enemies = []; enemyBullets = []; wave = 1; nextWaveScore = 10; LK.setScore(0); scoreTxt.setText('0'); gameOver = false; // Reset lives heroLives = 3; livesTxt.setText('♥'.repeat(heroLives)); // Reset spread shot spreadShotActive = false; spreadShotTimer = 0; // Reset firing mode firingModes = [0]; firingModeTimers = [0]; firingMode = 0; firingModeSwitchCooldown = 0; // Hero if (hero) hero.destroy(); hero = new HeroShip(); hero.x = 2048 / 2; hero.y = 2732 - 220; game.addChild(hero); // First wave spawnWave(wave); // Firing mode label if (typeof firingModeTxt !== "undefined" && firingModeTxt.parent) firingModeTxt.parent.removeChild(firingModeTxt); if (typeof firingModeIcon !== "undefined" && firingModeIcon.parent) firingModeIcon.parent.removeChild(firingModeIcon); firingModeTxt = new Text2('', { size: 60, fill: 0xFFFF00 }); firingModeTxt.anchor.set(0.5, 1); game.addChild(firingModeTxt); // Reset lastBombScore for bomb reward lastBombScore = 0; // Reset lastLifeScore for extra life reward lastLifeScore = 0; } // Drag/move handler function handleMove(x, y, obj) { if (dragNode && !gameOver) { // Clamp inside screen var minX = hero.width / 2; var maxX = 2048 - hero.width / 2; dragNode.x = Math.max(minX, Math.min(maxX, x)); // Y is fixed (bottom) dragNode.y = hero.y; } } // Touch/drag events game.down = function (x, y, obj) { if (gameOver) return; // Only allow drag if touch is on hero var local = hero.toLocal(game.toGlobal({ x: x, y: y })); // Bomb fire: if two or more touches, fire bomb (multi-touch) if (obj && obj.event && obj.event.touches && obj.event.touches.length >= 2 && bombCooldown === 0) { spawnBomb(hero.x, hero.y - hero.height / 2); bombCooldown = 60; // 1 second cooldown return; } if (local.x > -hero.width / 2 && local.x < hero.width / 2 && local.y > -hero.height / 2 && local.y < hero.height / 2) { // If multiple firing modes, tap to switch if (firingModes.length > 1 && firingModeSwitchCooldown === 0) { var idx = firingModes.indexOf(firingMode); idx = (idx + 1) % firingModes.length; firingMode = firingModes[idx]; firingModeSwitchCooldown = 15; // prevent rapid switching } else { dragNode = hero; handleMove(x, y, obj); } } }; game.up = function (x, y, obj) { dragNode = null; }; game.move = handleMove; // Main update loop game.update = function () { if (gameOver) return; // Hero fire if (hero.cooldown > 0) hero.cooldown--; // After 200 points, default to 2-way spread shot (center+left+right) if (hero.cooldown <= 0) { if (firingMode === 2) { // Wide 3-way spread: center, wide left, wide right var wideAngle = 32 * Math.PI / 180; // 32 degrees in radians spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0); spawnHeroBullet(hero.x, hero.y - hero.height / 2, -wideAngle); spawnHeroBullet(hero.x, hero.y - hero.height / 2, wideAngle); } else if (firingMode === 1) { // Vertical 3-way: center, slightly left, slightly right (all nearly vertical) var vAngle = 8 * Math.PI / 180; // 8 degrees in radians spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0); spawnHeroBullet(hero.x, hero.y - hero.height / 2, -vAngle); spawnHeroBullet(hero.x, hero.y - hero.height / 2, vAngle); } else if (spreadShotActive) { // 3-way spread: center, left, right (legacy power-up) var spreadAngle = 18 * Math.PI / 180; // 18 degrees in radians spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0); spawnHeroBullet(hero.x, hero.y - hero.height / 2, -spreadAngle); spawnHeroBullet(hero.x, hero.y - hero.height / 2, spreadAngle); } else if (LK.getScore() >= 200) { // Default: 2-way spread (left, right only) after 200 points var spreadAngle = 18 * Math.PI / 180; spawnHeroBullet(hero.x, hero.y - hero.height / 2, -spreadAngle); spawnHeroBullet(hero.x, hero.y - hero.height / 2, spreadAngle); } else { // Single straight bullet spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0); } hero.cooldown = 18; } // Spread shot timer countdown if (spreadShotActive) { spreadShotTimer--; if (spreadShotTimer <= 0) { spreadShotActive = false; } } // Firing mode timers countdown and cleanup for (var i = firingModes.length - 1; i > 0; i--) { // skip base mode at 0 firingModeTimers[i]--; if (firingModeTimers[i] <= 0) { // Remove expired mode if (firingMode === firingModes[i]) { firingMode = 0; // fallback to base } firingModes.splice(i, 1); firingModeTimers.splice(i, 1); } } // Clamp firingMode to available if (firingModes.indexOf(firingMode) === -1) firingMode = firingModes[0]; // Firing mode switch cooldown if (firingModeSwitchCooldown > 0) firingModeSwitchCooldown--; // Update hero bullets for (var i = heroBullets.length - 1; i >= 0; i--) { var b = heroBullets[i]; b.update(); // Off screen if (b.y < -80) { b.destroy(); heroBullets.splice(i, 1); continue; } // Hit enemy var hit = false; for (var j = enemies.length - 1; j >= 0; j--) { var e = enemies[j]; if (b.intersects(e)) { e.flash(); b.destroy(); heroBullets.splice(i, 1); if (typeof e.health === "undefined") e.health = 1; e.health--; if (e.health <= 0) { enemies.splice(j, 1); e.destroy(); LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); } hit = true; break; } } if (hit) continue; } // Update bombs for (var i = bombs.length - 1; i >= 0; i--) { var b = bombs[i]; b.update(); // Remove if off screen and not exploded if (!b.exploded && b.y < -200) { b.explode(); } if (b.exploded && (!b.parent || b.destroyed)) { bombs.splice(i, 1); } } if (bombCooldown > 0) bombCooldown--; // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); // Off screen if (e.y > 2732 + 100) { e.destroy(); enemies.splice(i, 1); continue; } // Collide with hero if (e.intersects(hero)) { hero.flash(); LK.effects.flashScreen(0xff0000, 1000); heroLives--; livesTxt.setText('♥'.repeat(heroLives)); if (heroLives <= 0) { gameOver = true; LK.showGameOver(); return; } else { // Remove enemy and continue e.destroy(); enemies.splice(i, 1); continue; } } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var b = enemyBullets[i]; b.update(); // Off screen if (b.y > 2732 + 80) { b.destroy(); enemyBullets.splice(i, 1); continue; } // Hit hero if (b.intersects(hero)) { hero.flash(); b.destroy(); enemyBullets.splice(i, 1); LK.effects.flashScreen(0xff0000, 1000); heroLives--; livesTxt.setText('♥'.repeat(heroLives)); if (heroLives <= 0) { gameOver = true; LK.showGameOver(); return; } } } // Spawn new wave if all enemies gone if (enemies.length === 0) { wave++; spawnWave(wave); } // Next wave at score milestones if (LK.getScore() >= nextWaveScore) { wave++; nextWaveScore += 10 + wave * 2; // Cap wave for enemy count after 200 points var cappedWave = wave; if (LK.getScore() >= 200) { cappedWave = Math.floor(LK.getScore() / 200) + 1; if (cappedWave > 13) cappedWave = 13; } spawnWave(cappedWave); } // Reward: Activate different firing modes at score milestones // Every 100: vertical 3-way, every 200: wide 3-way if (LK.getScore() > 0 && LK.getScore() % 200 === 0 && firingModes.indexOf(2) === -1) { activateWide3Way(360); } else if (LK.getScore() > 0 && LK.getScore() % 100 === 0 && firingModes.indexOf(1) === -1) { activateVertical3Way(360); } else if (LK.getScore() > 0 && LK.getScore() % 20 === 0 && !spreadShotActive && firingModes.length === 1) { activateSpreadShot(360); } // Bomb shot at every 50 points if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && lastBombScore !== LK.getScore()) { spawnBomb(hero.x, hero.y - hero.height / 2); lastBombScore = LK.getScore(); } // Extra life at every 50 points (max 5 lives) if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && typeof lastLifeScore !== "undefined" && lastLifeScore !== LK.getScore()) { if (heroLives < 5) { heroLives++; livesTxt.setText('♥'.repeat(heroLives)); LK.effects.flashObject(livesTxt, 0x00ff00, 500); } lastLifeScore = LK.getScore(); } else if (typeof lastLifeScore === "undefined") { lastLifeScore = 0; } // Update firing mode label and icon if (typeof firingModeTxt !== "undefined" && firingModeTxt) { firingModeTxt.x = hero.x; firingModeTxt.y = hero.y - hero.height / 2 - 20; var label = ""; var iconAssetId = "heroBullet"; var iconAngle = 0; if (firingMode === 1) { label = "Dikey 3'lü"; iconAngle = 0; } else if (firingMode === 2) { label = "Geniş 3'lü"; iconAngle = 32 * Math.PI / 180; // show wide } else if (spreadShotActive) { label = "Yayılı 3'lü"; iconAngle = 18 * Math.PI / 180; } else if (LK.getScore() >= 200) { label = "2'li Yaylım"; iconAngle = 18 * Math.PI / 180; // icon will show right-tilted bullet (no center) } else { label = "Tekli"; iconAngle = 0; } firingModeTxt.setText(label); // Remove previous icon if exists if (typeof firingModeIcon !== "undefined" && firingModeIcon.parent) { firingModeIcon.parent.removeChild(firingModeIcon); } // Add bullet icon next to label firingModeIcon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, rotation: iconAngle }); firingModeIcon.x = firingModeTxt.x + firingModeTxt.width / 2 + 50; firingModeIcon.y = firingModeTxt.y + firingModeTxt.height / 2; game.addChild(firingModeIcon); } }; // Start game resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bomb Class
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bomb = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
// bomb visual size is now handled by asset size (20% larger)
self.speed = -20; // Upwards, slower than normal bullet
self.radius = 220; // Bomb explosion radius
self.exploded = false;
self.update = function () {
self.y += self.speed;
// Explode at top or on first enemy hit
if (!self.exploded && self.y < 600) {
self.explode();
}
};
self.explode = function () {
if (self.exploded) return;
self.exploded = true;
// Bomb explosion effect: only flash bomb object (not screen)
LK.effects.flashObject(self, 0xffff00, 300);
// Only destroy enemies within bomb radius
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
// Calculate distance from bomb center to enemy center
var dx = self.x - e.x;
var dy = self.y - e.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist <= self.radius) {
e.flash();
e.destroy();
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
}
// Remove bomb after short delay
var _self = self;
LK.setTimeout(function () {
_self.destroy();
if (bombs.indexOf(_self) !== -1) bombs.splice(bombs.indexOf(_self), 1);
}, 200);
};
return self;
});
// Enemy Class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemy = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = enemy.width;
self.height = enemy.height;
self.speed = 3 + Math.random() * 2; // Downwards, slower and less random
self.type = 0; // 0: normal, 1: zigzag, 2: shooter
self.dir = Math.random() < 0.5 ? -1 : 1; // for zigzag
self.shootCooldown = 0;
self.update = function () {
if (self.type === 1) {
// Zigzag
self.x += self.dir * 12 * Math.sin(LK.ticks / 20 + self._zigzagSeed);
}
self.y += self.speed;
// Shooter
if (self.type === 2) {
self.shootCooldown--;
if (self.shootCooldown <= 0) {
self.shootCooldown = 90 + Math.floor(Math.random() * 60);
spawnEnemyBullet(self.x, self.y + self.height / 2);
}
}
};
// For zigzag
self._zigzagSeed = Math.random() * 1000;
// Flash on hit
self.flash = function () {
tween(enemy, {
tint: 0xffffff
}, {
duration: 80,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xff3333
}, {
duration: 120
});
}
});
};
enemy.tint = 0xff3333;
return self;
});
// Enemy Bullet Class
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 18; // Downwards
self.update = function () {
self.y += self.speed;
};
return self;
});
// Hero Bullet Class
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -32; // Upwards
self.angle = 0; // Default straight up, can be set externally
self.update = function () {
// Move in direction of angle (angle 0 = straight up)
self.x += Math.sin(self.angle) * Math.abs(self.speed);
self.y += Math.cos(self.angle) * self.speed;
};
return self;
});
// Hero Ship Class
var HeroShip = Container.expand(function () {
var self = Container.call(this);
// Attach ship asset (box, blue)
var ship = self.attachAsset('heroShip', {
anchorX: 0.5,
anchorY: 0.5
});
// Ship properties
self.width = ship.width;
self.height = ship.height;
self.cooldown = 0; // fire cooldown
// Ship hit flash
self.flash = function () {
tween(ship, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(ship, {
tint: 0x3399ff
}, {
duration: 200
});
}
});
};
// Ship reset color
ship.tint = 0x3399ff;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000010
});
/****
* Game Code
****/
// Score text
// Add background image
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048 * 1.2,
height: 2732 * 1.2
});
game.addChild(background);
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Game variables
var hero = null;
var heroBullets = [];
var bombs = [];
var bombCooldown = 0;
var enemies = [];
var enemyBullets = [];
var dragNode = null;
var lastHeroX = 0;
var lastHeroY = 0;
var spawnTimer = 0;
var wave = 1;
var nextWaveScore = 10;
var gameOver = false;
var lastBombScore = 0;
var firingModeIcon = undefined; // Icon for bullet type
// Spread shot power-up state
var spreadShotActive = false;
var spreadShotTimer = 0;
// New: Firing mode state
// 0: single, 1: vertical 3-way, 2: wide 3-way
var firingModes = [0]; // Array of active firing modes, 0 always present
var firingModeTimers = [0]; // Timers for each mode (0 = infinite for base)
var firingMode = 0; // Current selected mode
var firingModeSwitchCooldown = 0; // Prevent rapid switching
// Player lives
var heroLives = 3;
var livesTxt = new Text2('♥♥♥', {
size: 100,
fill: 0xFF4444
});
livesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(livesTxt);
livesTxt.x = 2048 / 2 - 400;
// Helper: spawn hero bullet
function spawnHeroBullet(x, y, angle) {
var b = new HeroBullet();
b.x = x;
b.y = y - hero.height / 2;
// If angle is provided, set it for spread, otherwise 0 (straight up)
b.angle = angle || 0;
heroBullets.push(b);
game.addChild(b);
}
// Helper: spawn bomb
function spawnBomb(x, y) {
var b = new Bomb();
b.x = x;
b.y = y - hero.height / 2;
bombs.push(b);
game.addChild(b);
}
// Helper: activate spread shot power-up for a duration (in frames)
function activateSpreadShot(duration) {
spreadShotActive = true;
spreadShotTimer = duration;
}
// Helper: activate vertical 3-way shot for a duration (in frames)
function activateVertical3Way(duration) {
// Add or refresh vertical 3-way mode in firingModes
var idx = firingModes.indexOf(1);
if (idx === -1) {
firingModes.push(1);
firingModeTimers.push(duration);
} else {
firingModeTimers[idx] = duration;
}
}
// Helper: activate wide 3-way spread shot for a duration (in frames)
function activateWide3Way(duration) {
// Add or refresh wide 3-way mode in firingModes
var idx = firingModes.indexOf(2);
if (idx === -1) {
firingModes.push(2);
firingModeTimers.push(duration);
} else {
firingModeTimers[idx] = duration;
}
}
// Helper: spawn enemy bullet
function spawnEnemyBullet(x, y) {
var b = new EnemyBullet();
b.x = x;
b.y = y;
enemyBullets.push(b);
game.addChild(b);
}
// Helper: spawn enemy
function spawnEnemy(type, x, y) {
var e = new Enemy();
e.x = x;
e.y = y;
e.type = type;
// Enemy health scales with score: base 1, +1 every 200 points
e.health = 1 + Math.floor(LK.getScore() / 200);
if (type === 2) {
e.shootCooldown = 60 + Math.floor(Math.random() * 60);
}
enemies.push(e);
game.addChild(e);
}
// Helper: spawn wave
function spawnWave(waveNum) {
// After 200 points, fix enemy count to the value at 200 points (waveNum at 200 points)
var maxWaveForCount = Math.floor(LK.getScore() / 200) + 1;
var cappedWaveNum = waveNum;
if (LK.getScore() >= 200) {
cappedWaveNum = maxWaveForCount;
if (cappedWaveNum > 13) cappedWaveNum = 13; // Prevent excessive enemy count if score is very high
}
var count = 3 + Math.min(cappedWaveNum, 13); // 3 + waveNum, but capped
var spacing = 2048 / (count + 1);
for (var i = 0; i < count; i++) {
var type = 0;
if (cappedWaveNum >= 2 && i % 3 === 0) type = 1; // zigzag
if (cappedWaveNum >= 3 && i % 4 === 0) type = 2; // shooter
spawnEnemy(type, spacing * (i + 1), -150 - Math.random() * 200);
}
}
// Reset game state
function resetGame() {
// Remove all
for (var i = 0; i < heroBullets.length; i++) heroBullets[i].destroy();
for (var i = 0; i < ((_bombs = bombs) === null || _bombs === void 0 ? void 0 : _bombs.length); i++) {
var _bombs;
bombs[i].destroy();
}
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
heroBullets = [];
bombs = [];
bombCooldown = 0;
enemies = [];
enemyBullets = [];
wave = 1;
nextWaveScore = 10;
LK.setScore(0);
scoreTxt.setText('0');
gameOver = false;
// Reset lives
heroLives = 3;
livesTxt.setText('♥'.repeat(heroLives));
// Reset spread shot
spreadShotActive = false;
spreadShotTimer = 0;
// Reset firing mode
firingModes = [0];
firingModeTimers = [0];
firingMode = 0;
firingModeSwitchCooldown = 0;
// Hero
if (hero) hero.destroy();
hero = new HeroShip();
hero.x = 2048 / 2;
hero.y = 2732 - 220;
game.addChild(hero);
// First wave
spawnWave(wave);
// Firing mode label
if (typeof firingModeTxt !== "undefined" && firingModeTxt.parent) firingModeTxt.parent.removeChild(firingModeTxt);
if (typeof firingModeIcon !== "undefined" && firingModeIcon.parent) firingModeIcon.parent.removeChild(firingModeIcon);
firingModeTxt = new Text2('', {
size: 60,
fill: 0xFFFF00
});
firingModeTxt.anchor.set(0.5, 1);
game.addChild(firingModeTxt);
// Reset lastBombScore for bomb reward
lastBombScore = 0;
// Reset lastLifeScore for extra life reward
lastLifeScore = 0;
}
// Drag/move handler
function handleMove(x, y, obj) {
if (dragNode && !gameOver) {
// Clamp inside screen
var minX = hero.width / 2;
var maxX = 2048 - hero.width / 2;
dragNode.x = Math.max(minX, Math.min(maxX, x));
// Y is fixed (bottom)
dragNode.y = hero.y;
}
}
// Touch/drag events
game.down = function (x, y, obj) {
if (gameOver) return;
// Only allow drag if touch is on hero
var local = hero.toLocal(game.toGlobal({
x: x,
y: y
}));
// Bomb fire: if two or more touches, fire bomb (multi-touch)
if (obj && obj.event && obj.event.touches && obj.event.touches.length >= 2 && bombCooldown === 0) {
spawnBomb(hero.x, hero.y - hero.height / 2);
bombCooldown = 60; // 1 second cooldown
return;
}
if (local.x > -hero.width / 2 && local.x < hero.width / 2 && local.y > -hero.height / 2 && local.y < hero.height / 2) {
// If multiple firing modes, tap to switch
if (firingModes.length > 1 && firingModeSwitchCooldown === 0) {
var idx = firingModes.indexOf(firingMode);
idx = (idx + 1) % firingModes.length;
firingMode = firingModes[idx];
firingModeSwitchCooldown = 15; // prevent rapid switching
} else {
dragNode = hero;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.move = handleMove;
// Main update loop
game.update = function () {
if (gameOver) return;
// Hero fire
if (hero.cooldown > 0) hero.cooldown--;
// After 200 points, default to 2-way spread shot (center+left+right)
if (hero.cooldown <= 0) {
if (firingMode === 2) {
// Wide 3-way spread: center, wide left, wide right
var wideAngle = 32 * Math.PI / 180; // 32 degrees in radians
spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, -wideAngle);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, wideAngle);
} else if (firingMode === 1) {
// Vertical 3-way: center, slightly left, slightly right (all nearly vertical)
var vAngle = 8 * Math.PI / 180; // 8 degrees in radians
spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, -vAngle);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, vAngle);
} else if (spreadShotActive) {
// 3-way spread: center, left, right (legacy power-up)
var spreadAngle = 18 * Math.PI / 180; // 18 degrees in radians
spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, -spreadAngle);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, spreadAngle);
} else if (LK.getScore() >= 200) {
// Default: 2-way spread (left, right only) after 200 points
var spreadAngle = 18 * Math.PI / 180;
spawnHeroBullet(hero.x, hero.y - hero.height / 2, -spreadAngle);
spawnHeroBullet(hero.x, hero.y - hero.height / 2, spreadAngle);
} else {
// Single straight bullet
spawnHeroBullet(hero.x, hero.y - hero.height / 2, 0);
}
hero.cooldown = 18;
}
// Spread shot timer countdown
if (spreadShotActive) {
spreadShotTimer--;
if (spreadShotTimer <= 0) {
spreadShotActive = false;
}
}
// Firing mode timers countdown and cleanup
for (var i = firingModes.length - 1; i > 0; i--) {
// skip base mode at 0
firingModeTimers[i]--;
if (firingModeTimers[i] <= 0) {
// Remove expired mode
if (firingMode === firingModes[i]) {
firingMode = 0; // fallback to base
}
firingModes.splice(i, 1);
firingModeTimers.splice(i, 1);
}
}
// Clamp firingMode to available
if (firingModes.indexOf(firingMode) === -1) firingMode = firingModes[0];
// Firing mode switch cooldown
if (firingModeSwitchCooldown > 0) firingModeSwitchCooldown--;
// Update hero bullets
for (var i = heroBullets.length - 1; i >= 0; i--) {
var b = heroBullets[i];
b.update();
// Off screen
if (b.y < -80) {
b.destroy();
heroBullets.splice(i, 1);
continue;
}
// Hit enemy
var hit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
e.flash();
b.destroy();
heroBullets.splice(i, 1);
if (typeof e.health === "undefined") e.health = 1;
e.health--;
if (e.health <= 0) {
enemies.splice(j, 1);
e.destroy();
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
hit = true;
break;
}
}
if (hit) continue;
}
// Update bombs
for (var i = bombs.length - 1; i >= 0; i--) {
var b = bombs[i];
b.update();
// Remove if off screen and not exploded
if (!b.exploded && b.y < -200) {
b.explode();
}
if (b.exploded && (!b.parent || b.destroyed)) {
bombs.splice(i, 1);
}
}
if (bombCooldown > 0) bombCooldown--;
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Off screen
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Collide with hero
if (e.intersects(hero)) {
hero.flash();
LK.effects.flashScreen(0xff0000, 1000);
heroLives--;
livesTxt.setText('♥'.repeat(heroLives));
if (heroLives <= 0) {
gameOver = true;
LK.showGameOver();
return;
} else {
// Remove enemy and continue
e.destroy();
enemies.splice(i, 1);
continue;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
// Off screen
if (b.y > 2732 + 80) {
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Hit hero
if (b.intersects(hero)) {
hero.flash();
b.destroy();
enemyBullets.splice(i, 1);
LK.effects.flashScreen(0xff0000, 1000);
heroLives--;
livesTxt.setText('♥'.repeat(heroLives));
if (heroLives <= 0) {
gameOver = true;
LK.showGameOver();
return;
}
}
}
// Spawn new wave if all enemies gone
if (enemies.length === 0) {
wave++;
spawnWave(wave);
}
// Next wave at score milestones
if (LK.getScore() >= nextWaveScore) {
wave++;
nextWaveScore += 10 + wave * 2;
// Cap wave for enemy count after 200 points
var cappedWave = wave;
if (LK.getScore() >= 200) {
cappedWave = Math.floor(LK.getScore() / 200) + 1;
if (cappedWave > 13) cappedWave = 13;
}
spawnWave(cappedWave);
}
// Reward: Activate different firing modes at score milestones
// Every 100: vertical 3-way, every 200: wide 3-way
if (LK.getScore() > 0 && LK.getScore() % 200 === 0 && firingModes.indexOf(2) === -1) {
activateWide3Way(360);
} else if (LK.getScore() > 0 && LK.getScore() % 100 === 0 && firingModes.indexOf(1) === -1) {
activateVertical3Way(360);
} else if (LK.getScore() > 0 && LK.getScore() % 20 === 0 && !spreadShotActive && firingModes.length === 1) {
activateSpreadShot(360);
}
// Bomb shot at every 50 points
if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && lastBombScore !== LK.getScore()) {
spawnBomb(hero.x, hero.y - hero.height / 2);
lastBombScore = LK.getScore();
}
// Extra life at every 50 points (max 5 lives)
if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && typeof lastLifeScore !== "undefined" && lastLifeScore !== LK.getScore()) {
if (heroLives < 5) {
heroLives++;
livesTxt.setText('♥'.repeat(heroLives));
LK.effects.flashObject(livesTxt, 0x00ff00, 500);
}
lastLifeScore = LK.getScore();
} else if (typeof lastLifeScore === "undefined") {
lastLifeScore = 0;
}
// Update firing mode label and icon
if (typeof firingModeTxt !== "undefined" && firingModeTxt) {
firingModeTxt.x = hero.x;
firingModeTxt.y = hero.y - hero.height / 2 - 20;
var label = "";
var iconAssetId = "heroBullet";
var iconAngle = 0;
if (firingMode === 1) {
label = "Dikey 3'lü";
iconAngle = 0;
} else if (firingMode === 2) {
label = "Geniş 3'lü";
iconAngle = 32 * Math.PI / 180; // show wide
} else if (spreadShotActive) {
label = "Yayılı 3'lü";
iconAngle = 18 * Math.PI / 180;
} else if (LK.getScore() >= 200) {
label = "2'li Yaylım";
iconAngle = 18 * Math.PI / 180; // icon will show right-tilted bullet (no center)
} else {
label = "Tekli";
iconAngle = 0;
}
firingModeTxt.setText(label);
// Remove previous icon if exists
if (typeof firingModeIcon !== "undefined" && firingModeIcon.parent) {
firingModeIcon.parent.removeChild(firingModeIcon);
}
// Add bullet icon next to label
firingModeIcon = LK.getAsset(iconAssetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
rotation: iconAngle
});
firingModeIcon.x = firingModeTxt.x + firingModeTxt.width / 2 + 50;
firingModeIcon.y = firingModeTxt.y + firingModeTxt.height / 2;
game.addChild(firingModeIcon);
}
};
// Start game
resetGame();