/**** * 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');