/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obs = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); // Speed will be set on creation self.speed = 0; self.update = function () { self.y += self.speed; }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // For possible future effects self.flash = function () { LK.effects.flashObject(self, 0xffff00, 300); }; return self; }); // Point (collectible) class var PointItem = Container.expand(function () { var self = Container.call(this); var pt = self.attachAsset('point', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Camera background asset (used by facekit plugin) // Point: Green circle // Obstacle: Red rectangles // Character: A bright ellipse for the player // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PLAYER_Y = GAME_HEIGHT - 400; // Player stays near bottom var OBSTACLE_MIN_SPEED = 10; var OBSTACLE_MAX_SPEED = 28; var OBSTACLE_SPAWN_INTERVAL = 60; // in ticks (~1s) var POINT_SPAWN_INTERVAL = 90; // in ticks (~1.5s) var DIFFICULTY_INCREASE_INTERVAL = 600; // every 10s var OBSTACLE_WIDTH = 180; var OBSTACLE_HEIGHT = 80; var POINT_SIZE = 80; // Game state var player; var obstacles = []; var points = []; var score = 0; var scoreTxt; var ticksSinceLastObstacle = 0; var ticksSinceLastPoint = 0; var gameSpeed = 1; var lastMouthX = GAME_WIDTH / 2; var lastMouthY = PLAYER_Y; var lastIntersectingObstacle = false; var lastIntersectingPoint = false; // Set up background to be camera feed game.setBackgroundColor(0x000000); // Black, but facekit will show camera // Score display scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create player player = new Player(); player.x = GAME_WIDTH / 2; player.y = PLAYER_Y; game.addChild(player); // Helper: Clamp value function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // Helper: Random X for obstacles/points function randomX(margin) { return margin + Math.random() * (GAME_WIDTH - 2 * margin); } // Main update loop game.update = function () { // --- Face tracking: Move player --- // Use mouth center if available, else nose tip var faceX = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : lastMouthX; var faceY = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : lastMouthY; // Clamp to game area, keep player near bottom var targetX = clamp(faceX, 60, GAME_WIDTH - 60); var targetY = PLAYER_Y; // Smooth movement (optional, can be direct for more responsive) player.x += (targetX - player.x) * 0.35; player.y = targetY; lastMouthX = faceX; lastMouthY = faceY; // --- Spawn obstacles --- ticksSinceLastObstacle++; if (ticksSinceLastObstacle >= Math.max(OBSTACLE_SPAWN_INTERVAL - Math.floor(gameSpeed * 5), 30)) { var obs = new Obstacle(); obs.x = randomX(OBSTACLE_WIDTH / 2 + 40); obs.y = -OBSTACLE_HEIGHT / 2; obs.speed = OBSTACLE_MIN_SPEED + Math.random() * (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * (0.7 + 0.3 * gameSpeed); obstacles.push(obs); game.addChild(obs); ticksSinceLastObstacle = 0; } // --- Spawn points --- ticksSinceLastPoint++; if (ticksSinceLastPoint >= Math.max(POINT_SPAWN_INTERVAL - Math.floor(gameSpeed * 5), 40)) { var pt = new PointItem(); pt.x = randomX(POINT_SIZE / 2 + 40); pt.y = -POINT_SIZE / 2; pt.speed = OBSTACLE_MIN_SPEED + Math.random() * 8 * (0.7 + 0.3 * gameSpeed); points.push(pt); game.addChild(pt); ticksSinceLastPoint = 0; } // --- Move obstacles, check collision --- for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if off screen if (obs.y - OBSTACLE_HEIGHT / 2 > GAME_HEIGHT + 100) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with player var intersecting = player.intersects(obs); if (intersecting) { // Flash screen, show game over LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } // --- Move points, check collection --- for (var j = points.length - 1; j >= 0; j--) { var pt = points[j]; pt.update(); // Remove if off screen if (pt.y - POINT_SIZE / 2 > GAME_HEIGHT + 100) { pt.destroy(); points.splice(j, 1); continue; } // Collection var intersecting = player.intersects(pt); if (intersecting) { // Flash player player.flash(); score += 1; scoreTxt.setText(score); pt.destroy(); points.splice(j, 1); continue; } } // --- Increase difficulty over time --- if (LK.ticks % DIFFICULTY_INCREASE_INTERVAL === 0) { gameSpeed += 0.15; } }; // No touch/drag controls needed; all movement is via facekit // Reset state on game over (handled by LK automatically) LK.setScore(0); // For leaderboard integration // End of file
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Obstacle class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
// Speed will be set on creation
self.speed = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// For possible future effects
self.flash = function () {
LK.effects.flashObject(self, 0xffff00, 300);
};
return self;
});
// Point (collectible) class
var PointItem = Container.expand(function () {
var self = Container.call(this);
var pt = self.attachAsset('point', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Camera background asset (used by facekit plugin)
// Point: Green circle
// Obstacle: Red rectangles
// Character: A bright ellipse for the player
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAYER_Y = GAME_HEIGHT - 400; // Player stays near bottom
var OBSTACLE_MIN_SPEED = 10;
var OBSTACLE_MAX_SPEED = 28;
var OBSTACLE_SPAWN_INTERVAL = 60; // in ticks (~1s)
var POINT_SPAWN_INTERVAL = 90; // in ticks (~1.5s)
var DIFFICULTY_INCREASE_INTERVAL = 600; // every 10s
var OBSTACLE_WIDTH = 180;
var OBSTACLE_HEIGHT = 80;
var POINT_SIZE = 80;
// Game state
var player;
var obstacles = [];
var points = [];
var score = 0;
var scoreTxt;
var ticksSinceLastObstacle = 0;
var ticksSinceLastPoint = 0;
var gameSpeed = 1;
var lastMouthX = GAME_WIDTH / 2;
var lastMouthY = PLAYER_Y;
var lastIntersectingObstacle = false;
var lastIntersectingPoint = false;
// Set up background to be camera feed
game.setBackgroundColor(0x000000); // Black, but facekit will show camera
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create player
player = new Player();
player.x = GAME_WIDTH / 2;
player.y = PLAYER_Y;
game.addChild(player);
// Helper: Clamp value
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// Helper: Random X for obstacles/points
function randomX(margin) {
return margin + Math.random() * (GAME_WIDTH - 2 * margin);
}
// Main update loop
game.update = function () {
// --- Face tracking: Move player ---
// Use mouth center if available, else nose tip
var faceX = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : lastMouthX;
var faceY = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : lastMouthY;
// Clamp to game area, keep player near bottom
var targetX = clamp(faceX, 60, GAME_WIDTH - 60);
var targetY = PLAYER_Y;
// Smooth movement (optional, can be direct for more responsive)
player.x += (targetX - player.x) * 0.35;
player.y = targetY;
lastMouthX = faceX;
lastMouthY = faceY;
// --- Spawn obstacles ---
ticksSinceLastObstacle++;
if (ticksSinceLastObstacle >= Math.max(OBSTACLE_SPAWN_INTERVAL - Math.floor(gameSpeed * 5), 30)) {
var obs = new Obstacle();
obs.x = randomX(OBSTACLE_WIDTH / 2 + 40);
obs.y = -OBSTACLE_HEIGHT / 2;
obs.speed = OBSTACLE_MIN_SPEED + Math.random() * (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * (0.7 + 0.3 * gameSpeed);
obstacles.push(obs);
game.addChild(obs);
ticksSinceLastObstacle = 0;
}
// --- Spawn points ---
ticksSinceLastPoint++;
if (ticksSinceLastPoint >= Math.max(POINT_SPAWN_INTERVAL - Math.floor(gameSpeed * 5), 40)) {
var pt = new PointItem();
pt.x = randomX(POINT_SIZE / 2 + 40);
pt.y = -POINT_SIZE / 2;
pt.speed = OBSTACLE_MIN_SPEED + Math.random() * 8 * (0.7 + 0.3 * gameSpeed);
points.push(pt);
game.addChild(pt);
ticksSinceLastPoint = 0;
}
// --- Move obstacles, check collision ---
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y - OBSTACLE_HEIGHT / 2 > GAME_HEIGHT + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with player
var intersecting = player.intersects(obs);
if (intersecting) {
// Flash screen, show game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// --- Move points, check collection ---
for (var j = points.length - 1; j >= 0; j--) {
var pt = points[j];
pt.update();
// Remove if off screen
if (pt.y - POINT_SIZE / 2 > GAME_HEIGHT + 100) {
pt.destroy();
points.splice(j, 1);
continue;
}
// Collection
var intersecting = player.intersects(pt);
if (intersecting) {
// Flash player
player.flash();
score += 1;
scoreTxt.setText(score);
pt.destroy();
points.splice(j, 1);
continue;
}
}
// --- Increase difficulty over time ---
if (LK.ticks % DIFFICULTY_INCREASE_INTERVAL === 0) {
gameSpeed += 0.15;
}
};
// No touch/drag controls needed; all movement is via facekit
// Reset state on game over (handled by LK automatically)
LK.setScore(0); // For leaderboard integration
// End of file