User prompt
Add an ability in which enemies can dodge your bullets every 5 seconds.
User prompt
Make the enemy ships which reach the bottom edge shoot 10 projectile before self-destructing.
User prompt
The bullets which are shot by enemy ships after reaching the bottom edge are very hard to see. Make them the same color as normal enemy bullets.
User prompt
Make it so that whenever an enemy ship reaches the bottom edge of the screen, it aims toward you and shoots with increased fire rate and bullet speed for 5 seconds before self destructing. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Does not play still, how to fix???
User prompt
Still can't hear it.
User prompt
I added a firepool sound, yet it does not play
User prompt
I accidentally deleted firepool sound asset, add again
User prompt
```javascript // Define your sounds at the beginning of your code LK.init.sound('explosion', {volume: 0.7}); LK.init.sound('shieldActivation', {volume: 0.5}); LK.init.sound('firePoolDestroy', {volume: 0.6}); LK.init.sound('bulletExplosion', {volume: 0.4}); LK.init.sound('shieldCollision', {volume: 0.5}); LK.init.sound('playerCollision', {volume: 0.6}); LK.init.sound('levelUp', {volume: 0.8}); LK.init.sound('playerHit', {volume: 0.5}); LK.init.sound('gameOver', {volume: 0.7}); LK.init.sound('winSound', {volume: 0.8}); do this it still does not play
User prompt
do this for me please in my game
User prompt
Add these sounds to assets
User prompt
I still can't hear anything how do I create these sounds
User prompt
Can you create sounds for: Add sound when enemy is destroyed by fire pool shield activation sound effect player bullet explosion sound when bullet is removed at max bounce count collision sound when enemy collides with shield collision sound when player collides with enemy level up sound sound when player gets hit by enemy bullet background music when game starts game over sound effect win sound effect
User prompt
It still hits me even though the bullet is only in the vicinity of me (player)
User prompt
make it so that when a bullet collides with the player, only then damage is dealt to the player, the bullet cannot be in the vicinity of the player and still deal damage.
User prompt
Remove all the hitbox stuff keep the hitboxes normal
User prompt
THe bullets don't hit me sometimes
User prompt
Make the bullet, player and enemy ship hitboxes to be more exact. I am able to get hit by bullets without properly hitting them.
User prompt
Add sounds to this game for all actions.
User prompt
After the explosion of enemies, the enemies inside the radius of the explosion should be destroyed.
User prompt
Remove enemy bullet destruction completely from the whole game.
User prompt
The game is lagging sometimes because of the enemy bullets destruction ability. Remove the lag please.
User prompt
Also make it that enemy bullets cannot be destroyed until 7 seconds after the quad powerup ends
User prompt
Please fix the bug: 'TypeError: tween.stopTweens is not a function. (In 'tween.stopTweens(finalLifeText)', 'tween.stopTweens' is undefined)' in or related to this line: 'tween.stopTweens(finalLifeText);' Line Number: 1007
User prompt
The game starts lagging a lot when the powerup which allows for bullets to fire from 4 sides is activated. MAke it so that during the powerup, enemy bullets cannot be destroyed.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Use default hitbox
// Enemy properties
self.health = 1;
self.speed = 2;
self.scoreValue = 100;
self.fireRate = 120; // Ticks between shots
self.lastShot = Math.floor(Math.random() * 60); // Randomize initial shot timer
self.movementPattern = Math.floor(Math.random() * 3); // 0: straight, 1: zigzag, 2: circular
self.movementCounter = 0;
self.lastY = 0; // Track last Y position to detect reaching bottom
self.firingMode = false; // Track if enemy is in enhanced firing mode
self.firingModeStartTime = 0; // When enhanced firing mode started
// Initial target position (will be set during movement)
self.targetX = null;
self.update = function () {
// Store last Y position for edge detection
if (self.lastY === undefined) {
self.lastY = self.y;
}
// Basic downward movement
self.y += self.speed;
// Check if enemy just reached bottom edge of game area
var bottomThreshold = GAME_HEIGHT - 200;
if (self.lastY < bottomThreshold && self.y >= bottomThreshold && !self.firingMode) {
// Enemy reached bottom edge - activate enhanced firing mode
self.firingMode = true;
self.firingModeStartTime = LK.ticks;
// Store original fire rate before enhancement
self.originalFireRate = self.fireRate;
// Increase fire rate and set player as target
self.fireRate = 30; // Much faster fire rate
// Flash red to indicate enhanced firing mode
LK.effects.flashObject(self, 0xff0000, 500);
// Start aiming at player
self.targetPlayer = true;
}
// Handle enhanced firing mode behavior
if (self.firingMode) {
// Check if 5 seconds have passed (300 ticks at 60fps)
if (LK.ticks - self.firingModeStartTime >= 300) {
// Self-destruct after 5 seconds
// Create explosion effect
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
explosions.push(explosion);
// Play explosion sound
LK.getSound('explosion').play();
// Add score for self-destruction
score += self.scoreValue;
LK.setScore(score);
updateScoreDisplay();
// Remove the enemy
self.destroy();
return true; // Signal to remove from enemies array
}
// Aim at player during enhanced firing mode
if (player && self.targetPlayer) {
// Calculate direction to player
var diffX = player.x - self.x;
var diffY = player.y - self.y;
// Move toward player with increased precision
self.x += diffX * 0.02;
// Apply a pulsating movement for visual effect
self.y += Math.sin(LK.ticks * 0.1) * 1.5;
return;
}
}
// Apply regular movement pattern when not in enhanced firing mode
if (self.movementPattern === 1) {
// Zigzag with occasional side movement
self.x += Math.sin(self.movementCounter * 0.05) * 3;
// Occasionally move to a different horizontal position
if (self.movementCounter % 500 === 0) {
// Choose a new target position on the opposite side
self.targetX = self.x < GAME_WIDTH / 2 ? GAME_WIDTH * 0.7 + Math.random() * GAME_WIDTH * 0.2 : GAME_WIDTH * 0.1 + Math.random() * GAME_WIDTH * 0.2;
}
if (self.targetX) {
var diffX = self.targetX - self.x;
if (Math.abs(diffX) > 10) {
self.x += diffX * 0.03;
}
}
self.movementCounter++;
} else if (self.movementPattern === 2) {
// Circular with occasional repositioning
self.x += Math.sin(self.movementCounter * 0.03) * 4;
// Occasionally reset position to avoid grouping
if (self.movementCounter % 700 === 0) {
// Move to random position on screen
self.targetX = Math.random() * GAME_WIDTH * 0.8 + GAME_WIDTH * 0.1;
}
// Move toward target if exists
if (self.targetX) {
var diffX = self.targetX - self.x;
if (Math.abs(diffX) > 10) {
self.x += diffX * 0.02;
}
}
self.movementCounter++;
} else {
// Add movement for straight pattern (pattern 0)
if (self.movementCounter % 900 === 0) {
// Occasional side movement
self.targetX = Math.random() * GAME_WIDTH * 0.8 + GAME_WIDTH * 0.1;
}
// Move toward target if exists
if (self.targetX) {
var diffX = self.targetX - self.x;
if (Math.abs(diffX) > 10) {
self.x += diffX * 0.01;
}
}
self.movementCounter++;
}
// Update lastY for next frame
self.lastY = self.y;
};
// Take damage and check if destroyed
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
return true; // Enemy is destroyed
}
return false;
};
// Use default intersection method
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7; // Moving downward
self.update = function () {
if (self.isAimed && self.speedX !== undefined && self.speedY !== undefined) {
// Move along calculated trajectory for aimed bullets
self.x += self.speedX;
self.y += self.speedY;
} else {
// Default downward movement
self.y += self.speed;
}
};
// Use default intersection method
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
// Explosion duration
self.duration = 30; // frames
self.currentFrame = 0;
// Scale explosion from small to large then fade
explosionGraphics.scale.x = 0.1;
explosionGraphics.scale.y = 0.1;
self.update = function () {
self.currentFrame++;
// Expand and then fade
if (self.currentFrame < 15) {
explosionGraphics.scale.x += 0.1;
explosionGraphics.scale.y += 0.1;
} else {
explosionGraphics.alpha -= 0.08;
}
// Remove when animation complete
if (self.currentFrame >= self.duration) {
self.destroy();
return true;
}
return false;
};
return self;
});
var FirePool = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('firePool', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
// Fire pool duration (4 seconds at 60fps)
self.duration = 240;
self.currentFrame = 0;
// Pulsate effect
self.pulsateDirection = 1;
self.pulsateAmount = 0;
self.update = function () {
self.currentFrame++;
// Pulsate effect
self.pulsateAmount += 0.02 * self.pulsateDirection;
if (self.pulsateAmount > 0.2 || self.pulsateAmount < -0.2) {
self.pulsateDirection *= -1;
}
fireGraphics.scale.x = 1 + self.pulsateAmount;
fireGraphics.scale.y = 1 + self.pulsateAmount;
// Fade out at the end
if (self.currentFrame > 150) {
fireGraphics.alpha -= 0.03;
}
// Check for enemies touching the fire pool
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(self)) {
// Enemy is instantly destroyed by fire
score += enemy.scoreValue;
LK.setScore(score);
updateScoreDisplay();
LK.effects.flashObject(enemy, 0xff0000, 300);
// Play explosion sound when enemy is destroyed by fire pool
LK.getSound('firePoolDestroy').play();
enemy.destroy();
enemies.splice(i, 1);
}
}
// Remove when duration complete
if (self.currentFrame >= self.duration) {
self.destroy();
return true;
}
return false;
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
// Health bar properties
self.maxHealth = 4;
self.currentHealth = 4;
self.width = 140;
self.height = 20;
// Create background bar (gray)
var background = self.attachAsset('healthbar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
// Adjust to match bar width
scaleY: 1,
// Adjust to match bar height
tint: 0x666666 // Gray color
});
// Create foreground bar (health indicator - green)
var foreground = self.attachAsset('healthbar', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1,
// Adjust to match bar width
scaleY: 1,
// Adjust to match bar height
tint: 0x00FF00 // Green color
});
// Center the foreground bar
foreground.x = -background.width / 2;
// Update health bar visual based on current health
self.updateHealth = function (health) {
self.currentHealth = health;
// Update the scale of the foreground bar based on current health
var healthPercentage = Math.max(self.currentHealth / self.maxHealth, 0);
// Scale should decrease as health decreases, not increase
// Ensure that we don't go to 0 until health is actually 0
if (self.currentHealth > 0) {
// For non-zero health, ensure we have at least a small visible portion of health bar
foreground.scale.x = Math.max(healthPercentage, 0.05);
} else {
// Only when health is truly zero, set scale to zero
foreground.scale.x = 0;
}
// Change color based on health level
if (healthPercentage > 0.6) {
foreground.tint = 0x00FF00; // Green
} else if (healthPercentage > 0.3) {
foreground.tint = 0xFFFF00; // Yellow
} else {
foreground.tint = 0xFF0000; // Red
}
};
return self;
});
var Missile = Container.expand(function () {
var self = Container.call(this);
var missileGraphics = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = -10; // Moving upward
self.targetX = null;
self.targetY = null; // Add targetY for better homing
self.turnSpeed = 0.25; // Significantly increased turn speed for better tracking
self.angle = 0; // For side missiles
self.update = function () {
// Basic upward movement
self.y += self.speed;
// Enhanced target tracking if we have a target
if (self.targetX && self.targetY) {
// Calculate distance to target
var diffX = self.targetX - self.x;
var diffY = self.targetY - self.y;
var dist = Math.sqrt(diffX * diffX + diffY * diffY);
// Track frames since launch for initial trajectory control
if (self.initialDirectionFrames === undefined) {
self.initialDirectionFrames = 0;
}
// For the first 20 frames, maintain initial trajectory with very minimal homing
// This ensures missiles start with distinctive paths
if (self.initialDirectionFrames < 20) {
self.initialDirectionFrames++;
// Initial direction based on missile type
if (self.initialDirection === 'left-up') {
// Left missile veers slightly left
self.x -= 2;
self.y += self.speed * 0.2; // Slow vertical movement slightly
} else if (self.initialDirection === 'right-up') {
// Right missile veers slightly right
self.x += 2;
self.y += self.speed * 0.2; // Slow vertical movement slightly
} else {
// Center missile goes straight up
// No horizontal movement, just straight up
}
} else {
// After initial frames, apply enhanced homing behavior
// Use a larger factor for more effective tracking while keeping realistic movement
var homingFactor = self.turnSpeed * 0.3; // Significantly increased factor for better homing
// Move more noticeably toward target x position
self.x += diffX * homingFactor;
// Also add vertical homing for more direct targeting
self.y += diffY * (homingFactor * 0.4); // Add vertical component to homing
// Apply slight angular adjustment to maintain separation
// This ensures missiles maintain some of their initial trajectory
if (self.angle) {
self.x += Math.sin(self.angle) * 0.2; // Further reduced angular influence for better homing
}
}
// Improved y-speed adjustment if target is far above or below
if (diffY < -150) {
// Increased speed adjustment for better vertical tracking
self.y += self.speed * 0.06; // More aggressive speed adjustment
} else if (diffY > 150) {
// Increased adjustment if target is below missile
self.y += self.speed * -0.04; // More noticeable slowdown
}
}
};
// Create explosion when hitting a target or edge
self.explode = function () {
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
// Create fire pool after explosion
var firePool = new FirePool();
firePool.x = self.x;
firePool.y = self.y;
game.addChild(firePool);
firePools.push(firePool);
// Play explosion sound
LK.getSound('explosion').play();
// Damage enemies in area
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If enemy is within explosion radius
if (distance < 150) {
// Enemy is destroyed by area damage
score += enemy.scoreValue;
LK.setScore(score);
updateScoreDisplay();
LK.effects.flashObject(enemy, 0xff0000, 300);
enemy.destroy();
enemies.splice(i, 1);
}
}
return true;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -20; // Moving upward (increased speed)
self.power = 1;
self.direction = 'up'; // up, down, left, right
self.isPiercing = false;
self.isBouncing = false;
self.bounceCount = 0;
self.maxBounces = 3;
// Enemy bullet destruction functionality removed
self.update = function () {
// Move bullet based on direction
if (self.direction === 'up') {
self.y += self.speed;
// Check for bouncing against top edge
if (self.isBouncing && self.y < 0 && self.bounceCount < self.maxBounces) {
self.direction = 'down';
self.bounceCount++;
}
} else if (self.direction === 'down') {
self.y -= self.speed; // Note: speed is negative, so this is adding a positive value
// Check for bouncing against bottom edge
if (self.isBouncing && self.y > GAME_HEIGHT && self.bounceCount < self.maxBounces) {
self.direction = 'up';
self.bounceCount++;
}
} else if (self.direction === 'left') {
self.x += self.speed;
// Check for bouncing against left edge
if (self.isBouncing && self.x < 0 && self.bounceCount < self.maxBounces) {
self.direction = 'right';
self.bounceCount++;
}
} else if (self.direction === 'right') {
self.x -= self.speed; // Note: speed is negative, so this is adding a positive value
// Check for bouncing against right edge
if (self.isBouncing && self.x > GAME_WIDTH && self.bounceCount < self.maxBounces) {
self.direction = 'left';
self.bounceCount++;
}
}
};
// Method to create explosion when player bullet is destroyed
self.explode = function () {
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
// Make player bullet explosion slightly smaller
explosion.scale.x = 0.6;
explosion.scale.y = 0.6;
game.addChild(explosion);
explosions.push(explosion);
// Play explosion sound
LK.getSound('explosion').play();
};
// Use default intersection method
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
// Visual representation
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Use default hitbox
// Health visual (initially invisible)
var shieldGraphics = self.attachAsset('health', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
});
// Final life warning text
var finalLifeText = new Text2('FINAL LIFE', {
size: 50,
fill: 0xFF0000
});
finalLifeText.anchor.set(0.5, 0.5);
finalLifeText.y = -110;
finalLifeText.alpha = 0;
self.addChild(finalLifeText);
// Player properties
self.speed = 10;
self.fireRate = 20; // Ticks between shots
self.lastShot = 0;
self.health = 4; // Player starts with 4 health
self.healthBar = new HealthBar();
self.healthBar.y = -80; // Position above player
self.healthBar.x = 0; // Perfectly center the healthbar with the ship
self.addChild(self.healthBar);
self.shieldActive = false;
self.powerUpActive = false;
self.quadBulletsActive = false;
self.rotationSpeed = 0;
self.finalLifeWarningActive = false;
// Physics properties for smooth movement
self.targetX = null;
self.targetY = null;
self.isMoving = false;
self.moveTween = null;
// Update method for rotation and missile text positioning
self.update = function () {
if (self.quadBulletsActive) {
shipGraphics.rotation += self.rotationSpeed;
}
// Keep missile ready text below the ship
if (missileReadyText && missileReadyText.visible) {
missileReadyText.x = self.x;
missileReadyText.y = self.y + 110;
}
};
// Use default intersection method
// Shield activation
self.activateShield = function () {
self.shieldActive = true;
shieldGraphics.alpha = 0.5;
// Play shield activation sound effect
LK.getSound('shieldActivation').play();
// Shield times out after 5 seconds
LK.setTimeout(function () {
self.shieldActive = false;
shieldGraphics.alpha = 0;
}, 5000);
};
// Power-up activation
self.activatePowerUp = function () {
self.powerUpActive = true;
shipGraphics.tint = 0xf1c40f; // Yellow tint for power-up
self.fireRate = 10; // Faster firing
// Power-up times out after 7 seconds
LK.setTimeout(function () {
self.powerUpActive = false;
shipGraphics.tint = 0xFFFFFF;
self.fireRate = 20;
}, 7000);
};
// Quad bullets activation
self.activateQuadBullets = function () {
self.quadBulletsActive = true;
shipGraphics.tint = 0xe74c3c; // Red tint for quad bullets
self.fireRate = 15; // Medium firing speed
self.rotationSpeed = 0.05; // Start spinning
// Quad bullets time out after 8 seconds
LK.setTimeout(function () {
self.quadBulletsActive = false;
shipGraphics.tint = 0xFFFFFF;
self.fireRate = 20;
self.rotationSpeed = 0;
shipGraphics.rotation = 0; // Reset rotation
}, 8000);
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 3;
// Add quad bullet type with 1/3 chance
var rand = Math.random();
if (rand < 0.33) {
self.type = 'health';
} else if (rand < 0.66) {
self.type = 'weapon';
} else {
self.type = 'quadBullets';
}
// Set color based on type
if (self.type === 'health') {
powerUpGraphics.tint = 0x2ecc71; // Green for health
} else if (self.type === 'weapon') {
powerUpGraphics.tint = 0xf1c40f; // Yellow for weapon
} else {
powerUpGraphics.tint = 0xe74c3c; // Red for quad bullets
}
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SPAWN_ENEMY_INTERVAL = 60; // Spawn enemy every 60 ticks initially
var SPAWN_POWERUP_INTERVAL = 600; // Spawn power-up every 600 ticks
var MIN_SPAWN_INTERVAL = 20; // Minimum spawn rate as difficulty increases
// Game state variables
var player;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var powerUps = [];
var missiles = [];
var explosions = [];
var firePools = [];
var gameLevel = 1;
var spawnCounter = 0;
var powerUpCounter = 0;
var isGameActive = true;
var score = 0;
var lastMissileTime = 0;
var missileReadyText = new Text2('MISSILE READY', {
size: 40,
fill: 0xFF0000
});
// Initialize score display
var scoreTxt = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 30;
// Initialize level display
var levelTxt = new Text2('LEVEL: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 100;
// Create player ship
function initializeGame() {
player = new PlayerShip();
player.x = GAME_WIDTH / 2;
player.y = GAME_HEIGHT - 200;
game.addChild(player);
// Reset arrays
playerBullets = [];
enemies = [];
enemyBullets = [];
powerUps = [];
missiles = [];
explosions = [];
firePools = [];
// Reset game state
gameLevel = 1;
spawnCounter = 0;
powerUpCounter = 0;
isGameActive = true;
lastMissileTime = 0;
// Initialize missile ready text
missileReadyText.anchor.set(0.5, 0.5);
missileReadyText.alpha = 1;
missileReadyText.visible = true;
// Set initial missile time to be ready at game start
lastMissileTime = LK.ticks - 600;
// Position text below the player ship
game.addChild(missileReadyText);
// Flash the text immediately
var _flashMissileText = function flashMissileText() {
tween(missileReadyText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
tween(missileReadyText, {
alpha: 1
}, {
duration: 500,
onFinish: _flashMissileText
});
}
});
};
_flashMissileText();
// Reset score and update display
LK.setScore(0);
score = 0;
updateScoreDisplay();
updateLevelDisplay();
// Play background music when game starts
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
}
// Initialize the game
initializeGame();
// Update score display
function updateScoreDisplay() {
scoreTxt.setText('SCORE: ' + score);
}
// Update level display
function updateLevelDisplay() {
levelTxt.setText('LEVEL: ' + gameLevel);
}
// Player shooting
function playerShoot() {
// Check fire rate cooldown
if (LK.ticks - player.lastShot < player.fireRate) {
return;
}
// Always fire dual cannons (left and right)
var bulletLeft = new PlayerBullet();
bulletLeft.x = player.x - 20;
bulletLeft.y = player.y - 40;
bulletLeft.direction = 'up';
game.addChild(bulletLeft);
playerBullets.push(bulletLeft);
var bulletRight = new PlayerBullet();
bulletRight.x = player.x + 20;
bulletRight.y = player.y - 40;
bulletRight.direction = 'up';
game.addChild(bulletRight);
playerBullets.push(bulletRight);
// Triple bullets if weapon power-up is active
if (player.powerUpActive) {
var bulletCenter = new PlayerBullet();
bulletCenter.x = player.x;
bulletCenter.y = player.y - 50;
bulletCenter.direction = 'up';
game.addChild(bulletCenter);
playerBullets.push(bulletCenter);
}
// Quad-directional bullets if quad bullets power-up is active
if (player.quadBulletsActive) {
// Up bullet already covered
// Down bullet
var bulletDown = new PlayerBullet();
bulletDown.x = player.x;
bulletDown.y = player.y + 40;
bulletDown.direction = 'down';
bulletDown.isPiercing = true;
bulletDown.isBouncing = true;
game.addChild(bulletDown);
playerBullets.push(bulletDown);
// Left bullet
var bulletLeft = new PlayerBullet();
bulletLeft.x = player.x - 40;
bulletLeft.y = player.y;
bulletLeft.direction = 'left';
bulletLeft.isPiercing = true;
bulletLeft.isBouncing = true;
game.addChild(bulletLeft);
playerBullets.push(bulletLeft);
// Right bullet
var bulletRight = new PlayerBullet();
bulletRight.x = player.x + 40;
bulletRight.y = player.y;
bulletRight.direction = 'right';
bulletRight.isPiercing = true;
bulletRight.isBouncing = true;
game.addChild(bulletRight);
playerBullets.push(bulletRight);
}
// Play sound and reset shot timer
LK.getSound('playerShoot').play();
player.lastShot = LK.ticks;
}
// Enemy shooting
function enemyShoot(enemy) {
if (LK.ticks - enemy.lastShot < enemy.fireRate) {
return;
}
var bullet = new EnemyBullet();
bullet.x = enemy.x;
bullet.y = enemy.y + 40;
// Check if enemy is in enhanced firing mode
if (enemy.firingMode) {
// Enhanced bullets are faster and aim at player
bullet.speed = 12; // Increased speed
// Calculate direction to player for aiming
if (player) {
// Get angle to player
var dx = player.x - enemy.x;
var dy = player.y - enemy.y;
var angle = Math.atan2(dy, dx);
// Set bullet velocity components based on angle
bullet.speedX = Math.cos(angle) * bullet.speed;
bullet.speedY = Math.sin(angle) * bullet.speed;
bullet.isAimed = true;
}
// Visual indicator for enhanced bullets
var bulletGraphics = bullet.getChildAt(0);
bulletGraphics.tint = 0xff0000; // Red tint for enhanced bullets
}
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
enemy.lastShot = LK.ticks;
}
// Spawn new enemy
function spawnEnemy() {
var enemy = new Enemy();
// Distribute enemies better across the screen width
// Check if we have other enemies and avoid spawning too close to them
if (enemies.length > 0) {
// Find a position away from other enemies
var attempts = 0;
var potentialX;
var validPosition = false;
while (!validPosition && attempts < 10) {
potentialX = Math.random() * (GAME_WIDTH - 100) + 50;
validPosition = true;
// Check distance from existing enemies
for (var i = 0; i < enemies.length; i++) {
if (Math.abs(enemies[i].x - potentialX) < 150) {
validPosition = false;
break;
}
}
attempts++;
}
enemy.x = validPosition ? potentialX : Math.random() * (GAME_WIDTH - 100) + 50;
} else {
enemy.x = Math.random() * (GAME_WIDTH - 100) + 50;
}
enemy.y = -50;
// Increase difficulty with levels
if (gameLevel > 1) {
enemy.speed = Math.min(2 + gameLevel * 0.5, 6);
enemy.health = Math.min(1 + Math.floor(gameLevel / 3), 3);
}
if (gameLevel > 5) {
enemy.fireRate = Math.max(120 - gameLevel * 5, 60);
}
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn power-up
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = Math.random() * (GAME_WIDTH - 100) + 50;
powerUp.y = -50;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Check level progress
function checkLevelProgress() {
// Advance level based on score
var shouldAdvanceLevel = Math.floor(score / 1000) + 1;
if (shouldAdvanceLevel > gameLevel) {
gameLevel = shouldAdvanceLevel;
updateLevelDisplay();
// Flash screen to indicate level up
LK.effects.flashScreen(0x3498db, 500);
// Play level up sound
LK.getSound('levelUp').play();
}
}
// Handle collisions
function handleCollisions() {
// Check player bullets hitting enemies
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
var bulletHit = false;
// Enemy bullet destruction completely removed
// Skip all bullet collision detection logic
// If player bullet was destroyed by enemy bullets, skip enemy collision check
if (bulletHit) {
continue;
}
// Now check for player bullet hitting enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Enemy takes damage
if (enemy.takeDamage(bullet.power)) {
// Enemy destroyed
score += enemy.scoreValue;
LK.setScore(score);
updateScoreDisplay();
LK.getSound('explosion').play();
LK.effects.flashObject(enemy, 0xff0000, 300);
// Create explosion animation at enemy position
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
explosions.push(explosion);
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
}
// Only remove non-piercing bullets on hit
if (!bullet.isPiercing) {
bullet.explode(); // Add explosion effect when bullet is destroyed
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
break;
}
}
}
// If a non-piercing bullet hit something, skip to the next bullet
if (bulletHit) {
continue;
}
}
// Check enemy bullets hitting player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Get center points of both objects for more precise collision detection
var bulletCenterX = bullet.x;
var bulletCenterY = bullet.y;
var playerCenterX = player.x;
var playerCenterY = player.y;
// Calculate distance between centers
var dx = bulletCenterX - playerCenterX;
var dy = bulletCenterY - playerCenterY;
var distance = Math.sqrt(dx * dx + dy * dy);
// Get the combined radius (half the width of both objects for a more precise collision)
var bulletRadius = bullet.width / 3.5; // Much smaller hitbox for accurate collision
var playerRadius = player.width / 3.5; // Much smaller hitbox for accurate collision
var combinedRadius = bulletRadius + playerRadius;
// Only register hit if the bullet is actually touching the player (more precise collision)
if (distance < combinedRadius) {
// Player hit
bullet.destroy();
enemyBullets.splice(i, 1);
if (player.shieldActive) {
// Shield absorbs the hit
// Play explosion sound for shield hit
LK.getSound('explosion').play();
player.shieldActive = false;
var shield = player.getChildAt(1);
shield.alpha = 0;
} else {
// Play sound when player gets hit by enemy bullet
LK.getSound('playerHit').play();
// Reduce player health
player.health--;
player.healthBar.updateHealth(player.health);
// Flash player to indicate damage
LK.effects.flashObject(player, 0xff0000, 300);
// Check if player health reaches 1 (final life)
if (player.health === 1 && !player.finalLifeWarningActive) {
player.finalLifeWarningActive = true;
// Hide health bar completely
player.healthBar.visible = false;
// Show and animate "Final Life" text
var finalLifeText = player.getChildAt(2); // Get the final life text
finalLifeText.alpha = 1;
// Create flashing effect for the text
var _flashTween2 = function flashTween() {
tween(finalLifeText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
tween(finalLifeText, {
alpha: 1
}, {
duration: 500,
onFinish: _flashTween2
});
}
});
};
_flashTween2(); // Start the flashing animation
}
// Check if player is out of health
if (player.health <= 0) {
// Game over
LK.effects.flashScreen(0xff0000, 1000);
isGameActive = false;
// Stop music with fade out
LK.playMusic('gameMusic', {
fade: {
start: 1,
end: 0,
duration: 800
}
});
// Play game over sound effect
LK.getSound('gameOver').play();
LK.showGameOver();
break;
}
}
}
}
// Check enemies colliding with player
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(player)) {
if (player.shieldActive) {
// Shield absorbs the hit
// Play collision sound when enemy collides with shield
LK.getSound('shieldCollision').play();
enemy.destroy();
enemies.splice(i, 1);
// Shield gets depleted
player.shieldActive = false;
var shield = player.getChildAt(1);
shield.alpha = 0;
score += enemy.scoreValue;
LK.setScore(score);
updateScoreDisplay();
} else {
// Reduce player health by 2 (collision is more dangerous)
player.health -= 2;
player.healthBar.updateHealth(player.health);
// Play collision sound when player collides with enemy
LK.getSound('playerCollision').play();
// Remove the enemy
enemy.destroy();
enemies.splice(i, 1);
// Flash player to indicate damage
LK.effects.flashObject(player, 0xff0000, 300);
// Check if player health reaches 1 (final life)
if (player.health === 1 && !player.finalLifeWarningActive) {
player.finalLifeWarningActive = true;
// Hide health bar completely
player.healthBar.visible = false;
// Show and animate "Final Life" text
var finalLifeText = player.getChildAt(2); // Get the final life text
finalLifeText.alpha = 1;
// Create flashing effect for the text
var _flashTween2 = function _flashTween() {
tween(finalLifeText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
tween(finalLifeText, {
alpha: 1
}, {
duration: 500,
onFinish: _flashTween2
});
}
});
};
_flashTween2(); // Start the flashing animation
}
// Check if player is out of health
if (player.health <= 0) {
// Game over
LK.effects.flashScreen(0xff0000, 1000);
isGameActive = false;
LK.showGameOver();
break;
}
}
}
}
// Check player collecting power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
// Apply power-up effect
if (powerUp.type === 'health') {
// Health regeneration logic
if (player.health < player.healthBar.maxHealth) {
// Add 1 health point
player.health = Math.min(player.health + 1, player.healthBar.maxHealth);
// If player was at final life, restore health bar and remove warning
if (player.finalLifeWarningActive && player.health > 1) {
player.finalLifeWarningActive = false;
player.healthBar.visible = true;
// Get the final life text and hide it
var finalLifeText = player.getChildAt(2);
// Stop any existing tweens on the final life text
tween.stop(finalLifeText);
finalLifeText.alpha = 0;
}
// Update health bar
player.healthBar.updateHealth(player.health);
}
} else if (powerUp.type === 'weapon') {
player.activatePowerUp();
} else if (powerUp.type === 'quadBullets') {
player.activateQuadBullets();
}
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Clean up off-screen objects
function cleanupOffscreenObjects() {
// Clean up missiles that went off screen
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
if (missile.y < -50 || missile.y > GAME_HEIGHT + 50 || missile.x < -50 || missile.x > GAME_WIDTH + 50) {
missile.explode();
missile.destroy();
missiles.splice(i, 1);
}
}
// Clean up bullets that went off screen
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Check if bullet is off screen based on direction (unless it's bouncing)
if (!bullet.isBouncing) {
if (bullet.direction === 'up' && bullet.y < -50 || bullet.direction === 'down' && bullet.y > GAME_HEIGHT + 50 || bullet.direction === 'left' && bullet.x < -50 || bullet.direction === 'right' && bullet.x > GAME_WIDTH + 50) {
bullet.destroy();
playerBullets.splice(i, 1);
}
} else if (bullet.bounceCount >= bullet.maxBounces) {
// Add explosion for bouncing bullets that reached max bounce count
bullet.explode();
// Play explosion sound when bullet is removed at max bounce count
LK.getSound('bulletExplosion').play();
bullet.destroy();
playerBullets.splice(i, 1);
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
if (enemyBullets[i].y > GAME_HEIGHT + 50) {
enemyBullets[i].destroy();
enemyBullets.splice(i, 1);
}
}
// Clean up enemies that went off screen
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i].y > GAME_HEIGHT + 100) {
enemies[i].destroy();
enemies.splice(i, 1);
}
}
// Clean up power-ups that went off screen
for (var i = powerUps.length - 1; i >= 0; i--) {
if (powerUps[i].y > GAME_HEIGHT + 50) {
powerUps[i].destroy();
powerUps.splice(i, 1);
}
}
}
// Player movement
var isDragging = false;
game.down = function (x, y) {
// Fire missile on left click if cooldown is ready
if (LK.ticks - lastMissileTime >= 600) {
// 10 seconds at 60fps
// Find closest enemy as target first
var closestEnemy = null;
var closestDistance = Number.MAX_VALUE;
var potentialTargets = [];
// Find up to 6 potential targets
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestEnemy = enemy;
}
// Add to potential targets list (sort by proximity later)
potentialTargets.push({
enemy: enemy,
distance: distance
});
}
// Sort targets by distance
potentialTargets.sort(function (a, b) {
return a.distance - b.distance;
});
// Launch three missiles from the same vertical position but different horizontal positions
// Center missile - positioned exactly in the center of player ship
var centerMissile = new Missile();
centerMissile.x = player.x; // Center horizontally with player
centerMissile.y = player.y - 60; // Launch from front center of player ship
centerMissile.turnSpeed = 0.05; // Very slight homing for center missile
centerMissile.initialDirection = 'up'; // Make sure it exits straight up first
// Left missile - positioned to the left of center missile
var leftMissile = new Missile();
leftMissile.x = player.x - 30; // Position left of the player
leftMissile.y = player.y - 60; // Same vertical position as center missile
leftMissile.angle = -0.3; // Slight left angle for initial trajectory
leftMissile.turnSpeed = 0.07; // Reduced homing for more separation
leftMissile.initialDirection = 'left-up'; // Make sure it exits left-up first
// Right missile - positioned to the right of center missile
var rightMissile = new Missile();
rightMissile.x = player.x + 30; // Position right of the player
rightMissile.y = player.y - 60; // Same vertical position as center missile
rightMissile.angle = 0.3; // Slight right angle for initial trajectory
rightMissile.turnSpeed = 0.07; // Reduced homing for more separation
rightMissile.initialDirection = 'right-up'; // Make sure it exits right-up first
// If we found a target, set it for missiles with different offsets to avoid pairing
if (closestEnemy) {
// Set slightly different targets for each missile to avoid pairing
centerMissile.targetX = closestEnemy.x;
centerMissile.targetY = closestEnemy.y;
// For side missiles, either use different enemies or offset from main target
if (potentialTargets.length > 1) {
leftMissile.targetX = potentialTargets[Math.min(1, potentialTargets.length - 1)].enemy.x - 50;
leftMissile.targetY = potentialTargets[Math.min(1, potentialTargets.length - 1)].enemy.y;
} else {
// If not enough targets, offset significantly from main target
leftMissile.targetX = closestEnemy.x - 150;
leftMissile.targetY = closestEnemy.y;
}
if (potentialTargets.length > 2) {
rightMissile.targetX = potentialTargets[Math.min(2, potentialTargets.length - 1)].enemy.x + 50;
rightMissile.targetY = potentialTargets[Math.min(2, potentialTargets.length - 1)].enemy.y;
} else {
// If not enough targets, offset significantly from main target
rightMissile.targetX = closestEnemy.x + 150;
rightMissile.targetY = closestEnemy.y;
}
}
// Add first wave of missiles to game
game.addChild(centerMissile);
missiles.push(centerMissile);
game.addChild(leftMissile);
missiles.push(leftMissile);
game.addChild(rightMissile);
missiles.push(rightMissile);
// Create a second wave of missiles with slightly different launch positions
// Second center missile
var centerMissile2 = new Missile();
centerMissile2.x = player.x;
centerMissile2.y = player.y - 30; // Slightly higher than first wave
centerMissile2.turnSpeed = 0.06;
centerMissile2.initialDirection = 'up';
// Second left missile
var leftMissile2 = new Missile();
leftMissile2.x = player.x - 40; // Different horizontal offset
leftMissile2.y = player.y - 30;
leftMissile2.angle = -0.4; // Different initial angle
leftMissile2.turnSpeed = 0.08;
leftMissile2.initialDirection = 'left-up';
// Second right missile
var rightMissile2 = new Missile();
rightMissile2.x = player.x + 40; // Different horizontal offset
rightMissile2.y = player.y - 30;
rightMissile2.angle = 0.4; // Different initial angle
rightMissile2.turnSpeed = 0.08;
rightMissile2.initialDirection = 'right-up';
// Set targets for second wave
if (closestEnemy) {
// Set slightly different targets for second wave missiles
if (potentialTargets.length > 3) {
centerMissile2.targetX = potentialTargets[3].enemy.x;
centerMissile2.targetY = potentialTargets[3].enemy.y;
} else {
centerMissile2.targetX = closestEnemy.x + 50;
centerMissile2.targetY = closestEnemy.y + 50;
}
if (potentialTargets.length > 4) {
leftMissile2.targetX = potentialTargets[4].enemy.x - 70;
leftMissile2.targetY = potentialTargets[4].enemy.y;
} else {
leftMissile2.targetX = closestEnemy.x - 200;
leftMissile2.targetY = closestEnemy.y + 50;
}
if (potentialTargets.length > 5) {
rightMissile2.targetX = potentialTargets[5].enemy.x + 70;
rightMissile2.targetY = potentialTargets[5].enemy.y;
} else {
rightMissile2.targetX = closestEnemy.x + 200;
rightMissile2.targetY = closestEnemy.y + 50;
}
}
// Add second wave of missiles to game
game.addChild(centerMissile2);
missiles.push(centerMissile2);
game.addChild(leftMissile2);
missiles.push(leftMissile2);
game.addChild(rightMissile2);
missiles.push(rightMissile2);
// Play missile launch sound
LK.getSound('missileLaunch').play();
// Reset cooldown
lastMissileTime = LK.ticks;
// Hide missile ready text and stop any active tweens
tween.stop(missileReadyText);
missileReadyText.visible = false;
} //[8F]
// Handle regular player movement
var targetX = x;
var targetY = y;
// Clamp target position to game bounds
if (targetX < 50) {
targetX = 50;
}
if (targetX > GAME_WIDTH - 50) {
targetX = GAME_WIDTH - 50;
}
if (targetY < 50) {
targetY = 50;
}
if (targetY > GAME_HEIGHT - 50) {
targetY = GAME_HEIGHT - 50;
}
player.targetX = targetX;
player.targetY = targetY;
player.isMoving = true;
// Also shoot when player taps
playerShoot();
};
game.move = function (x, y) {
if (isGameActive) {
// Clamp target position to game bounds
var targetX = x;
var targetY = y;
if (targetX < 50) {
targetX = 50;
}
if (targetX > GAME_WIDTH - 50) {
targetX = GAME_WIDTH - 50;
}
if (targetY < 50) {
targetY = 50;
}
if (targetY > GAME_HEIGHT - 50) {
targetY = GAME_HEIGHT - 50;
}
// Update target position
player.targetX = targetX;
player.targetY = targetY;
// For better tracking during fast mouse movements, directly update position
player.x = player.targetX;
player.y = player.targetY;
player.isMoving = true; //{2K}{2L}{2M}{2N}
}
};
game.up = function () {
// Keep the ship moving toward last target point
};
// Main game update loop
game.update = function () {
if (!isGameActive) {
return;
}
// Update missile ready text
if (LK.ticks - lastMissileTime >= 600) {
// 10 seconds cooldown
if (!missileReadyText.visible) {
missileReadyText.visible = true;
missileReadyText.x = player.x;
missileReadyText.y = player.y + 110;
missileReadyText.alpha = 1;
// Flash the text when ready
var _flashMissileText2 = function flashMissileText() {
tween(missileReadyText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
tween(missileReadyText, {
alpha: 1
}, {
duration: 500,
onFinish: _flashMissileText2
});
}
});
};
_flashMissileText2();
}
}
// Spawn enemies
spawnCounter++;
var currentSpawnRate = Math.max(SPAWN_ENEMY_INTERVAL - gameLevel * 5, MIN_SPAWN_INTERVAL);
if (spawnCounter >= currentSpawnRate) {
spawnEnemy();
spawnCounter = 0;
}
// Spawn power-ups
powerUpCounter++;
if (powerUpCounter >= SPAWN_POWERUP_INTERVAL) {
spawnPowerUp();
powerUpCounter = 0;
}
// Make player shoot automatically
if (player.isMoving) {
playerShoot();
}
// Update enemies and their shooting
for (var i = enemies.length - 1; i >= 0; i--) {
// Check if the enemy should be removed (returned true from update)
if (enemies[i].update && enemies[i].update() === true) {
enemies.splice(i, 1);
continue;
}
enemyShoot(enemies[i]);
}
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
var missile = missiles[i];
// If missile doesn't have a target or target is destroyed, find new target
if ((missile.targetX === null || missile.targetY === null) && enemies.length > 0) {
// Find closest enemy as new target
var closestEnemy = null;
var closestDistance = Number.MAX_VALUE;
// Check all enemies for potential targets
for (var k = 0; k < enemies.length; k++) {
var dx = enemies[k].x - missile.x;
var dy = enemies[k].y - missile.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestEnemy = enemies[k];
}
}
// If we found a target, set it with slight offset based on missile type
if (closestEnemy) {
// Add slightly different offsets to each missile's target to maintain separation
// We can determine missile "type" by its position relative to player
var offsetX = 0;
var offsetY = 0; // Adding vertical offset for better separation
// Using angle to identify missile type
if (missile.angle < 0) {
// Left missile
offsetX = -100; // Increased horizontal offset
offsetY = -20; // Slight vertical offset
} else if (missile.angle > 0) {
// Right missile
offsetX = 100; // Increased horizontal offset
offsetY = -20; // Slight vertical offset
} else {
// Center missile
offsetY = -50; // Different vertical offset for center missile
}
missile.targetX = closestEnemy.x + offsetX;
missile.targetY = closestEnemy.y + offsetY;
}
}
// Check if missile hits an enemy
var missileHit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
if (missile.intersects(enemies[j])) {
missile.explode();
missile.destroy();
missiles.splice(i, 1);
missileHit = true;
break;
}
}
// Check if missile is off screen
if (!missileHit && (missile.y < -50 || missile.y > GAME_HEIGHT + 50 || missile.x < -50 || missile.x > GAME_WIDTH + 50)) {
missile.explode();
missile.destroy();
missiles.splice(i, 1);
}
}
// Update explosions
for (var i = explosions.length - 1; i >= 0; i--) {
if (explosions[i].update()) {
explosions.splice(i, 1);
}
}
// Update fire pools
for (var i = firePools.length - 1; i >= 0; i--) {
if (firePools[i].update()) {
firePools.splice(i, 1);
}
}
// Check collisions
handleCollisions();
// Clean up off-screen objects
cleanupOffscreenObjects();
// Check level progression
checkLevelProgress();
// Win condition check
if (score >= 10000) {
// Play win sound effect
LK.getSound('winSound').play();
// Stop music with fade out
LK.playMusic('gameMusic', {
fade: {
start: 1,
end: 0,
duration: 800
}
});
LK.showYouWin();
isGameActive = false;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -20,14 +20,69 @@
self.fireRate = 120; // Ticks between shots
self.lastShot = Math.floor(Math.random() * 60); // Randomize initial shot timer
self.movementPattern = Math.floor(Math.random() * 3); // 0: straight, 1: zigzag, 2: circular
self.movementCounter = 0;
+ self.lastY = 0; // Track last Y position to detect reaching bottom
+ self.firingMode = false; // Track if enemy is in enhanced firing mode
+ self.firingModeStartTime = 0; // When enhanced firing mode started
// Initial target position (will be set during movement)
self.targetX = null;
self.update = function () {
+ // Store last Y position for edge detection
+ if (self.lastY === undefined) {
+ self.lastY = self.y;
+ }
// Basic downward movement
self.y += self.speed;
- // Apply movement pattern
+ // Check if enemy just reached bottom edge of game area
+ var bottomThreshold = GAME_HEIGHT - 200;
+ if (self.lastY < bottomThreshold && self.y >= bottomThreshold && !self.firingMode) {
+ // Enemy reached bottom edge - activate enhanced firing mode
+ self.firingMode = true;
+ self.firingModeStartTime = LK.ticks;
+ // Store original fire rate before enhancement
+ self.originalFireRate = self.fireRate;
+ // Increase fire rate and set player as target
+ self.fireRate = 30; // Much faster fire rate
+ // Flash red to indicate enhanced firing mode
+ LK.effects.flashObject(self, 0xff0000, 500);
+ // Start aiming at player
+ self.targetPlayer = true;
+ }
+ // Handle enhanced firing mode behavior
+ if (self.firingMode) {
+ // Check if 5 seconds have passed (300 ticks at 60fps)
+ if (LK.ticks - self.firingModeStartTime >= 300) {
+ // Self-destruct after 5 seconds
+ // Create explosion effect
+ var explosion = new Explosion();
+ explosion.x = self.x;
+ explosion.y = self.y;
+ game.addChild(explosion);
+ explosions.push(explosion);
+ // Play explosion sound
+ LK.getSound('explosion').play();
+ // Add score for self-destruction
+ score += self.scoreValue;
+ LK.setScore(score);
+ updateScoreDisplay();
+ // Remove the enemy
+ self.destroy();
+ return true; // Signal to remove from enemies array
+ }
+ // Aim at player during enhanced firing mode
+ if (player && self.targetPlayer) {
+ // Calculate direction to player
+ var diffX = player.x - self.x;
+ var diffY = player.y - self.y;
+ // Move toward player with increased precision
+ self.x += diffX * 0.02;
+ // Apply a pulsating movement for visual effect
+ self.y += Math.sin(LK.ticks * 0.1) * 1.5;
+ return;
+ }
+ }
+ // Apply regular movement pattern when not in enhanced firing mode
if (self.movementPattern === 1) {
// Zigzag with occasional side movement
self.x += Math.sin(self.movementCounter * 0.05) * 3;
// Occasionally move to a different horizontal position
@@ -72,8 +127,10 @@
}
}
self.movementCounter++;
}
+ // Update lastY for next frame
+ self.lastY = self.y;
};
// Take damage and check if destroyed
self.takeDamage = function (amount) {
self.health -= amount;
@@ -92,9 +149,16 @@
anchorY: 0.5
});
self.speed = 7; // Moving downward
self.update = function () {
- self.y += self.speed;
+ if (self.isAimed && self.speedX !== undefined && self.speedY !== undefined) {
+ // Move along calculated trajectory for aimed bullets
+ self.x += self.speedX;
+ self.y += self.speedY;
+ } else {
+ // Default downward movement
+ self.y += self.speed;
+ }
};
// Use default intersection method
return self;
});
@@ -718,8 +782,27 @@
}
var bullet = new EnemyBullet();
bullet.x = enemy.x;
bullet.y = enemy.y + 40;
+ // Check if enemy is in enhanced firing mode
+ if (enemy.firingMode) {
+ // Enhanced bullets are faster and aim at player
+ bullet.speed = 12; // Increased speed
+ // Calculate direction to player for aiming
+ if (player) {
+ // Get angle to player
+ var dx = player.x - enemy.x;
+ var dy = player.y - enemy.y;
+ var angle = Math.atan2(dy, dx);
+ // Set bullet velocity components based on angle
+ bullet.speedX = Math.cos(angle) * bullet.speed;
+ bullet.speedY = Math.sin(angle) * bullet.speed;
+ bullet.isAimed = true;
+ }
+ // Visual indicator for enhanced bullets
+ var bulletGraphics = bullet.getChildAt(0);
+ bulletGraphics.tint = 0xff0000; // Red tint for enhanced bullets
+ }
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
enemy.lastShot = LK.ticks;
@@ -1306,10 +1389,15 @@
// Make player shoot automatically
if (player.isMoving) {
playerShoot();
}
- // Update enemy shooting
- for (var i = 0; i < enemies.length; i++) {
+ // Update enemies and their shooting
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ // Check if the enemy should be removed (returned true from update)
+ if (enemies[i].update && enemies[i].update() === true) {
+ enemies.splice(i, 1);
+ continue;
+ }
enemyShoot(enemies[i]);
}
// Update missiles
for (var i = missiles.length - 1; i >= 0; i--) {
An enemy spaceship in a topdown shooter. In-Game asset. 2d. High contrast. No shadows
A player's spaceship in a topdown shooter (mainly blue in colour). In-Game asset. 2d. High contrast. No shadows
A powerup in a top-down shooter (icon of powerup no text). In-Game asset. 2d. High contrast. No shadows
Health Powerup in 2d space shooter (top down). In-Game asset. 2d. High contrast. No shadows
An explosion which contains debris of a spaceship. In-Game asset. 2d. High contrast. No shadows
pool of fire with top down view. In-Game asset. 2d. High contrast. No shadows
Make a small circle that looks like a laser (red colour). In-Game asset. 2d. High contrast. No shadows
Make a very small circle that looks like a laser (blue colour). In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
A missile. In-Game asset. 2d. High contrast. No shadows