/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.bossLevel = 1;
self.health = 20;
self.maxHealth = 20;
self.speed = 3;
self.direction = 1;
self.shootCooldown = 0;
self.shootInterval = 45;
self.phase = 1;
self.points = 1000;
self.setBossLevel = function (level) {
self.bossLevel = Math.floor(level / 10);
self.health = 30 + self.bossLevel * 20;
self.maxHealth = self.health;
self.points = 1000 * (self.bossLevel + 1);
bossGraphics.scale.x = 1 + self.bossLevel * 0.2;
bossGraphics.scale.y = 1 + self.bossLevel * 0.2;
};
self.update = function () {
// Boss movement pattern
self.y += self.speed * self.direction;
if (self.y > 600 || self.y < 300) {
self.direction *= -1;
}
// More complex movement for higher level bosses
if (self.bossLevel >= 2) {
self.x += Math.sin(LK.ticks * 0.02) * 2;
}
self.shootCooldown++;
// Different attack patterns based on phase
if (self.health < self.maxHealth * 0.5 && self.phase === 1) {
self.phase = 2;
self.shootInterval = 30;
}
if (self.health < self.maxHealth * 0.25 && self.phase === 2 && self.bossLevel >= 2) {
self.phase = 3;
self.shootInterval = 20;
}
if (self.health < self.maxHealth * 0.1 && self.phase === 3 && self.bossLevel >= 4) {
self.phase = 4;
self.shootInterval = 15;
}
if (self.shootCooldown >= self.shootInterval) {
self.shootCooldown = 0;
return self.phase; // Return phase for different bullet patterns
}
return 0;
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // Boss destroyed
}
tween(bossGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
bossGraphics.tint = 0xffffff;
}
});
bossGraphics.tint = 0xff0000;
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.enemyType = 'basic';
self.health = 2;
self.speed = -2;
self.shootCooldown = 0;
self.shootInterval = 120;
self.points = 100;
self.pattern = 0;
self.setType = function (type) {
self.enemyType = type;
var stats = enemyTypesPerLevel[type];
self.health = stats.health;
self.speed = stats.speed;
self.shootInterval = stats.shootInterval;
enemyGraphics.tint = stats.color;
self.points = stats.health * 50;
};
self.update = function () {
self.x += self.speed;
// Different movement patterns for different enemy types
if (self.enemyType === 'fast') {
self.y += Math.sin(self.x * 0.01) * 2;
} else if (self.enemyType === 'sniper' && self.x < 1500) {
self.speed = 0;
}
self.shootCooldown++;
if (self.shootCooldown >= self.shootInterval) {
self.shootCooldown = 0;
return true; // Signal to shoot
}
return false;
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // Enemy destroyed
}
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
enemyGraphics.tint = enemyTypesPerLevel[self.enemyType].color;
}
});
enemyGraphics.tint = 0xff0000;
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = -8;
self.speedY = 0;
self.canBeParried = false;
self.parried = false;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Make bullets parryable when they're pink
if (!self.canBeParried && Math.random() < 0.3) {
self.canBeParried = true;
bulletGraphics.tint = 0xff00ff;
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.hand = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0.5,
x: 270,
y: -5
});
self.handBaseY = -15;
self.handAnimating = false;
self.health = 3;
self.maxHealth = 3;
self.shootCooldown = 0;
self.shootInterval = 20;
self.invulnerable = 0;
self.powerupTime = 0;
self.powerupType = null;
self.weaponType = 0;
self.chargeTime = 0;
self.isParrying = false;
self.parryIndicator = null;
self.originalTint = 0xffffff;
self.isPowerupFlashing = false;
self.perryCharges = 3; // Start with 3 perrys
self.perryEffect = null;
self.perryActive = false;
self.perryCooldown = 0;
self.perryMaxCooldown = 300; // 5 seconds at 60fps
self.tapIndicator = null;
self.tapBg = null;
self.shieldActive = false;
self.shieldTime = 0;
self.update = function () {
if (self.invulnerable > 0) {
self.invulnerable--;
self.alpha = Math.sin(self.invulnerable * 0.3) > 0 ? 1 : 0.5;
} else {
self.alpha = 1;
}
if (self.powerupTime > 0) {
self.powerupTime--;
// Flash between powerup color and original color in the last 2 seconds
if (self.powerupTime <= 120 && !self.isPowerupFlashing) {
self.isPowerupFlashing = true;
self.startPowerupFlash();
}
if (self.powerupTime === 0) {
self.powerupType = null;
self.shootInterval = 20;
heroGraphics.tint = self.originalTint;
self.isPowerupFlashing = false;
}
}
self.shootCooldown++;
// Update charge for charge weapon
if (self.weaponType === 2 && self.chargeTime > 0) {
self.chargeTime--;
}
// Update perry cooldown (weapon-specific for level 10 weapon)
if (self.perryCooldown > 0) {
self.perryCooldown--;
}
// Update shield timer
if (self.shieldTime > 0) {
self.shieldTime--;
if (self.shieldTime === 0) {
self.shieldActive = false;
}
}
};
self.takeDamage = function () {
if (self.invulnerable > 0) {
return false;
}
// Check if shield is active and blocks damage
if (self.shieldActive) {
self.shieldActive = false;
self.shieldTime = 0;
LK.effects.flashObject(self, 0x00ff00, 300);
return false; // Damage blocked by shield
}
self.health--;
self.invulnerable = 120; // 2 seconds of invulnerability
if (self.health <= 0) {
return true; // Hero destroyed
}
LK.effects.flashObject(self, 0xff0000, 500);
return false;
};
self.canShoot = function () {
var weapon = weaponTypes[self.weaponType];
var interval = self.shootInterval;
if (weapon.fireRate) {
interval = weapon.fireRate;
}
if (self.shootCooldown >= interval) {
self.shootCooldown = 0;
return true;
}
return false;
};
self.applyPowerup = function (type) {
self.powerupType = type;
self.powerupTime = 600; // 10 seconds
self.isPowerupFlashing = false;
// Change hero color based on powerup type
var powerupColor = type === 'rapid' ? 0xff00ff : 0x00ffff;
heroGraphics.tint = powerupColor;
if (type === 'rapid') {
self.shootInterval = 10;
}
};
self.startPowerupFlash = function () {
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
flashCount++;
if (flashCount % 2 === 0) {
heroGraphics.tint = self.originalTint;
} else {
var powerupColor = self.powerupType === 'rapid' ? 0xff00ff : 0x00ffff;
heroGraphics.tint = powerupColor;
}
if (self.powerupTime === 0) {
LK.clearInterval(flashInterval);
heroGraphics.tint = self.originalTint;
}
}, 200); // Flash every 200ms
};
self.setWeapon = function (weaponIndex) {
self.weaponType = weaponIndex;
};
self.startParry = function () {
if (!self.isParrying && !self.parryIndicator) {
self.isParrying = true;
self.parryIndicator = self.attachAsset('parryIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.parryIndicator.alpha = 0.5;
self.parryIndicator.tint = weaponTypes[self.weaponType].parryColor;
}
};
self.endParry = function () {
self.isParrying = false;
if (self.parryIndicator) {
self.parryIndicator.destroy();
self.parryIndicator = null;
}
};
self.animateHandShoot = function () {
if (!self.handAnimating) {
self.handAnimating = true;
tween(self.hand, {
y: self.handBaseY - 20
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.hand, {
y: self.handBaseY
}, {
duration: 100,
onFinish: function onFinish() {
self.handAnimating = false;
}
});
}
});
}
};
self.activatePerry = function () {
if (self.perryCharges > 0 && !self.perryActive && self.perryCooldown === 0) {
self.perryCharges--;
self.perryActive = true;
// Set weapon-specific cooldown (4.5 seconds for Homing weapon at 60fps)
if (self.weaponType === 3) {
// Homing weapon
self.perryCooldown = 270; // 4.5 seconds at 60fps
} else {
self.perryCooldown = self.perryMaxCooldown; // Default cooldown
}
var weapon = weaponTypes[self.weaponType];
// Create perry effect visual
self.perryEffect = self.attachAsset('perryEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.perryEffect.tint = weapon.parryColor;
// Weapon-specific animations and effects
if (weapon.name === 'Spread') {
// Freeze all enemies briefly
self.performSpreadPerry();
} else if (weapon.name === 'Rapid') {
// Multi-hit explosion
self.performRapidPerry();
} else if (weapon.name === 'Charge') {
// Piercing beam attack
self.performChargePerry();
} else if (weapon.name === 'Homing') {
// Healing wave
self.performHomingPerry();
} else if (weapon.name === 'Bounce') {
// Multi-directional attack
self.performBouncePerry();
}
// Animate perry effect
tween(self.perryEffect, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
if (self.perryEffect) {
self.perryEffect.destroy();
self.perryEffect = null;
}
self.perryActive = false;
}
});
// Hand animation for perry
tween(self.hand, {
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI / 4
}, {
duration: 200,
onFinish: function onFinish() {
tween(self.hand, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 200
});
}
});
}
};
self.performSpreadPerry = function () {
// Freeze all enemies for 2 seconds
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var originalSpeed = enemy.speed;
enemy.speed = 0;
tween(enemy, {
tint: 0x00ffff
}, {
duration: 2000,
onFinish: function onFinish() {
enemy.speed = originalSpeed;
enemy.tint = enemyTypesPerLevel[enemy.enemyType].color;
}
});
}
if (boss) {
var originalSpeed = boss.speed;
boss.speed = 0;
tween(boss, {
tint: 0x00ffff
}, {
duration: 2000,
onFinish: function onFinish() {
boss.speed = originalSpeed;
boss.tint = 0xffffff;
}
});
}
};
self.performRapidPerry = function () {
// Damage all enemies with explosion effect
LK.effects.flashScreen(0xff00ff, 500);
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.takeDamage(3)) {
LK.setScore(LK.getScore() + enemy.points * 2);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
if (boss) {
boss.takeDamage(5);
}
};
self.performChargePerry = function () {
// Create piercing beam that hits all enemies in line
var beamY = self.y;
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (Math.abs(enemy.y - beamY) < 50) {
if (enemy.takeDamage(4)) {
LK.setScore(LK.getScore() + enemy.points * 2);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
if (boss && Math.abs(boss.y - beamY) < 75) {
boss.takeDamage(8);
}
// Visual beam effect
LK.effects.flashScreen(0xffff00, 300);
};
self.performHomingPerry = function () {
// Activate shield for 1.5 seconds
self.shieldActive = true;
self.shieldTime = 90; // 1.5 seconds at 60fps
// Visual shield effect
LK.effects.flashObject(self, 0x00ff00, 1500);
// Damage nearby enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < 300) {
if (enemy.takeDamage(2)) {
LK.setScore(LK.getScore() + enemy.points);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
if (boss) {
var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2));
if (distance < 400) {
boss.takeDamage(3);
}
}
};
self.performBouncePerry = function () {
// Create multiple bouncing attacks
for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 4) {
var bullet = new HeroBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.speed = 12;
bullet.damage = 3;
bullet.bounces = 3;
bullet.speedX = Math.cos(angle) * bullet.speed;
bullet.speedY = Math.sin(angle) * bullet.speed;
bullet.setWeaponType(4, weaponTypes[4]);
heroBullets.push(bullet);
game.addChild(bullet);
}
};
self.collectPerry = function () {
self.perryCharges++;
};
self.down = function (x, y, obj) {
// Create tap indicator text with background
if (!self.tapIndicator) {
// Create background for tap text
self.tapBg = self.attachAsset('textBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.9
});
// Create tap text
self.tapIndicator = new Text2('Tap!', {
size: 45,
fill: 0xffff00
});
self.tapIndicator.anchor.set(0.5, 0.5);
self.tapIndicator.x = 0;
self.tapIndicator.y = -120;
self.addChild(self.tapIndicator);
// Animate text with tween
tween(self.tapIndicator, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.tapIndicator, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
// Activate parry and remove tap indicator
self.activatePerry();
perryTxt.setText('Perry: ' + self.perryCharges);
// Remove tap indicator and background after animation
LK.setTimeout(function () {
if (self.tapIndicator) {
tween(self.tapIndicator, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.tapIndicator.destroy();
self.tapIndicator = null;
}
});
}
if (self.tapBg) {
tween(self.tapBg, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.tapBg.destroy();
self.tapBg = null;
}
});
}
}, 500);
}
};
return self;
});
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1;
self.weaponType = 0;
self.target = null;
self.bounces = 0;
self.pierce = false;
self.setWeaponType = function (type, weapon) {
self.weaponType = type;
bulletGraphics.tint = weapon.parryColor;
if (type === 2) {
// Charge weapon
self.damage = 2;
bulletGraphics.scale.x = 1.5;
bulletGraphics.scale.y = 1.5;
} else if (type === 4) {
// Bounce weapon
self.bounces = weapon.bounceCount;
}
};
self.update = function () {
if (self.weaponType === 3 && self.target && !self.target.destroyed) {
// Homing
var angle = Math.atan2(self.target.y - self.y, self.target.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else if (self.speedX !== undefined && self.speedY !== undefined) {
// Perry bouncing bullets
self.x += self.speedX;
self.y += self.speedY;
// Bounce off screen edges
if (self.bounces > 0 && (self.y < 100 || self.y > 2632)) {
self.speedY *= -1;
self.bounces--;
}
} else {
self.x += self.speed;
}
};
return self;
});
var PerryCollectible = Container.expand(function () {
var self = Container.call(this);
var perryGraphics = self.attachAsset('perryEffect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
self.speed = -3;
self.update = function () {
self.x += self.speed;
self.rotation += 0.03;
// Floating animation
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() > 0.5 ? 'rapid' : 'triple';
self.speed = -3;
self.update = function () {
self.x += self.speed;
self.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
game.setBackgroundColor(0x1a1a2e);
// Background layers
var backgroundLayer1 = LK.getAsset('background1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 1.0
});
game.addChild(backgroundLayer1);
var backgroundLayer2 = LK.getAsset('background2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 1.0
});
game.addChild(backgroundLayer2);
// Clouds array for parallax effect
var clouds = [];
for (var i = 0; i < 8; i++) {
var cloud = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: 200 + Math.random() * 1000,
alpha: 0.1 + Math.random() * 0.1
});
clouds.push(cloud);
game.addChild(cloud);
}
// Game variables
var hero;
var heroBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var perryCollectibles = [];
var boss = null;
var currentLevel = 9;
var enemiesSpawned = 0;
var enemiesPerLevel = 10;
var spawnCooldown = 0;
var gameStarted = false;
var isDragging = false;
var dragOffsetY = 0;
var parryWindow = false;
var parryWindowTimer = 0;
// Weapon types with different parry mechanics
var weaponTypes = [{
name: 'Spread',
bulletCount: 3,
fireRate: 25,
parryColor: 0x00ffff,
parryEffect: 'freeze'
}, {
name: 'Rapid',
fireRate: 15,
parryColor: 0xff00ff,
parryEffect: 'explode'
}, {
name: 'Charge',
chargeTime: 45,
fireRate: 60,
parryColor: 0xffff00,
parryEffect: 'pierce'
}, {
name: 'Homing',
homingStrength: 0.1,
fireRate: 30,
parryColor: 0x00ff00,
parryEffect: 'heal'
}, {
name: 'Bounce',
bounceCount: 2,
fireRate: 35,
parryColor: 0xff0000,
parryEffect: 'multi'
}];
var currentWeapon = 0;
// Enemy types per level range (base values)
var enemyTypesBase = {
basic: {
health: 2,
speed: -2,
shootInterval: 120,
color: 0xff4444
},
fast: {
health: 1,
speed: -4,
shootInterval: 80,
color: 0xff8844
},
heavy: {
health: 4,
speed: -1,
shootInterval: 150,
color: 0x884444
},
sniper: {
health: 2,
speed: -1.5,
shootInterval: 180,
color: 0x4444ff
},
burst: {
health: 3,
speed: -2.5,
shootInterval: 100,
color: 0xff44ff
}
};
// Current enemy stats (will be modified based on weapon changes)
var enemyTypesPerLevel = {
basic: {
health: 2,
speed: -2,
shootInterval: 120,
color: 0xff4444
},
fast: {
health: 1,
speed: -4,
shootInterval: 80,
color: 0xff8844
},
heavy: {
health: 4,
speed: -1,
shootInterval: 150,
color: 0x884444
},
sniper: {
health: 2,
speed: -1.5,
shootInterval: 180,
color: 0x4444ff
},
burst: {
health: 3,
speed: -2.5,
shootInterval: 100,
color: 0xff44ff
}
};
// Ground
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100
});
game.addChild(ground);
// Hero
hero = new Hero();
hero.x = 200;
hero.y = 2732 - 200;
game.addChild(hero);
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
// Health display
var healthContainer = new Container();
LK.gui.topRight.addChild(healthContainer);
healthContainer.x = -120;
healthContainer.y = 40;
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthContainer.addChild(healthBarBg);
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: -100
});
healthContainer.addChild(healthBar);
// Level text background
var levelBg = LK.getAsset('levelBg', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
LK.gui.center.addChild(levelBg);
// Level text
var levelTxt = new Text2('Level 1', {
size: 80,
fill: 0xFFFF00
});
levelTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelTxt);
levelTxt.alpha = 0;
// Weapon text background
var weaponBg = LK.getAsset('textBg', {
anchorX: 0,
anchorY: 0,
x: 20,
y: 120,
alpha: 1.0,
scaleX: 1.3
});
LK.gui.topLeft.addChild(weaponBg);
// Weapon text
var weaponTxt = new Text2('Weapon: Spread', {
size: 50,
fill: 0xFFFFFF
});
weaponTxt.anchor.set(0, 0);
weaponTxt.x = 35;
weaponTxt.y = 145;
LK.gui.topLeft.addChild(weaponTxt);
// Perry charges text background
var perryBg = LK.getAsset('textBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0
});
LK.gui.topLeft.addChild(perryBg);
// Perry charges text
var perryTxt = new Text2('Perry: 3', {
size: 45,
fill: 0xff6600
});
perryTxt.anchor.set(0, 0);
perryTxt.x = 35;
perryTxt.y = 205;
LK.gui.topLeft.addChild(perryTxt);
// Perry cooldown text
var perryCooldownTxt = new Text2('', {
size: 35,
fill: 0xffaa00
});
perryCooldownTxt.anchor.set(0, 0);
perryCooldownTxt.x = 20;
perryCooldownTxt.y = 270;
LK.gui.topLeft.addChild(perryCooldownTxt);
// Touch controls
game.down = function (x, y, obj) {
var heroGlobalPos = hero.toGlobal({
x: 0,
y: 0
});
var localPos = game.toLocal(heroGlobalPos);
if (Math.abs(x - localPos.x) < 100 && Math.abs(y - localPos.y) < 100) {
isDragging = true;
dragOffsetY = y - hero.y;
gameStarted = true;
} else if (x > 1024) {
// Right side tap for parry
parryWindow = true;
parryWindowTimer = 20; // 1/3 second parry window
hero.startParry();
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
game.move = function (x, y, obj) {
if (isDragging) {
hero.y = Math.max(300, Math.min(2732 - 200, y - dragOffsetY));
}
};
// Helper functions
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = 2048 + 50;
enemy.y = 300 + Math.random() * (2732 - 600);
// Choose enemy type based on level
var types = ['basic'];
if (currentLevel >= 5) {
types.push('fast');
}
if (currentLevel >= 10) {
types.push('heavy');
}
if (currentLevel >= 15) {
types.push('sniper');
}
if (currentLevel >= 20) {
types.push('burst');
}
var randomType = types[Math.floor(Math.random() * types.length)];
enemy.setType(randomType);
enemies.push(enemy);
game.addChild(enemy);
}
function spawnBoss() {
boss = new Boss();
boss.x = 2048 - 200;
boss.y = 450;
boss.setBossLevel(currentLevel);
game.addChild(boss);
// Show boss warning
levelTxt.setText('BOSS LEVEL ' + currentLevel + '!');
levelTxt.alpha = 1;
levelBg.alpha = 0.9;
tween(levelTxt, {
alpha: 0
}, {
duration: 2000
});
tween(levelBg, {
alpha: 0
}, {
duration: 2000
});
}
function spawnPowerup(x, y) {
if (Math.random() < 0.08) {
// 8% chance for perry collectible
var perryCollectible = new PerryCollectible();
perryCollectible.x = x;
perryCollectible.y = y;
perryCollectibles.push(perryCollectible);
game.addChild(perryCollectible);
} else if (Math.random() < 0.1) {
// 10% chance for regular powerup
var powerup = new PowerUp();
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
}
function shootHeroBullet() {
var weapon = weaponTypes[hero.weaponType];
hero.animateHandShoot();
var bulletStartX = hero.x + hero.hand.x;
var bulletStartY = hero.y + hero.hand.y;
if (hero.weaponType === 0 || hero.powerupType === 'triple') {
// Spread weapon
// Triple shot
for (var i = -1; i <= 1; i++) {
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY + i * 30;
bullet.setWeaponType(hero.weaponType, weapon);
if (hero.weaponType === 3) {
// Homing
bullet.target = enemies.length > 0 ? enemies[0] : boss;
}
heroBullets.push(bullet);
game.addChild(bullet);
}
} else if (hero.weaponType === 2) {
// Charge weapon
if (hero.chargeTime <= 0) {
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.setWeaponType(hero.weaponType, weapon);
heroBullets.push(bullet);
game.addChild(bullet);
hero.chargeTime = weapon.chargeTime;
}
} else {
// Normal shot
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.setWeaponType(hero.weaponType, weapon);
if (hero.weaponType === 3) {
// Homing
bullet.target = enemies.length > 0 ? enemies[0] : boss;
}
heroBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
function shootEnemyBullet(enemy) {
var bullet = new EnemyBullet();
bullet.x = enemy.x - 30;
bullet.y = enemy.y;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
}
function shootBossBullet(phase) {
if (phase === 1) {
// Single aimed shot
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
var angle = Math.atan2(hero.y - boss.y, hero.x - boss.x);
bullet.speedX = Math.cos(angle) * 10;
bullet.speedY = Math.sin(angle) * 10;
enemyBullets.push(bullet);
game.addChild(bullet);
} else if (phase === 2) {
// Spread shot
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
bullet.speedX = -8;
bullet.speedY = i * 2;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (phase === 3) {
// Circular burst
for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 4) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
bullet.speedX = Math.cos(angle) * 6;
bullet.speedY = Math.sin(angle) * 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (phase === 4) {
// Rapid multi-directional chaos
for (var i = 0; i < 8; i++) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
var angle = Math.random() * Math.PI * 2;
bullet.speedX = Math.cos(angle) * (8 + Math.random() * 4);
bullet.speedY = Math.sin(angle) * (8 + Math.random() * 4);
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
LK.getSound('enemyShoot').play();
}
// Game update
game.update = function () {
if (!gameStarted) {
return;
}
// Update health bar
healthBar.scale.x = hero.health / hero.maxHealth;
// Update perry cooldown display
if (hero.perryCooldown > 0) {
var cooldownSeconds = Math.ceil(hero.perryCooldown / 60);
perryCooldownTxt.setText('Cooldown: ' + cooldownSeconds + 's');
} else {
perryCooldownTxt.setText('');
}
// Update background clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].x -= 0.5;
if (clouds[i].x < -100) {
clouds[i].x = 2048 + 100;
clouds[i].y = 200 + Math.random() * 1000;
}
}
// Spawn enemies
if (!boss && enemiesSpawned < enemiesPerLevel) {
spawnCooldown++;
var spawnRate = Math.max(60, 120 - currentLevel * 2); // Faster spawns at higher levels
if (spawnCooldown >= spawnRate) {
spawnCooldown = 0;
spawnEnemy();
enemiesSpawned++;
}
}
// Update parry window
if (parryWindow && parryWindowTimer > 0) {
parryWindowTimer--;
if (parryWindowTimer === 0) {
parryWindow = false;
hero.endParry();
}
}
// Check for next level
if (!boss && enemiesSpawned >= enemiesPerLevel && enemies.length === 0) {
currentLevel++;
enemiesSpawned = 0;
enemiesPerLevel = Math.min(20, 10 + Math.floor(currentLevel / 5));
// Change weapon every 3 levels
if ((currentLevel - 1) % 3 === 0 && currentLevel > 1) {
var newWeaponIndex = Math.floor((currentLevel - 1) / 3) % weaponTypes.length;
hero.setWeapon(newWeaponIndex);
weaponTxt.setText('Weapon: ' + weaponTypes[hero.weaponType].name);
// Make enemies stronger when weapon changes
var strengthMultiplier = 1 + Math.floor((currentLevel - 1) / 3) * 0.3;
for (var enemyType in enemyTypesPerLevel) {
enemyTypesPerLevel[enemyType].health = Math.floor(enemyTypesPerLevel[enemyType].health * strengthMultiplier);
enemyTypesPerLevel[enemyType].speed = enemyTypesPerLevel[enemyType].speed * (1 + strengthMultiplier * 0.1);
}
}
if (currentLevel > 50) {
// Win condition
LK.showYouWin();
} else if (currentLevel % 10 === 0) {
// Boss level
spawnBoss();
} else {
// Normal level
levelTxt.setText('Level ' + currentLevel);
levelTxt.alpha = 1;
levelBg.alpha = 0.9;
tween(levelTxt, {
alpha: 0
}, {
duration: 2000
});
tween(levelBg, {
alpha: 0
}, {
duration: 2000
});
}
}
// Hero shooting
if (hero.canShoot()) {
shootHeroBullet();
}
// Update hero bullets
for (var i = heroBullets.length - 1; i >= 0; i--) {
var bullet = heroBullets[i];
if (bullet.x > 2048 + 50) {
bullet.destroy();
heroBullets.splice(i, 1);
continue;
}
// Check enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
heroBullets.splice(i, 1);
break;
}
}
// Check boss collision
if (boss && bullet.intersects(boss)) {
if (boss.takeDamage(bullet.damage)) {
// Boss destroyed
LK.setScore(LK.getScore() + boss.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(boss.x, boss.y);
boss.destroy();
boss = null;
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
heroBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -50) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
if (enemy.update()) {
shootEnemyBullet(enemy);
}
// Check collision with hero
if (enemy.intersects(hero)) {
if (hero.takeDamage()) {
LK.showGameOver();
}
enemy.destroy();
enemies.splice(i, 1);
LK.getSound('hit').play();
}
}
// Update boss
if (boss) {
var phase = boss.update();
if (phase > 0) {
shootBossBullet(phase);
}
// Check collision with hero
if (boss.intersects(hero)) {
if (hero.takeDamage()) {
LK.showGameOver();
}
LK.getSound('hit').play();
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < -50 || bullet.x > 2048 + 50 || bullet.y < -50 || bullet.y > 2732 + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with hero
if (bullet.intersects(hero)) {
if (parryWindow && bullet.canBeParried && !bullet.parried) {
// Successful parry!
bullet.parried = true;
bullet.speedX *= -2;
bullet.speedY *= -0.5;
bullet.tint = weaponTypes[hero.weaponType].parryColor;
LK.setScore(LK.getScore() + 50);
scoreTxt.setText('Score: ' + LK.getScore());
// Apply parry effect
var effect = weaponTypes[hero.weaponType].parryEffect;
if (effect === 'heal' && hero.health < hero.maxHealth) {
hero.health++;
} else if (effect === 'explode') {
LK.effects.flashScreen(weaponTypes[hero.weaponType].parryColor, 200);
// Damage all enemies
for (var j = 0; j < enemies.length; j++) {
enemies[j].takeDamage(1);
}
} else if (effect === 'freeze') {
// Slow all enemies temporarily
for (var j = 0; j < enemies.length; j++) {
enemies[j].speed *= 0.5;
}
}
} else if (!bullet.parried) {
if (hero.takeDamage()) {
LK.showGameOver();
}
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
}
}
// Check parried bullets hitting enemies
if (bullet.parried) {
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(2)) {
LK.setScore(LK.getScore() + enemy.points * 2);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
enemyBullets.splice(i, 1);
break;
}
}
// Check boss collision
if (boss && bullet.intersects(boss)) {
if (boss.takeDamage(2)) {
LK.setScore(LK.getScore() + boss.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(boss.x, boss.y);
boss.destroy();
boss = null;
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (powerup.x < -50) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with hero
if (powerup.intersects(hero)) {
hero.applyPowerup(powerup.type);
powerup.destroy();
powerups.splice(i, 1);
LK.getSound('powerupCollect').play();
}
}
// Update perry collectibles
for (var i = perryCollectibles.length - 1; i >= 0; i--) {
var perryCollectible = perryCollectibles[i];
if (perryCollectible.x < -50) {
perryCollectible.destroy();
perryCollectibles.splice(i, 1);
continue;
}
// Check collision with hero
if (perryCollectible.intersects(hero)) {
hero.collectPerry();
perryTxt.setText('Perry: ' + hero.perryCharges);
perryCollectible.destroy();
perryCollectibles.splice(i, 1);
LK.getSound('powerupCollect').play();
}
}
};
// Start music
LK.playMusic('bgMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.bossLevel = 1;
self.health = 20;
self.maxHealth = 20;
self.speed = 3;
self.direction = 1;
self.shootCooldown = 0;
self.shootInterval = 45;
self.phase = 1;
self.points = 1000;
self.setBossLevel = function (level) {
self.bossLevel = Math.floor(level / 10);
self.health = 30 + self.bossLevel * 20;
self.maxHealth = self.health;
self.points = 1000 * (self.bossLevel + 1);
bossGraphics.scale.x = 1 + self.bossLevel * 0.2;
bossGraphics.scale.y = 1 + self.bossLevel * 0.2;
};
self.update = function () {
// Boss movement pattern
self.y += self.speed * self.direction;
if (self.y > 600 || self.y < 300) {
self.direction *= -1;
}
// More complex movement for higher level bosses
if (self.bossLevel >= 2) {
self.x += Math.sin(LK.ticks * 0.02) * 2;
}
self.shootCooldown++;
// Different attack patterns based on phase
if (self.health < self.maxHealth * 0.5 && self.phase === 1) {
self.phase = 2;
self.shootInterval = 30;
}
if (self.health < self.maxHealth * 0.25 && self.phase === 2 && self.bossLevel >= 2) {
self.phase = 3;
self.shootInterval = 20;
}
if (self.health < self.maxHealth * 0.1 && self.phase === 3 && self.bossLevel >= 4) {
self.phase = 4;
self.shootInterval = 15;
}
if (self.shootCooldown >= self.shootInterval) {
self.shootCooldown = 0;
return self.phase; // Return phase for different bullet patterns
}
return 0;
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // Boss destroyed
}
tween(bossGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
bossGraphics.tint = 0xffffff;
}
});
bossGraphics.tint = 0xff0000;
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.enemyType = 'basic';
self.health = 2;
self.speed = -2;
self.shootCooldown = 0;
self.shootInterval = 120;
self.points = 100;
self.pattern = 0;
self.setType = function (type) {
self.enemyType = type;
var stats = enemyTypesPerLevel[type];
self.health = stats.health;
self.speed = stats.speed;
self.shootInterval = stats.shootInterval;
enemyGraphics.tint = stats.color;
self.points = stats.health * 50;
};
self.update = function () {
self.x += self.speed;
// Different movement patterns for different enemy types
if (self.enemyType === 'fast') {
self.y += Math.sin(self.x * 0.01) * 2;
} else if (self.enemyType === 'sniper' && self.x < 1500) {
self.speed = 0;
}
self.shootCooldown++;
if (self.shootCooldown >= self.shootInterval) {
self.shootCooldown = 0;
return true; // Signal to shoot
}
return false;
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // Enemy destroyed
}
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
enemyGraphics.tint = enemyTypesPerLevel[self.enemyType].color;
}
});
enemyGraphics.tint = 0xff0000;
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = -8;
self.speedY = 0;
self.canBeParried = false;
self.parried = false;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Make bullets parryable when they're pink
if (!self.canBeParried && Math.random() < 0.3) {
self.canBeParried = true;
bulletGraphics.tint = 0xff00ff;
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.hand = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0.5,
x: 270,
y: -5
});
self.handBaseY = -15;
self.handAnimating = false;
self.health = 3;
self.maxHealth = 3;
self.shootCooldown = 0;
self.shootInterval = 20;
self.invulnerable = 0;
self.powerupTime = 0;
self.powerupType = null;
self.weaponType = 0;
self.chargeTime = 0;
self.isParrying = false;
self.parryIndicator = null;
self.originalTint = 0xffffff;
self.isPowerupFlashing = false;
self.perryCharges = 3; // Start with 3 perrys
self.perryEffect = null;
self.perryActive = false;
self.perryCooldown = 0;
self.perryMaxCooldown = 300; // 5 seconds at 60fps
self.tapIndicator = null;
self.tapBg = null;
self.shieldActive = false;
self.shieldTime = 0;
self.update = function () {
if (self.invulnerable > 0) {
self.invulnerable--;
self.alpha = Math.sin(self.invulnerable * 0.3) > 0 ? 1 : 0.5;
} else {
self.alpha = 1;
}
if (self.powerupTime > 0) {
self.powerupTime--;
// Flash between powerup color and original color in the last 2 seconds
if (self.powerupTime <= 120 && !self.isPowerupFlashing) {
self.isPowerupFlashing = true;
self.startPowerupFlash();
}
if (self.powerupTime === 0) {
self.powerupType = null;
self.shootInterval = 20;
heroGraphics.tint = self.originalTint;
self.isPowerupFlashing = false;
}
}
self.shootCooldown++;
// Update charge for charge weapon
if (self.weaponType === 2 && self.chargeTime > 0) {
self.chargeTime--;
}
// Update perry cooldown (weapon-specific for level 10 weapon)
if (self.perryCooldown > 0) {
self.perryCooldown--;
}
// Update shield timer
if (self.shieldTime > 0) {
self.shieldTime--;
if (self.shieldTime === 0) {
self.shieldActive = false;
}
}
};
self.takeDamage = function () {
if (self.invulnerable > 0) {
return false;
}
// Check if shield is active and blocks damage
if (self.shieldActive) {
self.shieldActive = false;
self.shieldTime = 0;
LK.effects.flashObject(self, 0x00ff00, 300);
return false; // Damage blocked by shield
}
self.health--;
self.invulnerable = 120; // 2 seconds of invulnerability
if (self.health <= 0) {
return true; // Hero destroyed
}
LK.effects.flashObject(self, 0xff0000, 500);
return false;
};
self.canShoot = function () {
var weapon = weaponTypes[self.weaponType];
var interval = self.shootInterval;
if (weapon.fireRate) {
interval = weapon.fireRate;
}
if (self.shootCooldown >= interval) {
self.shootCooldown = 0;
return true;
}
return false;
};
self.applyPowerup = function (type) {
self.powerupType = type;
self.powerupTime = 600; // 10 seconds
self.isPowerupFlashing = false;
// Change hero color based on powerup type
var powerupColor = type === 'rapid' ? 0xff00ff : 0x00ffff;
heroGraphics.tint = powerupColor;
if (type === 'rapid') {
self.shootInterval = 10;
}
};
self.startPowerupFlash = function () {
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
flashCount++;
if (flashCount % 2 === 0) {
heroGraphics.tint = self.originalTint;
} else {
var powerupColor = self.powerupType === 'rapid' ? 0xff00ff : 0x00ffff;
heroGraphics.tint = powerupColor;
}
if (self.powerupTime === 0) {
LK.clearInterval(flashInterval);
heroGraphics.tint = self.originalTint;
}
}, 200); // Flash every 200ms
};
self.setWeapon = function (weaponIndex) {
self.weaponType = weaponIndex;
};
self.startParry = function () {
if (!self.isParrying && !self.parryIndicator) {
self.isParrying = true;
self.parryIndicator = self.attachAsset('parryIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.parryIndicator.alpha = 0.5;
self.parryIndicator.tint = weaponTypes[self.weaponType].parryColor;
}
};
self.endParry = function () {
self.isParrying = false;
if (self.parryIndicator) {
self.parryIndicator.destroy();
self.parryIndicator = null;
}
};
self.animateHandShoot = function () {
if (!self.handAnimating) {
self.handAnimating = true;
tween(self.hand, {
y: self.handBaseY - 20
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.hand, {
y: self.handBaseY
}, {
duration: 100,
onFinish: function onFinish() {
self.handAnimating = false;
}
});
}
});
}
};
self.activatePerry = function () {
if (self.perryCharges > 0 && !self.perryActive && self.perryCooldown === 0) {
self.perryCharges--;
self.perryActive = true;
// Set weapon-specific cooldown (4.5 seconds for Homing weapon at 60fps)
if (self.weaponType === 3) {
// Homing weapon
self.perryCooldown = 270; // 4.5 seconds at 60fps
} else {
self.perryCooldown = self.perryMaxCooldown; // Default cooldown
}
var weapon = weaponTypes[self.weaponType];
// Create perry effect visual
self.perryEffect = self.attachAsset('perryEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.perryEffect.tint = weapon.parryColor;
// Weapon-specific animations and effects
if (weapon.name === 'Spread') {
// Freeze all enemies briefly
self.performSpreadPerry();
} else if (weapon.name === 'Rapid') {
// Multi-hit explosion
self.performRapidPerry();
} else if (weapon.name === 'Charge') {
// Piercing beam attack
self.performChargePerry();
} else if (weapon.name === 'Homing') {
// Healing wave
self.performHomingPerry();
} else if (weapon.name === 'Bounce') {
// Multi-directional attack
self.performBouncePerry();
}
// Animate perry effect
tween(self.perryEffect, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
if (self.perryEffect) {
self.perryEffect.destroy();
self.perryEffect = null;
}
self.perryActive = false;
}
});
// Hand animation for perry
tween(self.hand, {
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI / 4
}, {
duration: 200,
onFinish: function onFinish() {
tween(self.hand, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 200
});
}
});
}
};
self.performSpreadPerry = function () {
// Freeze all enemies for 2 seconds
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var originalSpeed = enemy.speed;
enemy.speed = 0;
tween(enemy, {
tint: 0x00ffff
}, {
duration: 2000,
onFinish: function onFinish() {
enemy.speed = originalSpeed;
enemy.tint = enemyTypesPerLevel[enemy.enemyType].color;
}
});
}
if (boss) {
var originalSpeed = boss.speed;
boss.speed = 0;
tween(boss, {
tint: 0x00ffff
}, {
duration: 2000,
onFinish: function onFinish() {
boss.speed = originalSpeed;
boss.tint = 0xffffff;
}
});
}
};
self.performRapidPerry = function () {
// Damage all enemies with explosion effect
LK.effects.flashScreen(0xff00ff, 500);
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.takeDamage(3)) {
LK.setScore(LK.getScore() + enemy.points * 2);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
if (boss) {
boss.takeDamage(5);
}
};
self.performChargePerry = function () {
// Create piercing beam that hits all enemies in line
var beamY = self.y;
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (Math.abs(enemy.y - beamY) < 50) {
if (enemy.takeDamage(4)) {
LK.setScore(LK.getScore() + enemy.points * 2);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
if (boss && Math.abs(boss.y - beamY) < 75) {
boss.takeDamage(8);
}
// Visual beam effect
LK.effects.flashScreen(0xffff00, 300);
};
self.performHomingPerry = function () {
// Activate shield for 1.5 seconds
self.shieldActive = true;
self.shieldTime = 90; // 1.5 seconds at 60fps
// Visual shield effect
LK.effects.flashObject(self, 0x00ff00, 1500);
// Damage nearby enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < 300) {
if (enemy.takeDamage(2)) {
LK.setScore(LK.getScore() + enemy.points);
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
if (boss) {
var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2));
if (distance < 400) {
boss.takeDamage(3);
}
}
};
self.performBouncePerry = function () {
// Create multiple bouncing attacks
for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 4) {
var bullet = new HeroBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.speed = 12;
bullet.damage = 3;
bullet.bounces = 3;
bullet.speedX = Math.cos(angle) * bullet.speed;
bullet.speedY = Math.sin(angle) * bullet.speed;
bullet.setWeaponType(4, weaponTypes[4]);
heroBullets.push(bullet);
game.addChild(bullet);
}
};
self.collectPerry = function () {
self.perryCharges++;
};
self.down = function (x, y, obj) {
// Create tap indicator text with background
if (!self.tapIndicator) {
// Create background for tap text
self.tapBg = self.attachAsset('textBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.9
});
// Create tap text
self.tapIndicator = new Text2('Tap!', {
size: 45,
fill: 0xffff00
});
self.tapIndicator.anchor.set(0.5, 0.5);
self.tapIndicator.x = 0;
self.tapIndicator.y = -120;
self.addChild(self.tapIndicator);
// Animate text with tween
tween(self.tapIndicator, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.tapIndicator, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
// Activate parry and remove tap indicator
self.activatePerry();
perryTxt.setText('Perry: ' + self.perryCharges);
// Remove tap indicator and background after animation
LK.setTimeout(function () {
if (self.tapIndicator) {
tween(self.tapIndicator, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.tapIndicator.destroy();
self.tapIndicator = null;
}
});
}
if (self.tapBg) {
tween(self.tapBg, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.tapBg.destroy();
self.tapBg = null;
}
});
}
}, 500);
}
};
return self;
});
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1;
self.weaponType = 0;
self.target = null;
self.bounces = 0;
self.pierce = false;
self.setWeaponType = function (type, weapon) {
self.weaponType = type;
bulletGraphics.tint = weapon.parryColor;
if (type === 2) {
// Charge weapon
self.damage = 2;
bulletGraphics.scale.x = 1.5;
bulletGraphics.scale.y = 1.5;
} else if (type === 4) {
// Bounce weapon
self.bounces = weapon.bounceCount;
}
};
self.update = function () {
if (self.weaponType === 3 && self.target && !self.target.destroyed) {
// Homing
var angle = Math.atan2(self.target.y - self.y, self.target.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else if (self.speedX !== undefined && self.speedY !== undefined) {
// Perry bouncing bullets
self.x += self.speedX;
self.y += self.speedY;
// Bounce off screen edges
if (self.bounces > 0 && (self.y < 100 || self.y > 2632)) {
self.speedY *= -1;
self.bounces--;
}
} else {
self.x += self.speed;
}
};
return self;
});
var PerryCollectible = Container.expand(function () {
var self = Container.call(this);
var perryGraphics = self.attachAsset('perryEffect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
self.speed = -3;
self.update = function () {
self.x += self.speed;
self.rotation += 0.03;
// Floating animation
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() > 0.5 ? 'rapid' : 'triple';
self.speed = -3;
self.update = function () {
self.x += self.speed;
self.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
game.setBackgroundColor(0x1a1a2e);
// Background layers
var backgroundLayer1 = LK.getAsset('background1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 1.0
});
game.addChild(backgroundLayer1);
var backgroundLayer2 = LK.getAsset('background2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 1.0
});
game.addChild(backgroundLayer2);
// Clouds array for parallax effect
var clouds = [];
for (var i = 0; i < 8; i++) {
var cloud = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: 200 + Math.random() * 1000,
alpha: 0.1 + Math.random() * 0.1
});
clouds.push(cloud);
game.addChild(cloud);
}
// Game variables
var hero;
var heroBullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var perryCollectibles = [];
var boss = null;
var currentLevel = 9;
var enemiesSpawned = 0;
var enemiesPerLevel = 10;
var spawnCooldown = 0;
var gameStarted = false;
var isDragging = false;
var dragOffsetY = 0;
var parryWindow = false;
var parryWindowTimer = 0;
// Weapon types with different parry mechanics
var weaponTypes = [{
name: 'Spread',
bulletCount: 3,
fireRate: 25,
parryColor: 0x00ffff,
parryEffect: 'freeze'
}, {
name: 'Rapid',
fireRate: 15,
parryColor: 0xff00ff,
parryEffect: 'explode'
}, {
name: 'Charge',
chargeTime: 45,
fireRate: 60,
parryColor: 0xffff00,
parryEffect: 'pierce'
}, {
name: 'Homing',
homingStrength: 0.1,
fireRate: 30,
parryColor: 0x00ff00,
parryEffect: 'heal'
}, {
name: 'Bounce',
bounceCount: 2,
fireRate: 35,
parryColor: 0xff0000,
parryEffect: 'multi'
}];
var currentWeapon = 0;
// Enemy types per level range (base values)
var enemyTypesBase = {
basic: {
health: 2,
speed: -2,
shootInterval: 120,
color: 0xff4444
},
fast: {
health: 1,
speed: -4,
shootInterval: 80,
color: 0xff8844
},
heavy: {
health: 4,
speed: -1,
shootInterval: 150,
color: 0x884444
},
sniper: {
health: 2,
speed: -1.5,
shootInterval: 180,
color: 0x4444ff
},
burst: {
health: 3,
speed: -2.5,
shootInterval: 100,
color: 0xff44ff
}
};
// Current enemy stats (will be modified based on weapon changes)
var enemyTypesPerLevel = {
basic: {
health: 2,
speed: -2,
shootInterval: 120,
color: 0xff4444
},
fast: {
health: 1,
speed: -4,
shootInterval: 80,
color: 0xff8844
},
heavy: {
health: 4,
speed: -1,
shootInterval: 150,
color: 0x884444
},
sniper: {
health: 2,
speed: -1.5,
shootInterval: 180,
color: 0x4444ff
},
burst: {
health: 3,
speed: -2.5,
shootInterval: 100,
color: 0xff44ff
}
};
// Ground
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100
});
game.addChild(ground);
// Hero
hero = new Hero();
hero.x = 200;
hero.y = 2732 - 200;
game.addChild(hero);
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
// Health display
var healthContainer = new Container();
LK.gui.topRight.addChild(healthContainer);
healthContainer.x = -120;
healthContainer.y = 40;
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthContainer.addChild(healthBarBg);
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: -100
});
healthContainer.addChild(healthBar);
// Level text background
var levelBg = LK.getAsset('levelBg', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
LK.gui.center.addChild(levelBg);
// Level text
var levelTxt = new Text2('Level 1', {
size: 80,
fill: 0xFFFF00
});
levelTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelTxt);
levelTxt.alpha = 0;
// Weapon text background
var weaponBg = LK.getAsset('textBg', {
anchorX: 0,
anchorY: 0,
x: 20,
y: 120,
alpha: 1.0,
scaleX: 1.3
});
LK.gui.topLeft.addChild(weaponBg);
// Weapon text
var weaponTxt = new Text2('Weapon: Spread', {
size: 50,
fill: 0xFFFFFF
});
weaponTxt.anchor.set(0, 0);
weaponTxt.x = 35;
weaponTxt.y = 145;
LK.gui.topLeft.addChild(weaponTxt);
// Perry charges text background
var perryBg = LK.getAsset('textBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0
});
LK.gui.topLeft.addChild(perryBg);
// Perry charges text
var perryTxt = new Text2('Perry: 3', {
size: 45,
fill: 0xff6600
});
perryTxt.anchor.set(0, 0);
perryTxt.x = 35;
perryTxt.y = 205;
LK.gui.topLeft.addChild(perryTxt);
// Perry cooldown text
var perryCooldownTxt = new Text2('', {
size: 35,
fill: 0xffaa00
});
perryCooldownTxt.anchor.set(0, 0);
perryCooldownTxt.x = 20;
perryCooldownTxt.y = 270;
LK.gui.topLeft.addChild(perryCooldownTxt);
// Touch controls
game.down = function (x, y, obj) {
var heroGlobalPos = hero.toGlobal({
x: 0,
y: 0
});
var localPos = game.toLocal(heroGlobalPos);
if (Math.abs(x - localPos.x) < 100 && Math.abs(y - localPos.y) < 100) {
isDragging = true;
dragOffsetY = y - hero.y;
gameStarted = true;
} else if (x > 1024) {
// Right side tap for parry
parryWindow = true;
parryWindowTimer = 20; // 1/3 second parry window
hero.startParry();
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
game.move = function (x, y, obj) {
if (isDragging) {
hero.y = Math.max(300, Math.min(2732 - 200, y - dragOffsetY));
}
};
// Helper functions
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = 2048 + 50;
enemy.y = 300 + Math.random() * (2732 - 600);
// Choose enemy type based on level
var types = ['basic'];
if (currentLevel >= 5) {
types.push('fast');
}
if (currentLevel >= 10) {
types.push('heavy');
}
if (currentLevel >= 15) {
types.push('sniper');
}
if (currentLevel >= 20) {
types.push('burst');
}
var randomType = types[Math.floor(Math.random() * types.length)];
enemy.setType(randomType);
enemies.push(enemy);
game.addChild(enemy);
}
function spawnBoss() {
boss = new Boss();
boss.x = 2048 - 200;
boss.y = 450;
boss.setBossLevel(currentLevel);
game.addChild(boss);
// Show boss warning
levelTxt.setText('BOSS LEVEL ' + currentLevel + '!');
levelTxt.alpha = 1;
levelBg.alpha = 0.9;
tween(levelTxt, {
alpha: 0
}, {
duration: 2000
});
tween(levelBg, {
alpha: 0
}, {
duration: 2000
});
}
function spawnPowerup(x, y) {
if (Math.random() < 0.08) {
// 8% chance for perry collectible
var perryCollectible = new PerryCollectible();
perryCollectible.x = x;
perryCollectible.y = y;
perryCollectibles.push(perryCollectible);
game.addChild(perryCollectible);
} else if (Math.random() < 0.1) {
// 10% chance for regular powerup
var powerup = new PowerUp();
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
}
function shootHeroBullet() {
var weapon = weaponTypes[hero.weaponType];
hero.animateHandShoot();
var bulletStartX = hero.x + hero.hand.x;
var bulletStartY = hero.y + hero.hand.y;
if (hero.weaponType === 0 || hero.powerupType === 'triple') {
// Spread weapon
// Triple shot
for (var i = -1; i <= 1; i++) {
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY + i * 30;
bullet.setWeaponType(hero.weaponType, weapon);
if (hero.weaponType === 3) {
// Homing
bullet.target = enemies.length > 0 ? enemies[0] : boss;
}
heroBullets.push(bullet);
game.addChild(bullet);
}
} else if (hero.weaponType === 2) {
// Charge weapon
if (hero.chargeTime <= 0) {
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.setWeaponType(hero.weaponType, weapon);
heroBullets.push(bullet);
game.addChild(bullet);
hero.chargeTime = weapon.chargeTime;
}
} else {
// Normal shot
var bullet = new HeroBullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.setWeaponType(hero.weaponType, weapon);
if (hero.weaponType === 3) {
// Homing
bullet.target = enemies.length > 0 ? enemies[0] : boss;
}
heroBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
function shootEnemyBullet(enemy) {
var bullet = new EnemyBullet();
bullet.x = enemy.x - 30;
bullet.y = enemy.y;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
}
function shootBossBullet(phase) {
if (phase === 1) {
// Single aimed shot
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
var angle = Math.atan2(hero.y - boss.y, hero.x - boss.x);
bullet.speedX = Math.cos(angle) * 10;
bullet.speedY = Math.sin(angle) * 10;
enemyBullets.push(bullet);
game.addChild(bullet);
} else if (phase === 2) {
// Spread shot
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
bullet.speedX = -8;
bullet.speedY = i * 2;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (phase === 3) {
// Circular burst
for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 4) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
bullet.speedX = Math.cos(angle) * 6;
bullet.speedY = Math.sin(angle) * 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (phase === 4) {
// Rapid multi-directional chaos
for (var i = 0; i < 8; i++) {
var bullet = new EnemyBullet();
bullet.x = boss.x - 75;
bullet.y = boss.y;
var angle = Math.random() * Math.PI * 2;
bullet.speedX = Math.cos(angle) * (8 + Math.random() * 4);
bullet.speedY = Math.sin(angle) * (8 + Math.random() * 4);
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
LK.getSound('enemyShoot').play();
}
// Game update
game.update = function () {
if (!gameStarted) {
return;
}
// Update health bar
healthBar.scale.x = hero.health / hero.maxHealth;
// Update perry cooldown display
if (hero.perryCooldown > 0) {
var cooldownSeconds = Math.ceil(hero.perryCooldown / 60);
perryCooldownTxt.setText('Cooldown: ' + cooldownSeconds + 's');
} else {
perryCooldownTxt.setText('');
}
// Update background clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].x -= 0.5;
if (clouds[i].x < -100) {
clouds[i].x = 2048 + 100;
clouds[i].y = 200 + Math.random() * 1000;
}
}
// Spawn enemies
if (!boss && enemiesSpawned < enemiesPerLevel) {
spawnCooldown++;
var spawnRate = Math.max(60, 120 - currentLevel * 2); // Faster spawns at higher levels
if (spawnCooldown >= spawnRate) {
spawnCooldown = 0;
spawnEnemy();
enemiesSpawned++;
}
}
// Update parry window
if (parryWindow && parryWindowTimer > 0) {
parryWindowTimer--;
if (parryWindowTimer === 0) {
parryWindow = false;
hero.endParry();
}
}
// Check for next level
if (!boss && enemiesSpawned >= enemiesPerLevel && enemies.length === 0) {
currentLevel++;
enemiesSpawned = 0;
enemiesPerLevel = Math.min(20, 10 + Math.floor(currentLevel / 5));
// Change weapon every 3 levels
if ((currentLevel - 1) % 3 === 0 && currentLevel > 1) {
var newWeaponIndex = Math.floor((currentLevel - 1) / 3) % weaponTypes.length;
hero.setWeapon(newWeaponIndex);
weaponTxt.setText('Weapon: ' + weaponTypes[hero.weaponType].name);
// Make enemies stronger when weapon changes
var strengthMultiplier = 1 + Math.floor((currentLevel - 1) / 3) * 0.3;
for (var enemyType in enemyTypesPerLevel) {
enemyTypesPerLevel[enemyType].health = Math.floor(enemyTypesPerLevel[enemyType].health * strengthMultiplier);
enemyTypesPerLevel[enemyType].speed = enemyTypesPerLevel[enemyType].speed * (1 + strengthMultiplier * 0.1);
}
}
if (currentLevel > 50) {
// Win condition
LK.showYouWin();
} else if (currentLevel % 10 === 0) {
// Boss level
spawnBoss();
} else {
// Normal level
levelTxt.setText('Level ' + currentLevel);
levelTxt.alpha = 1;
levelBg.alpha = 0.9;
tween(levelTxt, {
alpha: 0
}, {
duration: 2000
});
tween(levelBg, {
alpha: 0
}, {
duration: 2000
});
}
}
// Hero shooting
if (hero.canShoot()) {
shootHeroBullet();
}
// Update hero bullets
for (var i = heroBullets.length - 1; i >= 0; i--) {
var bullet = heroBullets[i];
if (bullet.x > 2048 + 50) {
bullet.destroy();
heroBullets.splice(i, 1);
continue;
}
// Check enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
heroBullets.splice(i, 1);
break;
}
}
// Check boss collision
if (boss && bullet.intersects(boss)) {
if (boss.takeDamage(bullet.damage)) {
// Boss destroyed
LK.setScore(LK.getScore() + boss.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(boss.x, boss.y);
boss.destroy();
boss = null;
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
heroBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -50) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
if (enemy.update()) {
shootEnemyBullet(enemy);
}
// Check collision with hero
if (enemy.intersects(hero)) {
if (hero.takeDamage()) {
LK.showGameOver();
}
enemy.destroy();
enemies.splice(i, 1);
LK.getSound('hit').play();
}
}
// Update boss
if (boss) {
var phase = boss.update();
if (phase > 0) {
shootBossBullet(phase);
}
// Check collision with hero
if (boss.intersects(hero)) {
if (hero.takeDamage()) {
LK.showGameOver();
}
LK.getSound('hit').play();
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < -50 || bullet.x > 2048 + 50 || bullet.y < -50 || bullet.y > 2732 + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with hero
if (bullet.intersects(hero)) {
if (parryWindow && bullet.canBeParried && !bullet.parried) {
// Successful parry!
bullet.parried = true;
bullet.speedX *= -2;
bullet.speedY *= -0.5;
bullet.tint = weaponTypes[hero.weaponType].parryColor;
LK.setScore(LK.getScore() + 50);
scoreTxt.setText('Score: ' + LK.getScore());
// Apply parry effect
var effect = weaponTypes[hero.weaponType].parryEffect;
if (effect === 'heal' && hero.health < hero.maxHealth) {
hero.health++;
} else if (effect === 'explode') {
LK.effects.flashScreen(weaponTypes[hero.weaponType].parryColor, 200);
// Damage all enemies
for (var j = 0; j < enemies.length; j++) {
enemies[j].takeDamage(1);
}
} else if (effect === 'freeze') {
// Slow all enemies temporarily
for (var j = 0; j < enemies.length; j++) {
enemies[j].speed *= 0.5;
}
}
} else if (!bullet.parried) {
if (hero.takeDamage()) {
LK.showGameOver();
}
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
}
}
// Check parried bullets hitting enemies
if (bullet.parried) {
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(2)) {
LK.setScore(LK.getScore() + enemy.points * 2);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
enemyBullets.splice(i, 1);
break;
}
}
// Check boss collision
if (boss && bullet.intersects(boss)) {
if (boss.takeDamage(2)) {
LK.setScore(LK.getScore() + boss.points);
scoreTxt.setText('Score: ' + LK.getScore());
spawnPowerup(boss.x, boss.y);
boss.destroy();
boss = null;
LK.getSound('enemyDestroy').play();
}
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (powerup.x < -50) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with hero
if (powerup.intersects(hero)) {
hero.applyPowerup(powerup.type);
powerup.destroy();
powerups.splice(i, 1);
LK.getSound('powerupCollect').play();
}
}
// Update perry collectibles
for (var i = perryCollectibles.length - 1; i >= 0; i--) {
var perryCollectible = perryCollectibles[i];
if (perryCollectible.x < -50) {
perryCollectible.destroy();
perryCollectibles.splice(i, 1);
continue;
}
// Check collision with hero
if (perryCollectible.intersects(hero)) {
hero.collectPerry();
perryTxt.setText('Perry: ' + hero.perryCharges);
perryCollectible.destroy();
perryCollectibles.splice(i, 1);
LK.getSound('powerupCollect').play();
}
}
};
// Start music
LK.playMusic('bgMusic');