/****
* 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