User prompt
karakterimiz mermi olarak healtbar atsın
User prompt
healthbar ı healtbar ın üstüne kaydet
User prompt
can barları full gözüksün
User prompt
demonların boss ların ve bestdemon ın üstünde can barı olsun
User prompt
health bar üstlerinde kalan can yeşil giden can kırmızı yan yatmış dikdörtgenin içinde olsun
User prompt
health bar üstlerinde olsun
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Best Demon (Ultimate Enemy) var BestDemon = Container.expand(function () { var self = Container.call(this); var bestDemonSprite = self.attachAsset('bestdemon', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bestDemonSprite.width * 0.5; self.hp = 120; self.shootCooldown = 0; self.speed = 2.5; self.groundSmashTimer = 0; self.weapons = []; // Array to hold weapon sprites self.healthBar = new HealthBar(); self.healthBar.width = 140; // Largest health bar for best demon self.healthBar.bgBar.scaleX = self.healthBar.width / 32; self.healthBar.hpBar.scaleX = self.healthBar.width / 32; game.addChild(self.healthBar); // Create visual weapons (bestdemongun) for best demon self.updateWeapons = function () { // Remove any existing weapons for (var i = 0; i < self.weapons.length; i++) { self.weapons[i].destroy(); } self.weapons = []; // Create 2 bestdemonguns for best demon (double shot) for (var i = -0.5; i <= 0.5; i++) { var weapon = LK.getAsset('bestdemongun', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // Position bestdemonguns around best demon var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.3; var radius = self.radius * 1.2; weapon.x = Math.cos(angle) * radius; weapon.y = Math.sin(angle) * radius; weapon.rotation = angle + Math.PI / 2; self.addChild(weapon); self.weapons.push(weapon); } }; self.update = function () { // Update health bar if (self.healthBar && !self.dead) { self.healthBar.updateBar(self.hp, 120); self.healthBar.setPosition(self.x, self.y); } // Move toward marine if (marine && !self.dead) { var dx = marine.x - self.x; var dy = marine.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Update weapon positions to match firing direction if (self.weapons.length === 0) { self.updateWeapons(); } else { for (var i = 0; i < self.weapons.length; i++) { var weapon = self.weapons[i]; var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + (i - 0.5) * 0.3; var radius = self.radius * 1.2; weapon.x = Math.cos(angle) * radius; weapon.y = Math.sin(angle) * radius; weapon.rotation = angle + Math.PI / 2; } } // Shoot bestdemonmermi at marine (double shot) if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 1500) { for (var i = -0.5; i <= 0.5; i++) { var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.2; var tx = self.x + Math.cos(angle) * 100; var ty = self.y + Math.sin(angle) * 100; spawnBestDemonBullet(self.x, self.y, tx, ty, 12); } self.shootCooldown = 40; } } }; self.hit = function () { self.hp--; tween(bestDemonSprite, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { tween(bestDemonSprite, { tint: 0x8e7602 }, { duration: 100 }); } }); if (self.hp <= 0) { self.dead = true; // Clean up health bar if (self.healthBar) { self.healthBar.destroy(); } // Add points to score - best demons give triple points var points = doublePointsActive ? 300 : 150; score += points; updateUI(); // Fade out best demon tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); } }; return self; }); // Best Demon Bullet var BestDemonBullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('bestdemonmermi', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletSprite.width * 0.5; self.speed = 16; self.dx = 0; self.dy = 1; self.update = function () { self.x += self.dx * self.speed; self.y += self.dy * self.speed; }; return self; }); // Boss Demon var Boss = Container.expand(function () { var self = Container.call(this); var bossSprite = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bossSprite.width * 0.5; self.hp = 80; self.shootCooldown = 0; self.speed = 3.5; self.groundSmashTimer = 0; // Add this property to track smash cooldown self.weapons = []; // Array to hold weapon sprites self.healthBar = new HealthBar(); self.healthBar.width = 120; // Larger health bar for boss self.healthBar.bgBar.scaleX = self.healthBar.width / 32; self.healthBar.hpBar.scaleX = self.healthBar.width / 32; game.addChild(self.healthBar); // Create visual weapons (tridents) for boss self.updateWeapons = function () { // Remove any existing weapons for (var i = 0; i < self.weapons.length; i++) { self.weapons[i].destroy(); } self.weapons = []; // Create 3 tridents for boss (triple shot) for (var i = -1; i <= 1; i++) { var weapon = LK.getAsset('furca', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); // Position tridents around boss var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.18; var radius = self.radius * 1.1; weapon.x = Math.cos(angle) * radius; weapon.y = Math.sin(angle) * radius; weapon.rotation = angle + Math.PI / 2; self.addChild(weapon); self.weapons.push(weapon); } }; self.update = function () { // Update health bar if (self.healthBar && !self.dead) { self.healthBar.updateBar(self.hp, 80); self.healthBar.setPosition(self.x, self.y); } // Move toward marine if (marine && !self.dead) { var dx = marine.x - self.x; var dy = marine.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Update weapon positions to match firing direction if (self.weapons.length === 0) { self.updateWeapons(); } else { for (var i = 0; i < self.weapons.length; i++) { var weapon = self.weapons[i]; var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + (i - 1) * 0.18; var radius = self.radius * 1.1; weapon.x = Math.cos(angle) * radius; weapon.y = Math.sin(angle) * radius; weapon.rotation = angle + Math.PI / 2; } } // Boss ground smash attack every 8 seconds (480 ticks) if (typeof self.groundSmashTimer === "undefined") self.groundSmashTimer = 0; self.groundSmashTimer++; // 3 seconds (180 ticks) before smash, start color warning if (self.groundSmashTimer === 300) { // Flash red for 1.5 seconds, then orange for 1.5 seconds tween(bossSprite, { tint: 0xff0000 }, { duration: 90, onFinish: function onFinish() { tween(bossSprite, { tint: 0xffa500 }, { duration: 90, onFinish: function onFinish() { // Do nothing, color will be reset after smash } }); } }); } if (self.groundSmashTimer >= 480) { self.groundSmashTimer = 0; // Visual effect: flash boss and screen tween(bossSprite, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(bossSprite, { tint: 0x8e44ad }, { duration: 120 }); } }); LK.effects.flashScreen(0xccccff, 200); // Damage marine if close to boss (melee range) if (marine && !marine.dead && marine.invuln === 0) { var smashDist = bossSprite.width * 1.1; var mdx = marine.x - self.x; var mdy = marine.y - self.y; if (mdx * mdx + mdy * mdy < smashDist * smashDist) { marine.hp -= 2; if (marine.hp < 0) marine.hp = 0; marine.invuln = 60; marine.flash(); updateUI(); if (marine.hp <= 0) { // Game over gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } // Shoot at marine (triple shot) if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 1200) { for (var i = -1; i <= 1; i++) { var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.18; var tx = self.x + Math.cos(angle) * 100; var ty = self.y + Math.sin(angle) * 100; spawnDemonBullet(self.x, self.y, tx, ty, 10); } self.shootCooldown = 50; } } }; self.hit = function () { self.hp--; tween(bossSprite, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { tween(bossSprite, { tint: 0x8e44ad }, { duration: 100 }); } }); if (self.hp <= 0) { self.dead = true; // Clean up health bar if (self.healthBar) { self.healthBar.destroy(); } // Spawn a shield at boss position var shield = new Shield(); shield.x = self.x; shield.y = self.y; game.addChild(shield); // Add points to score - bosses give double points when health pack effect is active var points = doublePointsActive ? 100 : 50; score += points; updateUI(); // Create visual effect for shield drop tween(shield, { y: self.y + 20 }, { duration: 60, onFinish: function onFinish() { tween(shield, { y: self.y }, { duration: 40 }); } }); // Fade out boss tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); } }; return self; }); // Demon (Enemy) var Demon = Container.expand(function () { var self = Container.call(this); var demonSprite = self.attachAsset('demon', { anchorX: 0.5, anchorY: 0.5 }); self.radius = demonSprite.width * 0.5; self.hp = 4; self.shootCooldown = 0; self.speed = 4 + Math.random() * 2; self.weapon = null; // Weapon sprite self.healthBar = new HealthBar(); game.addChild(self.healthBar); // Create visual weapon (trident) for demon self.updateWeapon = function () { // Remove existing weapon if any if (self.weapon) { self.weapon.destroy(); } // Create a furca (trident) for demon self.weapon = LK.getAsset('furca', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Position trident in front of demon if (marine) { var angle = Math.atan2(marine.y - self.y, marine.x - self.x); var radius = self.radius * 1.1; self.weapon.x = Math.cos(angle) * radius; self.weapon.y = Math.sin(angle) * radius; self.weapon.rotation = angle + Math.PI / 2; } else { self.weapon.x = self.radius; self.weapon.y = 0; } self.addChild(self.weapon); }; self.update = function () { // Update health bar if (self.healthBar && !self.dead) { self.healthBar.updateBar(self.hp, 4); self.healthBar.setPosition(self.x, self.y); } // Move toward marine if (marine && !self.dead) { var dx = marine.x - self.x; var dy = marine.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Create weapon if it doesn't exist if (!self.weapon) { self.updateWeapon(); } // Update weapon position to match firing direction if (self.weapon) { var angle = Math.atan2(marine.y - self.y, marine.x - self.x); var radius = self.radius * 1.1; self.weapon.x = Math.cos(angle) * radius; self.weapon.y = Math.sin(angle) * radius; self.weapon.rotation = angle + Math.PI / 2; } // Shoot at marine if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 900) { spawnDemonBullet(self.x, self.y, marine.x, marine.y); self.shootCooldown = 90 + Math.floor(Math.random() * 30); } } }; self.hit = function () { self.hp--; tween(demonSprite, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { tween(demonSprite, { tint: 0xc0392b }, { duration: 100 }); } }); if (self.hp <= 0) { self.dead = true; // Clean up health bar if (self.healthBar) { self.healthBar.destroy(); } // If the demon has a weapon, fade it out too if (self.weapon) { tween(self.weapon, { alpha: 0 }, { duration: 200 }); } tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); } }; return self; }); // Demon Bullet var DemonBullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('demonBullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletSprite.width * 0.5; self.speed = 14; self.dx = 0; self.dy = 1; self.update = function () { self.x += self.dx * self.speed; self.y += self.dy * self.speed; }; return self; }); // FireParticle for hell effect var FireParticle = Container.expand(function () { var self = Container.call(this); var particleSprite = self.attachAsset('fireParticle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1 + Math.random() * 3; self.lifetime = 60 + Math.random() * 120; self.initialAlpha = 0.4 + Math.random() * 0.6; self.alpha = self.initialAlpha; self.scaleValue = 0.3 + Math.random() * 0.7; particleSprite.scale.set(self.scaleValue, self.scaleValue); // Random tint between orange and red var tintValue = Math.random(); if (tintValue < 0.3) { particleSprite.tint = 0xFF4500; // Orange-Red } else if (tintValue < 0.6) { particleSprite.tint = 0xFF6347; // Tomato } else if (tintValue < 0.9) { particleSprite.tint = 0xFF0000; // Red } else { particleSprite.tint = 0xFFD700; // Gold } self.update = function () { self.y -= self.speed; self.lifetime--; // Fade out as lifetime decreases self.alpha = self.initialAlpha * (self.lifetime / 180); if (self.lifetime <= 0) { self.destroy(); } }; return self; }); // Health Bar var HealthBar = Container.expand(function () { var self = Container.call(this); self.maxHp = 1; self.currentHp = 1; self.width = 80; self.height = 8; self.offsetY = -80; // Position prominently above entity // Create background bar (red) self.bgBar = LK.getAsset('marineBullet', { anchorX: 0, anchorY: 0, scaleX: self.width / 32, scaleY: self.height / 32 }); self.bgBar.tint = 0x8B0000; // Dark red self.addChild(self.bgBar); // Create health bar (green) self.hpBar = LK.getAsset('marineBullet', { anchorX: 0, anchorY: 0, scaleX: self.width / 32, scaleY: self.height / 32 }); self.hpBar.tint = 0x27AE60; // Green self.addChild(self.hpBar); self.updateBar = function (currentHp, maxHp) { self.currentHp = currentHp; self.maxHp = maxHp; var healthPercent = Math.max(0, currentHp / maxHp); self.hpBar.scaleX = self.width / 32 * healthPercent; // Change color based on health percentage if (healthPercent > 0.6) { self.hpBar.tint = 0x27AE60; // Green } else if (healthPercent > 0.3) { self.hpBar.tint = 0xF39C12; // Orange } else { self.hpBar.tint = 0xE74C3C; // Red } }; self.setPosition = function (x, y) { self.x = x - self.width / 2; self.y = y + self.offsetY - 10; // Additional spacing above entity }; return self; }); // Health Pack var HealthPack = Container.expand(function () { var self = Container.call(this); var hpSprite = self.attachAsset('healthPack', { anchorX: 0.5, anchorY: 0.5 }); self.radius = hpSprite.width * 0.5; return self; }); // HellRock for background decoration var HellRock = Container.expand(function () { var self = Container.call(this); var rockSprite = self.attachAsset('hellRock', { anchorX: 0.5, anchorY: 0.5 }); // Randomly adjust rock appearance self.scale.set(0.8 + Math.random() * 0.5, 0.8 + Math.random() * 0.5); rockSprite.rotation = Math.random() * Math.PI * 2; // Random dark colors for rocks var darkColors = [0x3D0C02, 0x2F0A02, 0x3B1001, 0x330000]; rockSprite.tint = darkColors[Math.floor(Math.random() * darkColors.length)]; return self; }); // Marine (Player) var Marine = Container.expand(function () { var self = Container.call(this); var marineSprite = self.attachAsset('marine', { anchorX: 0.5, anchorY: 0.5 }); self.radius = marineSprite.width * 0.5; self.hp = 1; self.invuln = 0; // invulnerability frames self.weapons = []; // Array to hold weapon sprites self.healthBar = new HealthBar(); game.addChild(self.healthBar); // Create visual weapons based on bullet count self.updateWeapons = function (bulletCount) { // Remove any existing weapons for (var i = 0; i < self.weapons.length; i++) { self.weapons[i].destroy(); } self.weapons = []; // Create AK47 weapon var weapon = LK.getAsset('ak47', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Position weapon at marine's side var radius = self.radius * 1.3; weapon.x = radius; weapon.y = 0; self.addChild(weapon); self.weapons.push(weapon); }; // Define findNearestTarget method at the top of the class self.findNearestTarget = function () { var minDist = 999999; var tx = self.x; var ty = self.y - 200; // Default target ahead of marine // Check demons first if (demons && demons.length > 0) { for (var i = 0; i < demons.length; ++i) { var d = demons[i]; if (!d.dead) { var dx = d.x - self.x; var dy = d.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; tx = d.x; ty = d.y; } } } } // Check boss if (boss && !boss.dead) { var dx = boss.x - self.x; var dy = boss.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; tx = boss.x; ty = boss.y; } } // Check best demon if (bestDemon && !bestDemon.dead) { var dx = bestDemon.x - self.x; var dy = bestDemon.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; tx = bestDemon.x; ty = bestDemon.y; } } return { x: tx, y: ty, distance: Math.sqrt(minDist) }; }; self.update = function () { if (self.invuln > 0) self.invuln--; // Update health bar if (self.healthBar) { self.healthBar.updateBar(self.hp, marineMaxHP); self.healthBar.setPosition(self.x, self.y); } // Update weapon positions to match bullet fire positions if (self.weapons && self.weapons.length > 0) { // Get the target for bullet direction var target = self.findNearestTarget(); var tx = target.x; var ty = target.y; // Calculate direction var dx = tx - self.x; var dy = ty - self.y; var baseAngle = Math.atan2(dy, dx); // Position AK47 in firing position if (self.weapons.length > 0) { var weapon = self.weapons[0]; // Position AK47 pointing at target var angle = baseAngle; // Position weapon at firing direction var radius = self.radius * 1.1; // Slightly outside marine weapon.x = Math.cos(angle) * radius; weapon.y = Math.sin(angle) * radius; // Rotate weapon to face firing direction weapon.rotation = angle + Math.PI / 2; } } }; // Flash when hit self.flash = function () { tween(marineSprite, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(marineSprite, { tint: 0x3a9ad9 }, { duration: 120 }); } }); }; return self; }); // Marine Bullet var MarineBullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('marineBullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletSprite.width * 0.5; self.speed = 32; self.dx = 0; self.dy = -1; self.update = function () { self.x += self.dx * self.speed; self.y += self.dy * self.speed; }; return self; }); // Shield (Protection) var Shield = Container.expand(function () { var self = Container.call(this); var shieldSprite = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); // Use a different tint for the shield shieldSprite.tint = 0x3498db; self.radius = shieldSprite.width * 1.1; self.duration = 600; // 10 seconds self.update = function () { self.duration--; // Flash purple and green when 5 seconds (300 ticks) remaining if (self.duration === 300) { // Start color transition sequence tween(shieldSprite, { tint: 0x9b59b6 // Purple }, { duration: 150, onFinish: function onFinish() { tween(shieldSprite, { tint: 0x2ecc71 // Green }, { duration: 150, onFinish: function onFinish() { // Repeat the color cycle until shield expires var flashInterval = LK.setInterval(function () { tween(shieldSprite, { tint: 0x9b59b6 // Purple }, { duration: 150, onFinish: function onFinish() { tween(shieldSprite, { tint: 0x2ecc71 // Green }, { duration: 150 }); } }); }, 300); // Store interval ID on shield for cleanup self.flashInterval = flashInterval; } }); } }); } if (self.duration <= 0) { // Clear flash interval if it exists if (self.flashInterval) { LK.clearInterval(self.flashInterval); } tween(self, { alpha: 0 }, { duration: 120, onFinish: function onFinish() { self.destroy(); } }); } // Follow the marine if (marine) { self.x = marine.x; self.y = marine.y; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x660000 }); /**** * Game Code ****/ // Hell background elements // Marine (player) // Demon (enemy) // Boss Demon // Marine bullet // Demon bullet // Health pack // Power-up var fireParticles = []; var hellRocks = []; var particleSpawnTimer = 0; // Create lava ground background var lavaGround = LK.getAsset('lavaGround', { anchorX: 0, anchorY: 0 }); game.addChild(lavaGround); // Generate initial rocks for hell landscape function generateHellLandscape() { // Create rocks scattered around the arena for (var i = 0; i < 15; i++) { var rock = new HellRock(); rock.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT); rock.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP); hellRocks.push(rock); game.addChild(rock); } } // Arena bounds var ARENA_MARGIN = 80; var ARENA_LEFT = ARENA_MARGIN; var ARENA_TOP = 180; var ARENA_RIGHT = 2048 - ARENA_MARGIN; var ARENA_BOTTOM = 2732 - ARENA_MARGIN; // Game state var marine = null; var demons = []; var boss = null; var bestDemon = null; var marineBullets = []; var demonBullets = []; var bestDemonBullets = []; var healthPacks = []; var powerUps = []; var shields = []; var wave = 1; var waveTimer = 0; var spawnTimer = 0; var bossActive = false; var dragging = false; var dragOffsetX = 0; var dragOffsetY = 0; var lastMoveX = 0; var lastMoveY = 0; var score = 0; var marineFireTimer = 0; var marineFireRate = 12; // ticks between shots var marinePowerTimer = 0; var marineMaxHP = 1; var gameOver = false; var doublePointsActive = false; var doublePointsTimer = 0; var doublePointsDuration = 300; // 5 seconds at 60 FPS var doublePointsIndicator = null; // Visual indicator for double points // UI var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var hpTxt = new Text2('♥♥♥', { size: 90, fill: 0xE74C3C }); hpTxt.anchor.set(0.5, 0); LK.gui.top.addChild(hpTxt); hpTxt.y = 120; hpTxt.x = 2048 / 2; // Timer display in top right corner var gameStartTime = 0; var timerTxt = new Text2('00:00', { size: 80, fill: 0xFFFFFF }); timerTxt.anchor.set(1, 0); // Right align LK.gui.topRight.addChild(timerTxt); timerTxt.x = -20; // Small margin from right edge timerTxt.y = 20; // Small margin from top // Center arena function centerArenaX() { return (ARENA_LEFT + ARENA_RIGHT) / 2; } function centerArenaY() { return (ARENA_TOP + ARENA_BOTTOM) / 2; } // Spawn marine function spawnMarine() { marine = new Marine(); marine.x = centerArenaX(); marine.y = ARENA_BOTTOM - 220; game.addChild(marine); } // Spawn demon function spawnDemon() { var d = new Demon(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top d.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT); d.y = ARENA_TOP + 40; } else if (edge === 1) { // bottom d.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT); d.y = ARENA_BOTTOM - 40; } else if (edge === 2) { // left d.x = ARENA_LEFT + 40; d.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP); } else { // right d.x = ARENA_RIGHT - 40; d.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP); } demons.push(d); game.addChild(d); // Initialize weapon for the demon d.updateWeapon(); } // Spawn boss function spawnBoss() { boss = new Boss(); boss.x = centerArenaX(); boss.y = ARENA_TOP + 200; game.addChild(boss); bossActive = true; // Initialize weapons for the boss boss.updateWeapons(); } // Spawn best demon function spawnBestDemon() { bestDemon = new BestDemon(); bestDemon.x = centerArenaX(); bestDemon.y = ARENA_TOP + 150; game.addChild(bestDemon); // Initialize weapons for the best demon bestDemon.updateWeapons(); } // Spawn marine bullet function spawnMarineBullet(x, y, dx, dy) { var b = new MarineBullet(); b.x = x; b.y = y; var mag = Math.sqrt(dx * dx + dy * dy); b.dx = dx / mag; b.dy = dy / mag; marineBullets.push(b); game.addChild(b); } // Spawn demon bullet function spawnDemonBullet(x, y, tx, ty, speed) { var b = new DemonBullet(); b.x = x; b.y = y; var dx = tx - x; var dy = ty - y; var mag = Math.sqrt(dx * dx + dy * dy); b.dx = dx / mag; b.dy = dy / mag; if (speed) b.speed = speed; demonBullets.push(b); game.addChild(b); } // Spawn best demon bullet function spawnBestDemonBullet(x, y, tx, ty, speed) { var b = new BestDemonBullet(); b.x = x; b.y = y; var dx = tx - x; var dy = ty - y; var mag = Math.sqrt(dx * dx + dy * dy); b.dx = dx / mag; b.dy = dy / mag; if (speed) b.speed = speed; bestDemonBullets.push(b); game.addChild(b); } // Spawn health pack function spawnHealthPack() { var hp = new HealthPack(); hp.x = ARENA_LEFT + 100 + Math.random() * (ARENA_RIGHT - ARENA_LEFT - 200); hp.y = ARENA_TOP + 100 + Math.random() * (ARENA_BOTTOM - ARENA_TOP - 200); healthPacks.push(hp); game.addChild(hp); } // Power-ups have been removed function spawnPowerUp() { // Function kept for compatibility but does nothing } // Update UI function updateUI() { scoreTxt.setText(score); var hpStr = ''; for (var i = 0; i < marineMaxHP; ++i) { hpStr += i < marine.hp ? '♥' : '♡'; } hpTxt.setText(hpStr); } // Start game function startGame() { score = 0; wave = 1; waveTimer = 0; spawnTimer = 0; bossActive = false; marineFireTimer = 0; gameOver = false; doublePointsActive = false; doublePointsTimer = 0; // Clean up double points indicator if (doublePointsIndicator) { doublePointsIndicator.destroy(); doublePointsIndicator = null; } gameStartTime = LK.ticks; // Record game start time // Remove all for (var i = 0; i < demons.length; ++i) demons[i].destroy(); for (var i = 0; i < marineBullets.length; ++i) marineBullets[i].destroy(); for (var i = 0; i < demonBullets.length; ++i) demonBullets[i].destroy(); for (var i = 0; i < bestDemonBullets.length; ++i) bestDemonBullets[i].destroy(); for (var i = 0; i < healthPacks.length; ++i) healthPacks[i].destroy(); // Remove fire particles and rocks for (var i = 0; i < fireParticles.length; ++i) fireParticles[i].destroy(); for (var i = 0; i < hellRocks.length; ++i) hellRocks[i].destroy(); fireParticles = []; hellRocks = []; // Remove any active shields and health bars for (var i = 0; i < game.children.length; i++) { if (game.children[i] instanceof Shield) { game.children[i].destroy(); } if (game.children[i] instanceof HealthBar) { game.children[i].destroy(); } } if (marine) marine.destroy(); if (boss) boss.destroy(); if (bestDemon) bestDemon.destroy(); demons = []; marineBullets = []; demonBullets = []; bestDemonBullets = []; healthPacks = []; shields = []; boss = null; bestDemon = null; spawnMarine(); // Initialize marine with 1 weapon if (marine) { marine.updateWeapons(1); } updateUI(); } // Generate initial hell landscape generateHellLandscape(); startGame(); // Touch controls game.down = function (x, y, obj) { if (gameOver) return; // Only drag if touch is inside marine var dx = x - marine.x; var dy = y - marine.y; if (dx * dx + dy * dy < marine.radius * marine.radius * 1.2) { dragging = true; dragOffsetX = marine.x - x; dragOffsetY = marine.y - y; lastMoveX = x; lastMoveY = y; } }; game.up = function (x, y, obj) { dragging = false; }; game.move = function (x, y, obj) { if (gameOver) return; // Always follow finger/mouse, clamp to arena if (marine) { var nx = x; var ny = y; nx = Math.max(ARENA_LEFT + marine.radius, Math.min(ARENA_RIGHT - marine.radius, nx)); ny = Math.max(ARENA_TOP + marine.radius, Math.min(ARENA_BOTTOM - marine.radius, ny)); marine.x = nx; marine.y = ny; lastMoveX = x; lastMoveY = y; } }; // Main update loop game.update = function () { if (gameOver) return; // Update timer display var elapsedTicks = LK.ticks - gameStartTime; var elapsedSeconds = Math.floor(elapsedTicks / 60); var minutes = Math.floor(elapsedSeconds / 60); var seconds = elapsedSeconds % 60; var timeStr = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds; timerTxt.setText(timeStr); // Update fire particles (hellish effect) particleSpawnTimer--; if (particleSpawnTimer <= 0) { // Spawn new fire particles for (var i = 0; i < 3; i++) { var particle = new FireParticle(); particle.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT); particle.y = ARENA_BOTTOM - Math.random() * 100; fireParticles.push(particle); game.addChild(particle); } particleSpawnTimer = 2 + Math.floor(Math.random() * 3); } // Update existing fire particles for (var i = fireParticles.length - 1; i >= 0; i--) { fireParticles[i].update(); if (fireParticles[i].lifetime <= 0) { fireParticles.splice(i, 1); } } // Update marine if (marine) marine.update(); // Update double points timer if (doublePointsActive) { // Create indicator if it doesn't exist if (!doublePointsIndicator) { doublePointsIndicator = LK.getAsset('2xpo', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); game.addChild(doublePointsIndicator); } // Position indicator next to marine if (marine && doublePointsIndicator) { doublePointsIndicator.x = marine.x + marine.radius * 1.5; doublePointsIndicator.y = marine.y - marine.radius * 0.5; } doublePointsTimer--; if (doublePointsTimer <= 0) { doublePointsActive = false; doublePointsTimer = 0; // Reset timer to ensure clean state // Remove indicator when effect ends if (doublePointsIndicator) { doublePointsIndicator.destroy(); doublePointsIndicator = null; } } } else { // Ensure indicator is removed when double points is not active if (doublePointsIndicator) { doublePointsIndicator.destroy(); doublePointsIndicator = null; } } // Update demons for (var i = demons.length - 1; i >= 0; --i) { var d = demons[i]; d.update(); if (d.dead) { demons.splice(i, 1); var points = doublePointsActive ? 20 : 10; // Double points if active score += points; updateUI(); // Chance to drop health if (Math.random() < 0.08) spawnHealthPack(); } } // Update boss if (boss) { boss.update(); if (boss.dead) { bossActive = false; boss = null; // Score is now added in the boss.hit method wave++; waveTimer = 0; } // Marine takes damage when touching boss if (marine && !marine.dead && marine.invuln === 0 && !boss.dead) { var dx = marine.x - boss.x; var dy = marine.y - boss.y; var r = marine.radius + boss.radius; if (dx * dx + dy * dy < r * r) { marine.hp--; if (marine.hp < 0) marine.hp = 0; marine.invuln = 60; marine.flash(); updateUI(); if (marine.hp <= 0) { gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } // Update best demon if (bestDemon) { bestDemon.update(); if (bestDemon.dead) { bestDemon = null; wave++; waveTimer = 0; } // Marine takes damage when touching best demon if (marine && !marine.dead && marine.invuln === 0 && !bestDemon.dead) { var dx = marine.x - bestDemon.x; var dy = marine.y - bestDemon.y; var r = marine.radius + bestDemon.radius; if (dx * dx + dy * dy < r * r) { marine.hp--; if (marine.hp < 0) marine.hp = 0; marine.invuln = 60; marine.flash(); updateUI(); if (marine.hp <= 0) { gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } // Spawn best demon when score reaches 500 or more if (!bestDemon && score >= 500) { spawnBestDemon(); } // Update marine bullets for (var i = marineBullets.length - 1; i >= 0; --i) { var b = marineBullets[i]; b.update(); // Remove if out of bounds if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) { b.destroy(); marineBullets.splice(i, 1); continue; } // Hit demons var hit = false; for (var j = demons.length - 1; j >= 0; --j) { var d = demons[j]; var dx = b.x - d.x; var dy = b.y - d.y; var r = b.radius + d.radius; if (dx * dx + dy * dy < r * r) { d.hit(); hit = true; break; } } // Hit boss if (!hit && boss) { var dx = b.x - boss.x; var dy = b.y - boss.y; var r = b.radius + boss.radius; if (dx * dx + dy * dy < r * r) { boss.hit(); hit = true; } } // Hit best demon if (!hit && bestDemon) { var dx = b.x - bestDemon.x; var dy = b.y - bestDemon.y; var r = b.radius + bestDemon.radius; if (dx * dx + dy * dy < r * r) { bestDemon.hit(); hit = true; } } if (hit) { b.destroy(); marineBullets.splice(i, 1); } } // Update demon bullets for (var i = demonBullets.length - 1; i >= 0; --i) { var b = demonBullets[i]; b.update(); // Remove if out of bounds if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) { b.destroy(); demonBullets.splice(i, 1); continue; } // Hit marine if (marine && marine.invuln === 0) { var dx = b.x - marine.x; var dy = b.y - marine.y; var r = b.radius + marine.radius; if (dx * dx + dy * dy < r * r) { b.destroy(); demonBullets.splice(i, 1); // Check if a shield is protecting the marine var hasShield = false; for (var j = 0; j < game.children.length; j++) { if (game.children[j] instanceof Shield) { hasShield = true; // Destroy shield immediately when hit if (game.children[j].flashInterval) { LK.clearInterval(game.children[j].flashInterval); } // Flash shield effect and destroy it tween(game.children[j], { alpha: 0 }, { duration: 120, onFinish: function onFinish(obj) { obj.destroy(); } }); break; } } if (!hasShield) { marine.hp--; marine.invuln = 60; marine.flash(); updateUI(); if (marine.hp <= 0) { // Game over gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } } // Update best demon bullets for (var i = bestDemonBullets.length - 1; i >= 0; --i) { var b = bestDemonBullets[i]; b.update(); // Remove if out of bounds if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) { b.destroy(); bestDemonBullets.splice(i, 1); continue; } // Hit marine if (marine && marine.invuln === 0) { var dx = b.x - marine.x; var dy = b.y - marine.y; var r = b.radius + marine.radius; if (dx * dx + dy * dy < r * r) { b.destroy(); bestDemonBullets.splice(i, 1); // Check if a shield is protecting the marine var hasShield = false; for (var j = 0; j < game.children.length; j++) { if (game.children[j] instanceof Shield) { hasShield = true; // Destroy shield immediately when hit if (game.children[j].flashInterval) { LK.clearInterval(game.children[j].flashInterval); } // Flash shield effect and destroy it tween(game.children[j], { alpha: 0 }, { duration: 120, onFinish: function onFinish(obj) { obj.destroy(); } }); break; } } if (!hasShield) { marine.hp--; marine.invuln = 60; marine.flash(); updateUI(); if (marine.hp <= 0) { // Game over gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } } // Update health packs for (var i = healthPacks.length - 1; i >= 0; --i) { var hp = healthPacks[i]; if (marine) { var dx = hp.x - marine.x; var dy = hp.y - marine.y; var r = hp.radius + marine.radius; if (dx * dx + dy * dy < r * r) { if (marine.hp < marineMaxHP) { marine.hp++; } // Activate double points for 10 seconds doublePointsActive = true; doublePointsTimer = doublePointsDuration; updateUI(); hp.destroy(); healthPacks.splice(i, 1); } } } // Power-ups have been removed // Marine auto-fire if (marine) { marineFireTimer--; if (marineFireTimer <= 0) { marineFireTimer = marineFireRate; // Auto-targeting: find nearest enemy var target = marine.findNearestTarget(); var tx = target.x; var ty = target.y; // Fire // Calculate bullets based on score - 1 bullet base + 1 extra per 500 points var totalBullets = 1 + Math.floor(score / 500); // Make sure marine has an AK47 if (marine.weapons.length === 0) { marine.updateWeapons(1); } var dx = tx - marine.x; var dy = ty - marine.y; var baseAngle = Math.atan2(dy, dx); for (var n = 0; n < totalBullets; ++n) { // Spread out extra bullets a bit var offset = (n - (totalBullets - 1) / 2) * 0.12; var angle = baseAngle + offset; var ddx = Math.cos(angle); var ddy = Math.sin(angle); spawnMarineBullet(marine.x, marine.y, ddx, ddy, false); } } } // Wave logic if (!bossActive) { // Spawn demons if (demons.length < Math.min(3 + wave, 8)) { spawnTimer--; if (spawnTimer <= 0) { spawnDemon(); spawnTimer = 120 + Math.floor(Math.random() * 60); // Increased timer for slower demon spawning } } // Next wave if (demons.length === 0 && !boss && waveTimer > 60) { if (score >= 100 && score < 490 && Math.floor(score / 100) > Math.floor((score - (doublePointsActive ? 20 : 10)) / 100)) { spawnBoss(); } else { wave++; waveTimer = 0; } } waveTimer++; } else { // Wait for boss defeat if (boss && boss.dead) { bossActive = false; boss = null; wave++; waveTimer = 0; } } // Randomly spawn health packs if (LK.ticks % 420 === 0 && Math.random() < 0.5) { spawnHealthPack(); } // Pulsate lava ground for hellish effect if (LK.ticks % 120 === 0) { var targetTint = Math.random() < 0.5 ? 0x990000 : 0x660000; tween(lavaGround, { tint: targetTint }, { duration: 1000, easing: tween.easeInOut }); } }; // Reset game on game over LK.on('gameover', function () { startGame(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Best Demon (Ultimate Enemy)
var BestDemon = Container.expand(function () {
var self = Container.call(this);
var bestDemonSprite = self.attachAsset('bestdemon', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bestDemonSprite.width * 0.5;
self.hp = 120;
self.shootCooldown = 0;
self.speed = 2.5;
self.groundSmashTimer = 0;
self.weapons = []; // Array to hold weapon sprites
self.healthBar = new HealthBar();
self.healthBar.width = 140; // Largest health bar for best demon
self.healthBar.bgBar.scaleX = self.healthBar.width / 32;
self.healthBar.hpBar.scaleX = self.healthBar.width / 32;
game.addChild(self.healthBar);
// Create visual weapons (bestdemongun) for best demon
self.updateWeapons = function () {
// Remove any existing weapons
for (var i = 0; i < self.weapons.length; i++) {
self.weapons[i].destroy();
}
self.weapons = [];
// Create 2 bestdemonguns for best demon (double shot)
for (var i = -0.5; i <= 0.5; i++) {
var weapon = LK.getAsset('bestdemongun', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Position bestdemonguns around best demon
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.3;
var radius = self.radius * 1.2;
weapon.x = Math.cos(angle) * radius;
weapon.y = Math.sin(angle) * radius;
weapon.rotation = angle + Math.PI / 2;
self.addChild(weapon);
self.weapons.push(weapon);
}
};
self.update = function () {
// Update health bar
if (self.healthBar && !self.dead) {
self.healthBar.updateBar(self.hp, 120);
self.healthBar.setPosition(self.x, self.y);
}
// Move toward marine
if (marine && !self.dead) {
var dx = marine.x - self.x;
var dy = marine.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 1) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Update weapon positions to match firing direction
if (self.weapons.length === 0) {
self.updateWeapons();
} else {
for (var i = 0; i < self.weapons.length; i++) {
var weapon = self.weapons[i];
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + (i - 0.5) * 0.3;
var radius = self.radius * 1.2;
weapon.x = Math.cos(angle) * radius;
weapon.y = Math.sin(angle) * radius;
weapon.rotation = angle + Math.PI / 2;
}
}
// Shoot bestdemonmermi at marine (double shot)
if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 1500) {
for (var i = -0.5; i <= 0.5; i++) {
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.2;
var tx = self.x + Math.cos(angle) * 100;
var ty = self.y + Math.sin(angle) * 100;
spawnBestDemonBullet(self.x, self.y, tx, ty, 12);
}
self.shootCooldown = 40;
}
}
};
self.hit = function () {
self.hp--;
tween(bestDemonSprite, {
tint: 0xffffff
}, {
duration: 60,
onFinish: function onFinish() {
tween(bestDemonSprite, {
tint: 0x8e7602
}, {
duration: 100
});
}
});
if (self.hp <= 0) {
self.dead = true;
// Clean up health bar
if (self.healthBar) {
self.healthBar.destroy();
}
// Add points to score - best demons give triple points
var points = doublePointsActive ? 300 : 150;
score += points;
updateUI();
// Fade out best demon
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// Best Demon Bullet
var BestDemonBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bestdemonmermi', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width * 0.5;
self.speed = 16;
self.dx = 0;
self.dy = 1;
self.update = function () {
self.x += self.dx * self.speed;
self.y += self.dy * self.speed;
};
return self;
});
// Boss Demon
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossSprite = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bossSprite.width * 0.5;
self.hp = 80;
self.shootCooldown = 0;
self.speed = 3.5;
self.groundSmashTimer = 0; // Add this property to track smash cooldown
self.weapons = []; // Array to hold weapon sprites
self.healthBar = new HealthBar();
self.healthBar.width = 120; // Larger health bar for boss
self.healthBar.bgBar.scaleX = self.healthBar.width / 32;
self.healthBar.hpBar.scaleX = self.healthBar.width / 32;
game.addChild(self.healthBar);
// Create visual weapons (tridents) for boss
self.updateWeapons = function () {
// Remove any existing weapons
for (var i = 0; i < self.weapons.length; i++) {
self.weapons[i].destroy();
}
self.weapons = [];
// Create 3 tridents for boss (triple shot)
for (var i = -1; i <= 1; i++) {
var weapon = LK.getAsset('furca', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.3,
scaleY: 1.3
});
// Position tridents around boss
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.18;
var radius = self.radius * 1.1;
weapon.x = Math.cos(angle) * radius;
weapon.y = Math.sin(angle) * radius;
weapon.rotation = angle + Math.PI / 2;
self.addChild(weapon);
self.weapons.push(weapon);
}
};
self.update = function () {
// Update health bar
if (self.healthBar && !self.dead) {
self.healthBar.updateBar(self.hp, 80);
self.healthBar.setPosition(self.x, self.y);
}
// Move toward marine
if (marine && !self.dead) {
var dx = marine.x - self.x;
var dy = marine.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 1) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Update weapon positions to match firing direction
if (self.weapons.length === 0) {
self.updateWeapons();
} else {
for (var i = 0; i < self.weapons.length; i++) {
var weapon = self.weapons[i];
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + (i - 1) * 0.18;
var radius = self.radius * 1.1;
weapon.x = Math.cos(angle) * radius;
weapon.y = Math.sin(angle) * radius;
weapon.rotation = angle + Math.PI / 2;
}
}
// Boss ground smash attack every 8 seconds (480 ticks)
if (typeof self.groundSmashTimer === "undefined") self.groundSmashTimer = 0;
self.groundSmashTimer++;
// 3 seconds (180 ticks) before smash, start color warning
if (self.groundSmashTimer === 300) {
// Flash red for 1.5 seconds, then orange for 1.5 seconds
tween(bossSprite, {
tint: 0xff0000
}, {
duration: 90,
onFinish: function onFinish() {
tween(bossSprite, {
tint: 0xffa500
}, {
duration: 90,
onFinish: function onFinish() {
// Do nothing, color will be reset after smash
}
});
}
});
}
if (self.groundSmashTimer >= 480) {
self.groundSmashTimer = 0;
// Visual effect: flash boss and screen
tween(bossSprite, {
tint: 0xffffff
}, {
duration: 80,
onFinish: function onFinish() {
tween(bossSprite, {
tint: 0x8e44ad
}, {
duration: 120
});
}
});
LK.effects.flashScreen(0xccccff, 200);
// Damage marine if close to boss (melee range)
if (marine && !marine.dead && marine.invuln === 0) {
var smashDist = bossSprite.width * 1.1;
var mdx = marine.x - self.x;
var mdy = marine.y - self.y;
if (mdx * mdx + mdy * mdy < smashDist * smashDist) {
marine.hp -= 2;
if (marine.hp < 0) marine.hp = 0;
marine.invuln = 60;
marine.flash();
updateUI();
if (marine.hp <= 0) {
// Game over
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
// Shoot at marine (triple shot)
if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 1200) {
for (var i = -1; i <= 1; i++) {
var angle = Math.atan2(marine.y - self.y, marine.x - self.x) + i * 0.18;
var tx = self.x + Math.cos(angle) * 100;
var ty = self.y + Math.sin(angle) * 100;
spawnDemonBullet(self.x, self.y, tx, ty, 10);
}
self.shootCooldown = 50;
}
}
};
self.hit = function () {
self.hp--;
tween(bossSprite, {
tint: 0xffffff
}, {
duration: 60,
onFinish: function onFinish() {
tween(bossSprite, {
tint: 0x8e44ad
}, {
duration: 100
});
}
});
if (self.hp <= 0) {
self.dead = true;
// Clean up health bar
if (self.healthBar) {
self.healthBar.destroy();
}
// Spawn a shield at boss position
var shield = new Shield();
shield.x = self.x;
shield.y = self.y;
game.addChild(shield);
// Add points to score - bosses give double points when health pack effect is active
var points = doublePointsActive ? 100 : 50;
score += points;
updateUI();
// Create visual effect for shield drop
tween(shield, {
y: self.y + 20
}, {
duration: 60,
onFinish: function onFinish() {
tween(shield, {
y: self.y
}, {
duration: 40
});
}
});
// Fade out boss
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// Demon (Enemy)
var Demon = Container.expand(function () {
var self = Container.call(this);
var demonSprite = self.attachAsset('demon', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = demonSprite.width * 0.5;
self.hp = 4;
self.shootCooldown = 0;
self.speed = 4 + Math.random() * 2;
self.weapon = null; // Weapon sprite
self.healthBar = new HealthBar();
game.addChild(self.healthBar);
// Create visual weapon (trident) for demon
self.updateWeapon = function () {
// Remove existing weapon if any
if (self.weapon) {
self.weapon.destroy();
}
// Create a furca (trident) for demon
self.weapon = LK.getAsset('furca', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Position trident in front of demon
if (marine) {
var angle = Math.atan2(marine.y - self.y, marine.x - self.x);
var radius = self.radius * 1.1;
self.weapon.x = Math.cos(angle) * radius;
self.weapon.y = Math.sin(angle) * radius;
self.weapon.rotation = angle + Math.PI / 2;
} else {
self.weapon.x = self.radius;
self.weapon.y = 0;
}
self.addChild(self.weapon);
};
self.update = function () {
// Update health bar
if (self.healthBar && !self.dead) {
self.healthBar.updateBar(self.hp, 4);
self.healthBar.setPosition(self.x, self.y);
}
// Move toward marine
if (marine && !self.dead) {
var dx = marine.x - self.x;
var dy = marine.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 1) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Create weapon if it doesn't exist
if (!self.weapon) {
self.updateWeapon();
}
// Update weapon position to match firing direction
if (self.weapon) {
var angle = Math.atan2(marine.y - self.y, marine.x - self.x);
var radius = self.radius * 1.1;
self.weapon.x = Math.cos(angle) * radius;
self.weapon.y = Math.sin(angle) * radius;
self.weapon.rotation = angle + Math.PI / 2;
}
// Shoot at marine
if (self.shootCooldown > 0) self.shootCooldown--;else if (dist < 900) {
spawnDemonBullet(self.x, self.y, marine.x, marine.y);
self.shootCooldown = 90 + Math.floor(Math.random() * 30);
}
}
};
self.hit = function () {
self.hp--;
tween(demonSprite, {
tint: 0xffffff
}, {
duration: 60,
onFinish: function onFinish() {
tween(demonSprite, {
tint: 0xc0392b
}, {
duration: 100
});
}
});
if (self.hp <= 0) {
self.dead = true;
// Clean up health bar
if (self.healthBar) {
self.healthBar.destroy();
}
// If the demon has a weapon, fade it out too
if (self.weapon) {
tween(self.weapon, {
alpha: 0
}, {
duration: 200
});
}
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// Demon Bullet
var DemonBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('demonBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width * 0.5;
self.speed = 14;
self.dx = 0;
self.dy = 1;
self.update = function () {
self.x += self.dx * self.speed;
self.y += self.dy * self.speed;
};
return self;
});
// FireParticle for hell effect
var FireParticle = Container.expand(function () {
var self = Container.call(this);
var particleSprite = self.attachAsset('fireParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 3;
self.lifetime = 60 + Math.random() * 120;
self.initialAlpha = 0.4 + Math.random() * 0.6;
self.alpha = self.initialAlpha;
self.scaleValue = 0.3 + Math.random() * 0.7;
particleSprite.scale.set(self.scaleValue, self.scaleValue);
// Random tint between orange and red
var tintValue = Math.random();
if (tintValue < 0.3) {
particleSprite.tint = 0xFF4500; // Orange-Red
} else if (tintValue < 0.6) {
particleSprite.tint = 0xFF6347; // Tomato
} else if (tintValue < 0.9) {
particleSprite.tint = 0xFF0000; // Red
} else {
particleSprite.tint = 0xFFD700; // Gold
}
self.update = function () {
self.y -= self.speed;
self.lifetime--;
// Fade out as lifetime decreases
self.alpha = self.initialAlpha * (self.lifetime / 180);
if (self.lifetime <= 0) {
self.destroy();
}
};
return self;
});
// Health Bar
var HealthBar = Container.expand(function () {
var self = Container.call(this);
self.maxHp = 1;
self.currentHp = 1;
self.width = 80;
self.height = 8;
self.offsetY = -80; // Position prominently above entity
// Create background bar (red)
self.bgBar = LK.getAsset('marineBullet', {
anchorX: 0,
anchorY: 0,
scaleX: self.width / 32,
scaleY: self.height / 32
});
self.bgBar.tint = 0x8B0000; // Dark red
self.addChild(self.bgBar);
// Create health bar (green)
self.hpBar = LK.getAsset('marineBullet', {
anchorX: 0,
anchorY: 0,
scaleX: self.width / 32,
scaleY: self.height / 32
});
self.hpBar.tint = 0x27AE60; // Green
self.addChild(self.hpBar);
self.updateBar = function (currentHp, maxHp) {
self.currentHp = currentHp;
self.maxHp = maxHp;
var healthPercent = Math.max(0, currentHp / maxHp);
self.hpBar.scaleX = self.width / 32 * healthPercent;
// Change color based on health percentage
if (healthPercent > 0.6) {
self.hpBar.tint = 0x27AE60; // Green
} else if (healthPercent > 0.3) {
self.hpBar.tint = 0xF39C12; // Orange
} else {
self.hpBar.tint = 0xE74C3C; // Red
}
};
self.setPosition = function (x, y) {
self.x = x - self.width / 2;
self.y = y + self.offsetY - 10; // Additional spacing above entity
};
return self;
});
// Health Pack
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var hpSprite = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = hpSprite.width * 0.5;
return self;
});
// HellRock for background decoration
var HellRock = Container.expand(function () {
var self = Container.call(this);
var rockSprite = self.attachAsset('hellRock', {
anchorX: 0.5,
anchorY: 0.5
});
// Randomly adjust rock appearance
self.scale.set(0.8 + Math.random() * 0.5, 0.8 + Math.random() * 0.5);
rockSprite.rotation = Math.random() * Math.PI * 2;
// Random dark colors for rocks
var darkColors = [0x3D0C02, 0x2F0A02, 0x3B1001, 0x330000];
rockSprite.tint = darkColors[Math.floor(Math.random() * darkColors.length)];
return self;
});
// Marine (Player)
var Marine = Container.expand(function () {
var self = Container.call(this);
var marineSprite = self.attachAsset('marine', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = marineSprite.width * 0.5;
self.hp = 1;
self.invuln = 0; // invulnerability frames
self.weapons = []; // Array to hold weapon sprites
self.healthBar = new HealthBar();
game.addChild(self.healthBar);
// Create visual weapons based on bullet count
self.updateWeapons = function (bulletCount) {
// Remove any existing weapons
for (var i = 0; i < self.weapons.length; i++) {
self.weapons[i].destroy();
}
self.weapons = [];
// Create AK47 weapon
var weapon = LK.getAsset('ak47', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Position weapon at marine's side
var radius = self.radius * 1.3;
weapon.x = radius;
weapon.y = 0;
self.addChild(weapon);
self.weapons.push(weapon);
};
// Define findNearestTarget method at the top of the class
self.findNearestTarget = function () {
var minDist = 999999;
var tx = self.x;
var ty = self.y - 200; // Default target ahead of marine
// Check demons first
if (demons && demons.length > 0) {
for (var i = 0; i < demons.length; ++i) {
var d = demons[i];
if (!d.dead) {
var dx = d.x - self.x;
var dy = d.y - self.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
tx = d.x;
ty = d.y;
}
}
}
}
// Check boss
if (boss && !boss.dead) {
var dx = boss.x - self.x;
var dy = boss.y - self.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
tx = boss.x;
ty = boss.y;
}
}
// Check best demon
if (bestDemon && !bestDemon.dead) {
var dx = bestDemon.x - self.x;
var dy = bestDemon.y - self.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
tx = bestDemon.x;
ty = bestDemon.y;
}
}
return {
x: tx,
y: ty,
distance: Math.sqrt(minDist)
};
};
self.update = function () {
if (self.invuln > 0) self.invuln--;
// Update health bar
if (self.healthBar) {
self.healthBar.updateBar(self.hp, marineMaxHP);
self.healthBar.setPosition(self.x, self.y);
}
// Update weapon positions to match bullet fire positions
if (self.weapons && self.weapons.length > 0) {
// Get the target for bullet direction
var target = self.findNearestTarget();
var tx = target.x;
var ty = target.y;
// Calculate direction
var dx = tx - self.x;
var dy = ty - self.y;
var baseAngle = Math.atan2(dy, dx);
// Position AK47 in firing position
if (self.weapons.length > 0) {
var weapon = self.weapons[0];
// Position AK47 pointing at target
var angle = baseAngle;
// Position weapon at firing direction
var radius = self.radius * 1.1; // Slightly outside marine
weapon.x = Math.cos(angle) * radius;
weapon.y = Math.sin(angle) * radius;
// Rotate weapon to face firing direction
weapon.rotation = angle + Math.PI / 2;
}
}
};
// Flash when hit
self.flash = function () {
tween(marineSprite, {
tint: 0xffffff
}, {
duration: 80,
onFinish: function onFinish() {
tween(marineSprite, {
tint: 0x3a9ad9
}, {
duration: 120
});
}
});
};
return self;
});
// Marine Bullet
var MarineBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('marineBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width * 0.5;
self.speed = 32;
self.dx = 0;
self.dy = -1;
self.update = function () {
self.x += self.dx * self.speed;
self.y += self.dy * self.speed;
};
return self;
});
// Shield (Protection)
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldSprite = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// Use a different tint for the shield
shieldSprite.tint = 0x3498db;
self.radius = shieldSprite.width * 1.1;
self.duration = 600; // 10 seconds
self.update = function () {
self.duration--;
// Flash purple and green when 5 seconds (300 ticks) remaining
if (self.duration === 300) {
// Start color transition sequence
tween(shieldSprite, {
tint: 0x9b59b6 // Purple
}, {
duration: 150,
onFinish: function onFinish() {
tween(shieldSprite, {
tint: 0x2ecc71 // Green
}, {
duration: 150,
onFinish: function onFinish() {
// Repeat the color cycle until shield expires
var flashInterval = LK.setInterval(function () {
tween(shieldSprite, {
tint: 0x9b59b6 // Purple
}, {
duration: 150,
onFinish: function onFinish() {
tween(shieldSprite, {
tint: 0x2ecc71 // Green
}, {
duration: 150
});
}
});
}, 300);
// Store interval ID on shield for cleanup
self.flashInterval = flashInterval;
}
});
}
});
}
if (self.duration <= 0) {
// Clear flash interval if it exists
if (self.flashInterval) {
LK.clearInterval(self.flashInterval);
}
tween(self, {
alpha: 0
}, {
duration: 120,
onFinish: function onFinish() {
self.destroy();
}
});
}
// Follow the marine
if (marine) {
self.x = marine.x;
self.y = marine.y;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x660000
});
/****
* Game Code
****/
// Hell background elements
// Marine (player)
// Demon (enemy)
// Boss Demon
// Marine bullet
// Demon bullet
// Health pack
// Power-up
var fireParticles = [];
var hellRocks = [];
var particleSpawnTimer = 0;
// Create lava ground background
var lavaGround = LK.getAsset('lavaGround', {
anchorX: 0,
anchorY: 0
});
game.addChild(lavaGround);
// Generate initial rocks for hell landscape
function generateHellLandscape() {
// Create rocks scattered around the arena
for (var i = 0; i < 15; i++) {
var rock = new HellRock();
rock.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT);
rock.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP);
hellRocks.push(rock);
game.addChild(rock);
}
}
// Arena bounds
var ARENA_MARGIN = 80;
var ARENA_LEFT = ARENA_MARGIN;
var ARENA_TOP = 180;
var ARENA_RIGHT = 2048 - ARENA_MARGIN;
var ARENA_BOTTOM = 2732 - ARENA_MARGIN;
// Game state
var marine = null;
var demons = [];
var boss = null;
var bestDemon = null;
var marineBullets = [];
var demonBullets = [];
var bestDemonBullets = [];
var healthPacks = [];
var powerUps = [];
var shields = [];
var wave = 1;
var waveTimer = 0;
var spawnTimer = 0;
var bossActive = false;
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastMoveX = 0;
var lastMoveY = 0;
var score = 0;
var marineFireTimer = 0;
var marineFireRate = 12; // ticks between shots
var marinePowerTimer = 0;
var marineMaxHP = 1;
var gameOver = false;
var doublePointsActive = false;
var doublePointsTimer = 0;
var doublePointsDuration = 300; // 5 seconds at 60 FPS
var doublePointsIndicator = null; // Visual indicator for double points
// UI
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var hpTxt = new Text2('♥♥♥', {
size: 90,
fill: 0xE74C3C
});
hpTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(hpTxt);
hpTxt.y = 120;
hpTxt.x = 2048 / 2;
// Timer display in top right corner
var gameStartTime = 0;
var timerTxt = new Text2('00:00', {
size: 80,
fill: 0xFFFFFF
});
timerTxt.anchor.set(1, 0); // Right align
LK.gui.topRight.addChild(timerTxt);
timerTxt.x = -20; // Small margin from right edge
timerTxt.y = 20; // Small margin from top
// Center arena
function centerArenaX() {
return (ARENA_LEFT + ARENA_RIGHT) / 2;
}
function centerArenaY() {
return (ARENA_TOP + ARENA_BOTTOM) / 2;
}
// Spawn marine
function spawnMarine() {
marine = new Marine();
marine.x = centerArenaX();
marine.y = ARENA_BOTTOM - 220;
game.addChild(marine);
}
// Spawn demon
function spawnDemon() {
var d = new Demon();
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
d.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT);
d.y = ARENA_TOP + 40;
} else if (edge === 1) {
// bottom
d.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT);
d.y = ARENA_BOTTOM - 40;
} else if (edge === 2) {
// left
d.x = ARENA_LEFT + 40;
d.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP);
} else {
// right
d.x = ARENA_RIGHT - 40;
d.y = ARENA_TOP + Math.random() * (ARENA_BOTTOM - ARENA_TOP);
}
demons.push(d);
game.addChild(d);
// Initialize weapon for the demon
d.updateWeapon();
}
// Spawn boss
function spawnBoss() {
boss = new Boss();
boss.x = centerArenaX();
boss.y = ARENA_TOP + 200;
game.addChild(boss);
bossActive = true;
// Initialize weapons for the boss
boss.updateWeapons();
}
// Spawn best demon
function spawnBestDemon() {
bestDemon = new BestDemon();
bestDemon.x = centerArenaX();
bestDemon.y = ARENA_TOP + 150;
game.addChild(bestDemon);
// Initialize weapons for the best demon
bestDemon.updateWeapons();
}
// Spawn marine bullet
function spawnMarineBullet(x, y, dx, dy) {
var b = new MarineBullet();
b.x = x;
b.y = y;
var mag = Math.sqrt(dx * dx + dy * dy);
b.dx = dx / mag;
b.dy = dy / mag;
marineBullets.push(b);
game.addChild(b);
}
// Spawn demon bullet
function spawnDemonBullet(x, y, tx, ty, speed) {
var b = new DemonBullet();
b.x = x;
b.y = y;
var dx = tx - x;
var dy = ty - y;
var mag = Math.sqrt(dx * dx + dy * dy);
b.dx = dx / mag;
b.dy = dy / mag;
if (speed) b.speed = speed;
demonBullets.push(b);
game.addChild(b);
}
// Spawn best demon bullet
function spawnBestDemonBullet(x, y, tx, ty, speed) {
var b = new BestDemonBullet();
b.x = x;
b.y = y;
var dx = tx - x;
var dy = ty - y;
var mag = Math.sqrt(dx * dx + dy * dy);
b.dx = dx / mag;
b.dy = dy / mag;
if (speed) b.speed = speed;
bestDemonBullets.push(b);
game.addChild(b);
}
// Spawn health pack
function spawnHealthPack() {
var hp = new HealthPack();
hp.x = ARENA_LEFT + 100 + Math.random() * (ARENA_RIGHT - ARENA_LEFT - 200);
hp.y = ARENA_TOP + 100 + Math.random() * (ARENA_BOTTOM - ARENA_TOP - 200);
healthPacks.push(hp);
game.addChild(hp);
}
// Power-ups have been removed
function spawnPowerUp() {
// Function kept for compatibility but does nothing
}
// Update UI
function updateUI() {
scoreTxt.setText(score);
var hpStr = '';
for (var i = 0; i < marineMaxHP; ++i) {
hpStr += i < marine.hp ? '♥' : '♡';
}
hpTxt.setText(hpStr);
}
// Start game
function startGame() {
score = 0;
wave = 1;
waveTimer = 0;
spawnTimer = 0;
bossActive = false;
marineFireTimer = 0;
gameOver = false;
doublePointsActive = false;
doublePointsTimer = 0;
// Clean up double points indicator
if (doublePointsIndicator) {
doublePointsIndicator.destroy();
doublePointsIndicator = null;
}
gameStartTime = LK.ticks; // Record game start time
// Remove all
for (var i = 0; i < demons.length; ++i) demons[i].destroy();
for (var i = 0; i < marineBullets.length; ++i) marineBullets[i].destroy();
for (var i = 0; i < demonBullets.length; ++i) demonBullets[i].destroy();
for (var i = 0; i < bestDemonBullets.length; ++i) bestDemonBullets[i].destroy();
for (var i = 0; i < healthPacks.length; ++i) healthPacks[i].destroy();
// Remove fire particles and rocks
for (var i = 0; i < fireParticles.length; ++i) fireParticles[i].destroy();
for (var i = 0; i < hellRocks.length; ++i) hellRocks[i].destroy();
fireParticles = [];
hellRocks = [];
// Remove any active shields and health bars
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] instanceof Shield) {
game.children[i].destroy();
}
if (game.children[i] instanceof HealthBar) {
game.children[i].destroy();
}
}
if (marine) marine.destroy();
if (boss) boss.destroy();
if (bestDemon) bestDemon.destroy();
demons = [];
marineBullets = [];
demonBullets = [];
bestDemonBullets = [];
healthPacks = [];
shields = [];
boss = null;
bestDemon = null;
spawnMarine();
// Initialize marine with 1 weapon
if (marine) {
marine.updateWeapons(1);
}
updateUI();
}
// Generate initial hell landscape
generateHellLandscape();
startGame();
// Touch controls
game.down = function (x, y, obj) {
if (gameOver) return;
// Only drag if touch is inside marine
var dx = x - marine.x;
var dy = y - marine.y;
if (dx * dx + dy * dy < marine.radius * marine.radius * 1.2) {
dragging = true;
dragOffsetX = marine.x - x;
dragOffsetY = marine.y - y;
lastMoveX = x;
lastMoveY = y;
}
};
game.up = function (x, y, obj) {
dragging = false;
};
game.move = function (x, y, obj) {
if (gameOver) return;
// Always follow finger/mouse, clamp to arena
if (marine) {
var nx = x;
var ny = y;
nx = Math.max(ARENA_LEFT + marine.radius, Math.min(ARENA_RIGHT - marine.radius, nx));
ny = Math.max(ARENA_TOP + marine.radius, Math.min(ARENA_BOTTOM - marine.radius, ny));
marine.x = nx;
marine.y = ny;
lastMoveX = x;
lastMoveY = y;
}
};
// Main update loop
game.update = function () {
if (gameOver) return;
// Update timer display
var elapsedTicks = LK.ticks - gameStartTime;
var elapsedSeconds = Math.floor(elapsedTicks / 60);
var minutes = Math.floor(elapsedSeconds / 60);
var seconds = elapsedSeconds % 60;
var timeStr = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
timerTxt.setText(timeStr);
// Update fire particles (hellish effect)
particleSpawnTimer--;
if (particleSpawnTimer <= 0) {
// Spawn new fire particles
for (var i = 0; i < 3; i++) {
var particle = new FireParticle();
particle.x = ARENA_LEFT + Math.random() * (ARENA_RIGHT - ARENA_LEFT);
particle.y = ARENA_BOTTOM - Math.random() * 100;
fireParticles.push(particle);
game.addChild(particle);
}
particleSpawnTimer = 2 + Math.floor(Math.random() * 3);
}
// Update existing fire particles
for (var i = fireParticles.length - 1; i >= 0; i--) {
fireParticles[i].update();
if (fireParticles[i].lifetime <= 0) {
fireParticles.splice(i, 1);
}
}
// Update marine
if (marine) marine.update();
// Update double points timer
if (doublePointsActive) {
// Create indicator if it doesn't exist
if (!doublePointsIndicator) {
doublePointsIndicator = LK.getAsset('2xpo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
game.addChild(doublePointsIndicator);
}
// Position indicator next to marine
if (marine && doublePointsIndicator) {
doublePointsIndicator.x = marine.x + marine.radius * 1.5;
doublePointsIndicator.y = marine.y - marine.radius * 0.5;
}
doublePointsTimer--;
if (doublePointsTimer <= 0) {
doublePointsActive = false;
doublePointsTimer = 0; // Reset timer to ensure clean state
// Remove indicator when effect ends
if (doublePointsIndicator) {
doublePointsIndicator.destroy();
doublePointsIndicator = null;
}
}
} else {
// Ensure indicator is removed when double points is not active
if (doublePointsIndicator) {
doublePointsIndicator.destroy();
doublePointsIndicator = null;
}
}
// Update demons
for (var i = demons.length - 1; i >= 0; --i) {
var d = demons[i];
d.update();
if (d.dead) {
demons.splice(i, 1);
var points = doublePointsActive ? 20 : 10; // Double points if active
score += points;
updateUI();
// Chance to drop health
if (Math.random() < 0.08) spawnHealthPack();
}
}
// Update boss
if (boss) {
boss.update();
if (boss.dead) {
bossActive = false;
boss = null;
// Score is now added in the boss.hit method
wave++;
waveTimer = 0;
}
// Marine takes damage when touching boss
if (marine && !marine.dead && marine.invuln === 0 && !boss.dead) {
var dx = marine.x - boss.x;
var dy = marine.y - boss.y;
var r = marine.radius + boss.radius;
if (dx * dx + dy * dy < r * r) {
marine.hp--;
if (marine.hp < 0) marine.hp = 0;
marine.invuln = 60;
marine.flash();
updateUI();
if (marine.hp <= 0) {
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
// Update best demon
if (bestDemon) {
bestDemon.update();
if (bestDemon.dead) {
bestDemon = null;
wave++;
waveTimer = 0;
}
// Marine takes damage when touching best demon
if (marine && !marine.dead && marine.invuln === 0 && !bestDemon.dead) {
var dx = marine.x - bestDemon.x;
var dy = marine.y - bestDemon.y;
var r = marine.radius + bestDemon.radius;
if (dx * dx + dy * dy < r * r) {
marine.hp--;
if (marine.hp < 0) marine.hp = 0;
marine.invuln = 60;
marine.flash();
updateUI();
if (marine.hp <= 0) {
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
// Spawn best demon when score reaches 500 or more
if (!bestDemon && score >= 500) {
spawnBestDemon();
}
// Update marine bullets
for (var i = marineBullets.length - 1; i >= 0; --i) {
var b = marineBullets[i];
b.update();
// Remove if out of bounds
if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) {
b.destroy();
marineBullets.splice(i, 1);
continue;
}
// Hit demons
var hit = false;
for (var j = demons.length - 1; j >= 0; --j) {
var d = demons[j];
var dx = b.x - d.x;
var dy = b.y - d.y;
var r = b.radius + d.radius;
if (dx * dx + dy * dy < r * r) {
d.hit();
hit = true;
break;
}
}
// Hit boss
if (!hit && boss) {
var dx = b.x - boss.x;
var dy = b.y - boss.y;
var r = b.radius + boss.radius;
if (dx * dx + dy * dy < r * r) {
boss.hit();
hit = true;
}
}
// Hit best demon
if (!hit && bestDemon) {
var dx = b.x - bestDemon.x;
var dy = b.y - bestDemon.y;
var r = b.radius + bestDemon.radius;
if (dx * dx + dy * dy < r * r) {
bestDemon.hit();
hit = true;
}
}
if (hit) {
b.destroy();
marineBullets.splice(i, 1);
}
}
// Update demon bullets
for (var i = demonBullets.length - 1; i >= 0; --i) {
var b = demonBullets[i];
b.update();
// Remove if out of bounds
if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) {
b.destroy();
demonBullets.splice(i, 1);
continue;
}
// Hit marine
if (marine && marine.invuln === 0) {
var dx = b.x - marine.x;
var dy = b.y - marine.y;
var r = b.radius + marine.radius;
if (dx * dx + dy * dy < r * r) {
b.destroy();
demonBullets.splice(i, 1);
// Check if a shield is protecting the marine
var hasShield = false;
for (var j = 0; j < game.children.length; j++) {
if (game.children[j] instanceof Shield) {
hasShield = true;
// Destroy shield immediately when hit
if (game.children[j].flashInterval) {
LK.clearInterval(game.children[j].flashInterval);
}
// Flash shield effect and destroy it
tween(game.children[j], {
alpha: 0
}, {
duration: 120,
onFinish: function onFinish(obj) {
obj.destroy();
}
});
break;
}
}
if (!hasShield) {
marine.hp--;
marine.invuln = 60;
marine.flash();
updateUI();
if (marine.hp <= 0) {
// Game over
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
}
// Update best demon bullets
for (var i = bestDemonBullets.length - 1; i >= 0; --i) {
var b = bestDemonBullets[i];
b.update();
// Remove if out of bounds
if (b.x < ARENA_LEFT - 60 || b.x > ARENA_RIGHT + 60 || b.y < ARENA_TOP - 60 || b.y > ARENA_BOTTOM + 60) {
b.destroy();
bestDemonBullets.splice(i, 1);
continue;
}
// Hit marine
if (marine && marine.invuln === 0) {
var dx = b.x - marine.x;
var dy = b.y - marine.y;
var r = b.radius + marine.radius;
if (dx * dx + dy * dy < r * r) {
b.destroy();
bestDemonBullets.splice(i, 1);
// Check if a shield is protecting the marine
var hasShield = false;
for (var j = 0; j < game.children.length; j++) {
if (game.children[j] instanceof Shield) {
hasShield = true;
// Destroy shield immediately when hit
if (game.children[j].flashInterval) {
LK.clearInterval(game.children[j].flashInterval);
}
// Flash shield effect and destroy it
tween(game.children[j], {
alpha: 0
}, {
duration: 120,
onFinish: function onFinish(obj) {
obj.destroy();
}
});
break;
}
}
if (!hasShield) {
marine.hp--;
marine.invuln = 60;
marine.flash();
updateUI();
if (marine.hp <= 0) {
// Game over
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
}
// Update health packs
for (var i = healthPacks.length - 1; i >= 0; --i) {
var hp = healthPacks[i];
if (marine) {
var dx = hp.x - marine.x;
var dy = hp.y - marine.y;
var r = hp.radius + marine.radius;
if (dx * dx + dy * dy < r * r) {
if (marine.hp < marineMaxHP) {
marine.hp++;
}
// Activate double points for 10 seconds
doublePointsActive = true;
doublePointsTimer = doublePointsDuration;
updateUI();
hp.destroy();
healthPacks.splice(i, 1);
}
}
}
// Power-ups have been removed
// Marine auto-fire
if (marine) {
marineFireTimer--;
if (marineFireTimer <= 0) {
marineFireTimer = marineFireRate;
// Auto-targeting: find nearest enemy
var target = marine.findNearestTarget();
var tx = target.x;
var ty = target.y;
// Fire
// Calculate bullets based on score - 1 bullet base + 1 extra per 500 points
var totalBullets = 1 + Math.floor(score / 500);
// Make sure marine has an AK47
if (marine.weapons.length === 0) {
marine.updateWeapons(1);
}
var dx = tx - marine.x;
var dy = ty - marine.y;
var baseAngle = Math.atan2(dy, dx);
for (var n = 0; n < totalBullets; ++n) {
// Spread out extra bullets a bit
var offset = (n - (totalBullets - 1) / 2) * 0.12;
var angle = baseAngle + offset;
var ddx = Math.cos(angle);
var ddy = Math.sin(angle);
spawnMarineBullet(marine.x, marine.y, ddx, ddy, false);
}
}
}
// Wave logic
if (!bossActive) {
// Spawn demons
if (demons.length < Math.min(3 + wave, 8)) {
spawnTimer--;
if (spawnTimer <= 0) {
spawnDemon();
spawnTimer = 120 + Math.floor(Math.random() * 60); // Increased timer for slower demon spawning
}
}
// Next wave
if (demons.length === 0 && !boss && waveTimer > 60) {
if (score >= 100 && score < 490 && Math.floor(score / 100) > Math.floor((score - (doublePointsActive ? 20 : 10)) / 100)) {
spawnBoss();
} else {
wave++;
waveTimer = 0;
}
}
waveTimer++;
} else {
// Wait for boss defeat
if (boss && boss.dead) {
bossActive = false;
boss = null;
wave++;
waveTimer = 0;
}
}
// Randomly spawn health packs
if (LK.ticks % 420 === 0 && Math.random() < 0.5) {
spawnHealthPack();
}
// Pulsate lava ground for hellish effect
if (LK.ticks % 120 === 0) {
var targetTint = Math.random() < 0.5 ? 0x990000 : 0x660000;
tween(lavaGround, {
tint: targetTint
}, {
duration: 1000,
easing: tween.easeInOut
});
}
};
// Reset game on game over
LK.on('gameover', function () {
startGame();
});
yumurta şeytan. In-Game asset. 2d. High contrast. No shadows
yuvarlak bir çerçevenin içerisinde şeytan kulaklı gülümseyen balkabağı kırmızı. In-Game asset. 2d. High contrast. No shadows
yarasa. In-Game asset. 2d. High contrast. No shadows
furca. In-Game asset. 2d. High contrast. No shadows
+. In-Game asset. 2d. High contrast. No shadows
angel . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue 2x. In-Game asset. 2d. High contrast. No shadows
bigg demon. In-Game asset. 2d. High contrast. No shadows
red sword. In-Game asset. 2d. High contrast. No shadows
ateş. In-Game asset. 2d. High contrast. No shadows
tsunami. In-Game asset. 2d. High contrast. No shadows
yeşil bar. In-Game asset. 2d. High contrast. No shadows