/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); // Attach bird asset (yellow ellipse) var birdAsset = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Physics properties self.vy = 0; // vertical velocity self.gravity = 1.1; // gravity per frame (bird falls faster) self.flapStrength = -22; // weaker flap, harder to lift // Bird size for collision self.radius = birdAsset.width * 0.45; // Flap method self.flap = function () { self.vy = self.flapStrength; }; // Update method (called every tick) self.update = function () { self.vy += self.gravity; self.y += self.vy; // Clamp rotation for visual feedback var maxAngle = Math.PI / 4; var minAngle = -Math.PI / 3; var targetAngle = Math.max(minAngle, Math.min(maxAngle, self.vy / 40)); birdAsset.rotation = targetAngle; }; return self; }); // PipePair class (top and bottom pipes) var PipePair = Container.expand(function () { var self = Container.call(this); // Pipe gap and width self.gap = 480; self.pipeWidth = 220; // Randomize gap position var minY = 180; var maxY = 2732 - 180 - self.gap; self.gapY = minY + Math.floor(Math.random() * (maxY - minY + 1)); // Top pipe var topPipe = self.attachAsset('pipe', { anchorX: 0, anchorY: 1, x: 0, y: self.gapY, height: self.gapY, width: self.pipeWidth, tint: 0x4ec04e }); // Bottom pipe var bottomPipe = self.attachAsset('pipe', { anchorX: 0, anchorY: 0, x: 0, y: self.gapY + self.gap, height: 2732 - (self.gapY + self.gap), width: self.pipeWidth, tint: 0x4ec04e }); // For collision self.topPipe = topPipe; self.bottomPipe = bottomPipe; // Has the bird passed this pipe? (for scoring) self.passed = false; // Update method self.update = function () { self.x -= pipesSpeed; }; // Destroy method self.destroyPair = function () { self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // Game constants var BIRD_START_X = 600; var BIRD_START_Y = 1366; var GROUND_HEIGHT = 220; var PIPE_INTERVAL = 140; // frames between pipes (less frequent) var pipesSpeed = 9; // Asset initialization // Score text var scoreTxt = new Text2('0', { size: 180, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Bird var bird = new Bird(); game.addChild(bird); bird.x = BIRD_START_X; bird.y = BIRD_START_Y; // Ground var ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: 2732 - GROUND_HEIGHT }); game.addChild(ground); // Pipes array var pipes = []; // Game state var isAlive = true; var frameCount = 0; var dragNode = null; // Reset function (called on game start and after game over) function resetGame() { // Remove pipes for (var i = pipes.length - 1; i >= 0; i--) { pipes[i].destroyPair(); pipes.splice(i, 1); } // Reset bird bird.x = BIRD_START_X; bird.y = BIRD_START_Y; bird.vy = 0; // Reset score LK.setScore(0); scoreTxt.setText('0'); // Reset state isAlive = true; frameCount = 0; } // Collision detection (circle-rectangle) function circleRectCollide(cx, cy, radius, rx, ry, rw, rh) { // Find closest point to circle within rectangle var closestX = Math.max(rx, Math.min(cx, rx + rw)); var closestY = Math.max(ry, Math.min(cy, ry + rh)); var dx = cx - closestX; var dy = cy - closestY; return dx * dx + dy * dy < radius * radius; } // Main update loop game.update = function () { if (!isAlive) return; bird.update(); // Pipes logic for (var i = pipes.length - 1; i >= 0; i--) { var pair = pipes[i]; pair.update(); // Remove pipes off screen if (pair.x + pair.pipeWidth < 0) { pair.destroyPair(); pipes.splice(i, 1); continue; } // Score: if bird passes pipe if (!pair.passed && bird.x > pair.x + pair.pipeWidth) { pair.passed = true; var newScore = LK.getScore() + 1; LK.setScore(newScore); scoreTxt.setText(newScore + ''); } // Collision with pipes // Top pipe if (circleRectCollide(bird.x, bird.y, bird.radius, pair.x, 0, pair.pipeWidth, pair.gapY)) { gameOver(); return; } // Bottom pipe if (circleRectCollide(bird.x, bird.y, bird.radius, pair.x, pair.gapY + pair.gap, pair.pipeWidth, 2732 - (pair.gapY + pair.gap))) { gameOver(); return; } } // Collision with ground if (bird.y + bird.radius > 2732 - GROUND_HEIGHT) { bird.y = 2732 - GROUND_HEIGHT - bird.radius; gameOver(); return; } // Collision with ceiling if (bird.y - bird.radius < 0) { bird.y = bird.radius; bird.vy = 0; } // Pipe spawn frameCount++; if (frameCount % PIPE_INTERVAL === 0) { var pipePair = new PipePair(); pipePair.x = 2048; game.addChild(pipePair); pipes.push(pipePair); } }; // Game over logic function gameOver() { isAlive = false; LK.effects.flashScreen(0xff0000, 600); LK.showGameOver(); } // Flap button UI var flapBtnSize = 320; var flapBtn = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 2048 - flapBtnSize * 0.7, y: 2732 - flapBtnSize * 0.7, scaleX: flapBtnSize / 100, scaleY: flapBtnSize / 100, tint: 0xffe066 }); LK.gui.bottomRight.addChild(flapBtn); // Flap button label var flapLabel = new Text2('Zıpla', { size: 90, fill: 0x7A4C00 }); flapLabel.anchor.set(0.5, 0.5); flapLabel.x = flapBtn.x; flapLabel.y = flapBtn.y; LK.gui.bottomRight.addChild(flapLabel); // Flap button tap handler flapBtn.down = function (x, y, obj) { if (!isAlive) return; bird.flap(); }; // Tap/Touch to flap (anywhere else) game.down = function (x, y, obj) { if (!isAlive) return; // Only flap if not tapping the button (button handles itself) // (No-op here, as button handles its own tap) // Optionally, you can keep bird.flap() here to allow both button and anywhere tap: bird.flap(); }; // Dragging is not used, but required for mobile compatibility game.move = function (x, y, obj) {}; // Reset game on game over (handled by LK, but for clarity) game.on('reset', function () { resetGame(); }); // Initial reset resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Attach bird asset (yellow ellipse)
var birdAsset = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.vy = 0; // vertical velocity
self.gravity = 1.1; // gravity per frame (bird falls faster)
self.flapStrength = -22; // weaker flap, harder to lift
// Bird size for collision
self.radius = birdAsset.width * 0.45;
// Flap method
self.flap = function () {
self.vy = self.flapStrength;
};
// Update method (called every tick)
self.update = function () {
self.vy += self.gravity;
self.y += self.vy;
// Clamp rotation for visual feedback
var maxAngle = Math.PI / 4;
var minAngle = -Math.PI / 3;
var targetAngle = Math.max(minAngle, Math.min(maxAngle, self.vy / 40));
birdAsset.rotation = targetAngle;
};
return self;
});
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
var self = Container.call(this);
// Pipe gap and width
self.gap = 480;
self.pipeWidth = 220;
// Randomize gap position
var minY = 180;
var maxY = 2732 - 180 - self.gap;
self.gapY = minY + Math.floor(Math.random() * (maxY - minY + 1));
// Top pipe
var topPipe = self.attachAsset('pipe', {
anchorX: 0,
anchorY: 1,
x: 0,
y: self.gapY,
height: self.gapY,
width: self.pipeWidth,
tint: 0x4ec04e
});
// Bottom pipe
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0,
anchorY: 0,
x: 0,
y: self.gapY + self.gap,
height: 2732 - (self.gapY + self.gap),
width: self.pipeWidth,
tint: 0x4ec04e
});
// For collision
self.topPipe = topPipe;
self.bottomPipe = bottomPipe;
// Has the bird passed this pipe? (for scoring)
self.passed = false;
// Update method
self.update = function () {
self.x -= pipesSpeed;
};
// Destroy method
self.destroyPair = function () {
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Game constants
var BIRD_START_X = 600;
var BIRD_START_Y = 1366;
var GROUND_HEIGHT = 220;
var PIPE_INTERVAL = 140; // frames between pipes (less frequent)
var pipesSpeed = 9;
// Asset initialization
// Score text
var scoreTxt = new Text2('0', {
size: 180,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Bird
var bird = new Bird();
game.addChild(bird);
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
// Ground
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - GROUND_HEIGHT
});
game.addChild(ground);
// Pipes array
var pipes = [];
// Game state
var isAlive = true;
var frameCount = 0;
var dragNode = null;
// Reset function (called on game start and after game over)
function resetGame() {
// Remove pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroyPair();
pipes.splice(i, 1);
}
// Reset bird
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
bird.vy = 0;
// Reset score
LK.setScore(0);
scoreTxt.setText('0');
// Reset state
isAlive = true;
frameCount = 0;
}
// Collision detection (circle-rectangle)
function circleRectCollide(cx, cy, radius, rx, ry, rw, rh) {
// Find closest point to circle within rectangle
var closestX = Math.max(rx, Math.min(cx, rx + rw));
var closestY = Math.max(ry, Math.min(cy, ry + rh));
var dx = cx - closestX;
var dy = cy - closestY;
return dx * dx + dy * dy < radius * radius;
}
// Main update loop
game.update = function () {
if (!isAlive) return;
bird.update();
// Pipes logic
for (var i = pipes.length - 1; i >= 0; i--) {
var pair = pipes[i];
pair.update();
// Remove pipes off screen
if (pair.x + pair.pipeWidth < 0) {
pair.destroyPair();
pipes.splice(i, 1);
continue;
}
// Score: if bird passes pipe
if (!pair.passed && bird.x > pair.x + pair.pipeWidth) {
pair.passed = true;
var newScore = LK.getScore() + 1;
LK.setScore(newScore);
scoreTxt.setText(newScore + '');
}
// Collision with pipes
// Top pipe
if (circleRectCollide(bird.x, bird.y, bird.radius, pair.x, 0, pair.pipeWidth, pair.gapY)) {
gameOver();
return;
}
// Bottom pipe
if (circleRectCollide(bird.x, bird.y, bird.radius, pair.x, pair.gapY + pair.gap, pair.pipeWidth, 2732 - (pair.gapY + pair.gap))) {
gameOver();
return;
}
}
// Collision with ground
if (bird.y + bird.radius > 2732 - GROUND_HEIGHT) {
bird.y = 2732 - GROUND_HEIGHT - bird.radius;
gameOver();
return;
}
// Collision with ceiling
if (bird.y - bird.radius < 0) {
bird.y = bird.radius;
bird.vy = 0;
}
// Pipe spawn
frameCount++;
if (frameCount % PIPE_INTERVAL === 0) {
var pipePair = new PipePair();
pipePair.x = 2048;
game.addChild(pipePair);
pipes.push(pipePair);
}
};
// Game over logic
function gameOver() {
isAlive = false;
LK.effects.flashScreen(0xff0000, 600);
LK.showGameOver();
}
// Flap button UI
var flapBtnSize = 320;
var flapBtn = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - flapBtnSize * 0.7,
y: 2732 - flapBtnSize * 0.7,
scaleX: flapBtnSize / 100,
scaleY: flapBtnSize / 100,
tint: 0xffe066
});
LK.gui.bottomRight.addChild(flapBtn);
// Flap button label
var flapLabel = new Text2('Zıpla', {
size: 90,
fill: 0x7A4C00
});
flapLabel.anchor.set(0.5, 0.5);
flapLabel.x = flapBtn.x;
flapLabel.y = flapBtn.y;
LK.gui.bottomRight.addChild(flapLabel);
// Flap button tap handler
flapBtn.down = function (x, y, obj) {
if (!isAlive) return;
bird.flap();
};
// Tap/Touch to flap (anywhere else)
game.down = function (x, y, obj) {
if (!isAlive) return;
// Only flap if not tapping the button (button handles itself)
// (No-op here, as button handles its own tap)
// Optionally, you can keep bird.flap() here to allow both button and anywhere tap:
bird.flap();
};
// Dragging is not used, but required for mobile compatibility
game.move = function (x, y, obj) {};
// Reset game on game over (handled by LK, but for clarity)
game.on('reset', function () {
resetGame();
});
// Initial reset
resetGame();