/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Obstacle class: moves downward, destroys itself off-screen var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleSprite = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); // Speed (randomized) self.speed = 10 + Math.random() * 8; // For collision detection self.obstacleSprite = obstacleSprite; self.update = function () { self.y += self.speed; }; return self; }); // Player class: follows mouth position, shows shield if mouth open var Player = Container.expand(function () { var self = Container.call(this); // Player body var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Shield (hidden by default) var shieldSprite = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.0 }); // Show/hide shield self.setShield = function (active) { if (active) { shieldSprite.alpha = 0.5; } else { shieldSprite.alpha = 0.0; } }; // For collision detection, expose playerSprite and shieldSprite self.playerSprite = playerSprite; self.shieldSprite = shieldSprite; return self; }); // Point class: moves downward, destroys itself off-screen var Point = Container.expand(function () { var self = Container.call(this); var pointSprite = self.attachAsset('point', { anchorX: 0.5, anchorY: 0.5 }); // Speed (slower than obstacles) self.speed = 7 + Math.random() * 4; // For collision detection self.pointSprite = pointSprite; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c2c }); /**** * Game Code ****/ // Point: yellow ellipse // Obstacle: red box // Shield: semi-transparent cyan ellipse, slightly larger // Player character: blue ellipse // Game area: 2048x2732 // Player starts at center var player = new Player(); player.x = 2048 / 2; player.y = 2732 * 0.7; game.addChild(player); // Score display var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: 0xFFF700 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives display var lives = 3; var livesTxt = new Text2('❤❤❤', { size: 90, fill: 0xFF3333 }); livesTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(livesTxt); // Arrays for obstacles and points var obstacles = []; var points = []; // Timers for spawning var obstacleTimer = 0; var pointTimer = 0; // Invulnerability after hit var invulnTicks = 0; var INVULN_DURATION = 60; // 1 second at 60fps // Helper: update lives text function updateLivesText() { var s = ''; for (var i = 0; i < lives; i++) s += '❤'; livesTxt.setText(s); } // Helper: clamp player position inside game area function clampPlayerPosition() { var r = 100; if (player.x < r) player.x = r; if (player.x > 2048 - r) player.x = 2048 - r; if (player.y < r + 100) player.y = r + 100; // avoid top menu if (player.y > 2732 - r) player.y = 2732 - r; } // Main update loop game.update = function () { // 1. Update player position from facekit var mouth = facekit.mouthCenter; if (mouth && typeof mouth.x === 'number' && typeof mouth.y === 'number') { // Smooth follow player.x += (mouth.x - player.x) * 0.35; player.y += (mouth.y - player.y) * 0.35; clampPlayerPosition(); } // 2. Shield: mouth open var shieldActive = !!facekit.mouthOpen; player.setShield(shieldActive); // 3. Spawn obstacles obstacleTimer--; if (obstacleTimer <= 0) { var obs = new Obstacle(); obs.x = 180 + Math.random() * (2048 - 360); obs.y = -80; obstacles.push(obs); game.addChild(obs); // Next spawn: 30-60 ticks obstacleTimer = 30 + Math.floor(Math.random() * 30); } // 4. Spawn points pointTimer--; if (pointTimer <= 0) { var pt = new Point(); pt.x = 180 + Math.random() * (2048 - 360); pt.y = -60; points.push(pt); game.addChild(pt); // Next spawn: 80-160 ticks pointTimer = 80 + Math.floor(Math.random() * 80); } // 5. Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if off-screen if (obs.y > 2732 + 100) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with player var collides = obs.obstacleSprite.intersects(player.playerSprite); if (collides) { if (shieldActive || invulnTicks > 0) { // Blocked: flash obstacle, destroy tween(obs.obstacleSprite, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { obs.destroy(); } }); obstacles.splice(i, 1); continue; } else { // Hit: lose life, invuln, flash player lives--; updateLivesText(); invulnTicks = INVULN_DURATION; LK.effects.flashObject(player, 0xff0000, 600); if (lives <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } // Remove obstacle obs.destroy(); obstacles.splice(i, 1); continue; } } } // 6. Update points for (var j = points.length - 1; j >= 0; j--) { var pt = points[j]; pt.update(); // Remove if off-screen if (pt.y > 2732 + 80) { pt.destroy(); points.splice(j, 1); continue; } // Collision with player var collides = pt.pointSprite.intersects(player.playerSprite); if (collides) { // Collect point score += 1; LK.setScore(score); scoreTxt.setText(score); // Flash point tween(pt.pointSprite, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { pt.destroy(); } }); points.splice(j, 1); continue; } } // 7. Invulnerability timer if (invulnTicks > 0) { invulnTicks--; // Flicker player player.playerSprite.alpha = invulnTicks % 8 < 4 ? 0.4 : 1.0; } else { player.playerSprite.alpha = 1.0; } }; // On game start, reset everything function resetGame() { score = 0; LK.setScore(0); scoreTxt.setText('0'); lives = 3; updateLivesText(); invulnTicks = 0; // 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 = []; // Reset player position player.x = 2048 / 2; player.y = 2732 * 0.7; player.setShield(false); } resetGame(); // No touch/mouse controls needed; all via facekit // End of MVP
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,266 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var facekit = LK.import("@upit/facekit.v1");
+
+/****
+* Classes
+****/
+// Obstacle class: moves downward, destroys itself off-screen
+var Obstacle = Container.expand(function () {
+ var self = Container.call(this);
+ var obstacleSprite = self.attachAsset('obstacle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Speed (randomized)
+ self.speed = 10 + Math.random() * 8;
+ // For collision detection
+ self.obstacleSprite = obstacleSprite;
+ self.update = function () {
+ self.y += self.speed;
+ };
+ return self;
+});
+// Player class: follows mouth position, shows shield if mouth open
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ // Player body
+ var playerSprite = self.attachAsset('player', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Shield (hidden by default)
+ var shieldSprite = self.attachAsset('shield', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.0
+ });
+ // Show/hide shield
+ self.setShield = function (active) {
+ if (active) {
+ shieldSprite.alpha = 0.5;
+ } else {
+ shieldSprite.alpha = 0.0;
+ }
+ };
+ // For collision detection, expose playerSprite and shieldSprite
+ self.playerSprite = playerSprite;
+ self.shieldSprite = shieldSprite;
+ return self;
+});
+// Point class: moves downward, destroys itself off-screen
+var Point = Container.expand(function () {
+ var self = Container.call(this);
+ var pointSprite = self.attachAsset('point', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Speed (slower than obstacles)
+ self.speed = 7 + Math.random() * 4;
+ // For collision detection
+ self.pointSprite = pointSprite;
+ 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: 0x181c2c
+});
+
+/****
+* Game Code
+****/
+// Point: yellow ellipse
+// Obstacle: red box
+// Shield: semi-transparent cyan ellipse, slightly larger
+// Player character: blue ellipse
+// Game area: 2048x2732
+// Player starts at center
+var player = new Player();
+player.x = 2048 / 2;
+player.y = 2732 * 0.7;
+game.addChild(player);
+// Score display
+var score = 0;
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0xFFF700
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Lives display
+var lives = 3;
+var livesTxt = new Text2('❤❤❤', {
+ size: 90,
+ fill: 0xFF3333
+});
+livesTxt.anchor.set(0.5, 0);
+LK.gui.topRight.addChild(livesTxt);
+// Arrays for obstacles and points
+var obstacles = [];
+var points = [];
+// Timers for spawning
+var obstacleTimer = 0;
+var pointTimer = 0;
+// Invulnerability after hit
+var invulnTicks = 0;
+var INVULN_DURATION = 60; // 1 second at 60fps
+// Helper: update lives text
+function updateLivesText() {
+ var s = '';
+ for (var i = 0; i < lives; i++) s += '❤';
+ livesTxt.setText(s);
+}
+// Helper: clamp player position inside game area
+function clampPlayerPosition() {
+ var r = 100;
+ if (player.x < r) player.x = r;
+ if (player.x > 2048 - r) player.x = 2048 - r;
+ if (player.y < r + 100) player.y = r + 100; // avoid top menu
+ if (player.y > 2732 - r) player.y = 2732 - r;
+}
+// Main update loop
+game.update = function () {
+ // 1. Update player position from facekit
+ var mouth = facekit.mouthCenter;
+ if (mouth && typeof mouth.x === 'number' && typeof mouth.y === 'number') {
+ // Smooth follow
+ player.x += (mouth.x - player.x) * 0.35;
+ player.y += (mouth.y - player.y) * 0.35;
+ clampPlayerPosition();
+ }
+ // 2. Shield: mouth open
+ var shieldActive = !!facekit.mouthOpen;
+ player.setShield(shieldActive);
+ // 3. Spawn obstacles
+ obstacleTimer--;
+ if (obstacleTimer <= 0) {
+ var obs = new Obstacle();
+ obs.x = 180 + Math.random() * (2048 - 360);
+ obs.y = -80;
+ obstacles.push(obs);
+ game.addChild(obs);
+ // Next spawn: 30-60 ticks
+ obstacleTimer = 30 + Math.floor(Math.random() * 30);
+ }
+ // 4. Spawn points
+ pointTimer--;
+ if (pointTimer <= 0) {
+ var pt = new Point();
+ pt.x = 180 + Math.random() * (2048 - 360);
+ pt.y = -60;
+ points.push(pt);
+ game.addChild(pt);
+ // Next spawn: 80-160 ticks
+ pointTimer = 80 + Math.floor(Math.random() * 80);
+ }
+ // 5. Update obstacles
+ for (var i = obstacles.length - 1; i >= 0; i--) {
+ var obs = obstacles[i];
+ obs.update();
+ // Remove if off-screen
+ if (obs.y > 2732 + 100) {
+ obs.destroy();
+ obstacles.splice(i, 1);
+ continue;
+ }
+ // Collision with player
+ var collides = obs.obstacleSprite.intersects(player.playerSprite);
+ if (collides) {
+ if (shieldActive || invulnTicks > 0) {
+ // Blocked: flash obstacle, destroy
+ tween(obs.obstacleSprite, {
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ obs.destroy();
+ }
+ });
+ obstacles.splice(i, 1);
+ continue;
+ } else {
+ // Hit: lose life, invuln, flash player
+ lives--;
+ updateLivesText();
+ invulnTicks = INVULN_DURATION;
+ LK.effects.flashObject(player, 0xff0000, 600);
+ if (lives <= 0) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ return;
+ }
+ // Remove obstacle
+ obs.destroy();
+ obstacles.splice(i, 1);
+ continue;
+ }
+ }
+ }
+ // 6. Update points
+ for (var j = points.length - 1; j >= 0; j--) {
+ var pt = points[j];
+ pt.update();
+ // Remove if off-screen
+ if (pt.y > 2732 + 80) {
+ pt.destroy();
+ points.splice(j, 1);
+ continue;
+ }
+ // Collision with player
+ var collides = pt.pointSprite.intersects(player.playerSprite);
+ if (collides) {
+ // Collect point
+ score += 1;
+ LK.setScore(score);
+ scoreTxt.setText(score);
+ // Flash point
+ tween(pt.pointSprite, {
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ pt.destroy();
+ }
+ });
+ points.splice(j, 1);
+ continue;
+ }
+ }
+ // 7. Invulnerability timer
+ if (invulnTicks > 0) {
+ invulnTicks--;
+ // Flicker player
+ player.playerSprite.alpha = invulnTicks % 8 < 4 ? 0.4 : 1.0;
+ } else {
+ player.playerSprite.alpha = 1.0;
+ }
+};
+// On game start, reset everything
+function resetGame() {
+ score = 0;
+ LK.setScore(0);
+ scoreTxt.setText('0');
+ lives = 3;
+ updateLivesText();
+ invulnTicks = 0;
+ // 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 = [];
+ // Reset player position
+ player.x = 2048 / 2;
+ player.y = 2732 * 0.7;
+ player.setShield(false);
+}
+resetGame();
+// No touch/mouse controls needed; all via facekit
+// End of MVP
\ No newline at end of file