/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AOEAttack = Container.expand(function () {
var self = Container.call(this);
var aoeGraphics = self.attachAsset('aoeIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.warningTime = 120;
self.activeTime = 30;
self.phase = 'warning';
aoeGraphics.alpha = 0.3;
self.update = function () {
if (self.phase === 'warning') {
self.warningTime--;
aoeGraphics.alpha = 0.3 + Math.sin(LK.ticks * 0.3) * 0.2;
if (self.warningTime <= 0) {
self.phase = 'active';
aoeGraphics.alpha = 0.8;
aoeGraphics.tint = 0xff0000;
}
} else if (self.phase === 'active') {
self.activeTime--;
if (self.activeTime <= 0) {
self.shouldDestroy = true;
}
}
};
return self;
});
var AmmoPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('ammoPickup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual effect - pulsing animation
self.pulseTimer = 0;
self.update = function () {
self.pulseTimer += 0.1;
pickupGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.2;
pickupGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.2;
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1000;
self.maxHealth = 1000;
self.phase = 1;
self.attackTimer = 0;
self.attackCooldown = 120;
self.currentAttack = 0;
self.takeDamage = function (damage) {
self.health -= damage;
// Flash effect
tween(bossGraphics, {
tint: 0xffffff
}, {
duration: 100
});
tween(bossGraphics, {
tint: 0xe74c3c
}, {
duration: 100
});
if (self.health <= 0) {
// Ensure health doesn't go below 0
self.health = 0;
LK.showYouWin();
}
// Phase transitions
if (self.health <= 750 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 90;
} else if (self.health <= 200 && self.phase === 2) {
self.phase = 3;
self.attackCooldown = 60;
} else if (self.health <= 100 && self.phase === 3) {
self.phase = 4;
self.attackCooldown = 45;
}
};
self.update = function () {
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
self.attackTimer = 0;
self.performAttack();
}
};
self.performAttack = function () {
LK.getSound('bossAttack').play();
if (self.phase === 1) {
// Simple projectile attack
self.projectileAttack();
} else if (self.phase === 2) {
// Phase 2: Original attacks plus 2 new ones
var attackType = Math.floor(Math.random() * 4);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else {
self.spiralAttack();
}
} else if (self.phase === 3) {
// All attacks randomly
var attackType = Math.floor(Math.random() * 6);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else if (attackType === 3) {
self.spiralAttack();
} else if (attackType === 4) {
self.waveAttack();
} else {
self.rapidFireAttack();
}
} else if (self.phase === 4) {
// Phase 4: All attacks with higher frequency
var attackType = Math.floor(Math.random() * 6);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else if (attackType === 3) {
self.spiralAttack();
} else if (attackType === 4) {
self.waveAttack();
} else {
self.rapidFireAttack();
}
}
};
self.projectileAttack = function () {
// Show target indicator at player position
var indicator = new TargetIndicator();
indicator.x = player.x;
indicator.y = player.y;
targetIndicators.push(indicator);
game.addChild(indicator);
// Delay the actual projectile by 1.5 seconds
LK.setTimeout(function () {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.targetX = indicator.x;
projectile.targetY = indicator.y;
projectiles.push(projectile);
game.addChild(projectile);
}, 1500);
};
self.multiProjectileAttack = function () {
for (var i = 0; i < 5; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
var angle = Math.PI * 2 * i / 5;
projectile.velocityX = Math.cos(angle) * 2.5;
projectile.velocityY = Math.sin(angle) * 2.5;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.aoeAttack = function () {
var aoe = new AOEAttack();
aoe.x = player.x;
aoe.y = player.y;
aoeAttacks.push(aoe);
game.addChild(aoe);
};
self.chargeAttack = function () {
var originalX = self.x;
var originalY = self.y;
// Show warning icon above boss
var warning = new ChargeWarning();
warning.x = self.x;
warning.y = self.y - 150;
chargeWarnings.push(warning);
game.addChild(warning);
// Wait for warning duration before charging
LK.setTimeout(function () {
tween(self, {
x: player.x,
y: player.y
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check collision with player
if (self.intersects(player)) {
player.takeDamage(15);
}
// Return to original position
tween(self, {
x: originalX,
y: originalY
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
}, 1500); // Wait 1.5 seconds (warning duration)
};
self.spiralAttack = function () {
for (var i = 0; i < 8; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
var angle = Math.PI * 2 * i / 8 + LK.ticks * 0.1;
projectile.velocityX = Math.cos(angle) * 2;
projectile.velocityY = Math.sin(angle) * 2;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.waveAttack = function () {
for (var i = 0; i < 7; i++) {
var projectile = new Projectile();
projectile.x = self.x - 200 + i * 70;
projectile.y = self.y;
projectile.velocityX = 0;
projectile.velocityY = 2.5;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.rapidFireAttack = function () {
for (var i = 0; i < 3; i++) {
// Show target indicator for each shot
var indicator = new TargetIndicator();
indicator.x = player.x;
indicator.y = player.y;
targetIndicators.push(indicator);
game.addChild(indicator);
LK.setTimeout(function () {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.targetX = indicator.x;
projectile.targetY = indicator.y;
projectiles.push(projectile);
game.addChild(projectile);
}, i * 200 + 1500); // Add 1.5 second delay after indicator
}
};
return self;
});
var ChargeWarning = Container.expand(function () {
var self = Container.call(this);
var warningGraphics = self.attachAsset('chargeWarning', {
anchorX: 0.5,
anchorY: 0.5
});
self.duration = 60; // Show warning for 1 second (60 frames)
self.pulseTimer = 0;
self.update = function () {
self.duration--;
self.pulseTimer += 0.3;
// Pulsing effect
warningGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.3;
warningGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.3;
if (self.duration <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var FireButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual feedback
self.isPressed = false;
self.down = function (x, y, obj) {
if (!self.isPressed && player.attackCooldown <= 0) {
self.isPressed = true;
buttonGraphics.scaleX = 0.9;
buttonGraphics.scaleY = 0.9;
buttonGraphics.tint = 0xff4500;
// Fire bullet
var bullet = new PlayerBullet();
bullet.x = player.x;
bullet.y = player.y;
if (boss) {
var dx = boss.x - player.x;
var dy = boss.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.velocityX = dx / distance * bullet.speed;
bullet.velocityY = dy / distance * bullet.speed;
}
playerBullets.push(bullet);
game.addChild(bullet);
if (player.ammo > 0) {
player.ammo--;
}
player.attackCooldown = 30; // 30 frames cooldown (0.5 seconds at 60fps)
LK.getSound('shoot').play();
}
}
};
self.up = function (x, y, obj) {
self.isPressed = false;
buttonGraphics.scaleX = 1.0;
buttonGraphics.scaleY = 1.0;
buttonGraphics.tint = 0xff6b35;
};
return self;
});
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('healthPickup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual effect - pulsing animation
self.pulseTimer = 0;
self.update = function () {
self.pulseTimer += 0.1;
pickupGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.3;
pickupGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.3;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 8;
self.shootCooldown = 0;
self.invulnerable = false;
self.ammo = 30;
self.maxAmmo = 30;
self.attackCooldown = 0;
self.rechargeAmmo = function () {
self.ammo = self.maxAmmo;
};
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) {
self.health = self.maxHealth;
}
};
self.takeDamage = function (damage) {
if (self.invulnerable) return;
self.health -= damage;
self.invulnerable = true;
// Flash effect
tween(playerGraphics, {
alpha: 0.3
}, {
duration: 100
});
tween(playerGraphics, {
alpha: 1
}, {
duration: 100
});
LK.getSound('hit').play();
LK.setTimeout(function () {
self.invulnerable = false;
}, 500);
if (self.health <= 0) {
LK.showGameOver();
}
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 10;
self.lifetime = 180;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = 0;
self.targetY = 0;
self.velocityX = 0;
self.velocityY = 0;
self.speed = 3;
self.lifetime = 300;
self.update = function () {
if (self.velocityX === 0 && self.velocityY === 0) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var TargetIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('targetIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.duration = 90; // Show indicator for 1.5 seconds (90 frames)
self.pulseTimer = 0;
indicatorGraphics.alpha = 0.6;
self.update = function () {
self.duration--;
self.pulseTimer += 0.2;
// Pulsing effect to make it visible
indicatorGraphics.scaleX = 0.8 + Math.sin(self.pulseTimer) * 0.3;
indicatorGraphics.scaleY = 0.8 + Math.sin(self.pulseTimer) * 0.3;
indicatorGraphics.alpha = 0.4 + Math.sin(self.pulseTimer) * 0.2;
if (self.duration <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
var arena = game.attachAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 / 2 + 300;
var boss = game.addChild(new Boss());
boss.x = 2048 / 2;
boss.y = 2732 / 2 - 300;
var projectiles = [];
var aoeAttacks = [];
var playerBullets = [];
// Arena boundaries
var arenaLeft = arena.x - arena.width / 2;
var arenaRight = arena.x + arena.width / 2;
var arenaTop = arena.y - arena.height / 2;
var arenaBottom = arena.y + arena.height / 2;
// UI
var healthText = new Text2('Health: 100', {
size: 60,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 150;
healthText.y = 50;
var bossHealthText = new Text2('Boss: 1000', {
size: 60,
fill: 0xFF0000
});
bossHealthText.anchor.set(0.5, 0);
LK.gui.top.addChild(bossHealthText);
bossHealthText.y = 50;
var ammoText = new Text2('Ammo: 30', {
size: 60,
fill: 0x00FF00
});
ammoText.anchor.set(0, 0);
LK.gui.topLeft.addChild(ammoText);
ammoText.x = 150;
ammoText.y = 120;
var dragNode = null;
var touchStartX = 0;
var touchStartY = 0;
var ammoPickups = [];
var ammoSpawnTimer = 0;
var healthPickups = [];
var healthSpawnTimer = 0;
var chargeWarnings = [];
var targetIndicators = [];
// Add fire button to GUI
var fireButton = new FireButton();
LK.gui.bottomRight.addChild(fireButton);
fireButton.x = -100;
fireButton.y = -100;
game.down = function (x, y, obj) {
dragNode = player;
touchStartX = x;
touchStartY = y;
};
game.move = function (x, y, obj) {
if (dragNode) {
var newX = x;
var newY = y;
// Clamp to arena boundaries
if (newX < arenaLeft + 40) newX = arenaLeft + 40;
if (newX > arenaRight - 40) newX = arenaRight - 40;
if (newY < arenaTop + 40) newY = arenaTop + 40;
if (newY > arenaBottom - 40) newY = arenaBottom - 40;
dragNode.x = newX;
dragNode.y = newY;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.update = function () {
// Update UI
healthText.setText('Health: ' + player.health);
ammoText.setText('Ammo: ' + player.ammo);
bossHealthText.setText('Boss: ' + boss.health);
// Spawn ammo pickups periodically
ammoSpawnTimer++;
if (ammoSpawnTimer >= 600) {
// Every 10 seconds at 60fps
ammoSpawnTimer = 0;
var pickup = new AmmoPickup();
pickup.x = arenaLeft + Math.random() * (arenaRight - arenaLeft);
pickup.y = arenaTop + Math.random() * (arenaBottom - arenaTop);
ammoPickups.push(pickup);
game.addChild(pickup);
}
// Spawn health pickups periodically
healthSpawnTimer++;
if (healthSpawnTimer >= 900) {
// Every 15 seconds at 60fps
healthSpawnTimer = 0;
var healthPickup = new HealthPickup();
healthPickup.x = arenaLeft + Math.random() * (arenaRight - arenaLeft);
healthPickup.y = arenaTop + Math.random() * (arenaBottom - arenaTop);
healthPickups.push(healthPickup);
game.addChild(healthPickup);
}
// Check ammo pickup collisions
for (var i = ammoPickups.length - 1; i >= 0; i--) {
var pickup = ammoPickups[i];
if (pickup.intersects(player)) {
player.rechargeAmmo();
pickup.destroy();
ammoPickups.splice(i, 1);
}
}
// Check health pickup collisions
for (var i = healthPickups.length - 1; i >= 0; i--) {
var healthPickup = healthPickups[i];
if (healthPickup.intersects(player)) {
player.heal(10);
healthPickup.destroy();
healthPickups.splice(i, 1);
}
}
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
if (projectile.shouldDestroy) {
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check collision with player
if (projectile.intersects(player)) {
player.takeDamage(10);
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check if out of arena
if (projectile.x < arenaLeft - 100 || projectile.x > arenaRight + 100 || projectile.y < arenaTop - 100 || projectile.y > arenaBottom + 100) {
projectile.destroy();
projectiles.splice(i, 1);
}
}
// Update AOE attacks
for (var i = aoeAttacks.length - 1; i >= 0; i--) {
var aoe = aoeAttacks[i];
if (aoe.shouldDestroy) {
aoe.destroy();
aoeAttacks.splice(i, 1);
continue;
}
// Check collision with player during active phase
if (aoe.phase === 'active' && aoe.intersects(player)) {
player.takeDamage(12);
}
}
// Update charge warnings
for (var i = chargeWarnings.length - 1; i >= 0; i--) {
var warning = chargeWarnings[i];
if (warning.shouldDestroy) {
warning.destroy();
chargeWarnings.splice(i, 1);
}
}
// Update target indicators
for (var i = targetIndicators.length - 1; i >= 0; i--) {
var indicator = targetIndicators[i];
if (indicator.shouldDestroy) {
indicator.destroy();
targetIndicators.splice(i, 1);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.shouldDestroy) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with boss
if (boss && bullet.intersects(boss)) {
// Calculate distance between player and boss
var dx = player.x - boss.x;
var dy = player.y - boss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Double damage if player is close to boss (within 200 pixels)
var damage = distance <= 200 ? 20 : 10;
boss.takeDamage(damage);
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check if out of arena
if (bullet.x < arenaLeft - 100 || bullet.x > arenaRight + 100 || bullet.y < arenaTop - 100 || bullet.y > arenaBottom + 100) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AOEAttack = Container.expand(function () {
var self = Container.call(this);
var aoeGraphics = self.attachAsset('aoeIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.warningTime = 120;
self.activeTime = 30;
self.phase = 'warning';
aoeGraphics.alpha = 0.3;
self.update = function () {
if (self.phase === 'warning') {
self.warningTime--;
aoeGraphics.alpha = 0.3 + Math.sin(LK.ticks * 0.3) * 0.2;
if (self.warningTime <= 0) {
self.phase = 'active';
aoeGraphics.alpha = 0.8;
aoeGraphics.tint = 0xff0000;
}
} else if (self.phase === 'active') {
self.activeTime--;
if (self.activeTime <= 0) {
self.shouldDestroy = true;
}
}
};
return self;
});
var AmmoPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('ammoPickup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual effect - pulsing animation
self.pulseTimer = 0;
self.update = function () {
self.pulseTimer += 0.1;
pickupGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.2;
pickupGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.2;
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1000;
self.maxHealth = 1000;
self.phase = 1;
self.attackTimer = 0;
self.attackCooldown = 120;
self.currentAttack = 0;
self.takeDamage = function (damage) {
self.health -= damage;
// Flash effect
tween(bossGraphics, {
tint: 0xffffff
}, {
duration: 100
});
tween(bossGraphics, {
tint: 0xe74c3c
}, {
duration: 100
});
if (self.health <= 0) {
// Ensure health doesn't go below 0
self.health = 0;
LK.showYouWin();
}
// Phase transitions
if (self.health <= 750 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 90;
} else if (self.health <= 200 && self.phase === 2) {
self.phase = 3;
self.attackCooldown = 60;
} else if (self.health <= 100 && self.phase === 3) {
self.phase = 4;
self.attackCooldown = 45;
}
};
self.update = function () {
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
self.attackTimer = 0;
self.performAttack();
}
};
self.performAttack = function () {
LK.getSound('bossAttack').play();
if (self.phase === 1) {
// Simple projectile attack
self.projectileAttack();
} else if (self.phase === 2) {
// Phase 2: Original attacks plus 2 new ones
var attackType = Math.floor(Math.random() * 4);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else {
self.spiralAttack();
}
} else if (self.phase === 3) {
// All attacks randomly
var attackType = Math.floor(Math.random() * 6);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else if (attackType === 3) {
self.spiralAttack();
} else if (attackType === 4) {
self.waveAttack();
} else {
self.rapidFireAttack();
}
} else if (self.phase === 4) {
// Phase 4: All attacks with higher frequency
var attackType = Math.floor(Math.random() * 6);
if (attackType === 0) {
self.multiProjectileAttack();
} else if (attackType === 1) {
self.aoeAttack();
} else if (attackType === 2) {
self.chargeAttack();
} else if (attackType === 3) {
self.spiralAttack();
} else if (attackType === 4) {
self.waveAttack();
} else {
self.rapidFireAttack();
}
}
};
self.projectileAttack = function () {
// Show target indicator at player position
var indicator = new TargetIndicator();
indicator.x = player.x;
indicator.y = player.y;
targetIndicators.push(indicator);
game.addChild(indicator);
// Delay the actual projectile by 1.5 seconds
LK.setTimeout(function () {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.targetX = indicator.x;
projectile.targetY = indicator.y;
projectiles.push(projectile);
game.addChild(projectile);
}, 1500);
};
self.multiProjectileAttack = function () {
for (var i = 0; i < 5; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
var angle = Math.PI * 2 * i / 5;
projectile.velocityX = Math.cos(angle) * 2.5;
projectile.velocityY = Math.sin(angle) * 2.5;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.aoeAttack = function () {
var aoe = new AOEAttack();
aoe.x = player.x;
aoe.y = player.y;
aoeAttacks.push(aoe);
game.addChild(aoe);
};
self.chargeAttack = function () {
var originalX = self.x;
var originalY = self.y;
// Show warning icon above boss
var warning = new ChargeWarning();
warning.x = self.x;
warning.y = self.y - 150;
chargeWarnings.push(warning);
game.addChild(warning);
// Wait for warning duration before charging
LK.setTimeout(function () {
tween(self, {
x: player.x,
y: player.y
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check collision with player
if (self.intersects(player)) {
player.takeDamage(15);
}
// Return to original position
tween(self, {
x: originalX,
y: originalY
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
}, 1500); // Wait 1.5 seconds (warning duration)
};
self.spiralAttack = function () {
for (var i = 0; i < 8; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
var angle = Math.PI * 2 * i / 8 + LK.ticks * 0.1;
projectile.velocityX = Math.cos(angle) * 2;
projectile.velocityY = Math.sin(angle) * 2;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.waveAttack = function () {
for (var i = 0; i < 7; i++) {
var projectile = new Projectile();
projectile.x = self.x - 200 + i * 70;
projectile.y = self.y;
projectile.velocityX = 0;
projectile.velocityY = 2.5;
projectiles.push(projectile);
game.addChild(projectile);
}
};
self.rapidFireAttack = function () {
for (var i = 0; i < 3; i++) {
// Show target indicator for each shot
var indicator = new TargetIndicator();
indicator.x = player.x;
indicator.y = player.y;
targetIndicators.push(indicator);
game.addChild(indicator);
LK.setTimeout(function () {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.targetX = indicator.x;
projectile.targetY = indicator.y;
projectiles.push(projectile);
game.addChild(projectile);
}, i * 200 + 1500); // Add 1.5 second delay after indicator
}
};
return self;
});
var ChargeWarning = Container.expand(function () {
var self = Container.call(this);
var warningGraphics = self.attachAsset('chargeWarning', {
anchorX: 0.5,
anchorY: 0.5
});
self.duration = 60; // Show warning for 1 second (60 frames)
self.pulseTimer = 0;
self.update = function () {
self.duration--;
self.pulseTimer += 0.3;
// Pulsing effect
warningGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.3;
warningGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.3;
if (self.duration <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var FireButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual feedback
self.isPressed = false;
self.down = function (x, y, obj) {
if (!self.isPressed && player.attackCooldown <= 0) {
self.isPressed = true;
buttonGraphics.scaleX = 0.9;
buttonGraphics.scaleY = 0.9;
buttonGraphics.tint = 0xff4500;
// Fire bullet
var bullet = new PlayerBullet();
bullet.x = player.x;
bullet.y = player.y;
if (boss) {
var dx = boss.x - player.x;
var dy = boss.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.velocityX = dx / distance * bullet.speed;
bullet.velocityY = dy / distance * bullet.speed;
}
playerBullets.push(bullet);
game.addChild(bullet);
if (player.ammo > 0) {
player.ammo--;
}
player.attackCooldown = 30; // 30 frames cooldown (0.5 seconds at 60fps)
LK.getSound('shoot').play();
}
}
};
self.up = function (x, y, obj) {
self.isPressed = false;
buttonGraphics.scaleX = 1.0;
buttonGraphics.scaleY = 1.0;
buttonGraphics.tint = 0xff6b35;
};
return self;
});
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('healthPickup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual effect - pulsing animation
self.pulseTimer = 0;
self.update = function () {
self.pulseTimer += 0.1;
pickupGraphics.scaleX = 1 + Math.sin(self.pulseTimer) * 0.3;
pickupGraphics.scaleY = 1 + Math.sin(self.pulseTimer) * 0.3;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 8;
self.shootCooldown = 0;
self.invulnerable = false;
self.ammo = 30;
self.maxAmmo = 30;
self.attackCooldown = 0;
self.rechargeAmmo = function () {
self.ammo = self.maxAmmo;
};
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) {
self.health = self.maxHealth;
}
};
self.takeDamage = function (damage) {
if (self.invulnerable) return;
self.health -= damage;
self.invulnerable = true;
// Flash effect
tween(playerGraphics, {
alpha: 0.3
}, {
duration: 100
});
tween(playerGraphics, {
alpha: 1
}, {
duration: 100
});
LK.getSound('hit').play();
LK.setTimeout(function () {
self.invulnerable = false;
}, 500);
if (self.health <= 0) {
LK.showGameOver();
}
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 10;
self.lifetime = 180;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = 0;
self.targetY = 0;
self.velocityX = 0;
self.velocityY = 0;
self.speed = 3;
self.lifetime = 300;
self.update = function () {
if (self.velocityX === 0 && self.velocityY === 0) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
var TargetIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('targetIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.duration = 90; // Show indicator for 1.5 seconds (90 frames)
self.pulseTimer = 0;
indicatorGraphics.alpha = 0.6;
self.update = function () {
self.duration--;
self.pulseTimer += 0.2;
// Pulsing effect to make it visible
indicatorGraphics.scaleX = 0.8 + Math.sin(self.pulseTimer) * 0.3;
indicatorGraphics.scaleY = 0.8 + Math.sin(self.pulseTimer) * 0.3;
indicatorGraphics.alpha = 0.4 + Math.sin(self.pulseTimer) * 0.2;
if (self.duration <= 0) {
self.shouldDestroy = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
var arena = game.attachAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 / 2 + 300;
var boss = game.addChild(new Boss());
boss.x = 2048 / 2;
boss.y = 2732 / 2 - 300;
var projectiles = [];
var aoeAttacks = [];
var playerBullets = [];
// Arena boundaries
var arenaLeft = arena.x - arena.width / 2;
var arenaRight = arena.x + arena.width / 2;
var arenaTop = arena.y - arena.height / 2;
var arenaBottom = arena.y + arena.height / 2;
// UI
var healthText = new Text2('Health: 100', {
size: 60,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 150;
healthText.y = 50;
var bossHealthText = new Text2('Boss: 1000', {
size: 60,
fill: 0xFF0000
});
bossHealthText.anchor.set(0.5, 0);
LK.gui.top.addChild(bossHealthText);
bossHealthText.y = 50;
var ammoText = new Text2('Ammo: 30', {
size: 60,
fill: 0x00FF00
});
ammoText.anchor.set(0, 0);
LK.gui.topLeft.addChild(ammoText);
ammoText.x = 150;
ammoText.y = 120;
var dragNode = null;
var touchStartX = 0;
var touchStartY = 0;
var ammoPickups = [];
var ammoSpawnTimer = 0;
var healthPickups = [];
var healthSpawnTimer = 0;
var chargeWarnings = [];
var targetIndicators = [];
// Add fire button to GUI
var fireButton = new FireButton();
LK.gui.bottomRight.addChild(fireButton);
fireButton.x = -100;
fireButton.y = -100;
game.down = function (x, y, obj) {
dragNode = player;
touchStartX = x;
touchStartY = y;
};
game.move = function (x, y, obj) {
if (dragNode) {
var newX = x;
var newY = y;
// Clamp to arena boundaries
if (newX < arenaLeft + 40) newX = arenaLeft + 40;
if (newX > arenaRight - 40) newX = arenaRight - 40;
if (newY < arenaTop + 40) newY = arenaTop + 40;
if (newY > arenaBottom - 40) newY = arenaBottom - 40;
dragNode.x = newX;
dragNode.y = newY;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.update = function () {
// Update UI
healthText.setText('Health: ' + player.health);
ammoText.setText('Ammo: ' + player.ammo);
bossHealthText.setText('Boss: ' + boss.health);
// Spawn ammo pickups periodically
ammoSpawnTimer++;
if (ammoSpawnTimer >= 600) {
// Every 10 seconds at 60fps
ammoSpawnTimer = 0;
var pickup = new AmmoPickup();
pickup.x = arenaLeft + Math.random() * (arenaRight - arenaLeft);
pickup.y = arenaTop + Math.random() * (arenaBottom - arenaTop);
ammoPickups.push(pickup);
game.addChild(pickup);
}
// Spawn health pickups periodically
healthSpawnTimer++;
if (healthSpawnTimer >= 900) {
// Every 15 seconds at 60fps
healthSpawnTimer = 0;
var healthPickup = new HealthPickup();
healthPickup.x = arenaLeft + Math.random() * (arenaRight - arenaLeft);
healthPickup.y = arenaTop + Math.random() * (arenaBottom - arenaTop);
healthPickups.push(healthPickup);
game.addChild(healthPickup);
}
// Check ammo pickup collisions
for (var i = ammoPickups.length - 1; i >= 0; i--) {
var pickup = ammoPickups[i];
if (pickup.intersects(player)) {
player.rechargeAmmo();
pickup.destroy();
ammoPickups.splice(i, 1);
}
}
// Check health pickup collisions
for (var i = healthPickups.length - 1; i >= 0; i--) {
var healthPickup = healthPickups[i];
if (healthPickup.intersects(player)) {
player.heal(10);
healthPickup.destroy();
healthPickups.splice(i, 1);
}
}
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
if (projectile.shouldDestroy) {
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check collision with player
if (projectile.intersects(player)) {
player.takeDamage(10);
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check if out of arena
if (projectile.x < arenaLeft - 100 || projectile.x > arenaRight + 100 || projectile.y < arenaTop - 100 || projectile.y > arenaBottom + 100) {
projectile.destroy();
projectiles.splice(i, 1);
}
}
// Update AOE attacks
for (var i = aoeAttacks.length - 1; i >= 0; i--) {
var aoe = aoeAttacks[i];
if (aoe.shouldDestroy) {
aoe.destroy();
aoeAttacks.splice(i, 1);
continue;
}
// Check collision with player during active phase
if (aoe.phase === 'active' && aoe.intersects(player)) {
player.takeDamage(12);
}
}
// Update charge warnings
for (var i = chargeWarnings.length - 1; i >= 0; i--) {
var warning = chargeWarnings[i];
if (warning.shouldDestroy) {
warning.destroy();
chargeWarnings.splice(i, 1);
}
}
// Update target indicators
for (var i = targetIndicators.length - 1; i >= 0; i--) {
var indicator = targetIndicators[i];
if (indicator.shouldDestroy) {
indicator.destroy();
targetIndicators.splice(i, 1);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.shouldDestroy) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with boss
if (boss && bullet.intersects(boss)) {
// Calculate distance between player and boss
var dx = player.x - boss.x;
var dy = player.y - boss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Double damage if player is close to boss (within 200 pixels)
var damage = distance <= 200 ? 20 : 10;
boss.takeDamage(damage);
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check if out of arena
if (bullet.x < arenaLeft - 100 || bullet.x > arenaRight + 100 || bullet.y < arenaTop - 100 || bullet.y > arenaBottom + 100) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
};