/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossShip = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('bossShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.moveDirection = 1;
self.shootTimer = 0;
self.maxHealth = 50;
self.health = self.maxHealth;
self.shootPattern = 0;
self.patternTimer = 0;
// Create boss health bar background
var healthBarBg = self.attachAsset('bossHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -140;
// Create boss health bar fill
var healthBarFill = self.attachAsset('bossHealthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -140;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0xff0000; // Red
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xff6600; // Orange
} else {
self.healthBarFill.tint = 0xffff00; // Yellow
}
};
self.update = function () {
self.y += self.speed;
// Move side to side
self.x += self.moveDirection * 2;
if (self.x <= 100 || self.x >= 1948) {
self.moveDirection *= -1;
}
// Handle shooting patterns
self.shootTimer--;
self.patternTimer++;
if (self.patternTimer % 300 === 0) {
self.shootPattern = (self.shootPattern + 1) % 3;
}
if (self.shootTimer <= 0) {
self.shootTimer = 30;
// Only shoot if not about to hit edges
if (self.x > 150 && self.x < 1898) {
self.shouldShoot = true;
}
}
};
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 = 8;
// Play shoot sound when enemy bullet is created
LK.getSound('shoot').play();
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.movePattern = Math.random() < 0.5 ? 'straight' : 'zigzag';
self.zigzagTimer = 0;
self.zigzagDirection = Math.random() < 0.5 ? -1 : 1;
self.shootTimer = Math.random() * 60 + 60; // Random initial shoot delay
self.maxHealth = 3;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -50;
// Create health bar fill
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -50;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xffff00; // Yellow
} else {
self.healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
self.y += self.speed;
if (self.movePattern === 'zigzag') {
self.zigzagTimer += 1;
if (self.zigzagTimer % 60 === 0) {
self.zigzagDirection *= -1;
}
self.x += self.zigzagDirection * 2;
}
// Keep enemy within screen bounds
if (self.x < 50) self.x = 50;
if (self.x > 1998) self.x = 1998;
// Handle shooting
self.shootTimer--;
if (self.shootTimer <= 0) {
self.shootTimer = Math.random() * 120 + 90; // Slower random shoot interval
self.shouldShoot = true;
}
};
return self;
});
var GunPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('gunPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var healthPackGraphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
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 = -12;
self.angle = 0; // Angle in radians for bullet direction
// Play shoot sound when bullet is created
LK.getSound('shoot').play();
self.update = function () {
self.y += self.speed * Math.cos(self.angle);
self.x += self.speed * Math.sin(self.angle);
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 10;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('playerHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -80;
// Create health bar fill
var healthBarFill = self.attachAsset('playerHealthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -80;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xffff00; // Yellow
} else {
self.healthBarFill.tint = 0xff0000; // Red
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game variables
var playerShip;
var playerBullets = [];
var enemyBullets = [];
var enemyShips = [];
var bossShips = [];
var difficultyLevel = 1;
var enemySpawnRate = 120; // frames between spawns
var bulletFireRate = 15; // frames between shots
var dragNode = null;
var lastBossScore = 0;
var gunPowerUps = [];
var gunPowerUpTimer = 0;
var healthPacks = [];
var healthPackTimer = 0;
var playerFireRate = bulletFireRate; // Track player's current fire rate
var hasTripleShot = false; // Track if player has triple shot upgrade
var gunPowerUpEndTime = 0; // Track when gun power-up should end
var isBossPresent = false; // Track if boss is currently on screen
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize player ship
playerShip = game.addChild(new PlayerShip());
playerShip.x = 1024; // Center horizontally
playerShip.y = 2400; // Near bottom of screen
// Update score display
function updateScore() {
scoreTxt.setText('Score: ' + LK.getScore());
}
// Handle movement
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep player within screen bounds
if (dragNode.x < 40) dragNode.x = 40;
if (dragNode.x > 2008) dragNode.x = 2008;
if (dragNode.y < 200) dragNode.y = 200;
if (dragNode.y > 2600) dragNode.y = 2600;
}
}
// Event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = playerShip;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update loop
game.update = function () {
// Fire player bullets
if (LK.ticks % playerFireRate === 0) {
if (hasTripleShot) {
// Fire three bullets in different directions
var angles = [-0.3, 0, 0.3]; // Left, center, right angles in radians
for (var bulletIndex = 0; bulletIndex < 3; bulletIndex++) {
var newBullet = new PlayerBullet();
newBullet.x = playerShip.x;
newBullet.y = playerShip.y - 60;
newBullet.angle = angles[bulletIndex];
newBullet.lastY = newBullet.y;
playerBullets.push(newBullet);
game.addChild(newBullet);
}
} else {
// Fire single bullet
var newBullet = new PlayerBullet();
newBullet.x = playerShip.x;
newBullet.y = playerShip.y - 60;
newBullet.lastY = newBullet.y;
playerBullets.push(newBullet);
game.addChild(newBullet);
}
}
// Spawn gun power-up every 13 seconds (780 frames)
gunPowerUpTimer++;
if (gunPowerUpTimer >= 780) {
var newGunPowerUp = new GunPowerUp();
newGunPowerUp.x = Math.random() * 1800 + 124; // Random x position within bounds
newGunPowerUp.y = -50;
newGunPowerUp.lastY = newGunPowerUp.y;
newGunPowerUp.lastIntersecting = false;
gunPowerUps.push(newGunPowerUp);
game.addChild(newGunPowerUp);
gunPowerUpTimer = 0;
}
// Spawn health pack every 30 seconds (1800 frames)
healthPackTimer++;
if (healthPackTimer >= 1800) {
var newHealthPack = new HealthPack();
newHealthPack.x = Math.random() * 1800 + 124; // Random x position within bounds
newHealthPack.y = -50;
newHealthPack.lastY = newHealthPack.y;
newHealthPack.lastIntersecting = false;
healthPacks.push(newHealthPack);
game.addChild(newHealthPack);
healthPackTimer = 0;
}
// Spawn boss every 1000 points
var currentScore = LK.getScore();
if (Math.floor(currentScore / 1000) > Math.floor(lastBossScore / 1000) && bossShips.length === 0) {
var newBoss = new BossShip();
newBoss.x = 1024; // Center horizontally
newBoss.y = -125;
newBoss.lastY = newBoss.y;
newBoss.lastIntersecting = false;
bossShips.push(newBoss);
game.addChild(newBoss);
lastBossScore = currentScore;
isBossPresent = true;
}
// Spawn enemies (only when no boss is present)
if (!isBossPresent && LK.ticks % enemySpawnRate === 0) {
var newEnemy = new EnemyShip();
newEnemy.x = Math.random() * 1800 + 124; // Random x position within bounds
newEnemy.y = -50;
newEnemy.lastY = newEnemy.y;
newEnemy.lastIntersecting = false;
enemyShips.push(newEnemy);
game.addChild(newEnemy);
}
// Update and check player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Remove bullets that go off screen
if (bullet.lastY >= -25 && bullet.y < -25) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
var bulletHit = false;
for (var j = enemyShips.length - 1; j >= 0; j--) {
var enemy = enemyShips[j];
if (bullet.intersects(enemy)) {
// Damage enemy
enemy.health--;
enemy.updateHealthBar();
LK.setScore(LK.getScore() + 5);
updateScore();
// Flash effect on enemy
LK.effects.flashObject(enemy, 0xffffff, 200);
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
// Check if enemy is destroyed
if (enemy.health <= 0) {
LK.setScore(LK.getScore() + 5); // Bonus points for destroying enemy
updateScore();
LK.getSound('enemyDestroy').play();
enemy.destroy();
enemyShips.splice(j, 1);
}
break;
}
}
// Check bullet-boss collisions
if (!bulletHit) {
for (var b = bossShips.length - 1; b >= 0; b--) {
var boss = bossShips[b];
if (bullet.intersects(boss)) {
// Damage boss
boss.health--;
boss.updateHealthBar();
// Flash effect on boss
LK.effects.flashObject(boss, 0xffffff, 200);
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
// Check if boss is destroyed
if (boss.health <= 0) {
LK.setScore(LK.getScore() + 500); // Big bonus for destroying boss
updateScore();
LK.getSound('enemyDestroy').play();
boss.destroy();
bossShips.splice(b, 1);
isBossPresent = false; // Allow enemies to spawn again
}
break;
}
}
}
if (!bulletHit) {
bullet.lastY = bullet.y;
}
}
// Update and check enemies
for (var k = enemyShips.length - 1; k >= 0; k--) {
var enemy = enemyShips[k];
// Create enemy bullet if enemy should shoot
if (enemy.shouldShoot) {
var newEnemyBullet = new EnemyBullet();
newEnemyBullet.x = enemy.x;
newEnemyBullet.y = enemy.y + 40;
newEnemyBullet.lastY = newEnemyBullet.y;
newEnemyBullet.lastIntersecting = false;
enemyBullets.push(newEnemyBullet);
game.addChild(newEnemyBullet);
enemy.shouldShoot = false;
}
// Check if enemy reached bottom edge - instant kill player
if (enemy.lastY <= 2780 && enemy.y > 2780) {
// Enemy reached bottom - instant kill player
playerShip.health = 0;
playerShip.updateHealthBar();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check player-enemy collision
var currentIntersecting = enemy.intersects(playerShip);
if (!enemy.lastIntersecting && currentIntersecting) {
// Damage player
playerShip.health--;
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
// Destroy enemy
enemy.destroy();
enemyShips.splice(k, 1);
continue;
}
enemy.lastY = enemy.y;
enemy.lastIntersecting = currentIntersecting;
}
// Update and check bosses
for (var n = bossShips.length - 1; n >= 0; n--) {
var boss = bossShips[n];
// Create boss bullets with different patterns
if (boss.shouldShoot) {
if (boss.shootPattern === 0) {
// Single shot at player
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
} else if (boss.shootPattern === 1) {
// Triple shot
for (var s = -1; s <= 1; s++) {
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x + s * 60;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
}
} else {
// Spread shot (5 bullets)
for (var s = -2; s <= 2; s++) {
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x + s * 40;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
}
}
boss.shouldShoot = false;
}
// Check if boss reached bottom edge - instant kill player
if (boss.lastY <= 2780 && boss.y > 2780) {
playerShip.health = 0;
playerShip.updateHealthBar();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check player-boss collision
var bossPlayerIntersecting = boss.intersects(playerShip);
if (!boss.lastIntersecting && bossPlayerIntersecting) {
// Damage player
playerShip.health -= 1; // Boss does 1 damage like other sources
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
}
boss.lastY = boss.y;
boss.lastIntersecting = bossPlayerIntersecting;
}
// Update and check enemy bullets
for (var m = enemyBullets.length - 1; m >= 0; m--) {
var enemyBullet = enemyBullets[m];
// Remove bullets that go off screen
if (enemyBullet.lastY <= 2780 && enemyBullet.y > 2780) {
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
// Check enemy bullet-player collision
var bulletPlayerIntersecting = enemyBullet.intersects(playerShip);
if (!enemyBullet.lastIntersecting && bulletPlayerIntersecting) {
// Damage player
playerShip.health--;
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
// Destroy bullet
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
enemyBullet.lastY = enemyBullet.y;
enemyBullet.lastIntersecting = bulletPlayerIntersecting;
}
// Update and check gun power-ups
for (var g = gunPowerUps.length - 1; g >= 0; g--) {
var gunPowerUp = gunPowerUps[g];
// Remove gun power-ups that go off screen
if (gunPowerUp.lastY <= 2780 && gunPowerUp.y > 2780) {
gunPowerUp.destroy();
gunPowerUps.splice(g, 1);
continue;
}
// Check gun power-up-player collision
var gunPowerUpPlayerIntersecting = gunPowerUp.intersects(playerShip);
if (!gunPowerUp.lastIntersecting && gunPowerUpPlayerIntersecting) {
// Enable triple shot for 6 seconds (360 frames at 60fps)
hasTripleShot = true;
gunPowerUpEndTime = LK.ticks + 360;
// Flash effect on player (blue for gun upgrade)
LK.effects.flashObject(playerShip, 0x0099ff, 300);
// Tint player ship blue to show power-up is active
tween(playerShip, {
tint: 0x4444ff
}, {
duration: 500
});
// Destroy gun power-up
gunPowerUp.destroy();
gunPowerUps.splice(g, 1);
continue;
}
gunPowerUp.lastY = gunPowerUp.y;
gunPowerUp.lastIntersecting = gunPowerUpPlayerIntersecting;
}
// Update and check health packs
for (var h = healthPacks.length - 1; h >= 0; h--) {
var healthPack = healthPacks[h];
// Remove health packs that go off screen
if (healthPack.lastY <= 2780 && healthPack.y > 2780) {
healthPack.destroy();
healthPacks.splice(h, 1);
continue;
}
// Check health pack-player collision
var healthPackPlayerIntersecting = healthPack.intersects(playerShip);
if (!healthPack.lastIntersecting && healthPackPlayerIntersecting) {
// Heal player to max health
if (playerShip.health < playerShip.maxHealth) {
playerShip.health = playerShip.maxHealth;
playerShip.updateHealthBar();
// Flash effect on player (magenta for health)
LK.effects.flashObject(playerShip, 0xff00ff, 300);
}
// Destroy health pack
healthPack.destroy();
healthPacks.splice(h, 1);
continue;
}
healthPack.lastY = healthPack.y;
healthPack.lastIntersecting = healthPackPlayerIntersecting;
}
// Check if gun power-up should expire
if (hasTripleShot && LK.ticks >= gunPowerUpEndTime) {
hasTripleShot = false;
// Fade player ship back to normal color
tween(playerShip, {
tint: 0xffffff
}, {
duration: 500
});
// Flash effect to show power-up ended
LK.effects.flashObject(playerShip, 0xffffff, 200);
}
// Check if player is dead
if (playerShip.health <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
difficultyLevel++;
if (enemySpawnRate > 30) {
enemySpawnRate -= 10;
}
if (bulletFireRate > 8 && difficultyLevel % 3 === 0) {
bulletFireRate -= 1;
}
}
};
// Start background music
LK.playMusic('gameMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossShip = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('bossShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.moveDirection = 1;
self.shootTimer = 0;
self.maxHealth = 50;
self.health = self.maxHealth;
self.shootPattern = 0;
self.patternTimer = 0;
// Create boss health bar background
var healthBarBg = self.attachAsset('bossHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -140;
// Create boss health bar fill
var healthBarFill = self.attachAsset('bossHealthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -140;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0xff0000; // Red
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xff6600; // Orange
} else {
self.healthBarFill.tint = 0xffff00; // Yellow
}
};
self.update = function () {
self.y += self.speed;
// Move side to side
self.x += self.moveDirection * 2;
if (self.x <= 100 || self.x >= 1948) {
self.moveDirection *= -1;
}
// Handle shooting patterns
self.shootTimer--;
self.patternTimer++;
if (self.patternTimer % 300 === 0) {
self.shootPattern = (self.shootPattern + 1) % 3;
}
if (self.shootTimer <= 0) {
self.shootTimer = 30;
// Only shoot if not about to hit edges
if (self.x > 150 && self.x < 1898) {
self.shouldShoot = true;
}
}
};
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 = 8;
// Play shoot sound when enemy bullet is created
LK.getSound('shoot').play();
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.movePattern = Math.random() < 0.5 ? 'straight' : 'zigzag';
self.zigzagTimer = 0;
self.zigzagDirection = Math.random() < 0.5 ? -1 : 1;
self.shootTimer = Math.random() * 60 + 60; // Random initial shoot delay
self.maxHealth = 3;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -50;
// Create health bar fill
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -50;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xffff00; // Yellow
} else {
self.healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
self.y += self.speed;
if (self.movePattern === 'zigzag') {
self.zigzagTimer += 1;
if (self.zigzagTimer % 60 === 0) {
self.zigzagDirection *= -1;
}
self.x += self.zigzagDirection * 2;
}
// Keep enemy within screen bounds
if (self.x < 50) self.x = 50;
if (self.x > 1998) self.x = 1998;
// Handle shooting
self.shootTimer--;
if (self.shootTimer <= 0) {
self.shootTimer = Math.random() * 120 + 90; // Slower random shoot interval
self.shouldShoot = true;
}
};
return self;
});
var GunPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('gunPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var healthPackGraphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
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 = -12;
self.angle = 0; // Angle in radians for bullet direction
// Play shoot sound when bullet is created
LK.getSound('shoot').play();
self.update = function () {
self.y += self.speed * Math.cos(self.angle);
self.x += self.speed * Math.sin(self.angle);
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 10;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('playerHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -80;
// Create health bar fill
var healthBarFill = self.attachAsset('playerHealthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -80;
self.healthBarFill = healthBarFill;
// Method to update health bar
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xffff00; // Yellow
} else {
self.healthBarFill.tint = 0xff0000; // Red
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game variables
var playerShip;
var playerBullets = [];
var enemyBullets = [];
var enemyShips = [];
var bossShips = [];
var difficultyLevel = 1;
var enemySpawnRate = 120; // frames between spawns
var bulletFireRate = 15; // frames between shots
var dragNode = null;
var lastBossScore = 0;
var gunPowerUps = [];
var gunPowerUpTimer = 0;
var healthPacks = [];
var healthPackTimer = 0;
var playerFireRate = bulletFireRate; // Track player's current fire rate
var hasTripleShot = false; // Track if player has triple shot upgrade
var gunPowerUpEndTime = 0; // Track when gun power-up should end
var isBossPresent = false; // Track if boss is currently on screen
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize player ship
playerShip = game.addChild(new PlayerShip());
playerShip.x = 1024; // Center horizontally
playerShip.y = 2400; // Near bottom of screen
// Update score display
function updateScore() {
scoreTxt.setText('Score: ' + LK.getScore());
}
// Handle movement
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep player within screen bounds
if (dragNode.x < 40) dragNode.x = 40;
if (dragNode.x > 2008) dragNode.x = 2008;
if (dragNode.y < 200) dragNode.y = 200;
if (dragNode.y > 2600) dragNode.y = 2600;
}
}
// Event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = playerShip;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update loop
game.update = function () {
// Fire player bullets
if (LK.ticks % playerFireRate === 0) {
if (hasTripleShot) {
// Fire three bullets in different directions
var angles = [-0.3, 0, 0.3]; // Left, center, right angles in radians
for (var bulletIndex = 0; bulletIndex < 3; bulletIndex++) {
var newBullet = new PlayerBullet();
newBullet.x = playerShip.x;
newBullet.y = playerShip.y - 60;
newBullet.angle = angles[bulletIndex];
newBullet.lastY = newBullet.y;
playerBullets.push(newBullet);
game.addChild(newBullet);
}
} else {
// Fire single bullet
var newBullet = new PlayerBullet();
newBullet.x = playerShip.x;
newBullet.y = playerShip.y - 60;
newBullet.lastY = newBullet.y;
playerBullets.push(newBullet);
game.addChild(newBullet);
}
}
// Spawn gun power-up every 13 seconds (780 frames)
gunPowerUpTimer++;
if (gunPowerUpTimer >= 780) {
var newGunPowerUp = new GunPowerUp();
newGunPowerUp.x = Math.random() * 1800 + 124; // Random x position within bounds
newGunPowerUp.y = -50;
newGunPowerUp.lastY = newGunPowerUp.y;
newGunPowerUp.lastIntersecting = false;
gunPowerUps.push(newGunPowerUp);
game.addChild(newGunPowerUp);
gunPowerUpTimer = 0;
}
// Spawn health pack every 30 seconds (1800 frames)
healthPackTimer++;
if (healthPackTimer >= 1800) {
var newHealthPack = new HealthPack();
newHealthPack.x = Math.random() * 1800 + 124; // Random x position within bounds
newHealthPack.y = -50;
newHealthPack.lastY = newHealthPack.y;
newHealthPack.lastIntersecting = false;
healthPacks.push(newHealthPack);
game.addChild(newHealthPack);
healthPackTimer = 0;
}
// Spawn boss every 1000 points
var currentScore = LK.getScore();
if (Math.floor(currentScore / 1000) > Math.floor(lastBossScore / 1000) && bossShips.length === 0) {
var newBoss = new BossShip();
newBoss.x = 1024; // Center horizontally
newBoss.y = -125;
newBoss.lastY = newBoss.y;
newBoss.lastIntersecting = false;
bossShips.push(newBoss);
game.addChild(newBoss);
lastBossScore = currentScore;
isBossPresent = true;
}
// Spawn enemies (only when no boss is present)
if (!isBossPresent && LK.ticks % enemySpawnRate === 0) {
var newEnemy = new EnemyShip();
newEnemy.x = Math.random() * 1800 + 124; // Random x position within bounds
newEnemy.y = -50;
newEnemy.lastY = newEnemy.y;
newEnemy.lastIntersecting = false;
enemyShips.push(newEnemy);
game.addChild(newEnemy);
}
// Update and check player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Remove bullets that go off screen
if (bullet.lastY >= -25 && bullet.y < -25) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
var bulletHit = false;
for (var j = enemyShips.length - 1; j >= 0; j--) {
var enemy = enemyShips[j];
if (bullet.intersects(enemy)) {
// Damage enemy
enemy.health--;
enemy.updateHealthBar();
LK.setScore(LK.getScore() + 5);
updateScore();
// Flash effect on enemy
LK.effects.flashObject(enemy, 0xffffff, 200);
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
// Check if enemy is destroyed
if (enemy.health <= 0) {
LK.setScore(LK.getScore() + 5); // Bonus points for destroying enemy
updateScore();
LK.getSound('enemyDestroy').play();
enemy.destroy();
enemyShips.splice(j, 1);
}
break;
}
}
// Check bullet-boss collisions
if (!bulletHit) {
for (var b = bossShips.length - 1; b >= 0; b--) {
var boss = bossShips[b];
if (bullet.intersects(boss)) {
// Damage boss
boss.health--;
boss.updateHealthBar();
// Flash effect on boss
LK.effects.flashObject(boss, 0xffffff, 200);
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
// Check if boss is destroyed
if (boss.health <= 0) {
LK.setScore(LK.getScore() + 500); // Big bonus for destroying boss
updateScore();
LK.getSound('enemyDestroy').play();
boss.destroy();
bossShips.splice(b, 1);
isBossPresent = false; // Allow enemies to spawn again
}
break;
}
}
}
if (!bulletHit) {
bullet.lastY = bullet.y;
}
}
// Update and check enemies
for (var k = enemyShips.length - 1; k >= 0; k--) {
var enemy = enemyShips[k];
// Create enemy bullet if enemy should shoot
if (enemy.shouldShoot) {
var newEnemyBullet = new EnemyBullet();
newEnemyBullet.x = enemy.x;
newEnemyBullet.y = enemy.y + 40;
newEnemyBullet.lastY = newEnemyBullet.y;
newEnemyBullet.lastIntersecting = false;
enemyBullets.push(newEnemyBullet);
game.addChild(newEnemyBullet);
enemy.shouldShoot = false;
}
// Check if enemy reached bottom edge - instant kill player
if (enemy.lastY <= 2780 && enemy.y > 2780) {
// Enemy reached bottom - instant kill player
playerShip.health = 0;
playerShip.updateHealthBar();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check player-enemy collision
var currentIntersecting = enemy.intersects(playerShip);
if (!enemy.lastIntersecting && currentIntersecting) {
// Damage player
playerShip.health--;
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
// Destroy enemy
enemy.destroy();
enemyShips.splice(k, 1);
continue;
}
enemy.lastY = enemy.y;
enemy.lastIntersecting = currentIntersecting;
}
// Update and check bosses
for (var n = bossShips.length - 1; n >= 0; n--) {
var boss = bossShips[n];
// Create boss bullets with different patterns
if (boss.shouldShoot) {
if (boss.shootPattern === 0) {
// Single shot at player
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
} else if (boss.shootPattern === 1) {
// Triple shot
for (var s = -1; s <= 1; s++) {
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x + s * 60;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
}
} else {
// Spread shot (5 bullets)
for (var s = -2; s <= 2; s++) {
var newBossBullet = new EnemyBullet();
newBossBullet.x = boss.x + s * 40;
newBossBullet.y = boss.y + 125;
newBossBullet.lastY = newBossBullet.y;
newBossBullet.lastIntersecting = false;
enemyBullets.push(newBossBullet);
game.addChild(newBossBullet);
}
}
boss.shouldShoot = false;
}
// Check if boss reached bottom edge - instant kill player
if (boss.lastY <= 2780 && boss.y > 2780) {
playerShip.health = 0;
playerShip.updateHealthBar();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check player-boss collision
var bossPlayerIntersecting = boss.intersects(playerShip);
if (!boss.lastIntersecting && bossPlayerIntersecting) {
// Damage player
playerShip.health -= 1; // Boss does 1 damage like other sources
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
}
boss.lastY = boss.y;
boss.lastIntersecting = bossPlayerIntersecting;
}
// Update and check enemy bullets
for (var m = enemyBullets.length - 1; m >= 0; m--) {
var enemyBullet = enemyBullets[m];
// Remove bullets that go off screen
if (enemyBullet.lastY <= 2780 && enemyBullet.y > 2780) {
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
// Check enemy bullet-player collision
var bulletPlayerIntersecting = enemyBullet.intersects(playerShip);
if (!enemyBullet.lastIntersecting && bulletPlayerIntersecting) {
// Damage player
playerShip.health--;
playerShip.updateHealthBar();
// Flash effect on player
LK.effects.flashObject(playerShip, 0xff0000, 300);
// Destroy bullet
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
enemyBullet.lastY = enemyBullet.y;
enemyBullet.lastIntersecting = bulletPlayerIntersecting;
}
// Update and check gun power-ups
for (var g = gunPowerUps.length - 1; g >= 0; g--) {
var gunPowerUp = gunPowerUps[g];
// Remove gun power-ups that go off screen
if (gunPowerUp.lastY <= 2780 && gunPowerUp.y > 2780) {
gunPowerUp.destroy();
gunPowerUps.splice(g, 1);
continue;
}
// Check gun power-up-player collision
var gunPowerUpPlayerIntersecting = gunPowerUp.intersects(playerShip);
if (!gunPowerUp.lastIntersecting && gunPowerUpPlayerIntersecting) {
// Enable triple shot for 6 seconds (360 frames at 60fps)
hasTripleShot = true;
gunPowerUpEndTime = LK.ticks + 360;
// Flash effect on player (blue for gun upgrade)
LK.effects.flashObject(playerShip, 0x0099ff, 300);
// Tint player ship blue to show power-up is active
tween(playerShip, {
tint: 0x4444ff
}, {
duration: 500
});
// Destroy gun power-up
gunPowerUp.destroy();
gunPowerUps.splice(g, 1);
continue;
}
gunPowerUp.lastY = gunPowerUp.y;
gunPowerUp.lastIntersecting = gunPowerUpPlayerIntersecting;
}
// Update and check health packs
for (var h = healthPacks.length - 1; h >= 0; h--) {
var healthPack = healthPacks[h];
// Remove health packs that go off screen
if (healthPack.lastY <= 2780 && healthPack.y > 2780) {
healthPack.destroy();
healthPacks.splice(h, 1);
continue;
}
// Check health pack-player collision
var healthPackPlayerIntersecting = healthPack.intersects(playerShip);
if (!healthPack.lastIntersecting && healthPackPlayerIntersecting) {
// Heal player to max health
if (playerShip.health < playerShip.maxHealth) {
playerShip.health = playerShip.maxHealth;
playerShip.updateHealthBar();
// Flash effect on player (magenta for health)
LK.effects.flashObject(playerShip, 0xff00ff, 300);
}
// Destroy health pack
healthPack.destroy();
healthPacks.splice(h, 1);
continue;
}
healthPack.lastY = healthPack.y;
healthPack.lastIntersecting = healthPackPlayerIntersecting;
}
// Check if gun power-up should expire
if (hasTripleShot && LK.ticks >= gunPowerUpEndTime) {
hasTripleShot = false;
// Fade player ship back to normal color
tween(playerShip, {
tint: 0xffffff
}, {
duration: 500
});
// Flash effect to show power-up ended
LK.effects.flashObject(playerShip, 0xffffff, 200);
}
// Check if player is dead
if (playerShip.health <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
difficultyLevel++;
if (enemySpawnRate > 30) {
enemySpawnRate -= 10;
}
if (bulletFireRate > 8 && difficultyLevel % 3 === 0) {
bulletFireRate -= 1;
}
}
};
// Start background music
LK.playMusic('gameMusic');
boss enimey space ship. In-Game asset. 2d. High contrast. No shadows
enimy space ship. In-Game asset. 2d. High contrast. No shadows
player space ship. In-Game asset. 2d. High contrast. No shadows
bullet. In-Game asset. 2d. High contrast. No shadows
shot gun. In-Game asset. 2d. High contrast. No shadows
first aid kit. In-Game asset. 2d. High contrast. No shadows