/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Player character controlled by face var FaceChar = Container.expand(function () { var self = Container.call(this); var _char = self.attachAsset('faceChar', { anchorX: 0.5, anchorY: 0.5 }); // For hit feedback self.flash = function () { tween(self, { alpha: 0.3 }, { duration: 80, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 120 }); } }); }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obs = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); // Speed is set on creation self.speed = 0; self.update = function () { self.y += self.speed; }; 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: 0x181c24 }); /**** * Game Code ****/ /* We use simple shapes for the character, obstacles, and points. */ // Game area: 2048x2732 // Center Y for spawn var GAME_W = 2048; var GAME_H = 2732; // Main character var faceChar = new FaceChar(); faceChar.x = GAME_W / 2; faceChar.y = GAME_H - 400; game.addChild(faceChar); // Arrays for obstacles and points var obstacles = []; var points = []; // Score display var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Best score display (optional, not persistent) var bestScore = 0; // Game state var isDead = false; var lastScore = 0; // Spawning timers var obstacleTimer = 0; var pointTimer = 0; // For face smoothing var lastFaceX = faceChar.x; var lastFaceY = faceChar.y; // Helper: clamp function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Main update loop game.update = function () { if (isDead) return; // --- Face tracking movement --- // Use mouthCenter if available, else fallback to noseTip var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : GAME_W / 2; var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : GAME_H - 400; // Clamp to game area, keep character fully visible var charR = faceChar.width / 2; fx = clamp(fx, charR, GAME_W - charR); fy = clamp(fy, charR + 120, GAME_H - charR - 40); // Smooth movement (lerp) lastFaceX += (fx - lastFaceX) * 0.35; lastFaceY += (fy - lastFaceY) * 0.35; faceChar.x = lastFaceX; faceChar.y = lastFaceY; // --- Spawning obstacles --- obstacleTimer--; if (obstacleTimer <= 0) { var obs = new Obstacle(); // Random X, avoid left 100px (menu) var minX = 120 + obs.width / 2; var maxX = GAME_W - obs.width / 2; obs.x = minX + Math.random() * (maxX - minX); obs.y = -obs.height / 2; // Speed increases with score obs.speed = 12 + LK.getScore() * 0.12; obstacles.push(obs); game.addChild(obs); // Next spawn: 36-60 ticks obstacleTimer = 36 + Math.floor(Math.random() * 24); } // --- Spawning points --- pointTimer--; if (pointTimer <= 0) { var pt = new PointItem(); var minX = 120 + pt.width / 2; var maxX = GAME_W - pt.width / 2; pt.x = minX + Math.random() * (maxX - minX); pt.y = -pt.height / 2; pt.speed = 10 + LK.getScore() * 0.10; points.push(pt); game.addChild(pt); // Next spawn: 60-120 ticks pointTimer = 60 + Math.floor(Math.random() * 60); } // --- Update obstacles --- for (var i = obstacles.length - 1; i >= 0; i--) { var o = obstacles[i]; o.update(); // Remove if off screen if (o.y - o.height / 2 > GAME_H + 40) { o.destroy(); obstacles.splice(i, 1); continue; } // Collision with player if (o.intersects(faceChar)) { // Game over isDead = true; faceChar.flash(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } // --- Update points --- for (var j = points.length - 1; j >= 0; j--) { var p = points[j]; p.update(); // Remove if off screen if (p.y - p.height / 2 > GAME_H + 40) { p.destroy(); points.splice(j, 1); continue; } // Collect if (p.intersects(faceChar)) { LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); // Feedback tween(p, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 180, onFinish: function onFinish() { p.destroy(); } }); points.splice(j, 1); continue; } } }; // Reset state on new game game.on('reset', function () { // Remove all obstacles and points for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy(); for (var j = 0; j < points.length; j++) points[j].destroy(); obstacles = []; points = []; isDead = false; LK.setScore(0); scoreTxt.setText('0'); // Reset faceChar position faceChar.x = GAME_W / 2; faceChar.y = GAME_H - 400; lastFaceX = faceChar.x; lastFaceY = faceChar.y; obstacleTimer = 30; pointTimer = 60; }); // Also reset on game over (for safety) game.on('gameover', function () { isDead = true; }); // Touch fallback: allow dragging character if facekit not available var dragNode = null; function handleMove(x, y, obj) { if (dragNode) { // Clamp to game area var charR = faceChar.width / 2; var nx = clamp(x, charR, GAME_W - charR); var ny = clamp(y, charR + 120, GAME_H - charR - 40); faceChar.x = nx; faceChar.y = ny; lastFaceX = nx; lastFaceY = ny; } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if facekit not available if (!facekit.mouthCenter || !facekit.mouthCenter.x) { dragNode = faceChar; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,251 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var facekit = LK.import("@upit/facekit.v1");
+
+/****
+* Classes
+****/
+// Player character controlled by face
+var FaceChar = Container.expand(function () {
+ var self = Container.call(this);
+ var _char = self.attachAsset('faceChar', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // For hit feedback
+ self.flash = function () {
+ tween(self, {
+ alpha: 0.3
+ }, {
+ duration: 80,
+ onFinish: function onFinish() {
+ tween(self, {
+ alpha: 1
+ }, {
+ duration: 120
+ });
+ }
+ });
+ };
+ return self;
+});
+// Obstacle class
+var Obstacle = Container.expand(function () {
+ var self = Container.call(this);
+ var obs = self.attachAsset('obstacle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Speed is set on creation
+ self.speed = 0;
+ self.update = function () {
+ self.y += self.speed;
+ };
+ 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
-});
\ No newline at end of file
+ backgroundColor: 0x181c24
+});
+
+/****
+* Game Code
+****/
+/*
+We use simple shapes for the character, obstacles, and points.
+*/
+// Game area: 2048x2732
+// Center Y for spawn
+var GAME_W = 2048;
+var GAME_H = 2732;
+// Main character
+var faceChar = new FaceChar();
+faceChar.x = GAME_W / 2;
+faceChar.y = GAME_H - 400;
+game.addChild(faceChar);
+// Arrays for obstacles and points
+var obstacles = [];
+var points = [];
+// Score display
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: "#fff"
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Best score display (optional, not persistent)
+var bestScore = 0;
+// Game state
+var isDead = false;
+var lastScore = 0;
+// Spawning timers
+var obstacleTimer = 0;
+var pointTimer = 0;
+// For face smoothing
+var lastFaceX = faceChar.x;
+var lastFaceY = faceChar.y;
+// Helper: clamp
+function clamp(val, min, max) {
+ return Math.max(min, Math.min(max, val));
+}
+// Main update loop
+game.update = function () {
+ if (isDead) return;
+ // --- Face tracking movement ---
+ // Use mouthCenter if available, else fallback to noseTip
+ var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : GAME_W / 2;
+ var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : GAME_H - 400;
+ // Clamp to game area, keep character fully visible
+ var charR = faceChar.width / 2;
+ fx = clamp(fx, charR, GAME_W - charR);
+ fy = clamp(fy, charR + 120, GAME_H - charR - 40);
+ // Smooth movement (lerp)
+ lastFaceX += (fx - lastFaceX) * 0.35;
+ lastFaceY += (fy - lastFaceY) * 0.35;
+ faceChar.x = lastFaceX;
+ faceChar.y = lastFaceY;
+ // --- Spawning obstacles ---
+ obstacleTimer--;
+ if (obstacleTimer <= 0) {
+ var obs = new Obstacle();
+ // Random X, avoid left 100px (menu)
+ var minX = 120 + obs.width / 2;
+ var maxX = GAME_W - obs.width / 2;
+ obs.x = minX + Math.random() * (maxX - minX);
+ obs.y = -obs.height / 2;
+ // Speed increases with score
+ obs.speed = 12 + LK.getScore() * 0.12;
+ obstacles.push(obs);
+ game.addChild(obs);
+ // Next spawn: 36-60 ticks
+ obstacleTimer = 36 + Math.floor(Math.random() * 24);
+ }
+ // --- Spawning points ---
+ pointTimer--;
+ if (pointTimer <= 0) {
+ var pt = new PointItem();
+ var minX = 120 + pt.width / 2;
+ var maxX = GAME_W - pt.width / 2;
+ pt.x = minX + Math.random() * (maxX - minX);
+ pt.y = -pt.height / 2;
+ pt.speed = 10 + LK.getScore() * 0.10;
+ points.push(pt);
+ game.addChild(pt);
+ // Next spawn: 60-120 ticks
+ pointTimer = 60 + Math.floor(Math.random() * 60);
+ }
+ // --- Update obstacles ---
+ for (var i = obstacles.length - 1; i >= 0; i--) {
+ var o = obstacles[i];
+ o.update();
+ // Remove if off screen
+ if (o.y - o.height / 2 > GAME_H + 40) {
+ o.destroy();
+ obstacles.splice(i, 1);
+ continue;
+ }
+ // Collision with player
+ if (o.intersects(faceChar)) {
+ // Game over
+ isDead = true;
+ faceChar.flash();
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ }
+ // --- Update points ---
+ for (var j = points.length - 1; j >= 0; j--) {
+ var p = points[j];
+ p.update();
+ // Remove if off screen
+ if (p.y - p.height / 2 > GAME_H + 40) {
+ p.destroy();
+ points.splice(j, 1);
+ continue;
+ }
+ // Collect
+ if (p.intersects(faceChar)) {
+ LK.setScore(LK.getScore() + 1);
+ scoreTxt.setText(LK.getScore());
+ // Feedback
+ tween(p, {
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0
+ }, {
+ duration: 180,
+ onFinish: function onFinish() {
+ p.destroy();
+ }
+ });
+ points.splice(j, 1);
+ continue;
+ }
+ }
+};
+// Reset state on new game
+game.on('reset', function () {
+ // Remove all obstacles and points
+ for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
+ for (var j = 0; j < points.length; j++) points[j].destroy();
+ obstacles = [];
+ points = [];
+ isDead = false;
+ LK.setScore(0);
+ scoreTxt.setText('0');
+ // Reset faceChar position
+ faceChar.x = GAME_W / 2;
+ faceChar.y = GAME_H - 400;
+ lastFaceX = faceChar.x;
+ lastFaceY = faceChar.y;
+ obstacleTimer = 30;
+ pointTimer = 60;
+});
+// Also reset on game over (for safety)
+game.on('gameover', function () {
+ isDead = true;
+});
+// Touch fallback: allow dragging character if facekit not available
+var dragNode = null;
+function handleMove(x, y, obj) {
+ if (dragNode) {
+ // Clamp to game area
+ var charR = faceChar.width / 2;
+ var nx = clamp(x, charR, GAME_W - charR);
+ var ny = clamp(y, charR + 120, GAME_H - charR - 40);
+ faceChar.x = nx;
+ faceChar.y = ny;
+ lastFaceX = nx;
+ lastFaceY = ny;
+ }
+}
+game.move = handleMove;
+game.down = function (x, y, obj) {
+ // Only allow drag if facekit not available
+ if (!facekit.mouthCenter || !facekit.mouthCenter.x) {
+ dragNode = faceChar;
+ handleMove(x, y, obj);
+ }
+};
+game.up = function (x, y, obj) {
+ dragNode = null;
+};
\ No newline at end of file