Code edit (1 edits merged)
Please save this source code
User prompt
Face Dash: Smile Runner
User prompt
Please continue polishing my design document.
User prompt
Make a poop clicker where you click poop. every time you click the poop you get one extra fly. every time you get 5 flies you can upgrade and get twice as much clicks
Initial prompt
hi
/****
* 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 flash
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
});
// For possible future animation
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.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c2c
});
/****
* Game Code
****/
/*
We use simple shapes for the character, obstacles, and points.
- character: ellipse, bright color
- obstacle: box, dark color
- point: ellipse, gold color
*/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CHAR_START_X = GAME_WIDTH / 2;
var CHAR_START_Y = GAME_HEIGHT * 0.8;
var OBSTACLE_MIN_X = 180;
var OBSTACLE_MAX_X = GAME_WIDTH - 180;
var OBSTACLE_MIN_GAP = 400;
var OBSTACLE_MAX_GAP = 900;
var OBSTACLE_MIN_SPEED = 12;
var OBSTACLE_MAX_SPEED = 32;
var POINT_MIN_GAP = 600;
var POINT_MAX_GAP = 1400;
var POINT_SPEED_FACTOR = 1.0;
// Game state
var faceChar;
var obstacles = [];
var points = [];
var score = 0;
var scoreTxt;
var lastObstacleY = 0;
var lastPointY = 0;
var gameSpeed = 1.0;
var ticksSinceStart = 0;
var isGameOver = false;
// Score display
scoreTxt = new Text2('0', {
size: 140,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create player character
faceChar = new FaceChar();
game.addChild(faceChar);
faceChar.x = CHAR_START_X;
faceChar.y = CHAR_START_Y;
// Helper: Clamp value
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Helper: Generate random integer in [min, max]
function randInt(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// Helper: Place new obstacle at top
function spawnObstacle() {
var obs = new Obstacle();
obs.x = randInt(OBSTACLE_MIN_X, OBSTACLE_MAX_X);
obs.y = -100;
obs.speed = OBSTACLE_MIN_SPEED + (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * Math.min(1, gameSpeed / 3);
obstacles.push(obs);
game.addChild(obs);
}
// Helper: Place new point at top
function spawnPoint() {
var pt = new PointItem();
pt.x = randInt(OBSTACLE_MIN_X, OBSTACLE_MAX_X);
pt.y = -80;
pt.speed = (OBSTACLE_MIN_SPEED + (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * Math.min(1, gameSpeed / 3)) * POINT_SPEED_FACTOR;
points.push(pt);
game.addChild(pt);
}
// Main update loop
game.update = function () {
if (isGameOver) return;
ticksSinceStart++;
// Increase speed over time
if (ticksSinceStart % 120 === 0) {
gameSpeed += 0.08;
}
// Face tracking: Use mouth center if available, else nose tip
var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : CHAR_START_X;
var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : CHAR_START_Y;
// Clamp to game area, avoid top 100px (menu)
faceChar.x = clamp(fx, 100 + faceChar.width / 2, GAME_WIDTH - faceChar.width / 2);
faceChar.y = clamp(fy, 200 + faceChar.height / 2, GAME_HEIGHT - faceChar.height / 2);
// Spawn obstacles
if (obstacles.length === 0 || obstacles[obstacles.length - 1].y > randInt(OBSTACLE_MIN_GAP, OBSTACLE_MAX_GAP)) {
spawnObstacle();
}
// Spawn points
if (points.length === 0 || points[points.length - 1].y > randInt(POINT_MIN_GAP, POINT_MAX_GAP)) {
spawnPoint();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.y += obs.speed * gameSpeed;
if (obs.y > GAME_HEIGHT + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with player
if (faceChar.intersects(obs)) {
isGameOver = true;
faceChar.flash();
LK.effects.flashScreen(0xff2222, 800);
LK.showGameOver();
return;
}
}
// Update points
for (var j = points.length - 1; j >= 0; j--) {
var pt = points[j];
pt.y += pt.speed * gameSpeed;
if (pt.y > GAME_HEIGHT + 80) {
pt.destroy();
points.splice(j, 1);
continue;
}
// Collect point
if (faceChar.intersects(pt)) {
score += 1;
scoreTxt.setText(score);
// Flash effect
LK.effects.flashObject(faceChar, 0xffd700, 200);
pt.destroy();
points.splice(j, 1);
continue;
}
}
};
// Reset state on game restart
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 = [];
score = 0;
scoreTxt.setText(score);
faceChar.x = CHAR_START_X;
faceChar.y = CHAR_START_Y;
gameSpeed = 1.0;
ticksSinceStart = 0;
isGameOver = false;
}); /****
* 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 flash
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
});
// For possible future animation
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.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c2c
});
/****
* Game Code
****/
/*
We use simple shapes for the character, obstacles, and points.
- character: ellipse, bright color
- obstacle: box, dark color
- point: ellipse, gold color
*/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CHAR_START_X = GAME_WIDTH / 2;
var CHAR_START_Y = GAME_HEIGHT * 0.8;
var OBSTACLE_MIN_X = 180;
var OBSTACLE_MAX_X = GAME_WIDTH - 180;
var OBSTACLE_MIN_GAP = 400;
var OBSTACLE_MAX_GAP = 900;
var OBSTACLE_MIN_SPEED = 12;
var OBSTACLE_MAX_SPEED = 32;
var POINT_MIN_GAP = 600;
var POINT_MAX_GAP = 1400;
var POINT_SPEED_FACTOR = 1.0;
// Game state
var faceChar;
var obstacles = [];
var points = [];
var score = 0;
var scoreTxt;
var lastObstacleY = 0;
var lastPointY = 0;
var gameSpeed = 1.0;
var ticksSinceStart = 0;
var isGameOver = false;
// Score display
scoreTxt = new Text2('0', {
size: 140,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create player character
faceChar = new FaceChar();
game.addChild(faceChar);
faceChar.x = CHAR_START_X;
faceChar.y = CHAR_START_Y;
// Helper: Clamp value
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Helper: Generate random integer in [min, max]
function randInt(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// Helper: Place new obstacle at top
function spawnObstacle() {
var obs = new Obstacle();
obs.x = randInt(OBSTACLE_MIN_X, OBSTACLE_MAX_X);
obs.y = -100;
obs.speed = OBSTACLE_MIN_SPEED + (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * Math.min(1, gameSpeed / 3);
obstacles.push(obs);
game.addChild(obs);
}
// Helper: Place new point at top
function spawnPoint() {
var pt = new PointItem();
pt.x = randInt(OBSTACLE_MIN_X, OBSTACLE_MAX_X);
pt.y = -80;
pt.speed = (OBSTACLE_MIN_SPEED + (OBSTACLE_MAX_SPEED - OBSTACLE_MIN_SPEED) * Math.min(1, gameSpeed / 3)) * POINT_SPEED_FACTOR;
points.push(pt);
game.addChild(pt);
}
// Main update loop
game.update = function () {
if (isGameOver) return;
ticksSinceStart++;
// Increase speed over time
if (ticksSinceStart % 120 === 0) {
gameSpeed += 0.08;
}
// Face tracking: Use mouth center if available, else nose tip
var fx = facekit.mouthCenter && facekit.mouthCenter.x ? facekit.mouthCenter.x : facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : CHAR_START_X;
var fy = facekit.mouthCenter && facekit.mouthCenter.y ? facekit.mouthCenter.y : facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : CHAR_START_Y;
// Clamp to game area, avoid top 100px (menu)
faceChar.x = clamp(fx, 100 + faceChar.width / 2, GAME_WIDTH - faceChar.width / 2);
faceChar.y = clamp(fy, 200 + faceChar.height / 2, GAME_HEIGHT - faceChar.height / 2);
// Spawn obstacles
if (obstacles.length === 0 || obstacles[obstacles.length - 1].y > randInt(OBSTACLE_MIN_GAP, OBSTACLE_MAX_GAP)) {
spawnObstacle();
}
// Spawn points
if (points.length === 0 || points[points.length - 1].y > randInt(POINT_MIN_GAP, POINT_MAX_GAP)) {
spawnPoint();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.y += obs.speed * gameSpeed;
if (obs.y > GAME_HEIGHT + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with player
if (faceChar.intersects(obs)) {
isGameOver = true;
faceChar.flash();
LK.effects.flashScreen(0xff2222, 800);
LK.showGameOver();
return;
}
}
// Update points
for (var j = points.length - 1; j >= 0; j--) {
var pt = points[j];
pt.y += pt.speed * gameSpeed;
if (pt.y > GAME_HEIGHT + 80) {
pt.destroy();
points.splice(j, 1);
continue;
}
// Collect point
if (faceChar.intersects(pt)) {
score += 1;
scoreTxt.setText(score);
// Flash effect
LK.effects.flashObject(faceChar, 0xffd700, 200);
pt.destroy();
points.splice(j, 1);
continue;
}
}
};
// Reset state on game restart
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 = [];
score = 0;
scoreTxt.setText(score);
faceChar.x = CHAR_START_X;
faceChar.y = CHAR_START_Y;
gameSpeed = 1.0;
ticksSinceStart = 0;
isGameOver = false;
});