/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Bonus class: falls from top, destroys itself when off screen var Bonus = Container.expand(function () { var self = Container.call(this); var gfx = self.attachAsset('bonus', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; // Will be increased as game progresses self.update = function () { self.y += self.speed; }; return self; }); // Obstacle class: falls from top, destroys itself when off screen var Obstacle = Container.expand(function () { var self = Container.call(this); var gfx = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; // Will be increased as game progresses self.update = function () { self.y += self.speed; }; return self; }); // Player class: follows face position var Player = Container.expand(function () { var self = Container.call(this); var gfx = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // No update needed; position is set by facekit in main game loop return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Player: blue ellipse // Bonus: yellow ellipse // Obstacles: gray boxes // Game variables var player = new Player(); game.addChild(player); player.x = 2048 / 2; player.y = 2732 - 350; // Start near bottom var obstacles = []; var bonuses = []; var score = 0; var bonusScore = 0; var gameOver = false; var ticksSurvived = 0; // Score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Bonus text var bonusTxt = new Text2('', { size: 80, fill: 0xFFE066 }); bonusTxt.anchor.set(0.5, 0); LK.gui.top.addChild(bonusTxt); bonusTxt.y = 130; // Difficulty progression var obstacleInterval = 60; // ticks between obstacles (start: 1/sec) var bonusInterval = 180; // ticks between bonuses (start: 1/3sec) var minObstacleInterval = 18; // fastest: ~3/sec var minBonusInterval = 240; // slowest: ~1/4sec var lastObstacleTick = 0; var lastBonusTick = 0; var obstacleSpeed = 12; var bonusSpeed = 10; var speedIncreaseEvery = 600; // every 10 seconds // Main update loop game.update = function () { if (gameOver) return; // Update player position from facekit // Clamp to game area var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : 2048 / 2; var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : 2732 - 350; // Keep player inside bounds var px = Math.max(player.width / 2, Math.min(2048 - player.width / 2, fx)); var py = Math.max(player.height / 2 + 100, Math.min(2732 - player.height / 2, fy)); player.x = px; player.y = py; // Spawn obstacles if (LK.ticks - lastObstacleTick >= obstacleInterval) { var obs = new Obstacle(); obs.x = Math.random() * (2048 - 200) + 100; obs.y = -obs.height / 2; obs.speed = obstacleSpeed; obstacles.push(obs); game.addChild(obs); lastObstacleTick = LK.ticks; } // Spawn bonuses if (LK.ticks - lastBonusTick >= bonusInterval) { // 60% chance to spawn a bonus if (Math.random() < 0.6) { var bon = new Bonus(); bon.x = Math.random() * (2048 - 160) + 80; bon.y = -bon.height / 2; bon.speed = bonusSpeed; bonuses.push(bon); game.addChild(bon); } lastBonusTick = LK.ticks; } // Increase difficulty over time if (LK.ticks % speedIncreaseEvery === 0 && LK.ticks > 0) { if (obstacleInterval > minObstacleInterval) obstacleInterval -= 4; if (bonusInterval < minBonusInterval) bonusInterval += 8; obstacleSpeed += 1.5; bonusSpeed += 1; } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if off screen if (obs.y - obs.height / 2 > 2732 + 50) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with player if (obs.intersects(player)) { // Game over LK.effects.flashScreen(0xff0000, 800); gameOver = true; tween(player, { alpha: 0.2 }, { duration: 400, easing: tween.easeOut }); LK.setTimeout(function () { LK.showGameOver(); }, 900); return; } } // Update bonuses for (var j = bonuses.length - 1; j >= 0; j--) { var bon = bonuses[j]; bon.update(); // Remove if off screen if (bon.y - bon.height / 2 > 2732 + 50) { bon.destroy(); bonuses.splice(j, 1); continue; } // Collision with player if (bon.intersects(player)) { bonusScore += 1; score += 5; scoreTxt.setText(score); bonusTxt.setText('Bonuses: ' + bonusScore); // Flash bonus LK.effects.flashObject(bon, 0xffff00, 300); bon.destroy(); bonuses.splice(j, 1); continue; } } // Score: 1 point per 30 ticks survived ticksSurvived++; if (ticksSurvived % 30 === 0) { score += 1; scoreTxt.setText(score); } }; // Reset game state on restart game.on('reset', function () { // Remove all obstacles and bonuses for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } for (var j = 0; j < bonuses.length; j++) { bonuses[j].destroy(); } obstacles = []; bonuses = []; score = 0; bonusScore = 0; ticksSurvived = 0; gameOver = false; player.x = 2048 / 2; player.y = 2732 - 350; scoreTxt.setText('0'); bonusTxt.setText(''); obstacleInterval = 60; bonusInterval = 180; obstacleSpeed = 12; bonusSpeed = 10; lastObstacleTick = 0; lastBonusTick = 0; }); // Show camera background game.setBackgroundColor(0x000000); // Camera will show behind game elements // No need to handle music, pause, or leaderboard
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Bonus class: falls from top, destroys itself when off screen
var Bonus = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('bonus', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10; // Will be increased as game progresses
self.update = function () {
self.y += self.speed;
};
return self;
});
// Obstacle class: falls from top, destroys itself when off screen
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12; // Will be increased as game progresses
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player class: follows face position
var Player = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// No update needed; position is set by facekit in main game loop
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Player: blue ellipse
// Bonus: yellow ellipse
// Obstacles: gray boxes
// Game variables
var player = new Player();
game.addChild(player);
player.x = 2048 / 2;
player.y = 2732 - 350; // Start near bottom
var obstacles = [];
var bonuses = [];
var score = 0;
var bonusScore = 0;
var gameOver = false;
var ticksSurvived = 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Bonus text
var bonusTxt = new Text2('', {
size: 80,
fill: 0xFFE066
});
bonusTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bonusTxt);
bonusTxt.y = 130;
// Difficulty progression
var obstacleInterval = 60; // ticks between obstacles (start: 1/sec)
var bonusInterval = 180; // ticks between bonuses (start: 1/3sec)
var minObstacleInterval = 18; // fastest: ~3/sec
var minBonusInterval = 240; // slowest: ~1/4sec
var lastObstacleTick = 0;
var lastBonusTick = 0;
var obstacleSpeed = 12;
var bonusSpeed = 10;
var speedIncreaseEvery = 600; // every 10 seconds
// Main update loop
game.update = function () {
if (gameOver) return;
// Update player position from facekit
// Clamp to game area
var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : 2048 / 2;
var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : 2732 - 350;
// Keep player inside bounds
var px = Math.max(player.width / 2, Math.min(2048 - player.width / 2, fx));
var py = Math.max(player.height / 2 + 100, Math.min(2732 - player.height / 2, fy));
player.x = px;
player.y = py;
// Spawn obstacles
if (LK.ticks - lastObstacleTick >= obstacleInterval) {
var obs = new Obstacle();
obs.x = Math.random() * (2048 - 200) + 100;
obs.y = -obs.height / 2;
obs.speed = obstacleSpeed;
obstacles.push(obs);
game.addChild(obs);
lastObstacleTick = LK.ticks;
}
// Spawn bonuses
if (LK.ticks - lastBonusTick >= bonusInterval) {
// 60% chance to spawn a bonus
if (Math.random() < 0.6) {
var bon = new Bonus();
bon.x = Math.random() * (2048 - 160) + 80;
bon.y = -bon.height / 2;
bon.speed = bonusSpeed;
bonuses.push(bon);
game.addChild(bon);
}
lastBonusTick = LK.ticks;
}
// Increase difficulty over time
if (LK.ticks % speedIncreaseEvery === 0 && LK.ticks > 0) {
if (obstacleInterval > minObstacleInterval) obstacleInterval -= 4;
if (bonusInterval < minBonusInterval) bonusInterval += 8;
obstacleSpeed += 1.5;
bonusSpeed += 1;
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y - obs.height / 2 > 2732 + 50) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with player
if (obs.intersects(player)) {
// Game over
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
tween(player, {
alpha: 0.2
}, {
duration: 400,
easing: tween.easeOut
});
LK.setTimeout(function () {
LK.showGameOver();
}, 900);
return;
}
}
// Update bonuses
for (var j = bonuses.length - 1; j >= 0; j--) {
var bon = bonuses[j];
bon.update();
// Remove if off screen
if (bon.y - bon.height / 2 > 2732 + 50) {
bon.destroy();
bonuses.splice(j, 1);
continue;
}
// Collision with player
if (bon.intersects(player)) {
bonusScore += 1;
score += 5;
scoreTxt.setText(score);
bonusTxt.setText('Bonuses: ' + bonusScore);
// Flash bonus
LK.effects.flashObject(bon, 0xffff00, 300);
bon.destroy();
bonuses.splice(j, 1);
continue;
}
}
// Score: 1 point per 30 ticks survived
ticksSurvived++;
if (ticksSurvived % 30 === 0) {
score += 1;
scoreTxt.setText(score);
}
};
// Reset game state on restart
game.on('reset', function () {
// Remove all obstacles and bonuses
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
for (var j = 0; j < bonuses.length; j++) {
bonuses[j].destroy();
}
obstacles = [];
bonuses = [];
score = 0;
bonusScore = 0;
ticksSurvived = 0;
gameOver = false;
player.x = 2048 / 2;
player.y = 2732 - 350;
scoreTxt.setText('0');
bonusTxt.setText('');
obstacleInterval = 60;
bonusInterval = 180;
obstacleSpeed = 12;
bonusSpeed = 10;
lastObstacleTick = 0;
lastBonusTick = 0;
});
// Show camera background
game.setBackgroundColor(0x000000); // Camera will show behind game elements
// No need to handle music, pause, or leaderboard