User prompt
Also add piece generation for red drones in game update.
User prompt
Make sure red drones generate pieces on destruction.
User prompt
var RedDrone = Container.expand(function() { var self = Container.call(this); var droneGraphics = self.attachAsset('Drone', { anchorX: 0.5, anchorY: 0.5 }); // Apply red tint to graphics droneGraphics.tint = 0xFF0000; // Set aggressive properties self.HitPoints = 3; self.randomOffset = Math.random() * 100; self.speed = 4; // Faster than regular drone self.update = function() { if (hero) { // Chase the hero if (self.x < hero.x) { self.x += self.speed; } else if (self.x > hero.x) { self.x -= self.speed; } self.y += self.speed; } // Keep pulse effect from base drone 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; } // Copy collision checks from base Drone if (CollisionManager.checkCollision(self, hero)) { if (hero.shielded) { hero.shieldLevel -= 1; if (hero.shieldLevel <= 0) { hero.shielded = false; if (hero.shieldGraphics) { hero.shieldGraphics.destroy(); hero.shieldGraphics = null; } } else { hero.shieldGraphics.tint = 0xFFFFFF; if (hero.shieldLevel === 2) { hero.shieldGraphics.tint = 0xFFFF00; } else if (hero.shieldLevel === 1) { hero.shieldGraphics.tint = 0xFFFFFF; } } generateEnemyPieces(self, DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']); self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } } else { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } if (self.HitPoints <= 0) { generateEnemyPieces(self, DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']); 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); difficultyManager.onEnemyDestroyed(); } } }; });
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.attachAsset')' in or related to this line: 'var droneGraphics = self.attachAsset('Drone', {' Line Number: 568
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.attachAsset')' in or related to this line: 'var droneGraphics = self.attachAsset('Drone', {' Line Number: 567
User prompt
var RedDrone = Drone.expand(function() { var self = Drone.call(this); // Get the graphics object from the base drone var droneGraphics = self.attachAsset('Drone', { anchorX: 0.5, anchorY: 0.5 }); // Apply tint to the graphics object droneGraphics.tint = 0xFF0000; // Increase base stats self.HitPoints = 2; self.speed = 4; // Override update to chase player var originalUpdate = self.update; self.update = function() { originalUpdate.call(self); if (hero) { // Move towards hero if (self.x < hero.x) { self.x += self.speed; } else if (self.x > hero.x) { self.x -= self.speed; } // Move down faster when above hero self.y += self.speed; } }; });
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.attachAsset')' in or related to this line: 'var redDroneGraphics = self.attachAsset('Drone', {' Line Number: 566
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.attachAsset')' in or related to this line: 'var redDroneGraphics = self.attachAsset('Drone', {' Line Number: 566
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.tint = 0xFF0000')' in or related to this line: 'self.tint = 0xFF0000;' Line Number: 567
User prompt
Modify DifficultyManager's spawnEnemy method to add RedDrone chance: self.spawnEnemy = function(enemyType) { if (!self.canSpawnEnemy()) { return; } var enemy; switch (enemyType) { case 'drone': // Chance for RedDrone increases with difficulty var redDroneChance = Math.min(self.currentDifficulty * 0.1, 0.3); // 10% per difficulty, max 30% if (Math.random() < redDroneChance) { enemy = new RedDrone(); } else { enemy = new Drone(); } break; case 'bruiser': enemy = new Bruiser(); break; case 'blaster': enemy = new Blaster(); break; default: return; } // Existing enemy enhancement enemy.HitPoints *= self.getEnemyStrength(); enemy.x = self.getSpawnX(); enemy.y = -enemy.height; enemies.push(enemy); game.addChild(enemy); self.activeEnemies++; };
User prompt
Let's create a RedDrone class that extends Drone: var RedDrone = Drone.expand(function() { var self = Drone.call(this); // Set tint to red self.tint = 0xFF0000; // Increase base stats self.HitPoints = 2; self.speed = 4; // Faster than regular drone // Override update to chase player var originalUpdate = self.update; self.update = function() { originalUpdate.call(self); // Chase logic if (hero) { // Move towards hero if (self.x < hero.x) { self.x += self.speed; } else if (self.x > hero.x) { self.x -= self.speed; } // Move down faster when above hero self.y += self.speed; } }; });
User prompt
Change spawnCratePair in CrateSpawnManager to: self.spawnCratePair = function() { var positions = self.getSpawnPositions(); var powerUps = self.getNextPowerUpPair(); // Changed this line var leftCrate = new PowerUpCrate(); leftCrate.init(powerUps.leftPowerUp); leftCrate.x = positions.leftX; leftCrate.y = -50; backgroundContainer.addChild(leftCrate); var rightCrate = new PowerUpCrate(); rightCrate.init(powerUps.rightPowerUp); rightCrate.x = positions.rightX; rightCrate.y = -50; backgroundContainer.addChild(rightCrate); self.powerUpPairsSpawned++; };
User prompt
Update getNextPowerUpPair and getRandomPowerUps in CrateSpawnManager to use consistent formats: self.getNextPowerUpPair = function() { if (self.powerUpPairsSpawned === 0) { self.powerUpPairsSpawned++; return { leftPowerUp: 'WEAPON_POWER', rightPowerUp: 'SOLDIER_CLONE' }; } else { return self.getRandomPowerUps(); } };
User prompt
Add an if and else check for the initial crate code we just added so it always returns those values if the they’re first but otherwise returned to random
User prompt
In crate spawn manager class 1. Add the tracking variable: self.powerUpPairsSpawned = 0; 2. Add the method for first pair guarantee: self.getNextPowerUpPair = function() { if (self.powerUpPairsSpawned === 0) { self.powerUpPairsSpawned++; return ['WEAPON_POWER', 'SOLDIER_CLONE']; } // Your existing random selection logic }; 3. In your crate spawn code, add: self.powerUpPairsSpawned++; // after spawning any pair of crates
User prompt
In PowerUpManager class: 1. Add the tracking variable: self.powerUpPairsSpawned = 0; 2. Add the method for first pair guarantee: self.getNextPowerUpPair = function() { if (self.powerUpPairsSpawned === 0) { self.powerUpPairsSpawned++; return ['WEAPON_POWER', 'SOLDIER_CLONE']; } // Your existing random selection logic }; In your crate spawn code, add: self.powerUpPairsSpawned++; // after spawning any pair of crates
User prompt
In PowerUpManager: 1. Add the tracking variable: self.powerUpPairsSpawned = 0; 2. Add the method for first pair guarantee: self.getNextPowerUpPair = function() { if (self.powerUpPairsSpawned === 0) { self.powerUpPairsSpawned++; return ['WEAPON_POWER', 'SOLDIER_CLONE']; } // Your existing random selection logic }; 3. In your crate spawn code, add: self.powerUpPairsSpawned++; // after spawning any pair of crates
User prompt
Let's modify the enemies to be tougher at higher difficulties. In DifficultyManager, add: self.getEnemyStrength = function() { // Every 2 levels of difficulty increases enemy HP var healthBonus = Math.floor(self.currentDifficulty / 2); return Math.max(1, healthBonus); }; Then modify spawnEnemy to use this: self.spawnEnemy = function(enemyType) { if (!self.canSpawnEnemy()) { return; } var enemy; switch (enemyType) { case 'drone': enemy = new Drone(); break; case 'bruiser': enemy = new Bruiser(); break; case 'blaster': enemy = new Blaster(); break; default: return; } // Increase enemy HP based on difficulty enemy.HitPoints *= self.getEnemyStrength(); enemy.x = self.getSpawnX(); enemy.y = -enemy.height; enemies.push(enemy); game.addChild(enemy); self.activeEnemies++; };
User prompt
Remove that function.
User prompt
Decrease speed of drone by .5
User prompt
Increase speed of all enemies by 1
User prompt
Laser should also destroy clones and update clone count on collision.
User prompt
Use collision manager to add collision detection to laser with hero. One collision laser should remove a shield level from hero if it is greater than 0 or flash screen and cause a game over if not.
User prompt
Double blaster health.
User prompt
Make sure to call difficulty manager on enemy destroyed if enemies leave the screen and are destroyed.
/****
* 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 = 10;
self.speed = 3;
// 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 (CollisionManager.checkCollision(self, hero)) {
// Handle collision with hero
if (hero.shielded) {
hero.shieldLevel -= 1;
if (hero.shieldLevel <= 0) {
hero.shielded = false;
if (hero.shieldGraphics) {
hero.shieldGraphics.destroy();
hero.shieldGraphics = null;
}
} else {
hero.shieldGraphics.tint = 0xFFFFFF;
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00;
} else if (hero.shieldLevel === 1) {
hero.shieldGraphics.tint = 0xFFFFFF;
}
}
// Destroy the enemy
generateEnemyPieces(self, BlasterPiece, ['BlasterBottomPiece', 'BlasterLeftPiece', 'BlasterRightPiece']);
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
if (self.HitPoints <= 0) {
// Create blaster pieces upon destruction
generateEnemyPieces(self, BlasterPiece, ['BlasterBottomPiece', 'BlasterLeftPiece', 'BlasterRightPiece']);
// 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);
difficultyManager.onEnemyDestroyed();
}
}
};
});
// 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();
}
};
});
var BombBlast = Container.expand(function () {
var self = Container.call(this);
var blastGraphics = self.attachAsset('BombBlast', {
anchorX: 0.5,
anchorY: 0.5
});
self.scaleX = 0.1;
self.scaleY = 0.1;
self.update = function () {
self.scaleX += 0.5;
self.scaleY += 0.5;
blastGraphics.scale.x = self.scaleX;
blastGraphics.scale.y = self.scaleY;
if (self.scaleX >= 10) {
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 = 20; // Double the hit points for Bruiser
self.speed = 5;
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 (CollisionManager.checkCollision(self, hero)) {
// Handle collision with hero
if (hero.shielded) {
hero.shieldLevel -= 1;
if (hero.shieldLevel <= 0) {
hero.shielded = false;
if (hero.shieldGraphics) {
hero.shieldGraphics.destroy();
hero.shieldGraphics = null;
}
} else {
hero.shieldGraphics.tint = 0xFFFFFF;
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00;
} else if (hero.shieldLevel === 1) {
hero.shieldGraphics.tint = 0xFFFFFF;
}
}
// Destroy the enemy
generateEnemyPieces(self, BruiserPiece, ['BruiserCenterPart', 'BruiserLeftPart', 'BruiserRightPart']);
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
if (self.HitPoints <= 0) {
// Create bruiser pieces upon destruction
generateEnemyPieces(self, BruiserPiece, ['BruiserCenterPart', 'BruiserLeftPart', 'BruiserRightPart']);
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);
difficultyManager.onEnemyDestroyed();
}
}
};
});
// 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();
}
};
});
var CrateSpawnManager = Container.expand(function () {
var self = Container.call(this);
self.powerUpPairsSpawned = 0;
self.lastSpawnTime = 0;
self.minSpawnInterval = 300;
self.maxSpawnInterval = 600;
self.getSpawnPositions = function () {
var roadCenterX = road1.x; // Assuming road1 is the reference for the road's center
var roadWidth = LK.getAsset('Road', {}).width;
return {
leftX: roadCenterX - roadWidth / 4 - 100 - roadWidth * 0.03,
rightX: roadCenterX + roadWidth / 4 + 100 - roadWidth * 0.015
};
};
self.getNextPowerUpPair = function () {
if (self.powerUpPairsSpawned === 0) {
self.powerUpPairsSpawned++;
return ['WEAPON_POWER', 'SOLDIER_CLONE'];
}
return self.getRandomPowerUps();
};
self.getRandomPowerUps = function () {
var powerUpTypes = ['SOLDIER_CLONE', 'SHIELD', 'WEAPON_POWER', 'BOMB'];
var leftIndex = Math.floor(Math.random() * powerUpTypes.length);
var rightIndex;
do {
rightIndex = Math.floor(Math.random() * powerUpTypes.length);
} while (rightIndex === leftIndex);
return {
leftPowerUp: powerUpTypes[leftIndex],
rightPowerUp: powerUpTypes[rightIndex]
};
};
self.spawnCratePair = function () {
var positions = self.getSpawnPositions();
var powerUps = self.getRandomPowerUps();
var leftCrate = new PowerUpCrate();
leftCrate.init(powerUps.leftPowerUp);
leftCrate.x = positions.leftX;
leftCrate.y = -50;
backgroundContainer.addChild(leftCrate);
var rightCrate = new PowerUpCrate();
rightCrate.init(powerUps.rightPowerUp);
rightCrate.x = positions.rightX;
rightCrate.y = -50;
backgroundContainer.addChild(rightCrate);
self.powerUpPairsSpawned++;
};
self.currentInterval = self.minSpawnInterval;
self.update = function () {
if (LK.ticks - self.lastSpawnTime > self.currentInterval) {
self.spawnCratePair();
self.lastSpawnTime = LK.ticks;
self.currentInterval = 6 * (self.minSpawnInterval + Math.floor(Math.random() * (self.maxSpawnInterval - self.minSpawnInterval)));
console.log('Spawned crate pair');
}
};
});
var DifficultyManager = Container.expand(function () {
var self = Container.call(this);
self.currentDifficulty = 1;
self.activeEnemies = 0;
self.maxEnemies = 12;
self.roadStartX = 2048 * 0.21;
self.roadWidth = 2048 * 0.55;
// Wave patterns for different difficulty levels
self.wavePatterns = {
1: {
drones: 3,
bruisers: 0,
blasters: 0
},
2: {
drones: 5,
bruisers: 0,
blasters: 0
},
3: {
drones: 6,
bruisers: 1,
blasters: 0
},
4: {
drones: 7,
bruisers: 1,
blasters: 1
},
5: {
drones: 8,
bruisers: 2,
blasters: 1
}
};
// Spawn quota to track needed spawns
self.spawnQuota = {
drones: 0,
bruisers: 0,
blasters: 0
};
self.update = function () {
if (LK.ticks % 60 === 0 && self.canSpawnEnemy()) {
var enemyType = self.getNextEnemyType();
if (enemyType) {
self.spawnEnemy(enemyType);
}
}
};
self.updateDifficulty = function (powerLevel) {
self.currentDifficulty = Math.floor(powerLevel * 1.5);
};
self.getSpawnX = function () {
return self.roadStartX + Math.random() * self.roadWidth;
};
self.getEnemyStrength = function () {
// Every 2 levels of difficulty increases enemy HP
var healthBonus = Math.floor(self.currentDifficulty / 2);
return Math.max(1, healthBonus);
};
self.updateSpawnQuota = function () {
var pattern = self.wavePatterns[self.currentDifficulty] || self.wavePatterns[5];
self.spawnQuota.drones = pattern.drones;
self.spawnQuota.bruisers = pattern.bruisers;
self.spawnQuota.blasters = pattern.blasters;
};
self.canSpawnEnemy = function () {
return self.activeEnemies < self.maxEnemies;
};
self.spawnEnemy = function (enemyType) {
if (!self.canSpawnEnemy()) {
return;
}
var enemy;
switch (enemyType) {
case 'drone':
enemy = new Drone();
break;
case 'bruiser':
enemy = new Bruiser();
break;
case 'blaster':
enemy = new Blaster();
break;
default:
return;
}
// Increase enemy HP based on difficulty
enemy.HitPoints *= self.getEnemyStrength();
enemy.x = self.getSpawnX();
enemy.y = -enemy.height;
enemies.push(enemy);
game.addChild(enemy);
self.activeEnemies++;
};
self.getNextEnemyType = function () {
// Check drones first
if (self.spawnQuota.drones > 0) {
self.spawnQuota.drones--;
return 'drone';
}
// Then bruisers
if (self.spawnQuota.bruisers > 0) {
self.spawnQuota.bruisers--;
return 'bruiser';
}
// Finally blasters
if (self.spawnQuota.blasters > 0) {
self.spawnQuota.blasters--;
return 'blaster';
}
return null;
};
self.onEnemyDestroyed = function () {
self.activeEnemies--;
if (self.spawnQuota.drones === 0 && self.spawnQuota.bruisers === 0 && self.spawnQuota.blasters === 0) {
self.updateSpawnQuota();
}
};
});
// 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.75;
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 (CollisionManager.checkCollision(self, hero)) {
// Handle collision with hero
if (hero.shielded) {
hero.shieldLevel -= 1;
if (hero.shieldLevel <= 0) {
hero.shielded = false;
if (hero.shieldGraphics) {
hero.shieldGraphics.destroy();
hero.shieldGraphics = null;
}
} else {
hero.shieldGraphics.tint = 0xFFFFFF;
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00;
} else if (hero.shieldLevel === 1) {
hero.shieldGraphics.tint = 0xFFFFFF;
}
}
// Destroy the enemy
generateEnemyPieces(self, DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']);
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
} else {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
if (self.HitPoints <= 0) {
// Create drone pieces upon destruction
generateEnemyPieces(self, DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']);
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);
difficultyManager.onEnemyDestroyed();
}
}
};
});
// 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':
difficultyManager.updateDifficulty(hero.soldierCloneCount + 1);
difficultyManager.updateSpawnQuota();
if (soldierClones.length < 6) {
// Array to track which positions are taken
var takenPositions = soldierClones.map(function (clone) {
return clone.offset;
});
// Find first available position
var positions = [-160, 160, -320, 320, -480, 480];
var newOffset = null;
for (var i = 0; i < positions.length; i++) {
if (!takenPositions.includes(positions[i])) {
newOffset = positions[i];
break;
}
}
if (newOffset !== null) {
hero.soldierCloneCount++;
var newClone = new SoldierClone();
newClone.offset = newOffset;
newClone.x = hero.x + newOffset;
newClone.y = hero.y;
newClone.zIndex = hero.zIndex - 1;
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);
difficultyManager.updateDifficulty(powerUpManager.currentPowerLevel);
difficultyManager.updateSpawnQuota();
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();
}
};
});
var PowerUpCrate = Container.expand(function () {
var self = Container.call(this);
var crateGraphics = self.attachAsset('PowerUpCrate', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize hitPoints property
self.hitPoints = 10;
// Create text display for hitPoints
var hitPointsText = new Text2(self.hitPoints.toString(), {
size: 80,
// Increase font size
fill: "#000000",
// Set initial font color to black
fontFamily: "Ultra" // Change font to Ultra
});
hitPointsText.anchor.set(0.5, 0.7); // Move text up by 50%
self.addChild(hitPointsText);
var powerUpAssetMap = {
SOLDIER_CLONE: 'SoldierCloneIcon',
SHIELD: 'ShieldIcon',
WEAPON_POWER: 'WeaponPowerIcon',
BOMB: 'BombIcon'
};
// Create icon display for power-up type using powerUpAssetMap
var powerUpIcon = null; // Store icon reference
var spinOffset = 0; // Add at top with other variables
var isInvulnerable = false; // Different name to be more clear
// Add init method
self.init = function (type) {
self.powerUpType = type;
// Create icon only after type is set
if (powerUpAssetMap[type]) {
powerUpIcon = self.attachAsset(powerUpAssetMap[type], {
anchorX: 0.5,
anchorY: 1.2
});
powerUpIcon.y = -50;
}
};
self.update = function () {
// Add floating and spinning animation to power-up icon
powerUpIcon.y = -50 + Math.sin(LK.ticks / 20) * 5;
// Y-axis spin effect using scaleX
spinOffset += 0.05; // Control spin speed
powerUpIcon.scale.x = Math.cos(spinOffset); // This will make it appear to spin
self.y += 4; // Update crate speed to 4
// Pulse effect on hit
if (self.pulseEffect) {
crateGraphics.scale.x = 1.2;
crateGraphics.scale.y = 1.2;
self.pulseEffect = false;
} else {
crateGraphics.scale.x = 1.0;
crateGraphics.scale.y = 1.0;
}
for (var j = heroBullets.length - 1; j >= 0; j--) {
if (heroBullets[j] && CollisionManager.checkCollision(heroBullets[j], self)) {
self.hitPoints -= 1;
self.pulseEffect = true; // Trigger pulse effect
heroBullets[j].destroy();
heroBullets.splice(j, 1);
hitPointsText.setText(self.hitPoints.toString(), {
size: 80,
fill: "#FF0000",
fontFamily: "Ultra"
});
LK.setTimeout(function () {
hitPointsText.setText(self.hitPoints.toString(), {
size: 80,
fill: "#000000",
fontFamily: "Ultra"
});
}, 100);
if (self.hitPoints <= 0) {
var powerUp = new PowerUp(powerUpAssetMap[self.powerUpType]);
powerUp.x = self.x;
powerUp.y = self.y;
backgroundContainer.addChild(powerUp);
self.destroy();
}
break;
}
}
// Check hero collision
if (hero && CollisionManager.checkCollision(self, hero)) {
LK.effects.flashScreen(0xff0000, 1000); // Flash screen red for 1 second
LK.showGameOver(); // Trigger proper game over
}
// Check soldier clone collisions
if (soldierClones && soldierClones.length > 0) {
for (var i = soldierClones.length - 1; i >= 0; i--) {
var clone = soldierClones[i];
if (clone && CollisionManager.checkCollision(self, clone)) {
clone.destroy();
// destroy() handles cleanup and count reduction
break;
}
}
}
if (self.y > 2732) {
self.destroy();
}
// Update the text display with current hitPoints
hitPointsText.setText(self.hitPoints.toString());
};
return self;
});
// 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);
self.side = null; // 'left' or 'right'
var cloneGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
scaleX: 0.75,
scaleY: 0.75
});
self.health = 1;
self.isImmune = false;
self.offset = 0; // Store initial offset from hero
self.update = function () {
self.y = hero.y;
// Maintain x offset from hero
self.x = hero.x + self.offset;
// Only check collisions once per frame
if (!self.isImmune && LK.ticks > self.lastCollisionFrame) {
for (var i = 0; i < enemies.length; i++) {
if (CollisionManager.checkCollision(self, enemies[i])) {
self.lastCollisionFrame = LK.ticks;
self.destroy();
return;
}
}
}
// Auto-fire like the player
self.shoot();
};
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);
}
}
if (self.side === 'right') {
// Only make clones on the same side immune
soldierClones.forEach(function (clone) {
if (clone.side === 'right') {
clone.isImmune = true;
LK.setTimeout(function () {
clone.isImmune = false;
}, 150);
}
});
} else {
// Same for left side
soldierClones.forEach(function (clone) {
if (clone.side === 'left') {
clone.isImmune = true;
LK.setTimeout(function () {
clone.isImmune = false;
}, 150);
}
});
}
// Update soldier clone count and array
var index = soldierClones.indexOf(self);
if (index > -1) {
soldierClones.splice(index, 1);
hero.soldierCloneCount--;
}
// Call original destroy method
Container.prototype.destroy.call(self);
};
// 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
****/
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) {
return t;
}
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) {
return i;
}
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function generateEnemyPieces(enemy, pieceClass, pieceTypes) {
pieceTypes.forEach(function (pieceType, index) {
var piece = new pieceClass(pieceType);
piece.x = enemy.x + (index - 1) * 40; // Spread pieces horizontally
piece.y = enemy.y;
game.addChild(piece);
});
}
var CollisionManager = {
// Remove the fixed collision data and simplify
checkCollision: function checkCollision(obj1, obj2) {
// Always use circle collision with calculated radii
return this.circleCollision(obj1, obj2);
},
getObjectRadius: function getObjectRadius(obj) {
var width = obj.width;
var height = obj.height;
// Adjust multiplier to tune collision size
return Math.min(width, height) * 0.4;
// Keep logging to help with tuning
console.log(obj.constructor.name + ' collision radius:', 'sprite size:', width, height, 'collision size:', Math.min(width, height) * 0.4);
},
circleCollision: function circleCollision(obj1, obj2) {
var radius1 = this.getObjectRadius(obj1);
var radius2 = this.getObjectRadius(obj2);
var dx = obj1.x - obj2.x;
var dy = obj1.y - obj2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance < radius1 + radius2;
}
};
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 = 1; // Initialize power level to default value
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 BombBlast();
blast.x = 1024;
blast.y = 1366;
blast.zIndex = 2000; // Ensure BombBlast is on a visible layer
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 = 30; // Increase shake intensity
var shakeDuration = 100; // Increase shake duration
game.x += shakeAmount;
LK.setTimeout(function () {
game.x -= shakeAmount * 2;
LK.setTimeout(function () {
game.x += shakeAmount;
LK.setTimeout(function () {
game.x -= shakeAmount * 2;
LK.setTimeout(function () {
game.x += shakeAmount;
LK.setTimeout(function () {
game.x = originalX;
}, shakeDuration);
}, shakeDuration);
}, shakeDuration);
}, shakeDuration);
}, shakeDuration);
};
};
// 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);
difficultyManager = new DifficultyManager();
difficultyManager.updateSpawnQuota();
// 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
var crateManager = new CrateSpawnManager();
backgroundContainer.addChild(crateManager);
enemies = [];
heroBullets = [];
activeLaserBeams = [];
hero.shootBehavior = powerUpManager.getCurrentPowerBehavior().bind(hero);
}
// Function to handle game updates
game.update = function () {
soldierClones.forEach(function (clone) {
clone.shootBehavior = hero.shootBehavior;
});
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] && CollisionManager.checkCollision(enemies[i], 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) {
generateEnemyPieces(enemies[i], DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']);
} else if (enemies[i] instanceof Bruiser) {
generateEnemyPieces(enemies[i], BruiserPiece, ['BruiserCenterPart', 'BruiserLeftPart', 'BruiserRightPart']);
} else if (enemies[i] instanceof Blaster) {
generateEnemyPieces(enemies[i], BlasterPiece, ['BlasterBottomPiece', 'BlasterLeftPiece', 'BlasterRightPiece']);
}
enemies[i].destroy();
enemies.splice(i, 1);
difficultyManager.onEnemyDestroyed();
} 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);
}
}
difficultyManager.update();
// 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] && CollisionManager.checkCollision(heroBullets[j], 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) {
if (enemies[k] instanceof Drone) {
generateEnemyPieces(enemies[k], DronePiece, ['DroneCenterPart', 'DroneLeftPart', 'DroneRightPart']);
} else if (enemies[k] instanceof Bruiser) {
generateEnemyPieces(enemies[k], BruiserPiece, ['BruiserCenterPart', 'BruiserLeftPart', 'BruiserRightPart']);
} else if (enemies[k] instanceof Blaster) {
generateEnemyPieces(enemies[k], BlasterPiece, ['BlasterBottomPiece', 'BlasterLeftPiece', 'BlasterRightPiece']);
}
enemies[k].destroy();
enemies.splice(k, 1);
difficultyManager.onEnemyDestroyed();
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
break;
}
}
}
// 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;
// Check collision with hero
if (CollisionManager.checkCollision(this.laserBeam, hero)) {
if (hero.shielded) {
hero.shieldLevel -= 1;
if (hero.shieldLevel <= 0) {
hero.shielded = false;
if (hero.shieldGraphics) {
hero.shieldGraphics.destroy();
hero.shieldGraphics = null;
}
} else {
hero.shieldGraphics.tint = 0xFFFFFF;
if (hero.shieldLevel === 2) {
hero.shieldGraphics.tint = 0xFFFF00;
} else if (hero.shieldLevel === 1) {
hero.shieldGraphics.tint = 0xFFFFFF;
}
}
} else {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
} else {
for (var i = soldierClones.length - 1; i >= 0; i--) {
var clone = soldierClones[i];
if (CollisionManager.checkCollision(this.laserBeam, clone)) {
clone.destroy();
break;
}
}
}
} 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();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -251,8 +251,9 @@
};
});
var CrateSpawnManager = Container.expand(function () {
var self = Container.call(this);
+ self.powerUpPairsSpawned = 0;
self.lastSpawnTime = 0;
self.minSpawnInterval = 300;
self.maxSpawnInterval = 600;
self.getSpawnPositions = function () {
@@ -262,8 +263,15 @@
leftX: roadCenterX - roadWidth / 4 - 100 - roadWidth * 0.03,
rightX: roadCenterX + roadWidth / 4 + 100 - roadWidth * 0.015
};
};
+ self.getNextPowerUpPair = function () {
+ if (self.powerUpPairsSpawned === 0) {
+ self.powerUpPairsSpawned++;
+ return ['WEAPON_POWER', 'SOLDIER_CLONE'];
+ }
+ return self.getRandomPowerUps();
+ };
self.getRandomPowerUps = function () {
var powerUpTypes = ['SOLDIER_CLONE', 'SHIELD', 'WEAPON_POWER', 'BOMB'];
var leftIndex = Math.floor(Math.random() * powerUpTypes.length);
var rightIndex;
@@ -287,9 +295,9 @@
rightCrate.init(powerUps.rightPowerUp);
rightCrate.x = positions.rightX;
rightCrate.y = -50;
backgroundContainer.addChild(rightCrate);
- this.powerUpPairsSpawned++;
+ self.powerUpPairsSpawned++;
};
self.currentInterval = self.minSpawnInterval;
self.update = function () {
if (LK.ticks - self.lastSpawnTime > self.currentInterval) {
@@ -1099,23 +1107,15 @@
};
// PowerUpManager class to manage power-ups
// Initialize the city background for parallax effect
var PowerUpManager = function PowerUpManager() {
- this.powerUpPairsSpawned = 0;
this.currentPowerUp = PowerUpTypes.DEFAULT;
this.currentPowerLevel = 1; // Initialize power level to default value
this.switchPowerUp = function (newPowerUp) {
if (PowerUpTypes[newPowerUp]) {
this.currentPowerUp = newPowerUp;
}
};
- this.getNextPowerUpPair = function () {
- if (this.powerUpPairsSpawned === 0) {
- this.powerUpPairsSpawned++;
- return ['WEAPON_POWER', 'SOLDIER_CLONE'];
- }
- // Your existing random selection logic
- };
this.getCurrentPowerBehavior = function () {
switch (this.currentPowerUp) {
case PowerUpTypes.SOLDIER_CLONE:
return this.soldierCloneBehavior;
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