User prompt
Add a method to randomly select two DIFFERENT power-up types from PowerUpTypes enum. Exclude 'DEFAULT' from the options. Return them as an object with: - leftPowerUp: type for left crate - rightPowerUp: type for right crate
User prompt
Add a getSpawnPositions() method that returns an object with: - leftX: road's left edge minus 100 pixels - rightX: road's right edge plus 100 pixels Use the RoadScroll position as reference for the center.
User prompt
Create a CrateSpawnManager class using Container.expand. For now, just add: - lastSpawnTime variable initialized to 0 - minSpawnInterval set to 300 ticks - maxSpawnInterval set to 600 ticks Give me this base class and I'll help expand it.
User prompt
Add all power ups to the pool
User prompt
Add drone and bruiser down to game.
User prompt
Okay the bombblast is appearing. But it needs to grow rapidly until it reaches target scale. Adjust bomb blast class accordingly.
User prompt
It’s still not visible. Debug the bombblast class and the power manager bomb icon power up behavior.
User prompt
Please tell me why bombblast is not visible when being called in power up manager.
User prompt
Make sure bombblast is on a visible layer.
User prompt
Increase the intensity and duration of shake during bomb
User prompt
Increase the intensity and duration of shake during bomb
User prompt
Increase the intensity and duration of the bomb power up
User prompt
Remove the flash from bomb power up
User prompt
Make only bomb power ups drop for now
User prompt
Create a BombBlast class similar to HeroBullet: var BombBlast = Container.expand(function() { var self = Container.call(this); var blastGraphics = self.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5 }); self.scale = 3; self.update = function() { self.scale += 0.2; if (self.scale >= 10) { self.destroy(); } }; }); // Then in bombBehavior: this.bombBehavior = function() { var blast = new BombBlast(); blast.x = 1024; blast.y = 1366; blast.zIndex = 1000; game.addChild(blast); // Rest of the code... };
User prompt
Slow the scaling of bomb blast by half
User prompt
Update bomb blast with simpler update logic: this.bombBehavior = function() { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, // Start smaller scaleY: 3 }); blast.x = 1024; blast.y = 1366; blast.zIndex = 1000; blast.isScaling = true; // Simple flag to control scaling blast.scaleCount = 0; // Counter to control destruction blast.update = function() { if (this.isScaling) { this.scale += 0.2; this.scaleCount++; if (this.scaleCount > 30) { // Destroy after 30 updates this.destroy(); } } }; game.addChild(blast); // Rest of the code (enemy destruction, flash, shake) stays the same... };
User prompt
Update bomb blast with only scale changes: this.bombBehavior = function() { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 5, scaleY: 5 }); blast.x = 1024; blast.y = 1366; blast.zIndex = 1000; // Add update function to blast with only scale changes blast.update = function() { if (this.scaleTarget) { this.scale += 0.2; // Just increment scale each update if (this.scale >= this.scaleTarget) { this.destroy(); } } }; blast.scaleTarget = 10; // Set target scale for expansion game.addChild(blast); // Kill enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i] && enemies[i].y > 0) { enemies[i].HitPoints = 0; } } // Flash effect after blast is created LK.setTimeout(function() { var flash = new Container(); var flashGraphics = flash.attachAsset('whitePixel', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 30 }); flash.x = game.width / 2; flash.y = game.height / 2; flash.alpha = 0.8; game.addChild(flash); LK.setTimeout(function() { flash.destroy(); }, 100); }, 100); // Screen shake var originalX = game.x; var shakeAmount = 20; game.x += shakeAmount; LK.setTimeout(function() { game.x -= shakeAmount * 2; LK.setTimeout(function() { game.x += shakeAmount; LK.setTimeout(function() { game.x = originalX; }, 50); }, 50); }, 50); };
User prompt
Do the flash and the do the blast expansion in the bomb. Change the order.
Code edit (1 edits merged)
Please save this source code
User prompt
Update bomb blast to properly update: this.bombBehavior = function() { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 5, scaleY: 5 }); blast.x = 1024; blast.y = 1366; blast.alpha = 1; blast.zIndex = 1000; // Add update function to blast blast.update = function() { if (this.scaleTarget) { this.scale += 0.2; // Increment scale each update this.alpha -= 0.02; // Fade out gradually if (this.scale >= this.scaleTarget) { this.destroy(); } } }; blast.scaleTarget = 10; // Set target scale for expansion game.addChild(blast); // Kill enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i] && enemies[i].y > 0) { enemies[i].HitPoints = 0; } } // Rest of flash and shake effects remain the same... };
User prompt
Update bomb blast with minimal animation: this.bombBehavior = function() { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 5, // Back to the size we know works scaleY: 5 }); blast.x = 1024; blast.y = 1366; blast.alpha = 1; blast.zIndex = 1000; game.addChild(blast); // Kill enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i] && enemies[i].y > 0) { enemies[i].HitPoints = 0; } } // Just ONE expansion after a delay LK.setTimeout(function() { blast.scale = 8; // Just expand once LK.setTimeout(function() { blast.destroy(); }, 200); // Stay visible a bit longer }, 200); // Wait a bit before expanding // Flash and shake effects remain the same... };
User prompt
Update the bomb blast animation: this.bombBehavior = function() { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, // Start smaller scaleY: 2 }); blast.x = 1024; blast.y = 1366; blast.alpha = 1; blast.zIndex = 1000; game.addChild(blast); // Kill enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i] && enemies[i].y > 0) { enemies[i].HitPoints = 0; } } // Animate with more dramatic changes and shorter intervals LK.setTimeout(function() { blast.scale = 4; LK.setTimeout(function() { blast.scale = 6; LK.setTimeout(function() { blast.scale = 8; blast.alpha = 0.7; LK.setTimeout(function() { blast.scale = 10; blast.alpha = 0.3; LK.setTimeout(function() { blast.destroy(); }, 50); }, 50); }, 50); }, 50); }, 50); // Flash and shake effects remain the same... };
User prompt
Okay check and double check the code with bomb blast. Use whatever timing you have to to get it to work, it is not expanding at all
User prompt
I can see the bomb blast very tiny in the center of the screen. It is not expanding. It needs to expand in size.
/**** * Classes ****/ // Blaster class representing a shooting enemy var Blaster = Container.expand(function () { var self = Container.call(this); var blasterGraphics = self.attachAsset('Blaster', { anchorX: 0.5, anchorY: 0.5 }); self.HitPoints = 5; self.speed = 2; // Laser attack properties self.laserMechanic = new LaserMechanic(self, 60, 30, 30); // charge, fire, slide durations self.nextAttackTime = LK.ticks + randomRange(180, 300); // 3-5 seconds initial delay function randomRange(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } self.update = function () { // Update laser mechanic self.laserMechanic.update(); // Check if it's time for a laser attack if (LK.ticks >= self.nextAttackTime && !self.laserMechanic.isCharging && !self.laserMechanic.isFiring && !self.laserMechanic.isSliding && !self.laserMechanic.attackComplete) { self.laserMechanic.startCharge(); } // Handle movement based on state if (self.laserMechanic.isCharging) { // Only rotate to track player during charge var directionX = hero.x - self.x; var directionY = hero.y - self.y; blasterGraphics.rotation = Math.atan2(directionY, directionX) - Math.PI / 2; } else if (self.laserMechanic.isFiring || self.laserMechanic.isSliding) { // No movement during firing and sliding return; } else { // Normal movement when not attacking // Track player position var directionX = hero.x - self.x; var directionY = hero.y - self.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); if (distance > 0) { self.x += directionX / distance * self.speed; self.y += directionY / distance * self.speed; blasterGraphics.rotation = Math.atan2(directionY, directionX) - Math.PI / 2; } // Set next attack time after sliding is done if (self.laserMechanic.isAttackComplete()) { self.laserMechanic.resetAttack(); self.nextAttackTime = LK.ticks + randomRange(300, 480); } } // Destroy if out of screen if (self.HitPoints <= 0) { // Create blaster pieces upon destruction var bottomPiece = new BlasterPiece('BlasterBottomPiece'); bottomPiece.x = self.x; bottomPiece.y = self.y; game.addChild(bottomPiece); var leftPiece = new BlasterPiece('BlasterLeftPiece'); leftPiece.x = self.x - 40; leftPiece.y = self.y; game.addChild(leftPiece); var rightPiece = new BlasterPiece('BlasterRightPiece'); rightPiece.x = self.x + 40; rightPiece.y = self.y; game.addChild(rightPiece); // Check if there's an active laser beam if (self.laserMechanic.laserBeam) { // Detach and slide the laser beam self.laserMechanic.detachBeam(); } self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } else if (self.y > 2732) { self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } }; }); // BlasterPiece class for blaster destruction effect var BlasterPiece = Container.expand(function (assetType) { var self = Container.call(this); var pieceGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5, alpha: 1 // Ensure pieces are fully visible on spawn }); self.speedX = (Math.random() - 0.5) * 12; // Random horizontal speed to move outwards self.speedY = (Math.random() - 0.5) * 12; // Random vertical speed to move outwards self.alphaDecay = 0.02; // Rate at which the piece fades out self.update = function () { self.x += self.speedX; self.y += self.speedY; pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation pieceGraphics.alpha -= self.alphaDecay; if (pieceGraphics.alpha <= 0) { self.destroy(); } }; }); // Bruiser class representing a tougher enemy var Bruiser = Container.expand(function () { var self = Container.call(this); var bruiserGraphics = self.attachAsset('Bruiser', { anchorX: 0.5, anchorY: 0.5 }); self.HitPoints = 10; // Higher hit points for Bruiser self.speed = 4; // Increased speed for Bruiser self.update = function () { // Implement mechanical stomping movement if (LK.ticks % 80 < 20) { bruiserGraphics.scale.x = 1.1; bruiserGraphics.scale.y = 0.9; bruiserGraphics.rotation = 0.1; // Tilt right } else if (LK.ticks % 80 < 40) { bruiserGraphics.scale.x = 1.0; bruiserGraphics.scale.y = 1.0; bruiserGraphics.rotation = 0; } else if (LK.ticks % 80 < 60) { bruiserGraphics.scale.x = 1.1; bruiserGraphics.scale.y = 0.9; bruiserGraphics.rotation = -0.1; // Tilt left } else { bruiserGraphics.scale.x = 1.0; bruiserGraphics.scale.y = 1.0; bruiserGraphics.rotation = 0; } // Move downwards only during tilt phases if (LK.ticks % 80 < 20 || LK.ticks % 80 >= 40 && LK.ticks % 80 < 60) { // Check for nearby enemies and adjust path to avoid collisions var nearbyEnemy = enemies.find(function (enemy) { return enemy !== self && Math.abs(enemy.x - self.x) < 100 && Math.abs(enemy.y - self.y) < 100; }); if (nearbyEnemy) { self.x += (self.x < nearbyEnemy.x ? -1 : 1) * self.speed; // Move away from the nearby enemy } else { self.y += self.speed; } } if (self.HitPoints <= 0) { // Create bruiser pieces upon destruction var centerPiece = new BruiserPiece('BruiserCenterPart'); centerPiece.x = self.x; centerPiece.y = self.y; game.addChild(centerPiece); var leftPiece = new BruiserPiece('BruiserLeftPart'); leftPiece.x = self.x - 40; leftPiece.y = self.y; game.addChild(leftPiece); var rightPiece = new BruiserPiece('BruiserRightPart'); rightPiece.x = self.x + 40; rightPiece.y = self.y; game.addChild(rightPiece); self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } else if (self.y > 2732) { self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } }; }); // BruiserPiece class for bruiser destruction effect var BruiserPiece = Container.expand(function (assetType) { var self = Container.call(this); var pieceGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); self.speedX = -Math.random() * 6 + 3; // Switch direction of horizontal speed self.speedY = Math.random() * 4 - 2; // Random vertical speed self.alphaDecay = 0.02; // Rate at which the piece fades out self.update = function () { self.x += self.speedX; self.y += self.speedY; pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation pieceGraphics.alpha -= self.alphaDecay; if (pieceGraphics.alpha <= 0) { self.destroy(); } }; }); // Enemy class representing the enemy robots var Drone = Container.expand(function () { var self = Container.call(this); var droneGraphics = self.attachAsset('Drone', { anchorX: 0.5, anchorY: 0.5 }); self.HitPoints = 3; self.randomOffset = Math.random() * 100; // Random timing for each drone self.speed = 2.25; self.update = function () { // Add robotic hover effects // Check for nearby enemies and adjust path to avoid collisions var nearbyEnemy = enemies.find(function (enemy) { return enemy !== self && Math.abs(enemy.x - self.x) < 100 && Math.abs(enemy.y - self.y) < 100; }); if (nearbyEnemy) { self.x += (self.x < nearbyEnemy.x ? -1 : 1) * self.speed; // Move away from the nearby enemy } else { self.y += self.speed * (Math.random() > 0.1 ? 1 : 0); // Brief pauses in downward movement } self.x += Math.sin(LK.ticks / 10 + self.randomOffset) * 2; // Small jerky side-to-side movements if (Math.random() > 0.95) { self.x += Math.random() * 4 - 2; // Quick position corrections } // Pulse effect on hit if (self.pulseEffect) { droneGraphics.scale.x = 1.2; droneGraphics.scale.y = 1.2; self.pulseEffect = false; } else { droneGraphics.scale.x = 1.0; droneGraphics.scale.y = 1.0; } if (self.HitPoints <= 0) { // Create drone pieces upon destruction var centerPiece = new DronePiece('DroneCenterPart'); centerPiece.x = self.x; centerPiece.y = self.y; game.addChild(centerPiece); var leftPiece = new DronePiece('DroneLeftPart'); leftPiece.x = self.x - 40; leftPiece.y = self.y; game.addChild(leftPiece); var rightPiece = new DronePiece('DroneRightPart'); rightPiece.x = self.x + 40; rightPiece.y = self.y; game.addChild(rightPiece); self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } else if (self.y > 2732) { self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } }; }); // DronePiece class for drone destruction effect var DronePiece = Container.expand(function (assetType) { var self = Container.call(this); var pieceGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); self.speedX = Math.random() * 6 - 3; // Increased random horizontal speed self.speedY = Math.random() * 4 - 2; // Random vertical speed self.alphaDecay = 0.02; // Rate at which the piece fades out self.update = function () { self.x += self.speedX; self.y += self.speedY; pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation pieceGraphics.alpha -= self.alphaDecay; if (pieceGraphics.alpha <= 0) { self.destroy(); } }; }); // Dust class for dust particles var Dust = Container.expand(function () { var self = Container.call(this); var dustGraphics = self.attachAsset('Dust', { anchorX: 0.5, anchorY: 0.5 }); dustGraphics.alpha = 0.75; self.speed = Math.random() * 3 + 1; self.rotationSpeed = Math.random() * 0.02 - 0.01; // Random rotation speed between -0.01 and 0.01 self.direction = Math.random() * Math.PI * 0.5; self.update = function () { self.y += self.speed; self.x += Math.sin(self.direction) * self.speed; // Add slight X travel based on direction self.rotation += self.rotationSpeed; // Add rotation dustGraphics.alpha -= 0.01; // fade out at a medium pace if (self.y > 2732 || dustGraphics.alpha <= 0) { self.destroy(); } }; }); // Assets will be automatically created and loaded by the LK engine based on their usage in the code. // Hero class representing the player's spaceship var Hero = Container.expand(function () { var self = Container.call(this); self.prevX = self.x; // Initialize prevX with the current x position var heroGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.soldierCloneCount = 0; // Initialize soldier clone count self.shielded = false; // Initialize shielded state self.shieldLevel = 0; // Initialize shield level self.shieldGraphics = null; // Placeholder for shield asset self.update = function () { if (self.shielded && self.shieldGraphics) { self.shieldGraphics.rotation += 0.01; // Rotate shield slowly // Adjust shield size to cover hero asset var scaleFactor = Math.max(heroGraphics.width / self.shieldGraphics.width, heroGraphics.height / self.shieldGraphics.height); self.shieldGraphics.scale.x = scaleFactor; self.shieldGraphics.scale.y = scaleFactor; // Update shield tint based on shield level self.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default if (self.shieldLevel === 2) { self.shieldGraphics.tint = 0xFFFF00; // Yellow tint } else if (self.shieldLevel === 3) { self.shieldGraphics.tint = 0xFF0000; // Red tint } } if (self.y > 2375) { self.y -= self.speed; } // Add rotation based on movement direction if (self.x > self.prevX) { self.rotation += Math.PI / 180 * 1; // Rotate 1 degree to the right if (self.rotation > Math.PI / 180 * 5) { self.rotation = Math.PI / 180 * 5; } } else if (self.x < self.prevX) { self.rotation -= Math.PI / 180 * 1; // Rotate 1 degree to the left if (self.rotation < Math.PI / 180 * -5) { self.rotation = Math.PI / 180 * -5; } } else { if (self.rotation > 0) { self.rotation -= Math.PI / 180 * 1; if (self.rotation < 0) { self.rotation = 0; } } else if (self.rotation < 0) { self.rotation += Math.PI / 180 * 1; if (self.rotation > 0) { self.rotation = 0; } } } self.prevX = self.x; // Store the current x position for the next frame // Removed pulsing scale effect for hero self.scale.x = 1.0; }; // Method to handle shooting self.shootBehavior = powerUpManager.defaultBehavior; // Set initial behavior // Method to handle shooting self.shoot = function () { self.shootBehavior.call(self); }; }); // Bullet class for hero's bullets var HeroBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('heroBullet1', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; self.Type = 'standard'; // Default type for bullets self.Power = powerUpManager.currentPowerLevel || 1; // Initialize power level from PowerUpManager self.update = function () { // Move in direction of rotation self.y += Math.cos(self.rotation) * self.speed; self.x += Math.sin(self.rotation) * self.speed; // Adjust out-of-bounds check for angled movement if (self.y < 0 || self.x < 0 || self.x > 2048) { self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } } }; self.updateVisual = function () { if (bulletGraphics) { self.removeChild(bulletGraphics); } var assetId = 'heroBullet' + self.Power; console.log("Loading bullet asset: " + assetId); bulletGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; }); // PowerUp class for handling power-up movement and collection var PowerUp = Container.expand(function (assetType) { var self = Container.call(this); var powerUpGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; // Speed at which the power-up moves down the screen self.update = function () { self.y += self.speed; // Check if the power-up is collected by the hero if (self.intersects(hero)) { switch (assetType) { case 'SoldierCloneIcon': if (soldierClones.length < 6) { hero.soldierCloneCount++; var offset = (soldierClones.length % 2 === 0 ? 40 : -40) * Math.ceil((soldierClones.length + 1) / 2); var newClone = new SoldierClone(); newClone.x = hero.x + offset; newClone.y = hero.y; newClone.zIndex = hero.zIndex - 1; // Ensure clones are rendered below the hero soldierClones.push(newClone); backgroundContainer.addChild(newClone); } break; case 'WeaponPowerIcon': powerUpManager.currentPowerLevel = Math.min(powerUpManager.currentPowerLevel + 1, 4); console.log("Power up collected. New level: " + powerUpManager.currentPowerLevel); break; case 'ShieldIcon': if (!hero.shielded) { hero.shielded = true; hero.shieldGraphics = hero.attachAsset('heroShield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 // Set opacity to 50% }); } hero.shieldLevel = Math.min(hero.shieldLevel + 1, 3); // Increase shield level to a max of 3 // Change shield tint based on shield level hero.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default if (hero.shieldLevel === 2) { hero.shieldGraphics.tint = 0xFFFF00; // Yellow tint } else if (hero.shieldLevel === 3) { hero.shieldGraphics.tint = 0xFF0000; // Red tint } break; case 'BombIcon': powerUpManager.switchPowerUp(PowerUpTypes.BOMB); powerUpManager.bombBehavior(); break; } hero.shootBehavior = powerUpManager.getCurrentPowerBehavior(); soldierClones.forEach(function (clone) { clone.shootBehavior = hero.shootBehavior; }); self.destroy(); } // Destroy if out of screen if (self.y > 2732) { self.destroy(); } }; }); // RailingLeft class for the scrolling left railing var RailingLeft = Container.expand(function (assetType) { var self = Container.call(this); var railingGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0 }); self.speed = 2; self.update = function () { self.y += self.speed; if (self.y >= 2732) { self.y = -2732; } }; }); // RailingRight class for the scrolling right railing var RailingRight = Container.expand(function (assetType) { var self = Container.call(this); var railingGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0 }); self.speed = 2; self.update = function () { self.y += self.speed; if (self.y >= 2732) { self.y = -2732; } }; }); // RoadScroll class for the scrolling road var RoadScroll = Container.expand(function (assetType) { var self = Container.call(this); var roadGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0 }); if (assetType === 'CityBackgroundHD') { self.speed = 1; } else { self.speed = 2; } self.update = function () { self.y += self.speed; if (self.y >= 2732) { self.y = -2732; } }; }); // SoldierClone class representing a clone of the player's character var SoldierClone = Container.expand(function () { var self = Container.call(this); var cloneGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 // Set opacity to 70% }); self.health = 1; self.update = function () { self.destroy = function () { // Remove bullets associated with this clone for (var i = heroBullets.length - 1; i >= 0; i--) { if (heroBullets[i].x === self.x && heroBullets[i].y === self.y - self.height / 2) { heroBullets[i].destroy(); heroBullets.splice(i, 1); } } // Call original destroy method Container.prototype.destroy.call(self); }; self.y = hero.y; // Check for collision with enemies for (var i = 0; i < enemies.length; i++) { if (self.intersects(enemies[i])) { self.destroy(); var index = soldierClones.indexOf(self); if (index > -1) { soldierClones.splice(index, 1); } hero.soldierCloneCount--; return; } } // Auto-fire like the player self.shoot(); }; // Method to handle shooting self.shoot = function () { if (LK.ticks % 18 == 0) { // Match hero's fire rate var newBullet = new HeroBullet(); // Use the same bullet type as the hero newBullet.x = self.x; // Create bullets at the clone's current position newBullet.y = self.y - self.height / 2; newBullet.Power = heroBullets.length > 0 ? heroBullets[0].Power : 1; // Match hero's bullet power newBullet.updateVisual(); // Update bullet visuals based on power heroBullets.push(newBullet); // Add the new bullets to the game's bullet array game.addChild(newBullet); } }; }); // TitleScreen class for the title screen var TitleScreen = Container.expand(function () { var self = Container.call(this); // Attach game logo var logo = self.attachAsset('GameLogoHD', { anchorX: 0.5, anchorY: 0.5 }); logo.x = 2048 / 2; logo.y = 2732 / 2 - 200; // Attach play button var playButton = self.attachAsset('PlayButton', { anchorX: 0.5, anchorY: 0.5 }); playButton.x = 2048 / 2; playButton.y = logo.y + logo.height / 2 + playButton.height / 2 + 50; // Event handler for play button playButton.down = function (x, y, obj) { isTitle = false; isStarted = true; self.destroy(); startGame(); }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 //Init game with black background }); /**** * Game Code ****/ var PowerUpTypes = { DEFAULT: 'DEFAULT', SOLDIER_CLONE: 'SOLDIER_CLONE', SHIELD: 'SHIELD', WEAPON_POWER: 'WEAPON_POWER', BOMB: 'BOMB' // Add bomb type }; // PowerUpManager class to manage power-ups // Initialize the city background for parallax effect var PowerUpManager = function PowerUpManager() { this.currentPowerUp = PowerUpTypes.DEFAULT; this.currentPowerLevel = LK.getScore() > 0 ? LK.getScore() : 1; // Initialize power level based on score or default to 1 this.switchPowerUp = function (newPowerUp) { if (PowerUpTypes[newPowerUp]) { this.currentPowerUp = newPowerUp; } }; this.getCurrentPowerBehavior = function () { switch (this.currentPowerUp) { case PowerUpTypes.SOLDIER_CLONE: return this.soldierCloneBehavior; case PowerUpTypes.BOMB: return this.bombBehavior; default: return this.defaultBehavior; } }; this.defaultBehavior = function () { var bullet = new HeroBullet(); bullet.x = hero.x; bullet.y = hero.y - hero.height / 2; bullet.Power = powerUpManager.currentPowerLevel || 1; // Use saved power level from PowerUpManager bullet.updateVisual(); // Update the visual after setting power heroBullets.push(bullet); game.addChild(bullet); console.log("Created bullet with power: " + bullet.Power); }; this.soldierCloneBehavior = function () { // Soldier clone behavior // Removed clone spawning logic }; this.bombBehavior = function () { var blast = new Container(); var blastGraphics = blast.attachAsset('BombBlast', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, // Start very small scaleY: 0.1 }); blast.x = 1024; blast.y = 1366; blast.alpha = 1; blast.zIndex = 1000; // Try putting it in front of everything game.addChild(blast); // Kill enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i] && enemies[i].y > 0) { enemies[i].HitPoints = 0; } } // Flash effect var flash = new Container(); var flashGraphics = flash.attachAsset('whitePixel', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 30 }); flash.x = game.width / 2; flash.y = game.height / 2; flash.alpha = 0.8; game.addChild(flash); LK.setTimeout(function () { flash.destroy(); }, 100); // Rapid expansion animation var expandBlast = LK.setInterval(function () { blast.scaleX += 5; // Increase scale more rapidly blast.scaleY += 5; if (blast.scaleX > 2048 || blast.scaleY > 2732) { // Check if it has expanded beyond the screen LK.clearInterval(expandBlast); blast.destroy(); } }, 30); // Faster interval // Screen shake var originalX = game.x; var shakeAmount = 20; game.x += shakeAmount; LK.setTimeout(function () { game.x -= shakeAmount * 2; LK.setTimeout(function () { game.x += shakeAmount; LK.setTimeout(function () { game.x = originalX; }, 50); }, 50); }, 50); }; }; // PowerUpTypes enum/constants var PowerUpTypes = { DEFAULT: 'DEFAULT', LASER_BEAM: 'LASER_BEAM', ROCKETS: 'ROCKETS', DRONE: 'DRONE', SOLDIER_CLONE: 'SOLDIER_CLONE', SHIELD: 'SHIELD', // Add shield power-up type WEAPON_POWER: 'WEAPON_POWER' }; var LaserMechanic = function LaserMechanic(origin, chargeDuration, fireDuration, slideOffDuration) { this.origin = origin; this.chargeDuration = chargeDuration; this.fireDuration = fireDuration; this.slideOffDuration = slideOffDuration; // State tracking this.isCharging = false; this.isFiring = false; this.isSliding = false; // Timing this.chargeStartTime = null; this.fireStartTime = null; this.slideStartTime = null; // Flag to indicate attack completion this.attackComplete = false; // Assets this.chargeEffect = null; this.laserBeam = null; var index = activeLaserBeams.indexOf(this); if (index > -1) { activeLaserBeams.splice(index, 1); } // Method to start charging LaserMechanic.prototype.startCharge = function () { if (this.isCharging || this.isFiring || this.isSliding) { return; } this.isCharging = true; this.chargeStartTime = LK.ticks; // Create charge effect this.chargeEffect = LK.getAsset('LaserCharge', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5, scale: { x: 0.5, y: 0.5 } }); if (this.origin) { this.chargeEffect.y += this.origin.height * 0.1; // Move charge effect down by 10% of origin's height this.origin.addChild(this.chargeEffect); } }; // Target this.targetX = null; this.targetY = null; // Method to update charge progress LaserMechanic.prototype.updateCharge = function () { if (!this.isCharging) { return; } var chargeProgress = (LK.ticks - this.chargeStartTime) / this.chargeDuration; // Update charge effect this.chargeEffect.alpha = 0.5 + chargeProgress * 0.5; // Fade in this.chargeEffect.scale.x = 0.5 + chargeProgress * 1.5; // Grow outward this.chargeEffect.scale.y = 0.5 + chargeProgress * 1.5; // Capture target position at 2/3 through charge if (chargeProgress >= 0.67 && !this.targetX) { this.targetX = hero.x; this.targetY = hero.y; } // Check if charge is complete if (chargeProgress >= 1) { if (this.origin && this.chargeEffect) { this.origin.removeChild(this.chargeEffect); } this.chargeEffect = null; this.isCharging = false; this.startFiring(); // Add this line to transition to firing phase } }; }; var cityBackground1 = game.addChild(new RoadScroll('CityBackgroundHD')); var cityBackground2 = game.addChild(new RoadScroll('CityBackgroundHD')); cityBackground1.x = 2048 / 2; cityBackground2.x = 2048 / 2; cityBackground1.y = 0; cityBackground2.y = -2732; // Initialize the road instances var road1 = game.addChild(new RoadScroll('Road')); var road2 = game.addChild(new RoadScroll('Road2')); road2.x = 2048 / 2; road1.x = 2048 / 2; road1.y = 0; road2.y = -2732; // Initialize the left railing instances var railingLeft1 = game.addChild(new RailingLeft('RailingStart')); var railingLeft2 = game.addChild(new RailingLeft('RailingEnd')); railingLeft1.x = 2048 * 0.16; railingLeft2.x = 2048 * 0.16; railingLeft1.y = 0; railingLeft2.y = -2732; // Initialize the right railing instances var railingRight1 = game.addChild(new RailingRight('RailingEnd')); var railingRight2 = game.addChild(new RailingRight('RailingStart')); railingRight1.x = 2048 * 0.81; // Moved left by 3% railingRight2.x = 2048 * 0.81; // Moved left by 3% railingRight1.y = 0; railingRight2.y = -2732; // Initialize game state variables var isTitle = true; var isStarted = false; // Initialize title screen if (isTitle) { var titleScreen = game.addChild(new TitleScreen()); } // Initialize variables var backgroundContainer; var hero; var enemies = []; var heroBullets = []; var soldierClones = []; var powerUpManager = new PowerUpManager(); // Initialize powerUpManager powerUpManager.currentPowerLevel = 1; // Track current power level at start // Function to start the game function startGame() { // Initialize background container backgroundContainer = new Container(); game.addChild(backgroundContainer); // Initialize hero hero = game.addChild(new Hero()); hero.soldierCloneCount = soldierClones.length; // Set initial soldier clone count hero.x = 2048 / 2; hero.y = 2732 + hero.height; // Initialize enemies, bullets, and laser beams arrays enemies = []; heroBullets = []; activeLaserBeams = []; hero.shootBehavior = powerUpManager.getCurrentPowerBehavior().bind(hero); } // Function to handle game updates game.update = function () { soldierClones.forEach(function (clone, index) { clone.shootBehavior = hero.shootBehavior; var offset = (index % 2 === 0 ? 160 : -160) * Math.ceil((index + 1) / 2); clone.x = hero.x + offset; }); cityBackground1.update(); cityBackground2.update(); // Update the road instances road1.update(); road2.update(); // Update the left railing instances railingLeft1.update(); railingLeft2.update(); // Update the right railing instances railingRight1.update(); railingRight2.update(); if (isStarted) { if (dragNode) { hero.x = dragNode.x; hero.y = dragNode.y; } // Update enemies if (!enemies) { return; } // Ensure enemies array is initialized for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i]) { enemies[i].update(); } if (enemies[i] && enemies[i].intersects(hero)) { if (hero.shielded) { hero.shieldLevel -= 1; if (hero.shieldLevel <= 0) { hero.shielded = false; if (hero.shieldGraphics) { hero.shieldGraphics.destroy(); hero.shieldGraphics = null; } } else { // Update shield tint based on new shield level hero.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default if (hero.shieldLevel === 2) { hero.shieldGraphics.tint = 0xFFFF00; // Yellow tint } else if (hero.shieldLevel === 1) { hero.shieldGraphics.tint = 0xFFFFFF; // White tint } } // Destroy enemy into pieces if (enemies[i] instanceof Drone) { var centerPiece = new DronePiece('DroneCenterPart'); centerPiece.x = enemies[i].x; centerPiece.y = enemies[i].y; game.addChild(centerPiece); var leftPiece = new DronePiece('DroneLeftPart'); leftPiece.x = enemies[i].x - 40; leftPiece.y = enemies[i].y; game.addChild(leftPiece); var rightPiece = new DronePiece('DroneRightPart'); rightPiece.x = enemies[i].x + 40; rightPiece.y = enemies[i].y; game.addChild(rightPiece); } else if (enemies[i] instanceof Bruiser) { var centerPiece = new BruiserPiece('BruiserCenterPart'); centerPiece.x = enemies[i].x; centerPiece.y = enemies[i].y; game.addChild(centerPiece); var leftPiece = new BruiserPiece('BruiserLeftPart'); leftPiece.x = enemies[i].x - 40; leftPiece.y = enemies[i].y; game.addChild(leftPiece); var rightPiece = new BruiserPiece('BruiserRightPart'); rightPiece.x = enemies[i].x + 40; rightPiece.y = enemies[i].y; game.addChild(rightPiece); } else if (enemies[i] instanceof Blaster) { var bottomPiece = new BlasterPiece('BlasterBottomPiece'); bottomPiece.x = enemies[i].x; bottomPiece.y = enemies[i].y; game.addChild(bottomPiece); var leftPiece = new BlasterPiece('BlasterLeftPiece'); leftPiece.x = enemies[i].x - 40; leftPiece.y = enemies[i].y; game.addChild(leftPiece); var rightPiece = new BlasterPiece('BlasterRightPiece'); rightPiece.x = enemies[i].x + 40; rightPiece.y = enemies[i].y; game.addChild(rightPiece); } enemies[i].destroy(); enemies.splice(i, 1); } else { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } // Update active laser beams for (var l = activeLaserBeams.length - 1; l >= 0; l--) { activeLaserBeams[l].update(); if (activeLaserBeams[l].isAttackComplete()) { if (activeLaserBeams[l].laserBeam) { activeLaserBeams[l].laserBeam.destroy(); } activeLaserBeams.splice(l, 1); } } // Update hero bullets for (var j = heroBullets.length - 1; j >= 0; j--) { heroBullets[j].update(); for (var k = enemies.length - 1; k >= 0; k--) { if (heroBullets[j] && heroBullets[j].intersects(enemies[k]) && enemies[k].y > 0) { enemies[k].HitPoints -= heroBullets[j].Power; // Apply an increased push back effect if (!(enemies[k] instanceof Bruiser)) { enemies[k].y -= 12; // Push the drone upwards slightly more } enemies[k].pulseEffect = true; // Trigger pulse effect // Removed tracerTail reference heroBullets[j].destroy(); heroBullets.splice(j, 1); if (enemies[k].HitPoints <= 0) { // Randomly select a power-up type for equal chance drops var powerUpTypes = ['SoldierCloneIcon', 'WeaponPowerIcon', 'ShieldIcon', 'BombIcon']; var randomPowerUpType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)]; var powerUp = new PowerUp(randomPowerUpType); powerUp.x = enemies[k].x; powerUp.y = enemies[k].y; game.addChild(powerUp); if (enemies[k] instanceof Drone) { // Create drone pieces upon destruction var centerPiece = new DronePiece('DroneCenterPart'); centerPiece.x = enemies[k].x; centerPiece.y = enemies[k].y; game.addChild(centerPiece); var leftPiece = new DronePiece('DroneLeftPart'); leftPiece.x = enemies[k].x - 40; // Increase spread leftPiece.y = enemies[k].y; game.addChild(leftPiece); var rightPiece = new DronePiece('DroneRightPart'); rightPiece.x = enemies[k].x + 40; // Increase spread rightPiece.y = enemies[k].y; game.addChild(rightPiece); } else if (enemies[k] instanceof Bruiser) { // Create bruiser pieces upon destruction var centerPiece = new BruiserPiece('BruiserCenterPart'); centerPiece.x = enemies[k].x; centerPiece.y = enemies[k].y; game.addChild(centerPiece); var leftPiece = new BruiserPiece('BruiserLeftPart'); leftPiece.x = enemies[k].x - 40; // Increase spread leftPiece.y = enemies[k].y; var rightPiece = new BruiserPiece('BruiserRightPart'); rightPiece.x = enemies[k].x + 40; // Increase spread rightPiece.y = enemies[k].y; leftPiece.speedX = -Math.abs(leftPiece.speedX) * 1.5; // Increase force for left piece rightPiece.speedX = Math.abs(rightPiece.speedX) * 1.5; // Increase force for right piece game.addChild(leftPiece); game.addChild(rightPiece); } else if (enemies[k] instanceof Blaster) { // Create blaster pieces upon destruction var bottomPiece = new BlasterPiece('BlasterBottomPiece'); bottomPiece.x = enemies[k].x; bottomPiece.y = enemies[k].y; game.addChild(bottomPiece); var leftPiece = new BlasterPiece('BlasterLeftPiece'); leftPiece.x = enemies[k].x - 40; // Increase spread leftPiece.y = enemies[k].y; game.addChild(leftPiece); var rightPiece = new BlasterPiece('BlasterRightPiece'); rightPiece.x = enemies[k].x + 40; // Increase spread rightPiece.y = enemies[k].y; game.addChild(rightPiece); } enemies[k].destroy(); enemies.splice(k, 1); LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); } break; } } } if (LK.ticks % 240 == 0) { var newBlaster = new Blaster(); newBlaster.x = 2048 * 0.21 + Math.random() * (2048 * 0.55); // Adjusted x position within the Road area with 5% margin newBlaster.y = -newBlaster.height; // Start just outside the top of the screen enemies.push(newBlaster); game.addChild(newBlaster); } // Fire bullets using current power-up behavior if (LK.ticks % 18 == 0) { if (hero && hero.shootBehavior) { hero.shootBehavior(); } } // Generate dust particles in sync with player pulsing if (LK.ticks % 24 == 0) { var newDust = new Dust(); newDust.x = hero.x - hero.width / 4; // Move dust spawn position right half as much as the last move newDust.y = hero.y + hero.height / 2 * 0.93; // Move dust spawn point up 3% more game.addChild(newDust); } else if (LK.ticks % 24 == 12) { var newDust = new Dust(); newDust.x = hero.x + hero.width / 4; // Create another dust spawn point an equal distance in from the right of the player asset newDust.y = hero.y + hero.height / 2 * 0.93; // Move dust spawn point up 3% more game.addChild(newDust); } } }; // Handle touch input for hero movement var dragNode = null; game.down = function (x, y, obj) { if (isStarted) { dragNode = { x: hero.x, y: hero.y }; // Add a tilt-back effect during initial movement hero.rotation = x > hero.x ? Math.PI / 180 * -1 : Math.PI / 180 * 1; } }; game.move = function (x, y, obj) { if (isStarted && dragNode) { // Add a slight delay to the drag control to make the player feel like it has more weight dragNode.x += (x - dragNode.x) * 0.1; dragNode.y = hero.y; // Lock the y position to the hero's initial y position } }; game.up = function (x, y, obj) { dragNode = null; }; // Display score var scoreTxt = new Text2('0', { size: 150, fill: "#ffffff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.setText(LK.getScore()); LaserMechanic.prototype.startFiring = function () { if (!this.origin || !this.targetX || !this.targetY || this.isFiring) { return; } this.isFiring = true; this.fireStartTime = LK.ticks; // Create laser beam this.laserBeam = LK.getAsset('LaserBeam', { anchorX: 0.5, anchorY: 0, scaleX: 1, // Normal width scaleY: 5 // Make it long }); game.addChild(this.laserBeam); activeLaserBeams.push(this); // Position at origin if (this.origin) { this.laserBeam.x = this.origin.x; this.laserBeam.y = this.origin.y; } // Calculate direction to target var directionX = this.targetX - this.laserBeam.x; var directionY = this.targetY - this.laserBeam.y; // Set rotation this.laserBeam.rotation = Math.atan2(directionY, directionX) - Math.PI / 2; }; LaserMechanic.prototype.updateFiring = function () { if (!this.isFiring) { return; } var fireProgress = (LK.ticks - this.fireStartTime) / this.fireDuration; if (fireProgress <= 1) { // Stretch the laser this.laserBeam.scaleY += (20 - this.laserBeam.scaleY) * 0.1; // Keep beam pinned to origin this.laserBeam.x = this.origin.x; this.laserBeam.y = this.origin.y; } else { // Transition to sliding phase this.isFiring = false; this.startSliding(); } }; LaserMechanic.prototype.startSliding = function () { this.isSliding = true; this.slideStartTime = LK.ticks; this.origin = null; // Detach laser from Blaster origin // Calculate slide direction to move away from the origin point var directionX = -Math.sin(this.laserBeam.rotation); var directionY = Math.cos(this.laserBeam.rotation); this.slideDirection = { x: directionX, y: directionY }; }; LaserMechanic.prototype.updateSliding = function () { if (!this.isSliding || !this.laserBeam) { return; } var slideProgress = (LK.ticks - this.slideStartTime) / this.slideOffDuration; if (slideProgress <= 1) { // Move the beam off screen this.laserBeam.x += this.slideDirection.x * 20; this.laserBeam.y += this.slideDirection.y * 20; } else { // Clean up if (this.laserBeam) { game.removeChild(this.laserBeam); this.laserBeam = null; } this.isSliding = false; this.slideDirection = null; this.attackComplete = true; if (this.origin) { this.origin.laserMechanic.attackComplete = true; } } }; // Method to reset attack states LaserMechanic.prototype.resetAttack = function () { this.isCharging = false; this.isFiring = false; this.isSliding = false; this.targetX = null; this.targetY = null; this.attackComplete = false; return true; }; LaserMechanic.prototype.update = function () { if (this.isCharging) { this.updateCharge(); } else if (this.isFiring) { this.updateFiring(); } else if (this.isSliding || this.laserBeam) { this.updateSliding(); } }; // Method to check if the attack sequence is complete LaserMechanic.prototype.isAttackComplete = function () { return this.attackComplete; }; LaserMechanic.prototype.detachBeam = function () { if (this.laserBeam) { // Detach laser from origin this.origin = null; // Force laser into sliding phase this.startSliding(); } };
/****
* Classes
****/
// Blaster class representing a shooting enemy
var Blaster = Container.expand(function () {
var self = Container.call(this);
var blasterGraphics = self.attachAsset('Blaster', {
anchorX: 0.5,
anchorY: 0.5
});
self.HitPoints = 5;
self.speed = 2;
// Laser attack properties
self.laserMechanic = new LaserMechanic(self, 60, 30, 30); // charge, fire, slide durations
self.nextAttackTime = LK.ticks + randomRange(180, 300); // 3-5 seconds initial delay
function randomRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
self.update = function () {
// Update laser mechanic
self.laserMechanic.update();
// Check if it's time for a laser attack
if (LK.ticks >= self.nextAttackTime && !self.laserMechanic.isCharging && !self.laserMechanic.isFiring && !self.laserMechanic.isSliding && !self.laserMechanic.attackComplete) {
self.laserMechanic.startCharge();
}
// Handle movement based on state
if (self.laserMechanic.isCharging) {
// Only rotate to track player during charge
var directionX = hero.x - self.x;
var directionY = hero.y - self.y;
blasterGraphics.rotation = Math.atan2(directionY, directionX) - Math.PI / 2;
} else if (self.laserMechanic.isFiring || self.laserMechanic.isSliding) {
// No movement during firing and sliding
return;
} else {
// Normal movement when not attacking
// Track player position
var directionX = hero.x - self.x;
var directionY = hero.y - self.y;
var distance = Math.sqrt(directionX * directionX + directionY * directionY);
if (distance > 0) {
self.x += directionX / distance * self.speed;
self.y += directionY / distance * self.speed;
blasterGraphics.rotation = Math.atan2(directionY, directionX) - Math.PI / 2;
}
// Set next attack time after sliding is done
if (self.laserMechanic.isAttackComplete()) {
self.laserMechanic.resetAttack();
self.nextAttackTime = LK.ticks + randomRange(300, 480);
}
}
// Destroy if out of screen
if (self.HitPoints <= 0) {
// Create blaster pieces upon destruction
var bottomPiece = new BlasterPiece('BlasterBottomPiece');
bottomPiece.x = self.x;
bottomPiece.y = self.y;
game.addChild(bottomPiece);
var leftPiece = new BlasterPiece('BlasterLeftPiece');
leftPiece.x = self.x - 40;
leftPiece.y = self.y;
game.addChild(leftPiece);
var rightPiece = new BlasterPiece('BlasterRightPiece');
rightPiece.x = self.x + 40;
rightPiece.y = self.y;
game.addChild(rightPiece);
// Check if there's an active laser beam
if (self.laserMechanic.laserBeam) {
// Detach and slide the laser beam
self.laserMechanic.detachBeam();
}
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else if (self.y > 2732) {
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
}
};
});
// BlasterPiece class for blaster destruction effect
var BlasterPiece = Container.expand(function (assetType) {
var self = Container.call(this);
var pieceGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1 // Ensure pieces are fully visible on spawn
});
self.speedX = (Math.random() - 0.5) * 12; // Random horizontal speed to move outwards
self.speedY = (Math.random() - 0.5) * 12; // Random vertical speed to move outwards
self.alphaDecay = 0.02; // Rate at which the piece fades out
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation
pieceGraphics.alpha -= self.alphaDecay;
if (pieceGraphics.alpha <= 0) {
self.destroy();
}
};
});
// Bruiser class representing a tougher enemy
var Bruiser = Container.expand(function () {
var self = Container.call(this);
var bruiserGraphics = self.attachAsset('Bruiser', {
anchorX: 0.5,
anchorY: 0.5
});
self.HitPoints = 10; // Higher hit points for Bruiser
self.speed = 4; // Increased speed for Bruiser
self.update = function () {
// Implement mechanical stomping movement
if (LK.ticks % 80 < 20) {
bruiserGraphics.scale.x = 1.1;
bruiserGraphics.scale.y = 0.9;
bruiserGraphics.rotation = 0.1; // Tilt right
} else if (LK.ticks % 80 < 40) {
bruiserGraphics.scale.x = 1.0;
bruiserGraphics.scale.y = 1.0;
bruiserGraphics.rotation = 0;
} else if (LK.ticks % 80 < 60) {
bruiserGraphics.scale.x = 1.1;
bruiserGraphics.scale.y = 0.9;
bruiserGraphics.rotation = -0.1; // Tilt left
} else {
bruiserGraphics.scale.x = 1.0;
bruiserGraphics.scale.y = 1.0;
bruiserGraphics.rotation = 0;
}
// Move downwards only during tilt phases
if (LK.ticks % 80 < 20 || LK.ticks % 80 >= 40 && LK.ticks % 80 < 60) {
// Check for nearby enemies and adjust path to avoid collisions
var nearbyEnemy = enemies.find(function (enemy) {
return enemy !== self && Math.abs(enemy.x - self.x) < 100 && Math.abs(enemy.y - self.y) < 100;
});
if (nearbyEnemy) {
self.x += (self.x < nearbyEnemy.x ? -1 : 1) * self.speed; // Move away from the nearby enemy
} else {
self.y += self.speed;
}
}
if (self.HitPoints <= 0) {
// Create bruiser pieces upon destruction
var centerPiece = new BruiserPiece('BruiserCenterPart');
centerPiece.x = self.x;
centerPiece.y = self.y;
game.addChild(centerPiece);
var leftPiece = new BruiserPiece('BruiserLeftPart');
leftPiece.x = self.x - 40;
leftPiece.y = self.y;
game.addChild(leftPiece);
var rightPiece = new BruiserPiece('BruiserRightPart');
rightPiece.x = self.x + 40;
rightPiece.y = self.y;
game.addChild(rightPiece);
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else if (self.y > 2732) {
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
}
};
});
// BruiserPiece class for bruiser destruction effect
var BruiserPiece = Container.expand(function (assetType) {
var self = Container.call(this);
var pieceGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = -Math.random() * 6 + 3; // Switch direction of horizontal speed
self.speedY = Math.random() * 4 - 2; // Random vertical speed
self.alphaDecay = 0.02; // Rate at which the piece fades out
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation
pieceGraphics.alpha -= self.alphaDecay;
if (pieceGraphics.alpha <= 0) {
self.destroy();
}
};
});
// Enemy class representing the enemy robots
var Drone = Container.expand(function () {
var self = Container.call(this);
var droneGraphics = self.attachAsset('Drone', {
anchorX: 0.5,
anchorY: 0.5
});
self.HitPoints = 3;
self.randomOffset = Math.random() * 100; // Random timing for each drone
self.speed = 2.25;
self.update = function () {
// Add robotic hover effects
// Check for nearby enemies and adjust path to avoid collisions
var nearbyEnemy = enemies.find(function (enemy) {
return enemy !== self && Math.abs(enemy.x - self.x) < 100 && Math.abs(enemy.y - self.y) < 100;
});
if (nearbyEnemy) {
self.x += (self.x < nearbyEnemy.x ? -1 : 1) * self.speed; // Move away from the nearby enemy
} else {
self.y += self.speed * (Math.random() > 0.1 ? 1 : 0); // Brief pauses in downward movement
}
self.x += Math.sin(LK.ticks / 10 + self.randomOffset) * 2; // Small jerky side-to-side movements
if (Math.random() > 0.95) {
self.x += Math.random() * 4 - 2; // Quick position corrections
}
// Pulse effect on hit
if (self.pulseEffect) {
droneGraphics.scale.x = 1.2;
droneGraphics.scale.y = 1.2;
self.pulseEffect = false;
} else {
droneGraphics.scale.x = 1.0;
droneGraphics.scale.y = 1.0;
}
if (self.HitPoints <= 0) {
// Create drone pieces upon destruction
var centerPiece = new DronePiece('DroneCenterPart');
centerPiece.x = self.x;
centerPiece.y = self.y;
game.addChild(centerPiece);
var leftPiece = new DronePiece('DroneLeftPart');
leftPiece.x = self.x - 40;
leftPiece.y = self.y;
game.addChild(leftPiece);
var rightPiece = new DronePiece('DroneRightPart');
rightPiece.x = self.x + 40;
rightPiece.y = self.y;
game.addChild(rightPiece);
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else if (self.y > 2732) {
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
}
};
});
// DronePiece class for drone destruction effect
var DronePiece = Container.expand(function (assetType) {
var self = Container.call(this);
var pieceGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = Math.random() * 6 - 3; // Increased random horizontal speed
self.speedY = Math.random() * 4 - 2; // Random vertical speed
self.alphaDecay = 0.02; // Rate at which the piece fades out
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
pieceGraphics.rotation += Math.random() * 0.1 - 0.05; // Add slight random rotation
pieceGraphics.alpha -= self.alphaDecay;
if (pieceGraphics.alpha <= 0) {
self.destroy();
}
};
});
// Dust class for dust particles
var Dust = Container.expand(function () {
var self = Container.call(this);
var dustGraphics = self.attachAsset('Dust', {
anchorX: 0.5,
anchorY: 0.5
});
dustGraphics.alpha = 0.75;
self.speed = Math.random() * 3 + 1;
self.rotationSpeed = Math.random() * 0.02 - 0.01; // Random rotation speed between -0.01 and 0.01
self.direction = Math.random() * Math.PI * 0.5;
self.update = function () {
self.y += self.speed;
self.x += Math.sin(self.direction) * self.speed; // Add slight X travel based on direction
self.rotation += self.rotationSpeed; // Add rotation
dustGraphics.alpha -= 0.01; // fade out at a medium pace
if (self.y > 2732 || dustGraphics.alpha <= 0) {
self.destroy();
}
};
});
// Assets will be automatically created and loaded by the LK engine based on their usage in the code.
// Hero class representing the player's spaceship
var Hero = Container.expand(function () {
var self = Container.call(this);
self.prevX = self.x; // Initialize prevX with the current x position
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.soldierCloneCount = 0; // Initialize soldier clone count
self.shielded = false; // Initialize shielded state
self.shieldLevel = 0; // Initialize shield level
self.shieldGraphics = null; // Placeholder for shield asset
self.update = function () {
if (self.shielded && self.shieldGraphics) {
self.shieldGraphics.rotation += 0.01; // Rotate shield slowly
// Adjust shield size to cover hero asset
var scaleFactor = Math.max(heroGraphics.width / self.shieldGraphics.width, heroGraphics.height / self.shieldGraphics.height);
self.shieldGraphics.scale.x = scaleFactor;
self.shieldGraphics.scale.y = scaleFactor;
// Update shield tint based on shield level
self.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default
if (self.shieldLevel === 2) {
self.shieldGraphics.tint = 0xFFFF00; // Yellow tint
} else if (self.shieldLevel === 3) {
self.shieldGraphics.tint = 0xFF0000; // Red tint
}
}
if (self.y > 2375) {
self.y -= self.speed;
}
// Add rotation based on movement direction
if (self.x > self.prevX) {
self.rotation += Math.PI / 180 * 1; // Rotate 1 degree to the right
if (self.rotation > Math.PI / 180 * 5) {
self.rotation = Math.PI / 180 * 5;
}
} else if (self.x < self.prevX) {
self.rotation -= Math.PI / 180 * 1; // Rotate 1 degree to the left
if (self.rotation < Math.PI / 180 * -5) {
self.rotation = Math.PI / 180 * -5;
}
} else {
if (self.rotation > 0) {
self.rotation -= Math.PI / 180 * 1;
if (self.rotation < 0) {
self.rotation = 0;
}
} else if (self.rotation < 0) {
self.rotation += Math.PI / 180 * 1;
if (self.rotation > 0) {
self.rotation = 0;
}
}
}
self.prevX = self.x; // Store the current x position for the next frame
// Removed pulsing scale effect for hero
self.scale.x = 1.0;
};
// Method to handle shooting
self.shootBehavior = powerUpManager.defaultBehavior; // Set initial behavior
// Method to handle shooting
self.shoot = function () {
self.shootBehavior.call(self);
};
});
// Bullet class for hero's bullets
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('heroBullet1', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.Type = 'standard'; // Default type for bullets
self.Power = powerUpManager.currentPowerLevel || 1; // Initialize power level from PowerUpManager
self.update = function () {
// Move in direction of rotation
self.y += Math.cos(self.rotation) * self.speed;
self.x += Math.sin(self.rotation) * self.speed;
// Adjust out-of-bounds check for angled movement
if (self.y < 0 || self.x < 0 || self.x > 2048) {
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
}
};
self.updateVisual = function () {
if (bulletGraphics) {
self.removeChild(bulletGraphics);
}
var assetId = 'heroBullet' + self.Power;
console.log("Loading bullet asset: " + assetId);
bulletGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
});
// PowerUp class for handling power-up movement and collection
var PowerUp = Container.expand(function (assetType) {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3; // Speed at which the power-up moves down the screen
self.update = function () {
self.y += self.speed;
// Check if the power-up is collected by the hero
if (self.intersects(hero)) {
switch (assetType) {
case 'SoldierCloneIcon':
if (soldierClones.length < 6) {
hero.soldierCloneCount++;
var offset = (soldierClones.length % 2 === 0 ? 40 : -40) * Math.ceil((soldierClones.length + 1) / 2);
var newClone = new SoldierClone();
newClone.x = hero.x + offset;
newClone.y = hero.y;
newClone.zIndex = hero.zIndex - 1; // Ensure clones are rendered below the hero
soldierClones.push(newClone);
backgroundContainer.addChild(newClone);
}
break;
case 'WeaponPowerIcon':
powerUpManager.currentPowerLevel = Math.min(powerUpManager.currentPowerLevel + 1, 4);
console.log("Power up collected. New level: " + powerUpManager.currentPowerLevel);
break;
case 'ShieldIcon':
if (!hero.shielded) {
hero.shielded = true;
hero.shieldGraphics = hero.attachAsset('heroShield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5 // Set opacity to 50%
});
}
hero.shieldLevel = Math.min(hero.shieldLevel + 1, 3); // Increase shield level to a max of 3
// Change shield tint based on shield level
hero.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00; // Yellow tint
} else if (hero.shieldLevel === 3) {
hero.shieldGraphics.tint = 0xFF0000; // Red tint
}
break;
case 'BombIcon':
powerUpManager.switchPowerUp(PowerUpTypes.BOMB);
powerUpManager.bombBehavior();
break;
}
hero.shootBehavior = powerUpManager.getCurrentPowerBehavior();
soldierClones.forEach(function (clone) {
clone.shootBehavior = hero.shootBehavior;
});
self.destroy();
}
// Destroy if out of screen
if (self.y > 2732) {
self.destroy();
}
};
});
// RailingLeft class for the scrolling left railing
var RailingLeft = Container.expand(function (assetType) {
var self = Container.call(this);
var railingGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
if (self.y >= 2732) {
self.y = -2732;
}
};
});
// RailingRight class for the scrolling right railing
var RailingRight = Container.expand(function (assetType) {
var self = Container.call(this);
var railingGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
if (self.y >= 2732) {
self.y = -2732;
}
};
});
// RoadScroll class for the scrolling road
var RoadScroll = Container.expand(function (assetType) {
var self = Container.call(this);
var roadGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0
});
if (assetType === 'CityBackgroundHD') {
self.speed = 1;
} else {
self.speed = 2;
}
self.update = function () {
self.y += self.speed;
if (self.y >= 2732) {
self.y = -2732;
}
};
});
// SoldierClone class representing a clone of the player's character
var SoldierClone = Container.expand(function () {
var self = Container.call(this);
var cloneGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7 // Set opacity to 70%
});
self.health = 1;
self.update = function () {
self.destroy = function () {
// Remove bullets associated with this clone
for (var i = heroBullets.length - 1; i >= 0; i--) {
if (heroBullets[i].x === self.x && heroBullets[i].y === self.y - self.height / 2) {
heroBullets[i].destroy();
heroBullets.splice(i, 1);
}
}
// Call original destroy method
Container.prototype.destroy.call(self);
};
self.y = hero.y;
// Check for collision with enemies
for (var i = 0; i < enemies.length; i++) {
if (self.intersects(enemies[i])) {
self.destroy();
var index = soldierClones.indexOf(self);
if (index > -1) {
soldierClones.splice(index, 1);
}
hero.soldierCloneCount--;
return;
}
}
// Auto-fire like the player
self.shoot();
};
// Method to handle shooting
self.shoot = function () {
if (LK.ticks % 18 == 0) {
// Match hero's fire rate
var newBullet = new HeroBullet(); // Use the same bullet type as the hero
newBullet.x = self.x; // Create bullets at the clone's current position
newBullet.y = self.y - self.height / 2;
newBullet.Power = heroBullets.length > 0 ? heroBullets[0].Power : 1; // Match hero's bullet power
newBullet.updateVisual(); // Update bullet visuals based on power
heroBullets.push(newBullet); // Add the new bullets to the game's bullet array
game.addChild(newBullet);
}
};
});
// TitleScreen class for the title screen
var TitleScreen = Container.expand(function () {
var self = Container.call(this);
// Attach game logo
var logo = self.attachAsset('GameLogoHD', {
anchorX: 0.5,
anchorY: 0.5
});
logo.x = 2048 / 2;
logo.y = 2732 / 2 - 200;
// Attach play button
var playButton = self.attachAsset('PlayButton', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.x = 2048 / 2;
playButton.y = logo.y + logo.height / 2 + playButton.height / 2 + 50;
// Event handler for play button
playButton.down = function (x, y, obj) {
isTitle = false;
isStarted = true;
self.destroy();
startGame();
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
var PowerUpTypes = {
DEFAULT: 'DEFAULT',
SOLDIER_CLONE: 'SOLDIER_CLONE',
SHIELD: 'SHIELD',
WEAPON_POWER: 'WEAPON_POWER',
BOMB: 'BOMB' // Add bomb type
};
// PowerUpManager class to manage power-ups
// Initialize the city background for parallax effect
var PowerUpManager = function PowerUpManager() {
this.currentPowerUp = PowerUpTypes.DEFAULT;
this.currentPowerLevel = LK.getScore() > 0 ? LK.getScore() : 1; // Initialize power level based on score or default to 1
this.switchPowerUp = function (newPowerUp) {
if (PowerUpTypes[newPowerUp]) {
this.currentPowerUp = newPowerUp;
}
};
this.getCurrentPowerBehavior = function () {
switch (this.currentPowerUp) {
case PowerUpTypes.SOLDIER_CLONE:
return this.soldierCloneBehavior;
case PowerUpTypes.BOMB:
return this.bombBehavior;
default:
return this.defaultBehavior;
}
};
this.defaultBehavior = function () {
var bullet = new HeroBullet();
bullet.x = hero.x;
bullet.y = hero.y - hero.height / 2;
bullet.Power = powerUpManager.currentPowerLevel || 1; // Use saved power level from PowerUpManager
bullet.updateVisual(); // Update the visual after setting power
heroBullets.push(bullet);
game.addChild(bullet);
console.log("Created bullet with power: " + bullet.Power);
};
this.soldierCloneBehavior = function () {
// Soldier clone behavior
// Removed clone spawning logic
};
this.bombBehavior = function () {
var blast = new Container();
var blastGraphics = blast.attachAsset('BombBlast', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
// Start very small
scaleY: 0.1
});
blast.x = 1024;
blast.y = 1366;
blast.alpha = 1;
blast.zIndex = 1000; // Try putting it in front of everything
game.addChild(blast);
// Kill enemies
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] && enemies[i].y > 0) {
enemies[i].HitPoints = 0;
}
}
// Flash effect
var flash = new Container();
var flashGraphics = flash.attachAsset('whitePixel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 30
});
flash.x = game.width / 2;
flash.y = game.height / 2;
flash.alpha = 0.8;
game.addChild(flash);
LK.setTimeout(function () {
flash.destroy();
}, 100);
// Rapid expansion animation
var expandBlast = LK.setInterval(function () {
blast.scaleX += 5; // Increase scale more rapidly
blast.scaleY += 5;
if (blast.scaleX > 2048 || blast.scaleY > 2732) {
// Check if it has expanded beyond the screen
LK.clearInterval(expandBlast);
blast.destroy();
}
}, 30); // Faster interval
// Screen shake
var originalX = game.x;
var shakeAmount = 20;
game.x += shakeAmount;
LK.setTimeout(function () {
game.x -= shakeAmount * 2;
LK.setTimeout(function () {
game.x += shakeAmount;
LK.setTimeout(function () {
game.x = originalX;
}, 50);
}, 50);
}, 50);
};
};
// PowerUpTypes enum/constants
var PowerUpTypes = {
DEFAULT: 'DEFAULT',
LASER_BEAM: 'LASER_BEAM',
ROCKETS: 'ROCKETS',
DRONE: 'DRONE',
SOLDIER_CLONE: 'SOLDIER_CLONE',
SHIELD: 'SHIELD',
// Add shield power-up type
WEAPON_POWER: 'WEAPON_POWER'
};
var LaserMechanic = function LaserMechanic(origin, chargeDuration, fireDuration, slideOffDuration) {
this.origin = origin;
this.chargeDuration = chargeDuration;
this.fireDuration = fireDuration;
this.slideOffDuration = slideOffDuration;
// State tracking
this.isCharging = false;
this.isFiring = false;
this.isSliding = false;
// Timing
this.chargeStartTime = null;
this.fireStartTime = null;
this.slideStartTime = null;
// Flag to indicate attack completion
this.attackComplete = false;
// Assets
this.chargeEffect = null;
this.laserBeam = null;
var index = activeLaserBeams.indexOf(this);
if (index > -1) {
activeLaserBeams.splice(index, 1);
}
// Method to start charging
LaserMechanic.prototype.startCharge = function () {
if (this.isCharging || this.isFiring || this.isSliding) {
return;
}
this.isCharging = true;
this.chargeStartTime = LK.ticks;
// Create charge effect
this.chargeEffect = LK.getAsset('LaserCharge', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
scale: {
x: 0.5,
y: 0.5
}
});
if (this.origin) {
this.chargeEffect.y += this.origin.height * 0.1; // Move charge effect down by 10% of origin's height
this.origin.addChild(this.chargeEffect);
}
};
// Target
this.targetX = null;
this.targetY = null;
// Method to update charge progress
LaserMechanic.prototype.updateCharge = function () {
if (!this.isCharging) {
return;
}
var chargeProgress = (LK.ticks - this.chargeStartTime) / this.chargeDuration;
// Update charge effect
this.chargeEffect.alpha = 0.5 + chargeProgress * 0.5; // Fade in
this.chargeEffect.scale.x = 0.5 + chargeProgress * 1.5; // Grow outward
this.chargeEffect.scale.y = 0.5 + chargeProgress * 1.5;
// Capture target position at 2/3 through charge
if (chargeProgress >= 0.67 && !this.targetX) {
this.targetX = hero.x;
this.targetY = hero.y;
}
// Check if charge is complete
if (chargeProgress >= 1) {
if (this.origin && this.chargeEffect) {
this.origin.removeChild(this.chargeEffect);
}
this.chargeEffect = null;
this.isCharging = false;
this.startFiring(); // Add this line to transition to firing phase
}
};
};
var cityBackground1 = game.addChild(new RoadScroll('CityBackgroundHD'));
var cityBackground2 = game.addChild(new RoadScroll('CityBackgroundHD'));
cityBackground1.x = 2048 / 2;
cityBackground2.x = 2048 / 2;
cityBackground1.y = 0;
cityBackground2.y = -2732;
// Initialize the road instances
var road1 = game.addChild(new RoadScroll('Road'));
var road2 = game.addChild(new RoadScroll('Road2'));
road2.x = 2048 / 2;
road1.x = 2048 / 2;
road1.y = 0;
road2.y = -2732;
// Initialize the left railing instances
var railingLeft1 = game.addChild(new RailingLeft('RailingStart'));
var railingLeft2 = game.addChild(new RailingLeft('RailingEnd'));
railingLeft1.x = 2048 * 0.16;
railingLeft2.x = 2048 * 0.16;
railingLeft1.y = 0;
railingLeft2.y = -2732;
// Initialize the right railing instances
var railingRight1 = game.addChild(new RailingRight('RailingEnd'));
var railingRight2 = game.addChild(new RailingRight('RailingStart'));
railingRight1.x = 2048 * 0.81; // Moved left by 3%
railingRight2.x = 2048 * 0.81; // Moved left by 3%
railingRight1.y = 0;
railingRight2.y = -2732;
// Initialize game state variables
var isTitle = true;
var isStarted = false;
// Initialize title screen
if (isTitle) {
var titleScreen = game.addChild(new TitleScreen());
}
// Initialize variables
var backgroundContainer;
var hero;
var enemies = [];
var heroBullets = [];
var soldierClones = [];
var powerUpManager = new PowerUpManager(); // Initialize powerUpManager
powerUpManager.currentPowerLevel = 1; // Track current power level at start
// Function to start the game
function startGame() {
// Initialize background container
backgroundContainer = new Container();
game.addChild(backgroundContainer);
// Initialize hero
hero = game.addChild(new Hero());
hero.soldierCloneCount = soldierClones.length; // Set initial soldier clone count
hero.x = 2048 / 2;
hero.y = 2732 + hero.height;
// Initialize enemies, bullets, and laser beams arrays
enemies = [];
heroBullets = [];
activeLaserBeams = [];
hero.shootBehavior = powerUpManager.getCurrentPowerBehavior().bind(hero);
}
// Function to handle game updates
game.update = function () {
soldierClones.forEach(function (clone, index) {
clone.shootBehavior = hero.shootBehavior;
var offset = (index % 2 === 0 ? 160 : -160) * Math.ceil((index + 1) / 2);
clone.x = hero.x + offset;
});
cityBackground1.update();
cityBackground2.update();
// Update the road instances
road1.update();
road2.update();
// Update the left railing instances
railingLeft1.update();
railingLeft2.update();
// Update the right railing instances
railingRight1.update();
railingRight2.update();
if (isStarted) {
if (dragNode) {
hero.x = dragNode.x;
hero.y = dragNode.y;
}
// Update enemies
if (!enemies) {
return;
} // Ensure enemies array is initialized
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i]) {
enemies[i].update();
}
if (enemies[i] && enemies[i].intersects(hero)) {
if (hero.shielded) {
hero.shieldLevel -= 1;
if (hero.shieldLevel <= 0) {
hero.shielded = false;
if (hero.shieldGraphics) {
hero.shieldGraphics.destroy();
hero.shieldGraphics = null;
}
} else {
// Update shield tint based on new shield level
hero.shieldGraphics.tint = 0xFFFFFF; // Reset tint to default
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00; // Yellow tint
} else if (hero.shieldLevel === 1) {
hero.shieldGraphics.tint = 0xFFFFFF; // White tint
}
}
// Destroy enemy into pieces
if (enemies[i] instanceof Drone) {
var centerPiece = new DronePiece('DroneCenterPart');
centerPiece.x = enemies[i].x;
centerPiece.y = enemies[i].y;
game.addChild(centerPiece);
var leftPiece = new DronePiece('DroneLeftPart');
leftPiece.x = enemies[i].x - 40;
leftPiece.y = enemies[i].y;
game.addChild(leftPiece);
var rightPiece = new DronePiece('DroneRightPart');
rightPiece.x = enemies[i].x + 40;
rightPiece.y = enemies[i].y;
game.addChild(rightPiece);
} else if (enemies[i] instanceof Bruiser) {
var centerPiece = new BruiserPiece('BruiserCenterPart');
centerPiece.x = enemies[i].x;
centerPiece.y = enemies[i].y;
game.addChild(centerPiece);
var leftPiece = new BruiserPiece('BruiserLeftPart');
leftPiece.x = enemies[i].x - 40;
leftPiece.y = enemies[i].y;
game.addChild(leftPiece);
var rightPiece = new BruiserPiece('BruiserRightPart');
rightPiece.x = enemies[i].x + 40;
rightPiece.y = enemies[i].y;
game.addChild(rightPiece);
} else if (enemies[i] instanceof Blaster) {
var bottomPiece = new BlasterPiece('BlasterBottomPiece');
bottomPiece.x = enemies[i].x;
bottomPiece.y = enemies[i].y;
game.addChild(bottomPiece);
var leftPiece = new BlasterPiece('BlasterLeftPiece');
leftPiece.x = enemies[i].x - 40;
leftPiece.y = enemies[i].y;
game.addChild(leftPiece);
var rightPiece = new BlasterPiece('BlasterRightPiece');
rightPiece.x = enemies[i].x + 40;
rightPiece.y = enemies[i].y;
game.addChild(rightPiece);
}
enemies[i].destroy();
enemies.splice(i, 1);
} else {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
// Update active laser beams
for (var l = activeLaserBeams.length - 1; l >= 0; l--) {
activeLaserBeams[l].update();
if (activeLaserBeams[l].isAttackComplete()) {
if (activeLaserBeams[l].laserBeam) {
activeLaserBeams[l].laserBeam.destroy();
}
activeLaserBeams.splice(l, 1);
}
}
// Update hero bullets
for (var j = heroBullets.length - 1; j >= 0; j--) {
heroBullets[j].update();
for (var k = enemies.length - 1; k >= 0; k--) {
if (heroBullets[j] && heroBullets[j].intersects(enemies[k]) && enemies[k].y > 0) {
enemies[k].HitPoints -= heroBullets[j].Power;
// Apply an increased push back effect
if (!(enemies[k] instanceof Bruiser)) {
enemies[k].y -= 12; // Push the drone upwards slightly more
}
enemies[k].pulseEffect = true; // Trigger pulse effect
// Removed tracerTail reference
heroBullets[j].destroy();
heroBullets.splice(j, 1);
if (enemies[k].HitPoints <= 0) {
// Randomly select a power-up type for equal chance drops
var powerUpTypes = ['SoldierCloneIcon', 'WeaponPowerIcon', 'ShieldIcon', 'BombIcon'];
var randomPowerUpType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
var powerUp = new PowerUp(randomPowerUpType);
powerUp.x = enemies[k].x;
powerUp.y = enemies[k].y;
game.addChild(powerUp);
if (enemies[k] instanceof Drone) {
// Create drone pieces upon destruction
var centerPiece = new DronePiece('DroneCenterPart');
centerPiece.x = enemies[k].x;
centerPiece.y = enemies[k].y;
game.addChild(centerPiece);
var leftPiece = new DronePiece('DroneLeftPart');
leftPiece.x = enemies[k].x - 40; // Increase spread
leftPiece.y = enemies[k].y;
game.addChild(leftPiece);
var rightPiece = new DronePiece('DroneRightPart');
rightPiece.x = enemies[k].x + 40; // Increase spread
rightPiece.y = enemies[k].y;
game.addChild(rightPiece);
} else if (enemies[k] instanceof Bruiser) {
// Create bruiser pieces upon destruction
var centerPiece = new BruiserPiece('BruiserCenterPart');
centerPiece.x = enemies[k].x;
centerPiece.y = enemies[k].y;
game.addChild(centerPiece);
var leftPiece = new BruiserPiece('BruiserLeftPart');
leftPiece.x = enemies[k].x - 40; // Increase spread
leftPiece.y = enemies[k].y;
var rightPiece = new BruiserPiece('BruiserRightPart');
rightPiece.x = enemies[k].x + 40; // Increase spread
rightPiece.y = enemies[k].y;
leftPiece.speedX = -Math.abs(leftPiece.speedX) * 1.5; // Increase force for left piece
rightPiece.speedX = Math.abs(rightPiece.speedX) * 1.5; // Increase force for right piece
game.addChild(leftPiece);
game.addChild(rightPiece);
} else if (enemies[k] instanceof Blaster) {
// Create blaster pieces upon destruction
var bottomPiece = new BlasterPiece('BlasterBottomPiece');
bottomPiece.x = enemies[k].x;
bottomPiece.y = enemies[k].y;
game.addChild(bottomPiece);
var leftPiece = new BlasterPiece('BlasterLeftPiece');
leftPiece.x = enemies[k].x - 40; // Increase spread
leftPiece.y = enemies[k].y;
game.addChild(leftPiece);
var rightPiece = new BlasterPiece('BlasterRightPiece');
rightPiece.x = enemies[k].x + 40; // Increase spread
rightPiece.y = enemies[k].y;
game.addChild(rightPiece);
}
enemies[k].destroy();
enemies.splice(k, 1);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
break;
}
}
}
if (LK.ticks % 240 == 0) {
var newBlaster = new Blaster();
newBlaster.x = 2048 * 0.21 + Math.random() * (2048 * 0.55); // Adjusted x position within the Road area with 5% margin
newBlaster.y = -newBlaster.height; // Start just outside the top of the screen
enemies.push(newBlaster);
game.addChild(newBlaster);
}
// Fire bullets using current power-up behavior
if (LK.ticks % 18 == 0) {
if (hero && hero.shootBehavior) {
hero.shootBehavior();
}
}
// Generate dust particles in sync with player pulsing
if (LK.ticks % 24 == 0) {
var newDust = new Dust();
newDust.x = hero.x - hero.width / 4; // Move dust spawn position right half as much as the last move
newDust.y = hero.y + hero.height / 2 * 0.93; // Move dust spawn point up 3% more
game.addChild(newDust);
} else if (LK.ticks % 24 == 12) {
var newDust = new Dust();
newDust.x = hero.x + hero.width / 4; // Create another dust spawn point an equal distance in from the right of the player asset
newDust.y = hero.y + hero.height / 2 * 0.93; // Move dust spawn point up 3% more
game.addChild(newDust);
}
}
};
// Handle touch input for hero movement
var dragNode = null;
game.down = function (x, y, obj) {
if (isStarted) {
dragNode = {
x: hero.x,
y: hero.y
};
// Add a tilt-back effect during initial movement
hero.rotation = x > hero.x ? Math.PI / 180 * -1 : Math.PI / 180 * 1;
}
};
game.move = function (x, y, obj) {
if (isStarted && dragNode) {
// Add a slight delay to the drag control to make the player feel like it has more weight
dragNode.x += (x - dragNode.x) * 0.1;
dragNode.y = hero.y; // Lock the y position to the hero's initial y position
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Display score
var scoreTxt = new Text2('0', {
size: 150,
fill: "#ffffff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
LaserMechanic.prototype.startFiring = function () {
if (!this.origin || !this.targetX || !this.targetY || this.isFiring) {
return;
}
this.isFiring = true;
this.fireStartTime = LK.ticks;
// Create laser beam
this.laserBeam = LK.getAsset('LaserBeam', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1,
// Normal width
scaleY: 5 // Make it long
});
game.addChild(this.laserBeam);
activeLaserBeams.push(this);
// Position at origin
if (this.origin) {
this.laserBeam.x = this.origin.x;
this.laserBeam.y = this.origin.y;
}
// Calculate direction to target
var directionX = this.targetX - this.laserBeam.x;
var directionY = this.targetY - this.laserBeam.y;
// Set rotation
this.laserBeam.rotation = Math.atan2(directionY, directionX) - Math.PI / 2;
};
LaserMechanic.prototype.updateFiring = function () {
if (!this.isFiring) {
return;
}
var fireProgress = (LK.ticks - this.fireStartTime) / this.fireDuration;
if (fireProgress <= 1) {
// Stretch the laser
this.laserBeam.scaleY += (20 - this.laserBeam.scaleY) * 0.1;
// Keep beam pinned to origin
this.laserBeam.x = this.origin.x;
this.laserBeam.y = this.origin.y;
} else {
// Transition to sliding phase
this.isFiring = false;
this.startSliding();
}
};
LaserMechanic.prototype.startSliding = function () {
this.isSliding = true;
this.slideStartTime = LK.ticks;
this.origin = null; // Detach laser from Blaster origin
// Calculate slide direction to move away from the origin point
var directionX = -Math.sin(this.laserBeam.rotation);
var directionY = Math.cos(this.laserBeam.rotation);
this.slideDirection = {
x: directionX,
y: directionY
};
};
LaserMechanic.prototype.updateSliding = function () {
if (!this.isSliding || !this.laserBeam) {
return;
}
var slideProgress = (LK.ticks - this.slideStartTime) / this.slideOffDuration;
if (slideProgress <= 1) {
// Move the beam off screen
this.laserBeam.x += this.slideDirection.x * 20;
this.laserBeam.y += this.slideDirection.y * 20;
} else {
// Clean up
if (this.laserBeam) {
game.removeChild(this.laserBeam);
this.laserBeam = null;
}
this.isSliding = false;
this.slideDirection = null;
this.attackComplete = true;
if (this.origin) {
this.origin.laserMechanic.attackComplete = true;
}
}
};
// Method to reset attack states
LaserMechanic.prototype.resetAttack = function () {
this.isCharging = false;
this.isFiring = false;
this.isSliding = false;
this.targetX = null;
this.targetY = null;
this.attackComplete = false;
return true;
};
LaserMechanic.prototype.update = function () {
if (this.isCharging) {
this.updateCharge();
} else if (this.isFiring) {
this.updateFiring();
} else if (this.isSliding || this.laserBeam) {
this.updateSliding();
}
};
// Method to check if the attack sequence is complete
LaserMechanic.prototype.isAttackComplete = function () {
return this.attackComplete;
};
LaserMechanic.prototype.detachBeam = function () {
if (this.laserBeam) {
// Detach laser from origin
this.origin = null;
// Force laser into sliding phase
this.startSliding();
}
};
View of a futuristic soldier from directly overhead. White armor with blue glowing cyberpunk details. Holding weapon forward.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
The lights of a futuristic city in the dark at night. Very high above it looking straight down like from an airplane or a map. Background for an endlessly scrolling game.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A big button that say Play to start playing a game. Use neon cyberpunk style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Overhead view. A hovering robot with a tapered midsection with two bulky arms with claw like hands and a giant red “eye” on top of its body. Looking straight down. Cyberpunk, black with red glowing highlights.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Overhead view. A heavily armored attack robot. Two arms with large gauntlet type fists. Four large red glowing eyes. Three distinct parts, body and two arms. Symmetrical design. Birds Eye view above them looking down on their head. Simple shapes. Low detail. Cyberpunk, black with red glowing highlights.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A red glowing line. Bright red core with subtle outer glow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A blue transparent dome type shield. Simple graphics. Low details. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A ring of nuclear fire seen from overhead. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A thin robot with goggles riding a hover-bike. Twin blaster guns mounted on front. Top down view. Birds Eye view. Cyberpunk with red glowing highlights... Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Battle drone, circular. White with blue glowing highlights. Birds Eye view from overhead. Cyberpunk. Simple shapes.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
GameTheme
Music
TitleTheme
Music
HeroBlaster
Sound effect
Explosion
Sound effect
PowerUp
Sound effect
CloneSoldier
Sound effect
WeaponPowerUp
Sound effect
Drone
Sound effect
BinaryStorm
Sound effect
LaserCharge
Sound effect
LaserFire
Sound effect
BruiserStomp
Sound effect
RaiderSwoop
Sound effect
ShieldLevelUp
Sound effect
HeroHit
Sound effect
HeroScream
Sound effect