/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; self.power = 1; self.update = function () { self.y += self.speed; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyShip', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.health = 1; self.moveDirection = 1; // 1 for right, -1 for left self.moveDistance = 0; self.maxDistance = 200; // Maximum horizontal movement self.descendAmount = 50; // Amount to descend after changing direction self.hit = function (damage) { self.health -= damage; if (self.health <= 0) { return true; // Enemy is destroyed } // Visual feedback for hit tween(enemyGraphics, { tint: 0xff0000 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { tween(enemyGraphics, { tint: 0xffffff }, { duration: 100, easing: tween.linear }); } }); return false; // Enemy still alive }; self.update = function () { // Move horizontally self.x += self.speed * self.moveDirection; self.moveDistance += Math.abs(self.speed); // Change direction and descend when reached max distance if (self.moveDistance >= self.maxDistance) { self.moveDirection *= -1; // Reverse direction self.y += self.descendAmount; // Move down self.moveDistance = 0; // Reset distance counter } // Simple rotation animation self.rotation = Math.sin(LK.ticks / 30) * 0.1; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.canFire = true; self.fireDelay = 300; self.lastFired = 0; self.specialWeapon = false; self.specialTimer = 0; self.lives = 3; self.fire = function () { var currentTime = Date.now(); if (self.canFire && currentTime - self.lastFired > self.fireDelay) { var bullet; if (self.specialWeapon) { bullet = new SpecialBullet(); } else { bullet = new Bullet(); } bullet.x = self.x; bullet.y = self.y - 60; game.addChild(bullet); bullets.push(bullet); LK.getSound('laser').play(); self.lastFired = currentTime; } }; self.activateSpecialWeapon = function () { self.specialWeapon = true; self.specialTimer = 5000; // Special weapon lasts for 5 seconds // Visual feedback for special weapon tween(shipGraphics, { tint: 0xffff00 }, { duration: 300, easing: tween.easeOut }); }; self.update = function () { // Update special weapon timer if (self.specialWeapon && self.specialTimer > 0) { self.specialTimer -= 16.67; // Approximate for 60fps if (self.specialTimer <= 0) { self.specialWeapon = false; tween(shipGraphics, { tint: 0xffffff }, { duration: 300, easing: tween.easeOut }); } } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.type = "special"; // Default type self.update = function () { self.y += self.speed; self.rotation += 0.03; }; return self; }); var SpecialBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('specialBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -18; self.power = 3; self.radius = 25; self.update = function () { self.y += self.speed; self.rotation += 0.1; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ // Game variables var player; var bullets = []; var enemies = []; var powerUps = []; var gameStarted = false; var gameOver = false; var score = 0; var level = 1; var enemiesPerRow = 5; var enemyRows = 3; var enemySpawnDelay = 800; var lastEnemySpawn = 0; var powerUpChance = 0.2; var highScore = storage.highScore || 0; // UI Elements var scoreTxt = new Text2('SCORE: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -scoreTxt.width - 20; scoreTxt.y = 20; var levelTxt = new Text2('LEVEL: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 20; var instructionsTxt = new Text2('Open mouth to FIRE\nMake noise for SPECIAL ATTACK', { size: 40, fill: 0xFFFFFF }); instructionsTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(instructionsTxt); instructionsTxt.y = -100; var livesTxt = new Text2('LIVES: 3', { size: 60, fill: 0xFFFFFF }); livesTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(livesTxt); livesTxt.x = 120; // Keep away from top-left corner (menu icon) livesTxt.y = 20; // Start the game function startGame() { if (!gameStarted) { gameStarted = true; // Initialize player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 200; game.addChild(player); // Reset game state score = 0; level = 1; bullets = []; enemies = []; powerUps = []; // Start background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); // Start spawning enemies spawnEnemyWave(); } } // Spawn wave of enemies function spawnEnemyWave() { var startX = (2048 - enemiesPerRow * 150) / 2 + 75; var startY = 200; for (var row = 0; row < enemyRows; row++) { for (var col = 0; col < enemiesPerRow; col++) { var enemy = new Enemy(); enemy.x = startX + col * 150; enemy.y = startY + row * 120; enemy.health = Math.ceil(level / 3); // Increase health every 3 levels enemy.speed = 1 + level * 0.5; // Increase speed with level // Alternate movement direction by row if (row % 2 === 1) { enemy.moveDirection = -1; } game.addChild(enemy); enemies.push(enemy); } } } // Spawn a power-up function spawnPowerUp(x, y) { if (Math.random() < powerUpChance) { var powerUp = new PowerUp(); powerUp.x = x; powerUp.y = y; game.addChild(powerUp); powerUps.push(powerUp); } } // Update score display function updateScoreDisplay() { scoreTxt.setText("SCORE: " + score); levelTxt.setText("LEVEL: " + level); livesTxt.setText("LIVES: " + player.lives); } // Check for level completion function checkLevelComplete() { if (enemies.length === 0) { level++; enemiesPerRow = Math.min(enemiesPerRow + 1, 8); enemyRows = Math.min(enemyRows + 1, 5); powerUpChance = Math.min(powerUpChance + 0.05, 0.5); // Clear all bullets for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); } bullets = []; // Spawn new enemy wave spawnEnemyWave(); // Update level display updateScoreDisplay(); } } // Check for game over conditions function checkGameOver() { // Check if player has no lives left if (player.lives <= 0) { endGame(); return; } // Check if any enemies have reached the bottom for (var i = 0; i < enemies.length; i++) { if (enemies[i].y > 2732 - 150) { endGame(); return; } } } // End game function function endGame() { gameOver = true; gameStarted = false; // Check for high score if (score > highScore) { highScore = score; storage.highScore = highScore; } // Show game over screen LK.showGameOver(); // Stop music LK.stopMusic(); } // Main update function game.update = function () { // Start game if face is detected and game not started if (facekit.mouthCenter && !gameStarted && !gameOver) { startGame(); } if (gameStarted && !gameOver) { // Update player position based on face position if (facekit.mouthCenter) { var targetX = facekit.mouthCenter.x; player.x += (targetX - player.x) * 0.2; // Smooth movement // Fire weapon if mouth is open if (facekit.mouthOpen) { player.fire(); } // Activate special weapon if making noise if (facekit.volume > 0.3 && !player.specialWeapon) { player.activateSpecialWeapon(); } } // Update player player.update(); // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Update bullet position bullet.update(); // Remove bullets that go off screen if (bullet.y < -100) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check for collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { var destroyed = enemy.hit(bullet.power); if (destroyed) { // Add score score += 10 * level; // Play explosion sound LK.getSound('explosion').play(); // Flash effect for destroyed enemy LK.effects.flashObject(enemy, 0xff0000, 200); // Possibly spawn power-up spawnPowerUp(enemy.x, enemy.y); // Remove enemy enemy.destroy(); enemies.splice(j, 1); } // Remove bullet bullet.destroy(); bullets.splice(i, 1); break; } } } // Update enemies for (var i = 0; i < enemies.length; i++) { enemies[i].update(); // Check for collision with player if (enemies[i].intersects(player)) { player.lives--; // Flash screen red LK.effects.flashScreen(0xff0000, 300); // Remove enemy enemies[i].destroy(); enemies.splice(i, 1); i--; // Check if game over if (player.lives <= 0) { checkGameOver(); } else { updateScoreDisplay(); } continue; } } // Update power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; // Update power-up position powerUp.update(); // Remove power-ups that go off screen if (powerUp.y > 2732 + 100) { powerUp.destroy(); powerUps.splice(i, 1); continue; } // Check for collision with player if (powerUp.intersects(player)) { // Apply power-up effect player.activateSpecialWeapon(); // Play power-up sound LK.getSound('powerup').play(); // Remove power-up powerUp.destroy(); powerUps.splice(i, 1); } } // Check if level is complete checkLevelComplete(); // Check for game over conditions checkGameOver(); // Update UI updateScoreDisplay(); } }; // Event handlers game.down = function (x, y, obj) { // Touch to start game if (!gameStarted && !gameOver) { startGame(); } }; // Start with an instructional message var startText = new Text2('Face the camera and\nopen your mouth to start!', { size: 80, fill: 0xFFFFFF }); startText.anchor.set(0.5, 0.5); startText.x = 2048 / 2; startText.y = 2732 / 2; game.addChild(startText); // Remove start text when game starts var checkStarted = LK.setInterval(function () { if (gameStarted) { startText.destroy(); LK.clearInterval(checkStarted); } }, 100);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.power = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.moveDirection = 1; // 1 for right, -1 for left
self.moveDistance = 0;
self.maxDistance = 200; // Maximum horizontal movement
self.descendAmount = 50; // Amount to descend after changing direction
self.hit = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // Enemy is destroyed
}
// Visual feedback for hit
tween(enemyGraphics, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 100,
easing: tween.linear
});
}
});
return false; // Enemy still alive
};
self.update = function () {
// Move horizontally
self.x += self.speed * self.moveDirection;
self.moveDistance += Math.abs(self.speed);
// Change direction and descend when reached max distance
if (self.moveDistance >= self.maxDistance) {
self.moveDirection *= -1; // Reverse direction
self.y += self.descendAmount; // Move down
self.moveDistance = 0; // Reset distance counter
}
// Simple rotation animation
self.rotation = Math.sin(LK.ticks / 30) * 0.1;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.canFire = true;
self.fireDelay = 300;
self.lastFired = 0;
self.specialWeapon = false;
self.specialTimer = 0;
self.lives = 3;
self.fire = function () {
var currentTime = Date.now();
if (self.canFire && currentTime - self.lastFired > self.fireDelay) {
var bullet;
if (self.specialWeapon) {
bullet = new SpecialBullet();
} else {
bullet = new Bullet();
}
bullet.x = self.x;
bullet.y = self.y - 60;
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('laser').play();
self.lastFired = currentTime;
}
};
self.activateSpecialWeapon = function () {
self.specialWeapon = true;
self.specialTimer = 5000; // Special weapon lasts for 5 seconds
// Visual feedback for special weapon
tween(shipGraphics, {
tint: 0xffff00
}, {
duration: 300,
easing: tween.easeOut
});
};
self.update = function () {
// Update special weapon timer
if (self.specialWeapon && self.specialTimer > 0) {
self.specialTimer -= 16.67; // Approximate for 60fps
if (self.specialTimer <= 0) {
self.specialWeapon = false;
tween(shipGraphics, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.type = "special"; // Default type
self.update = function () {
self.y += self.speed;
self.rotation += 0.03;
};
return self;
});
var SpecialBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('specialBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -18;
self.power = 3;
self.radius = 25;
self.update = function () {
self.y += self.speed;
self.rotation += 0.1;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var bullets = [];
var enemies = [];
var powerUps = [];
var gameStarted = false;
var gameOver = false;
var score = 0;
var level = 1;
var enemiesPerRow = 5;
var enemyRows = 3;
var enemySpawnDelay = 800;
var lastEnemySpawn = 0;
var powerUpChance = 0.2;
var highScore = storage.highScore || 0;
// UI Elements
var scoreTxt = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -scoreTxt.width - 20;
scoreTxt.y = 20;
var levelTxt = new Text2('LEVEL: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(1, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 20;
var instructionsTxt = new Text2('Open mouth to FIRE\nMake noise for SPECIAL ATTACK', {
size: 40,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0);
LK.gui.bottom.addChild(instructionsTxt);
instructionsTxt.y = -100;
var livesTxt = new Text2('LIVES: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesTxt);
livesTxt.x = 120; // Keep away from top-left corner (menu icon)
livesTxt.y = 20;
// Start the game
function startGame() {
if (!gameStarted) {
gameStarted = true;
// Initialize player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Reset game state
score = 0;
level = 1;
bullets = [];
enemies = [];
powerUps = [];
// Start background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Start spawning enemies
spawnEnemyWave();
}
}
// Spawn wave of enemies
function spawnEnemyWave() {
var startX = (2048 - enemiesPerRow * 150) / 2 + 75;
var startY = 200;
for (var row = 0; row < enemyRows; row++) {
for (var col = 0; col < enemiesPerRow; col++) {
var enemy = new Enemy();
enemy.x = startX + col * 150;
enemy.y = startY + row * 120;
enemy.health = Math.ceil(level / 3); // Increase health every 3 levels
enemy.speed = 1 + level * 0.5; // Increase speed with level
// Alternate movement direction by row
if (row % 2 === 1) {
enemy.moveDirection = -1;
}
game.addChild(enemy);
enemies.push(enemy);
}
}
}
// Spawn a power-up
function spawnPowerUp(x, y) {
if (Math.random() < powerUpChance) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
game.addChild(powerUp);
powerUps.push(powerUp);
}
}
// Update score display
function updateScoreDisplay() {
scoreTxt.setText("SCORE: " + score);
levelTxt.setText("LEVEL: " + level);
livesTxt.setText("LIVES: " + player.lives);
}
// Check for level completion
function checkLevelComplete() {
if (enemies.length === 0) {
level++;
enemiesPerRow = Math.min(enemiesPerRow + 1, 8);
enemyRows = Math.min(enemyRows + 1, 5);
powerUpChance = Math.min(powerUpChance + 0.05, 0.5);
// Clear all bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
// Spawn new enemy wave
spawnEnemyWave();
// Update level display
updateScoreDisplay();
}
}
// Check for game over conditions
function checkGameOver() {
// Check if player has no lives left
if (player.lives <= 0) {
endGame();
return;
}
// Check if any enemies have reached the bottom
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].y > 2732 - 150) {
endGame();
return;
}
}
}
// End game function
function endGame() {
gameOver = true;
gameStarted = false;
// Check for high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
}
// Show game over screen
LK.showGameOver();
// Stop music
LK.stopMusic();
}
// Main update function
game.update = function () {
// Start game if face is detected and game not started
if (facekit.mouthCenter && !gameStarted && !gameOver) {
startGame();
}
if (gameStarted && !gameOver) {
// Update player position based on face position
if (facekit.mouthCenter) {
var targetX = facekit.mouthCenter.x;
player.x += (targetX - player.x) * 0.2; // Smooth movement
// Fire weapon if mouth is open
if (facekit.mouthOpen) {
player.fire();
}
// Activate special weapon if making noise
if (facekit.volume > 0.3 && !player.specialWeapon) {
player.activateSpecialWeapon();
}
}
// Update player
player.update();
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Update bullet position
bullet.update();
// Remove bullets that go off screen
if (bullet.y < -100) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check for collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
var destroyed = enemy.hit(bullet.power);
if (destroyed) {
// Add score
score += 10 * level;
// Play explosion sound
LK.getSound('explosion').play();
// Flash effect for destroyed enemy
LK.effects.flashObject(enemy, 0xff0000, 200);
// Possibly spawn power-up
spawnPowerUp(enemy.x, enemy.y);
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
// Check for collision with player
if (enemies[i].intersects(player)) {
player.lives--;
// Flash screen red
LK.effects.flashScreen(0xff0000, 300);
// Remove enemy
enemies[i].destroy();
enemies.splice(i, 1);
i--;
// Check if game over
if (player.lives <= 0) {
checkGameOver();
} else {
updateScoreDisplay();
}
continue;
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
// Update power-up position
powerUp.update();
// Remove power-ups that go off screen
if (powerUp.y > 2732 + 100) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check for collision with player
if (powerUp.intersects(player)) {
// Apply power-up effect
player.activateSpecialWeapon();
// Play power-up sound
LK.getSound('powerup').play();
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Check if level is complete
checkLevelComplete();
// Check for game over conditions
checkGameOver();
// Update UI
updateScoreDisplay();
}
};
// Event handlers
game.down = function (x, y, obj) {
// Touch to start game
if (!gameStarted && !gameOver) {
startGame();
}
};
// Start with an instructional message
var startText = new Text2('Face the camera and\nopen your mouth to start!', {
size: 80,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 2732 / 2;
game.addChild(startText);
// Remove start text when game starts
var checkStarted = LK.setInterval(function () {
if (gameStarted) {
startText.destroy();
LK.clearInterval(checkStarted);
}
}, 100);