/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bird = Container.expand(function (characterType) {
var self = Container.call(this);
// Create bird graphics based on character type
var assetName = characterType || 'bird';
var birdGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.velocity = 0;
self.gravity = 0.8;
self.flapPower = -12;
self.maxVelocity = 15;
// Tracking properties
self.lastY = 0;
self.update = function () {
// Store last position
self.lastY = self.y;
// Only apply physics if game has started and not paused
if (gameStarted && !gamePaused) {
// Apply gravity
self.velocity += self.gravity;
// Limit velocity
if (self.velocity > self.maxVelocity) {
self.velocity = self.maxVelocity;
}
// Update position
self.y += self.velocity;
// Rotate bird based on velocity
birdGraphics.rotation = Math.min(Math.max(self.velocity * 0.05, -0.5), 1.2);
}
};
self.flap = function () {
self.velocity = self.flapPower;
LK.getSound('flap').play();
// Add smooth rotation animation when flapping
tween(birdGraphics, {
rotation: -0.3
}, {
duration: 150,
onFinish: function onFinish() {
// Bird naturally rotates back down due to velocity in update
}
});
// Add scale animation for visual feedback
tween(birdGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(birdGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
// Create ground graphics
var groundGraphics = self.attachAsset('ground', {
anchorX: 0,
anchorY: 0
});
// Movement properties
self.speed = -4;
self.update = function () {
// Only move ground if game is not paused
if (!gamePaused) {
// Move ground left
self.x += self.speed;
// Reset position when off screen for infinite scrolling
if (self.x <= -2048) {
self.x = 2048;
}
}
};
return self;
});
var ParticleSystem = Container.expand(function (config) {
var self = Container.call(this);
self.particles = [];
self.maxParticles = config.maxParticles || 50;
self.particleConfig = config;
self.emit = function (x, y, count) {
count = count || 10;
for (var i = 0; i < count && self.particles.length < self.maxParticles; i++) {
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1 + Math.random() * 0.2,
scaleY: 0.1 + Math.random() * 0.2
});
particle.x = x + (Math.random() - 0.5) * 100;
particle.y = y + (Math.random() - 0.5) * 100;
particle.tint = self.particleConfig.color || 0xFFFFFF;
particle.alpha = 0.8;
particle.vx = (Math.random() - 0.5) * 10;
particle.vy = (Math.random() - 0.5) * 10 - 5;
particle.life = 1.0;
particle.decay = 0.02;
self.particles.push(particle);
self.addChild(particle);
}
};
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
particle.x += particle.vx;
particle.y += particle.vy;
particle.vy += 0.3; // gravity
particle.life -= particle.decay;
particle.alpha = particle.life;
if (particle.life <= 0) {
self.removeChild(particle);
self.particles.splice(i, 1);
}
}
};
return self;
});
// Game variables
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Create top and bottom pipe parts
var topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0
});
// Movement properties
self.speed = -4;
self.gapSize = 300;
self.passed = false;
// Tracking properties
self.lastX = 0;
self.setGapPosition = function (centerY) {
// Position top pipe (anchor at bottom, so y is bottom edge)
topPipe.y = centerY - self.gapSize / 2;
// Position bottom pipe (anchor at top, so y is top edge)
bottomPipe.y = centerY + self.gapSize / 2;
};
self.update = function () {
// Store last position
self.lastX = self.x;
// Only move pipe if game is not paused
if (!gamePaused) {
// Move pipe left
self.x += self.speed;
}
};
self.getTopBounds = function () {
return {
x: self.x - 100,
y: 0,
width: 200,
height: topPipe.y
};
};
self.getBottomBounds = function () {
return {
x: self.x - 100,
y: bottomPipe.y,
width: 200,
height: 2732 - bottomPipe.y
};
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'coin';
self.collected = false;
var powerUpGraphics = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Different colors for different power-ups
if (self.type === 'coin') {
powerUpGraphics.tint = 0xFFD700;
} else if (self.type === 'shield') {
powerUpGraphics.tint = 0x00FFFF;
}
self.speed = -4;
self.floatOffset = 0;
self.update = function () {
if (!gamePaused) {
self.x += self.speed;
// Floating animation
self.floatOffset += 0.1;
powerUpGraphics.y = Math.sin(self.floatOffset) * 20;
// Rotation animation
powerUpGraphics.rotation += 0.05;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
// Initialize bird asset - yellow circle for the flappy bird
// Initialize pipe assets - green rectangles for obstacles
// Initialize ground asset - brown rectangle for the ground
// Initialize sound for flap
var bird;
var pipes = [];
var ground1, ground2;
var gameStarted = false;
var gamePaused = false;
var pipeTimer = 0;
var pipeSpacing = 800;
// Modern game features
var comboCount = 0;
var comboTimer = 0;
var maxCombo = 0;
var powerUps = [];
var particleSystem;
var shieldActive = false;
var shieldTimer = 0;
var coins = 0;
var difficulty = 1;
var difficultyTimer = 0;
// Game state management
var gameState = 'MAIN_MENU'; // 'MAIN_MENU', 'CHARACTER_SELECT', 'START_SCREEN', 'PLAYING'
var selectedCharacter = 'bird';
var characterTypes = ['bird', 'bird2', 'bird3', 'bird4'];
var characterNames = ['Classic', 'Red', 'Green', 'Blue'];
// Score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Best score display
var bestScore = storage.bestScore || 0;
var bestScoreTxt = new Text2('BEST: ' + bestScore, {
size: 40,
fill: 0xFFD700
});
bestScoreTxt.anchor.set(0.5, 0);
bestScoreTxt.y = 100;
LK.gui.top.addChild(bestScoreTxt);
// Combo display
var comboTxt = new Text2('', {
size: 50,
fill: 0xFF4500
});
comboTxt.anchor.set(0.5, 0.5);
comboTxt.x = 0;
comboTxt.y = 200;
comboTxt.visible = false;
LK.gui.center.addChild(comboTxt);
// Coin counter
var coinTxt = new Text2('💰 0', {
size: 60,
fill: 0xFFD700
});
coinTxt.anchor.set(0, 0);
coinTxt.x = 20;
coinTxt.y = 20;
LK.gui.topLeft.addChild(coinTxt);
// Shield indicator
var shieldTxt = new Text2('🛡️', {
size: 80,
fill: 0x00FFFF
});
shieldTxt.anchor.set(1, 0);
shieldTxt.x = -120;
shieldTxt.y = 20;
shieldTxt.visible = false;
LK.gui.topRight.addChild(shieldTxt);
// Difficulty indicator
var difficultyTxt = new Text2('LEVEL 1', {
size: 35,
fill: 0xFFFFFF
});
difficultyTxt.anchor.set(0.5, 0);
difficultyTxt.y = 160;
LK.gui.top.addChild(difficultyTxt);
// Pause button
var pauseBtn = new Text2('| |', {
size: 60,
fill: 0xFFFFFF
});
pauseBtn.anchor.set(1, 0);
pauseBtn.x = -20; // Position from right edge
pauseBtn.y = 20;
LK.gui.topRight.addChild(pauseBtn);
// Pause overlay
var pauseOverlay = new Container();
var pauseBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.7,
scaleX: 20,
scaleY: 27
});
pauseOverlay.addChild(pauseBackground);
var pauseText = new Text2('PAUSED', {
size: 120,
fill: 0xFFFFFF
});
pauseText.anchor.set(0.5, 0.5);
pauseText.x = 1024;
pauseText.y = 1200;
pauseOverlay.addChild(pauseText);
var resumeText = new Text2('TAP TO RESUME', {
size: 60,
fill: 0xFFFFFF
});
resumeText.anchor.set(0.5, 0.5);
resumeText.x = 1024;
resumeText.y = 1400;
pauseOverlay.addChild(resumeText);
pauseOverlay.visible = false;
game.addChild(pauseOverlay);
// Main Menu Screen - Welcome Screen
var mainMenuScreen = new Container();
var menuBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.95,
scaleX: 20,
scaleY: 27
});
mainMenuScreen.addChild(menuBackground);
var welcomeTitle = new Text2('FLAPPY ANIMAL', {
size: 140,
fill: 0xFFD700
});
welcomeTitle.anchor.set(0.5, 0.5);
welcomeTitle.x = 1024;
welcomeTitle.y = 700;
mainMenuScreen.addChild(welcomeTitle);
var subtitleText = new Text2('CLASSIC ARCADE GAME', {
size: 60,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 850;
mainMenuScreen.addChild(subtitleText);
// Preview bird animation
var previewBird = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
previewBird.x = 1024;
previewBird.y = 1200;
mainMenuScreen.addChild(previewBird);
// Add floating animation to preview bird
var birdFloat = LK.setInterval(function () {
if (previewBird && mainMenuScreen.visible) {
tween(previewBird, {
y: 1150
}, {
duration: 1000,
onFinish: function onFinish() {
tween(previewBird, {
y: 1250
}, {
duration: 1000
});
}
});
}
}, 2000);
var playButton = new Text2('PLAY', {
size: 100,
fill: 0x00ff00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 1024;
playButton.y = 1600;
mainMenuScreen.addChild(playButton);
// Play button background
var playBtnBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 1.3,
alpha: 0.3
});
playBtnBg.x = 1024;
playBtnBg.y = 1600;
mainMenuScreen.addChild(playBtnBg);
// Add pulsing animation to play button
var playBtnPulse = LK.setInterval(function () {
if (playButton && mainMenuScreen.visible) {
tween(playButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 600
});
}
});
}
}, 1200);
var tapToPlayInfo = new Text2('TAP TO BEGIN YOUR ADVENTURE!', {
size: 45,
fill: 0xFFD700
});
tapToPlayInfo.anchor.set(0.5, 0.5);
tapToPlayInfo.x = 1024;
tapToPlayInfo.y = 1750;
mainMenuScreen.addChild(tapToPlayInfo);
// Add blinking animation to tap instruction
var tapInfoBlink = LK.setInterval(function () {
if (tapToPlayInfo && mainMenuScreen.visible) {
tween(tapToPlayInfo, {
alpha: 0.4
}, {
duration: 700,
onFinish: function onFinish() {
tween(tapToPlayInfo, {
alpha: 1
}, {
duration: 700
});
}
});
}
}, 1400);
// Play button click handler
playButton.down = function (x, y, obj) {
// Clear animations
LK.clearInterval(playBtnPulse);
LK.clearInterval(birdFloat);
LK.clearInterval(tapInfoBlink);
// Add click feedback animation
tween(playButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'CHARACTER_SELECT';
// Hide main menu with animation
tween(mainMenuScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
mainMenuScreen.visible = false;
// Show character selection screen
showCharacterSelection();
}
});
};
game.addChild(mainMenuScreen);
// Function to show character selection
function showCharacterSelection() {
characterSelectionScreen.visible = true;
characterSelectionScreen.alpha = 0;
tween(characterSelectionScreen, {
alpha: 1
}, {
duration: 300
});
}
// Character Selection Screen
var characterSelectionScreen = new Container();
var selectionBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.95,
scaleX: 20,
scaleY: 27
});
characterSelectionScreen.addChild(selectionBackground);
var selectionTitle = new Text2('SELECT YOUR ANIMAL', {
size: 100,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 500;
characterSelectionScreen.addChild(selectionTitle);
// Character selection buttons
var characterButtons = [];
for (var i = 0; i < characterTypes.length; i++) {
var buttonContainer = new Container();
// Character preview
var charPreview = LK.getAsset(characterTypes[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
buttonContainer.addChild(charPreview);
// Character name
var charName = new Text2(characterNames[i], {
size: 40,
fill: 0xFFFFFF
});
charName.anchor.set(0.5, 0.5);
charName.y = 100;
buttonContainer.addChild(charName);
// Position buttons in a grid
var col = i % 2;
var row = Math.floor(i / 2);
buttonContainer.x = 724 + col * 600;
buttonContainer.y = 1000 + row * 300;
// Store character type for click handling
buttonContainer.characterType = characterTypes[i];
buttonContainer.characterIndex = i;
// Add selection border (initially hidden)
var selectionBorder = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: 0.3
});
selectionBorder.visible = false;
buttonContainer.addChild(selectionBorder);
buttonContainer.selectionBorder = selectionBorder;
// Click handler for character selection
buttonContainer.down = function (x, y, obj) {
// Remove selection from all buttons
for (var j = 0; j < characterButtons.length; j++) {
characterButtons[j].selectionBorder.visible = false;
}
// Show selection on clicked button
this.selectionBorder.visible = true;
selectedCharacter = this.characterType;
// Add selection feedback animation
tween(this, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(this, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
characterButtons.push(buttonContainer);
characterSelectionScreen.addChild(buttonContainer);
}
// Show selection on first character by default
characterButtons[0].selectionBorder.visible = true;
// Confirm selection button
var confirmBtn = new Text2('CONFIRM', {
size: 70,
fill: 0x00ff00
});
confirmBtn.anchor.set(0.5, 0.5);
confirmBtn.x = 1024;
confirmBtn.y = 2200;
characterSelectionScreen.addChild(confirmBtn);
confirmBtn.down = function (x, y, obj) {
gameState = 'START_SCREEN';
// Hide character selection with animation
tween(characterSelectionScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
characterSelectionScreen.visible = false;
// Show start screen
showStartScreen();
}
});
};
characterSelectionScreen.visible = false;
game.addChild(characterSelectionScreen);
// Start Game Screen
var startGameScreen = new Container();
var startBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9,
scaleX: 20,
scaleY: 27
});
startGameScreen.addChild(startBackground);
var gameTitle = new Text2('FLAPPY ANIMAL', {
size: 120,
fill: 0xFFD700
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 1024;
gameTitle.y = 600;
startGameScreen.addChild(gameTitle);
// Show selected character preview
var selectedCharacterPreview = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
selectedCharacterPreview.x = 1024;
selectedCharacterPreview.y = 1000;
startGameScreen.addChild(selectedCharacterPreview);
var characterLabel = new Text2('Ready!', {
size: 60,
fill: 0xFFFFFF
});
characterLabel.anchor.set(0.5, 0.5);
characterLabel.x = 1024;
characterLabel.y = 1200;
startGameScreen.addChild(characterLabel);
var startBtn = new Text2('START GAME', {
size: 100,
fill: 0x00ff00
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = 1024;
startBtn.y = 1600;
startGameScreen.addChild(startBtn);
// Add pulsing animation to start button
var startBtnPulse = LK.setInterval(function () {
if (startBtn && startGameScreen.visible) {
tween(startBtn, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
onFinish: function onFinish() {
tween(startBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
}
});
}
}, 1000);
var tapToPlayText = new Text2('TAP BUTTON TO BEGIN!', {
size: 45,
fill: 0xFFD700
});
tapToPlayText.anchor.set(0.5, 0.5);
tapToPlayText.x = 1024;
tapToPlayText.y = 1750;
startGameScreen.addChild(tapToPlayText);
// Add blinking animation to tap instruction
var tapTextBlink = LK.setInterval(function () {
if (tapToPlayText && startGameScreen.visible) {
tween(tapToPlayText, {
alpha: 0.4
}, {
duration: 600,
onFinish: function onFinish() {
tween(tapToPlayText, {
alpha: 1
}, {
duration: 600
});
}
});
}
}, 1200);
var backBtn = new Text2('BACK', {
size: 50,
fill: 0xff6600
});
backBtn.anchor.set(0.5, 0.5);
backBtn.x = 1024;
backBtn.y = 1900;
startGameScreen.addChild(backBtn);
// Add start button background for better visibility
var startBtnBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5,
alpha: 0.3
});
startBtnBg.x = 1024;
startBtnBg.y = 1600;
startGameScreen.addChild(startBtnBg);
// Ensure start button is on top of background
startGameScreen.removeChild(startBtn);
startGameScreen.addChild(startBtn);
startBtn.down = function (x, y, obj) {
// Clear all animations
LK.clearInterval(startBtnPulse);
LK.clearInterval(tapTextBlink);
// Add click feedback animation
tween(startBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(startBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'PLAYING';
// Hide start screen with animation
tween(startGameScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
startGameScreen.visible = false;
// Initialize game with selected character
initializeGameWithCharacter();
}
});
};
backBtn.down = function (x, y, obj) {
// Clear animations
LK.clearInterval(startBtnPulse);
LK.clearInterval(tapTextBlink);
// Add click feedback for back button
tween(backBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(backBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'CHARACTER_SELECT';
// Hide start screen and show character selection
tween(startGameScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
startGameScreen.visible = false;
characterSelectionScreen.visible = true;
characterSelectionScreen.alpha = 0;
tween(characterSelectionScreen, {
alpha: 1
}, {
duration: 300
});
}
});
};
startGameScreen.visible = false;
game.addChild(startGameScreen);
// Function to show start screen
function showStartScreen() {
// Update selected character preview
startGameScreen.removeChild(selectedCharacterPreview);
selectedCharacterPreview = LK.getAsset(selectedCharacter, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
selectedCharacterPreview.x = 1024;
selectedCharacterPreview.y = 1000;
startGameScreen.addChild(selectedCharacterPreview);
startGameScreen.visible = true;
startGameScreen.alpha = 0;
tween(startGameScreen, {
alpha: 1
}, {
duration: 300
});
}
// Game start instruction
var instructionTxt = new Text2('TAP TO START', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1000;
game.addChild(instructionTxt);
// Add blinking animation
var instructionBlink = LK.setInterval(function () {
if (instructionTxt && instructionTxt.parent) {
tween(instructionTxt, {
alpha: 0.3
}, {
duration: 500,
onFinish: function onFinish() {
if (instructionTxt && instructionTxt.parent) {
tween(instructionTxt, {
alpha: 1
}, {
duration: 500
});
}
}
});
}
}, 1000);
// Function to initialize game with selected character
function initializeGameWithCharacter() {
// Initialize bird with selected character
bird = game.addChild(new Bird(selectedCharacter));
bird.x = 400;
bird.y = 1366; // Center of screen vertically
bird.lastY = bird.y; // Initialize tracking property
// Initialize particle system
particleSystem = game.addChild(new ParticleSystem({
maxParticles: 100,
color: 0xFFD700
}));
// Reset modern game variables
comboCount = 0;
comboTimer = 0;
maxCombo = 0;
coins = storage.coins || 0;
coinTxt.setText('💰 ' + coins);
difficulty = 1;
difficultyTimer = 0;
shieldActive = false;
shieldTimer = 0;
}
// Don't initialize bird immediately - wait for character selection
var bird;
// Initialize ground
ground1 = game.addChild(new Ground());
ground1.x = 0;
ground1.y = 2400; // Position ground lower for better gameplay
ground2 = game.addChild(new Ground());
ground2.x = 2048;
ground2.y = 2400; // Position ground lower for better gameplay
// Add pause button click handler
pauseBtn.down = function (x, y, obj) {
if (gameStarted && !gamePaused) {
gamePaused = true;
pauseOverlay.visible = true;
// Add fade in animation for pause overlay
pauseOverlay.alpha = 0;
tween(pauseOverlay, {
alpha: 1
}, {
duration: 200
});
}
};
// Add pause overlay click handler for resume
pauseOverlay.down = function (x, y, obj) {
if (gamePaused) {
// Add fade out animation
tween(pauseOverlay, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
pauseOverlay.visible = false;
gamePaused = false;
}
});
}
};
// Tap to flap
game.down = function (x, y, obj) {
// Don't allow interaction during non-playing states (except main menu)
if (gameState !== 'PLAYING' && gameState !== 'MAIN_MENU') {
return;
}
// Handle main menu tap anywhere to start
if (gameState === 'MAIN_MENU') {
// Trigger the same action as play button
playButton.down(x, y, obj);
return;
}
// Don't allow flapping when paused
if (gamePaused) {
return;
}
if (!gameStarted) {
gameStarted = true;
// Hide instruction text with animation
if (instructionTxt) {
LK.clearInterval(instructionBlink);
tween(instructionTxt, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
instructionTxt.destroy();
instructionTxt = null;
}
});
}
}
if (bird) {
bird.flap();
}
};
// Collision detection helper function
function checkCollision(birdBounds, pipeBounds) {
return birdBounds.x < pipeBounds.x + pipeBounds.width && birdBounds.x + birdBounds.width > pipeBounds.x && birdBounds.y < pipeBounds.y + pipeBounds.height && birdBounds.y + birdBounds.height > pipeBounds.y;
}
// Main game update
game.update = function () {
if (gameState !== 'PLAYING' || !gameStarted || gamePaused || !bird) {
return;
}
// Store bird's last Y position
if (bird.lastY === undefined) {
bird.lastY = bird.y;
}
// Update difficulty over time
difficultyTimer++;
if (difficultyTimer >= 1800) {
// Every 30 seconds at 60fps
difficulty++;
difficultyTimer = 0;
difficultyTxt.setText('LEVEL ' + difficulty);
// Increase game speed slightly
pipeSpacing = Math.max(600, pipeSpacing - 20);
// Visual feedback for difficulty increase
tween(difficultyTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(difficultyTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Update shield timer
if (shieldActive) {
shieldTimer--;
if (shieldTimer <= 0) {
shieldActive = false;
shieldTxt.visible = false;
}
}
// Update combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer <= 0) {
comboCount = 0;
comboTxt.visible = false;
}
}
// Spawn pipes
pipeTimer++;
if (pipeTimer >= pipeSpacing / 4) {
// Adjust timing based on speed and difficulty
var newPipe = new Pipe();
newPipe.x = 2200; // Start off-screen right
newPipe.lastX = newPipe.x; // Initialize tracking property
// Random gap position (avoid top and bottom areas)
var gapCenter = 500 + Math.random() * 1200; // Between 500 and 1700 for better gameplay
// Adjust gap size based on difficulty
newPipe.gapSize = Math.max(250, 300 - (difficulty - 1) * 10);
newPipe.setGapPosition(gapCenter);
// Add entrance animation
newPipe.alpha = 0;
tween(newPipe, {
alpha: 1
}, {
duration: 300
});
pipes.push(newPipe);
game.addChild(newPipe);
pipeTimer = 0;
// Spawn power-ups occasionally
if (Math.random() < 0.3) {
// 30% chance
var powerUpType = Math.random() < 0.7 ? 'coin' : 'shield';
var powerUp = new PowerUp(powerUpType);
powerUp.x = 2200;
powerUp.y = gapCenter + (Math.random() - 0.5) * 100;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Update pipes and check collisions/scoring
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Initialize tracking properties
if (pipe.lastX === undefined) {
pipe.lastX = pipe.x;
}
// Check if pipe passed bird for scoring
if (!pipe.passed && pipe.lastX > bird.x && pipe.x <= bird.x) {
pipe.passed = true;
comboCount++;
comboTimer = 180; // 3 seconds at 60fps
maxCombo = Math.max(maxCombo, comboCount);
// Calculate score with combo multiplier
var scoreGain = 1;
if (comboCount >= 3) {
scoreGain = Math.min(comboCount, 10); // Max 10x multiplier
}
LK.setScore(LK.getScore() + scoreGain);
scoreTxt.setText(LK.getScore());
// Show combo text
if (comboCount >= 3) {
comboTxt.setText('COMBO x' + comboCount + '!');
comboTxt.visible = true;
tween(comboTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Particle effect at bird position
particleSystem.emit(bird.x, bird.y, 8);
// Play score sound
LK.getSound('score').play();
// Check and update best score
var currentScore = LK.getScore();
if (currentScore > bestScore) {
bestScore = currentScore;
storage.bestScore = bestScore;
bestScoreTxt.setText('BEST: ' + bestScore);
// Add special animation for new best score
tween(bestScoreTxt, {
scaleX: 1.4,
scaleY: 1.4,
alpha: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
tween(bestScoreTxt, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200
});
}
});
// Flash screen gold for new best score
LK.effects.flashScreen(0xFFD700, 300);
}
// Add score animation
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Flash screen green for successful pass
LK.effects.flashScreen(0x00ff00, 200);
}
// Remove pipes that are off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
continue;
}
// Check collision with pipes
var birdBounds = {
x: bird.x - 70,
y: bird.y - 70,
width: 140,
height: 140
};
var topBounds = pipe.getTopBounds();
var bottomBounds = pipe.getBottomBounds();
if (checkCollision(birdBounds, topBounds) || checkCollision(birdBounds, bottomBounds)) {
// Check if shield is active
if (shieldActive) {
// Shield protects from one hit
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
// Visual feedback for shield use
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
// Reset combo but don't end game
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
// Skip to next iteration, don't end game
continue;
}
// Play hit sound
LK.getSound('hit').play();
// Reset combo on collision
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
// Stop the game immediately
gameStarted = false;
// Add dramatic bird rotation and fall effect
tween(bird, {
rotation: Math.PI * 2,
y: bird.y + 200
}, {
duration: 800
});
// Add bird shake effect before game over
tween(bird, {
x: bird.x - 15
}, {
duration: 75,
onFinish: function onFinish() {
tween(bird, {
x: bird.x + 30
}, {
duration: 75,
onFinish: function onFinish() {
tween(bird, {
x: bird.x - 15
}, {
duration: 75
});
}
});
}
});
// Flash screen red for longer duration
LK.effects.flashScreen(0xff0000, 800);
// Show dramatic "GAME OVER" text before official game over
var gameOverTxt = new Text2('GAME OVER', {
size: 120,
fill: 0xff0000
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.x = 1024;
gameOverTxt.y = 1366;
gameOverTxt.alpha = 0;
game.addChild(gameOverTxt);
// Animate game over text appearance
tween(gameOverTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
// Wait a moment then show official game over
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 800);
}
});
return;
}
// Update last position
pipe.lastX = pipe.x;
}
// Update and check power-ups
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
// Remove off-screen power-ups
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(j, 1);
continue;
}
// Check collision with bird
if (!powerUp.collected) {
var powerUpBounds = {
x: powerUp.x - 40,
y: powerUp.y - 40,
width: 80,
height: 80
};
if (checkCollision(birdBounds, powerUpBounds)) {
powerUp.collected = true;
if (powerUp.type === 'coin') {
coins++;
storage.coins = coins;
coinTxt.setText('💰 ' + coins);
// Coin collection particle effect
particleSystem.emit(powerUp.x, powerUp.y, 15);
tween(coinTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(coinTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
} else if (powerUp.type === 'shield') {
shieldActive = true;
shieldTimer = 600; // 10 seconds at 60fps
shieldTxt.visible = true;
// Shield activation effect
LK.effects.flashScreen(0x00FFFF, 300);
tween(shieldTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(shieldTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Remove collected power-up with animation
tween(powerUp, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 200,
onFinish: function onFinish() {
powerUp.destroy();
powerUps.splice(j, 1);
}
});
}
}
}
// Check collision with ground
if (bird.y >= 2330) {
// Ground collision (ground at 2400, bird radius 70)
if (shieldActive) {
// Shield protects from ground collision too
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
bird.y = 2320; // Move bird up slightly
bird.velocity = -8; // Give upward momentum
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
return; // Don't end game
}
// Play hit sound
LK.getSound('hit').play();
// Save game statistics
storage.maxCombo = Math.max(storage.maxCombo || 0, maxCombo);
storage.totalGames = (storage.totalGames || 0) + 1;
storage.totalCoins = coins;
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
gameStarted = false;
// Make bird bounce slightly on ground impact
tween(bird, {
y: 2320,
rotation: Math.PI / 4
}, {
duration: 200,
onFinish: function onFinish() {
tween(bird, {
y: 2330
}, {
duration: 100
});
}
});
LK.effects.flashScreen(0xff0000, 800);
// Show impact text
var impactTxt = new Text2('CRASHED!', {
size: 100,
fill: 0xff4500
});
impactTxt.anchor.set(0.5, 0.5);
impactTxt.x = 1024;
impactTxt.y = 1200;
impactTxt.alpha = 0;
game.addChild(impactTxt);
tween(impactTxt, {
alpha: 1,
y: 1100
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 600);
}
});
return;
}
// Check collision with ceiling
if (bird.y <= 70) {
if (shieldActive) {
// Shield protects from ceiling collision
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
bird.y = 80; // Move bird down slightly
bird.velocity = 5; // Give downward momentum
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
return; // Don't end game
}
// Play hit sound
LK.getSound('hit').play();
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
gameStarted = false;
// Make bird fall dramatically from ceiling
tween(bird, {
y: 200,
rotation: -Math.PI / 2
}, {
duration: 300
});
LK.effects.flashScreen(0xffffff, 300);
// Show ceiling hit text
var ceilingTxt = new Text2('HIT CEILING!', {
size: 80,
fill: 0xff6600
});
ceilingTxt.anchor.set(0.5, 0.5);
ceilingTxt.x = 1024;
ceilingTxt.y = 400;
ceilingTxt.alpha = 0;
game.addChild(ceilingTxt);
tween(ceilingTxt, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 250,
onFinish: function onFinish() {
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 500);
}
});
return;
}
// Update last position
bird.lastY = bird.y;
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bird = Container.expand(function (characterType) {
var self = Container.call(this);
// Create bird graphics based on character type
var assetName = characterType || 'bird';
var birdGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.velocity = 0;
self.gravity = 0.8;
self.flapPower = -12;
self.maxVelocity = 15;
// Tracking properties
self.lastY = 0;
self.update = function () {
// Store last position
self.lastY = self.y;
// Only apply physics if game has started and not paused
if (gameStarted && !gamePaused) {
// Apply gravity
self.velocity += self.gravity;
// Limit velocity
if (self.velocity > self.maxVelocity) {
self.velocity = self.maxVelocity;
}
// Update position
self.y += self.velocity;
// Rotate bird based on velocity
birdGraphics.rotation = Math.min(Math.max(self.velocity * 0.05, -0.5), 1.2);
}
};
self.flap = function () {
self.velocity = self.flapPower;
LK.getSound('flap').play();
// Add smooth rotation animation when flapping
tween(birdGraphics, {
rotation: -0.3
}, {
duration: 150,
onFinish: function onFinish() {
// Bird naturally rotates back down due to velocity in update
}
});
// Add scale animation for visual feedback
tween(birdGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(birdGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
// Create ground graphics
var groundGraphics = self.attachAsset('ground', {
anchorX: 0,
anchorY: 0
});
// Movement properties
self.speed = -4;
self.update = function () {
// Only move ground if game is not paused
if (!gamePaused) {
// Move ground left
self.x += self.speed;
// Reset position when off screen for infinite scrolling
if (self.x <= -2048) {
self.x = 2048;
}
}
};
return self;
});
var ParticleSystem = Container.expand(function (config) {
var self = Container.call(this);
self.particles = [];
self.maxParticles = config.maxParticles || 50;
self.particleConfig = config;
self.emit = function (x, y, count) {
count = count || 10;
for (var i = 0; i < count && self.particles.length < self.maxParticles; i++) {
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1 + Math.random() * 0.2,
scaleY: 0.1 + Math.random() * 0.2
});
particle.x = x + (Math.random() - 0.5) * 100;
particle.y = y + (Math.random() - 0.5) * 100;
particle.tint = self.particleConfig.color || 0xFFFFFF;
particle.alpha = 0.8;
particle.vx = (Math.random() - 0.5) * 10;
particle.vy = (Math.random() - 0.5) * 10 - 5;
particle.life = 1.0;
particle.decay = 0.02;
self.particles.push(particle);
self.addChild(particle);
}
};
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
particle.x += particle.vx;
particle.y += particle.vy;
particle.vy += 0.3; // gravity
particle.life -= particle.decay;
particle.alpha = particle.life;
if (particle.life <= 0) {
self.removeChild(particle);
self.particles.splice(i, 1);
}
}
};
return self;
});
// Game variables
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Create top and bottom pipe parts
var topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0
});
// Movement properties
self.speed = -4;
self.gapSize = 300;
self.passed = false;
// Tracking properties
self.lastX = 0;
self.setGapPosition = function (centerY) {
// Position top pipe (anchor at bottom, so y is bottom edge)
topPipe.y = centerY - self.gapSize / 2;
// Position bottom pipe (anchor at top, so y is top edge)
bottomPipe.y = centerY + self.gapSize / 2;
};
self.update = function () {
// Store last position
self.lastX = self.x;
// Only move pipe if game is not paused
if (!gamePaused) {
// Move pipe left
self.x += self.speed;
}
};
self.getTopBounds = function () {
return {
x: self.x - 100,
y: 0,
width: 200,
height: topPipe.y
};
};
self.getBottomBounds = function () {
return {
x: self.x - 100,
y: bottomPipe.y,
width: 200,
height: 2732 - bottomPipe.y
};
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'coin';
self.collected = false;
var powerUpGraphics = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Different colors for different power-ups
if (self.type === 'coin') {
powerUpGraphics.tint = 0xFFD700;
} else if (self.type === 'shield') {
powerUpGraphics.tint = 0x00FFFF;
}
self.speed = -4;
self.floatOffset = 0;
self.update = function () {
if (!gamePaused) {
self.x += self.speed;
// Floating animation
self.floatOffset += 0.1;
powerUpGraphics.y = Math.sin(self.floatOffset) * 20;
// Rotation animation
powerUpGraphics.rotation += 0.05;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
// Initialize bird asset - yellow circle for the flappy bird
// Initialize pipe assets - green rectangles for obstacles
// Initialize ground asset - brown rectangle for the ground
// Initialize sound for flap
var bird;
var pipes = [];
var ground1, ground2;
var gameStarted = false;
var gamePaused = false;
var pipeTimer = 0;
var pipeSpacing = 800;
// Modern game features
var comboCount = 0;
var comboTimer = 0;
var maxCombo = 0;
var powerUps = [];
var particleSystem;
var shieldActive = false;
var shieldTimer = 0;
var coins = 0;
var difficulty = 1;
var difficultyTimer = 0;
// Game state management
var gameState = 'MAIN_MENU'; // 'MAIN_MENU', 'CHARACTER_SELECT', 'START_SCREEN', 'PLAYING'
var selectedCharacter = 'bird';
var characterTypes = ['bird', 'bird2', 'bird3', 'bird4'];
var characterNames = ['Classic', 'Red', 'Green', 'Blue'];
// Score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Best score display
var bestScore = storage.bestScore || 0;
var bestScoreTxt = new Text2('BEST: ' + bestScore, {
size: 40,
fill: 0xFFD700
});
bestScoreTxt.anchor.set(0.5, 0);
bestScoreTxt.y = 100;
LK.gui.top.addChild(bestScoreTxt);
// Combo display
var comboTxt = new Text2('', {
size: 50,
fill: 0xFF4500
});
comboTxt.anchor.set(0.5, 0.5);
comboTxt.x = 0;
comboTxt.y = 200;
comboTxt.visible = false;
LK.gui.center.addChild(comboTxt);
// Coin counter
var coinTxt = new Text2('💰 0', {
size: 60,
fill: 0xFFD700
});
coinTxt.anchor.set(0, 0);
coinTxt.x = 20;
coinTxt.y = 20;
LK.gui.topLeft.addChild(coinTxt);
// Shield indicator
var shieldTxt = new Text2('🛡️', {
size: 80,
fill: 0x00FFFF
});
shieldTxt.anchor.set(1, 0);
shieldTxt.x = -120;
shieldTxt.y = 20;
shieldTxt.visible = false;
LK.gui.topRight.addChild(shieldTxt);
// Difficulty indicator
var difficultyTxt = new Text2('LEVEL 1', {
size: 35,
fill: 0xFFFFFF
});
difficultyTxt.anchor.set(0.5, 0);
difficultyTxt.y = 160;
LK.gui.top.addChild(difficultyTxt);
// Pause button
var pauseBtn = new Text2('| |', {
size: 60,
fill: 0xFFFFFF
});
pauseBtn.anchor.set(1, 0);
pauseBtn.x = -20; // Position from right edge
pauseBtn.y = 20;
LK.gui.topRight.addChild(pauseBtn);
// Pause overlay
var pauseOverlay = new Container();
var pauseBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.7,
scaleX: 20,
scaleY: 27
});
pauseOverlay.addChild(pauseBackground);
var pauseText = new Text2('PAUSED', {
size: 120,
fill: 0xFFFFFF
});
pauseText.anchor.set(0.5, 0.5);
pauseText.x = 1024;
pauseText.y = 1200;
pauseOverlay.addChild(pauseText);
var resumeText = new Text2('TAP TO RESUME', {
size: 60,
fill: 0xFFFFFF
});
resumeText.anchor.set(0.5, 0.5);
resumeText.x = 1024;
resumeText.y = 1400;
pauseOverlay.addChild(resumeText);
pauseOverlay.visible = false;
game.addChild(pauseOverlay);
// Main Menu Screen - Welcome Screen
var mainMenuScreen = new Container();
var menuBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.95,
scaleX: 20,
scaleY: 27
});
mainMenuScreen.addChild(menuBackground);
var welcomeTitle = new Text2('FLAPPY ANIMAL', {
size: 140,
fill: 0xFFD700
});
welcomeTitle.anchor.set(0.5, 0.5);
welcomeTitle.x = 1024;
welcomeTitle.y = 700;
mainMenuScreen.addChild(welcomeTitle);
var subtitleText = new Text2('CLASSIC ARCADE GAME', {
size: 60,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 850;
mainMenuScreen.addChild(subtitleText);
// Preview bird animation
var previewBird = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
previewBird.x = 1024;
previewBird.y = 1200;
mainMenuScreen.addChild(previewBird);
// Add floating animation to preview bird
var birdFloat = LK.setInterval(function () {
if (previewBird && mainMenuScreen.visible) {
tween(previewBird, {
y: 1150
}, {
duration: 1000,
onFinish: function onFinish() {
tween(previewBird, {
y: 1250
}, {
duration: 1000
});
}
});
}
}, 2000);
var playButton = new Text2('PLAY', {
size: 100,
fill: 0x00ff00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 1024;
playButton.y = 1600;
mainMenuScreen.addChild(playButton);
// Play button background
var playBtnBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 1.3,
alpha: 0.3
});
playBtnBg.x = 1024;
playBtnBg.y = 1600;
mainMenuScreen.addChild(playBtnBg);
// Add pulsing animation to play button
var playBtnPulse = LK.setInterval(function () {
if (playButton && mainMenuScreen.visible) {
tween(playButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 600
});
}
});
}
}, 1200);
var tapToPlayInfo = new Text2('TAP TO BEGIN YOUR ADVENTURE!', {
size: 45,
fill: 0xFFD700
});
tapToPlayInfo.anchor.set(0.5, 0.5);
tapToPlayInfo.x = 1024;
tapToPlayInfo.y = 1750;
mainMenuScreen.addChild(tapToPlayInfo);
// Add blinking animation to tap instruction
var tapInfoBlink = LK.setInterval(function () {
if (tapToPlayInfo && mainMenuScreen.visible) {
tween(tapToPlayInfo, {
alpha: 0.4
}, {
duration: 700,
onFinish: function onFinish() {
tween(tapToPlayInfo, {
alpha: 1
}, {
duration: 700
});
}
});
}
}, 1400);
// Play button click handler
playButton.down = function (x, y, obj) {
// Clear animations
LK.clearInterval(playBtnPulse);
LK.clearInterval(birdFloat);
LK.clearInterval(tapInfoBlink);
// Add click feedback animation
tween(playButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'CHARACTER_SELECT';
// Hide main menu with animation
tween(mainMenuScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
mainMenuScreen.visible = false;
// Show character selection screen
showCharacterSelection();
}
});
};
game.addChild(mainMenuScreen);
// Function to show character selection
function showCharacterSelection() {
characterSelectionScreen.visible = true;
characterSelectionScreen.alpha = 0;
tween(characterSelectionScreen, {
alpha: 1
}, {
duration: 300
});
}
// Character Selection Screen
var characterSelectionScreen = new Container();
var selectionBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.95,
scaleX: 20,
scaleY: 27
});
characterSelectionScreen.addChild(selectionBackground);
var selectionTitle = new Text2('SELECT YOUR ANIMAL', {
size: 100,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 500;
characterSelectionScreen.addChild(selectionTitle);
// Character selection buttons
var characterButtons = [];
for (var i = 0; i < characterTypes.length; i++) {
var buttonContainer = new Container();
// Character preview
var charPreview = LK.getAsset(characterTypes[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
buttonContainer.addChild(charPreview);
// Character name
var charName = new Text2(characterNames[i], {
size: 40,
fill: 0xFFFFFF
});
charName.anchor.set(0.5, 0.5);
charName.y = 100;
buttonContainer.addChild(charName);
// Position buttons in a grid
var col = i % 2;
var row = Math.floor(i / 2);
buttonContainer.x = 724 + col * 600;
buttonContainer.y = 1000 + row * 300;
// Store character type for click handling
buttonContainer.characterType = characterTypes[i];
buttonContainer.characterIndex = i;
// Add selection border (initially hidden)
var selectionBorder = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: 0.3
});
selectionBorder.visible = false;
buttonContainer.addChild(selectionBorder);
buttonContainer.selectionBorder = selectionBorder;
// Click handler for character selection
buttonContainer.down = function (x, y, obj) {
// Remove selection from all buttons
for (var j = 0; j < characterButtons.length; j++) {
characterButtons[j].selectionBorder.visible = false;
}
// Show selection on clicked button
this.selectionBorder.visible = true;
selectedCharacter = this.characterType;
// Add selection feedback animation
tween(this, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(this, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
characterButtons.push(buttonContainer);
characterSelectionScreen.addChild(buttonContainer);
}
// Show selection on first character by default
characterButtons[0].selectionBorder.visible = true;
// Confirm selection button
var confirmBtn = new Text2('CONFIRM', {
size: 70,
fill: 0x00ff00
});
confirmBtn.anchor.set(0.5, 0.5);
confirmBtn.x = 1024;
confirmBtn.y = 2200;
characterSelectionScreen.addChild(confirmBtn);
confirmBtn.down = function (x, y, obj) {
gameState = 'START_SCREEN';
// Hide character selection with animation
tween(characterSelectionScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
characterSelectionScreen.visible = false;
// Show start screen
showStartScreen();
}
});
};
characterSelectionScreen.visible = false;
game.addChild(characterSelectionScreen);
// Start Game Screen
var startGameScreen = new Container();
var startBackground = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9,
scaleX: 20,
scaleY: 27
});
startGameScreen.addChild(startBackground);
var gameTitle = new Text2('FLAPPY ANIMAL', {
size: 120,
fill: 0xFFD700
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 1024;
gameTitle.y = 600;
startGameScreen.addChild(gameTitle);
// Show selected character preview
var selectedCharacterPreview = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
selectedCharacterPreview.x = 1024;
selectedCharacterPreview.y = 1000;
startGameScreen.addChild(selectedCharacterPreview);
var characterLabel = new Text2('Ready!', {
size: 60,
fill: 0xFFFFFF
});
characterLabel.anchor.set(0.5, 0.5);
characterLabel.x = 1024;
characterLabel.y = 1200;
startGameScreen.addChild(characterLabel);
var startBtn = new Text2('START GAME', {
size: 100,
fill: 0x00ff00
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = 1024;
startBtn.y = 1600;
startGameScreen.addChild(startBtn);
// Add pulsing animation to start button
var startBtnPulse = LK.setInterval(function () {
if (startBtn && startGameScreen.visible) {
tween(startBtn, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
onFinish: function onFinish() {
tween(startBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
}
});
}
}, 1000);
var tapToPlayText = new Text2('TAP BUTTON TO BEGIN!', {
size: 45,
fill: 0xFFD700
});
tapToPlayText.anchor.set(0.5, 0.5);
tapToPlayText.x = 1024;
tapToPlayText.y = 1750;
startGameScreen.addChild(tapToPlayText);
// Add blinking animation to tap instruction
var tapTextBlink = LK.setInterval(function () {
if (tapToPlayText && startGameScreen.visible) {
tween(tapToPlayText, {
alpha: 0.4
}, {
duration: 600,
onFinish: function onFinish() {
tween(tapToPlayText, {
alpha: 1
}, {
duration: 600
});
}
});
}
}, 1200);
var backBtn = new Text2('BACK', {
size: 50,
fill: 0xff6600
});
backBtn.anchor.set(0.5, 0.5);
backBtn.x = 1024;
backBtn.y = 1900;
startGameScreen.addChild(backBtn);
// Add start button background for better visibility
var startBtnBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5,
alpha: 0.3
});
startBtnBg.x = 1024;
startBtnBg.y = 1600;
startGameScreen.addChild(startBtnBg);
// Ensure start button is on top of background
startGameScreen.removeChild(startBtn);
startGameScreen.addChild(startBtn);
startBtn.down = function (x, y, obj) {
// Clear all animations
LK.clearInterval(startBtnPulse);
LK.clearInterval(tapTextBlink);
// Add click feedback animation
tween(startBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(startBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'PLAYING';
// Hide start screen with animation
tween(startGameScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
startGameScreen.visible = false;
// Initialize game with selected character
initializeGameWithCharacter();
}
});
};
backBtn.down = function (x, y, obj) {
// Clear animations
LK.clearInterval(startBtnPulse);
LK.clearInterval(tapTextBlink);
// Add click feedback for back button
tween(backBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(backBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
gameState = 'CHARACTER_SELECT';
// Hide start screen and show character selection
tween(startGameScreen, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
startGameScreen.visible = false;
characterSelectionScreen.visible = true;
characterSelectionScreen.alpha = 0;
tween(characterSelectionScreen, {
alpha: 1
}, {
duration: 300
});
}
});
};
startGameScreen.visible = false;
game.addChild(startGameScreen);
// Function to show start screen
function showStartScreen() {
// Update selected character preview
startGameScreen.removeChild(selectedCharacterPreview);
selectedCharacterPreview = LK.getAsset(selectedCharacter, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
selectedCharacterPreview.x = 1024;
selectedCharacterPreview.y = 1000;
startGameScreen.addChild(selectedCharacterPreview);
startGameScreen.visible = true;
startGameScreen.alpha = 0;
tween(startGameScreen, {
alpha: 1
}, {
duration: 300
});
}
// Game start instruction
var instructionTxt = new Text2('TAP TO START', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1000;
game.addChild(instructionTxt);
// Add blinking animation
var instructionBlink = LK.setInterval(function () {
if (instructionTxt && instructionTxt.parent) {
tween(instructionTxt, {
alpha: 0.3
}, {
duration: 500,
onFinish: function onFinish() {
if (instructionTxt && instructionTxt.parent) {
tween(instructionTxt, {
alpha: 1
}, {
duration: 500
});
}
}
});
}
}, 1000);
// Function to initialize game with selected character
function initializeGameWithCharacter() {
// Initialize bird with selected character
bird = game.addChild(new Bird(selectedCharacter));
bird.x = 400;
bird.y = 1366; // Center of screen vertically
bird.lastY = bird.y; // Initialize tracking property
// Initialize particle system
particleSystem = game.addChild(new ParticleSystem({
maxParticles: 100,
color: 0xFFD700
}));
// Reset modern game variables
comboCount = 0;
comboTimer = 0;
maxCombo = 0;
coins = storage.coins || 0;
coinTxt.setText('💰 ' + coins);
difficulty = 1;
difficultyTimer = 0;
shieldActive = false;
shieldTimer = 0;
}
// Don't initialize bird immediately - wait for character selection
var bird;
// Initialize ground
ground1 = game.addChild(new Ground());
ground1.x = 0;
ground1.y = 2400; // Position ground lower for better gameplay
ground2 = game.addChild(new Ground());
ground2.x = 2048;
ground2.y = 2400; // Position ground lower for better gameplay
// Add pause button click handler
pauseBtn.down = function (x, y, obj) {
if (gameStarted && !gamePaused) {
gamePaused = true;
pauseOverlay.visible = true;
// Add fade in animation for pause overlay
pauseOverlay.alpha = 0;
tween(pauseOverlay, {
alpha: 1
}, {
duration: 200
});
}
};
// Add pause overlay click handler for resume
pauseOverlay.down = function (x, y, obj) {
if (gamePaused) {
// Add fade out animation
tween(pauseOverlay, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
pauseOverlay.visible = false;
gamePaused = false;
}
});
}
};
// Tap to flap
game.down = function (x, y, obj) {
// Don't allow interaction during non-playing states (except main menu)
if (gameState !== 'PLAYING' && gameState !== 'MAIN_MENU') {
return;
}
// Handle main menu tap anywhere to start
if (gameState === 'MAIN_MENU') {
// Trigger the same action as play button
playButton.down(x, y, obj);
return;
}
// Don't allow flapping when paused
if (gamePaused) {
return;
}
if (!gameStarted) {
gameStarted = true;
// Hide instruction text with animation
if (instructionTxt) {
LK.clearInterval(instructionBlink);
tween(instructionTxt, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
instructionTxt.destroy();
instructionTxt = null;
}
});
}
}
if (bird) {
bird.flap();
}
};
// Collision detection helper function
function checkCollision(birdBounds, pipeBounds) {
return birdBounds.x < pipeBounds.x + pipeBounds.width && birdBounds.x + birdBounds.width > pipeBounds.x && birdBounds.y < pipeBounds.y + pipeBounds.height && birdBounds.y + birdBounds.height > pipeBounds.y;
}
// Main game update
game.update = function () {
if (gameState !== 'PLAYING' || !gameStarted || gamePaused || !bird) {
return;
}
// Store bird's last Y position
if (bird.lastY === undefined) {
bird.lastY = bird.y;
}
// Update difficulty over time
difficultyTimer++;
if (difficultyTimer >= 1800) {
// Every 30 seconds at 60fps
difficulty++;
difficultyTimer = 0;
difficultyTxt.setText('LEVEL ' + difficulty);
// Increase game speed slightly
pipeSpacing = Math.max(600, pipeSpacing - 20);
// Visual feedback for difficulty increase
tween(difficultyTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(difficultyTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Update shield timer
if (shieldActive) {
shieldTimer--;
if (shieldTimer <= 0) {
shieldActive = false;
shieldTxt.visible = false;
}
}
// Update combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer <= 0) {
comboCount = 0;
comboTxt.visible = false;
}
}
// Spawn pipes
pipeTimer++;
if (pipeTimer >= pipeSpacing / 4) {
// Adjust timing based on speed and difficulty
var newPipe = new Pipe();
newPipe.x = 2200; // Start off-screen right
newPipe.lastX = newPipe.x; // Initialize tracking property
// Random gap position (avoid top and bottom areas)
var gapCenter = 500 + Math.random() * 1200; // Between 500 and 1700 for better gameplay
// Adjust gap size based on difficulty
newPipe.gapSize = Math.max(250, 300 - (difficulty - 1) * 10);
newPipe.setGapPosition(gapCenter);
// Add entrance animation
newPipe.alpha = 0;
tween(newPipe, {
alpha: 1
}, {
duration: 300
});
pipes.push(newPipe);
game.addChild(newPipe);
pipeTimer = 0;
// Spawn power-ups occasionally
if (Math.random() < 0.3) {
// 30% chance
var powerUpType = Math.random() < 0.7 ? 'coin' : 'shield';
var powerUp = new PowerUp(powerUpType);
powerUp.x = 2200;
powerUp.y = gapCenter + (Math.random() - 0.5) * 100;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Update pipes and check collisions/scoring
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Initialize tracking properties
if (pipe.lastX === undefined) {
pipe.lastX = pipe.x;
}
// Check if pipe passed bird for scoring
if (!pipe.passed && pipe.lastX > bird.x && pipe.x <= bird.x) {
pipe.passed = true;
comboCount++;
comboTimer = 180; // 3 seconds at 60fps
maxCombo = Math.max(maxCombo, comboCount);
// Calculate score with combo multiplier
var scoreGain = 1;
if (comboCount >= 3) {
scoreGain = Math.min(comboCount, 10); // Max 10x multiplier
}
LK.setScore(LK.getScore() + scoreGain);
scoreTxt.setText(LK.getScore());
// Show combo text
if (comboCount >= 3) {
comboTxt.setText('COMBO x' + comboCount + '!');
comboTxt.visible = true;
tween(comboTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Particle effect at bird position
particleSystem.emit(bird.x, bird.y, 8);
// Play score sound
LK.getSound('score').play();
// Check and update best score
var currentScore = LK.getScore();
if (currentScore > bestScore) {
bestScore = currentScore;
storage.bestScore = bestScore;
bestScoreTxt.setText('BEST: ' + bestScore);
// Add special animation for new best score
tween(bestScoreTxt, {
scaleX: 1.4,
scaleY: 1.4,
alpha: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
tween(bestScoreTxt, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200
});
}
});
// Flash screen gold for new best score
LK.effects.flashScreen(0xFFD700, 300);
}
// Add score animation
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Flash screen green for successful pass
LK.effects.flashScreen(0x00ff00, 200);
}
// Remove pipes that are off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
continue;
}
// Check collision with pipes
var birdBounds = {
x: bird.x - 70,
y: bird.y - 70,
width: 140,
height: 140
};
var topBounds = pipe.getTopBounds();
var bottomBounds = pipe.getBottomBounds();
if (checkCollision(birdBounds, topBounds) || checkCollision(birdBounds, bottomBounds)) {
// Check if shield is active
if (shieldActive) {
// Shield protects from one hit
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
// Visual feedback for shield use
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
// Reset combo but don't end game
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
// Skip to next iteration, don't end game
continue;
}
// Play hit sound
LK.getSound('hit').play();
// Reset combo on collision
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
// Stop the game immediately
gameStarted = false;
// Add dramatic bird rotation and fall effect
tween(bird, {
rotation: Math.PI * 2,
y: bird.y + 200
}, {
duration: 800
});
// Add bird shake effect before game over
tween(bird, {
x: bird.x - 15
}, {
duration: 75,
onFinish: function onFinish() {
tween(bird, {
x: bird.x + 30
}, {
duration: 75,
onFinish: function onFinish() {
tween(bird, {
x: bird.x - 15
}, {
duration: 75
});
}
});
}
});
// Flash screen red for longer duration
LK.effects.flashScreen(0xff0000, 800);
// Show dramatic "GAME OVER" text before official game over
var gameOverTxt = new Text2('GAME OVER', {
size: 120,
fill: 0xff0000
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.x = 1024;
gameOverTxt.y = 1366;
gameOverTxt.alpha = 0;
game.addChild(gameOverTxt);
// Animate game over text appearance
tween(gameOverTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
// Wait a moment then show official game over
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 800);
}
});
return;
}
// Update last position
pipe.lastX = pipe.x;
}
// Update and check power-ups
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
// Remove off-screen power-ups
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(j, 1);
continue;
}
// Check collision with bird
if (!powerUp.collected) {
var powerUpBounds = {
x: powerUp.x - 40,
y: powerUp.y - 40,
width: 80,
height: 80
};
if (checkCollision(birdBounds, powerUpBounds)) {
powerUp.collected = true;
if (powerUp.type === 'coin') {
coins++;
storage.coins = coins;
coinTxt.setText('💰 ' + coins);
// Coin collection particle effect
particleSystem.emit(powerUp.x, powerUp.y, 15);
tween(coinTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(coinTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
} else if (powerUp.type === 'shield') {
shieldActive = true;
shieldTimer = 600; // 10 seconds at 60fps
shieldTxt.visible = true;
// Shield activation effect
LK.effects.flashScreen(0x00FFFF, 300);
tween(shieldTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(shieldTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
// Remove collected power-up with animation
tween(powerUp, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 200,
onFinish: function onFinish() {
powerUp.destroy();
powerUps.splice(j, 1);
}
});
}
}
}
// Check collision with ground
if (bird.y >= 2330) {
// Ground collision (ground at 2400, bird radius 70)
if (shieldActive) {
// Shield protects from ground collision too
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
bird.y = 2320; // Move bird up slightly
bird.velocity = -8; // Give upward momentum
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
return; // Don't end game
}
// Play hit sound
LK.getSound('hit').play();
// Save game statistics
storage.maxCombo = Math.max(storage.maxCombo || 0, maxCombo);
storage.totalGames = (storage.totalGames || 0) + 1;
storage.totalCoins = coins;
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
gameStarted = false;
// Make bird bounce slightly on ground impact
tween(bird, {
y: 2320,
rotation: Math.PI / 4
}, {
duration: 200,
onFinish: function onFinish() {
tween(bird, {
y: 2330
}, {
duration: 100
});
}
});
LK.effects.flashScreen(0xff0000, 800);
// Show impact text
var impactTxt = new Text2('CRASHED!', {
size: 100,
fill: 0xff4500
});
impactTxt.anchor.set(0.5, 0.5);
impactTxt.x = 1024;
impactTxt.y = 1200;
impactTxt.alpha = 0;
game.addChild(impactTxt);
tween(impactTxt, {
alpha: 1,
y: 1100
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 600);
}
});
return;
}
// Check collision with ceiling
if (bird.y <= 70) {
if (shieldActive) {
// Shield protects from ceiling collision
shieldActive = false;
shieldTimer = 0;
shieldTxt.visible = false;
bird.y = 80; // Move bird down slightly
bird.velocity = 5; // Give downward momentum
LK.effects.flashScreen(0x00FFFF, 400);
particleSystem.emit(bird.x, bird.y, 20);
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
return; // Don't end game
}
// Play hit sound
LK.getSound('hit').play();
comboCount = 0;
comboTimer = 0;
comboTxt.visible = false;
gameStarted = false;
// Make bird fall dramatically from ceiling
tween(bird, {
y: 200,
rotation: -Math.PI / 2
}, {
duration: 300
});
LK.effects.flashScreen(0xffffff, 300);
// Show ceiling hit text
var ceilingTxt = new Text2('HIT CEILING!', {
size: 80,
fill: 0xff6600
});
ceilingTxt.anchor.set(0.5, 0.5);
ceilingTxt.x = 1024;
ceilingTxt.y = 400;
ceilingTxt.alpha = 0;
game.addChild(ceilingTxt);
tween(ceilingTxt, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 250,
onFinish: function onFinish() {
LK.setTimeout(function () {
LK.getSound('gameover').play();
LK.showGameOver();
}, 500);
}
});
return;
}
// Update last position
bird.lastY = bird.y;
};