/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highscore: 0, level: 1 }); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var Monster = Container.expand(function () { var self = Container.call(this); // Create monster visuals var monsterGraphics = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5 }); // Monster properties self.speed = 2 + Math.random() * 3; self.targetX = 0; self.targetY = 0; self.isEaten = false; self.directionChangeTimer = 0; self.directionChangeFrequency = 30; // frames self.value = 10; // score value // Set random color tint for variety var colors = [0xffc0cb, 0xffb6c1, 0xffd700, 0xadd8e6, 0x98fb98]; monsterGraphics.tint = colors[Math.floor(Math.random() * colors.length)]; self.update = function () { if (self.isEaten) { return; } self.directionChangeTimer++; // Update targets periodically for more natural movement if (self.directionChangeTimer >= self.directionChangeFrequency) { self.directionChangeTimer = 0; // When mouth is closed, monsters flee from player if (!facekit.mouthOpen) { // Run away from player var playerPos = { x: facekit.mouthCenter.x, y: facekit.mouthCenter.y }; var angle = Math.atan2(self.y - playerPos.y, self.x - playerPos.x); self.targetX = self.x + Math.cos(angle) * 300; self.targetY = self.y + Math.sin(angle) * 300; // Keep within bounds if (self.targetX < 100) { self.targetX = 100; } if (self.targetX > 2048 - 100) { self.targetX = 2048 - 100; } if (self.targetY < 100) { self.targetY = 100; } if (self.targetY > 2732 - 100) { self.targetY = 2732 - 100; } } else { // Random movement when mouth is open self.targetX = 100 + Math.random() * (2048 - 200); self.targetY = 100 + Math.random() * (2732 - 200); } } // Move toward target position var dx = self.targetX - self.x; var dy = self.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.eat = function () { if (self.isEaten) { return; } self.isEaten = true; // Tween to player's mouth with cute animation tween(self, { x: facekit.mouthCenter.x, y: facekit.mouthCenter.y, scaleX: 0.1, scaleY: 0.1, alpha: 0, rotation: Math.PI * 2 // Add a spin for cuteness }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); return self.value; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Game variables var monsters = []; var score = 0; var highscore = storage.highscore || 0; var level = storage.level || 1; var monstersToSpawn = 5; var monstersPerLevel = 5; var monsterSpawnTimer = 0; var monsterSpawnDelay = 60; // frames var mouthPosition = { x: 0, y: 0 }; var isEatingMode = false; var lastMouthState = false; var gameActive = true; // Play cute background music LK.playMusic('cuteGameMusic', { fade: { start: 0, end: 0.5, duration: 1000 } }); // Create player visualization (follows mouth) var player = game.addChild(LK.getAsset('player', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 })); // UI elements var scoreText = new Text2('Score: 0', { size: 50, fill: 0xFFFFFF }); var scoreBackground = LK.getAsset('scoreBackground', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); scoreText.anchor.set(0.5, 0.5); LK.gui.topRight.addChild(scoreBackground); LK.gui.topRight.addChild(scoreText); var levelText = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF }); var levelBackground = LK.getAsset('levelBackground', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); levelText.anchor.set(0.5, 0.5); LK.gui.topLeft.addChild(levelBackground); LK.gui.topLeft.addChild(levelText); // Position UI elements scoreBackground.x = -250; scoreBackground.y = 50; scoreText.x = -250; scoreText.y = 50; levelBackground.x = 250; levelBackground.y = 50; levelText.x = 250; levelText.y = 50; // Disclaimer text var disclaimerText = new Text2("Make sure you are in an open and well-lighted environment", { size: 60, fill: 0xFF0000 }); disclaimerText.anchor.set(0.5, 0.5); disclaimerText.y = 150; // Lower the disclaimer text position further LK.gui.top.addChild(disclaimerText); // Instructions text var instructionsText = new Text2("Open your mouth to eat monsters!\nClose it to make them run away!", { size: 60, fill: 0xFFFFFF }); instructionsText.anchor.set(0.5, 0.5); LK.gui.center.addChild(instructionsText); // Hide instructions after 5 seconds LK.setTimeout(function () { tween(instructionsText, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { instructionsText.destroy(); } }); }, 5000); // Helper function to spawn a monster function spawnMonster() { var monster = new Monster(); // Random position along the edge of the screen var side = Math.floor(Math.random() * 4); switch (side) { case 0: // top monster.x = Math.random() * 2048; monster.y = 0; break; case 1: // right monster.x = 2048; monster.y = Math.random() * 2732; break; case 2: // bottom monster.x = Math.random() * 2048; monster.y = 2732; break; case 3: // left monster.x = 0; monster.y = Math.random() * 2732; break; } // Speed up monsters based on level monster.speed += (level - 1) * 0.5; // Increase score value based on level monster.value = 10 * level; monsters.push(monster); game.addChild(monster); return monster; } // Helper function to start the next level function startNextLevel() { level++; levelText.setText("Level: " + level); monstersToSpawn = level * monstersPerLevel; // Store level progress storage.level = level; // Play level up sound LK.getSound('levelUp').play(); // Show level up message var levelUpText = new Text2("Level " + level + "!", { size: 120, fill: 0xFFFF00 }); levelUpText.anchor.set(0.5, 0.5); LK.gui.center.addChild(levelUpText); // Animate level up text tween(levelUpText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(levelUpText, { scaleX: 1, scaleY: 1, alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { levelUpText.destroy(); } }); } }); } // Game update function game.update = function () { // Update mouth position from facekit mouthPosition.x = facekit.mouthCenter.x; mouthPosition.y = facekit.mouthCenter.y; isEatingMode = facekit.mouthOpen; // Update player position to follow mouth player.x = mouthPosition.x; player.y = mouthPosition.y; // Visual feedback for mouth state if (isEatingMode) { // Mouth open - eating mode tween.stop(player, { scaleX: true, scaleY: true }); player.scaleX = 1.5; player.scaleY = 1.5; player.tint = 0x00ff00; } else { // Mouth closed - neutral mode tween.stop(player, { scaleX: true, scaleY: true }); player.scaleX = 1; player.scaleY = 1; player.tint = 0x4287f5; } // Track mouth state changes if (isEatingMode !== lastMouthState) { lastMouthState = isEatingMode; } // Spawn monsters if (monstersToSpawn > 0 && monsters.length < 10) { monsterSpawnTimer++; if (monsterSpawnTimer >= monsterSpawnDelay) { monsterSpawnTimer = 0; spawnMonster(); monstersToSpawn--; } } // Check if level is complete if (monstersToSpawn === 0 && monsters.length === 0) { startNextLevel(); } // Update all monsters for (var i = monsters.length - 1; i >= 0; i--) { var monster = monsters[i]; // Detect if monster is eaten if (isEatingMode && !monster.isEaten) { var dx = monster.x - mouthPosition.x; var dy = monster.y - mouthPosition.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < player.width / 2) { // Monster is eaten score += monster.eat(); scoreText.setText("Score: " + score); // Update highscore if needed if (score > highscore) { highscore = score; storage.highscore = highscore; } // Play cute munch sound LK.getSound('cuteMunch').play(); // Remove from array monsters.splice(i, 1); } } } }; // Game click/touch handlers (for testing on desktop) game.down = function (x, y, obj) { // Not needed for face tracking game, but could be used for additional controls }; game.up = function (x, y, obj) { // Not needed for face tracking game }; game.move = function (x, y, obj) { // Not needed for face tracking game };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highscore: 0,
level: 1
});
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
var Monster = Container.expand(function () {
var self = Container.call(this);
// Create monster visuals
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
// Monster properties
self.speed = 2 + Math.random() * 3;
self.targetX = 0;
self.targetY = 0;
self.isEaten = false;
self.directionChangeTimer = 0;
self.directionChangeFrequency = 30; // frames
self.value = 10; // score value
// Set random color tint for variety
var colors = [0xffc0cb, 0xffb6c1, 0xffd700, 0xadd8e6, 0x98fb98];
monsterGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
self.update = function () {
if (self.isEaten) {
return;
}
self.directionChangeTimer++;
// Update targets periodically for more natural movement
if (self.directionChangeTimer >= self.directionChangeFrequency) {
self.directionChangeTimer = 0;
// When mouth is closed, monsters flee from player
if (!facekit.mouthOpen) {
// Run away from player
var playerPos = {
x: facekit.mouthCenter.x,
y: facekit.mouthCenter.y
};
var angle = Math.atan2(self.y - playerPos.y, self.x - playerPos.x);
self.targetX = self.x + Math.cos(angle) * 300;
self.targetY = self.y + Math.sin(angle) * 300;
// Keep within bounds
if (self.targetX < 100) {
self.targetX = 100;
}
if (self.targetX > 2048 - 100) {
self.targetX = 2048 - 100;
}
if (self.targetY < 100) {
self.targetY = 100;
}
if (self.targetY > 2732 - 100) {
self.targetY = 2732 - 100;
}
} else {
// Random movement when mouth is open
self.targetX = 100 + Math.random() * (2048 - 200);
self.targetY = 100 + Math.random() * (2732 - 200);
}
}
// Move toward target position
var dx = self.targetX - self.x;
var dy = self.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.eat = function () {
if (self.isEaten) {
return;
}
self.isEaten = true;
// Tween to player's mouth with cute animation
tween(self, {
x: facekit.mouthCenter.x,
y: facekit.mouthCenter.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0,
rotation: Math.PI * 2 // Add a spin for cuteness
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
}
});
return self.value;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game variables
var monsters = [];
var score = 0;
var highscore = storage.highscore || 0;
var level = storage.level || 1;
var monstersToSpawn = 5;
var monstersPerLevel = 5;
var monsterSpawnTimer = 0;
var monsterSpawnDelay = 60; // frames
var mouthPosition = {
x: 0,
y: 0
};
var isEatingMode = false;
var lastMouthState = false;
var gameActive = true;
// Play cute background music
LK.playMusic('cuteGameMusic', {
fade: {
start: 0,
end: 0.5,
duration: 1000
}
});
// Create player visualization (follows mouth)
var player = game.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
}));
// UI elements
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
var scoreBackground = LK.getAsset('scoreBackground', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
scoreText.anchor.set(0.5, 0.5);
LK.gui.topRight.addChild(scoreBackground);
LK.gui.topRight.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
var levelBackground = LK.getAsset('levelBackground', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
levelText.anchor.set(0.5, 0.5);
LK.gui.topLeft.addChild(levelBackground);
LK.gui.topLeft.addChild(levelText);
// Position UI elements
scoreBackground.x = -250;
scoreBackground.y = 50;
scoreText.x = -250;
scoreText.y = 50;
levelBackground.x = 250;
levelBackground.y = 50;
levelText.x = 250;
levelText.y = 50;
// Disclaimer text
var disclaimerText = new Text2("Make sure you are in an open and well-lighted environment", {
size: 60,
fill: 0xFF0000
});
disclaimerText.anchor.set(0.5, 0.5);
disclaimerText.y = 150; // Lower the disclaimer text position further
LK.gui.top.addChild(disclaimerText);
// Instructions text
var instructionsText = new Text2("Open your mouth to eat monsters!\nClose it to make them run away!", {
size: 60,
fill: 0xFFFFFF
});
instructionsText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsText);
// Hide instructions after 5 seconds
LK.setTimeout(function () {
tween(instructionsText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
instructionsText.destroy();
}
});
}, 5000);
// Helper function to spawn a monster
function spawnMonster() {
var monster = new Monster();
// Random position along the edge of the screen
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// top
monster.x = Math.random() * 2048;
monster.y = 0;
break;
case 1:
// right
monster.x = 2048;
monster.y = Math.random() * 2732;
break;
case 2:
// bottom
monster.x = Math.random() * 2048;
monster.y = 2732;
break;
case 3:
// left
monster.x = 0;
monster.y = Math.random() * 2732;
break;
}
// Speed up monsters based on level
monster.speed += (level - 1) * 0.5;
// Increase score value based on level
monster.value = 10 * level;
monsters.push(monster);
game.addChild(monster);
return monster;
}
// Helper function to start the next level
function startNextLevel() {
level++;
levelText.setText("Level: " + level);
monstersToSpawn = level * monstersPerLevel;
// Store level progress
storage.level = level;
// Play level up sound
LK.getSound('levelUp').play();
// Show level up message
var levelUpText = new Text2("Level " + level + "!", {
size: 120,
fill: 0xFFFF00
});
levelUpText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelUpText);
// Animate level up text
tween(levelUpText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelUpText, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
levelUpText.destroy();
}
});
}
});
}
// Game update function
game.update = function () {
// Update mouth position from facekit
mouthPosition.x = facekit.mouthCenter.x;
mouthPosition.y = facekit.mouthCenter.y;
isEatingMode = facekit.mouthOpen;
// Update player position to follow mouth
player.x = mouthPosition.x;
player.y = mouthPosition.y;
// Visual feedback for mouth state
if (isEatingMode) {
// Mouth open - eating mode
tween.stop(player, {
scaleX: true,
scaleY: true
});
player.scaleX = 1.5;
player.scaleY = 1.5;
player.tint = 0x00ff00;
} else {
// Mouth closed - neutral mode
tween.stop(player, {
scaleX: true,
scaleY: true
});
player.scaleX = 1;
player.scaleY = 1;
player.tint = 0x4287f5;
}
// Track mouth state changes
if (isEatingMode !== lastMouthState) {
lastMouthState = isEatingMode;
}
// Spawn monsters
if (monstersToSpawn > 0 && monsters.length < 10) {
monsterSpawnTimer++;
if (monsterSpawnTimer >= monsterSpawnDelay) {
monsterSpawnTimer = 0;
spawnMonster();
monstersToSpawn--;
}
}
// Check if level is complete
if (monstersToSpawn === 0 && monsters.length === 0) {
startNextLevel();
}
// Update all monsters
for (var i = monsters.length - 1; i >= 0; i--) {
var monster = monsters[i];
// Detect if monster is eaten
if (isEatingMode && !monster.isEaten) {
var dx = monster.x - mouthPosition.x;
var dy = monster.y - mouthPosition.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < player.width / 2) {
// Monster is eaten
score += monster.eat();
scoreText.setText("Score: " + score);
// Update highscore if needed
if (score > highscore) {
highscore = score;
storage.highscore = highscore;
}
// Play cute munch sound
LK.getSound('cuteMunch').play();
// Remove from array
monsters.splice(i, 1);
}
}
}
};
// Game click/touch handlers (for testing on desktop)
game.down = function (x, y, obj) {
// Not needed for face tracking game, but could be used for additional controls
};
game.up = function (x, y, obj) {
// Not needed for face tracking game
};
game.move = function (x, y, obj) {
// Not needed for face tracking game
};