/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, unlockedWeapons: [0] }); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphic = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 30; self.maxHealth = 30; self.speed = 2; self.damage = 10; self.attackCooldown = 60; // frames self.attackTimer = 0; self.scoreValue = 10; self.healthBar = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, y: -80 }); self.healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, y: -80 }); self.healthBar.width = self.health / self.maxHealth * 100; self.takeDamage = function (amount) { self.health -= amount; self.healthBar.width = self.health / self.maxHealth * 100; // Flash red when hit tween(enemyGraphic, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(enemyGraphic, { alpha: 1 }, { duration: 100 }); } }); if (self.health <= 0) { LK.getSound('enemyDeath').play(); var randomChance = Math.random(); if (randomChance < 0.2) { // 20% chance to drop powerup var powerup = new PowerUp(); powerup.x = self.x; powerup.y = self.y; game.addChild(powerup); powerups.push(powerup); } self.readyToRemove = true; return true; } return false; }; self.moveTowards = function (targetX, targetY) { var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; self.update = function () { if (self.attackTimer > 0) { self.attackTimer--; } }; return self; }); var BossEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace the enemy graphic with a boss graphic self.removeChild(self.children[0]); // Remove regular enemy graphic var bossGraphic = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.health = 150; self.maxHealth = 150; self.speed = 1.5; self.damage = 20; self.attackCooldown = 120; self.scoreValue = 50; // Update health bar position and size for boss self.healthBar.y = -120; self.healthBarBg.y = -120; self.healthBar.width = 200; self.healthBarBg.width = 200; // Special boss attack pattern var attackPhase = 0; self.update = function () { Enemy.prototype.update.call(self); // Call the parent update method if (self.attackTimer === 0) { // Boss can fire projectiles attackPhase = (attackPhase + 1) % 3; switch (attackPhase) { case 0: // Fire in cardinal directions for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 2) { var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.setDirection(Math.cos(angle), Math.sin(angle)); projectile.damage = 15; projectile.isEnemyProjectile = true; game.addChild(projectile); enemyProjectiles.push(projectile); } break; case 1: // Fire at player if (warrior) { var dx = warrior.x - self.x; var dy = warrior.y - self.y; var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.setDirection(dx, dy); projectile.damage = 15; projectile.isEnemyProjectile = true; game.addChild(projectile); enemyProjectiles.push(projectile); } break; case 2: // Spawn minions var minion = new Enemy(); minion.x = self.x + (Math.random() * 200 - 100); minion.y = self.y + (Math.random() * 200 - 100); minion.health = 15; minion.maxHealth = 15; minion.speed = 3; game.addChild(minion); enemies.push(minion); break; } self.attackTimer = self.attackCooldown; } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphic = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.type = Math.floor(Math.random() * 3); // 0: health, 1: speed, 2: damage // Different colors for different powerup types switch (self.type) { case 0: // Health powerupGraphic.tint = 0x33cc33; // Green break; case 1: // Speed powerupGraphic.tint = 0x3366ff; // Blue break; case 2: // Damage powerupGraphic.tint = 0xff3333; // Red break; } self.lifespan = 300; // frames the powerup will stay self.age = 0; // Pulsing animation self.update = function () { self.age++; var scale = 1 + 0.1 * Math.sin(self.age * 0.1); powerupGraphic.scale.set(scale, scale); if (self.age >= self.lifespan) { self.readyToRemove = true; } }; self.applyEffect = function (warrior) { LK.getSound('powerupCollect').play(); switch (self.type) { case 0: // Health warrior.health = Math.min(warrior.health + 30, warrior.maxHealth); warrior.updateHealthBar(); break; case 1: // Speed warrior.speedBoost = 300; // Number of frames for speed boost break; case 2: // Damage warrior.damageBoost = 300; // Number of frames for damage boost break; } }; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var projectileGraphic = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.damage = 10; self.direction = { x: 0, y: 0 }; self.lifespan = 120; // frames the projectile will live self.age = 0; self.setDirection = function (dirX, dirY) { // Normalize direction vector var length = Math.sqrt(dirX * dirX + dirY * dirY); if (length > 0) { self.direction.x = dirX / length; self.direction.y = dirY / length; } }; self.update = function () { self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; self.age++; if (self.age >= self.lifespan) { self.readyToRemove = true; } }; return self; }); var Warrior = Container.expand(function () { var self = Container.call(this); var warriorGraphic = self.attachAsset('warrior', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.speed = 5; self.damage = 20; self.attackCooldown = 20; // frames self.attackTimer = 0; self.invulnerable = false; self.invulnerableTime = 0; self.speedBoost = 0; self.damageBoost = 0; // Health bar displayed at the top of the screen self.healthBar = null; self.healthBarBg = null; self.initializeHealthBar = function () { self.healthBarBg = LK.getAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 30 }); self.healthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0.5, width: 300, height: 30 }); LK.gui.top.addChild(self.healthBarBg); self.healthBarBg.y = 50; LK.gui.top.addChild(self.healthBar); self.healthBar.y = 50; self.healthBar.x = self.healthBarBg.x - self.healthBarBg.width / 2; self.updateHealthBar(); }; self.updateHealthBar = function () { if (self.healthBar) { self.healthBar.width = self.health / self.maxHealth * 300; } }; self.takeDamage = function (amount) { if (self.invulnerable) { return false; } self.health -= amount; self.updateHealthBar(); LK.getSound('playerHit').play(); // Flash and set invulnerable briefly self.invulnerable = true; self.invulnerableTime = 60; // 1 second of invulnerability tween(warriorGraphic, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(warriorGraphic, { alpha: 1 }, { duration: 100 }); } }); if (self.health <= 0) { LK.getSound('gameOver').play(); LK.showGameOver(); return true; } return false; }; self.fire = function (dirX, dirY) { if (self.attackTimer === 0) { var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.setDirection(dirX, dirY); // Apply damage boost if active if (self.damageBoost > 0) { projectile.damage = self.damage * 1.5; projectile.tint = 0xff0000; // Red tint for boosted projectiles } else { projectile.damage = self.damage; } game.addChild(projectile); playerProjectiles.push(projectile); self.attackTimer = self.attackCooldown; } }; self.update = function () { if (self.attackTimer > 0) { self.attackTimer--; } if (self.invulnerable) { self.invulnerableTime--; warriorGraphic.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * 0.2); if (self.invulnerableTime <= 0) { self.invulnerable = false; warriorGraphic.alpha = 1; } } // Handle boosts if (self.speedBoost > 0) { self.speedBoost--; warriorGraphic.tint = 0x3366ff; // Blue tint during speed boost } else { warriorGraphic.tint = 0xffffff; // Reset tint } if (self.damageBoost > 0) { self.damageBoost--; if (!self.speedBoost) { // Only tint red if not speed boosted warriorGraphic.tint = 0xff3333; // Red tint during damage boost } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Game state variables var warrior = null; var enemies = []; var playerProjectiles = []; var enemyProjectiles = []; var powerups = []; var waveNumber = 1; var enemiesPerWave = 5; var score = 0; var waveClearTimeBonus = 5000; // Base time bonus for clearing waves var waveStartTime = 0; var gameActive = false; var arena = null; var arenaSize = 1800; var waveText = null; var scoreText = null; var dragging = false; var lastMoveX = 0; var lastMoveY = 0; // Initialize the game function initGame() { // Reset game state warrior = null; enemies = []; playerProjectiles = []; enemyProjectiles = []; powerups = []; waveNumber = 1; enemiesPerWave = 5; score = 0; gameActive = true; // Set score for LK LK.setScore(score); // Create arena arena = LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5 }); game.addChild(arena); arena.x = 2048 / 2; arena.y = 2732 / 2; arena.alpha = 0.5; // Create warrior warrior = new Warrior(); warrior.x = 2048 / 2; warrior.y = 2732 / 2; game.addChild(warrior); warrior.initializeHealthBar(); // Create UI elements createUI(); // Start first wave startWave(); // Play background music LK.playMusic('battleMusic'); } function createUI() { // Score text scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); LK.gui.topRight.addChild(scoreText); scoreText.x = -20; scoreText.y = 20; // Wave text waveText = new Text2('Wave 1', { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(0, 0); LK.gui.topRight.addChild(waveText); waveText.x = -20; waveText.y = 80; } function updateUI() { scoreText.setText('Score: ' + score); waveText.setText('Wave ' + waveNumber); } function startWave() { waveStartTime = Date.now(); // Create enemies for this wave var enemiesToSpawn = enemiesPerWave + waveNumber; // Every 3rd wave has a boss if (waveNumber % 3 === 0) { var boss = new BossEnemy(); placeEnemyOutsideArena(boss); game.addChild(boss); enemies.push(boss); enemiesToSpawn -= 3; // Boss counts as 3 regular enemies } for (var i = 0; i < enemiesToSpawn; i++) { var enemy = new Enemy(); // Scale difficulty with wave number enemy.health = 30 + waveNumber * 5; enemy.maxHealth = enemy.health; enemy.speed = 2 + waveNumber * 0.1; enemy.damage = 10 + waveNumber * 2; placeEnemyOutsideArena(enemy); game.addChild(enemy); enemies.push(enemy); } updateUI(); } function placeEnemyOutsideArena(enemy) { var angle = Math.random() * Math.PI * 2; var distance = arenaSize / 2 + 100 + Math.random() * 300; // Spawn outside arena enemy.x = 2048 / 2 + Math.cos(angle) * distance; enemy.y = 2732 / 2 + Math.sin(angle) * distance; } function waveCompleted() { // Calculate time bonus var timeElapsed = Date.now() - waveStartTime; var timeBonus = Math.max(0, waveClearTimeBonus - Math.floor(timeElapsed / 100)); score += timeBonus; LK.setScore(score); // Update high score if (score > storage.highScore) { storage.highScore = score; } // Play victory sound LK.getSound('waveComplete').play(); // Flash screen LK.effects.flashScreen(0x33cc33, 500); // Next wave waveNumber++; enemiesPerWave += 2; // Brief delay before next wave LK.setTimeout(function () { startWave(); }, 2000); } // Game update function game.update = function () { if (!gameActive) { return; } // Update warrior if (warrior) { warrior.update(); // Move warrior if dragging if (dragging) { // Calculate actual speed based on speed boost var actualSpeed = warrior.speed; if (warrior.speedBoost > 0) { actualSpeed *= 1.5; } // Calculate direction to move var dx = lastMoveX - warrior.x; var dy = lastMoveY - warrior.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > actualSpeed) { warrior.x += dx / distance * actualSpeed; warrior.y += dy / distance * actualSpeed; } else { warrior.x = lastMoveX; warrior.y = lastMoveY; } // Keep warrior inside the arena var arenaRadius = arenaSize / 2; var centerX = 2048 / 2; var centerY = 2732 / 2; var dx = warrior.x - centerX; var dy = warrior.y - centerY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > arenaRadius) { warrior.x = centerX + dx / distance * arenaRadius; warrior.y = centerY + dy / distance * arenaRadius; } } // Check for powerup collisions for (var i = powerups.length - 1; i >= 0; i--) { if (warrior.intersects(powerups[i])) { powerups[i].applyEffect(warrior); powerups[i].destroy(); powerups.splice(i, 1); } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Move towards warrior if (warrior) { enemy.moveTowards(warrior.x, warrior.y); // Check for collision with warrior if (warrior.intersects(enemy) && enemy.attackTimer === 0) { warrior.takeDamage(enemy.damage); enemy.attackTimer = enemy.attackCooldown; } } // Remove dead enemies if (enemy.readyToRemove) { score += enemy.scoreValue; LK.setScore(score); enemy.destroy(); enemies.splice(i, 1); } } // Update player projectiles for (var i = playerProjectiles.length - 1; i >= 0; i--) { var proj = playerProjectiles[i]; proj.update(); // Check for enemy hits for (var j = enemies.length - 1; j >= 0; j--) { if (proj.intersects(enemies[j])) { LK.getSound('hit').play(); var killed = enemies[j].takeDamage(proj.damage); if (killed) { score += enemies[j].scoreValue; LK.setScore(score); } proj.readyToRemove = true; break; } } // Remove projectiles that are off-screen or have hit something if (proj.readyToRemove || proj.x < 0 || proj.x > 2048 || proj.y < 0 || proj.y > 2732) { proj.destroy(); playerProjectiles.splice(i, 1); } } // Update enemy projectiles for (var i = enemyProjectiles.length - 1; i >= 0; i--) { var proj = enemyProjectiles[i]; proj.update(); // Check for warrior hit if (warrior && proj.intersects(warrior)) { warrior.takeDamage(proj.damage); proj.readyToRemove = true; } // Remove projectiles that are off-screen or have hit something if (proj.readyToRemove || proj.x < 0 || proj.x > 2048 || proj.y < 0 || proj.y > 2732) { proj.destroy(); enemyProjectiles.splice(i, 1); } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].update(); if (powerups[i].readyToRemove) { powerups[i].destroy(); powerups.splice(i, 1); } } // Check if wave is completed if (enemies.length === 0) { waveCompleted(); } // Update UI updateUI(); }; // Input handling function handleMove(x, y, obj) { if (dragging && warrior) { lastMoveX = x; lastMoveY = y; } } game.move = handleMove; game.down = function (x, y, obj) { if (warrior) { dragging = true; lastMoveX = x; lastMoveY = y; // Fire in the direction opposite to the touch var dx = x - warrior.x; var dy = y - warrior.y; warrior.fire(dx, dy); } }; game.up = function (x, y, obj) { dragging = false; }; // Initialize game when script loads initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
unlockedWeapons: [0]
});
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 30;
self.maxHealth = 30;
self.speed = 2;
self.damage = 10;
self.attackCooldown = 60; // frames
self.attackTimer = 0;
self.scoreValue = 10;
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -80
});
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: -80
});
self.healthBar.width = self.health / self.maxHealth * 100;
self.takeDamage = function (amount) {
self.health -= amount;
self.healthBar.width = self.health / self.maxHealth * 100;
// Flash red when hit
tween(enemyGraphic, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphic, {
alpha: 1
}, {
duration: 100
});
}
});
if (self.health <= 0) {
LK.getSound('enemyDeath').play();
var randomChance = Math.random();
if (randomChance < 0.2) {
// 20% chance to drop powerup
var powerup = new PowerUp();
powerup.x = self.x;
powerup.y = self.y;
game.addChild(powerup);
powerups.push(powerup);
}
self.readyToRemove = true;
return true;
}
return false;
};
self.moveTowards = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
self.update = function () {
if (self.attackTimer > 0) {
self.attackTimer--;
}
};
return self;
});
var BossEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
// Replace the enemy graphic with a boss graphic
self.removeChild(self.children[0]); // Remove regular enemy graphic
var bossGraphic = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 150;
self.maxHealth = 150;
self.speed = 1.5;
self.damage = 20;
self.attackCooldown = 120;
self.scoreValue = 50;
// Update health bar position and size for boss
self.healthBar.y = -120;
self.healthBarBg.y = -120;
self.healthBar.width = 200;
self.healthBarBg.width = 200;
// Special boss attack pattern
var attackPhase = 0;
self.update = function () {
Enemy.prototype.update.call(self); // Call the parent update method
if (self.attackTimer === 0) {
// Boss can fire projectiles
attackPhase = (attackPhase + 1) % 3;
switch (attackPhase) {
case 0:
// Fire in cardinal directions
for (var angle = 0; angle < Math.PI * 2; angle += Math.PI / 2) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.setDirection(Math.cos(angle), Math.sin(angle));
projectile.damage = 15;
projectile.isEnemyProjectile = true;
game.addChild(projectile);
enemyProjectiles.push(projectile);
}
break;
case 1:
// Fire at player
if (warrior) {
var dx = warrior.x - self.x;
var dy = warrior.y - self.y;
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.setDirection(dx, dy);
projectile.damage = 15;
projectile.isEnemyProjectile = true;
game.addChild(projectile);
enemyProjectiles.push(projectile);
}
break;
case 2:
// Spawn minions
var minion = new Enemy();
minion.x = self.x + (Math.random() * 200 - 100);
minion.y = self.y + (Math.random() * 200 - 100);
minion.health = 15;
minion.maxHealth = 15;
minion.speed = 3;
game.addChild(minion);
enemies.push(minion);
break;
}
self.attackTimer = self.attackCooldown;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.floor(Math.random() * 3); // 0: health, 1: speed, 2: damage
// Different colors for different powerup types
switch (self.type) {
case 0:
// Health
powerupGraphic.tint = 0x33cc33; // Green
break;
case 1:
// Speed
powerupGraphic.tint = 0x3366ff; // Blue
break;
case 2:
// Damage
powerupGraphic.tint = 0xff3333; // Red
break;
}
self.lifespan = 300; // frames the powerup will stay
self.age = 0;
// Pulsing animation
self.update = function () {
self.age++;
var scale = 1 + 0.1 * Math.sin(self.age * 0.1);
powerupGraphic.scale.set(scale, scale);
if (self.age >= self.lifespan) {
self.readyToRemove = true;
}
};
self.applyEffect = function (warrior) {
LK.getSound('powerupCollect').play();
switch (self.type) {
case 0:
// Health
warrior.health = Math.min(warrior.health + 30, warrior.maxHealth);
warrior.updateHealthBar();
break;
case 1:
// Speed
warrior.speedBoost = 300; // Number of frames for speed boost
break;
case 2:
// Damage
warrior.damageBoost = 300; // Number of frames for damage boost
break;
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphic = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.damage = 10;
self.direction = {
x: 0,
y: 0
};
self.lifespan = 120; // frames the projectile will live
self.age = 0;
self.setDirection = function (dirX, dirY) {
// Normalize direction vector
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > 0) {
self.direction.x = dirX / length;
self.direction.y = dirY / length;
}
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
self.age++;
if (self.age >= self.lifespan) {
self.readyToRemove = true;
}
};
return self;
});
var Warrior = Container.expand(function () {
var self = Container.call(this);
var warriorGraphic = self.attachAsset('warrior', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 5;
self.damage = 20;
self.attackCooldown = 20; // frames
self.attackTimer = 0;
self.invulnerable = false;
self.invulnerableTime = 0;
self.speedBoost = 0;
self.damageBoost = 0;
// Health bar displayed at the top of the screen
self.healthBar = null;
self.healthBarBg = null;
self.initializeHealthBar = function () {
self.healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 30
});
self.healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
width: 300,
height: 30
});
LK.gui.top.addChild(self.healthBarBg);
self.healthBarBg.y = 50;
LK.gui.top.addChild(self.healthBar);
self.healthBar.y = 50;
self.healthBar.x = self.healthBarBg.x - self.healthBarBg.width / 2;
self.updateHealthBar();
};
self.updateHealthBar = function () {
if (self.healthBar) {
self.healthBar.width = self.health / self.maxHealth * 300;
}
};
self.takeDamage = function (amount) {
if (self.invulnerable) {
return false;
}
self.health -= amount;
self.updateHealthBar();
LK.getSound('playerHit').play();
// Flash and set invulnerable briefly
self.invulnerable = true;
self.invulnerableTime = 60; // 1 second of invulnerability
tween(warriorGraphic, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorGraphic, {
alpha: 1
}, {
duration: 100
});
}
});
if (self.health <= 0) {
LK.getSound('gameOver').play();
LK.showGameOver();
return true;
}
return false;
};
self.fire = function (dirX, dirY) {
if (self.attackTimer === 0) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.setDirection(dirX, dirY);
// Apply damage boost if active
if (self.damageBoost > 0) {
projectile.damage = self.damage * 1.5;
projectile.tint = 0xff0000; // Red tint for boosted projectiles
} else {
projectile.damage = self.damage;
}
game.addChild(projectile);
playerProjectiles.push(projectile);
self.attackTimer = self.attackCooldown;
}
};
self.update = function () {
if (self.attackTimer > 0) {
self.attackTimer--;
}
if (self.invulnerable) {
self.invulnerableTime--;
warriorGraphic.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * 0.2);
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
warriorGraphic.alpha = 1;
}
}
// Handle boosts
if (self.speedBoost > 0) {
self.speedBoost--;
warriorGraphic.tint = 0x3366ff; // Blue tint during speed boost
} else {
warriorGraphic.tint = 0xffffff; // Reset tint
}
if (self.damageBoost > 0) {
self.damageBoost--;
if (!self.speedBoost) {
// Only tint red if not speed boosted
warriorGraphic.tint = 0xff3333; // Red tint during damage boost
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game state variables
var warrior = null;
var enemies = [];
var playerProjectiles = [];
var enemyProjectiles = [];
var powerups = [];
var waveNumber = 1;
var enemiesPerWave = 5;
var score = 0;
var waveClearTimeBonus = 5000; // Base time bonus for clearing waves
var waveStartTime = 0;
var gameActive = false;
var arena = null;
var arenaSize = 1800;
var waveText = null;
var scoreText = null;
var dragging = false;
var lastMoveX = 0;
var lastMoveY = 0;
// Initialize the game
function initGame() {
// Reset game state
warrior = null;
enemies = [];
playerProjectiles = [];
enemyProjectiles = [];
powerups = [];
waveNumber = 1;
enemiesPerWave = 5;
score = 0;
gameActive = true;
// Set score for LK
LK.setScore(score);
// Create arena
arena = LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(arena);
arena.x = 2048 / 2;
arena.y = 2732 / 2;
arena.alpha = 0.5;
// Create warrior
warrior = new Warrior();
warrior.x = 2048 / 2;
warrior.y = 2732 / 2;
game.addChild(warrior);
warrior.initializeHealthBar();
// Create UI elements
createUI();
// Start first wave
startWave();
// Play background music
LK.playMusic('battleMusic');
}
function createUI() {
// Score text
scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
scoreText.x = -20;
scoreText.y = 20;
// Wave text
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0, 0);
LK.gui.topRight.addChild(waveText);
waveText.x = -20;
waveText.y = 80;
}
function updateUI() {
scoreText.setText('Score: ' + score);
waveText.setText('Wave ' + waveNumber);
}
function startWave() {
waveStartTime = Date.now();
// Create enemies for this wave
var enemiesToSpawn = enemiesPerWave + waveNumber;
// Every 3rd wave has a boss
if (waveNumber % 3 === 0) {
var boss = new BossEnemy();
placeEnemyOutsideArena(boss);
game.addChild(boss);
enemies.push(boss);
enemiesToSpawn -= 3; // Boss counts as 3 regular enemies
}
for (var i = 0; i < enemiesToSpawn; i++) {
var enemy = new Enemy();
// Scale difficulty with wave number
enemy.health = 30 + waveNumber * 5;
enemy.maxHealth = enemy.health;
enemy.speed = 2 + waveNumber * 0.1;
enemy.damage = 10 + waveNumber * 2;
placeEnemyOutsideArena(enemy);
game.addChild(enemy);
enemies.push(enemy);
}
updateUI();
}
function placeEnemyOutsideArena(enemy) {
var angle = Math.random() * Math.PI * 2;
var distance = arenaSize / 2 + 100 + Math.random() * 300; // Spawn outside arena
enemy.x = 2048 / 2 + Math.cos(angle) * distance;
enemy.y = 2732 / 2 + Math.sin(angle) * distance;
}
function waveCompleted() {
// Calculate time bonus
var timeElapsed = Date.now() - waveStartTime;
var timeBonus = Math.max(0, waveClearTimeBonus - Math.floor(timeElapsed / 100));
score += timeBonus;
LK.setScore(score);
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Play victory sound
LK.getSound('waveComplete').play();
// Flash screen
LK.effects.flashScreen(0x33cc33, 500);
// Next wave
waveNumber++;
enemiesPerWave += 2;
// Brief delay before next wave
LK.setTimeout(function () {
startWave();
}, 2000);
}
// Game update function
game.update = function () {
if (!gameActive) {
return;
}
// Update warrior
if (warrior) {
warrior.update();
// Move warrior if dragging
if (dragging) {
// Calculate actual speed based on speed boost
var actualSpeed = warrior.speed;
if (warrior.speedBoost > 0) {
actualSpeed *= 1.5;
}
// Calculate direction to move
var dx = lastMoveX - warrior.x;
var dy = lastMoveY - warrior.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > actualSpeed) {
warrior.x += dx / distance * actualSpeed;
warrior.y += dy / distance * actualSpeed;
} else {
warrior.x = lastMoveX;
warrior.y = lastMoveY;
}
// Keep warrior inside the arena
var arenaRadius = arenaSize / 2;
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var dx = warrior.x - centerX;
var dy = warrior.y - centerY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > arenaRadius) {
warrior.x = centerX + dx / distance * arenaRadius;
warrior.y = centerY + dy / distance * arenaRadius;
}
}
// Check for powerup collisions
for (var i = powerups.length - 1; i >= 0; i--) {
if (warrior.intersects(powerups[i])) {
powerups[i].applyEffect(warrior);
powerups[i].destroy();
powerups.splice(i, 1);
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Move towards warrior
if (warrior) {
enemy.moveTowards(warrior.x, warrior.y);
// Check for collision with warrior
if (warrior.intersects(enemy) && enemy.attackTimer === 0) {
warrior.takeDamage(enemy.damage);
enemy.attackTimer = enemy.attackCooldown;
}
}
// Remove dead enemies
if (enemy.readyToRemove) {
score += enemy.scoreValue;
LK.setScore(score);
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update player projectiles
for (var i = playerProjectiles.length - 1; i >= 0; i--) {
var proj = playerProjectiles[i];
proj.update();
// Check for enemy hits
for (var j = enemies.length - 1; j >= 0; j--) {
if (proj.intersects(enemies[j])) {
LK.getSound('hit').play();
var killed = enemies[j].takeDamage(proj.damage);
if (killed) {
score += enemies[j].scoreValue;
LK.setScore(score);
}
proj.readyToRemove = true;
break;
}
}
// Remove projectiles that are off-screen or have hit something
if (proj.readyToRemove || proj.x < 0 || proj.x > 2048 || proj.y < 0 || proj.y > 2732) {
proj.destroy();
playerProjectiles.splice(i, 1);
}
}
// Update enemy projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
var proj = enemyProjectiles[i];
proj.update();
// Check for warrior hit
if (warrior && proj.intersects(warrior)) {
warrior.takeDamage(proj.damage);
proj.readyToRemove = true;
}
// Remove projectiles that are off-screen or have hit something
if (proj.readyToRemove || proj.x < 0 || proj.x > 2048 || proj.y < 0 || proj.y > 2732) {
proj.destroy();
enemyProjectiles.splice(i, 1);
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].update();
if (powerups[i].readyToRemove) {
powerups[i].destroy();
powerups.splice(i, 1);
}
}
// Check if wave is completed
if (enemies.length === 0) {
waveCompleted();
}
// Update UI
updateUI();
};
// Input handling
function handleMove(x, y, obj) {
if (dragging && warrior) {
lastMoveX = x;
lastMoveY = y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (warrior) {
dragging = true;
lastMoveX = x;
lastMoveY = y;
// Fire in the direction opposite to the touch
var dx = x - warrior.x;
var dy = y - warrior.y;
warrior.fire(dx, dy);
}
};
game.up = function (x, y, obj) {
dragging = false;
};
// Initialize game when script loads
initGame();