/**** * 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.flapStrength = -12; self.isDead = false; self.flap = function () { if (!self.isDead) { self.velocity = self.flapStrength; LK.getSound('flap').play(); // Rotate bird up when flapping var tweenPromise = tween(self, { rotation: -0.5, scaleX: 1.1, // Slightly squash & stretch for dynamic effect scaleY: 0.9 }, { duration: 100, easing: tween.linear }); if (tweenPromise && typeof tweenPromise.then === 'function') { tweenPromise.then(function () { // Return to normal scale after flap tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOutQuad }); }); } } }; self.update = function () { if (self.isDead) { return; } // Apply gravity and update position self.velocity += self.gravity; self.y += self.velocity; // Rotate bird based on velocity if (self.velocity > 0) { var targetRotation = Math.min(self.velocity * 0.05, 1.2); tween(self, { rotation: targetRotation }, { duration: 100, easing: tween.linear }); } }; self.die = function () { if (!self.isDead) { self.isDead = true; LK.getSound('hit').play(); } }; return self; }); var HighScores = Container.expand(function () { var self = Container.call(this); // Create high scores background var highScoresBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); self.addChild(highScoresBg); // Create title var titleText = new Text2('High Scores', { size: 150, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; self.addChild(titleText); // High score display var highScoreText = new Text2('High Score: 0', { size: 120, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); highScoreText.anchor.set(0.5, 0.5); highScoreText.x = 2048 / 2; highScoreText.y = 1000; self.addChild(highScoreText); // Back button var backButton = new Text2('Back', { size: 100, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); backButton.anchor.set(0.5, 0.5); backButton.x = 2048 / 2; backButton.y = 1400; self.addChild(backButton); // Event handlers self.updateHighScore = function () { var highScore = storage.highScore || 0; highScoreText.setText('High Score: ' + highScore); }; backButton.down = function () { if (self.onBack) { self.onBack(); } }; return self; }); var Menu = Container.expand(function () { var self = Container.call(this); // Create menu background var menuBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); self.addChild(menuBg); // Create title var titleText = new Text2('Flying Bird', { size: 150, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; self.addChild(titleText); // Create play button var playButton = new Text2('Play', { size: 100, fill: 0xFFFFFF }); playButton.anchor.set(0.5, 0.5); playButton.x = 2048 / 2; playButton.y = 1000; self.addChild(playButton); // Create settings button var settingsButton = new Text2('Settings', { size: 100, fill: 0xFFFFFF }); settingsButton.anchor.set(0.5, 0.5); settingsButton.x = 2048 / 2; settingsButton.y = 1150; self.addChild(settingsButton); // Create high scores button var highScoresButton = new Text2('High Scores', { size: 100, fill: 0xFFFFFF }); highScoresButton.anchor.set(0.5, 0.5); highScoresButton.x = 2048 / 2; highScoresButton.y = 1300; self.addChild(highScoresButton); // Event handlers playButton.down = function () { if (self.onPlay) { self.onPlay(); } }; highScoresButton.down = function () { if (self.onHighScores) { self.onHighScores(); } }; settingsButton.down = function () { if (self.onSettings) { self.onSettings(); } }; return self; }); var Parallax = Container.expand(function () { var self = Container.call(this); // Layer properties self.layers = []; self.layerCount = 0; // Add a layer to the parallax effect self.addLayer = function (asset, depth, y) { var layer1 = self.addChild(LK.getAsset(asset, { anchorX: 0, anchorY: 0, x: 0, y: y || 0 })); // Create duplicate for infinite scrolling var layer2 = self.addChild(LK.getAsset(asset, { anchorX: 0, anchorY: 0, x: layer1.width, y: y || 0 })); // Store layer info including duplicates for scrolling self.layers.push({ elements: [layer1, layer2], speed: 0.5 / depth, // Speed based on depth (farther = slower) width: layer1.width }); self.layerCount++; return self.layers[self.layerCount - 1]; }; // Update parallax layers based on game speed self.update = function (baseSpeed) { baseSpeed = baseSpeed || 1; for (var i = 0; i < self.layers.length; i++) { var layer = self.layers[i]; // Move both elements of the layer for (var j = 0; j < layer.elements.length; j++) { var element = layer.elements[j]; element.x -= layer.speed * baseSpeed; // If element is completely off-screen to the left, move it to the right if (element.x + layer.width < 0) { element.x += layer.width * layer.elements.length; } } } }; return self; }); var Pipe = Container.expand(function () { var self = Container.call(this); var topPipe = self.attachAsset('pipeTop', { anchorX: 0.5, anchorY: 1.0 }); var bottomPipe = self.attachAsset('pipeBottom', { anchorX: 0.5, anchorY: 0 }); self.gapHeight = 400; self.gapPosition = 0; self.speed = 5; self.scored = false; self.setGapPosition = function (position) { self.gapPosition = position; // Position pipes to create gap topPipe.y = position - self.gapHeight / 2; bottomPipe.y = position + self.gapHeight / 2; }; self.update = function () { self.x -= self.speed; }; return self; }); var Settings = Container.expand(function () { var self = Container.call(this); // Create settings background var settingsBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); self.addChild(settingsBg); // Create title var titleText = new Text2('Settings', { size: 150, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; self.addChild(titleText); // Music toggle var musicText = new Text2('Music: ON', { size: 100, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); musicText.anchor.set(0.5, 0.5); musicText.x = 2048 / 2; musicText.y = 1000; self.addChild(musicText); // Sound toggle var soundText = new Text2('Sound: ON', { size: 100, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); soundText.anchor.set(0.5, 0.5); soundText.x = 2048 / 2; soundText.y = 1200; self.addChild(soundText); // Back button var backButton = new Text2('Back', { size: 100, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); backButton.anchor.set(0.5, 0.5); backButton.x = 2048 / 2; backButton.y = 1400; self.addChild(backButton); // State variables self.musicEnabled = true; self.soundEnabled = true; // Event handlers musicText.down = function () { self.musicEnabled = !self.musicEnabled; musicText.setText('Music: ' + (self.musicEnabled ? 'ON' : 'OFF')); if (self.onMusicToggle) { self.onMusicToggle(self.musicEnabled); } }; soundText.down = function () { self.soundEnabled = !self.soundEnabled; soundText.setText('Sound: ' + (self.soundEnabled ? 'ON' : 'OFF')); if (self.onSoundToggle) { self.onSoundToggle(self.soundEnabled); } }; backButton.down = function () { if (self.onBack) { self.onBack(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var bird; var pipes = []; var ground; var background; var parallaxBg; // 3D parallax background var isGameStarted = false; var pipeSpawnTimer = 0; var pipeSpawnInterval = 120; // frames (2 seconds at 60fps) var lastPipeX = 0; var gameover = false; // Menu management var mainMenu; var settingsMenu; var highScoresMenu; var gameState = 'MENU'; // MENU, SETTINGS, HIGHSCORES, GAME var musicEnabled = true; var soundEnabled = true; // GUI var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create tap to start text (but don't add it yet) var startTxt = new Text2('Tap to Start', { size: 80, fill: 0xFFFFFF }); startTxt.anchor.set(0.5, 0.5); // Create 3D parallax background parallaxBg = new Parallax(); game.addChild(parallaxBg); // Add parallax layers with different depths (higher number = further away) background = parallaxBg.addLayer('background', 8, 0); // Background sky (moves very slowly) parallaxBg.addLayer('farClouds', 6, 300).elements.forEach(function (cloud) { cloud.x = 1024; }); // Position far clouds in center parallaxBg.addLayer('midClouds', 4, 400); // Mid-distance clouds (moves at medium speed) parallaxBg.addLayer('nearClouds', 2, 700); // Close clouds (moves faster) // Tint the clouds with different colors to create depth for (var i = 0; i < parallaxBg.layers.length; i++) { // Skip the background layer if (i > 0) { // Add different tints for each cloud layer var layerElements = parallaxBg.layers[i].elements; for (var j = 0; j < layerElements.length; j++) { // Farther clouds are more blue/white, closer clouds more warm/gray if (i === 1) { layerElements[j].tint = 0xDDEEFF; } // Far clouds - light blue else if (i === 2) { layerElements[j].tint = 0xEAEAEA; } // Mid clouds - light gray else { layerElements[j].tint = 0xFFFFFF; } // Near clouds - white // Add alpha variation for depth perception with increased opacity layerElements[j].alpha = 0.8 + i * 0.1; } } } // Create ground ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: 2732 - 100 }); game.addChild(ground); // Create bird bird = new Bird(); bird.x = 400; bird.y = 2732 / 2; game.addChild(bird); // Create menus mainMenu = new Menu(); mainMenu.onPlay = function () { showGame(); }; mainMenu.onSettings = function () { showSettings(); }; mainMenu.onHighScores = function () { showHighScores(); }; game.addChild(mainMenu); settingsMenu = new Settings(); settingsMenu.onBack = function () { showMainMenu(); }; settingsMenu.onMusicToggle = function (enabled) { musicEnabled = enabled; if (enabled) { LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); } else { LK.stopMusic(); } }; settingsMenu.onSoundToggle = function (enabled) { soundEnabled = enabled; }; settingsMenu.visible = false; game.addChild(settingsMenu); highScoresMenu = new HighScores(); highScoresMenu.onBack = function () { showMainMenu(); }; highScoresMenu.visible = false; game.addChild(highScoresMenu); // Start music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); // Game functions function spawnPipe() { var pipe = new Pipe(); pipe.x = 2048 + 150; // Start just off-screen // Random gap position between 500 and 2732-500 (avoiding too close to top/bottom) var minY = 500; var maxY = 2732 - 500; var gapY = minY + Math.random() * (maxY - minY); pipe.setGapPosition(gapY); pipes.push(pipe); game.addChild(pipe); // Place pipe behind bird but in front of background game.setChildIndex(pipe, 1); lastPipeX = pipe.x; } function startGame() { if (!isGameStarted) { isGameStarted = true; gameover = false; LK.setScore(0); scoreTxt.setText(0); // Start music if enabled if (musicEnabled) { LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); } // Remove start text if (startTxt.parent) { startTxt.parent.removeChild(startTxt); } // Initial bird flap with sound based on settings if (soundEnabled) { bird.flap(); } else { // Just apply velocity without sound bird.velocity = bird.flapStrength; tween(bird, { rotation: -0.5 }, { duration: 100, easing: tween.linear }); } } } function checkCollisions() { // Check if bird hits ground if (bird.y + 40 > ground.y) { bird.y = ground.y - 40; // Prevent bird from going through ground gameOver(); return true; } // Check if bird hits ceiling if (bird.y - 40 < 0) { bird.y = 40; // Prevent bird from going through ceiling bird.velocity = 0; } // Check collision with pipes for (var i = 0; i < pipes.length; i++) { var pipe = pipes[i]; // Get pipe children (top and bottom pipes) var topPipe = pipe.children[0]; var bottomPipe = pipe.children[1]; // Calculate collision areas var birdLeft = bird.x - 40; var birdRight = bird.x + 40; var birdTop = bird.y - 40; var birdBottom = bird.y + 40; var pipeLeft = pipe.x - 75; var pipeRight = pipe.x + 75; var topPipeBottom = pipe.gapPosition - pipe.gapHeight / 2; var bottomPipeTop = pipe.gapPosition + pipe.gapHeight / 2; // Check for collision if (birdRight > pipeLeft && birdLeft < pipeRight) { if (birdTop < topPipeBottom || birdBottom > bottomPipeTop) { gameOver(); return true; } } // Check for score if (!pipe.scored && birdLeft > pipe.x) { pipe.scored = true; LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('score').play(); // Show "Great!" message when player passes 10 levels if (LK.getScore() === 10) { var greatText = new Text2("Great!", { size: 150, fill: 0xFFFFFF, shadow: { color: 0x000000, blur: 10, offsetX: 3, offsetY: 3 } }); greatText.anchor.set(0.5, 0.5); LK.gui.center.addChild(greatText); // Remove the text after 2 seconds LK.setTimeout(function () { if (greatText.parent) { greatText.parent.removeChild(greatText); } }, 2000); } } } return false; } function gameOver() { if (!gameover) { gameover = true; bird.die(); // Flash screen and show game over LK.effects.flashScreen(0xFF0000, 500); // Update high score if current score is higher var currentScore = LK.getScore(); var highScore = storage.highScore || 0; if (currentScore > highScore) { storage.highScore = currentScore; } // Wait a moment before showing game over LK.setTimeout(function () { LK.showGameOver(); // After game over, show the main menu again LK.setTimeout(function () { showMainMenu(); }, 500); }, 1000); } } function showMainMenu() { gameState = 'MENU'; mainMenu.visible = true; settingsMenu.visible = false; highScoresMenu.visible = false; bird.visible = false; // Hide the game elements for (var i = 0; i < pipes.length; i++) { pipes[i].visible = false; } // Remove start text if visible if (startTxt.parent) { startTxt.parent.removeChild(startTxt); } } function showHighScores() { gameState = 'HIGHSCORES'; mainMenu.visible = false; settingsMenu.visible = false; highScoresMenu.visible = true; bird.visible = false; highScoresMenu.updateHighScore(); } function showSettings() { gameState = 'SETTINGS'; mainMenu.visible = false; settingsMenu.visible = true; highScoresMenu.visible = false; bird.visible = false; } function showGame() { gameState = 'GAME'; mainMenu.visible = false; settingsMenu.visible = false; bird.visible = true; // Show all game elements for (var i = 0; i < pipes.length; i++) { pipes[i].visible = true; } resetGame(); // Add the start text LK.gui.center.addChild(startTxt); } function resetGame() { // Remove all pipes for (var i = pipes.length - 1; i >= 0; i--) { game.removeChild(pipes[i]); pipes[i].destroy(); } pipes = []; // Reset bird bird.velocity = 0; bird.rotation = 0; bird.y = 2732 / 2; bird.isDead = false; // Reset game state isGameStarted = false; gameover = false; pipeSpawnTimer = 0; LK.setScore(0); scoreTxt.setText("0"); // Show start text LK.gui.center.addChild(startTxt); } // Input handlers game.down = function (x, y, obj) { if (gameState === 'MENU' || gameState === 'SETTINGS' || gameState === 'HIGHSCORES') { // Menu input is handled by menu button objects return; } if (!isGameStarted) { startGame(); } else if (!gameover) { if (soundEnabled) { bird.flap(); } else { // Just update velocity without sound bird.velocity = bird.flapStrength; // Rotate bird up when flapping tween(bird, { rotation: -0.5 }, { duration: 100, easing: tween.linear }); } } }; // Lion asset removed as requested // Game update loop game.update = function () { // If in menu or settings, don't update game logic if (gameState === 'MENU' || gameState === 'SETTINGS' || gameState === 'HIGHSCORES') { // Slowly move parallax layers even in menu for ambient effect parallaxBg.update(0.2); return; } if (!isGameStarted) { // Bird gently floats up and down before game starts bird.y = 2732 / 2 + Math.sin(LK.ticks / 30) * 20; // Slowly move parallax layers before game starts parallaxBg.update(0.3); return; } if (!gameover) { // Update bird bird.update(); // Update parallax background - speed based on game state parallaxBg.update(5); // Apply subtle vertical parallax based on bird position var verticalOffset = (bird.y - 2732 / 2) * 0.05; for (var l = 0; l < parallaxBg.layers.length; l++) { var depthFactor = (parallaxBg.layers.length - l) / parallaxBg.layers.length; var layerElements = parallaxBg.layers[l].elements; for (var e = 0; e < layerElements.length; e++) { // Only adjust y for cloud layers (skip the background) if (l > 0) { // Original y position plus vertical offset based on bird's position var originalY = l === 1 ? 100 : l === 2 ? 400 : 700; layerElements[e].y = originalY + verticalOffset * depthFactor; } } } // Spawn pipes pipeSpawnTimer++; if (pipeSpawnTimer >= pipeSpawnInterval) { spawnPipe(); pipeSpawnTimer = 0; } // Update and clean up pipes for (var i = pipes.length - 1; i >= 0; i--) { pipes[i].update(); // Remove pipes that are off-screen if (pipes[i].x < -200) { game.removeChild(pipes[i]); pipes[i].destroy(); pipes.splice(i, 1); } } // Check collisions checkCollisions(); } };
/****
* 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.flapStrength = -12;
self.isDead = false;
self.flap = function () {
if (!self.isDead) {
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Rotate bird up when flapping
var tweenPromise = tween(self, {
rotation: -0.5,
scaleX: 1.1,
// Slightly squash & stretch for dynamic effect
scaleY: 0.9
}, {
duration: 100,
easing: tween.linear
});
if (tweenPromise && typeof tweenPromise.then === 'function') {
tweenPromise.then(function () {
// Return to normal scale after flap
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOutQuad
});
});
}
}
};
self.update = function () {
if (self.isDead) {
return;
}
// Apply gravity and update position
self.velocity += self.gravity;
self.y += self.velocity;
// Rotate bird based on velocity
if (self.velocity > 0) {
var targetRotation = Math.min(self.velocity * 0.05, 1.2);
tween(self, {
rotation: targetRotation
}, {
duration: 100,
easing: tween.linear
});
}
};
self.die = function () {
if (!self.isDead) {
self.isDead = true;
LK.getSound('hit').play();
}
};
return self;
});
var HighScores = Container.expand(function () {
var self = Container.call(this);
// Create high scores background
var highScoresBg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
self.addChild(highScoresBg);
// Create title
var titleText = new Text2('High Scores', {
size: 150,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// High score display
var highScoreText = new Text2('High Score: 0', {
size: 120,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 2048 / 2;
highScoreText.y = 1000;
self.addChild(highScoreText);
// Back button
var backButton = new Text2('Back', {
size: 100,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 2048 / 2;
backButton.y = 1400;
self.addChild(backButton);
// Event handlers
self.updateHighScore = function () {
var highScore = storage.highScore || 0;
highScoreText.setText('High Score: ' + highScore);
};
backButton.down = function () {
if (self.onBack) {
self.onBack();
}
};
return self;
});
var Menu = Container.expand(function () {
var self = Container.call(this);
// Create menu background
var menuBg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
self.addChild(menuBg);
// Create title
var titleText = new Text2('Flying Bird', {
size: 150,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// Create play button
var playButton = new Text2('Play', {
size: 100,
fill: 0xFFFFFF
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 2048 / 2;
playButton.y = 1000;
self.addChild(playButton);
// Create settings button
var settingsButton = new Text2('Settings', {
size: 100,
fill: 0xFFFFFF
});
settingsButton.anchor.set(0.5, 0.5);
settingsButton.x = 2048 / 2;
settingsButton.y = 1150;
self.addChild(settingsButton);
// Create high scores button
var highScoresButton = new Text2('High Scores', {
size: 100,
fill: 0xFFFFFF
});
highScoresButton.anchor.set(0.5, 0.5);
highScoresButton.x = 2048 / 2;
highScoresButton.y = 1300;
self.addChild(highScoresButton);
// Event handlers
playButton.down = function () {
if (self.onPlay) {
self.onPlay();
}
};
highScoresButton.down = function () {
if (self.onHighScores) {
self.onHighScores();
}
};
settingsButton.down = function () {
if (self.onSettings) {
self.onSettings();
}
};
return self;
});
var Parallax = Container.expand(function () {
var self = Container.call(this);
// Layer properties
self.layers = [];
self.layerCount = 0;
// Add a layer to the parallax effect
self.addLayer = function (asset, depth, y) {
var layer1 = self.addChild(LK.getAsset(asset, {
anchorX: 0,
anchorY: 0,
x: 0,
y: y || 0
}));
// Create duplicate for infinite scrolling
var layer2 = self.addChild(LK.getAsset(asset, {
anchorX: 0,
anchorY: 0,
x: layer1.width,
y: y || 0
}));
// Store layer info including duplicates for scrolling
self.layers.push({
elements: [layer1, layer2],
speed: 0.5 / depth,
// Speed based on depth (farther = slower)
width: layer1.width
});
self.layerCount++;
return self.layers[self.layerCount - 1];
};
// Update parallax layers based on game speed
self.update = function (baseSpeed) {
baseSpeed = baseSpeed || 1;
for (var i = 0; i < self.layers.length; i++) {
var layer = self.layers[i];
// Move both elements of the layer
for (var j = 0; j < layer.elements.length; j++) {
var element = layer.elements[j];
element.x -= layer.speed * baseSpeed;
// If element is completely off-screen to the left, move it to the right
if (element.x + layer.width < 0) {
element.x += layer.width * layer.elements.length;
}
}
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
var topPipe = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 1.0
});
var bottomPipe = self.attachAsset('pipeBottom', {
anchorX: 0.5,
anchorY: 0
});
self.gapHeight = 400;
self.gapPosition = 0;
self.speed = 5;
self.scored = false;
self.setGapPosition = function (position) {
self.gapPosition = position;
// Position pipes to create gap
topPipe.y = position - self.gapHeight / 2;
bottomPipe.y = position + self.gapHeight / 2;
};
self.update = function () {
self.x -= self.speed;
};
return self;
});
var Settings = Container.expand(function () {
var self = Container.call(this);
// Create settings background
var settingsBg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
self.addChild(settingsBg);
// Create title
var titleText = new Text2('Settings', {
size: 150,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// Music toggle
var musicText = new Text2('Music: ON', {
size: 100,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
musicText.anchor.set(0.5, 0.5);
musicText.x = 2048 / 2;
musicText.y = 1000;
self.addChild(musicText);
// Sound toggle
var soundText = new Text2('Sound: ON', {
size: 100,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
soundText.anchor.set(0.5, 0.5);
soundText.x = 2048 / 2;
soundText.y = 1200;
self.addChild(soundText);
// Back button
var backButton = new Text2('Back', {
size: 100,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 2048 / 2;
backButton.y = 1400;
self.addChild(backButton);
// State variables
self.musicEnabled = true;
self.soundEnabled = true;
// Event handlers
musicText.down = function () {
self.musicEnabled = !self.musicEnabled;
musicText.setText('Music: ' + (self.musicEnabled ? 'ON' : 'OFF'));
if (self.onMusicToggle) {
self.onMusicToggle(self.musicEnabled);
}
};
soundText.down = function () {
self.soundEnabled = !self.soundEnabled;
soundText.setText('Sound: ' + (self.soundEnabled ? 'ON' : 'OFF'));
if (self.onSoundToggle) {
self.onSoundToggle(self.soundEnabled);
}
};
backButton.down = function () {
if (self.onBack) {
self.onBack();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var bird;
var pipes = [];
var ground;
var background;
var parallaxBg; // 3D parallax background
var isGameStarted = false;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 120; // frames (2 seconds at 60fps)
var lastPipeX = 0;
var gameover = false;
// Menu management
var mainMenu;
var settingsMenu;
var highScoresMenu;
var gameState = 'MENU'; // MENU, SETTINGS, HIGHSCORES, GAME
var musicEnabled = true;
var soundEnabled = true;
// GUI
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create tap to start text (but don't add it yet)
var startTxt = new Text2('Tap to Start', {
size: 80,
fill: 0xFFFFFF
});
startTxt.anchor.set(0.5, 0.5);
// Create 3D parallax background
parallaxBg = new Parallax();
game.addChild(parallaxBg);
// Add parallax layers with different depths (higher number = further away)
background = parallaxBg.addLayer('background', 8, 0); // Background sky (moves very slowly)
parallaxBg.addLayer('farClouds', 6, 300).elements.forEach(function (cloud) {
cloud.x = 1024;
}); // Position far clouds in center
parallaxBg.addLayer('midClouds', 4, 400); // Mid-distance clouds (moves at medium speed)
parallaxBg.addLayer('nearClouds', 2, 700); // Close clouds (moves faster)
// Tint the clouds with different colors to create depth
for (var i = 0; i < parallaxBg.layers.length; i++) {
// Skip the background layer
if (i > 0) {
// Add different tints for each cloud layer
var layerElements = parallaxBg.layers[i].elements;
for (var j = 0; j < layerElements.length; j++) {
// Farther clouds are more blue/white, closer clouds more warm/gray
if (i === 1) {
layerElements[j].tint = 0xDDEEFF;
} // Far clouds - light blue
else if (i === 2) {
layerElements[j].tint = 0xEAEAEA;
} // Mid clouds - light gray
else {
layerElements[j].tint = 0xFFFFFF;
} // Near clouds - white
// Add alpha variation for depth perception with increased opacity
layerElements[j].alpha = 0.8 + i * 0.1;
}
}
}
// Create ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100
});
game.addChild(ground);
// Create bird
bird = new Bird();
bird.x = 400;
bird.y = 2732 / 2;
game.addChild(bird);
// Create menus
mainMenu = new Menu();
mainMenu.onPlay = function () {
showGame();
};
mainMenu.onSettings = function () {
showSettings();
};
mainMenu.onHighScores = function () {
showHighScores();
};
game.addChild(mainMenu);
settingsMenu = new Settings();
settingsMenu.onBack = function () {
showMainMenu();
};
settingsMenu.onMusicToggle = function (enabled) {
musicEnabled = enabled;
if (enabled) {
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
} else {
LK.stopMusic();
}
};
settingsMenu.onSoundToggle = function (enabled) {
soundEnabled = enabled;
};
settingsMenu.visible = false;
game.addChild(settingsMenu);
highScoresMenu = new HighScores();
highScoresMenu.onBack = function () {
showMainMenu();
};
highScoresMenu.visible = false;
game.addChild(highScoresMenu);
// Start music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Game functions
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 150; // Start just off-screen
// Random gap position between 500 and 2732-500 (avoiding too close to top/bottom)
var minY = 500;
var maxY = 2732 - 500;
var gapY = minY + Math.random() * (maxY - minY);
pipe.setGapPosition(gapY);
pipes.push(pipe);
game.addChild(pipe);
// Place pipe behind bird but in front of background
game.setChildIndex(pipe, 1);
lastPipeX = pipe.x;
}
function startGame() {
if (!isGameStarted) {
isGameStarted = true;
gameover = false;
LK.setScore(0);
scoreTxt.setText(0);
// Start music if enabled
if (musicEnabled) {
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
}
// Remove start text
if (startTxt.parent) {
startTxt.parent.removeChild(startTxt);
}
// Initial bird flap with sound based on settings
if (soundEnabled) {
bird.flap();
} else {
// Just apply velocity without sound
bird.velocity = bird.flapStrength;
tween(bird, {
rotation: -0.5
}, {
duration: 100,
easing: tween.linear
});
}
}
}
function checkCollisions() {
// Check if bird hits ground
if (bird.y + 40 > ground.y) {
bird.y = ground.y - 40; // Prevent bird from going through ground
gameOver();
return true;
}
// Check if bird hits ceiling
if (bird.y - 40 < 0) {
bird.y = 40; // Prevent bird from going through ceiling
bird.velocity = 0;
}
// Check collision with pipes
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
// Get pipe children (top and bottom pipes)
var topPipe = pipe.children[0];
var bottomPipe = pipe.children[1];
// Calculate collision areas
var birdLeft = bird.x - 40;
var birdRight = bird.x + 40;
var birdTop = bird.y - 40;
var birdBottom = bird.y + 40;
var pipeLeft = pipe.x - 75;
var pipeRight = pipe.x + 75;
var topPipeBottom = pipe.gapPosition - pipe.gapHeight / 2;
var bottomPipeTop = pipe.gapPosition + pipe.gapHeight / 2;
// Check for collision
if (birdRight > pipeLeft && birdLeft < pipeRight) {
if (birdTop < topPipeBottom || birdBottom > bottomPipeTop) {
gameOver();
return true;
}
}
// Check for score
if (!pipe.scored && birdLeft > pipe.x) {
pipe.scored = true;
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
// Show "Great!" message when player passes 10 levels
if (LK.getScore() === 10) {
var greatText = new Text2("Great!", {
size: 150,
fill: 0xFFFFFF,
shadow: {
color: 0x000000,
blur: 10,
offsetX: 3,
offsetY: 3
}
});
greatText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(greatText);
// Remove the text after 2 seconds
LK.setTimeout(function () {
if (greatText.parent) {
greatText.parent.removeChild(greatText);
}
}, 2000);
}
}
}
return false;
}
function gameOver() {
if (!gameover) {
gameover = true;
bird.die();
// Flash screen and show game over
LK.effects.flashScreen(0xFF0000, 500);
// Update high score if current score is higher
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
// Wait a moment before showing game over
LK.setTimeout(function () {
LK.showGameOver();
// After game over, show the main menu again
LK.setTimeout(function () {
showMainMenu();
}, 500);
}, 1000);
}
}
function showMainMenu() {
gameState = 'MENU';
mainMenu.visible = true;
settingsMenu.visible = false;
highScoresMenu.visible = false;
bird.visible = false;
// Hide the game elements
for (var i = 0; i < pipes.length; i++) {
pipes[i].visible = false;
}
// Remove start text if visible
if (startTxt.parent) {
startTxt.parent.removeChild(startTxt);
}
}
function showHighScores() {
gameState = 'HIGHSCORES';
mainMenu.visible = false;
settingsMenu.visible = false;
highScoresMenu.visible = true;
bird.visible = false;
highScoresMenu.updateHighScore();
}
function showSettings() {
gameState = 'SETTINGS';
mainMenu.visible = false;
settingsMenu.visible = true;
highScoresMenu.visible = false;
bird.visible = false;
}
function showGame() {
gameState = 'GAME';
mainMenu.visible = false;
settingsMenu.visible = false;
bird.visible = true;
// Show all game elements
for (var i = 0; i < pipes.length; i++) {
pipes[i].visible = true;
}
resetGame();
// Add the start text
LK.gui.center.addChild(startTxt);
}
function resetGame() {
// Remove all pipes
for (var i = pipes.length - 1; i >= 0; i--) {
game.removeChild(pipes[i]);
pipes[i].destroy();
}
pipes = [];
// Reset bird
bird.velocity = 0;
bird.rotation = 0;
bird.y = 2732 / 2;
bird.isDead = false;
// Reset game state
isGameStarted = false;
gameover = false;
pipeSpawnTimer = 0;
LK.setScore(0);
scoreTxt.setText("0");
// Show start text
LK.gui.center.addChild(startTxt);
}
// Input handlers
game.down = function (x, y, obj) {
if (gameState === 'MENU' || gameState === 'SETTINGS' || gameState === 'HIGHSCORES') {
// Menu input is handled by menu button objects
return;
}
if (!isGameStarted) {
startGame();
} else if (!gameover) {
if (soundEnabled) {
bird.flap();
} else {
// Just update velocity without sound
bird.velocity = bird.flapStrength;
// Rotate bird up when flapping
tween(bird, {
rotation: -0.5
}, {
duration: 100,
easing: tween.linear
});
}
}
};
// Lion asset removed as requested
// Game update loop
game.update = function () {
// If in menu or settings, don't update game logic
if (gameState === 'MENU' || gameState === 'SETTINGS' || gameState === 'HIGHSCORES') {
// Slowly move parallax layers even in menu for ambient effect
parallaxBg.update(0.2);
return;
}
if (!isGameStarted) {
// Bird gently floats up and down before game starts
bird.y = 2732 / 2 + Math.sin(LK.ticks / 30) * 20;
// Slowly move parallax layers before game starts
parallaxBg.update(0.3);
return;
}
if (!gameover) {
// Update bird
bird.update();
// Update parallax background - speed based on game state
parallaxBg.update(5);
// Apply subtle vertical parallax based on bird position
var verticalOffset = (bird.y - 2732 / 2) * 0.05;
for (var l = 0; l < parallaxBg.layers.length; l++) {
var depthFactor = (parallaxBg.layers.length - l) / parallaxBg.layers.length;
var layerElements = parallaxBg.layers[l].elements;
for (var e = 0; e < layerElements.length; e++) {
// Only adjust y for cloud layers (skip the background)
if (l > 0) {
// Original y position plus vertical offset based on bird's position
var originalY = l === 1 ? 100 : l === 2 ? 400 : 700;
layerElements[e].y = originalY + verticalOffset * depthFactor;
}
}
}
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Update and clean up pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].update();
// Remove pipes that are off-screen
if (pipes[i].x < -200) {
game.removeChild(pipes[i]);
pipes[i].destroy();
pipes.splice(i, 1);
}
}
// Check collisions
checkCollisions();
}
};
Orman vektör tarzda. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Orman vektör gökyüzü gölgeli hafif siyah Arka plan. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Ağaç kütüğü vektör tarzda dik bir adet koyu kahverengi. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Sarı muhabbet kuşu sevimli küçük vektör ve piksel sanatı. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Bulut piksel sanatı. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows