/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.vx = 0; self.vy = 0; self.lifetime = 120; self.update = function () { self.x += self.vx; self.y += self.vy; self.lifetime--; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.shootCooldown = 0; self.moveTimer = 0; // Enemy magazine/reload system self.magazine = 7; self.maxMagazine = 7; self.reloading = false; self.reloadTime = 1500; // ms self.reloadTimeout = null; // Start at a random non-captured zone position var availableZones = []; for (var k = 0; k < zones.length; k++) { if (!zones[k].captured) { availableZones.push(k); } } if (availableZones.length > 0) { var randomIndex = Math.floor(Math.random() * availableZones.length); var zoneIndex = availableZones[randomIndex]; self.targetX = [512, 1536, 512, 1536][zoneIndex]; self.targetY = [683, 683, 2049, 2049][zoneIndex]; } else { // If all zones are captured, default to center self.targetX = 1024; self.targetY = 1366; } self.update = function () { // Move towards target position var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 20) { // Store previous position var prevX = self.x; var prevY = self.y; self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; // Prevent enemy from moving through walls for (var w = 0; w < walls.length; w++) { if (self.intersects(walls[w])) { self.x = prevX; self.y = prevY; break; } } } // Change target position periodically self.moveTimer++; // Find available (uncaptured) zones var availableZones = []; for (var k = 0; k < zones.length; k++) { if (!zones[k].captured) { availableZones.push(k); } } // If only one zone left, allow random movement within that zone's area if (availableZones.length === 1) { if (self.moveTimer > 120 || dist < 20) { self.moveTimer = 0; var zoneIndex = availableZones[0]; // Pick a random point within the zone's bounds (±180px from center) var zx = [512, 1536, 512, 1536][zoneIndex]; var zy = [683, 683, 2049, 2049][zoneIndex]; var offsetX = (Math.random() - 0.5) * 360; var offsetY = (Math.random() - 0.5) * 360; self.targetX = zx + offsetX; self.targetY = zy + offsetY; } } else if (self.moveTimer > 180 || dist < 20) { self.moveTimer = 0; // Move to a random non-captured zone position if (availableZones.length > 0) { var randomIndex = Math.floor(Math.random() * availableZones.length); var zoneIndex = availableZones[randomIndex]; self.targetX = [512, 1536, 512, 1536][zoneIndex]; self.targetY = [683, 683, 2049, 2049][zoneIndex]; } } // Shoot at player if (self.shootCooldown > 0) { self.shootCooldown--; } else if (player) { var pdx = player.x - self.x; var pdy = player.y - self.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); // Only attack when within 500 pixel proximity if (pdist < 500) { self.shoot(player.x, player.y); } } }; self.shoot = function (targetX, targetY) { // Only shoot if not reloading and magazine > 0 if (self.reloading) { return; } if (self.magazine <= 0) { // Start reload if not already if (!self.reloading) { self.reloading = true; self.reloadTimeout = LK.setTimeout(function () { self.magazine = self.maxMagazine; self.reloading = false; }, self.reloadTime); } return; } var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; var dx = targetX - self.x; var dy = targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); bullet.vx = dx / dist * bullet.speed; bullet.vy = dy / dist * bullet.speed; bullet.isEnemyBullet = true; enemyBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.shootCooldown = 60; self.magazine--; if (self.magazine <= 0) { // Start reload self.reloading = true; self.reloadTimeout = LK.setTimeout(function () { self.magazine = self.maxMagazine; self.reloading = false; }, self.reloadTime); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Stylized, highly visible gun: colored barrel, body, handle, and sight // Gun barrel (long, thick, bright yellow) var gunBarrelLength = 70; var gunBarrel = self.attachAsset('zone', { width: gunBarrelLength, height: 18, tint: 0xffe066, anchorX: 0.1, anchorY: 0.5, alpha: 1 }); gunBarrel.x = 54; gunBarrel.y = 0; // Gun body (short, thick, black) var gunBody = self.attachAsset('zone', { width: 38, height: 28, tint: 0x222222, anchorX: 0.1, anchorY: 0.5, alpha: 1 }); gunBody.x = 38; gunBody.y = 0; // Gun handle (angled, orange) var gunHandle = self.attachAsset('zone', { width: 18, height: 36, tint: 0xff9900, anchorX: 0.1, anchorY: 0.1, alpha: 1 }); gunHandle.x = 38 + 20; gunHandle.y = 16; gunHandle.rotation = Math.PI / 2.1; // Gun trigger guard (small, black ellipse) var gunTrigger = self.attachAsset('bullet', { width: 12, height: 10, color: 0x111111, anchorX: 0.5, anchorY: 0.5, alpha: 0.9 }); gunTrigger.x = 38 + 10; gunTrigger.y = 13; // Gun sight (small, red dot at barrel tip) var gunSight = self.attachAsset('bullet', { width: 10, height: 10, color: 0xff2222, anchorX: 0.5, anchorY: 0.5, alpha: 1 }); gunSight.x = gunBarrel.x + gunBarrelLength - 10; gunSight.y = 0; // Group all as the gun self.gun = gunBarrel; self.gunBody = gunBody; self.gunHandle = gunHandle; self.gunTrigger = gunTrigger; self.gunSight = gunSight; self.gunAngle = 0; // Track current gun angle self.speed = 8; self.shootCooldown = 0; self.health = 12; self.maxHealth = 12; // Create health bar container var healthBar = self.addChild(new Container()); healthBar.y = -playerGraphics.height / 2 - 50; healthBar.visible = false; // Health bar background var healthBg = healthBar.attachAsset('zone', { width: 260, height: 28, tint: 0x333333, anchorX: 0.5, anchorY: 0.5 }); // Health bar fill var healthFill = healthBar.attachAsset('zone', { width: 252, height: 22, tint: 0x00ff00, anchorX: 0, anchorY: 0.5 }); healthFill.x = -130; self.healthBar = healthBar; self.healthFill = healthFill; self.healthBg = healthBg; self.takeDamage = function () { self.health--; self.healthBar.visible = true; // Update health bar width self.healthFill.width = self.health / self.maxHealth * 252; // Update health bar color based on health if (self.health <= 3) { self.healthFill.tint = 0xff0000; } else if (self.health <= 6) { self.healthFill.tint = 0xffaa00; } else { self.healthFill.tint = 0x00ff00; } // Flash effect LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { LK.showGameOver({ text: "Wasted" }); } }; // Override intersects to use a smaller hitbox for the player self.intersects = function (other) { // Use a smaller hitbox (60% of width/height, centered) var scale = 0.6; var px = self.x, py = self.y; var pw = playerGraphics.width * scale, ph = playerGraphics.height * scale; var pLeft = px - pw / 2, pRight = px + pw / 2, pTop = py - ph / 2, pBottom = py + ph / 2; // Get other's bounds (assume center anchor) var ox = other.x, oy = other.y; var ow = typeof other.width !== "undefined" ? other.width : other.graphics && other.graphics.width ? other.graphics.width : 0; var oh = typeof other.height !== "undefined" ? other.height : other.graphics && other.graphics.height ? other.graphics.height : 0; if (ow === 0 && typeof other.children !== "undefined" && other.children.length > 0 && typeof other.children[0].width !== "undefined") { ow = other.children[0].width; oh = other.children[0].height; } var oLeft = ox - ow / 2, oRight = ox + ow / 2, oTop = oy - oh / 2, oBottom = oy + oh / 2; // AABB collision return !(pRight < oLeft || pLeft > oRight || pBottom < oTop || pTop > oBottom); }; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.shoot = function (targetX, targetY) { // Magazine/cooldown logic if (typeof playerMagazine !== "undefined" && typeof playerReloading !== "undefined") { if (playerReloading) { // Can't shoot while reloading return; } if (playerMagazine <= 0) { // Start reload if not already if (!playerReloading) { playerReloading = true; // Track reload bar timing if (typeof Date !== "undefined") { reloadStartTime = Date.now(); reloadEndTime = reloadStartTime + playerReloadTime; } // Animate reload bar fill and bullet icons if (typeof reloadBar !== "undefined") { reloadBar.visible = true; reloadFill.width = 0; // Clear all bullet icons (hide them) when magazine is empty for (var i = 0; i < reloadBar.bulletIcons.length; i++) { reloadBar.bulletIcons[i].alpha = 0; reloadBar.bulletIcons[i].color = 0x888888; } } playerReloadTimeout = LK.setTimeout(function () { playerMagazine = playerMaxMagazine; playerReloading = false; reloadStartTime = 0; reloadEndTime = 0; // On reload complete, show all bullets as filled if (typeof reloadBar !== "undefined") { for (var i = 0; i < reloadBar.bulletIcons.length; i++) { reloadBar.bulletIcons[i].alpha = 1; reloadBar.bulletIcons[i].color = 0xffff00; } reloadFill.width = 200; } }, playerReloadTime); } return; } } if (self.shootCooldown <= 0) { // Use selected bullet type var type = bulletTypes[currentBulletType]; var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; // Change bullet asset and speed if (type.id !== 'bullet') { bullet.removeChild(bullet.children[0]); var bulletGraphics = bullet.attachAsset(type.id, { anchorX: 0.5, anchorY: 0.5 }); bullet.speed = type.speed; } else { bullet.speed = type.speed; } var dx = targetX - self.x; var dy = targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); bullet.vx = dx / dist * bullet.speed; bullet.vy = dy / dist * bullet.speed; // Rotate the gun towards the shooting direction if (self.gun) { var angle = Math.atan2(dy, dx); // If shooting to the left (targetX < self.x), teleport gun to left side if (targetX < self.x) { // Place gun on left side self.gun.x = -54; self.gunBody.x = -38; self.gunHandle.x = -38 - 20; self.gunTrigger.x = -38 - 10; // Sight will be repositioned below } else { // Place gun on right side (default) self.gun.x = 54; self.gunBody.x = 38; self.gunHandle.x = 38 + 20; self.gunTrigger.x = 38 + 10; // Sight will be repositioned below } self.gun.rotation = angle; self.gunAngle = angle; // Rotate the body and trigger to match the barrel if (self.gunBody) { self.gunBody.rotation = angle; } if (self.gunTrigger) { self.gunTrigger.rotation = angle; } // Rotate the handle with a slight offset to look like a real gun if (self.gunHandle) { self.gunHandle.rotation = angle + Math.PI / 2.1; } // Rotate and reposition the sight to always be at the barrel tip if (self.gunSight) { self.gunSight.rotation = angle; // Place at the tip of the barrel var barrelLen = 70; self.gunSight.x = self.gun.x + Math.cos(angle) * (barrelLen - 10); self.gunSight.y = self.gun.y + Math.sin(angle) * (barrelLen - 10); } } bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.shootCooldown = 15; // Decrement magazine if (typeof playerMagazine !== "undefined") { playerMagazine--; // Immediately update reload bar bullet icons after shooting if (typeof reloadBar !== "undefined" && reloadBar.bulletIcons) { for (var i = 0; i < reloadBar.bulletIcons.length; i++) { if (i < playerMagazine && !playerReloading) { reloadBar.bulletIcons[i].alpha = 1; reloadBar.bulletIcons[i].color = 0xffff00; } else { reloadBar.bulletIcons[i].alpha = 0.3; reloadBar.bulletIcons[i].color = 0x888888; } } } if (playerMagazine <= 0) { playerReloading = true; playerReloadTimeout = LK.setTimeout(function () { playerMagazine = playerMaxMagazine; playerReloading = false; }, playerReloadTime); } } } }; return self; }); // Wall class for bullet-blocking cover var Wall = Container.expand(function () { var self = Container.call(this); self.wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); self.isCapturedVisual = false; // Method to change wall visual to captured self.setCapturedVisual = function () { if (!self.isCapturedVisual) { self.removeChild(self.wallGraphics); self.wallGraphics = self.attachAsset('wall_captured', { anchorX: 0.5, anchorY: 0.5 }); self.isCapturedVisual = true; } }; // No update needed, static return self; }); var Zone = Container.expand(function (zoneIndex) { var self = Container.call(this); var zoneAssetId = 'zone' + (zoneIndex + 1); var zoneGraphics = self.attachAsset(zoneAssetId, { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); // Increase brightness using tween color effect (tint to a lighter color) tween(zoneGraphics, { tint: 0xffffff }, { duration: 500 }); self.graphics = zoneGraphics; self.captureProgress = 0; self.captureTime = 180; self.captured = false; self.playerInside = false; var progressBar = self.addChild(new Container()); progressBar.y = -zoneGraphics.height / 2 - 30; var progressBg = progressBar.attachAsset('zone', { width: 300, height: 20, tint: 0x333333, anchorX: 0.5, anchorY: 0.5 }); var progressFill = progressBar.attachAsset('zone', { width: 0, height: 16, tint: 0x00ff00, anchorX: 0, anchorY: 0.5 }); progressFill.x = -148; self.progressFill = progressFill; progressBar.visible = false; self.progressBar = progressBar; self.update = function () { if (self.playerInside && !self.captured) { self.captureProgress++; self.progressBar.visible = true; self.progressFill.width = self.captureProgress / self.captureTime * 296; if (self.captureProgress >= self.captureTime) { self.captured = true; self.graphics.tint = 0x00ff00; self.graphics.alpha = 0.5; self.progressBar.visible = false; LK.getSound('capture').play(); capturedZones++; updateScore(); // Change visual of only the nearest wall to this zone var nearestWall = null; var minDist = Infinity; for (var w = 0; w < walls.length; w++) { var wx = walls[w].x; var wy = walls[w].y; var dx = wx - self.x; var dy = wy - self.y; var distSq = dx * dx + dy * dy; if (distSq < minDist) { minDist = distSq; nearestWall = walls[w]; } } if (nearestWall && typeof nearestWall.setCapturedVisual === "function") { nearestWall.setCapturedVisual(); } // If all zones are captured, set all walls to captured visual if (capturedZones >= totalZones) { for (var w = 0; w < walls.length; w++) { if (typeof walls[w].setCapturedVisual === "function") { walls[w].setCapturedVisual(); } } } // No reload bar or magazine logic here; zone capture does not affect reload bar } } else if (!self.playerInside && self.captureProgress > 0 && !self.captured) { self.captureProgress = Math.max(0, self.captureProgress - 2); if (self.captureProgress === 0) { self.progressBar.visible = false; } else { self.progressFill.width = self.captureProgress / self.captureTime * 296; } } }; self.checkPlayerInside = function (player) { var halfWidth = self.graphics.width / 2; var halfHeight = self.graphics.height / 2; var dx = Math.abs(player.x - self.x); var dy = Math.abs(player.y - self.y); self.playerInside = dx < halfWidth && dy < halfHeight; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Wall asset for small cover/wall (cephé) var player; var bullets = []; var enemyBullets = []; var enemies = []; var zones = []; var walls = []; // Array for wall objects var capturedZones = 0; var totalZones = 4; var isDragging = false; var lastShootX = 0; var lastShootY = 0; // Bullet type switching var bulletTypes = [{ id: 'bullet', color: 0xffff00, speed: 15, size: 20 }, // normal { id: 'bullet_red', color: 0xff4444, speed: 10, size: 32 }, // slow, big { id: 'bullet_blue', color: 0x44aaff, speed: 22, size: 14 } // fast, small ]; var currentBulletType = 0; if (typeof storage.getItem === "function" && storage.getItem("currentBulletType") !== undefined && storage.getItem("currentBulletType") !== null) { currentBulletType = parseInt(storage.getItem("currentBulletType")); } // Dynamically create bullet assets if not already present for (var i = 1; i < bulletTypes.length; i++) { if (!LK.getAsset(bulletTypes[i].id, {})) {} } // UI for bullet type var bulletTypeTxt = new Text2('Bullet: Normal', { size: 60, fill: 0xffffff }); bulletTypeTxt.anchor.set(0.5, 0); bulletTypeTxt.y = 120; bulletTypeTxt.x = 1024; LK.gui.top.addChild(bulletTypeTxt); // Button to switch bullet type (simple text button) var switchBtn = new Text2('Change Bullet', { size: 60, fill: 0x00ffcc }); switchBtn.anchor.set(0.5, 0); switchBtn.y = 210; switchBtn.x = 1024; LK.gui.top.addChild(switchBtn); // Touch/click event for switchBtn switchBtn.down = function (x, y, obj) { currentBulletType = (currentBulletType + 1) % bulletTypes.length; storage.set("currentBulletType", currentBulletType); var names = ['Normal', 'Big', 'Fast']; bulletTypeTxt.setText('Bullet: ' + names[currentBulletType]); }; var scoreTxt = new Text2('Zones: 0/4', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); function updateScore() { scoreTxt.setText('Zones: ' + capturedZones + '/' + totalZones); if (capturedZones >= totalZones) { LK.showYouWin({ text: "Mission Passed" }); } ; // Update reload bar position and progress, animate fill and update bullet icons if (typeof reloadBar !== "undefined" && typeof player !== "undefined") { reloadBar.x = player.x; reloadBar.y = player.y - 170; // Update bullet icons: show filled for each bullet in magazine, empty for spent if (typeof playerMagazine !== "undefined" && reloadBar.bulletIcons) { for (var i = 0; i < reloadBar.bulletIcons.length; i++) { if (i < playerMagazine && !playerReloading) { reloadBar.bulletIcons[i].alpha = 1; reloadBar.bulletIcons[i].color = 0xffff00; } else { reloadBar.bulletIcons[i].alpha = 0.3; reloadBar.bulletIcons[i].color = 0x888888; } } } if (typeof playerReloading !== "undefined" && playerReloading) { reloadBar.visible = true; // Animate fill: (playerReloadTime - remaining) / playerReloadTime if (typeof reloadStartTime !== "undefined" && typeof reloadEndTime !== "undefined" && reloadStartTime > 0 && reloadEndTime > reloadStartTime) { var now = Date.now(); var progress = Math.min(1, Math.max(0, (now - reloadStartTime) / (reloadEndTime - reloadStartTime))); reloadFill.width = 200 * progress; // Animate bullet icons: fill them as reload progresses var bulletsToShow = Math.floor(progress * 10); for (var i = 0; i < reloadBar.bulletIcons.length; i++) { if (i < bulletsToShow) { reloadBar.bulletIcons[i].alpha = 1; reloadBar.bulletIcons[i].color = 0xffff00; } else { reloadBar.bulletIcons[i].alpha = 0.3; reloadBar.bulletIcons[i].color = 0x888888; } } } else { reloadFill.width = 0; } } else if (typeof playerReloading !== "undefined" && !playerReloading) { reloadBar.visible = true; reloadFill.width = 200; } } } ; // Magazine and cooldown for player shooting var playerMagazine = 10; var playerMaxMagazine = 10; var playerReloading = false; var playerReloadTimeout = null; var playerReloadTime = 1500; // ms // Track reload progress for bar var reloadStartTime = 0; var reloadEndTime = 0; player = game.addChild(new Player()); player.x = 1024; player.y = 1366; // Reload progress bar UI above player, with 7 bullet icons and animated fill var reloadBar = new Container(); // Background bar var reloadBg = reloadBar.attachAsset('reloadBarBg', { anchorX: 0.5, anchorY: 0.5 }); // Animated fill (for reload progress) var reloadFill = reloadBar.attachAsset('reloadBarFill', { width: 0, anchorX: 0, anchorY: 0.5 }); reloadFill.x = -100; reloadFill.y = 0; // 10 bullet icons (small ellipses) spaced evenly on the bar reloadBar.bulletIcons = []; var bulletIconSpacing = 20; var bulletIconStartX = -90; for (var i = 0; i < 10; i++) { var icon = reloadBar.attachAsset('bullet', { width: 18, height: 18, anchorX: 0.5, anchorY: 0.5, color: 0xffff00 }); icon.x = bulletIconStartX + i * bulletIconSpacing; icon.y = 0; reloadBar.bulletIcons.push(icon); } reloadBar.visible = true; game.addChild(reloadBar); var zonePositions = [{ x: 512, y: 683 }, { x: 1536, y: 683 }, { x: 512, y: 2049 }, { x: 1536, y: 2049 }]; for (var i = 0; i < zonePositions.length; i++) { var zone = new Zone(i); zone.x = zonePositions[i].x; zone.y = zonePositions[i].y; zones.push(zone); game.addChild(zone); } // Place walls (cephé) at strategic locations var wallPositions = [{ x: 1024, y: 500, rotation: 0 }, // Top center { x: 1024, y: 2200, rotation: 0 }, // Bottom center { x: 400, y: 1366, rotation: Math.PI / 2 }, // Left center { x: 1648, y: 1366, rotation: Math.PI / 2 }, // Right center { x: 800, y: 900, rotation: 0.3 }, // Near zone 1 { x: 1300, y: 1800, rotation: -0.3 } // Near zone 4 ]; for (var i = 0; i < wallPositions.length; i++) { var wall = new Wall(); wall.x = wallPositions[i].x; wall.y = wallPositions[i].y; if (wallPositions[i].rotation) wall.rotation = wallPositions[i].rotation; walls.push(wall); game.addChild(wall); } // Spawn enemies at zone positions for (var i = 0; i < 3; i++) { var enemy = new Enemy(); var zoneIndex = i % zonePositions.length; enemy.x = zonePositions[zoneIndex].x; enemy.y = zonePositions[zoneIndex].y; enemies.push(enemy); game.addChild(enemy); } game.down = function (x, y, obj) { isDragging = true; lastShootX = x; lastShootY = y; }; game.move = function (x, y, obj) { if (isDragging) { // Calculate drag direction from last position var dx = x - lastShootX; var dy = y - lastShootY; var dist = Math.sqrt(dx * dx + dy * dy); // Move player in the direction of the drag, but slower if (dist > 0) { var moveScale = 0.5; // Increase speed to 50% of drag // Store previous position var prevX = player.x; var prevY = player.y; player.x += dx * moveScale; player.y += dy * moveScale; player.x = Math.max(30, Math.min(2018, player.x)); player.y = Math.max(30, Math.min(2702, player.y)); // Check collision with walls, revert if colliding for (var w = 0; w < walls.length; w++) { if (player.intersects(walls[w])) { player.x = prevX; player.y = prevY; break; } } } lastShootX = x; lastShootY = y; } }; game.up = function (x, y, obj) { if (isDragging) { player.shoot(x, y); isDragging = false; } }; game.update = function () { // Update reload bar position to follow player if (typeof reloadBar !== "undefined" && typeof player !== "undefined") { reloadBar.x = player.x; reloadBar.y = player.y - 170; } // Update zones for (var i = zones.length - 1; i >= 0; i--) { zones[i].checkPlayerInside(player); } // Update player bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Block by wall var hitWall = false; for (var w = 0; w < walls.length; w++) { if (bullet.intersects(walls[w])) { hitWall = true; break; } } if (hitWall || bullet.lifetime <= 0 || bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { bullet.destroy(); bullets.splice(i, 1); // Mini explosion effect at enemy position var explosion = new Container(); var expAsset = explosion.attachAsset('bullet', { width: 80, height: 80, color: 0xffaa00, anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); explosion.x = enemies[j].x; explosion.y = enemies[j].y; game.addChild(explosion); // Animate explosion: scale up and fade out, then destroy tween(expAsset, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 350, onComplete: function onComplete() { explosion.destroy(); } }); enemies[j].destroy(); enemies.splice(j, 1); // Spawn new enemy at a random non-captured zone position // Recalculate availableZones at spawn time to ensure accuracy if (zones.filter(function (z) { return !z.captured; }).length > 0) { // Delay enemy spawn by 2 seconds (2000ms) LK.setTimeout(function () { var availableZones = []; for (var k = 0; k < zones.length; k++) { if (!zones[k].captured) { availableZones.push(k); } } if (availableZones.length > 0) { var newEnemy = new Enemy(); var randomIndex = Math.floor(Math.random() * availableZones.length); var zoneIndex = availableZones[randomIndex]; newEnemy.x = zonePositions[zoneIndex].x; newEnemy.y = zonePositions[zoneIndex].y; enemies.push(newEnemy); game.addChild(newEnemy); } }, 2000); } break; } } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Block by wall var hitWall = false; for (var w = 0; w < walls.length; w++) { if (bullet.intersects(walls[w])) { hitWall = true; break; } } if (hitWall || bullet.lifetime <= 0 || bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } // Check collision with player if (bullet.intersects(player)) { bullet.destroy(); enemyBullets.splice(i, 1); player.takeDamage(); } // Example: Restart the game if you want to force a full reset (uncomment to use) // LK.showGameOver(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.vx = 0;
self.vy = 0;
self.lifetime = 120;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.lifetime--;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.shootCooldown = 0;
self.moveTimer = 0;
// Enemy magazine/reload system
self.magazine = 7;
self.maxMagazine = 7;
self.reloading = false;
self.reloadTime = 1500; // ms
self.reloadTimeout = null;
// Start at a random non-captured zone position
var availableZones = [];
for (var k = 0; k < zones.length; k++) {
if (!zones[k].captured) {
availableZones.push(k);
}
}
if (availableZones.length > 0) {
var randomIndex = Math.floor(Math.random() * availableZones.length);
var zoneIndex = availableZones[randomIndex];
self.targetX = [512, 1536, 512, 1536][zoneIndex];
self.targetY = [683, 683, 2049, 2049][zoneIndex];
} else {
// If all zones are captured, default to center
self.targetX = 1024;
self.targetY = 1366;
}
self.update = function () {
// Move towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 20) {
// Store previous position
var prevX = self.x;
var prevY = self.y;
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
// Prevent enemy from moving through walls
for (var w = 0; w < walls.length; w++) {
if (self.intersects(walls[w])) {
self.x = prevX;
self.y = prevY;
break;
}
}
}
// Change target position periodically
self.moveTimer++;
// Find available (uncaptured) zones
var availableZones = [];
for (var k = 0; k < zones.length; k++) {
if (!zones[k].captured) {
availableZones.push(k);
}
}
// If only one zone left, allow random movement within that zone's area
if (availableZones.length === 1) {
if (self.moveTimer > 120 || dist < 20) {
self.moveTimer = 0;
var zoneIndex = availableZones[0];
// Pick a random point within the zone's bounds (±180px from center)
var zx = [512, 1536, 512, 1536][zoneIndex];
var zy = [683, 683, 2049, 2049][zoneIndex];
var offsetX = (Math.random() - 0.5) * 360;
var offsetY = (Math.random() - 0.5) * 360;
self.targetX = zx + offsetX;
self.targetY = zy + offsetY;
}
} else if (self.moveTimer > 180 || dist < 20) {
self.moveTimer = 0;
// Move to a random non-captured zone position
if (availableZones.length > 0) {
var randomIndex = Math.floor(Math.random() * availableZones.length);
var zoneIndex = availableZones[randomIndex];
self.targetX = [512, 1536, 512, 1536][zoneIndex];
self.targetY = [683, 683, 2049, 2049][zoneIndex];
}
}
// Shoot at player
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else if (player) {
var pdx = player.x - self.x;
var pdy = player.y - self.y;
var pdist = Math.sqrt(pdx * pdx + pdy * pdy);
// Only attack when within 500 pixel proximity
if (pdist < 500) {
self.shoot(player.x, player.y);
}
}
};
self.shoot = function (targetX, targetY) {
// Only shoot if not reloading and magazine > 0
if (self.reloading) {
return;
}
if (self.magazine <= 0) {
// Start reload if not already
if (!self.reloading) {
self.reloading = true;
self.reloadTimeout = LK.setTimeout(function () {
self.magazine = self.maxMagazine;
self.reloading = false;
}, self.reloadTime);
}
return;
}
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
var dx = targetX - self.x;
var dy = targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
bullet.vx = dx / dist * bullet.speed;
bullet.vy = dy / dist * bullet.speed;
bullet.isEnemyBullet = true;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 60;
self.magazine--;
if (self.magazine <= 0) {
// Start reload
self.reloading = true;
self.reloadTimeout = LK.setTimeout(function () {
self.magazine = self.maxMagazine;
self.reloading = false;
}, self.reloadTime);
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Stylized, highly visible gun: colored barrel, body, handle, and sight
// Gun barrel (long, thick, bright yellow)
var gunBarrelLength = 70;
var gunBarrel = self.attachAsset('zone', {
width: gunBarrelLength,
height: 18,
tint: 0xffe066,
anchorX: 0.1,
anchorY: 0.5,
alpha: 1
});
gunBarrel.x = 54;
gunBarrel.y = 0;
// Gun body (short, thick, black)
var gunBody = self.attachAsset('zone', {
width: 38,
height: 28,
tint: 0x222222,
anchorX: 0.1,
anchorY: 0.5,
alpha: 1
});
gunBody.x = 38;
gunBody.y = 0;
// Gun handle (angled, orange)
var gunHandle = self.attachAsset('zone', {
width: 18,
height: 36,
tint: 0xff9900,
anchorX: 0.1,
anchorY: 0.1,
alpha: 1
});
gunHandle.x = 38 + 20;
gunHandle.y = 16;
gunHandle.rotation = Math.PI / 2.1;
// Gun trigger guard (small, black ellipse)
var gunTrigger = self.attachAsset('bullet', {
width: 12,
height: 10,
color: 0x111111,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
gunTrigger.x = 38 + 10;
gunTrigger.y = 13;
// Gun sight (small, red dot at barrel tip)
var gunSight = self.attachAsset('bullet', {
width: 10,
height: 10,
color: 0xff2222,
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
gunSight.x = gunBarrel.x + gunBarrelLength - 10;
gunSight.y = 0;
// Group all as the gun
self.gun = gunBarrel;
self.gunBody = gunBody;
self.gunHandle = gunHandle;
self.gunTrigger = gunTrigger;
self.gunSight = gunSight;
self.gunAngle = 0; // Track current gun angle
self.speed = 8;
self.shootCooldown = 0;
self.health = 12;
self.maxHealth = 12;
// Create health bar container
var healthBar = self.addChild(new Container());
healthBar.y = -playerGraphics.height / 2 - 50;
healthBar.visible = false;
// Health bar background
var healthBg = healthBar.attachAsset('zone', {
width: 260,
height: 28,
tint: 0x333333,
anchorX: 0.5,
anchorY: 0.5
});
// Health bar fill
var healthFill = healthBar.attachAsset('zone', {
width: 252,
height: 22,
tint: 0x00ff00,
anchorX: 0,
anchorY: 0.5
});
healthFill.x = -130;
self.healthBar = healthBar;
self.healthFill = healthFill;
self.healthBg = healthBg;
self.takeDamage = function () {
self.health--;
self.healthBar.visible = true;
// Update health bar width
self.healthFill.width = self.health / self.maxHealth * 252;
// Update health bar color based on health
if (self.health <= 3) {
self.healthFill.tint = 0xff0000;
} else if (self.health <= 6) {
self.healthFill.tint = 0xffaa00;
} else {
self.healthFill.tint = 0x00ff00;
}
// Flash effect
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
LK.showGameOver({
text: "Wasted"
});
}
};
// Override intersects to use a smaller hitbox for the player
self.intersects = function (other) {
// Use a smaller hitbox (60% of width/height, centered)
var scale = 0.6;
var px = self.x,
py = self.y;
var pw = playerGraphics.width * scale,
ph = playerGraphics.height * scale;
var pLeft = px - pw / 2,
pRight = px + pw / 2,
pTop = py - ph / 2,
pBottom = py + ph / 2;
// Get other's bounds (assume center anchor)
var ox = other.x,
oy = other.y;
var ow = typeof other.width !== "undefined" ? other.width : other.graphics && other.graphics.width ? other.graphics.width : 0;
var oh = typeof other.height !== "undefined" ? other.height : other.graphics && other.graphics.height ? other.graphics.height : 0;
if (ow === 0 && typeof other.children !== "undefined" && other.children.length > 0 && typeof other.children[0].width !== "undefined") {
ow = other.children[0].width;
oh = other.children[0].height;
}
var oLeft = ox - ow / 2,
oRight = ox + ow / 2,
oTop = oy - oh / 2,
oBottom = oy + oh / 2;
// AABB collision
return !(pRight < oLeft || pLeft > oRight || pBottom < oTop || pTop > oBottom);
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.shoot = function (targetX, targetY) {
// Magazine/cooldown logic
if (typeof playerMagazine !== "undefined" && typeof playerReloading !== "undefined") {
if (playerReloading) {
// Can't shoot while reloading
return;
}
if (playerMagazine <= 0) {
// Start reload if not already
if (!playerReloading) {
playerReloading = true;
// Track reload bar timing
if (typeof Date !== "undefined") {
reloadStartTime = Date.now();
reloadEndTime = reloadStartTime + playerReloadTime;
}
// Animate reload bar fill and bullet icons
if (typeof reloadBar !== "undefined") {
reloadBar.visible = true;
reloadFill.width = 0;
// Clear all bullet icons (hide them) when magazine is empty
for (var i = 0; i < reloadBar.bulletIcons.length; i++) {
reloadBar.bulletIcons[i].alpha = 0;
reloadBar.bulletIcons[i].color = 0x888888;
}
}
playerReloadTimeout = LK.setTimeout(function () {
playerMagazine = playerMaxMagazine;
playerReloading = false;
reloadStartTime = 0;
reloadEndTime = 0;
// On reload complete, show all bullets as filled
if (typeof reloadBar !== "undefined") {
for (var i = 0; i < reloadBar.bulletIcons.length; i++) {
reloadBar.bulletIcons[i].alpha = 1;
reloadBar.bulletIcons[i].color = 0xffff00;
}
reloadFill.width = 200;
}
}, playerReloadTime);
}
return;
}
}
if (self.shootCooldown <= 0) {
// Use selected bullet type
var type = bulletTypes[currentBulletType];
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
// Change bullet asset and speed
if (type.id !== 'bullet') {
bullet.removeChild(bullet.children[0]);
var bulletGraphics = bullet.attachAsset(type.id, {
anchorX: 0.5,
anchorY: 0.5
});
bullet.speed = type.speed;
} else {
bullet.speed = type.speed;
}
var dx = targetX - self.x;
var dy = targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
bullet.vx = dx / dist * bullet.speed;
bullet.vy = dy / dist * bullet.speed;
// Rotate the gun towards the shooting direction
if (self.gun) {
var angle = Math.atan2(dy, dx);
// If shooting to the left (targetX < self.x), teleport gun to left side
if (targetX < self.x) {
// Place gun on left side
self.gun.x = -54;
self.gunBody.x = -38;
self.gunHandle.x = -38 - 20;
self.gunTrigger.x = -38 - 10;
// Sight will be repositioned below
} else {
// Place gun on right side (default)
self.gun.x = 54;
self.gunBody.x = 38;
self.gunHandle.x = 38 + 20;
self.gunTrigger.x = 38 + 10;
// Sight will be repositioned below
}
self.gun.rotation = angle;
self.gunAngle = angle;
// Rotate the body and trigger to match the barrel
if (self.gunBody) {
self.gunBody.rotation = angle;
}
if (self.gunTrigger) {
self.gunTrigger.rotation = angle;
}
// Rotate the handle with a slight offset to look like a real gun
if (self.gunHandle) {
self.gunHandle.rotation = angle + Math.PI / 2.1;
}
// Rotate and reposition the sight to always be at the barrel tip
if (self.gunSight) {
self.gunSight.rotation = angle;
// Place at the tip of the barrel
var barrelLen = 70;
self.gunSight.x = self.gun.x + Math.cos(angle) * (barrelLen - 10);
self.gunSight.y = self.gun.y + Math.sin(angle) * (barrelLen - 10);
}
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 15;
// Decrement magazine
if (typeof playerMagazine !== "undefined") {
playerMagazine--;
// Immediately update reload bar bullet icons after shooting
if (typeof reloadBar !== "undefined" && reloadBar.bulletIcons) {
for (var i = 0; i < reloadBar.bulletIcons.length; i++) {
if (i < playerMagazine && !playerReloading) {
reloadBar.bulletIcons[i].alpha = 1;
reloadBar.bulletIcons[i].color = 0xffff00;
} else {
reloadBar.bulletIcons[i].alpha = 0.3;
reloadBar.bulletIcons[i].color = 0x888888;
}
}
}
if (playerMagazine <= 0) {
playerReloading = true;
playerReloadTimeout = LK.setTimeout(function () {
playerMagazine = playerMaxMagazine;
playerReloading = false;
}, playerReloadTime);
}
}
}
};
return self;
});
// Wall class for bullet-blocking cover
var Wall = Container.expand(function () {
var self = Container.call(this);
self.wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.isCapturedVisual = false;
// Method to change wall visual to captured
self.setCapturedVisual = function () {
if (!self.isCapturedVisual) {
self.removeChild(self.wallGraphics);
self.wallGraphics = self.attachAsset('wall_captured', {
anchorX: 0.5,
anchorY: 0.5
});
self.isCapturedVisual = true;
}
};
// No update needed, static
return self;
});
var Zone = Container.expand(function (zoneIndex) {
var self = Container.call(this);
var zoneAssetId = 'zone' + (zoneIndex + 1);
var zoneGraphics = self.attachAsset(zoneAssetId, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
// Increase brightness using tween color effect (tint to a lighter color)
tween(zoneGraphics, {
tint: 0xffffff
}, {
duration: 500
});
self.graphics = zoneGraphics;
self.captureProgress = 0;
self.captureTime = 180;
self.captured = false;
self.playerInside = false;
var progressBar = self.addChild(new Container());
progressBar.y = -zoneGraphics.height / 2 - 30;
var progressBg = progressBar.attachAsset('zone', {
width: 300,
height: 20,
tint: 0x333333,
anchorX: 0.5,
anchorY: 0.5
});
var progressFill = progressBar.attachAsset('zone', {
width: 0,
height: 16,
tint: 0x00ff00,
anchorX: 0,
anchorY: 0.5
});
progressFill.x = -148;
self.progressFill = progressFill;
progressBar.visible = false;
self.progressBar = progressBar;
self.update = function () {
if (self.playerInside && !self.captured) {
self.captureProgress++;
self.progressBar.visible = true;
self.progressFill.width = self.captureProgress / self.captureTime * 296;
if (self.captureProgress >= self.captureTime) {
self.captured = true;
self.graphics.tint = 0x00ff00;
self.graphics.alpha = 0.5;
self.progressBar.visible = false;
LK.getSound('capture').play();
capturedZones++;
updateScore();
// Change visual of only the nearest wall to this zone
var nearestWall = null;
var minDist = Infinity;
for (var w = 0; w < walls.length; w++) {
var wx = walls[w].x;
var wy = walls[w].y;
var dx = wx - self.x;
var dy = wy - self.y;
var distSq = dx * dx + dy * dy;
if (distSq < minDist) {
minDist = distSq;
nearestWall = walls[w];
}
}
if (nearestWall && typeof nearestWall.setCapturedVisual === "function") {
nearestWall.setCapturedVisual();
}
// If all zones are captured, set all walls to captured visual
if (capturedZones >= totalZones) {
for (var w = 0; w < walls.length; w++) {
if (typeof walls[w].setCapturedVisual === "function") {
walls[w].setCapturedVisual();
}
}
}
// No reload bar or magazine logic here; zone capture does not affect reload bar
}
} else if (!self.playerInside && self.captureProgress > 0 && !self.captured) {
self.captureProgress = Math.max(0, self.captureProgress - 2);
if (self.captureProgress === 0) {
self.progressBar.visible = false;
} else {
self.progressFill.width = self.captureProgress / self.captureTime * 296;
}
}
};
self.checkPlayerInside = function (player) {
var halfWidth = self.graphics.width / 2;
var halfHeight = self.graphics.height / 2;
var dx = Math.abs(player.x - self.x);
var dy = Math.abs(player.y - self.y);
self.playerInside = dx < halfWidth && dy < halfHeight;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Wall asset for small cover/wall (cephé)
var player;
var bullets = [];
var enemyBullets = [];
var enemies = [];
var zones = [];
var walls = []; // Array for wall objects
var capturedZones = 0;
var totalZones = 4;
var isDragging = false;
var lastShootX = 0;
var lastShootY = 0;
// Bullet type switching
var bulletTypes = [{
id: 'bullet',
color: 0xffff00,
speed: 15,
size: 20
},
// normal
{
id: 'bullet_red',
color: 0xff4444,
speed: 10,
size: 32
},
// slow, big
{
id: 'bullet_blue',
color: 0x44aaff,
speed: 22,
size: 14
} // fast, small
];
var currentBulletType = 0;
if (typeof storage.getItem === "function" && storage.getItem("currentBulletType") !== undefined && storage.getItem("currentBulletType") !== null) {
currentBulletType = parseInt(storage.getItem("currentBulletType"));
}
// Dynamically create bullet assets if not already present
for (var i = 1; i < bulletTypes.length; i++) {
if (!LK.getAsset(bulletTypes[i].id, {})) {}
}
// UI for bullet type
var bulletTypeTxt = new Text2('Bullet: Normal', {
size: 60,
fill: 0xffffff
});
bulletTypeTxt.anchor.set(0.5, 0);
bulletTypeTxt.y = 120;
bulletTypeTxt.x = 1024;
LK.gui.top.addChild(bulletTypeTxt);
// Button to switch bullet type (simple text button)
var switchBtn = new Text2('Change Bullet', {
size: 60,
fill: 0x00ffcc
});
switchBtn.anchor.set(0.5, 0);
switchBtn.y = 210;
switchBtn.x = 1024;
LK.gui.top.addChild(switchBtn);
// Touch/click event for switchBtn
switchBtn.down = function (x, y, obj) {
currentBulletType = (currentBulletType + 1) % bulletTypes.length;
storage.set("currentBulletType", currentBulletType);
var names = ['Normal', 'Big', 'Fast'];
bulletTypeTxt.setText('Bullet: ' + names[currentBulletType]);
};
var scoreTxt = new Text2('Zones: 0/4', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
function updateScore() {
scoreTxt.setText('Zones: ' + capturedZones + '/' + totalZones);
if (capturedZones >= totalZones) {
LK.showYouWin({
text: "Mission Passed"
});
}
;
// Update reload bar position and progress, animate fill and update bullet icons
if (typeof reloadBar !== "undefined" && typeof player !== "undefined") {
reloadBar.x = player.x;
reloadBar.y = player.y - 170;
// Update bullet icons: show filled for each bullet in magazine, empty for spent
if (typeof playerMagazine !== "undefined" && reloadBar.bulletIcons) {
for (var i = 0; i < reloadBar.bulletIcons.length; i++) {
if (i < playerMagazine && !playerReloading) {
reloadBar.bulletIcons[i].alpha = 1;
reloadBar.bulletIcons[i].color = 0xffff00;
} else {
reloadBar.bulletIcons[i].alpha = 0.3;
reloadBar.bulletIcons[i].color = 0x888888;
}
}
}
if (typeof playerReloading !== "undefined" && playerReloading) {
reloadBar.visible = true;
// Animate fill: (playerReloadTime - remaining) / playerReloadTime
if (typeof reloadStartTime !== "undefined" && typeof reloadEndTime !== "undefined" && reloadStartTime > 0 && reloadEndTime > reloadStartTime) {
var now = Date.now();
var progress = Math.min(1, Math.max(0, (now - reloadStartTime) / (reloadEndTime - reloadStartTime)));
reloadFill.width = 200 * progress;
// Animate bullet icons: fill them as reload progresses
var bulletsToShow = Math.floor(progress * 10);
for (var i = 0; i < reloadBar.bulletIcons.length; i++) {
if (i < bulletsToShow) {
reloadBar.bulletIcons[i].alpha = 1;
reloadBar.bulletIcons[i].color = 0xffff00;
} else {
reloadBar.bulletIcons[i].alpha = 0.3;
reloadBar.bulletIcons[i].color = 0x888888;
}
}
} else {
reloadFill.width = 0;
}
} else if (typeof playerReloading !== "undefined" && !playerReloading) {
reloadBar.visible = true;
reloadFill.width = 200;
}
}
}
;
// Magazine and cooldown for player shooting
var playerMagazine = 10;
var playerMaxMagazine = 10;
var playerReloading = false;
var playerReloadTimeout = null;
var playerReloadTime = 1500; // ms
// Track reload progress for bar
var reloadStartTime = 0;
var reloadEndTime = 0;
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Reload progress bar UI above player, with 7 bullet icons and animated fill
var reloadBar = new Container();
// Background bar
var reloadBg = reloadBar.attachAsset('reloadBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Animated fill (for reload progress)
var reloadFill = reloadBar.attachAsset('reloadBarFill', {
width: 0,
anchorX: 0,
anchorY: 0.5
});
reloadFill.x = -100;
reloadFill.y = 0;
// 10 bullet icons (small ellipses) spaced evenly on the bar
reloadBar.bulletIcons = [];
var bulletIconSpacing = 20;
var bulletIconStartX = -90;
for (var i = 0; i < 10; i++) {
var icon = reloadBar.attachAsset('bullet', {
width: 18,
height: 18,
anchorX: 0.5,
anchorY: 0.5,
color: 0xffff00
});
icon.x = bulletIconStartX + i * bulletIconSpacing;
icon.y = 0;
reloadBar.bulletIcons.push(icon);
}
reloadBar.visible = true;
game.addChild(reloadBar);
var zonePositions = [{
x: 512,
y: 683
}, {
x: 1536,
y: 683
}, {
x: 512,
y: 2049
}, {
x: 1536,
y: 2049
}];
for (var i = 0; i < zonePositions.length; i++) {
var zone = new Zone(i);
zone.x = zonePositions[i].x;
zone.y = zonePositions[i].y;
zones.push(zone);
game.addChild(zone);
}
// Place walls (cephé) at strategic locations
var wallPositions = [{
x: 1024,
y: 500,
rotation: 0
},
// Top center
{
x: 1024,
y: 2200,
rotation: 0
},
// Bottom center
{
x: 400,
y: 1366,
rotation: Math.PI / 2
},
// Left center
{
x: 1648,
y: 1366,
rotation: Math.PI / 2
},
// Right center
{
x: 800,
y: 900,
rotation: 0.3
},
// Near zone 1
{
x: 1300,
y: 1800,
rotation: -0.3
} // Near zone 4
];
for (var i = 0; i < wallPositions.length; i++) {
var wall = new Wall();
wall.x = wallPositions[i].x;
wall.y = wallPositions[i].y;
if (wallPositions[i].rotation) wall.rotation = wallPositions[i].rotation;
walls.push(wall);
game.addChild(wall);
}
// Spawn enemies at zone positions
for (var i = 0; i < 3; i++) {
var enemy = new Enemy();
var zoneIndex = i % zonePositions.length;
enemy.x = zonePositions[zoneIndex].x;
enemy.y = zonePositions[zoneIndex].y;
enemies.push(enemy);
game.addChild(enemy);
}
game.down = function (x, y, obj) {
isDragging = true;
lastShootX = x;
lastShootY = y;
};
game.move = function (x, y, obj) {
if (isDragging) {
// Calculate drag direction from last position
var dx = x - lastShootX;
var dy = y - lastShootY;
var dist = Math.sqrt(dx * dx + dy * dy);
// Move player in the direction of the drag, but slower
if (dist > 0) {
var moveScale = 0.5; // Increase speed to 50% of drag
// Store previous position
var prevX = player.x;
var prevY = player.y;
player.x += dx * moveScale;
player.y += dy * moveScale;
player.x = Math.max(30, Math.min(2018, player.x));
player.y = Math.max(30, Math.min(2702, player.y));
// Check collision with walls, revert if colliding
for (var w = 0; w < walls.length; w++) {
if (player.intersects(walls[w])) {
player.x = prevX;
player.y = prevY;
break;
}
}
}
lastShootX = x;
lastShootY = y;
}
};
game.up = function (x, y, obj) {
if (isDragging) {
player.shoot(x, y);
isDragging = false;
}
};
game.update = function () {
// Update reload bar position to follow player
if (typeof reloadBar !== "undefined" && typeof player !== "undefined") {
reloadBar.x = player.x;
reloadBar.y = player.y - 170;
}
// Update zones
for (var i = zones.length - 1; i >= 0; i--) {
zones[i].checkPlayerInside(player);
}
// Update player bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Block by wall
var hitWall = false;
for (var w = 0; w < walls.length; w++) {
if (bullet.intersects(walls[w])) {
hitWall = true;
break;
}
}
if (hitWall || bullet.lifetime <= 0 || bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
if (bullet.intersects(enemies[j])) {
bullet.destroy();
bullets.splice(i, 1);
// Mini explosion effect at enemy position
var explosion = new Container();
var expAsset = explosion.attachAsset('bullet', {
width: 80,
height: 80,
color: 0xffaa00,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
explosion.x = enemies[j].x;
explosion.y = enemies[j].y;
game.addChild(explosion);
// Animate explosion: scale up and fade out, then destroy
tween(expAsset, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 350,
onComplete: function onComplete() {
explosion.destroy();
}
});
enemies[j].destroy();
enemies.splice(j, 1);
// Spawn new enemy at a random non-captured zone position
// Recalculate availableZones at spawn time to ensure accuracy
if (zones.filter(function (z) {
return !z.captured;
}).length > 0) {
// Delay enemy spawn by 2 seconds (2000ms)
LK.setTimeout(function () {
var availableZones = [];
for (var k = 0; k < zones.length; k++) {
if (!zones[k].captured) {
availableZones.push(k);
}
}
if (availableZones.length > 0) {
var newEnemy = new Enemy();
var randomIndex = Math.floor(Math.random() * availableZones.length);
var zoneIndex = availableZones[randomIndex];
newEnemy.x = zonePositions[zoneIndex].x;
newEnemy.y = zonePositions[zoneIndex].y;
enemies.push(newEnemy);
game.addChild(newEnemy);
}
}, 2000);
}
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Block by wall
var hitWall = false;
for (var w = 0; w < walls.length; w++) {
if (bullet.intersects(walls[w])) {
hitWall = true;
break;
}
}
if (hitWall || bullet.lifetime <= 0 || bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
bullet.destroy();
enemyBullets.splice(i, 1);
player.takeDamage();
}
// Example: Restart the game if you want to force a full reset (uncomment to use)
// LK.showGameOver();
}
};
Gangside ghetto Neighbourhood. In-Game asset. 2d. High contrast. No shadows
Tuğladan duvar üzerinde ballas grafitisi var,west side tarzında. In-Game asset. 2d. High contrast. No shadows
Tuğla duvar duvarda CJ's Gang yazacak. In-Game asset. 2d. High contrast. No shadows
CJ. In-Game asset. 2d. High contrast. No shadows
Ballas üyesi gang. In-Game asset. 2d. High contrast. No shadows