/**** * 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({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Face Dash: Smile to Survive --- // Game area: 2048x2732 // Player setup var player = new Player(); player.x = 2048 / 2; player.y = 2732 * 0.7; game.addChild(player); // Score and lives var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: 0xFFF700 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var lives = 3; var livesTxt = new Text2('❤❤❤', { size: 90, fill: 0xFF3333 }); livesTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(livesTxt); // Game objects var obstacles = []; var points = []; // Timers var obstacleTimer = 0; var pointTimer = 0; // Invulnerability var invulnTicks = 0; var INVULN_DURATION = 60; // 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; 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') { 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; obs.lastY = obs.y; obs.lastWasIntersecting = false; obstacles.push(obs); game.addChild(obs); 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; pt.lastY = pt.y; pt.lastWasIntersecting = false; points.push(pt); game.addChild(pt); 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.lastY <= 2732 + 100 && obs.y > 2732 + 100) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with player: only trigger on collision moment var isIntersecting = obs.obstacleSprite.intersects(player.playerSprite); if (!obs.lastWasIntersecting && isIntersecting) { 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; } obs.destroy(); obstacles.splice(i, 1); continue; } } obs.lastY = obs.y; obs.lastWasIntersecting = isIntersecting; } // 6. Update points for (var j = points.length - 1; j >= 0; j--) { var pt = points[j]; pt.update(); // Remove if off-screen if (pt.lastY <= 2732 + 80 && pt.y > 2732 + 80) { pt.destroy(); points.splice(j, 1); continue; } // Collision with player: only trigger on collision moment var isIntersecting = pt.pointSprite.intersects(player.playerSprite); if (!pt.lastWasIntersecting && isIntersecting) { // Collect point score += 1; LK.setScore(score); scoreTxt.setText(score); tween(pt.pointSprite, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { pt.destroy(); } }); points.splice(j, 1); continue; } pt.lastY = pt.y; pt.lastWasIntersecting = isIntersecting; } // 7. Invulnerability timer if (invulnTicks > 0) { invulnTicks--; 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; for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy(); for (var j = 0; j < points.length; j++) points[j].destroy(); obstacles = []; points = []; 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
@@ -78,43 +78,39 @@
/****
* Game Code
****/
-// Point: yellow ellipse
-// Obstacle: red box
-// Shield: semi-transparent cyan ellipse, slightly larger
-// Player character: blue ellipse
+// --- Face Dash: Smile to Survive ---
// Game area: 2048x2732
-// Player starts at center
+// Player setup
var player = new Player();
player.x = 2048 / 2;
player.y = 2732 * 0.7;
game.addChild(player);
-// Score display
+// Score and lives
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
+// Game objects
var obstacles = [];
var points = [];
-// Timers for spawning
+// Timers
var obstacleTimer = 0;
var pointTimer = 0;
-// Invulnerability after hit
+// Invulnerability
var invulnTicks = 0;
-var INVULN_DURATION = 60; // 1 second at 60fps
+var INVULN_DURATION = 60;
// Helper: update lives text
function updateLivesText() {
var s = '';
for (var i = 0; i < lives; i++) s += '❤';
@@ -124,17 +120,16 @@
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 < r + 100) player.y = r + 100;
if (player.y > 2732 - r) player.y = 2732 - r;
}
-// Main update loop
+// --- 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();
}
@@ -146,37 +141,39 @@
if (obstacleTimer <= 0) {
var obs = new Obstacle();
obs.x = 180 + Math.random() * (2048 - 360);
obs.y = -80;
+ obs.lastY = obs.y;
+ obs.lastWasIntersecting = false;
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;
+ pt.lastY = pt.y;
+ pt.lastWasIntersecting = false;
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) {
+ if (obs.lastY <= 2732 + 100 && obs.y > 2732 + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
- // Collision with player
- var collides = obs.obstacleSprite.intersects(player.playerSprite);
- if (collides) {
+ // Collision with player: only trigger on collision moment
+ var isIntersecting = obs.obstacleSprite.intersects(player.playerSprite);
+ if (!obs.lastWasIntersecting && isIntersecting) {
if (shieldActive || invulnTicks > 0) {
// Blocked: flash obstacle, destroy
tween(obs.obstacleSprite, {
alpha: 0
@@ -198,33 +195,33 @@
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
- // Remove obstacle
obs.destroy();
obstacles.splice(i, 1);
continue;
}
}
+ obs.lastY = obs.y;
+ obs.lastWasIntersecting = isIntersecting;
}
// 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) {
+ if (pt.lastY <= 2732 + 80 && pt.y > 2732 + 80) {
pt.destroy();
points.splice(j, 1);
continue;
}
- // Collision with player
- var collides = pt.pointSprite.intersects(player.playerSprite);
- if (collides) {
+ // Collision with player: only trigger on collision moment
+ var isIntersecting = pt.pointSprite.intersects(player.playerSprite);
+ if (!pt.lastWasIntersecting && isIntersecting) {
// Collect point
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
- // Flash point
tween(pt.pointSprite, {
alpha: 0
}, {
duration: 200,
@@ -234,13 +231,14 @@
});
points.splice(j, 1);
continue;
}
+ pt.lastY = pt.y;
+ pt.lastWasIntersecting = isIntersecting;
}
// 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;
}
@@ -252,17 +250,15 @@
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
+// End of MVP;
\ No newline at end of file