/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestScore: 0
});
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Base = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.isPlayerBase = true;
// Health bar background
self.healthBarBg = self.attachAsset('unit', {
width: 300,
height: 20,
color: 0x000000,
anchorX: 0.5,
anchorY: 0.5,
y: -180
});
// Health bar foreground
self.healthBar = self.attachAsset('unit', {
width: 300,
height: 20,
color: 0x00ff00,
anchorX: 0,
anchorY: 0.5,
y: -180,
x: -150
});
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) {
self.health = 0;
}
// Update health bar width
self.healthBar.width = self.health / 100 * 300;
if (self.health <= 0 && self.isPlayerBase) {
LK.showGameOver();
} else if (self.health <= 0 && !self.isPlayerBase) {
// Player wins
LK.setScore(LK.getScore() + 1000);
LK.showYouWin();
}
};
return self;
});
var EnemyBase = Base.expand(function () {
var self = Base.call(this);
// Override base graphics with enemy base
self.graphics.destroy();
self.graphics = self.attachAsset('enemyBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.healthBar.tint = 0xff0000;
self.isPlayerBase = false;
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.alive = true;
self.targetUnit = null;
self.lastPosition = {
x: 0,
y: 0
};
self.update = function () {
if (!self.alive) {
return;
}
self.lastPosition.x = self.x;
self.lastPosition.y = self.y;
// If we have a target unit, move toward it
if (self.targetUnit && self.targetUnit.alive) {
var dx = self.targetUnit.x - self.x;
var dy = self.targetUnit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// No target or target is dead, find new target
self.findNewTarget();
}
};
self.findNewTarget = function () {
var closestUnit = null;
var closestDistance = Infinity;
// Find the closest military unit
for (var i = 0; i < units.length; i++) {
var unit = units[i];
if (!unit.alive) {
continue;
}
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If target is in stealth mode and not super close, can't detect it
if (unit.state === "stealth" && distance > 100) {
continue;
}
if (distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
self.targetUnit = closestUnit;
};
self.kill = function () {
if (!self.alive) {
return;
}
self.alive = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var MilitaryUnit = Container.expand(function () {
var self = Container.call(this);
// Default state is normal
self.state = "normal";
self.targetPosition = null;
self.speed = 5;
self.alive = true;
self.score = 0;
// Normal unit representation
self.normalGraphics = self.attachAsset('unit', {
anchorX: 0.5,
anchorY: 0.5
});
// Stealth unit representation (initially hidden)
self.stealthGraphics = self.attachAsset('stealth', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Attack unit representation (initially hidden)
self.attackGraphics = self.attachAsset('attack', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Set initial state
self.setState = function (newState) {
if (newState === self.state) {
return;
}
// Hide all graphics first
self.normalGraphics.alpha = 0;
self.stealthGraphics.alpha = 0;
self.attackGraphics.alpha = 0;
// Show the appropriate graphics
if (newState === "normal") {
self.normalGraphics.alpha = 1;
self.speed = 5;
} else if (newState === "stealth") {
self.stealthGraphics.alpha = 1;
self.speed = 3; // Slower in stealth mode
} else if (newState === "attack") {
self.attackGraphics.alpha = 1;
self.speed = 7; // Faster in attack mode
}
self.state = newState;
};
// Move toward target if one is set
self.update = function () {
if (!self.alive) {
return;
}
if (self.targetPosition) {
var dx = self.targetPosition.x - self.x;
var dy = self.targetPosition.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.x = self.targetPosition.x;
self.y = self.targetPosition.y;
self.targetPosition = null;
}
}
};
// Destroy unit
self.kill = function () {
if (!self.alive) {
return;
}
self.alive = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
// Pulse animation
self.pulse = function () {
tween(self.graphics, {
alpha: 0.8,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.graphics, {
alpha: 0.5,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeIn
});
}
});
};
self.pulse();
return self;
});
var VoiceIndicator = Container.expand(function () {
var self = Container.call(this);
// Background
self.bg = self.attachAsset('unit', {
width: 400,
height: 100,
color: 0x000000,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
// Voice level indicator
self.level = self.attachAsset('unit', {
width: 0,
height: 80,
color: 0x00ff00,
anchorX: 0,
anchorY: 0.5,
x: -190
});
// Text labels
self.whisperText = new Text2("Whisper", {
size: 40,
fill: 0xFFFFFF
});
self.whisperText.anchor.set(0.5);
self.whisperText.x = -135;
self.whisperText.y = 50;
self.addChild(self.whisperText);
self.normalText = new Text2("Normal", {
size: 40,
fill: 0xFFFFFF
});
self.normalText.anchor.set(0.5);
self.normalText.x = 0;
self.normalText.y = 50;
self.addChild(self.normalText);
self.shoutText = new Text2("Shout", {
size: 40,
fill: 0xFFFFFF
});
self.shoutText.anchor.set(0.5);
self.shoutText.x = 135;
self.shoutText.y = 50;
self.addChild(self.shoutText);
// Update the indicator based on volume
self.update = function () {
var volume = facekit.volume;
// Calculate width based on volume (0-1)
var width = volume * 380;
self.level.width = width;
// Change color based on volume
if (volume < 0.3) {
self.level.tint = 0x33cc33; // Green for whisper
} else if (volume > 0.7) {
self.level.tint = 0xcc3333; // Red for shout
} else {
self.level.tint = 0x3366cc; // Blue for normal
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game state variables
var units = [];
var enemies = [];
var target = null;
var playerBase = null;
var enemyBase = null;
var voiceIndicator = null;
var voiceMode = "normal";
var lastVoiceMode = "normal";
var lastSpawnTime = 0;
var currentWave = 1;
var gameStarted = false;
// Setup GUI
var scoreTxt = new Text2("Score: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2("Wave: 1", {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(1, 0);
waveTxt.x = -50;
LK.gui.topRight.addChild(waveTxt);
var instructionsTxt = new Text2("Use your voice to command units:\nWhisper - Stealth Mode\nNormal Voice - Normal Mode\nShout - Attack Mode\n\nTap to place target location", {
size: 50,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsTxt);
var startButton = LK.getAsset('unit', {
width: 300,
height: 100,
color: 0x3366cc,
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.center.addChild(startButton);
startButton.y = 200;
var startText = new Text2("START", {
size: 60,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startButton.addChild(startText);
// Start game when button is pressed
startButton.down = function () {
startGame();
};
function startGame() {
gameStarted = true;
LK.gui.center.removeChild(instructionsTxt);
LK.gui.center.removeChild(startButton);
// Create bases
playerBase = new Base();
playerBase.x = 1024;
playerBase.y = 2300;
game.addChild(playerBase);
enemyBase = new EnemyBase();
enemyBase.x = 1024;
enemyBase.y = 400;
game.addChild(enemyBase);
// Create voice indicator
voiceIndicator = new VoiceIndicator();
voiceIndicator.x = 1024;
voiceIndicator.y = 2600;
game.addChild(voiceIndicator);
// Create initial units
createUnit(900, 2000);
createUnit(1150, 2000);
// Start background music
LK.playMusic('bgmusic');
}
function createUnit(x, y) {
var unit = new MilitaryUnit();
unit.x = x;
unit.y = y;
game.addChild(unit);
units.push(unit);
return unit;
}
function createEnemy(x, y) {
var enemy = new Enemy();
enemy.x = x;
enemy.y = y;
game.addChild(enemy);
enemies.push(enemy);
return enemy;
}
function spawnEnemies() {
var now = Date.now();
if (now - lastSpawnTime > 5000) {
// Spawn every 5 seconds
lastSpawnTime = now;
// Spawn enemies based on wave
var count = Math.min(2 + currentWave, 8);
for (var i = 0; i < count; i++) {
var x = 400 + Math.random() * 1248;
var y = 400 + Math.random() * 200;
createEnemy(x, y);
}
// Increase wave
currentWave++;
waveTxt.setText("Wave: " + currentWave);
}
}
function createTarget(x, y) {
// Remove existing target if there is one
if (target) {
target.destroy();
}
// Create new target
target = new Target();
target.x = x;
target.y = y;
game.addChild(target);
// Command all units to move to target
for (var i = 0; i < units.length; i++) {
if (units[i].alive) {
units[i].targetPosition = {
x: x,
y: y
};
}
}
// Play sound based on voice mode
if (voiceMode === "stealth") {
LK.getSound('stealth').play();
} else if (voiceMode === "attack") {
LK.getSound('attack').play();
} else {
LK.getSound('order').play();
}
}
function checkCollisions() {
// Check for enemy-unit collisions
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy.alive) {
continue;
}
// Check collision with player base
if (playerBase && enemy.intersects(playerBase)) {
playerBase.takeDamage(1);
enemy.kill();
enemies.splice(i, 1);
continue;
}
// Check collision with units
for (var j = units.length - 1; j >= 0; j--) {
var unit = units[j];
if (!unit.alive) {
continue;
}
if (unit.intersects(enemy)) {
// Combat outcome depends on unit state
if (unit.state === "attack") {
// Unit is in attack mode, more likely to win
enemy.kill();
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 100);
break;
} else if (unit.state === "stealth") {
// Stealth units can sometimes evade
if (Math.random() > 0.7) {
// Unit escapes
unit.x += Math.random() * 100 - 50;
unit.y += Math.random() * 100 - 50;
} else {
unit.kill();
units.splice(j, 1);
}
} else {
// Normal combat, 50/50 chance
if (Math.random() > 0.5) {
enemy.kill();
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 50);
} else {
unit.kill();
units.splice(j, 1);
}
break;
}
}
}
}
// Check for units reaching enemy base
for (var k = units.length - 1; k >= 0; k--) {
var unit = units[k];
if (!unit.alive) {
continue;
}
if (enemyBase && unit.intersects(enemyBase)) {
// Unit is attacking enemy base
var damage = unit.state === "attack" ? 20 : 10;
enemyBase.takeDamage(damage);
unit.kill();
units.splice(k, 1);
LK.setScore(LK.getScore() + 200);
}
}
}
function determineVoiceMode() {
var volume = facekit.volume;
if (volume < 0.1) {
// No sound, keep previous mode
return voiceMode;
} else if (volume < 0.3) {
return "stealth";
} else if (volume > 0.7) {
return "attack";
} else {
return "normal";
}
}
function spawnNewUnits() {
// Spawn new units every 10 seconds if we have fewer than 5
if (LK.ticks % 600 === 0 && units.length < 5) {
createUnit(900 + Math.random() * 250, 2000 + Math.random() * 200);
}
}
function updateScore() {
scoreTxt.setText("Score: " + LK.getScore());
// Store best score if current score is higher
if (LK.getScore() > storage.bestScore) {
storage.bestScore = LK.getScore();
}
}
// Game down event - place target
game.down = function (x, y) {
if (!gameStarted) {
return;
}
// Don't place target too close to enemy base or on bases
var distToEnemyBase = Math.sqrt(Math.pow(x - enemyBase.x, 2) + Math.pow(y - enemyBase.y, 2));
var distToPlayerBase = Math.sqrt(Math.pow(x - playerBase.x, 2) + Math.pow(y - playerBase.y, 2));
if (distToEnemyBase > 350 && distToPlayerBase > 350) {
createTarget(x, y);
}
};
// Game tick event
game.update = function () {
if (!gameStarted) {
return;
}
// Update voice mode based on audio input
voiceMode = determineVoiceMode();
// Update voice indicator
if (voiceIndicator) {
voiceIndicator.update();
}
// Update all units with current voice mode
if (voiceMode !== lastVoiceMode) {
for (var i = 0; i < units.length; i++) {
if (units[i].alive) {
units[i].setState(voiceMode);
}
}
lastVoiceMode = voiceMode;
}
// Check for collisions
checkCollisions();
// Spawn enemies
spawnEnemies();
// Spawn new units if needed
spawnNewUnits();
// Update score display
updateScore();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestScore: 0
});
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Base = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.isPlayerBase = true;
// Health bar background
self.healthBarBg = self.attachAsset('unit', {
width: 300,
height: 20,
color: 0x000000,
anchorX: 0.5,
anchorY: 0.5,
y: -180
});
// Health bar foreground
self.healthBar = self.attachAsset('unit', {
width: 300,
height: 20,
color: 0x00ff00,
anchorX: 0,
anchorY: 0.5,
y: -180,
x: -150
});
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) {
self.health = 0;
}
// Update health bar width
self.healthBar.width = self.health / 100 * 300;
if (self.health <= 0 && self.isPlayerBase) {
LK.showGameOver();
} else if (self.health <= 0 && !self.isPlayerBase) {
// Player wins
LK.setScore(LK.getScore() + 1000);
LK.showYouWin();
}
};
return self;
});
var EnemyBase = Base.expand(function () {
var self = Base.call(this);
// Override base graphics with enemy base
self.graphics.destroy();
self.graphics = self.attachAsset('enemyBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.healthBar.tint = 0xff0000;
self.isPlayerBase = false;
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.alive = true;
self.targetUnit = null;
self.lastPosition = {
x: 0,
y: 0
};
self.update = function () {
if (!self.alive) {
return;
}
self.lastPosition.x = self.x;
self.lastPosition.y = self.y;
// If we have a target unit, move toward it
if (self.targetUnit && self.targetUnit.alive) {
var dx = self.targetUnit.x - self.x;
var dy = self.targetUnit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// No target or target is dead, find new target
self.findNewTarget();
}
};
self.findNewTarget = function () {
var closestUnit = null;
var closestDistance = Infinity;
// Find the closest military unit
for (var i = 0; i < units.length; i++) {
var unit = units[i];
if (!unit.alive) {
continue;
}
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If target is in stealth mode and not super close, can't detect it
if (unit.state === "stealth" && distance > 100) {
continue;
}
if (distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
self.targetUnit = closestUnit;
};
self.kill = function () {
if (!self.alive) {
return;
}
self.alive = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var MilitaryUnit = Container.expand(function () {
var self = Container.call(this);
// Default state is normal
self.state = "normal";
self.targetPosition = null;
self.speed = 5;
self.alive = true;
self.score = 0;
// Normal unit representation
self.normalGraphics = self.attachAsset('unit', {
anchorX: 0.5,
anchorY: 0.5
});
// Stealth unit representation (initially hidden)
self.stealthGraphics = self.attachAsset('stealth', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Attack unit representation (initially hidden)
self.attackGraphics = self.attachAsset('attack', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Set initial state
self.setState = function (newState) {
if (newState === self.state) {
return;
}
// Hide all graphics first
self.normalGraphics.alpha = 0;
self.stealthGraphics.alpha = 0;
self.attackGraphics.alpha = 0;
// Show the appropriate graphics
if (newState === "normal") {
self.normalGraphics.alpha = 1;
self.speed = 5;
} else if (newState === "stealth") {
self.stealthGraphics.alpha = 1;
self.speed = 3; // Slower in stealth mode
} else if (newState === "attack") {
self.attackGraphics.alpha = 1;
self.speed = 7; // Faster in attack mode
}
self.state = newState;
};
// Move toward target if one is set
self.update = function () {
if (!self.alive) {
return;
}
if (self.targetPosition) {
var dx = self.targetPosition.x - self.x;
var dy = self.targetPosition.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.x = self.targetPosition.x;
self.y = self.targetPosition.y;
self.targetPosition = null;
}
}
};
// Destroy unit
self.kill = function () {
if (!self.alive) {
return;
}
self.alive = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
// Pulse animation
self.pulse = function () {
tween(self.graphics, {
alpha: 0.8,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.graphics, {
alpha: 0.5,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeIn
});
}
});
};
self.pulse();
return self;
});
var VoiceIndicator = Container.expand(function () {
var self = Container.call(this);
// Background
self.bg = self.attachAsset('unit', {
width: 400,
height: 100,
color: 0x000000,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
// Voice level indicator
self.level = self.attachAsset('unit', {
width: 0,
height: 80,
color: 0x00ff00,
anchorX: 0,
anchorY: 0.5,
x: -190
});
// Text labels
self.whisperText = new Text2("Whisper", {
size: 40,
fill: 0xFFFFFF
});
self.whisperText.anchor.set(0.5);
self.whisperText.x = -135;
self.whisperText.y = 50;
self.addChild(self.whisperText);
self.normalText = new Text2("Normal", {
size: 40,
fill: 0xFFFFFF
});
self.normalText.anchor.set(0.5);
self.normalText.x = 0;
self.normalText.y = 50;
self.addChild(self.normalText);
self.shoutText = new Text2("Shout", {
size: 40,
fill: 0xFFFFFF
});
self.shoutText.anchor.set(0.5);
self.shoutText.x = 135;
self.shoutText.y = 50;
self.addChild(self.shoutText);
// Update the indicator based on volume
self.update = function () {
var volume = facekit.volume;
// Calculate width based on volume (0-1)
var width = volume * 380;
self.level.width = width;
// Change color based on volume
if (volume < 0.3) {
self.level.tint = 0x33cc33; // Green for whisper
} else if (volume > 0.7) {
self.level.tint = 0xcc3333; // Red for shout
} else {
self.level.tint = 0x3366cc; // Blue for normal
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game state variables
var units = [];
var enemies = [];
var target = null;
var playerBase = null;
var enemyBase = null;
var voiceIndicator = null;
var voiceMode = "normal";
var lastVoiceMode = "normal";
var lastSpawnTime = 0;
var currentWave = 1;
var gameStarted = false;
// Setup GUI
var scoreTxt = new Text2("Score: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2("Wave: 1", {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(1, 0);
waveTxt.x = -50;
LK.gui.topRight.addChild(waveTxt);
var instructionsTxt = new Text2("Use your voice to command units:\nWhisper - Stealth Mode\nNormal Voice - Normal Mode\nShout - Attack Mode\n\nTap to place target location", {
size: 50,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsTxt);
var startButton = LK.getAsset('unit', {
width: 300,
height: 100,
color: 0x3366cc,
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.center.addChild(startButton);
startButton.y = 200;
var startText = new Text2("START", {
size: 60,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startButton.addChild(startText);
// Start game when button is pressed
startButton.down = function () {
startGame();
};
function startGame() {
gameStarted = true;
LK.gui.center.removeChild(instructionsTxt);
LK.gui.center.removeChild(startButton);
// Create bases
playerBase = new Base();
playerBase.x = 1024;
playerBase.y = 2300;
game.addChild(playerBase);
enemyBase = new EnemyBase();
enemyBase.x = 1024;
enemyBase.y = 400;
game.addChild(enemyBase);
// Create voice indicator
voiceIndicator = new VoiceIndicator();
voiceIndicator.x = 1024;
voiceIndicator.y = 2600;
game.addChild(voiceIndicator);
// Create initial units
createUnit(900, 2000);
createUnit(1150, 2000);
// Start background music
LK.playMusic('bgmusic');
}
function createUnit(x, y) {
var unit = new MilitaryUnit();
unit.x = x;
unit.y = y;
game.addChild(unit);
units.push(unit);
return unit;
}
function createEnemy(x, y) {
var enemy = new Enemy();
enemy.x = x;
enemy.y = y;
game.addChild(enemy);
enemies.push(enemy);
return enemy;
}
function spawnEnemies() {
var now = Date.now();
if (now - lastSpawnTime > 5000) {
// Spawn every 5 seconds
lastSpawnTime = now;
// Spawn enemies based on wave
var count = Math.min(2 + currentWave, 8);
for (var i = 0; i < count; i++) {
var x = 400 + Math.random() * 1248;
var y = 400 + Math.random() * 200;
createEnemy(x, y);
}
// Increase wave
currentWave++;
waveTxt.setText("Wave: " + currentWave);
}
}
function createTarget(x, y) {
// Remove existing target if there is one
if (target) {
target.destroy();
}
// Create new target
target = new Target();
target.x = x;
target.y = y;
game.addChild(target);
// Command all units to move to target
for (var i = 0; i < units.length; i++) {
if (units[i].alive) {
units[i].targetPosition = {
x: x,
y: y
};
}
}
// Play sound based on voice mode
if (voiceMode === "stealth") {
LK.getSound('stealth').play();
} else if (voiceMode === "attack") {
LK.getSound('attack').play();
} else {
LK.getSound('order').play();
}
}
function checkCollisions() {
// Check for enemy-unit collisions
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy.alive) {
continue;
}
// Check collision with player base
if (playerBase && enemy.intersects(playerBase)) {
playerBase.takeDamage(1);
enemy.kill();
enemies.splice(i, 1);
continue;
}
// Check collision with units
for (var j = units.length - 1; j >= 0; j--) {
var unit = units[j];
if (!unit.alive) {
continue;
}
if (unit.intersects(enemy)) {
// Combat outcome depends on unit state
if (unit.state === "attack") {
// Unit is in attack mode, more likely to win
enemy.kill();
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 100);
break;
} else if (unit.state === "stealth") {
// Stealth units can sometimes evade
if (Math.random() > 0.7) {
// Unit escapes
unit.x += Math.random() * 100 - 50;
unit.y += Math.random() * 100 - 50;
} else {
unit.kill();
units.splice(j, 1);
}
} else {
// Normal combat, 50/50 chance
if (Math.random() > 0.5) {
enemy.kill();
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 50);
} else {
unit.kill();
units.splice(j, 1);
}
break;
}
}
}
}
// Check for units reaching enemy base
for (var k = units.length - 1; k >= 0; k--) {
var unit = units[k];
if (!unit.alive) {
continue;
}
if (enemyBase && unit.intersects(enemyBase)) {
// Unit is attacking enemy base
var damage = unit.state === "attack" ? 20 : 10;
enemyBase.takeDamage(damage);
unit.kill();
units.splice(k, 1);
LK.setScore(LK.getScore() + 200);
}
}
}
function determineVoiceMode() {
var volume = facekit.volume;
if (volume < 0.1) {
// No sound, keep previous mode
return voiceMode;
} else if (volume < 0.3) {
return "stealth";
} else if (volume > 0.7) {
return "attack";
} else {
return "normal";
}
}
function spawnNewUnits() {
// Spawn new units every 10 seconds if we have fewer than 5
if (LK.ticks % 600 === 0 && units.length < 5) {
createUnit(900 + Math.random() * 250, 2000 + Math.random() * 200);
}
}
function updateScore() {
scoreTxt.setText("Score: " + LK.getScore());
// Store best score if current score is higher
if (LK.getScore() > storage.bestScore) {
storage.bestScore = LK.getScore();
}
}
// Game down event - place target
game.down = function (x, y) {
if (!gameStarted) {
return;
}
// Don't place target too close to enemy base or on bases
var distToEnemyBase = Math.sqrt(Math.pow(x - enemyBase.x, 2) + Math.pow(y - enemyBase.y, 2));
var distToPlayerBase = Math.sqrt(Math.pow(x - playerBase.x, 2) + Math.pow(y - playerBase.y, 2));
if (distToEnemyBase > 350 && distToPlayerBase > 350) {
createTarget(x, y);
}
};
// Game tick event
game.update = function () {
if (!gameStarted) {
return;
}
// Update voice mode based on audio input
voiceMode = determineVoiceMode();
// Update voice indicator
if (voiceIndicator) {
voiceIndicator.update();
}
// Update all units with current voice mode
if (voiceMode !== lastVoiceMode) {
for (var i = 0; i < units.length; i++) {
if (units[i].alive) {
units[i].setState(voiceMode);
}
}
lastVoiceMode = voiceMode;
}
// Check for collisions
checkCollisions();
// Spawn enemies
spawnEnemies();
// Spawn new units if needed
spawnNewUnits();
// Update score display
updateScore();
};