/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoBar = Container.expand(function () {
var self = Container.call(this);
var bgBar = self.attachAsset('ammoBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var ammoBar = self.attachAsset('ammoBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxAmmo = 100;
self.currentAmmo = 100;
self.setAmmo = function (ammo) {
self.currentAmmo = Math.max(0, Math.min(self.maxAmmo, ammo));
var ammoPercent = self.currentAmmo / self.maxAmmo;
ammoBar.scaleX = ammoPercent;
if (ammoPercent > 0.6) {
ammoBar.tint = 0x0088ff;
} else if (ammoPercent > 0.3) {
ammoBar.tint = 0xffaa00;
} else {
ammoBar.tint = 0xff4444;
}
};
return self;
});
var AmmoPack = Container.expand(function () {
var self = Container.call(this);
var ammoPackGraphics = self.attachAsset('ammoPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobTimer = 0;
self.baseY = 0;
self.collected = false;
self.ammoAmount = 25;
self.update = function () {
self.bobTimer += 0.1;
self.y = self.baseY + Math.sin(self.bobTimer) * 10;
ammoPackGraphics.rotation += 0.03;
};
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('powerupPickup').play();
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
if (player) {
player.addAmmo(self.ammoAmount);
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
var shield = self.attachAsset('bossShield', {
anchorX: 0.5,
anchorY: 0.5
});
shield.alpha = 0.3;
self.health = 500;
self.maxHealth = 500;
self.shootCooldown = 0;
self.shootDelay = 20;
self.speed = 1.5;
self.moveTimer = 0;
self.phase = 1;
self.shieldActive = true;
self.shieldHealth = 150;
self.maxShieldHealth = 150;
self.specialAttackCooldown = 0;
self.burstCount = 0;
self.isBoss = true;
var healthBar = self.addChild(new HealthBar());
healthBar.y = -70;
healthBar.maxHealth = self.maxHealth;
healthBar.setHealth(self.health);
healthBar.scaleX = 2;
healthBar.scaleY = 1.5;
var shieldBar = self.addChild(new HealthBar());
shieldBar.y = -85;
shieldBar.maxHealth = self.maxShieldHealth;
shieldBar.setHealth(self.shieldHealth);
shieldBar.scaleX = 2;
shieldBar.scaleY = 1.2;
shieldBar.tint = 0x4444aa;
self.takeDamage = function (damage) {
if (self.shieldActive && self.shieldHealth > 0) {
self.shieldHealth -= damage;
shieldBar.setHealth(self.shieldHealth);
LK.effects.flashObject(shield, 0xffffff, 200);
if (self.shieldHealth <= 0) {
self.shieldActive = false;
shield.visible = false;
LK.effects.flashScreen(0xff0000, 800);
self.phase = 2;
self.speed = 2.5;
self.shootDelay = 15;
}
} else {
self.health -= damage;
healthBar.setHealth(self.health);
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 1000);
scoreText.setText(LK.getScore());
tween(self, {
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 4,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
}
return false;
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.specialAttackCooldown > 0) {
self.specialAttackCooldown--;
}
self.moveTimer++;
shield.rotation += 0.05;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (self.phase === 1) {
// Phase 1: Slow movement, shield active
var targetDistance = 300;
if (distance > targetDistance + 50) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
} else if (distance < targetDistance - 50) {
var moveX = -(dx / distance) * self.speed;
var moveY = -(dy / distance) * self.speed;
self.x += moveX;
self.y += moveY;
}
} else {
// Phase 2: Aggressive movement, no shield
if (distance > 150) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
}
// Keep boss within bounds
self.x = Math.max(150, Math.min(1898, self.x));
self.y = Math.max(250, Math.min(2400, self.y));
// Regular shooting
if (self.shootCooldown <= 0 && distance < 500) {
if (self.phase === 1) {
self.shootAtPlayer();
self.shootCooldown = self.shootDelay;
} else {
// Phase 2: Burst fire
self.burstShoot();
self.shootCooldown = self.shootDelay;
}
}
// Special attacks
if (self.specialAttackCooldown <= 0) {
if (self.phase === 1) {
self.spiralAttack();
self.specialAttackCooldown = 240;
} else {
self.radiusAttack();
self.specialAttackCooldown = 180;
}
}
}
};
self.shootAtPlayer = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
bullet.damage = 30;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('bullet').play();
}
};
self.burstShoot = function () {
if (player) {
for (var i = 0; i < 3; i++) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx) + (i - 1) * 0.3;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 25;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
}
};
self.spiralAttack = function () {
for (var i = 0; i < 8; i++) {
var angle = i / 8 * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 20;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
};
self.radiusAttack = function () {
for (var i = 0; i < 12; i++) {
var angle = i / 12 * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 15;
bullet.speed = 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = damageBoostActive ? 50 : 25;
self.isPlayerBullet = true;
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
var assetName = 'enemy' + (enemyType || 1);
var enemyGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 75;
self.maxHealth = 75;
self.shootCooldown = 0;
self.shootDelay = 60;
self.speed = 2;
self.enemyType = enemyType || 1;
self.moveTimer = 0;
self.lastPlayerX = 0;
self.lastPlayerY = 0;
var healthBar = self.addChild(new HealthBar());
healthBar.y = -35;
healthBar.maxHealth = self.maxHealth;
healthBar.setHealth(self.health);
if (self.enemyType === 1) {
self.speed = 3;
self.shootDelay = 45;
} else if (self.enemyType === 2) {
self.speed = 1.5;
self.shootDelay = 40;
} else if (self.enemyType === 3) {
self.speed = 2.5;
self.shootDelay = 50;
}
self.takeDamage = function (damage) {
self.health -= damage;
healthBar.setHealth(self.health);
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyDeath').play();
LK.setScore(LK.getScore() + 100);
scoreText.setText(LK.getScore());
// Death animation
tween(self, {
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 2,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
return false;
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
self.moveTimer++;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (self.enemyType === 1) {
// Aggressive rusher
if (distance > 100) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
} else if (self.enemyType === 2) {
// Tactical shooter - keeps distance
if (distance < 200) {
var moveX = -(dx / distance) * self.speed;
var moveY = -(dy / distance) * self.speed;
self.x += moveX;
self.y += moveY;
} else if (distance > 300) {
var moveX = dx / distance * self.speed * 0.5;
var moveY = dy / distance * self.speed * 0.5;
self.x += moveX;
self.y += moveY;
}
} else if (self.enemyType === 3) {
// Flanking opponent - moves in circles
var angle = Math.atan2(dy, dx) + Math.PI / 2;
var circleRadius = 150;
if (distance > circleRadius + 50) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
} else {
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
// Keep enemies within arena bounds
self.x = Math.max(100, Math.min(1948, self.x));
self.y = Math.max(200, Math.min(2500, self.y));
// Shoot at player
if (self.shootCooldown <= 0 && distance < 400) {
self.shootAtPlayer();
self.shootCooldown = self.shootDelay;
}
}
};
self.shootAtPlayer = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('bullet').play();
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 20;
self.isPlayerBullet = false;
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.currentHealth = 100;
self.setHealth = function (health) {
self.currentHealth = Math.max(0, Math.min(self.maxHealth, health));
var healthPercent = self.currentHealth / self.maxHealth;
healthBar.scaleX = healthPercent;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
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.shootCooldown = 0;
self.shootDelay = 15;
self.ammo = 100;
self.maxAmmo = 100;
self.healthBar = self.addChild(new HealthBar());
self.healthBar.y = -40;
var ammoBar = self.addChild(new AmmoBar());
ammoBar.y = -55;
ammoBar.maxAmmo = self.maxAmmo;
ammoBar.setAmmo(self.ammo);
self.consumeAmmo = function (amount) {
self.ammo = Math.max(0, self.ammo - amount);
ammoBar.setAmmo(self.ammo);
return self.ammo > 0;
};
self.addAmmo = function (amount) {
self.ammo = Math.min(self.maxAmmo, self.ammo + amount);
ammoBar.setAmmo(self.ammo);
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.setHealth(self.health);
LK.getSound('hit').play();
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
// Death animation
tween(self, {
scaleX: 0.5,
scaleY: 0.5,
rotation: Math.PI,
alpha: 0.3
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var PowerUp = Container.expand(function (powerType) {
var self = Container.call(this);
self.powerType = powerType || 'damage';
var assetName = 'powerup' + (powerType === 'damage' ? 'Damage' : powerType === 'bomb' ? 'Bomb' : powerType === 'bossBuster' ? 'BossBuster' : 'Health');
var powerupGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.bobTimer = 0;
self.baseY = 0;
self.collected = false;
self.update = function () {
self.bobTimer += 0.1;
self.y = self.baseY + Math.sin(self.bobTimer) * 10;
powerupGraphics.rotation += 0.05;
};
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('powerupPickup').play();
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
if (self.powerType === 'damage') {
activateDamageBoost();
} else if (self.powerType === 'bomb') {
activateBomb();
} else if (self.powerType === 'health') {
activateHealthBoost();
} else if (self.powerType === 'bossBuster') {
activateBossBuster();
}
};
return self;
});
var SettingsMenu = Container.expand(function () {
var self = Container.call(this);
// Load settings from storage
var settings = storage.settings || {
brightness: 1.0,
music: 0.4,
volume: 0.5
};
var panel = self.attachAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5
});
var titleText = new Text2('SETTINGS', {
size: 60,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -220;
self.addChild(titleText);
// Brightness controls
var brightnessLabel = new Text2('Brightness', {
size: 40,
fill: 0xffffff
});
brightnessLabel.anchor.set(0.5, 0.5);
brightnessLabel.y = -120;
self.addChild(brightnessLabel);
var brightnessSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
brightnessSliderBg.y = -80;
var brightnessHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
brightnessHandle.y = -80;
brightnessHandle.x = (settings.brightness - 0.5) * 180;
// Music controls
var musicLabel = new Text2('Music', {
size: 40,
fill: 0xffffff
});
musicLabel.anchor.set(0.5, 0.5);
musicLabel.y = -20;
self.addChild(musicLabel);
var musicSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
musicSliderBg.y = 20;
var musicHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
musicHandle.y = 20;
musicHandle.x = (settings.music - 0.5) * 180;
// Volume controls
var volumeLabel = new Text2('Volume', {
size: 40,
fill: 0xffffff
});
volumeLabel.anchor.set(0.5, 0.5);
volumeLabel.y = 80;
self.addChild(volumeLabel);
var volumeSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeSliderBg.y = 120;
var volumeHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeHandle.y = 120;
volumeHandle.x = (settings.volume - 0.5) * 180;
// Close button
var closeButton = self.addChild(LK.getAsset('closeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 200;
var closeText = new Text2('CLOSE', {
size: 30,
fill: 0xffffff
});
closeText.anchor.set(0.5, 0.5);
closeText.y = 200;
self.addChild(closeText);
self.visible = false;
self.isDragging = null;
self.updateSettings = function () {
// Apply brightness
game.alpha = settings.brightness;
// Apply music volume
LK.stopMusic();
if (settings.music > 0) {
LK.playMusic('fightMusic', {
fade: {
start: 0,
end: settings.music,
duration: 100
}
});
}
// Store settings
storage.settings = settings;
};
self.down = function (x, y, obj) {
if (!obj || !obj.parent) return;
var localPos = self.toLocal(obj.parent.toGlobal(obj.position));
// Check close button
if (Math.abs(localPos.x - closeButton.x) < 30 && Math.abs(localPos.y - closeButton.y) < 30) {
self.visible = false;
return;
}
// Check slider handles
if (Math.abs(localPos.x - brightnessHandle.x) < 15 && Math.abs(localPos.y - brightnessHandle.y) < 20) {
self.isDragging = 'brightness';
} else if (Math.abs(localPos.x - musicHandle.x) < 15 && Math.abs(localPos.y - musicHandle.y) < 20) {
self.isDragging = 'music';
} else if (Math.abs(localPos.x - volumeHandle.x) < 15 && Math.abs(localPos.y - volumeHandle.y) < 20) {
self.isDragging = 'volume';
}
};
self.move = function (x, y, obj) {
if (self.isDragging && obj && obj.parent) {
var localPos = self.toLocal(obj.parent.toGlobal(obj.position));
var sliderValue = Math.max(-90, Math.min(90, localPos.x));
var normalizedValue = (sliderValue + 90) / 180;
if (self.isDragging === 'brightness') {
brightnessHandle.x = sliderValue;
settings.brightness = Math.max(0.2, Math.min(1.0, normalizedValue));
} else if (self.isDragging === 'music') {
musicHandle.x = sliderValue;
settings.music = Math.max(0, Math.min(1.0, normalizedValue));
} else if (self.isDragging === 'volume') {
volumeHandle.x = sliderValue;
settings.volume = Math.max(0, Math.min(1.0, normalizedValue));
}
self.updateSettings();
}
};
self.up = function (x, y, obj) {
self.isDragging = null;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameState = 'start'; // 'start', 'playing', 'gameOver'
var player = null;
var enemies = [];
var bullets = [];
var enemyBullets = [];
var wave = 1;
var enemiesKilled = 0;
var dragNode = null;
var isSpawningWave = false;
var powerups = [];
var ammoPacks = [];
var damageBoostActive = false;
var damageBoostTimer = 0;
var powerupSpawnTimer = 0;
var powerupSpawnInterval = 600; // 10 seconds at 60fps
var ammoPackSpawnTimer = 0;
var ammoPackSpawnInterval = 900; // 15 seconds at 60fps
var boss = null;
var isBossWave = false;
var bossWaveInterval = 5; // Boss appears every 5 waves
// Settings menu
var settingsMenu = null;
var settingsButton = new Text2('⚙', {
size: 60,
fill: 0xffffff
});
settingsButton.anchor.set(0.5, 0.5);
LK.gui.topRight.addChild(settingsButton);
settingsButton.x = -50;
settingsButton.y = 50;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 50;
var waveText = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFFFF
});
waveText.anchor.set(0, 0);
LK.gui.topRight.addChild(waveText);
waveText.x = -200;
waveText.y = 50;
// Start Menu UI
var titleText = new Text2('ROMBO: ARENA SHOWDOWN', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(titleText);
titleText.y = -200;
var startButton = new Text2('TAP TO START', {
size: 80,
fill: 0x00FF00
});
startButton.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startButton);
startButton.y = 100;
var instructionText = new Text2('Drag your rombo to move • Auto-shoot enemy rombos\nCollect power-ups to survive the arena!', {
size: 45,
fill: 0xCCCCCC
});
instructionText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionText);
instructionText.y = 250;
// Hide game UI initially
scoreText.visible = false;
waveText.visible = false;
// Start the game
function startGame() {
gameState = 'playing';
// Hide start menu
titleText.visible = false;
startButton.visible = false;
instructionText.visible = false;
// Show game UI
scoreText.visible = true;
waveText.visible = true;
// Initialize game
initializePlayer();
spawnEnemies();
// Initialize settings menu
settingsMenu = game.addChild(new SettingsMenu());
settingsMenu.x = 1024;
settingsMenu.y = 1366;
settingsMenu.updateSettings();
// Start fight music
LK.playMusic('fightMusic');
}
// Initialize player
function initializePlayer() {
player = game.addChild(new Player());
player.x = 1024;
player.y = 1800;
}
// Initialize enemies for current wave
function spawnEnemies() {
enemies = [];
isBossWave = wave % bossWaveInterval === 0;
if (isBossWave) {
// Boss wave
boss = game.addChild(new Boss());
boss.x = 1024;
boss.y = 800;
enemies.push(boss);
LK.getSound('bossSpawn').play();
LK.effects.flashScreen(0x990000, 1000);
// Spawn fewer regular enemies with boss
var enemyCount = Math.max(1, Math.floor(wave / 10));
for (var i = 0; i < enemyCount; i++) {
var enemyType = i % 3 + 1;
var enemy = game.addChild(new Enemy(enemyType));
var angle = i / enemyCount * Math.PI * 2;
var radius = 400 + Math.random() * 100;
enemy.x = boss.x + Math.cos(angle) * radius;
enemy.y = boss.y + Math.sin(angle) * radius;
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(200, Math.min(2500, enemy.y));
enemies.push(enemy);
}
} else {
// Regular wave
var enemyCount = Math.min(3, 2 + Math.floor(wave / 3));
for (var i = 0; i < enemyCount; i++) {
var enemyType = i % 3 + 1;
var enemy = game.addChild(new Enemy(enemyType));
// Spawn enemies at random positions around the arena
var angle = i / enemyCount * Math.PI * 2;
var radius = 300 + Math.random() * 200;
enemy.x = 1024 + Math.cos(angle) * radius;
enemy.y = 1000 + Math.sin(angle) * radius;
// Keep within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(200, Math.min(2500, enemy.y));
enemies.push(enemy);
}
}
}
// Find nearest enemy to player
function findNearestEnemy() {
if (!player || enemies.length === 0) return null;
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
return nearestDistance < 350 ? nearestEnemy : null;
}
// Player shooting
function playerShoot() {
if (!player || player.shootCooldown > 0) return;
if (player.ammo <= 0) return; // Can't shoot without ammo
var target = findNearestEnemy();
if (!target) return;
if (!player.consumeAmmo(1)) return; // Consume 1 ammo per shot
var dx = target.x - player.x;
var dy = target.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
bullets.push(bullet);
game.addChild(bullet);
player.shootCooldown = player.shootDelay;
LK.getSound('shoot').play();
}
// Touch controls
function handleMove(x, y, obj) {
if (dragNode && player) {
player.x = x;
player.y = y;
// Keep player within arena bounds
player.x = Math.max(50, Math.min(1998, player.x));
player.y = Math.max(250, Math.min(2600, player.y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameState === 'start') {
startGame();
} else if (gameState === 'playing') {
// Check if settings button was clicked
if (obj && obj.parent) {
var settingsPos = LK.gui.topRight.toLocal(obj.parent.toGlobal(obj.position));
if (Math.abs(settingsPos.x - settingsButton.x) < 40 && Math.abs(settingsPos.y - settingsButton.y) < 40) {
if (settingsMenu) {
settingsMenu.visible = !settingsMenu.visible;
}
return;
}
}
// Check if settings menu is visible and handle its events
if (settingsMenu && settingsMenu.visible) {
return; // Don't move player when settings menu is open
}
if (player) {
dragNode = player;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Power-up functions
function activateDamageBoost() {
damageBoostActive = true;
damageBoostTimer = 300; // 5 seconds at 60fps
LK.effects.flashScreen(0x0088ff, 500);
}
function activateBomb() {
LK.getSound('bombSound').play();
LK.getSound('bombExplode').play();
LK.effects.flashScreen(0xff8800, 800);
// Damage all enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var enemyDied = enemy.takeDamage(50);
if (enemyDied) {
enemies.splice(i, 1);
enemiesKilled++;
}
}
// Clear all enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
}
function activateHealthBoost() {
if (player) {
var healAmount = 40;
player.health = Math.min(player.maxHealth, player.health + healAmount);
player.healthBar.setHealth(player.health); // Update health bar using stored reference
LK.effects.flashScreen(0x00ff00, 500);
tween(player, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
function activateBossBuster() {
LK.getSound('bossBusterActivate').play();
LK.effects.flashScreen(0xffaa00, 1000);
// Find and instantly kill any boss enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.isBoss) {
// Create dramatic destruction effect
tween(enemy, {
scaleX: 2,
scaleY: 2,
rotation: Math.PI * 6,
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
enemy.destroy();
}
});
// Award massive score for boss kill
LK.setScore(LK.getScore() + 2000);
scoreText.setText(LK.getScore());
enemies.splice(i, 1);
enemiesKilled++;
// Reset boss reference
if (enemy === boss) {
boss = null;
}
}
}
}
function spawnRandomPowerup() {
var rand = Math.random();
var powerType;
// Boss buster only spawns during boss waves and with 10% chance
if (isBossWave && rand < 0.1) {
powerType = 'bossBuster';
} else if (rand < 0.4) {
powerType = 'damage';
} else if (rand < 0.7) {
powerType = 'health';
} else {
powerType = 'bomb';
}
var powerup = new PowerUp(powerType);
powerup.x = 200 + Math.random() * 1648;
powerup.y = 400 + Math.random() * 1800;
powerup.baseY = powerup.y;
powerups.push(powerup);
game.addChild(powerup);
}
function spawnAmmoPack() {
var ammoPack = new AmmoPack();
ammoPack.x = 200 + Math.random() * 1648;
ammoPack.y = 400 + Math.random() * 1800;
ammoPack.baseY = ammoPack.y;
ammoPacks.push(ammoPack);
game.addChild(ammoPack);
}
// Main game loop
game.update = function () {
// Only update game when playing
if (gameState !== 'playing') return;
// Handle damage boost timer
if (damageBoostActive) {
damageBoostTimer--;
if (damageBoostTimer <= 0) {
damageBoostActive = false;
}
}
// Handle power-up spawning
powerupSpawnTimer++;
if (powerupSpawnTimer >= powerupSpawnInterval) {
spawnRandomPowerup();
powerupSpawnTimer = 0;
powerupSpawnInterval = 600 + Math.random() * 600; // Random interval between 10-20 seconds
}
// Handle ammo pack spawning
ammoPackSpawnTimer++;
if (ammoPackSpawnTimer >= ammoPackSpawnInterval) {
spawnAmmoPack();
ammoPackSpawnTimer = 0;
ammoPackSpawnInterval = 900 + Math.random() * 600; // Random interval between 15-25 seconds
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player && powerup.intersects(player)) {
powerup.collect();
powerups.splice(i, 1);
}
}
// Update ammo packs
for (var i = ammoPacks.length - 1; i >= 0; i--) {
var ammoPack = ammoPacks[i];
if (player && ammoPack.intersects(player)) {
ammoPack.collect();
ammoPacks.splice(i, 1);
}
}
// Auto-shoot at nearest enemy
playerShoot();
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
var enemyDied = enemy.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(i, 1);
if (enemyDied) {
enemies.splice(j, 1);
enemiesKilled++;
}
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (player && bullet.intersects(player)) {
player.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Check if wave is complete
if (enemies.length === 0 && !isSpawningWave) {
isSpawningWave = true;
if (isBossWave) {
boss = null;
isBossWave = false;
// Longer delay after boss wave
LK.setTimeout(function () {
wave++;
waveText.setText('Wave: ' + wave);
spawnEnemies();
isSpawningWave = false;
}, 2000);
} else {
wave++;
waveText.setText('Wave: ' + wave);
// Small delay before next wave
LK.setTimeout(function () {
spawnEnemies();
isSpawningWave = false;
}, 1000);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoBar = Container.expand(function () {
var self = Container.call(this);
var bgBar = self.attachAsset('ammoBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var ammoBar = self.attachAsset('ammoBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxAmmo = 100;
self.currentAmmo = 100;
self.setAmmo = function (ammo) {
self.currentAmmo = Math.max(0, Math.min(self.maxAmmo, ammo));
var ammoPercent = self.currentAmmo / self.maxAmmo;
ammoBar.scaleX = ammoPercent;
if (ammoPercent > 0.6) {
ammoBar.tint = 0x0088ff;
} else if (ammoPercent > 0.3) {
ammoBar.tint = 0xffaa00;
} else {
ammoBar.tint = 0xff4444;
}
};
return self;
});
var AmmoPack = Container.expand(function () {
var self = Container.call(this);
var ammoPackGraphics = self.attachAsset('ammoPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobTimer = 0;
self.baseY = 0;
self.collected = false;
self.ammoAmount = 25;
self.update = function () {
self.bobTimer += 0.1;
self.y = self.baseY + Math.sin(self.bobTimer) * 10;
ammoPackGraphics.rotation += 0.03;
};
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('powerupPickup').play();
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
if (player) {
player.addAmmo(self.ammoAmount);
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
var shield = self.attachAsset('bossShield', {
anchorX: 0.5,
anchorY: 0.5
});
shield.alpha = 0.3;
self.health = 500;
self.maxHealth = 500;
self.shootCooldown = 0;
self.shootDelay = 20;
self.speed = 1.5;
self.moveTimer = 0;
self.phase = 1;
self.shieldActive = true;
self.shieldHealth = 150;
self.maxShieldHealth = 150;
self.specialAttackCooldown = 0;
self.burstCount = 0;
self.isBoss = true;
var healthBar = self.addChild(new HealthBar());
healthBar.y = -70;
healthBar.maxHealth = self.maxHealth;
healthBar.setHealth(self.health);
healthBar.scaleX = 2;
healthBar.scaleY = 1.5;
var shieldBar = self.addChild(new HealthBar());
shieldBar.y = -85;
shieldBar.maxHealth = self.maxShieldHealth;
shieldBar.setHealth(self.shieldHealth);
shieldBar.scaleX = 2;
shieldBar.scaleY = 1.2;
shieldBar.tint = 0x4444aa;
self.takeDamage = function (damage) {
if (self.shieldActive && self.shieldHealth > 0) {
self.shieldHealth -= damage;
shieldBar.setHealth(self.shieldHealth);
LK.effects.flashObject(shield, 0xffffff, 200);
if (self.shieldHealth <= 0) {
self.shieldActive = false;
shield.visible = false;
LK.effects.flashScreen(0xff0000, 800);
self.phase = 2;
self.speed = 2.5;
self.shootDelay = 15;
}
} else {
self.health -= damage;
healthBar.setHealth(self.health);
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 1000);
scoreText.setText(LK.getScore());
tween(self, {
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 4,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
}
return false;
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.specialAttackCooldown > 0) {
self.specialAttackCooldown--;
}
self.moveTimer++;
shield.rotation += 0.05;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (self.phase === 1) {
// Phase 1: Slow movement, shield active
var targetDistance = 300;
if (distance > targetDistance + 50) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
} else if (distance < targetDistance - 50) {
var moveX = -(dx / distance) * self.speed;
var moveY = -(dy / distance) * self.speed;
self.x += moveX;
self.y += moveY;
}
} else {
// Phase 2: Aggressive movement, no shield
if (distance > 150) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
}
// Keep boss within bounds
self.x = Math.max(150, Math.min(1898, self.x));
self.y = Math.max(250, Math.min(2400, self.y));
// Regular shooting
if (self.shootCooldown <= 0 && distance < 500) {
if (self.phase === 1) {
self.shootAtPlayer();
self.shootCooldown = self.shootDelay;
} else {
// Phase 2: Burst fire
self.burstShoot();
self.shootCooldown = self.shootDelay;
}
}
// Special attacks
if (self.specialAttackCooldown <= 0) {
if (self.phase === 1) {
self.spiralAttack();
self.specialAttackCooldown = 240;
} else {
self.radiusAttack();
self.specialAttackCooldown = 180;
}
}
}
};
self.shootAtPlayer = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
bullet.damage = 30;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('bullet').play();
}
};
self.burstShoot = function () {
if (player) {
for (var i = 0; i < 3; i++) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx) + (i - 1) * 0.3;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 25;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
}
};
self.spiralAttack = function () {
for (var i = 0; i < 8; i++) {
var angle = i / 8 * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 20;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
};
self.radiusAttack = function () {
for (var i = 0; i < 12; i++) {
var angle = i / 12 * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullet.damage = 15;
bullet.speed = 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('bullet').play();
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = damageBoostActive ? 50 : 25;
self.isPlayerBullet = true;
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
var assetName = 'enemy' + (enemyType || 1);
var enemyGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 75;
self.maxHealth = 75;
self.shootCooldown = 0;
self.shootDelay = 60;
self.speed = 2;
self.enemyType = enemyType || 1;
self.moveTimer = 0;
self.lastPlayerX = 0;
self.lastPlayerY = 0;
var healthBar = self.addChild(new HealthBar());
healthBar.y = -35;
healthBar.maxHealth = self.maxHealth;
healthBar.setHealth(self.health);
if (self.enemyType === 1) {
self.speed = 3;
self.shootDelay = 45;
} else if (self.enemyType === 2) {
self.speed = 1.5;
self.shootDelay = 40;
} else if (self.enemyType === 3) {
self.speed = 2.5;
self.shootDelay = 50;
}
self.takeDamage = function (damage) {
self.health -= damage;
healthBar.setHealth(self.health);
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('enemyDeath').play();
LK.setScore(LK.getScore() + 100);
scoreText.setText(LK.getScore());
// Death animation
tween(self, {
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 2,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return true;
}
return false;
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
self.moveTimer++;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (self.enemyType === 1) {
// Aggressive rusher
if (distance > 100) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
} else if (self.enemyType === 2) {
// Tactical shooter - keeps distance
if (distance < 200) {
var moveX = -(dx / distance) * self.speed;
var moveY = -(dy / distance) * self.speed;
self.x += moveX;
self.y += moveY;
} else if (distance > 300) {
var moveX = dx / distance * self.speed * 0.5;
var moveY = dy / distance * self.speed * 0.5;
self.x += moveX;
self.y += moveY;
}
} else if (self.enemyType === 3) {
// Flanking opponent - moves in circles
var angle = Math.atan2(dy, dx) + Math.PI / 2;
var circleRadius = 150;
if (distance > circleRadius + 50) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
} else {
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
// Keep enemies within arena bounds
self.x = Math.max(100, Math.min(1948, self.x));
self.y = Math.max(200, Math.min(2500, self.y));
// Shoot at player
if (self.shootCooldown <= 0 && distance < 400) {
self.shootAtPlayer();
self.shootCooldown = self.shootDelay;
}
}
};
self.shootAtPlayer = function () {
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('bullet').play();
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 20;
self.isPlayerBullet = false;
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.currentHealth = 100;
self.setHealth = function (health) {
self.currentHealth = Math.max(0, Math.min(self.maxHealth, health));
var healthPercent = self.currentHealth / self.maxHealth;
healthBar.scaleX = healthPercent;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
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.shootCooldown = 0;
self.shootDelay = 15;
self.ammo = 100;
self.maxAmmo = 100;
self.healthBar = self.addChild(new HealthBar());
self.healthBar.y = -40;
var ammoBar = self.addChild(new AmmoBar());
ammoBar.y = -55;
ammoBar.maxAmmo = self.maxAmmo;
ammoBar.setAmmo(self.ammo);
self.consumeAmmo = function (amount) {
self.ammo = Math.max(0, self.ammo - amount);
ammoBar.setAmmo(self.ammo);
return self.ammo > 0;
};
self.addAmmo = function (amount) {
self.ammo = Math.min(self.maxAmmo, self.ammo + amount);
ammoBar.setAmmo(self.ammo);
};
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.setHealth(self.health);
LK.getSound('hit').play();
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
// Death animation
tween(self, {
scaleX: 0.5,
scaleY: 0.5,
rotation: Math.PI,
alpha: 0.3
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var PowerUp = Container.expand(function (powerType) {
var self = Container.call(this);
self.powerType = powerType || 'damage';
var assetName = 'powerup' + (powerType === 'damage' ? 'Damage' : powerType === 'bomb' ? 'Bomb' : powerType === 'bossBuster' ? 'BossBuster' : 'Health');
var powerupGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.bobTimer = 0;
self.baseY = 0;
self.collected = false;
self.update = function () {
self.bobTimer += 0.1;
self.y = self.baseY + Math.sin(self.bobTimer) * 10;
powerupGraphics.rotation += 0.05;
};
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('powerupPickup').play();
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
if (self.powerType === 'damage') {
activateDamageBoost();
} else if (self.powerType === 'bomb') {
activateBomb();
} else if (self.powerType === 'health') {
activateHealthBoost();
} else if (self.powerType === 'bossBuster') {
activateBossBuster();
}
};
return self;
});
var SettingsMenu = Container.expand(function () {
var self = Container.call(this);
// Load settings from storage
var settings = storage.settings || {
brightness: 1.0,
music: 0.4,
volume: 0.5
};
var panel = self.attachAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5
});
var titleText = new Text2('SETTINGS', {
size: 60,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -220;
self.addChild(titleText);
// Brightness controls
var brightnessLabel = new Text2('Brightness', {
size: 40,
fill: 0xffffff
});
brightnessLabel.anchor.set(0.5, 0.5);
brightnessLabel.y = -120;
self.addChild(brightnessLabel);
var brightnessSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
brightnessSliderBg.y = -80;
var brightnessHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
brightnessHandle.y = -80;
brightnessHandle.x = (settings.brightness - 0.5) * 180;
// Music controls
var musicLabel = new Text2('Music', {
size: 40,
fill: 0xffffff
});
musicLabel.anchor.set(0.5, 0.5);
musicLabel.y = -20;
self.addChild(musicLabel);
var musicSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
musicSliderBg.y = 20;
var musicHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
musicHandle.y = 20;
musicHandle.x = (settings.music - 0.5) * 180;
// Volume controls
var volumeLabel = new Text2('Volume', {
size: 40,
fill: 0xffffff
});
volumeLabel.anchor.set(0.5, 0.5);
volumeLabel.y = 80;
self.addChild(volumeLabel);
var volumeSliderBg = self.addChild(LK.getAsset('slider', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeSliderBg.y = 120;
var volumeHandle = self.addChild(LK.getAsset('sliderHandle', {
anchorX: 0.5,
anchorY: 0.5
}));
volumeHandle.y = 120;
volumeHandle.x = (settings.volume - 0.5) * 180;
// Close button
var closeButton = self.addChild(LK.getAsset('closeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
closeButton.y = 200;
var closeText = new Text2('CLOSE', {
size: 30,
fill: 0xffffff
});
closeText.anchor.set(0.5, 0.5);
closeText.y = 200;
self.addChild(closeText);
self.visible = false;
self.isDragging = null;
self.updateSettings = function () {
// Apply brightness
game.alpha = settings.brightness;
// Apply music volume
LK.stopMusic();
if (settings.music > 0) {
LK.playMusic('fightMusic', {
fade: {
start: 0,
end: settings.music,
duration: 100
}
});
}
// Store settings
storage.settings = settings;
};
self.down = function (x, y, obj) {
if (!obj || !obj.parent) return;
var localPos = self.toLocal(obj.parent.toGlobal(obj.position));
// Check close button
if (Math.abs(localPos.x - closeButton.x) < 30 && Math.abs(localPos.y - closeButton.y) < 30) {
self.visible = false;
return;
}
// Check slider handles
if (Math.abs(localPos.x - brightnessHandle.x) < 15 && Math.abs(localPos.y - brightnessHandle.y) < 20) {
self.isDragging = 'brightness';
} else if (Math.abs(localPos.x - musicHandle.x) < 15 && Math.abs(localPos.y - musicHandle.y) < 20) {
self.isDragging = 'music';
} else if (Math.abs(localPos.x - volumeHandle.x) < 15 && Math.abs(localPos.y - volumeHandle.y) < 20) {
self.isDragging = 'volume';
}
};
self.move = function (x, y, obj) {
if (self.isDragging && obj && obj.parent) {
var localPos = self.toLocal(obj.parent.toGlobal(obj.position));
var sliderValue = Math.max(-90, Math.min(90, localPos.x));
var normalizedValue = (sliderValue + 90) / 180;
if (self.isDragging === 'brightness') {
brightnessHandle.x = sliderValue;
settings.brightness = Math.max(0.2, Math.min(1.0, normalizedValue));
} else if (self.isDragging === 'music') {
musicHandle.x = sliderValue;
settings.music = Math.max(0, Math.min(1.0, normalizedValue));
} else if (self.isDragging === 'volume') {
volumeHandle.x = sliderValue;
settings.volume = Math.max(0, Math.min(1.0, normalizedValue));
}
self.updateSettings();
}
};
self.up = function (x, y, obj) {
self.isDragging = null;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameState = 'start'; // 'start', 'playing', 'gameOver'
var player = null;
var enemies = [];
var bullets = [];
var enemyBullets = [];
var wave = 1;
var enemiesKilled = 0;
var dragNode = null;
var isSpawningWave = false;
var powerups = [];
var ammoPacks = [];
var damageBoostActive = false;
var damageBoostTimer = 0;
var powerupSpawnTimer = 0;
var powerupSpawnInterval = 600; // 10 seconds at 60fps
var ammoPackSpawnTimer = 0;
var ammoPackSpawnInterval = 900; // 15 seconds at 60fps
var boss = null;
var isBossWave = false;
var bossWaveInterval = 5; // Boss appears every 5 waves
// Settings menu
var settingsMenu = null;
var settingsButton = new Text2('⚙', {
size: 60,
fill: 0xffffff
});
settingsButton.anchor.set(0.5, 0.5);
LK.gui.topRight.addChild(settingsButton);
settingsButton.x = -50;
settingsButton.y = 50;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 50;
var waveText = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFFFF
});
waveText.anchor.set(0, 0);
LK.gui.topRight.addChild(waveText);
waveText.x = -200;
waveText.y = 50;
// Start Menu UI
var titleText = new Text2('ROMBO: ARENA SHOWDOWN', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(titleText);
titleText.y = -200;
var startButton = new Text2('TAP TO START', {
size: 80,
fill: 0x00FF00
});
startButton.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startButton);
startButton.y = 100;
var instructionText = new Text2('Drag your rombo to move • Auto-shoot enemy rombos\nCollect power-ups to survive the arena!', {
size: 45,
fill: 0xCCCCCC
});
instructionText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionText);
instructionText.y = 250;
// Hide game UI initially
scoreText.visible = false;
waveText.visible = false;
// Start the game
function startGame() {
gameState = 'playing';
// Hide start menu
titleText.visible = false;
startButton.visible = false;
instructionText.visible = false;
// Show game UI
scoreText.visible = true;
waveText.visible = true;
// Initialize game
initializePlayer();
spawnEnemies();
// Initialize settings menu
settingsMenu = game.addChild(new SettingsMenu());
settingsMenu.x = 1024;
settingsMenu.y = 1366;
settingsMenu.updateSettings();
// Start fight music
LK.playMusic('fightMusic');
}
// Initialize player
function initializePlayer() {
player = game.addChild(new Player());
player.x = 1024;
player.y = 1800;
}
// Initialize enemies for current wave
function spawnEnemies() {
enemies = [];
isBossWave = wave % bossWaveInterval === 0;
if (isBossWave) {
// Boss wave
boss = game.addChild(new Boss());
boss.x = 1024;
boss.y = 800;
enemies.push(boss);
LK.getSound('bossSpawn').play();
LK.effects.flashScreen(0x990000, 1000);
// Spawn fewer regular enemies with boss
var enemyCount = Math.max(1, Math.floor(wave / 10));
for (var i = 0; i < enemyCount; i++) {
var enemyType = i % 3 + 1;
var enemy = game.addChild(new Enemy(enemyType));
var angle = i / enemyCount * Math.PI * 2;
var radius = 400 + Math.random() * 100;
enemy.x = boss.x + Math.cos(angle) * radius;
enemy.y = boss.y + Math.sin(angle) * radius;
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(200, Math.min(2500, enemy.y));
enemies.push(enemy);
}
} else {
// Regular wave
var enemyCount = Math.min(3, 2 + Math.floor(wave / 3));
for (var i = 0; i < enemyCount; i++) {
var enemyType = i % 3 + 1;
var enemy = game.addChild(new Enemy(enemyType));
// Spawn enemies at random positions around the arena
var angle = i / enemyCount * Math.PI * 2;
var radius = 300 + Math.random() * 200;
enemy.x = 1024 + Math.cos(angle) * radius;
enemy.y = 1000 + Math.sin(angle) * radius;
// Keep within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(200, Math.min(2500, enemy.y));
enemies.push(enemy);
}
}
}
// Find nearest enemy to player
function findNearestEnemy() {
if (!player || enemies.length === 0) return null;
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
return nearestDistance < 350 ? nearestEnemy : null;
}
// Player shooting
function playerShoot() {
if (!player || player.shootCooldown > 0) return;
if (player.ammo <= 0) return; // Can't shoot without ammo
var target = findNearestEnemy();
if (!target) return;
if (!player.consumeAmmo(1)) return; // Consume 1 ammo per shot
var dx = target.x - player.x;
var dy = target.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
bullets.push(bullet);
game.addChild(bullet);
player.shootCooldown = player.shootDelay;
LK.getSound('shoot').play();
}
// Touch controls
function handleMove(x, y, obj) {
if (dragNode && player) {
player.x = x;
player.y = y;
// Keep player within arena bounds
player.x = Math.max(50, Math.min(1998, player.x));
player.y = Math.max(250, Math.min(2600, player.y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameState === 'start') {
startGame();
} else if (gameState === 'playing') {
// Check if settings button was clicked
if (obj && obj.parent) {
var settingsPos = LK.gui.topRight.toLocal(obj.parent.toGlobal(obj.position));
if (Math.abs(settingsPos.x - settingsButton.x) < 40 && Math.abs(settingsPos.y - settingsButton.y) < 40) {
if (settingsMenu) {
settingsMenu.visible = !settingsMenu.visible;
}
return;
}
}
// Check if settings menu is visible and handle its events
if (settingsMenu && settingsMenu.visible) {
return; // Don't move player when settings menu is open
}
if (player) {
dragNode = player;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Power-up functions
function activateDamageBoost() {
damageBoostActive = true;
damageBoostTimer = 300; // 5 seconds at 60fps
LK.effects.flashScreen(0x0088ff, 500);
}
function activateBomb() {
LK.getSound('bombSound').play();
LK.getSound('bombExplode').play();
LK.effects.flashScreen(0xff8800, 800);
// Damage all enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var enemyDied = enemy.takeDamage(50);
if (enemyDied) {
enemies.splice(i, 1);
enemiesKilled++;
}
}
// Clear all enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
}
function activateHealthBoost() {
if (player) {
var healAmount = 40;
player.health = Math.min(player.maxHealth, player.health + healAmount);
player.healthBar.setHealth(player.health); // Update health bar using stored reference
LK.effects.flashScreen(0x00ff00, 500);
tween(player, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
function activateBossBuster() {
LK.getSound('bossBusterActivate').play();
LK.effects.flashScreen(0xffaa00, 1000);
// Find and instantly kill any boss enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.isBoss) {
// Create dramatic destruction effect
tween(enemy, {
scaleX: 2,
scaleY: 2,
rotation: Math.PI * 6,
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
enemy.destroy();
}
});
// Award massive score for boss kill
LK.setScore(LK.getScore() + 2000);
scoreText.setText(LK.getScore());
enemies.splice(i, 1);
enemiesKilled++;
// Reset boss reference
if (enemy === boss) {
boss = null;
}
}
}
}
function spawnRandomPowerup() {
var rand = Math.random();
var powerType;
// Boss buster only spawns during boss waves and with 10% chance
if (isBossWave && rand < 0.1) {
powerType = 'bossBuster';
} else if (rand < 0.4) {
powerType = 'damage';
} else if (rand < 0.7) {
powerType = 'health';
} else {
powerType = 'bomb';
}
var powerup = new PowerUp(powerType);
powerup.x = 200 + Math.random() * 1648;
powerup.y = 400 + Math.random() * 1800;
powerup.baseY = powerup.y;
powerups.push(powerup);
game.addChild(powerup);
}
function spawnAmmoPack() {
var ammoPack = new AmmoPack();
ammoPack.x = 200 + Math.random() * 1648;
ammoPack.y = 400 + Math.random() * 1800;
ammoPack.baseY = ammoPack.y;
ammoPacks.push(ammoPack);
game.addChild(ammoPack);
}
// Main game loop
game.update = function () {
// Only update game when playing
if (gameState !== 'playing') return;
// Handle damage boost timer
if (damageBoostActive) {
damageBoostTimer--;
if (damageBoostTimer <= 0) {
damageBoostActive = false;
}
}
// Handle power-up spawning
powerupSpawnTimer++;
if (powerupSpawnTimer >= powerupSpawnInterval) {
spawnRandomPowerup();
powerupSpawnTimer = 0;
powerupSpawnInterval = 600 + Math.random() * 600; // Random interval between 10-20 seconds
}
// Handle ammo pack spawning
ammoPackSpawnTimer++;
if (ammoPackSpawnTimer >= ammoPackSpawnInterval) {
spawnAmmoPack();
ammoPackSpawnTimer = 0;
ammoPackSpawnInterval = 900 + Math.random() * 600; // Random interval between 15-25 seconds
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player && powerup.intersects(player)) {
powerup.collect();
powerups.splice(i, 1);
}
}
// Update ammo packs
for (var i = ammoPacks.length - 1; i >= 0; i--) {
var ammoPack = ammoPacks[i];
if (player && ammoPack.intersects(player)) {
ammoPack.collect();
ammoPacks.splice(i, 1);
}
}
// Auto-shoot at nearest enemy
playerShoot();
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
var enemyDied = enemy.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(i, 1);
if (enemyDied) {
enemies.splice(j, 1);
enemiesKilled++;
}
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (player && bullet.intersects(player)) {
player.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Check if wave is complete
if (enemies.length === 0 && !isSpawningWave) {
isSpawningWave = true;
if (isBossWave) {
boss = null;
isBossWave = false;
// Longer delay after boss wave
LK.setTimeout(function () {
wave++;
waveText.setText('Wave: ' + wave);
spawnEnemies();
isSpawningWave = false;
}, 2000);
} else {
wave++;
waveText.setText('Wave: ' + wave);
// Small delay before next wave
LK.setTimeout(function () {
spawnEnemies();
isSpawningWave = false;
}, 1000);
}
}
};
Bomb. In-Game asset. High contrast. No shadows. 2d
Heart. In-Game asset. 2d. High contrast. No shadows
Fire. In-Game asset. 2d. High contrast. No shadows
2D ammo pack. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Sharp katana with bloods. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat