User prompt
After score even 50 make sure none of the pipes shouldnt be impossible to pass maybe we can do %1 easier after 50 till 50 everything is ok
User prompt
Start my score from 45 for test purposes
User prompt
make %4-5 less extreme for make vertical extreme in later on the game score around 50+ make %2-3 more extreme
User prompt
Biraz daha arttır gap position randomness make vertical movement little bit more extreme
User prompt
Pipe spawnını aniden en alttan en üste çekme biraz daha yakınlaştır kuş zor olsada yetişebilsin ama çokta kolaylaştırma
User prompt
Pipe spawnını biraz daha zorlaştır şuan çok kolay
User prompt
Pipeların boşluğunu yetişebileceğimiz şekilde derecelendir bir anda en yüksekten en aşağıya geçişlerde bazen geçmek imkansız olabiliyor bunları kuşun hızına göre ölç ayarla
User prompt
Her 30 puanda bir arka plan asseti değişsin toplamda 3 farklı asset olabilir
User prompt
Pipeların üstleri ve altları tamamen ekranın üstüne altına gelsin boşluk sadece pipeların arasında kalsın
User prompt
Pipelar tamamen oyun ekranına sığdırılsın alttan ve üstten boşluk kalmasın
User prompt
Pipe'ların içinden geçiş kolaylaşması adına aralıkları genişlesin
Code edit (1 edits merged)
Please save this source code
User prompt
Flappy Bird - Tap to Fly
Initial prompt
Flappy Bird oyunu
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bird = Container.expand(function () { var self = Container.call(this); var birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); self.velocity = 0; self.gravity = 0.5; self.flapPower = -10; self.maxFallSpeed = 10; self.rotation = 0; self.flap = function () { self.velocity = self.flapPower; LK.getSound('flap').play(); // Animate bird flap tween(birdGraphics, { rotation: -0.3 }, { duration: 150, easing: tween.easeOut }); tween(birdGraphics, { rotation: 0 }, { duration: 300, easing: tween.easeInOut }); }; self.die = function () { // Remove current bird graphics birdGraphics.destroy(); // Add dead bird graphics birdGraphics = self.attachAsset('deadBird', { anchorX: 0.5, anchorY: 0.5 }); }; self.reset = function () { // Remove current bird graphics birdGraphics.destroy(); // Add normal bird graphics birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); }; self.update = function () { // Only apply physics when game is started and not showing menu or countdown if (!gameStarted || showingMenu || showingCountdown) { return; } // Apply gravity self.velocity += self.gravity; // Limit fall speed if (self.velocity > self.maxFallSpeed) { self.velocity = self.maxFallSpeed; } // Update position self.y += self.velocity; // Rotate bird based on velocity var targetRotation = Math.min(Math.PI / 4, self.velocity * 0.05); birdGraphics.rotation = targetRotation; }; return self; }); var GameOverScreen = Container.expand(function () { var self = Container.call(this); // Semi-transparent overlay var overlay = self.attachAsset('ground', { anchorX: 0, anchorY: 0, width: 2048, height: 2732, alpha: 0.7, tint: 0x000000 }); overlay.width = 2048; overlay.height = 2732; // Game Over text var gameOverText = new Text2('GAME OVER', { size: 120, fill: 0xFF0000 }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 1024; gameOverText.y = 800; self.addChild(gameOverText); // Score text var scoreText = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0.5); scoreText.x = 1024; scoreText.y = 950; self.addChild(scoreText); // High score text var highScoreText = new Text2('High Score: 0', { size: 80, fill: 0xFFD700 }); highScoreText.anchor.set(0.5, 0.5); highScoreText.x = 1024; highScoreText.y = 1050; self.addChild(highScoreText); // Play Again button var playAgainButton = self.attachAsset('ground', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 80, tint: 0x00AA00 }); playAgainButton.x = 1024; playAgainButton.y = 1200; var playAgainText = new Text2('PLAY AGAIN', { size: 40, fill: 0xFFFFFF }); playAgainText.anchor.set(0.5, 0.5); playAgainText.x = 1024; playAgainText.y = 1200; self.addChild(playAgainText); // Menu button var menuButton = self.attachAsset('ground', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 80, tint: 0x0066CC }); menuButton.x = 1024; menuButton.y = 1320; var menuText = new Text2('MAIN MENU', { size: 40, fill: 0xFFFFFF }); menuText.anchor.set(0.5, 0.5); menuText.x = 1024; menuText.y = 1320; self.addChild(menuText); self.show = function (currentScore, highScore) { scoreText.setText('Score: ' + currentScore); highScoreText.setText('High Score: ' + highScore); self.visible = true; }; self.hide = function () { self.visible = false; }; // Button handlers playAgainButton.down = function () { // Reset game state gameStarted = false; isGameOver = false; showingMenu = true; bird.velocity = 0; bird.y = 1366; bird.reset(); LK.setScore(0); scoreTxt.setText('0'); if (instructionTxt) instructionTxt.visible = true; // Clear all pipes for (var i = pipes.length - 1; i >= 0; i--) { pipes[i].destroy(); } pipes = []; pipeSpawnTimer = 0; // Reset background to level 0 if (currentBackgroundLevel !== 0) { currentBackgroundLevel = 0; background.destroy(); background = game.addChild(LK.getAsset('background1', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; game.setChildIndex(background, 0); } // Hide game over screen and show main menu self.hide(); bird.visible = false; // Hide bird when returning to menu mainMenu.show(); }; menuButton.down = function () { // Reset game state (same as play again for now) gameStarted = false; isGameOver = false; showingMenu = true; bird.velocity = 0; bird.y = 1366; bird.reset(); LK.setScore(0); scoreTxt.setText('0'); if (instructionTxt) instructionTxt.visible = true; // Clear all pipes for (var i = pipes.length - 1; i >= 0; i--) { pipes[i].destroy(); } pipes = []; pipeSpawnTimer = 0; // Reset background to level 0 if (currentBackgroundLevel !== 0) { currentBackgroundLevel = 0; background.destroy(); background = game.addChild(LK.getAsset('background1', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; game.setChildIndex(background, 0); } // Hide game over screen and show main menu self.hide(); bird.visible = false; // Hide bird when returning to menu mainMenu.show(); }; self.visible = false; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Game title var titleText = new Text2('FLAPPY PLANE', { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; self.addChild(titleText); // Play button var playButton = self.attachAsset('ground', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 80, tint: 0x00AA00 }); playButton.x = 1024; playButton.y = 1200; var playText = new Text2('PLAY', { size: 50, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playText.x = 1024; playText.y = 1200; self.addChild(playText); self.show = function () { self.visible = true; if (instructionTxt) instructionTxt.visible = false; // Hide instruction text when showing menu }; self.hide = function () { self.visible = false; }; // Button handler playButton.down = function () { // Start countdown showingMenu = false; showingCountdown = true; countdownValue = 3; countdownTimer = 0; countdownTxt.setText('3'); countdownTxt.visible = true; bird.visible = true; // Show bird when starting countdown self.hide(); }; return self; }); var Pipe = Container.expand(function () { var self = Container.call(this); self.speed = -4; self.gapSize = 400; self.passed = false; var topPipe = self.attachAsset('pipeTop', { anchorX: 0.5, anchorY: 1 }); var bottomPipe = self.attachAsset('pipeBottom', { anchorX: 0.5, anchorY: 0 }); self.setGapPosition = function (gapY) { // Position top pipe so it extends from screen top (0) to gap // Top pipe anchored at bottom (anchorY: 1), so y position is where bottom edge should be topPipe.y = gapY - self.gapSize / 2; // Position bottom pipe so it extends from gap to screen bottom (2732) // Bottom pipe anchored at top (anchorY: 0), so y position is where top edge should be bottomPipe.y = gapY + self.gapSize / 2; }; self.update = function () { self.x += self.speed; }; self.checkCollision = function (bird) { var birdBounds = { x: bird.x - 30, y: bird.y - 30, width: 60, height: 60 }; var topPipeBounds = { x: self.x - 60, y: topPipe.y - 2732, width: 120, height: 2732 }; var bottomPipeBounds = { x: self.x - 60, y: bottomPipe.y, width: 120, height: 2732 }; return self.intersectsBounds(birdBounds, topPipeBounds) || self.intersectsBounds(birdBounds, bottomPipeBounds); }; self.intersectsBounds = function (a, b) { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game state var gameStarted = false; var bird; var pipes = []; var ground; var pipeSpawnTimer = 0; var pipeSpawnDelay = 120; // 2 seconds at 60fps var currentBackgroundLevel = 0; var background; var gameOverScreen; var isGameOver = false; var mainMenu; var showingMenu = true; var showingCountdown = false; var countdownValue = 3; var countdownTimer = 0; // Create background background = game.addChild(LK.getAsset('background1', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; // Create bird bird = game.addChild(new Bird()); bird.x = 400; bird.y = 1366; // Center of screen bird.visible = false; // Hide bird initially when showing menu // Create ground ground = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0 })); ground.x = 0; ground.y = 2732 - 100; // Create custom game over screen gameOverScreen = game.addChild(new GameOverScreen()); // Create main menu mainMenu = game.addChild(new MainMenu()); mainMenu.show(); // Set initial score to 0 for normal gameplay LK.setScore(0); // Create score display var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 150; // Create instruction text var instructionTxt = new Text2('TAP TO FLY', { size: 80, fill: 0xFFFFFF }); instructionTxt.anchor.set(0.5, 0.5); game.addChild(instructionTxt); instructionTxt.x = 1024; instructionTxt.y = 800; instructionTxt.visible = false; // Hide instruction text when showing menu // Create countdown text var countdownTxt = new Text2('3', { size: 200, fill: 0xFFFFFF }); countdownTxt.anchor.set(0.5, 0.5); game.addChild(countdownTxt); countdownTxt.x = 1024; countdownTxt.y = 1366; countdownTxt.visible = false; // Spawn pipe function function spawnPipe() { var pipe = new Pipe(); var minY = 600; var maxY = 2132; var totalRange = maxY - minY; var currentScore = LK.getScore(); var randomnessMultiplier; // Adjust randomness based on score if (currentScore < 50) { // Early game: 4-5% less extreme (reduce range by ~20-25%) randomnessMultiplier = 0.75; } else { // Late game (50+): 2-3% more extreme but 1% easier to prevent impossible pipes randomnessMultiplier = 1.14; } ; var adjustedRange = totalRange * randomnessMultiplier; var rangeOffset = (totalRange - adjustedRange) / 2; var adjustedMinY = minY + rangeOffset; var adjustedMaxY = maxY - rangeOffset; var gapY = adjustedMinY + Math.random() * adjustedRange; pipe.setGapPosition(gapY); pipe.x = 2048 + 60; pipes.push(pipe); game.addChild(pipe); } // Game input handling game.down = function (x, y, obj) { if (showingMenu || showingCountdown) return; // Don't allow input when menu or countdown is showing if (gameStarted && !isGameOver) { bird.flap(); } }; // Main game loop game.update = function () { // Handle countdown if (showingCountdown) { countdownTimer++; if (countdownTimer >= 60) { // 1 second at 60fps countdownTimer = 0; countdownValue--; if (countdownValue > 0) { countdownTxt.setText(countdownValue.toString()); tween(countdownTxt, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut }); tween(countdownTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } else { // Countdown finished, start game showingCountdown = false; gameStarted = true; countdownTxt.visible = false; if (instructionTxt) instructionTxt.visible = true; spawnPipe(); } } return; } if (showingMenu || !gameStarted || isGameOver) return; // Update bird bird.update(); // Check bird boundaries if (bird.y <= 0 || bird.y >= ground.y - 30) { // Hit ceiling or ground bird.die(); // Stop bird at ground level and prevent going behind ground if (bird.y >= ground.y - 30) { bird.y = ground.y - 30; bird.velocity = 0; } // Save high score var currentScore = LK.getScore(); var highScore = storage.highScore || 0; if (currentScore > highScore) { storage.highScore = currentScore; highScore = currentScore; // Update local highScore variable } LK.getSound('hit').play(); gameOverScreen.show(currentScore, highScore); isGameOver = true; return; } // Additional check to ensure bird never goes behind ground even during normal flight if (bird.y > ground.y - 30) { bird.y = ground.y - 30; bird.velocity = 0; } // Spawn pipes pipeSpawnTimer++; if (pipeSpawnTimer >= pipeSpawnDelay) { spawnPipe(); pipeSpawnTimer = 0; } // Update pipes for (var i = pipes.length - 1; i >= 0; i--) { var pipe = pipes[i]; pipe.update(); // Check collision if (pipe.checkCollision(bird)) { bird.die(); // Save high score var currentScore = LK.getScore(); var highScore = storage.highScore || 0; if (currentScore > highScore) { storage.highScore = currentScore; highScore = currentScore; // Update local highScore variable } LK.getSound('hit').play(); gameOverScreen.show(currentScore, highScore); isGameOver = true; return; } // Check if bird passed pipe if (!pipe.passed && bird.x > pipe.x) { pipe.passed = true; LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('check').play(); // Change background every 20 points var newBackgroundLevel = Math.floor(LK.getScore() / 20) % 5; if (newBackgroundLevel !== currentBackgroundLevel) { currentBackgroundLevel = newBackgroundLevel; var backgroundAssets = ['background1', 'background2', 'background3', 'background4', 'background5']; background.destroy(); background = game.addChild(LK.getAsset(backgroundAssets[currentBackgroundLevel], { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; // Move background to back game.setChildIndex(background, 0); } } // Remove pipes that are off screen if (pipe.x < -120) { pipe.destroy(); pipes.splice(i, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = 0;
self.gravity = 0.5;
self.flapPower = -10;
self.maxFallSpeed = 10;
self.rotation = 0;
self.flap = function () {
self.velocity = self.flapPower;
LK.getSound('flap').play();
// Animate bird flap
tween(birdGraphics, {
rotation: -0.3
}, {
duration: 150,
easing: tween.easeOut
});
tween(birdGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
};
self.die = function () {
// Remove current bird graphics
birdGraphics.destroy();
// Add dead bird graphics
birdGraphics = self.attachAsset('deadBird', {
anchorX: 0.5,
anchorY: 0.5
});
};
self.reset = function () {
// Remove current bird graphics
birdGraphics.destroy();
// Add normal bird graphics
birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
// Only apply physics when game is started and not showing menu or countdown
if (!gameStarted || showingMenu || showingCountdown) {
return;
}
// Apply gravity
self.velocity += self.gravity;
// Limit fall speed
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
// Update position
self.y += self.velocity;
// Rotate bird based on velocity
var targetRotation = Math.min(Math.PI / 4, self.velocity * 0.05);
birdGraphics.rotation = targetRotation;
};
return self;
});
var GameOverScreen = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent overlay
var overlay = self.attachAsset('ground', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732,
alpha: 0.7,
tint: 0x000000
});
overlay.width = 2048;
overlay.height = 2732;
// Game Over text
var gameOverText = new Text2('GAME OVER', {
size: 120,
fill: 0xFF0000
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 1024;
gameOverText.y = 800;
self.addChild(gameOverText);
// Score text
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 1024;
scoreText.y = 950;
self.addChild(scoreText);
// High score text
var highScoreText = new Text2('High Score: 0', {
size: 80,
fill: 0xFFD700
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 1024;
highScoreText.y = 1050;
self.addChild(highScoreText);
// Play Again button
var playAgainButton = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00AA00
});
playAgainButton.x = 1024;
playAgainButton.y = 1200;
var playAgainText = new Text2('PLAY AGAIN', {
size: 40,
fill: 0xFFFFFF
});
playAgainText.anchor.set(0.5, 0.5);
playAgainText.x = 1024;
playAgainText.y = 1200;
self.addChild(playAgainText);
// Menu button
var menuButton = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x0066CC
});
menuButton.x = 1024;
menuButton.y = 1320;
var menuText = new Text2('MAIN MENU', {
size: 40,
fill: 0xFFFFFF
});
menuText.anchor.set(0.5, 0.5);
menuText.x = 1024;
menuText.y = 1320;
self.addChild(menuText);
self.show = function (currentScore, highScore) {
scoreText.setText('Score: ' + currentScore);
highScoreText.setText('High Score: ' + highScore);
self.visible = true;
};
self.hide = function () {
self.visible = false;
};
// Button handlers
playAgainButton.down = function () {
// Reset game state
gameStarted = false;
isGameOver = false;
showingMenu = true;
bird.velocity = 0;
bird.y = 1366;
bird.reset();
LK.setScore(0);
scoreTxt.setText('0');
if (instructionTxt) instructionTxt.visible = true;
// Clear all pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
pipeSpawnTimer = 0;
// Reset background to level 0
if (currentBackgroundLevel !== 0) {
currentBackgroundLevel = 0;
background.destroy();
background = game.addChild(LK.getAsset('background1', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
game.setChildIndex(background, 0);
}
// Hide game over screen and show main menu
self.hide();
bird.visible = false; // Hide bird when returning to menu
mainMenu.show();
};
menuButton.down = function () {
// Reset game state (same as play again for now)
gameStarted = false;
isGameOver = false;
showingMenu = true;
bird.velocity = 0;
bird.y = 1366;
bird.reset();
LK.setScore(0);
scoreTxt.setText('0');
if (instructionTxt) instructionTxt.visible = true;
// Clear all pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
pipeSpawnTimer = 0;
// Reset background to level 0
if (currentBackgroundLevel !== 0) {
currentBackgroundLevel = 0;
background.destroy();
background = game.addChild(LK.getAsset('background1', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
game.setChildIndex(background, 0);
}
// Hide game over screen and show main menu
self.hide();
bird.visible = false; // Hide bird when returning to menu
mainMenu.show();
};
self.visible = false;
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Game title
var titleText = new Text2('FLAPPY PLANE', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
self.addChild(titleText);
// Play button
var playButton = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00AA00
});
playButton.x = 1024;
playButton.y = 1200;
var playText = new Text2('PLAY', {
size: 50,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1200;
self.addChild(playText);
self.show = function () {
self.visible = true;
if (instructionTxt) instructionTxt.visible = false; // Hide instruction text when showing menu
};
self.hide = function () {
self.visible = false;
};
// Button handler
playButton.down = function () {
// Start countdown
showingMenu = false;
showingCountdown = true;
countdownValue = 3;
countdownTimer = 0;
countdownTxt.setText('3');
countdownTxt.visible = true;
bird.visible = true; // Show bird when starting countdown
self.hide();
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.speed = -4;
self.gapSize = 400;
self.passed = false;
var topPipe = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 1
});
var bottomPipe = self.attachAsset('pipeBottom', {
anchorX: 0.5,
anchorY: 0
});
self.setGapPosition = function (gapY) {
// Position top pipe so it extends from screen top (0) to gap
// Top pipe anchored at bottom (anchorY: 1), so y position is where bottom edge should be
topPipe.y = gapY - self.gapSize / 2;
// Position bottom pipe so it extends from gap to screen bottom (2732)
// Bottom pipe anchored at top (anchorY: 0), so y position is where top edge should be
bottomPipe.y = gapY + self.gapSize / 2;
};
self.update = function () {
self.x += self.speed;
};
self.checkCollision = function (bird) {
var birdBounds = {
x: bird.x - 30,
y: bird.y - 30,
width: 60,
height: 60
};
var topPipeBounds = {
x: self.x - 60,
y: topPipe.y - 2732,
width: 120,
height: 2732
};
var bottomPipeBounds = {
x: self.x - 60,
y: bottomPipe.y,
width: 120,
height: 2732
};
return self.intersectsBounds(birdBounds, topPipeBounds) || self.intersectsBounds(birdBounds, bottomPipeBounds);
};
self.intersectsBounds = function (a, b) {
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state
var gameStarted = false;
var bird;
var pipes = [];
var ground;
var pipeSpawnTimer = 0;
var pipeSpawnDelay = 120; // 2 seconds at 60fps
var currentBackgroundLevel = 0;
var background;
var gameOverScreen;
var isGameOver = false;
var mainMenu;
var showingMenu = true;
var showingCountdown = false;
var countdownValue = 3;
var countdownTimer = 0;
// Create background
background = game.addChild(LK.getAsset('background1', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Create bird
bird = game.addChild(new Bird());
bird.x = 400;
bird.y = 1366; // Center of screen
bird.visible = false; // Hide bird initially when showing menu
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2732 - 100;
// Create custom game over screen
gameOverScreen = game.addChild(new GameOverScreen());
// Create main menu
mainMenu = game.addChild(new MainMenu());
mainMenu.show();
// Set initial score to 0 for normal gameplay
LK.setScore(0);
// Create score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 150;
// Create instruction text
var instructionTxt = new Text2('TAP TO FLY', {
size: 80,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
game.addChild(instructionTxt);
instructionTxt.x = 1024;
instructionTxt.y = 800;
instructionTxt.visible = false; // Hide instruction text when showing menu
// Create countdown text
var countdownTxt = new Text2('3', {
size: 200,
fill: 0xFFFFFF
});
countdownTxt.anchor.set(0.5, 0.5);
game.addChild(countdownTxt);
countdownTxt.x = 1024;
countdownTxt.y = 1366;
countdownTxt.visible = false;
// Spawn pipe function
function spawnPipe() {
var pipe = new Pipe();
var minY = 600;
var maxY = 2132;
var totalRange = maxY - minY;
var currentScore = LK.getScore();
var randomnessMultiplier;
// Adjust randomness based on score
if (currentScore < 50) {
// Early game: 4-5% less extreme (reduce range by ~20-25%)
randomnessMultiplier = 0.75;
} else {
// Late game (50+): 2-3% more extreme but 1% easier to prevent impossible pipes
randomnessMultiplier = 1.14;
}
;
var adjustedRange = totalRange * randomnessMultiplier;
var rangeOffset = (totalRange - adjustedRange) / 2;
var adjustedMinY = minY + rangeOffset;
var adjustedMaxY = maxY - rangeOffset;
var gapY = adjustedMinY + Math.random() * adjustedRange;
pipe.setGapPosition(gapY);
pipe.x = 2048 + 60;
pipes.push(pipe);
game.addChild(pipe);
}
// Game input handling
game.down = function (x, y, obj) {
if (showingMenu || showingCountdown) return; // Don't allow input when menu or countdown is showing
if (gameStarted && !isGameOver) {
bird.flap();
}
};
// Main game loop
game.update = function () {
// Handle countdown
if (showingCountdown) {
countdownTimer++;
if (countdownTimer >= 60) {
// 1 second at 60fps
countdownTimer = 0;
countdownValue--;
if (countdownValue > 0) {
countdownTxt.setText(countdownValue.toString());
tween(countdownTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut
});
tween(countdownTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
} else {
// Countdown finished, start game
showingCountdown = false;
gameStarted = true;
countdownTxt.visible = false;
if (instructionTxt) instructionTxt.visible = true;
spawnPipe();
}
}
return;
}
if (showingMenu || !gameStarted || isGameOver) return;
// Update bird
bird.update();
// Check bird boundaries
if (bird.y <= 0 || bird.y >= ground.y - 30) {
// Hit ceiling or ground
bird.die();
// Stop bird at ground level and prevent going behind ground
if (bird.y >= ground.y - 30) {
bird.y = ground.y - 30;
bird.velocity = 0;
}
// Save high score
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
highScore = currentScore; // Update local highScore variable
}
LK.getSound('hit').play();
gameOverScreen.show(currentScore, highScore);
isGameOver = true;
return;
}
// Additional check to ensure bird never goes behind ground even during normal flight
if (bird.y > ground.y - 30) {
bird.y = ground.y - 30;
bird.velocity = 0;
}
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnDelay) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Update pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.update();
// Check collision
if (pipe.checkCollision(bird)) {
bird.die();
// Save high score
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
highScore = currentScore; // Update local highScore variable
}
LK.getSound('hit').play();
gameOverScreen.show(currentScore, highScore);
isGameOver = true;
return;
}
// Check if bird passed pipe
if (!pipe.passed && bird.x > pipe.x) {
pipe.passed = true;
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('check').play();
// Change background every 20 points
var newBackgroundLevel = Math.floor(LK.getScore() / 20) % 5;
if (newBackgroundLevel !== currentBackgroundLevel) {
currentBackgroundLevel = newBackgroundLevel;
var backgroundAssets = ['background1', 'background2', 'background3', 'background4', 'background5'];
background.destroy();
background = game.addChild(LK.getAsset(backgroundAssets[currentBackgroundLevel], {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Move background to back
game.setChildIndex(background, 0);
}
}
// Remove pipes that are off screen
if (pipe.x < -120) {
pipe.destroy();
pipes.splice(i, 1);
}
}
};