/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Alien class
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = alienAsset.width;
self.height = alienAsset.height;
self.hp = 2; // Each alien takes 2 hits (all aliens always 2 hits)
self.isHit = false;
self.hitTween = null;
// For hit flash
self.flash = function () {
// If a previous hitTween is running, stop it
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
// Set alien to red tint
alienAsset.tint = 0xff5252;
// Tween back to normal color (no tint) over 120ms
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 8 + Math.random() * 4; // Slightly random speed
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
// Bigger Alien class (for level > 3, 3 hits to kill, larger)
var BiggerAlien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.width = alienAsset.width * 1.5;
self.height = alienAsset.height * 1.5;
self.hp = 2; // Takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
alienAsset.tint = 0xff5252;
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 10 + Math.random() * 2; // Slightly slower than strong alien
self.update = function () {
self.y += self.speed;
};
return self;
});
// Boss Alien class (for level 7)
var BossAlien = Container.expand(function () {
var self = Container.call(this);
var bossAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.7,
scaleY: 1.7
});
self.width = bossAsset.width * 1.7;
self.height = bossAsset.height * 1.7;
self.hp = 2; // Boss takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(bossAsset, {
tint: true
});
}
bossAsset.tint = 0xff5252;
self.hitTween = tween(bossAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
self.speed = 10; // Boss is faster
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -32; // Upwards
self.power = bulletPower; // Set bullet power at creation
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy bullet class (alien shoots at player)
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
bulletAsset.tint = 0xff5252; // Red tint for enemy bullets
self.speed = 27; // Downwards, 1.5x faster than before
self.update = function () {
self.y += self.speed;
};
return self;
});
// Rocket (player) class
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketAsset = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rocketAsset.width;
self.height = rocketAsset.height;
// For hit flash
self.flashTween = null;
// Show hit flash
self.flash = function () {
// If a previous flashTween is running, stop it
if (self.flashTween) {
tween.stop(rocketAsset, {
tint: true
});
}
// Set rocket to reddish tint
rocketAsset.tint = 0xff5252;
// Tween back to normal color (white) over 200ms
self.flashTween = tween(rocketAsset, {
tint: 0xffffff
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
self.flashTween = null;
}
});
};
return self;
});
// Star class for animated background stars
var Star = Container.expand(function () {
var self = Container.call(this);
// Use a larger ellipse for the star to make it more visible
var size = 6 + Math.random() * 8; // Increased min and max size
var starAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 160,
scaleY: size / 160
});
// Brighter color choices for more visibility
var colorChoices = [0xffffff, 0xe3f2fd, 0xfffde7, 0xb3e5fc, 0xfff9c4];
starAsset.tint = colorChoices[Math.floor(Math.random() * colorChoices.length)];
self.width = size;
self.height = size;
self.speed = 2.5 + Math.random() * 4.5;
// Higher minimum alpha for more visible stars
self.alpha = 0.7 + Math.random() * 0.3;
self.update = function () {
self.y += self.speed;
if (self.y > GAME_HEIGHT + 10) {
// Respawn at top
self.y = -10;
self.x = 10 + Math.random() * (GAME_WIDTH - 20);
self.speed = 2.5 + Math.random() * 4.5;
self.alpha = 0.7 + Math.random() * 0.3;
}
};
return self;
});
// Strong Alien class (tougher, faster)
var StrongAlien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.width = alienAsset.width * 1.2;
self.height = alienAsset.height * 1.2;
self.hp = 2; // Strong alien takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
alienAsset.tint = 0xff5252;
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 12 + Math.random() * 3; // Stronger and faster
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
// Rocket (player)
// Alien (enemy)
// Bullet
// Alien hit flash
// Life bar
// Life bar background
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// --- Kill Counter (top right) ---
var killNumberText = new Text2("0", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
killNumberText.anchor.set(1, 0); // right anchor, top edge
killNumberText.x = GAME_WIDTH - 40;
killNumberText.y = 40;
LK.gui.top.addChild(killNumberText);
// --- Starfield background ---
var stars = [];
var STAR_COUNT = 60;
for (var i = 0; i < STAR_COUNT; ++i) {
var star = new Star();
star.x = 10 + Math.random() * (GAME_WIDTH - 20);
star.y = Math.random() * GAME_HEIGHT;
stars.push(star);
game.addChildAt(star, 0); // Add behind all other objects
}
var ROCKET_START_LIFE = 5;
var LEVEL_TO_BOSS = 7;
// Game state
var rocket = null;
var bullets = [];
var aliens = [];
var level = 1;
var rocketLife = ROCKET_START_LIFE;
var bulletPower = 1; // Bullet power, increases every level
var canShoot = true;
var shootCooldown = 0;
var dragNode = null;
var lastMoveX = 0;
var lastMoveY = 0;
var score = 0;
var bossSpawned = false;
var enemyBullets = []; // Track enemy bullets
// --- Shield state for rocket ---
var rocketShieldActive = false;
var rocketShieldTimer = 0;
var rocketShieldVisual = null;
// GUI elements
var scoreTxt = new Text2('0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 1);
// Ensure score is always visible
scoreTxt.alpha = 1;
scoreTxt.visible = true;
// Position the score text horizontally aligned with the rocket, above it
scoreTxt.x = GAME_WIDTH / 2;
scoreTxt.y = GAME_HEIGHT - 400 - (rocket ? rocket.height / 2 : 110) - 40; // 40px above rocket top, fallback if rocket not yet created
LK.gui.top.addChild(scoreTxt);
if (LK.gui.top.children && LK.gui.top.children.length > 1) {
LK.gui.top.setChildIndex(scoreTxt, LK.gui.top.children.length - 1);
}
// New health bar will be created below
// updateLevelBar and updateLevelText helpers removed as level bar is no longer shown
// Helper to update score text
function updateScoreText() {
scoreTxt.setText(score);
// Update kill counter text (if defined)
if (typeof killCounterText !== "undefined") {
killCounterText.setText(score.toString());
}
// Update kill number text (top right)
if (typeof killNumberText !== "undefined") {
killNumberText.setText(score.toString());
}
// Update health bar kill counter text (if defined)
if (typeof healthBarKillCounterText !== "undefined") {
healthBarKillCounterText.setText(score.toString());
}
// Update rocket kill counter text (above rocket)
if (typeof rocketKillCounterText !== "undefined") {
rocketKillCounterText.setText(score.toString());
}
// updateLevelBar removed
}
// Spawn a new alien
function spawnAlien() {
var alien;
if (level === LEVEL_TO_BOSS && !bossSpawned) {
alien = new BossAlien();
alien.hp = 2; // Boss always 2 hits
bossSpawned = true;
} else {
// 20% chance to spawn a BiggerAlien after level 3, 30% StrongAlien, otherwise normal Alien
if (level > 3 && Math.random() < 0.2) {
alien = new BiggerAlien();
alien.hp = 2; // Always 2 hits for bigger alien
} else if (Math.random() < 0.3 && level > 2) {
alien = new StrongAlien();
alien.hp = 2; // Always 2 hits for strong alien
} else {
alien = new Alien();
alien.hp = 2; // Always 2 hits for normal alien
}
}
// Defensive: always set hp to 2 for all enemy types
if (alien) {
alien.hp = 2;
// 1. seviyede düşmanlar 1.5 kat hızlı gelsin
if (level === 1 && typeof alien.speed === "number") {
alien.speed *= 1.5;
}
}
// Random x, but keep inside screen
var margin = 120;
alien.x = margin + Math.random() * (GAME_WIDTH - margin * 2);
alien.y = -alien.height / 2;
aliens.push(alien);
game.addChild(alien);
}
// Reset game state
function resetGame() {
// Remove all bullets and aliens
for (var i = 0; i < bullets.length; ++i) {
bullets[i].destroy();
}
for (var j = 0; j < aliens.length; ++j) {
aliens[j].destroy();
}
for (var k = 0; k < enemyBullets.length; ++k) {
enemyBullets[k].destroy();
}
bullets = [];
aliens = [];
enemyBullets = [];
level = 1;
rocketLife = ROCKET_START_LIFE;
bulletPower = 1; // Always 1, so all enemies take 2 hits
canShoot = true;
shootCooldown = 0;
dragNode = null;
lastMoveX = 0;
lastMoveY = 0;
score = 0;
bossSpawned = false;
// updateLevelText and updateLevelBar removed
updateScoreText();
updateLevelBar();
updateHealthBar();
}
// Initialize rocket
rocket = new Rocket();
rocket.x = GAME_WIDTH / 2;
rocket.y = GAME_HEIGHT - 400;
game.addChild(rocket);
// --- Rocket health bar that follows rocket ---
var rocketLifeBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 0,
width: 220,
height: 18
});
var rocketLifeBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0,
x: -110,
y: 0,
width: 220,
height: 18
});
var rocketLifeBarContainer = new Container();
rocketLifeBarContainer.addChild(rocketLifeBarBg);
rocketLifeBarContainer.addChild(rocketLifeBar);
rocketLifeBarContainer.x = rocket.x;
rocketLifeBarContainer.y = rocket.y + rocket.height / 2 + 12; // 12px below rocket
game.addChild(rocketLifeBarContainer);
// Move scoreTxt to be above the rocket, horizontally aligned
scoreTxt.x = rocket.x;
scoreTxt.y = rocket.y - rocket.height / 2 - 40; // 40px above rocket top
// --- Kill Counter above Rocket ---
// Create kill counter text to be placed above the rocket
var rocketKillCounterText = new Text2("0", {
size: 54,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
rocketKillCounterText.anchor.set(0.5, 1); // center anchor, bottom edge
rocketKillCounterText.x = rocket.x;
rocketKillCounterText.y = rocket.y - rocket.height / 2 - 60; // 60px above rocket top
game.addChild(rocketKillCounterText);
// --- New Health Bar (top center) ---
var healthBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 440,
height: 44,
x: 0,
y: 0
});
var healthBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0.5,
width: 400,
height: 36,
x: -200,
y: 0
});
var healthBarContainer = new Container();
healthBarContainer.addChild(healthBarBg);
healthBarContainer.addChild(healthBar);
healthBarContainer.x = GAME_WIDTH / 2;
healthBarContainer.y = 110;
LK.gui.top.addChild(healthBarContainer);
// --- Kill Counter below Health Bar (top center) ---
var healthBarKillCounterText = new Text2("0", {
size: 54,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
healthBarKillCounterText.anchor.set(0.5, 0); // center anchor, top edge
healthBarKillCounterText.x = GAME_WIDTH / 2;
healthBarKillCounterText.y = healthBarContainer.y + 32; // just below health bar
LK.gui.top.addChild(healthBarKillCounterText);
// Helper to update health bar
function updateHealthBar() {
var percent = rocketLife / ROCKET_START_LIFE;
if (percent < 0) {
percent = 0;
}
if (percent > 1) {
percent = 1;
}
healthBar.width = 400 * percent;
if (percent > 0.5) {
healthBar.tint = 0x43a047;
} else if (percent > 0.2) {
healthBar.tint = 0xffc107;
} else {
healthBar.tint = 0xd32f2f;
}
}
// Initial GUI
// updateLevelText and updateLevelBar removed
updateScoreText();
updateHealthBar();
// Touch/move controls
game.down = function (x, y, obj) {
// Only start drag if touch is on rocket
var local = rocket.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -rocket.width / 2 && local.x < rocket.width / 2 && local.y > -rocket.height / 2 && local.y < rocket.height / 2) {
dragNode = rocket;
lastMoveX = x;
lastMoveY = y;
}
};
game.move = function (x, y, obj) {
// Always move the rocket to the mouse/touch position, clamped to screen
var newX = x;
var halfW = rocket && rocket.width ? rocket.width / 2 : 70; // fallback to 70 if rocket is null
if (newX < halfW) {
newX = halfW;
}
if (newX > GAME_WIDTH - halfW) {
newX = GAME_WIDTH - halfW;
}
if (rocket) {
rocket.x = newX;
// Y position stays fixed at the starting Y
rocket.y = GAME_HEIGHT - 400;
}
lastMoveX = x;
lastMoveY = y;
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Tap to shoot (left mouse button or tap)
game.down = function (x, y, obj) {
// Only start drag if touch is on rocket
var local = rocket.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -rocket.width / 2 && local.x < rocket.width / 2 && local.y > -rocket.height / 2 && local.y < rocket.height / 2) {
dragNode = rocket;
lastMoveX = x;
lastMoveY = y;
}
// Always allow shooting with left mouse button/tap, regardless of drag state
if (canShoot) {
shootBullet();
}
};
// Shoot bullet
function shootBullet() {
if (!canShoot) {
return;
}
var bullet = new Bullet();
bullet.x = rocket.x;
bullet.y = rocket.y - rocket.height / 2 - 20;
bullets.push(bullet);
game.addChild(bullet);
// Play laser gun sound effect
LK.getSound('dfds').play();
canShoot = false;
shootCooldown = 10; // 10 ticks cooldown
}
// Main update loop
game.update = function () {
// Shooting cooldown
if (!canShoot) {
shootCooldown--;
if (shootCooldown <= 0) {
canShoot = true;
}
}
// --- Shield logic update ---
if (rocketShieldActive) {
rocketShieldTimer--;
// Keep shield visual in sync with rocket
if (rocket && rocketShieldVisual && rocket.children.indexOf(rocketShieldVisual) === -1) {
rocket.addChild(rocketShieldVisual);
if (rocket.children.length > 1) {
rocket.setChildIndex(rocketShieldVisual, 0);
}
}
if (rocketShieldTimer <= 0) {
rocketShieldActive = false;
rocketShieldTimer = 0;
// Remove shield visual
if (rocketShieldVisual && rocket) {
rocket.removeChild(rocketShieldVisual);
}
rocketShieldVisual = null;
}
} else {
// Defensive: remove shield visual if not active
if (rocketShieldVisual && rocket) {
rocket.removeChild(rocketShieldVisual);
rocketShieldVisual = null;
}
}
// Update stars
for (var si = 0; si < stars.length; ++si) {
stars[si].update();
}
// Keep score counter aligned with rocket
scoreTxt.x = rocket.x;
scoreTxt.y = rocket.y - rocket.height / 2 - 40; // 40px above rocket top
// Move rocket kill counter above rocket
if (typeof rocketKillCounterText !== "undefined" && rocket) {
rocketKillCounterText.x = rocket.x;
rocketKillCounterText.y = rocket.y - rocket.height / 2 - 60;
}
// Move kill counter to the right of the rocket, just above it
if (typeof killCounterText !== "undefined" && rocket) {
killCounterText.x = rocket.x + rocket.width / 2 + 32;
killCounterText.y = rocket.y - rocket.height / 2 - 40;
}
// Move rocket health bar with rocket
if (typeof rocketLifeBarContainer !== "undefined") {
rocketLifeBarContainer.x = rocket.x;
rocketLifeBarContainer.y = rocket.y + rocket.height / 2 + 12; // 12px below rocket
// Update width and color
var percent = rocketLife / ROCKET_START_LIFE;
if (percent < 0) {
percent = 0;
}
rocketLifeBar.width = 220 * percent;
if (percent > 0.5) {
rocketLifeBar.tint = 0x43a047;
} else if (percent > 0.2) {
rocketLifeBar.tint = 0xffc107;
} else {
rocketLifeBar.tint = 0xd32f2f;
}
// Do NOT change rocket color based on health
}
// (level bar stays fixed in GUI, do not move with rocket)
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update aliens
for (var j = aliens.length - 1; j >= 0; --j) {
var a = aliens[j];
a.update();
// Remove if off screen
if (a.y > GAME_HEIGHT + 200) {
a.destroy();
aliens.splice(j, 1);
continue;
}
// Alien shooting logic: all aliens shoot every eligible tick (no randomness, no alignment check)
if (level > 1 && a.y > 0 && a.y < GAME_HEIGHT - 400) {
if (LK.ticks % Math.max(60 - level * 4, 18) === 0) {
if (level >= 5) {
// Shoot two bullets, slightly offset horizontally
var offset = 38;
for (var bidx = -1; bidx <= 1; bidx += 2) {
var enemyBullet = new EnemyBullet();
enemyBullet.x = a.x + bidx * offset;
enemyBullet.y = a.y + a.height / 2 + 10;
enemyBullets.push(enemyBullet);
game.addChild(enemyBullet);
}
} else {
// Shoot one bullet as before
var enemyBullet = new EnemyBullet();
enemyBullet.x = a.x;
enemyBullet.y = a.y + a.height / 2 + 10;
enemyBullets.push(enemyBullet);
game.addChild(enemyBullet);
}
}
}
// Check collision with rocket (alien-rocket contact)
if (a.intersects(rocket)) {
if (!rocketShieldActive && rocketLife > 0) {
rocketLife--;
updateHealthBar();
rocket.flash();
// Destroy rocket if it has taken 5 damage
if (rocketLife <= 0) {
// Play rocket explosion sound when rocket's life reaches zero
LK.getSound('patlama').play();
if (rocket && typeof rocket.destroy === "function") {
rocket.destroy();
rocket = null;
}
}
}
// Remove alien on contact
a.destroy();
aliens.splice(j, 1);
// Check for game over
if (rocketLife <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('patlama').play();
LK.showGameOver();
return;
}
}
// No alien-rocket collision: aliens do not damage rocket by contact
}
// Update enemy bullets
for (var eb = enemyBullets.length - 1; eb >= 0; --eb) {
var ebull = enemyBullets[eb];
ebull.update();
// Remove if off screen
if (ebull.y > GAME_HEIGHT + 100) {
ebull.destroy();
enemyBullets.splice(eb, 1);
continue;
}
// Check collision with rocket
if (ebull.intersects(rocket)) {
if (!rocketShieldActive && rocketLife > 0) {
if (level >= 6) {
rocketLife = 0;
} else {
rocketLife -= 0.5;
}
updateHealthBar();
rocket.flash();
// Destroy rocket if it has taken 5 damage
if (rocketLife <= 0) {
if (rocket && typeof rocket.destroy === "function") {
// Play rocket explosion sound
LK.getSound('patlama').play();
rocket.destroy();
rocket = null;
}
}
}
ebull.destroy();
enemyBullets.splice(eb, 1);
// Check for game over
if (rocketLife <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Bullet-alien collisions
for (var i2 = bullets.length - 1; i2 >= 0; --i2) {
var b2 = bullets[i2];
for (var j2 = aliens.length - 1; j2 >= 0; --j2) {
var a2 = aliens[j2];
if (b2.intersects(a2)) {
a2.hp -= b2.power !== undefined ? b2.power : 1; // Use bullet power, fallback to 1
a2.flash();
b2.destroy();
bullets.splice(i2, 1);
if (a2.hp <= 0) {
a2.destroy();
aliens.splice(j2, 1);
score++;
updateScoreText();
updateLevelBar();
// Increase level every 10 kills
if (level < LEVEL_TO_BOSS && score % 10 === 0) {
level++;
// Flash the screen to indicate level up
LK.effects.flashScreen(0xffffff, 600); // White flash for 600ms
// Activate 4s shield when reaching level 3
if (level === 3) {
rocketShieldActive = true;
rocketShieldTimer = 240; // 4 seconds at 60 FPS
// Add shield visual if not present
if (!rocketShieldVisual && rocket) {
rocketShieldVisual = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.1,
scaleY: 2.1,
x: 0,
y: 0,
color: 0x2196f3,
tint: 0x2196f3
});
rocketShieldVisual.alpha = 0.38;
rocket.addChild(rocketShieldVisual);
// Make sure shield is behind rocket sprite
if (rocket.children.length > 1) {
rocket.setChildIndex(rocketShieldVisual, 0);
}
}
}
// End game after level 6 (when level becomes 7)
if (level === LEVEL_TO_BOSS) {
LK.effects.flashScreen(0x00e676, 1000);
LK.showYouWin();
return;
}
bulletPower = 1; // Always 1, so all enemies take 2 hits
rocketLife = ROCKET_START_LIFE; // Full heal on level up
updateHealthBar();
updateLevelBar();
// Star explosion effect at center of screen
for (var sx = 0; sx < 18; ++sx) {
(function (sx) {
var star = new Star();
star.x = GAME_WIDTH / 2;
star.y = GAME_HEIGHT / 2;
// Give each star a random direction and speed
var angle = Math.PI * 2 * (sx / 18);
var speed = 18 + Math.random() * 12;
var vx = Math.cos(angle) * speed;
var vy = Math.sin(angle) * speed;
var life = 32 + Math.floor(Math.random() * 16);
var tick = 0;
// Animate star outward and fade out
star.update = function () {
star.x += vx;
star.y += vy;
star.alpha -= 0.025;
tick++;
if (tick > life || star.alpha <= 0) {
star.destroy();
}
};
game.addChild(star);
})(sx);
}
// Change all background star colors
var colorChoices = [0xffffff, 0xe3f2fd, 0xfffde7, 0xb3e5fc, 0xfff9c4, 0xffb3c6, 0xc5e1a5, 0xffcc80, 0x90caf9, 0xf8bbd0];
for (var sc = 0; sc < stars.length; ++sc) {
var starObj = stars[sc];
// Only change tint if starObj has children and a valid asset
if (starObj.children && starObj.children.length > 0 && starObj.children[0]) {
var newColor = colorChoices[Math.floor(Math.random() * colorChoices.length)];
starObj.children[0].tint = newColor;
}
}
// Add more stars to the background on each level up
var additionalStars = 8; // Number of stars to add per level up
for (var addStar = 0; addStar < additionalStars; ++addStar) {
var newStar = new Star();
newStar.x = 10 + Math.random() * (GAME_WIDTH - 20);
newStar.y = Math.random() * GAME_HEIGHT;
stars.push(newStar);
game.addChildAt(newStar, 0); // Add behind all other objects
}
}
// If boss defeated, win
if (level === LEVEL_TO_BOSS && bossSpawned && aliens.length === 0) {
LK.effects.flashScreen(0x00e676, 1000);
LK.showYouWin();
return;
}
}
break;
}
}
}
// Alien spawn logic
if (level < LEVEL_TO_BOSS) {
// Increase max aliens on screen as level increases
var maxAliens = 2 + Math.floor((level - 1) / 2); // +1 every 2 levels (2,3,4,5...)
// Double the number of aliens on level 5 and above
if (level >= 5) {
maxAliens *= 2;
}
// Increase spawn rate as level increases
var spawnRate = Math.max(1, 1 + Math.floor((level - 1) / 2)); // +1 spawn per 2 levels
if (level >= 5) {
spawnRate *= 2;
}
if (aliens.length < maxAliens && LK.ticks % (60 - level * 4) === 0) {
for (var s = 0; s < spawnRate && aliens.length < maxAliens; ++s) {
spawnAlien();
}
}
} else if (level === LEVEL_TO_BOSS && !bossSpawned) {
// Spawn boss
spawnAlien();
}
};
// --- Level Bar (next to Seviye text) ---
// Level text
var levelText = new Text2("Seviye", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
levelText.anchor.set(1, 0.5);
// Level bar background
var levelBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0,
anchorY: 0.5,
width: 420,
height: 64,
x: 0,
y: 0
});
// Level bar fill (fills with each kill)
var levelBar = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0.5,
width: 420,
height: 48,
x: 0,
y: 0,
color: 0x2196f3,
tint: 0x2196f3 // blue
});
// Container for text and bar
var levelBarContainer = new Container();
// Kill counter text (will be placed to the right of the rocket)
var killCounterText = new Text2("0", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
killCounterText.anchor.set(0, 0.5); // left anchor for right-of-rocket placement
// Level number text (shows current level, right of 'Seviye')
var levelNumberText = new Text2(level.toString(), {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
levelText.anchor.set(1, 0.5);
levelNumberText.anchor.set(0, 0.5);
// Place 'Seviye', then bar, then number (kill counter will be right of rocket, not in this container)
levelText.x = 0;
levelText.y = 0;
var gapBetween = 24; // small gap between 'Seviye' and bar
var barStartX = levelText.x + levelText.width + gapBetween;
levelBarBg.x = barStartX;
levelBar.x = barStartX;
levelBarBg.y = 0;
levelBar.y = 0;
// Center the level number between 'Seviye' and the bar
levelNumberText.x = barStartX / 2 + levelText.x / 2 - levelNumberText.width / 2;
levelNumberText.y = 0;
// Only add levelText, levelNumberText, levelBarBg, levelBar to container
levelBarContainer.addChild(levelText);
levelBarContainer.addChild(levelNumberText);
levelBarContainer.addChild(levelBarBg);
levelBarContainer.addChild(levelBar);
// Position: move level bar container further left (reduce left margin)
levelBarContainer.x = 10;
levelBarContainer.y = 66;
LK.gui.top.addChild(levelBarContainer);
// Place kill counter to the right of the rocket, just above it
killCounterText.x = typeof rocket !== "undefined" && rocket ? rocket.x + (rocket.width ? rocket.width / 2 : 70) + 32 : GAME_WIDTH / 2 + 140;
killCounterText.y = typeof rocket !== "undefined" && rocket ? rocket.y - (rocket.height ? rocket.height / 2 : 110) - 40 : GAME_HEIGHT - 400 - 110 - 40;
LK.gui.top.addChild(killCounterText);
// Helper to update level bar and level text
function updateLevelBar() {
// Progress to next level: score % 10 (10 kills per level)
var killsThisLevel = score % 10;
if (killsThisLevel < 0) {
killsThisLevel = 0;
}
if (killsThisLevel > 10) {
killsThisLevel = 10;
}
// Each kill paints a segment of the bar
var segmentCount = 10;
var segmentWidth = 420 / segmentCount; // Match new bar width
var targetWidth = segmentWidth * killsThisLevel;
// Animate the level bar fill width to visually show progress
if (typeof levelBar.lastWidth === "undefined") {
levelBar.lastWidth = 0;
}
if (Math.abs(levelBar.width - targetWidth) > 2) {
// Animate width smoothly
if (!levelBar.widthTween) {
levelBar.widthTween = tween(levelBar, {
width: targetWidth
}, {
duration: 250,
easing: tween.linear,
onFinish: function onFinish() {
levelBar.widthTween = null;
levelBar.width = targetWidth;
levelBar.lastWidth = targetWidth;
}
});
}
} else {
// Snap to target if very close
if (levelBar.widthTween) {
tween.stop(levelBar, {
width: true
});
levelBar.widthTween = null;
}
levelBar.width = targetWidth;
levelBar.lastWidth = targetWidth;
}
// Color: fill blue on every kill
levelBar.tint = 0x2196f3; // blue
// Update level text (static, just "Seviye")
if (typeof levelText !== "undefined") {
levelText.setText("Seviye");
}
// Update level number text to show current level
if (typeof levelNumberText !== "undefined") {
levelNumberText.setText(level.toString());
}
}
// Update level bar on score change and level up
var oldUpdateScoreText = updateScoreText;
updateLevelBar();
// Initial spawn
spawnAlien();
// Play background music at game start
LK.playMusic('Bckgrnd');
// Play background music at game start
LK.playMusic('Bckgrnd'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Alien class
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = alienAsset.width;
self.height = alienAsset.height;
self.hp = 2; // Each alien takes 2 hits (all aliens always 2 hits)
self.isHit = false;
self.hitTween = null;
// For hit flash
self.flash = function () {
// If a previous hitTween is running, stop it
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
// Set alien to red tint
alienAsset.tint = 0xff5252;
// Tween back to normal color (no tint) over 120ms
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 8 + Math.random() * 4; // Slightly random speed
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
// Bigger Alien class (for level > 3, 3 hits to kill, larger)
var BiggerAlien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.width = alienAsset.width * 1.5;
self.height = alienAsset.height * 1.5;
self.hp = 2; // Takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
alienAsset.tint = 0xff5252;
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 10 + Math.random() * 2; // Slightly slower than strong alien
self.update = function () {
self.y += self.speed;
};
return self;
});
// Boss Alien class (for level 7)
var BossAlien = Container.expand(function () {
var self = Container.call(this);
var bossAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.7,
scaleY: 1.7
});
self.width = bossAsset.width * 1.7;
self.height = bossAsset.height * 1.7;
self.hp = 2; // Boss takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(bossAsset, {
tint: true
});
}
bossAsset.tint = 0xff5252;
self.hitTween = tween(bossAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
self.speed = 10; // Boss is faster
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -32; // Upwards
self.power = bulletPower; // Set bullet power at creation
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy bullet class (alien shoots at player)
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
bulletAsset.tint = 0xff5252; // Red tint for enemy bullets
self.speed = 27; // Downwards, 1.5x faster than before
self.update = function () {
self.y += self.speed;
};
return self;
});
// Rocket (player) class
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketAsset = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rocketAsset.width;
self.height = rocketAsset.height;
// For hit flash
self.flashTween = null;
// Show hit flash
self.flash = function () {
// If a previous flashTween is running, stop it
if (self.flashTween) {
tween.stop(rocketAsset, {
tint: true
});
}
// Set rocket to reddish tint
rocketAsset.tint = 0xff5252;
// Tween back to normal color (white) over 200ms
self.flashTween = tween(rocketAsset, {
tint: 0xffffff
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
self.flashTween = null;
}
});
};
return self;
});
// Star class for animated background stars
var Star = Container.expand(function () {
var self = Container.call(this);
// Use a larger ellipse for the star to make it more visible
var size = 6 + Math.random() * 8; // Increased min and max size
var starAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 160,
scaleY: size / 160
});
// Brighter color choices for more visibility
var colorChoices = [0xffffff, 0xe3f2fd, 0xfffde7, 0xb3e5fc, 0xfff9c4];
starAsset.tint = colorChoices[Math.floor(Math.random() * colorChoices.length)];
self.width = size;
self.height = size;
self.speed = 2.5 + Math.random() * 4.5;
// Higher minimum alpha for more visible stars
self.alpha = 0.7 + Math.random() * 0.3;
self.update = function () {
self.y += self.speed;
if (self.y > GAME_HEIGHT + 10) {
// Respawn at top
self.y = -10;
self.x = 10 + Math.random() * (GAME_WIDTH - 20);
self.speed = 2.5 + Math.random() * 4.5;
self.alpha = 0.7 + Math.random() * 0.3;
}
};
return self;
});
// Strong Alien class (tougher, faster)
var StrongAlien = Container.expand(function () {
var self = Container.call(this);
var alienAsset = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.width = alienAsset.width * 1.2;
self.height = alienAsset.height * 1.2;
self.hp = 2; // Strong alien takes 2 hits (all enemies always 2 hits)
self.isHit = false;
self.hitTween = null;
self.flash = function () {
if (self.hitTween) {
tween.stop(alienAsset, {
tint: true
});
}
alienAsset.tint = 0xff5252;
self.hitTween = tween(alienAsset, {
tint: 0xffffff
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
self.hitTween = null;
}
});
};
// For movement
self.speed = 12 + Math.random() * 3; // Stronger and faster
self.update = function () {
// Only move downwards, do not follow rocket's x position
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
// Rocket (player)
// Alien (enemy)
// Bullet
// Alien hit flash
// Life bar
// Life bar background
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// --- Kill Counter (top right) ---
var killNumberText = new Text2("0", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
killNumberText.anchor.set(1, 0); // right anchor, top edge
killNumberText.x = GAME_WIDTH - 40;
killNumberText.y = 40;
LK.gui.top.addChild(killNumberText);
// --- Starfield background ---
var stars = [];
var STAR_COUNT = 60;
for (var i = 0; i < STAR_COUNT; ++i) {
var star = new Star();
star.x = 10 + Math.random() * (GAME_WIDTH - 20);
star.y = Math.random() * GAME_HEIGHT;
stars.push(star);
game.addChildAt(star, 0); // Add behind all other objects
}
var ROCKET_START_LIFE = 5;
var LEVEL_TO_BOSS = 7;
// Game state
var rocket = null;
var bullets = [];
var aliens = [];
var level = 1;
var rocketLife = ROCKET_START_LIFE;
var bulletPower = 1; // Bullet power, increases every level
var canShoot = true;
var shootCooldown = 0;
var dragNode = null;
var lastMoveX = 0;
var lastMoveY = 0;
var score = 0;
var bossSpawned = false;
var enemyBullets = []; // Track enemy bullets
// --- Shield state for rocket ---
var rocketShieldActive = false;
var rocketShieldTimer = 0;
var rocketShieldVisual = null;
// GUI elements
var scoreTxt = new Text2('0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 1);
// Ensure score is always visible
scoreTxt.alpha = 1;
scoreTxt.visible = true;
// Position the score text horizontally aligned with the rocket, above it
scoreTxt.x = GAME_WIDTH / 2;
scoreTxt.y = GAME_HEIGHT - 400 - (rocket ? rocket.height / 2 : 110) - 40; // 40px above rocket top, fallback if rocket not yet created
LK.gui.top.addChild(scoreTxt);
if (LK.gui.top.children && LK.gui.top.children.length > 1) {
LK.gui.top.setChildIndex(scoreTxt, LK.gui.top.children.length - 1);
}
// New health bar will be created below
// updateLevelBar and updateLevelText helpers removed as level bar is no longer shown
// Helper to update score text
function updateScoreText() {
scoreTxt.setText(score);
// Update kill counter text (if defined)
if (typeof killCounterText !== "undefined") {
killCounterText.setText(score.toString());
}
// Update kill number text (top right)
if (typeof killNumberText !== "undefined") {
killNumberText.setText(score.toString());
}
// Update health bar kill counter text (if defined)
if (typeof healthBarKillCounterText !== "undefined") {
healthBarKillCounterText.setText(score.toString());
}
// Update rocket kill counter text (above rocket)
if (typeof rocketKillCounterText !== "undefined") {
rocketKillCounterText.setText(score.toString());
}
// updateLevelBar removed
}
// Spawn a new alien
function spawnAlien() {
var alien;
if (level === LEVEL_TO_BOSS && !bossSpawned) {
alien = new BossAlien();
alien.hp = 2; // Boss always 2 hits
bossSpawned = true;
} else {
// 20% chance to spawn a BiggerAlien after level 3, 30% StrongAlien, otherwise normal Alien
if (level > 3 && Math.random() < 0.2) {
alien = new BiggerAlien();
alien.hp = 2; // Always 2 hits for bigger alien
} else if (Math.random() < 0.3 && level > 2) {
alien = new StrongAlien();
alien.hp = 2; // Always 2 hits for strong alien
} else {
alien = new Alien();
alien.hp = 2; // Always 2 hits for normal alien
}
}
// Defensive: always set hp to 2 for all enemy types
if (alien) {
alien.hp = 2;
// 1. seviyede düşmanlar 1.5 kat hızlı gelsin
if (level === 1 && typeof alien.speed === "number") {
alien.speed *= 1.5;
}
}
// Random x, but keep inside screen
var margin = 120;
alien.x = margin + Math.random() * (GAME_WIDTH - margin * 2);
alien.y = -alien.height / 2;
aliens.push(alien);
game.addChild(alien);
}
// Reset game state
function resetGame() {
// Remove all bullets and aliens
for (var i = 0; i < bullets.length; ++i) {
bullets[i].destroy();
}
for (var j = 0; j < aliens.length; ++j) {
aliens[j].destroy();
}
for (var k = 0; k < enemyBullets.length; ++k) {
enemyBullets[k].destroy();
}
bullets = [];
aliens = [];
enemyBullets = [];
level = 1;
rocketLife = ROCKET_START_LIFE;
bulletPower = 1; // Always 1, so all enemies take 2 hits
canShoot = true;
shootCooldown = 0;
dragNode = null;
lastMoveX = 0;
lastMoveY = 0;
score = 0;
bossSpawned = false;
// updateLevelText and updateLevelBar removed
updateScoreText();
updateLevelBar();
updateHealthBar();
}
// Initialize rocket
rocket = new Rocket();
rocket.x = GAME_WIDTH / 2;
rocket.y = GAME_HEIGHT - 400;
game.addChild(rocket);
// --- Rocket health bar that follows rocket ---
var rocketLifeBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 0,
width: 220,
height: 18
});
var rocketLifeBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0,
x: -110,
y: 0,
width: 220,
height: 18
});
var rocketLifeBarContainer = new Container();
rocketLifeBarContainer.addChild(rocketLifeBarBg);
rocketLifeBarContainer.addChild(rocketLifeBar);
rocketLifeBarContainer.x = rocket.x;
rocketLifeBarContainer.y = rocket.y + rocket.height / 2 + 12; // 12px below rocket
game.addChild(rocketLifeBarContainer);
// Move scoreTxt to be above the rocket, horizontally aligned
scoreTxt.x = rocket.x;
scoreTxt.y = rocket.y - rocket.height / 2 - 40; // 40px above rocket top
// --- Kill Counter above Rocket ---
// Create kill counter text to be placed above the rocket
var rocketKillCounterText = new Text2("0", {
size: 54,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
rocketKillCounterText.anchor.set(0.5, 1); // center anchor, bottom edge
rocketKillCounterText.x = rocket.x;
rocketKillCounterText.y = rocket.y - rocket.height / 2 - 60; // 60px above rocket top
game.addChild(rocketKillCounterText);
// --- New Health Bar (top center) ---
var healthBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 440,
height: 44,
x: 0,
y: 0
});
var healthBar = LK.getAsset('lifeBar', {
anchorX: 0,
anchorY: 0.5,
width: 400,
height: 36,
x: -200,
y: 0
});
var healthBarContainer = new Container();
healthBarContainer.addChild(healthBarBg);
healthBarContainer.addChild(healthBar);
healthBarContainer.x = GAME_WIDTH / 2;
healthBarContainer.y = 110;
LK.gui.top.addChild(healthBarContainer);
// --- Kill Counter below Health Bar (top center) ---
var healthBarKillCounterText = new Text2("0", {
size: 54,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
healthBarKillCounterText.anchor.set(0.5, 0); // center anchor, top edge
healthBarKillCounterText.x = GAME_WIDTH / 2;
healthBarKillCounterText.y = healthBarContainer.y + 32; // just below health bar
LK.gui.top.addChild(healthBarKillCounterText);
// Helper to update health bar
function updateHealthBar() {
var percent = rocketLife / ROCKET_START_LIFE;
if (percent < 0) {
percent = 0;
}
if (percent > 1) {
percent = 1;
}
healthBar.width = 400 * percent;
if (percent > 0.5) {
healthBar.tint = 0x43a047;
} else if (percent > 0.2) {
healthBar.tint = 0xffc107;
} else {
healthBar.tint = 0xd32f2f;
}
}
// Initial GUI
// updateLevelText and updateLevelBar removed
updateScoreText();
updateHealthBar();
// Touch/move controls
game.down = function (x, y, obj) {
// Only start drag if touch is on rocket
var local = rocket.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -rocket.width / 2 && local.x < rocket.width / 2 && local.y > -rocket.height / 2 && local.y < rocket.height / 2) {
dragNode = rocket;
lastMoveX = x;
lastMoveY = y;
}
};
game.move = function (x, y, obj) {
// Always move the rocket to the mouse/touch position, clamped to screen
var newX = x;
var halfW = rocket && rocket.width ? rocket.width / 2 : 70; // fallback to 70 if rocket is null
if (newX < halfW) {
newX = halfW;
}
if (newX > GAME_WIDTH - halfW) {
newX = GAME_WIDTH - halfW;
}
if (rocket) {
rocket.x = newX;
// Y position stays fixed at the starting Y
rocket.y = GAME_HEIGHT - 400;
}
lastMoveX = x;
lastMoveY = y;
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Tap to shoot (left mouse button or tap)
game.down = function (x, y, obj) {
// Only start drag if touch is on rocket
var local = rocket.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -rocket.width / 2 && local.x < rocket.width / 2 && local.y > -rocket.height / 2 && local.y < rocket.height / 2) {
dragNode = rocket;
lastMoveX = x;
lastMoveY = y;
}
// Always allow shooting with left mouse button/tap, regardless of drag state
if (canShoot) {
shootBullet();
}
};
// Shoot bullet
function shootBullet() {
if (!canShoot) {
return;
}
var bullet = new Bullet();
bullet.x = rocket.x;
bullet.y = rocket.y - rocket.height / 2 - 20;
bullets.push(bullet);
game.addChild(bullet);
// Play laser gun sound effect
LK.getSound('dfds').play();
canShoot = false;
shootCooldown = 10; // 10 ticks cooldown
}
// Main update loop
game.update = function () {
// Shooting cooldown
if (!canShoot) {
shootCooldown--;
if (shootCooldown <= 0) {
canShoot = true;
}
}
// --- Shield logic update ---
if (rocketShieldActive) {
rocketShieldTimer--;
// Keep shield visual in sync with rocket
if (rocket && rocketShieldVisual && rocket.children.indexOf(rocketShieldVisual) === -1) {
rocket.addChild(rocketShieldVisual);
if (rocket.children.length > 1) {
rocket.setChildIndex(rocketShieldVisual, 0);
}
}
if (rocketShieldTimer <= 0) {
rocketShieldActive = false;
rocketShieldTimer = 0;
// Remove shield visual
if (rocketShieldVisual && rocket) {
rocket.removeChild(rocketShieldVisual);
}
rocketShieldVisual = null;
}
} else {
// Defensive: remove shield visual if not active
if (rocketShieldVisual && rocket) {
rocket.removeChild(rocketShieldVisual);
rocketShieldVisual = null;
}
}
// Update stars
for (var si = 0; si < stars.length; ++si) {
stars[si].update();
}
// Keep score counter aligned with rocket
scoreTxt.x = rocket.x;
scoreTxt.y = rocket.y - rocket.height / 2 - 40; // 40px above rocket top
// Move rocket kill counter above rocket
if (typeof rocketKillCounterText !== "undefined" && rocket) {
rocketKillCounterText.x = rocket.x;
rocketKillCounterText.y = rocket.y - rocket.height / 2 - 60;
}
// Move kill counter to the right of the rocket, just above it
if (typeof killCounterText !== "undefined" && rocket) {
killCounterText.x = rocket.x + rocket.width / 2 + 32;
killCounterText.y = rocket.y - rocket.height / 2 - 40;
}
// Move rocket health bar with rocket
if (typeof rocketLifeBarContainer !== "undefined") {
rocketLifeBarContainer.x = rocket.x;
rocketLifeBarContainer.y = rocket.y + rocket.height / 2 + 12; // 12px below rocket
// Update width and color
var percent = rocketLife / ROCKET_START_LIFE;
if (percent < 0) {
percent = 0;
}
rocketLifeBar.width = 220 * percent;
if (percent > 0.5) {
rocketLifeBar.tint = 0x43a047;
} else if (percent > 0.2) {
rocketLifeBar.tint = 0xffc107;
} else {
rocketLifeBar.tint = 0xd32f2f;
}
// Do NOT change rocket color based on health
}
// (level bar stays fixed in GUI, do not move with rocket)
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update aliens
for (var j = aliens.length - 1; j >= 0; --j) {
var a = aliens[j];
a.update();
// Remove if off screen
if (a.y > GAME_HEIGHT + 200) {
a.destroy();
aliens.splice(j, 1);
continue;
}
// Alien shooting logic: all aliens shoot every eligible tick (no randomness, no alignment check)
if (level > 1 && a.y > 0 && a.y < GAME_HEIGHT - 400) {
if (LK.ticks % Math.max(60 - level * 4, 18) === 0) {
if (level >= 5) {
// Shoot two bullets, slightly offset horizontally
var offset = 38;
for (var bidx = -1; bidx <= 1; bidx += 2) {
var enemyBullet = new EnemyBullet();
enemyBullet.x = a.x + bidx * offset;
enemyBullet.y = a.y + a.height / 2 + 10;
enemyBullets.push(enemyBullet);
game.addChild(enemyBullet);
}
} else {
// Shoot one bullet as before
var enemyBullet = new EnemyBullet();
enemyBullet.x = a.x;
enemyBullet.y = a.y + a.height / 2 + 10;
enemyBullets.push(enemyBullet);
game.addChild(enemyBullet);
}
}
}
// Check collision with rocket (alien-rocket contact)
if (a.intersects(rocket)) {
if (!rocketShieldActive && rocketLife > 0) {
rocketLife--;
updateHealthBar();
rocket.flash();
// Destroy rocket if it has taken 5 damage
if (rocketLife <= 0) {
// Play rocket explosion sound when rocket's life reaches zero
LK.getSound('patlama').play();
if (rocket && typeof rocket.destroy === "function") {
rocket.destroy();
rocket = null;
}
}
}
// Remove alien on contact
a.destroy();
aliens.splice(j, 1);
// Check for game over
if (rocketLife <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('patlama').play();
LK.showGameOver();
return;
}
}
// No alien-rocket collision: aliens do not damage rocket by contact
}
// Update enemy bullets
for (var eb = enemyBullets.length - 1; eb >= 0; --eb) {
var ebull = enemyBullets[eb];
ebull.update();
// Remove if off screen
if (ebull.y > GAME_HEIGHT + 100) {
ebull.destroy();
enemyBullets.splice(eb, 1);
continue;
}
// Check collision with rocket
if (ebull.intersects(rocket)) {
if (!rocketShieldActive && rocketLife > 0) {
if (level >= 6) {
rocketLife = 0;
} else {
rocketLife -= 0.5;
}
updateHealthBar();
rocket.flash();
// Destroy rocket if it has taken 5 damage
if (rocketLife <= 0) {
if (rocket && typeof rocket.destroy === "function") {
// Play rocket explosion sound
LK.getSound('patlama').play();
rocket.destroy();
rocket = null;
}
}
}
ebull.destroy();
enemyBullets.splice(eb, 1);
// Check for game over
if (rocketLife <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Bullet-alien collisions
for (var i2 = bullets.length - 1; i2 >= 0; --i2) {
var b2 = bullets[i2];
for (var j2 = aliens.length - 1; j2 >= 0; --j2) {
var a2 = aliens[j2];
if (b2.intersects(a2)) {
a2.hp -= b2.power !== undefined ? b2.power : 1; // Use bullet power, fallback to 1
a2.flash();
b2.destroy();
bullets.splice(i2, 1);
if (a2.hp <= 0) {
a2.destroy();
aliens.splice(j2, 1);
score++;
updateScoreText();
updateLevelBar();
// Increase level every 10 kills
if (level < LEVEL_TO_BOSS && score % 10 === 0) {
level++;
// Flash the screen to indicate level up
LK.effects.flashScreen(0xffffff, 600); // White flash for 600ms
// Activate 4s shield when reaching level 3
if (level === 3) {
rocketShieldActive = true;
rocketShieldTimer = 240; // 4 seconds at 60 FPS
// Add shield visual if not present
if (!rocketShieldVisual && rocket) {
rocketShieldVisual = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.1,
scaleY: 2.1,
x: 0,
y: 0,
color: 0x2196f3,
tint: 0x2196f3
});
rocketShieldVisual.alpha = 0.38;
rocket.addChild(rocketShieldVisual);
// Make sure shield is behind rocket sprite
if (rocket.children.length > 1) {
rocket.setChildIndex(rocketShieldVisual, 0);
}
}
}
// End game after level 6 (when level becomes 7)
if (level === LEVEL_TO_BOSS) {
LK.effects.flashScreen(0x00e676, 1000);
LK.showYouWin();
return;
}
bulletPower = 1; // Always 1, so all enemies take 2 hits
rocketLife = ROCKET_START_LIFE; // Full heal on level up
updateHealthBar();
updateLevelBar();
// Star explosion effect at center of screen
for (var sx = 0; sx < 18; ++sx) {
(function (sx) {
var star = new Star();
star.x = GAME_WIDTH / 2;
star.y = GAME_HEIGHT / 2;
// Give each star a random direction and speed
var angle = Math.PI * 2 * (sx / 18);
var speed = 18 + Math.random() * 12;
var vx = Math.cos(angle) * speed;
var vy = Math.sin(angle) * speed;
var life = 32 + Math.floor(Math.random() * 16);
var tick = 0;
// Animate star outward and fade out
star.update = function () {
star.x += vx;
star.y += vy;
star.alpha -= 0.025;
tick++;
if (tick > life || star.alpha <= 0) {
star.destroy();
}
};
game.addChild(star);
})(sx);
}
// Change all background star colors
var colorChoices = [0xffffff, 0xe3f2fd, 0xfffde7, 0xb3e5fc, 0xfff9c4, 0xffb3c6, 0xc5e1a5, 0xffcc80, 0x90caf9, 0xf8bbd0];
for (var sc = 0; sc < stars.length; ++sc) {
var starObj = stars[sc];
// Only change tint if starObj has children and a valid asset
if (starObj.children && starObj.children.length > 0 && starObj.children[0]) {
var newColor = colorChoices[Math.floor(Math.random() * colorChoices.length)];
starObj.children[0].tint = newColor;
}
}
// Add more stars to the background on each level up
var additionalStars = 8; // Number of stars to add per level up
for (var addStar = 0; addStar < additionalStars; ++addStar) {
var newStar = new Star();
newStar.x = 10 + Math.random() * (GAME_WIDTH - 20);
newStar.y = Math.random() * GAME_HEIGHT;
stars.push(newStar);
game.addChildAt(newStar, 0); // Add behind all other objects
}
}
// If boss defeated, win
if (level === LEVEL_TO_BOSS && bossSpawned && aliens.length === 0) {
LK.effects.flashScreen(0x00e676, 1000);
LK.showYouWin();
return;
}
}
break;
}
}
}
// Alien spawn logic
if (level < LEVEL_TO_BOSS) {
// Increase max aliens on screen as level increases
var maxAliens = 2 + Math.floor((level - 1) / 2); // +1 every 2 levels (2,3,4,5...)
// Double the number of aliens on level 5 and above
if (level >= 5) {
maxAliens *= 2;
}
// Increase spawn rate as level increases
var spawnRate = Math.max(1, 1 + Math.floor((level - 1) / 2)); // +1 spawn per 2 levels
if (level >= 5) {
spawnRate *= 2;
}
if (aliens.length < maxAliens && LK.ticks % (60 - level * 4) === 0) {
for (var s = 0; s < spawnRate && aliens.length < maxAliens; ++s) {
spawnAlien();
}
}
} else if (level === LEVEL_TO_BOSS && !bossSpawned) {
// Spawn boss
spawnAlien();
}
};
// --- Level Bar (next to Seviye text) ---
// Level text
var levelText = new Text2("Seviye", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
levelText.anchor.set(1, 0.5);
// Level bar background
var levelBarBg = LK.getAsset('lifeBarBg', {
anchorX: 0,
anchorY: 0.5,
width: 420,
height: 64,
x: 0,
y: 0
});
// Level bar fill (fills with each kill)
var levelBar = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0.5,
width: 420,
height: 48,
x: 0,
y: 0,
color: 0x2196f3,
tint: 0x2196f3 // blue
});
// Container for text and bar
var levelBarContainer = new Container();
// Kill counter text (will be placed to the right of the rocket)
var killCounterText = new Text2("0", {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
killCounterText.anchor.set(0, 0.5); // left anchor for right-of-rocket placement
// Level number text (shows current level, right of 'Seviye')
var levelNumberText = new Text2(level.toString(), {
size: 68,
fill: "#fff",
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
shadow: {
color: 0x1976D2,
blur: 8,
offsetX: 0,
offsetY: 2
}
});
levelText.anchor.set(1, 0.5);
levelNumberText.anchor.set(0, 0.5);
// Place 'Seviye', then bar, then number (kill counter will be right of rocket, not in this container)
levelText.x = 0;
levelText.y = 0;
var gapBetween = 24; // small gap between 'Seviye' and bar
var barStartX = levelText.x + levelText.width + gapBetween;
levelBarBg.x = barStartX;
levelBar.x = barStartX;
levelBarBg.y = 0;
levelBar.y = 0;
// Center the level number between 'Seviye' and the bar
levelNumberText.x = barStartX / 2 + levelText.x / 2 - levelNumberText.width / 2;
levelNumberText.y = 0;
// Only add levelText, levelNumberText, levelBarBg, levelBar to container
levelBarContainer.addChild(levelText);
levelBarContainer.addChild(levelNumberText);
levelBarContainer.addChild(levelBarBg);
levelBarContainer.addChild(levelBar);
// Position: move level bar container further left (reduce left margin)
levelBarContainer.x = 10;
levelBarContainer.y = 66;
LK.gui.top.addChild(levelBarContainer);
// Place kill counter to the right of the rocket, just above it
killCounterText.x = typeof rocket !== "undefined" && rocket ? rocket.x + (rocket.width ? rocket.width / 2 : 70) + 32 : GAME_WIDTH / 2 + 140;
killCounterText.y = typeof rocket !== "undefined" && rocket ? rocket.y - (rocket.height ? rocket.height / 2 : 110) - 40 : GAME_HEIGHT - 400 - 110 - 40;
LK.gui.top.addChild(killCounterText);
// Helper to update level bar and level text
function updateLevelBar() {
// Progress to next level: score % 10 (10 kills per level)
var killsThisLevel = score % 10;
if (killsThisLevel < 0) {
killsThisLevel = 0;
}
if (killsThisLevel > 10) {
killsThisLevel = 10;
}
// Each kill paints a segment of the bar
var segmentCount = 10;
var segmentWidth = 420 / segmentCount; // Match new bar width
var targetWidth = segmentWidth * killsThisLevel;
// Animate the level bar fill width to visually show progress
if (typeof levelBar.lastWidth === "undefined") {
levelBar.lastWidth = 0;
}
if (Math.abs(levelBar.width - targetWidth) > 2) {
// Animate width smoothly
if (!levelBar.widthTween) {
levelBar.widthTween = tween(levelBar, {
width: targetWidth
}, {
duration: 250,
easing: tween.linear,
onFinish: function onFinish() {
levelBar.widthTween = null;
levelBar.width = targetWidth;
levelBar.lastWidth = targetWidth;
}
});
}
} else {
// Snap to target if very close
if (levelBar.widthTween) {
tween.stop(levelBar, {
width: true
});
levelBar.widthTween = null;
}
levelBar.width = targetWidth;
levelBar.lastWidth = targetWidth;
}
// Color: fill blue on every kill
levelBar.tint = 0x2196f3; // blue
// Update level text (static, just "Seviye")
if (typeof levelText !== "undefined") {
levelText.setText("Seviye");
}
// Update level number text to show current level
if (typeof levelNumberText !== "undefined") {
levelNumberText.setText(level.toString());
}
}
// Update level bar on score change and level up
var oldUpdateScoreText = updateScoreText;
updateLevelBar();
// Initial spawn
spawnAlien();
// Play background music at game start
LK.playMusic('Bckgrnd');
// Play background music at game start
LK.playMusic('Bckgrnd');