User prompt
stop the death when game resets
User prompt
add the death when the player dies
User prompt
add the music to the game
User prompt
make the title "Flappy Bird" yellow
User prompt
delete "make it yellow "
User prompt
make it yellow
User prompt
add a pixelated text that says "Flappy Bird" and hide it after the first tap
User prompt
put it above the flap insructions
User prompt
show a pixelated text above the flap instruction and hide after first tap
User prompt
add a pixelated text above the flap instruction and hide after first tap
User prompt
make the bird, and pipes stop moving before first tap
User prompt
make everything stop moving before first tap
User prompt
add a ui
User prompt
put at the bottom of the screen
User prompt
i keep dying when i go through the gap
User prompt
make the top pipe hitboxes smaller
User prompt
make the pipes hitbox smaller
User prompt
the top pipe collision isn't working
User prompt
make it when the player touches the pipes they die
User prompt
make it when the player touches the pipes, the ground, and the ceiling die
User prompt
add the sun
User prompt
add clouds in the background
User prompt
when the player dies dont change their high score unless they go past it ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make it so when the player hits the ground they die
User prompt
make the space between the pipes smaller
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); // Attach bird asset (yellow ellipse) var birdAsset = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Set initial properties self.vy = 0; // vertical velocity self.gravity = 0.5; // gravity per frame (further reduced for even slower falling) self.flapStrength = -18; // negative for upward movement (lower jump) // Bird update: apply gravity, move, clamp position self.update = function () { self.vy += self.gravity; self.y += self.vy; // Clamp to top of screen (use ellipse top) if (self.y < self.height / 2 * 0.82) { self.y = self.height / 2 * 0.82; self.vy = 0; } }; // Flap: set upward velocity self.flap = function () { self.vy = self.flapStrength; }; return self; }); // PipePair class (top and bottom pipes) var PipePair = Container.expand(function () { var self = Container.call(this); // Pipe config self.pipeWidth = 400; self.gapHeight = 900; // Reduced gap for harder gameplay self.speed = 7; // Create top pipe (green box) self.topPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 1, width: self.pipeWidth, height: 900 }); self.topPipe.rotation = Math.PI; // Create bottom pipe (green box) self.bottomPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 0, width: self.pipeWidth, height: 900 }); // Set initial positions (will be set by spawn) self.topPipe.x = 0; self.bottomPipe.x = 0; // Used to track if score was already given for this pipe self.passed = false; // Set pipes' vertical positions based on gapY self.setGap = function (gapY) { self.topPipe.y = 0; // Touch the ceiling self.bottomPipe.y = gapY + self.gapHeight / 2; }; // Move pipes left self.update = function () { self.x -= self.speed; }; // Helper: get bounding rect for collision self.getTopRect = function () { return new Rectangle(self.x - self.pipeWidth / 2, 0, self.pipeWidth, self.topPipe.y); }; self.getBottomRect = function () { return new Rectangle(self.x - self.pipeWidth / 2, self.bottomPipe.y, self.pipeWidth, 2732 - self.bottomPipe.y); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // --- Game Variables --- // --- Asset Initialization --- var bird; var pipes = []; var ground; var score = 0; var scoreTxt; var gameStarted = false; var gameOver = false; var pipeTimer = null; var lastPipeX = 0; var nextPipeDist = 0; var bestScore = 0; // --- GUI Score Display --- scoreTxt = new Text2('0', { size: 180, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Best Score Display (top right) --- var bestScoreTxt = new Text2('', { size: 60, fill: 0xFFF7B2 }); bestScoreTxt.anchor.set(1, 0); bestScoreTxt.x = -60; bestScoreTxt.y = 30; LK.gui.topRight.addChild(bestScoreTxt); // --- Ground --- ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: 2732 - 120 }); game.addChild(ground); // --- Bird --- bird = new Bird(); bird.x = 500; bird.y = 2732 / 2; game.addChild(bird); // --- Reset Game State --- function resetGame() { // Remove pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Reset bird bird.x = 500; bird.y = 2732 / 2; bird.vy = 0; // Reset score score = 0; scoreTxt.setText(score); // Reset state gameStarted = false; gameOver = false; // Show best score bestScore = bestScore || 0; bestScoreTxt.setText('Best: ' + bestScore); // Remove pipe timer if any if (pipeTimer) { LK.clearInterval(pipeTimer); pipeTimer = null; } } // --- Start Game --- function startGame() { if (gameStarted) return; gameStarted = true; gameOver = false; score = 0; scoreTxt.setText(score); // Remove pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Reset bird bird.x = 500; bird.y = 2732 / 2; bird.vy = 0; // Start pipe spawning spawnPipe(); if (pipeTimer) LK.clearInterval(pipeTimer); pipeTimer = LK.setInterval(spawnPipe, 1100); } // --- End Game --- function endGame() { if (gameOver) return; gameOver = true; gameStarted = false; // Stop pipe spawning if (pipeTimer) { LK.clearInterval(pipeTimer); pipeTimer = null; } // Flash screen LK.effects.flashScreen(0xff0000, 600); // Update best score if (score > bestScore) { bestScore = score; } bestScoreTxt.setText('Best: ' + bestScore); // Show game over popup (handled by LK) LK.showGameOver(); } // --- Pipe Spawning --- function spawnPipe() { // Gap vertical position: slightly above the vertical center of the screen var gapY = 2732 / 2 - 250; var pipePair = new PipePair(); pipePair.x = 2048 + pipePair.pipeWidth; // Spawn just off right edge pipePair.setGap(gapY); game.addChild(pipePair); pipes.push(pipePair); } // --- Collision Detection --- function rectsIntersect(ax, ay, aw, ah, bx, by, bw, bh) { return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by; } // --- Game Update Loop --- game.update = function () { if (!gameStarted) return; // Bird update bird.update(); // Ground collision (use ellipse bottom) if (bird.y + bird.height / 2 * 0.82 >= 2732 - 120) { bird.y = 2732 - 120 - bird.height / 2 * 0.82; endGame(); return; } // Pipe update and collision var _loop = function _loop() { pipe = pipes[i]; pipe.update(); // Remove pipes off screen if (pipe.x < -pipe.pipeWidth) { pipe.destroy(); pipes.splice(i, 1); return 0; // continue } // Collision with pipes // Bird ellipse center and radii birdCx = bird.x; birdCy = bird.y; birdRx = bird.width / 2 * 0.82; // slightly smaller for visual fit birdRy = bird.height / 2 * 0.82; // Ellipse-rectangle collision helper function ellipseRectCollides(cx, cy, rx, ry, rx1, ry1, rw, rh) { // Find closest point on rectangle to ellipse center var closestX = Math.max(rx1, Math.min(cx, rx1 + rw)); var closestY = Math.max(ry1, Math.min(cy, ry1 + rh)); // Compute normalized distance var dx = (closestX - cx) / rx; var dy = (closestY - cy) / ry; return dx * dx + dy * dy <= 1; } // Top pipe topRect = pipe.getTopRect(); if (ellipseRectCollides(birdCx, birdCy, birdRx, birdRy, topRect.x, topRect.y, topRect.width, topRect.height)) { endGame(); return { v: void 0 }; } // Bottom pipe bottomRect = pipe.getBottomRect(); if (ellipseRectCollides(birdCx, birdCy, birdRx, birdRy, bottomRect.x, bottomRect.y, bottomRect.width, bottomRect.height)) { endGame(); return { v: void 0 }; } // Score: if bird passed pipe center and not yet scored if (!pipe.passed && pipe.x + pipe.pipeWidth / 2 < bird.x - bird.width / 2) { pipe.passed = true; score += 1; scoreTxt.setText(score); } }, pipe, birdCx, birdCy, birdRx, birdRy, topRect, bottomRect, _ret; for (var i = pipes.length - 1; i >= 0; i--) { _ret = _loop(); if (_ret === 0) continue; if (_ret) return _ret.v; } }; // --- Tap/Touch Controls --- game.down = function (x, y, obj) { if (gameOver) { resetGame(); return; } if (!gameStarted) { startGame(); } bird.flap(); }; // --- Reset on Game Over --- LK.on('gameover', function () { resetGame(); }); // --- Initial State --- resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Attach bird asset (yellow ellipse)
var birdAsset = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial properties
self.vy = 0; // vertical velocity
self.gravity = 0.5; // gravity per frame (further reduced for even slower falling)
self.flapStrength = -18; // negative for upward movement (lower jump)
// Bird update: apply gravity, move, clamp position
self.update = function () {
self.vy += self.gravity;
self.y += self.vy;
// Clamp to top of screen (use ellipse top)
if (self.y < self.height / 2 * 0.82) {
self.y = self.height / 2 * 0.82;
self.vy = 0;
}
};
// Flap: set upward velocity
self.flap = function () {
self.vy = self.flapStrength;
};
return self;
});
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
var self = Container.call(this);
// Pipe config
self.pipeWidth = 400;
self.gapHeight = 900; // Reduced gap for harder gameplay
self.speed = 7;
// Create top pipe (green box)
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1,
width: self.pipeWidth,
height: 900
});
self.topPipe.rotation = Math.PI;
// Create bottom pipe (green box)
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0,
width: self.pipeWidth,
height: 900
});
// Set initial positions (will be set by spawn)
self.topPipe.x = 0;
self.bottomPipe.x = 0;
// Used to track if score was already given for this pipe
self.passed = false;
// Set pipes' vertical positions based on gapY
self.setGap = function (gapY) {
self.topPipe.y = 0; // Touch the ceiling
self.bottomPipe.y = gapY + self.gapHeight / 2;
};
// Move pipes left
self.update = function () {
self.x -= self.speed;
};
// Helper: get bounding rect for collision
self.getTopRect = function () {
return new Rectangle(self.x - self.pipeWidth / 2, 0, self.pipeWidth, self.topPipe.y);
};
self.getBottomRect = function () {
return new Rectangle(self.x - self.pipeWidth / 2, self.bottomPipe.y, self.pipeWidth, 2732 - self.bottomPipe.y);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// --- Game Variables ---
// --- Asset Initialization ---
var bird;
var pipes = [];
var ground;
var score = 0;
var scoreTxt;
var gameStarted = false;
var gameOver = false;
var pipeTimer = null;
var lastPipeX = 0;
var nextPipeDist = 0;
var bestScore = 0;
// --- GUI Score Display ---
scoreTxt = new Text2('0', {
size: 180,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Best Score Display (top right) ---
var bestScoreTxt = new Text2('', {
size: 60,
fill: 0xFFF7B2
});
bestScoreTxt.anchor.set(1, 0);
bestScoreTxt.x = -60;
bestScoreTxt.y = 30;
LK.gui.topRight.addChild(bestScoreTxt);
// --- Ground ---
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 120
});
game.addChild(ground);
// --- Bird ---
bird = new Bird();
bird.x = 500;
bird.y = 2732 / 2;
game.addChild(bird);
// --- Reset Game State ---
function resetGame() {
// Remove pipes
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
// Reset bird
bird.x = 500;
bird.y = 2732 / 2;
bird.vy = 0;
// Reset score
score = 0;
scoreTxt.setText(score);
// Reset state
gameStarted = false;
gameOver = false;
// Show best score
bestScore = bestScore || 0;
bestScoreTxt.setText('Best: ' + bestScore);
// Remove pipe timer if any
if (pipeTimer) {
LK.clearInterval(pipeTimer);
pipeTimer = null;
}
}
// --- Start Game ---
function startGame() {
if (gameStarted) return;
gameStarted = true;
gameOver = false;
score = 0;
scoreTxt.setText(score);
// Remove pipes
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
// Reset bird
bird.x = 500;
bird.y = 2732 / 2;
bird.vy = 0;
// Start pipe spawning
spawnPipe();
if (pipeTimer) LK.clearInterval(pipeTimer);
pipeTimer = LK.setInterval(spawnPipe, 1100);
}
// --- End Game ---
function endGame() {
if (gameOver) return;
gameOver = true;
gameStarted = false;
// Stop pipe spawning
if (pipeTimer) {
LK.clearInterval(pipeTimer);
pipeTimer = null;
}
// Flash screen
LK.effects.flashScreen(0xff0000, 600);
// Update best score
if (score > bestScore) {
bestScore = score;
}
bestScoreTxt.setText('Best: ' + bestScore);
// Show game over popup (handled by LK)
LK.showGameOver();
}
// --- Pipe Spawning ---
function spawnPipe() {
// Gap vertical position: slightly above the vertical center of the screen
var gapY = 2732 / 2 - 250;
var pipePair = new PipePair();
pipePair.x = 2048 + pipePair.pipeWidth; // Spawn just off right edge
pipePair.setGap(gapY);
game.addChild(pipePair);
pipes.push(pipePair);
}
// --- Collision Detection ---
function rectsIntersect(ax, ay, aw, ah, bx, by, bw, bh) {
return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
}
// --- Game Update Loop ---
game.update = function () {
if (!gameStarted) return;
// Bird update
bird.update();
// Ground collision (use ellipse bottom)
if (bird.y + bird.height / 2 * 0.82 >= 2732 - 120) {
bird.y = 2732 - 120 - bird.height / 2 * 0.82;
endGame();
return;
}
// Pipe update and collision
var _loop = function _loop() {
pipe = pipes[i];
pipe.update();
// Remove pipes off screen
if (pipe.x < -pipe.pipeWidth) {
pipe.destroy();
pipes.splice(i, 1);
return 0; // continue
}
// Collision with pipes
// Bird ellipse center and radii
birdCx = bird.x;
birdCy = bird.y;
birdRx = bird.width / 2 * 0.82; // slightly smaller for visual fit
birdRy = bird.height / 2 * 0.82; // Ellipse-rectangle collision helper
function ellipseRectCollides(cx, cy, rx, ry, rx1, ry1, rw, rh) {
// Find closest point on rectangle to ellipse center
var closestX = Math.max(rx1, Math.min(cx, rx1 + rw));
var closestY = Math.max(ry1, Math.min(cy, ry1 + rh));
// Compute normalized distance
var dx = (closestX - cx) / rx;
var dy = (closestY - cy) / ry;
return dx * dx + dy * dy <= 1;
}
// Top pipe
topRect = pipe.getTopRect();
if (ellipseRectCollides(birdCx, birdCy, birdRx, birdRy, topRect.x, topRect.y, topRect.width, topRect.height)) {
endGame();
return {
v: void 0
};
}
// Bottom pipe
bottomRect = pipe.getBottomRect();
if (ellipseRectCollides(birdCx, birdCy, birdRx, birdRy, bottomRect.x, bottomRect.y, bottomRect.width, bottomRect.height)) {
endGame();
return {
v: void 0
};
}
// Score: if bird passed pipe center and not yet scored
if (!pipe.passed && pipe.x + pipe.pipeWidth / 2 < bird.x - bird.width / 2) {
pipe.passed = true;
score += 1;
scoreTxt.setText(score);
}
},
pipe,
birdCx,
birdCy,
birdRx,
birdRy,
topRect,
bottomRect,
_ret;
for (var i = pipes.length - 1; i >= 0; i--) {
_ret = _loop();
if (_ret === 0) continue;
if (_ret) return _ret.v;
}
};
// --- Tap/Touch Controls ---
game.down = function (x, y, obj) {
if (gameOver) {
resetGame();
return;
}
if (!gameStarted) {
startGame();
}
bird.flap();
};
// --- Reset on Game Over ---
LK.on('gameover', function () {
resetGame();
});
// --- Initial State ---
resetGame();