/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function (isStork) {
var self = Container.call(this);
// Pick color
var birdAssetId;
self.isStork = !!isStork;
if (self.isStork) {
birdAssetId = 'birdRed'; // Use red as stork, or replace with a stork asset if available
} else if (typeof score !== "undefined" && score > 15) {
// After score > 15, always blue bird
birdAssetId = 'birdBlue';
} else {
var colorIdx = Math.floor(Math.random() * 3);
birdAssetId = colorIdx === 0 ? 'birdRed' : colorIdx === 1 ? 'birdBlue' : 'birdGreen';
}
var birdBody = self.attachAsset(birdAssetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.7,
scaleY: 1.7
});
// Add wings (for simple up/down animation)
var leftWing = self.attachAsset('birdWing', {
anchorX: 0.9,
anchorY: 0.5,
x: -85,
y: 0,
scaleX: 1.7,
scaleY: 1.7
});
var rightWing = self.attachAsset('birdWing', {
anchorX: 0.1,
anchorY: 0.5,
x: 85,
y: 0,
scaleX: 1.7,
scaleY: 1.7
});
rightWing.scaleY = 1;
leftWing.scaleY = 1;
// Bird movement
self.speed = 3 + Math.random() * 2.5; // px per frame (slower)
self.dir = Math.random() < 0.5 ? 1 : -1; // 1: left->right, -1: right->left
self.amplitude = 60 + Math.random() * 80; // vertical sine amplitude
self.freq = 0.002 + Math.random() * 0.001; // vertical sine frequency (slower)
self.baseY = 0;
self.t = 0;
self.isAlive = true;
self.hasDroppedBomb = false;
// For bomb drop
self.lastHit = false;
// Animate wings
self.update = function () {
if (!self.isAlive) return;
self.t += 1;
// Sine wave vertical movement
self.y = self.baseY + Math.sin(self.t * self.freq * 2 * Math.PI) * self.amplitude;
self.x += self.speed * self.dir;
// Animate wings
var wingAngle = Math.sin(self.t * 0.25) * 0.7;
leftWing.rotation = -wingAngle;
rightWing.rotation = wingAngle;
// Bomb drop logic is now handled in game.update for sequential dropping
// Remove if off screen
if (self.dir === 1 && self.x > 2200 || self.dir === -1 && self.x < -200) {
self.destroy();
var idx = birds.indexOf(self);
if (idx !== -1) birds.splice(idx, 1);
}
};
// Called when hit by bullet
self.hit = function () {
if (self.isStork) return; // Stork is invulnerable
if (!self.isAlive) return;
self.isAlive = false;
// Play hit sound
LK.getSound('birdHit').play();
// Flash bird
LK.effects.flashObject(self, 0xffffff, 200);
// Drop bomb
self.dropBomb();
// Remove bird after short delay
LK.setTimeout(function () {
self.destroy();
var idx = birds.indexOf(self);
if (idx !== -1) birds.splice(idx, 1);
}, 200);
};
// Drop bomb
self.dropBomb = function () {
// Remove single-bomb restriction for random bomb drops
var bomb = new Bomb();
bomb.x = self.x;
bomb.y = self.y + 40;
// Bomb gets a random horizontal velocity
bomb.vx = (Math.random() - 0.5) * 12;
// Calculate bomb speed: base is a bit faster, increase by 1 for every 10 score
var bombBaseVy = 8 + Math.random() * 4; // faster base speed
var bombSpeedBonus = 0;
if (typeof score !== "undefined") {
bombSpeedBonus = Math.floor(score / 10);
}
bomb.vy = bombBaseVy + bombSpeedBonus;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
};
return self;
});
// Bomb class
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bomb = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 14;
self.gravity = 0.7;
self.landed = false;
self.update = function () {
if (self.landed) return;
self.x += self.vx;
self.y += self.vy;
self.vy += self.gravity;
// If hits ground (bottom 180px)
if (self.y > 2732 - 180) {
self.landed = true;
self.explode();
}
};
self.explode = function () {
// Play explosion sound
LK.getSound('explosion').play();
// Show explosion effect
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: 2732 - 120,
scaleX: 0.5,
scaleY: 0.5
});
game.addChild(explosion);
tween(explosion, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Remove bomb
LK.setTimeout(function () {
self.destroy();
var idx = bombs.indexOf(self);
if (idx !== -1) bombs.splice(idx, 1);
}, 100);
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -32; // Upwards
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
// Body
var body = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Gun
var gun = self.attachAsset('gun', {
anchorX: 1,
// align right edge of gun to player
anchorY: 0.5,
// middle vertically
x: body.width / 2,
// move to right edge of player body
y: 0 // align vertically to center of player
});
// For drag
self.isDragging = false;
// For shooting cooldown
self.lastShotTick = -100;
// For hit flash
self.flashTimeout = null;
// Flash effect
self.flash = function () {
if (self.flashTimeout) {
LK.clearTimeout(self.flashTimeout);
}
body.tint = 0xff0000;
self.flashTimeout = LK.setTimeout(function () {
body.tint = 0x222222;
self.flashTimeout = null;
}, 200);
};
// Add hold-to-shoot on player
self.down = function (x, y, obj) {
// Only allow shooting if not dragging (to avoid double fire on drag)
if (!self.isDragging) {
shootBullet();
// Start interval for continuous shooting
if (!self.shootInterval) {
self.shootInterval = LK.setInterval(function () {
shootBullet();
}, 120);
}
}
};
self.up = function (x, y, obj) {
// Stop continuous shooting
if (self.shootInterval) {
LK.clearInterval(self.shootInterval);
self.shootInterval = null;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Play music
// Sounds
// Explosion (for bomb impact)
// Bomb
// Bullet
// Gun barrel
// Player: rectangle
// Bird wing (for simple animation)
// Birds: 3 colors, simple ellipses
// Play music
LK.playMusic('bgmusic');
// Add background image
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 2048 / 100,
// asset width is 100, scale to fit game width
scaleY: 2732 / 100 // asset height is 100, scale to fit game height
});
game.addChildAt(background, 0); // Add as the bottom-most layer
// Arrays for game objects
var birds = [];
var bullets = [];
var bombs = [];
// For sequential bomb drop
var nextBirdToDropBomb = 0;
// Score
var score = 0;
// Stork logic
var storkActive = false;
var storkScoreStart = 0;
var stork = null;
// Player
var player = new Player();
game.addChild(player);
player.x = 2048 / 2;
player.y = 2732 - 180;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Dragging
var dragNode = null;
// For shooting
function shootBullet() {
// Cooldown: 10 ticks
if (LK.ticks - player.lastShotTick < 10) return;
player.lastShotTick = LK.ticks;
var bullet = new Bullet();
// Find gun tip position relative to player
var gunOffsetX = player.x + (player.width ? player.width / 2 : 160) + 20 + 15; // gun width/2
var gunOffsetY = player.y - 70 - 60; // gun y + gun height
// But since gun is attached to player, get its position
if (player.children && player.children.length > 1) {
var gunObj = player.children[1];
// gunObj.x/y are relative to player
bullet.x = player.x + gunObj.x + gunObj.width / 2;
bullet.y = player.y + gunObj.y - gunObj.height;
} else {
bullet.x = player.x + 175;
bullet.y = player.y - 130;
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
// Move handler
function handleMove(x, y, obj) {
// Clamp x to avoid left menu
var minX = 120;
var maxX = 2048 - 120;
if (dragNode === player) {
player.x = Math.max(minX, Math.min(maxX, x));
// Update lastPlayerMoveTick on movement
lastPlayerMoveTick = LK.ticks;
bombedForNoPlayerMove = false;
}
}
// Touch/mouse events
game.down = function (x, y, obj) {
// Only drag if touch is on lower 1/3 of screen
if (y > 2732 - 600) {
dragNode = player;
handleMove(x, y, obj);
} else {
// Shoot if tap upper area
shootBullet();
}
};
game.move = function (x, y, obj) {
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
// Stop continuous shooting if touch is released anywhere
if (player.shootInterval) {
LK.clearInterval(player.shootInterval);
player.shootInterval = null;
}
};
// Spawn birds at intervals
var birdSpawnTimer = 0;
function spawnBird() {
var bird = new Bird();
// Random Y in upper 2/3
bird.baseY = 200 + Math.random() * 1200;
// Start at left or right
if (bird.dir === 1) {
bird.x = -100;
} else {
bird.x = 2048 + 100;
}
bird.y = bird.baseY;
birds.push(bird);
game.addChild(bird);
}
// Main update loop
game.update = function () {
// Determine max birds: 2 at start, +1 for every 10 score
var maxBirds = 2 + Math.floor(score / 10);
// Stork logic: spawn if score > 30, not already active, and not present
if (score > 30 && !storkActive && !stork) {
stork = new Bird(true); // true = isStork
// Place stork at random Y in upper 2/3, random direction
stork.baseY = 200 + Math.random() * 1200;
stork.dir = Math.random() < 0.5 ? 1 : -1;
if (stork.dir === 1) {
stork.x = -100;
} else {
stork.x = 2048 + 100;
}
stork.y = stork.baseY;
birds.push(stork);
game.addChild(stork);
storkActive = true;
storkScoreStart = score;
}
// Remove stork after 3 score increments
if (storkActive && stork && score >= storkScoreStart + 3) {
if (birds.indexOf(stork) !== -1) {
stork.destroy();
birds.splice(birds.indexOf(stork), 1);
}
stork = null;
storkActive = false;
}
// Spawn birds
if (LK.ticks % 40 === 0 && birds.length < maxBirds) {
spawnBird();
}
// Update birds
for (var i = birds.length - 1; i >= 0; i--) {
var bird = birds[i];
bird.update();
}
// Sequential bomb drop logic: only one bird drops a bomb at a time, in order
if (birds.length > 0) {
// Find the next bird eligible to drop a bomb
var found = false;
for (var i = 0; i < birds.length; i++) {
var idx = (nextBirdToDropBomb + i) % birds.length;
var bird = birds[idx];
if (bird.isAlive && !bird.hasDroppedBomb) {
bird.dropBomb();
bird.hasDroppedBomb = true;
nextBirdToDropBomb = (idx + 1) % birds.length;
found = true;
break;
}
}
// Reset hasDroppedBomb for dead or offscreen birds
for (var i = 0; i < birds.length; i++) {
var bird = birds[i];
if (!bird.isAlive) {
bird.hasDroppedBomb = false;
}
}
}
// --- 10 seconds no bird hit bomb/gameover logic ---
if (typeof lastBirdHitTick === "undefined") {
var lastBirdHitTick = LK.ticks;
}
if (typeof bombedForNoHit === "undefined") {
var bombedForNoHit = false;
}
// --- 10 seconds no player movement bomb/gameover logic ---
if (typeof lastPlayerMoveTick === "undefined") {
var lastPlayerMoveTick = LK.ticks;
}
if (typeof bombedForNoPlayerMove === "undefined") {
var bombedForNoPlayerMove = false;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove if off screen
if (bullet.y < -60) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with birds
for (var j = 0; j < birds.length; j++) {
var bird = birds[j];
if (bird.isAlive && bullet.intersects(bird)) {
if (bird.isStork) {
// Stork: ignore hit, just destroy bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
// Hit!
bird.hit();
bullet.destroy();
bullets.splice(i, 1);
// Score
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Add simple explosion effect at bird position
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: bird.x,
y: bird.y,
scaleX: 0.5,
scaleY: 0.5
});
game.addChild(explosion);
tween(explosion, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// --- Reset no-hit timer on bird hit ---
lastBirdHitTick = LK.ticks;
bombedForNoHit = false;
break;
}
}
}
// --- Check for 10 seconds without bird hit ---
if (!bombedForNoHit && LK.ticks - lastBirdHitTick > 600) {
// Drop a bomb at player's position and end game
bombedForNoHit = true;
var bomb = new Bomb();
bomb.x = player.x;
bomb.y = player.y - 120;
bomb.vx = 0;
bomb.vy = 18;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
// Flash and show game over after short delay for bomb to "land"
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}, 400);
}
// --- Check for 10 seconds of player inactivity ---
if (!bombedForNoPlayerMove && LK.ticks - lastPlayerMoveTick > 600) {
bombedForNoPlayerMove = true;
var bomb = new Bomb();
bomb.x = player.x;
bomb.y = player.y - 120;
bomb.vx = 0;
bomb.vy = 18;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}, 400);
}
// Update bombs
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
bomb.update();
// Check collision with player (if not landed)
if (!bomb.landed && bomb.intersects(player)) {
// Player hit!
player.flash();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function (isStork) {
var self = Container.call(this);
// Pick color
var birdAssetId;
self.isStork = !!isStork;
if (self.isStork) {
birdAssetId = 'birdRed'; // Use red as stork, or replace with a stork asset if available
} else if (typeof score !== "undefined" && score > 15) {
// After score > 15, always blue bird
birdAssetId = 'birdBlue';
} else {
var colorIdx = Math.floor(Math.random() * 3);
birdAssetId = colorIdx === 0 ? 'birdRed' : colorIdx === 1 ? 'birdBlue' : 'birdGreen';
}
var birdBody = self.attachAsset(birdAssetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.7,
scaleY: 1.7
});
// Add wings (for simple up/down animation)
var leftWing = self.attachAsset('birdWing', {
anchorX: 0.9,
anchorY: 0.5,
x: -85,
y: 0,
scaleX: 1.7,
scaleY: 1.7
});
var rightWing = self.attachAsset('birdWing', {
anchorX: 0.1,
anchorY: 0.5,
x: 85,
y: 0,
scaleX: 1.7,
scaleY: 1.7
});
rightWing.scaleY = 1;
leftWing.scaleY = 1;
// Bird movement
self.speed = 3 + Math.random() * 2.5; // px per frame (slower)
self.dir = Math.random() < 0.5 ? 1 : -1; // 1: left->right, -1: right->left
self.amplitude = 60 + Math.random() * 80; // vertical sine amplitude
self.freq = 0.002 + Math.random() * 0.001; // vertical sine frequency (slower)
self.baseY = 0;
self.t = 0;
self.isAlive = true;
self.hasDroppedBomb = false;
// For bomb drop
self.lastHit = false;
// Animate wings
self.update = function () {
if (!self.isAlive) return;
self.t += 1;
// Sine wave vertical movement
self.y = self.baseY + Math.sin(self.t * self.freq * 2 * Math.PI) * self.amplitude;
self.x += self.speed * self.dir;
// Animate wings
var wingAngle = Math.sin(self.t * 0.25) * 0.7;
leftWing.rotation = -wingAngle;
rightWing.rotation = wingAngle;
// Bomb drop logic is now handled in game.update for sequential dropping
// Remove if off screen
if (self.dir === 1 && self.x > 2200 || self.dir === -1 && self.x < -200) {
self.destroy();
var idx = birds.indexOf(self);
if (idx !== -1) birds.splice(idx, 1);
}
};
// Called when hit by bullet
self.hit = function () {
if (self.isStork) return; // Stork is invulnerable
if (!self.isAlive) return;
self.isAlive = false;
// Play hit sound
LK.getSound('birdHit').play();
// Flash bird
LK.effects.flashObject(self, 0xffffff, 200);
// Drop bomb
self.dropBomb();
// Remove bird after short delay
LK.setTimeout(function () {
self.destroy();
var idx = birds.indexOf(self);
if (idx !== -1) birds.splice(idx, 1);
}, 200);
};
// Drop bomb
self.dropBomb = function () {
// Remove single-bomb restriction for random bomb drops
var bomb = new Bomb();
bomb.x = self.x;
bomb.y = self.y + 40;
// Bomb gets a random horizontal velocity
bomb.vx = (Math.random() - 0.5) * 12;
// Calculate bomb speed: base is a bit faster, increase by 1 for every 10 score
var bombBaseVy = 8 + Math.random() * 4; // faster base speed
var bombSpeedBonus = 0;
if (typeof score !== "undefined") {
bombSpeedBonus = Math.floor(score / 10);
}
bomb.vy = bombBaseVy + bombSpeedBonus;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
};
return self;
});
// Bomb class
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bomb = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 14;
self.gravity = 0.7;
self.landed = false;
self.update = function () {
if (self.landed) return;
self.x += self.vx;
self.y += self.vy;
self.vy += self.gravity;
// If hits ground (bottom 180px)
if (self.y > 2732 - 180) {
self.landed = true;
self.explode();
}
};
self.explode = function () {
// Play explosion sound
LK.getSound('explosion').play();
// Show explosion effect
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: 2732 - 120,
scaleX: 0.5,
scaleY: 0.5
});
game.addChild(explosion);
tween(explosion, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Remove bomb
LK.setTimeout(function () {
self.destroy();
var idx = bombs.indexOf(self);
if (idx !== -1) bombs.splice(idx, 1);
}, 100);
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -32; // Upwards
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
// Body
var body = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Gun
var gun = self.attachAsset('gun', {
anchorX: 1,
// align right edge of gun to player
anchorY: 0.5,
// middle vertically
x: body.width / 2,
// move to right edge of player body
y: 0 // align vertically to center of player
});
// For drag
self.isDragging = false;
// For shooting cooldown
self.lastShotTick = -100;
// For hit flash
self.flashTimeout = null;
// Flash effect
self.flash = function () {
if (self.flashTimeout) {
LK.clearTimeout(self.flashTimeout);
}
body.tint = 0xff0000;
self.flashTimeout = LK.setTimeout(function () {
body.tint = 0x222222;
self.flashTimeout = null;
}, 200);
};
// Add hold-to-shoot on player
self.down = function (x, y, obj) {
// Only allow shooting if not dragging (to avoid double fire on drag)
if (!self.isDragging) {
shootBullet();
// Start interval for continuous shooting
if (!self.shootInterval) {
self.shootInterval = LK.setInterval(function () {
shootBullet();
}, 120);
}
}
};
self.up = function (x, y, obj) {
// Stop continuous shooting
if (self.shootInterval) {
LK.clearInterval(self.shootInterval);
self.shootInterval = null;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Play music
// Sounds
// Explosion (for bomb impact)
// Bomb
// Bullet
// Gun barrel
// Player: rectangle
// Bird wing (for simple animation)
// Birds: 3 colors, simple ellipses
// Play music
LK.playMusic('bgmusic');
// Add background image
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 2048 / 100,
// asset width is 100, scale to fit game width
scaleY: 2732 / 100 // asset height is 100, scale to fit game height
});
game.addChildAt(background, 0); // Add as the bottom-most layer
// Arrays for game objects
var birds = [];
var bullets = [];
var bombs = [];
// For sequential bomb drop
var nextBirdToDropBomb = 0;
// Score
var score = 0;
// Stork logic
var storkActive = false;
var storkScoreStart = 0;
var stork = null;
// Player
var player = new Player();
game.addChild(player);
player.x = 2048 / 2;
player.y = 2732 - 180;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Dragging
var dragNode = null;
// For shooting
function shootBullet() {
// Cooldown: 10 ticks
if (LK.ticks - player.lastShotTick < 10) return;
player.lastShotTick = LK.ticks;
var bullet = new Bullet();
// Find gun tip position relative to player
var gunOffsetX = player.x + (player.width ? player.width / 2 : 160) + 20 + 15; // gun width/2
var gunOffsetY = player.y - 70 - 60; // gun y + gun height
// But since gun is attached to player, get its position
if (player.children && player.children.length > 1) {
var gunObj = player.children[1];
// gunObj.x/y are relative to player
bullet.x = player.x + gunObj.x + gunObj.width / 2;
bullet.y = player.y + gunObj.y - gunObj.height;
} else {
bullet.x = player.x + 175;
bullet.y = player.y - 130;
}
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
// Move handler
function handleMove(x, y, obj) {
// Clamp x to avoid left menu
var minX = 120;
var maxX = 2048 - 120;
if (dragNode === player) {
player.x = Math.max(minX, Math.min(maxX, x));
// Update lastPlayerMoveTick on movement
lastPlayerMoveTick = LK.ticks;
bombedForNoPlayerMove = false;
}
}
// Touch/mouse events
game.down = function (x, y, obj) {
// Only drag if touch is on lower 1/3 of screen
if (y > 2732 - 600) {
dragNode = player;
handleMove(x, y, obj);
} else {
// Shoot if tap upper area
shootBullet();
}
};
game.move = function (x, y, obj) {
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
// Stop continuous shooting if touch is released anywhere
if (player.shootInterval) {
LK.clearInterval(player.shootInterval);
player.shootInterval = null;
}
};
// Spawn birds at intervals
var birdSpawnTimer = 0;
function spawnBird() {
var bird = new Bird();
// Random Y in upper 2/3
bird.baseY = 200 + Math.random() * 1200;
// Start at left or right
if (bird.dir === 1) {
bird.x = -100;
} else {
bird.x = 2048 + 100;
}
bird.y = bird.baseY;
birds.push(bird);
game.addChild(bird);
}
// Main update loop
game.update = function () {
// Determine max birds: 2 at start, +1 for every 10 score
var maxBirds = 2 + Math.floor(score / 10);
// Stork logic: spawn if score > 30, not already active, and not present
if (score > 30 && !storkActive && !stork) {
stork = new Bird(true); // true = isStork
// Place stork at random Y in upper 2/3, random direction
stork.baseY = 200 + Math.random() * 1200;
stork.dir = Math.random() < 0.5 ? 1 : -1;
if (stork.dir === 1) {
stork.x = -100;
} else {
stork.x = 2048 + 100;
}
stork.y = stork.baseY;
birds.push(stork);
game.addChild(stork);
storkActive = true;
storkScoreStart = score;
}
// Remove stork after 3 score increments
if (storkActive && stork && score >= storkScoreStart + 3) {
if (birds.indexOf(stork) !== -1) {
stork.destroy();
birds.splice(birds.indexOf(stork), 1);
}
stork = null;
storkActive = false;
}
// Spawn birds
if (LK.ticks % 40 === 0 && birds.length < maxBirds) {
spawnBird();
}
// Update birds
for (var i = birds.length - 1; i >= 0; i--) {
var bird = birds[i];
bird.update();
}
// Sequential bomb drop logic: only one bird drops a bomb at a time, in order
if (birds.length > 0) {
// Find the next bird eligible to drop a bomb
var found = false;
for (var i = 0; i < birds.length; i++) {
var idx = (nextBirdToDropBomb + i) % birds.length;
var bird = birds[idx];
if (bird.isAlive && !bird.hasDroppedBomb) {
bird.dropBomb();
bird.hasDroppedBomb = true;
nextBirdToDropBomb = (idx + 1) % birds.length;
found = true;
break;
}
}
// Reset hasDroppedBomb for dead or offscreen birds
for (var i = 0; i < birds.length; i++) {
var bird = birds[i];
if (!bird.isAlive) {
bird.hasDroppedBomb = false;
}
}
}
// --- 10 seconds no bird hit bomb/gameover logic ---
if (typeof lastBirdHitTick === "undefined") {
var lastBirdHitTick = LK.ticks;
}
if (typeof bombedForNoHit === "undefined") {
var bombedForNoHit = false;
}
// --- 10 seconds no player movement bomb/gameover logic ---
if (typeof lastPlayerMoveTick === "undefined") {
var lastPlayerMoveTick = LK.ticks;
}
if (typeof bombedForNoPlayerMove === "undefined") {
var bombedForNoPlayerMove = false;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove if off screen
if (bullet.y < -60) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with birds
for (var j = 0; j < birds.length; j++) {
var bird = birds[j];
if (bird.isAlive && bullet.intersects(bird)) {
if (bird.isStork) {
// Stork: ignore hit, just destroy bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
// Hit!
bird.hit();
bullet.destroy();
bullets.splice(i, 1);
// Score
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Add simple explosion effect at bird position
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: bird.x,
y: bird.y,
scaleX: 0.5,
scaleY: 0.5
});
game.addChild(explosion);
tween(explosion, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// --- Reset no-hit timer on bird hit ---
lastBirdHitTick = LK.ticks;
bombedForNoHit = false;
break;
}
}
}
// --- Check for 10 seconds without bird hit ---
if (!bombedForNoHit && LK.ticks - lastBirdHitTick > 600) {
// Drop a bomb at player's position and end game
bombedForNoHit = true;
var bomb = new Bomb();
bomb.x = player.x;
bomb.y = player.y - 120;
bomb.vx = 0;
bomb.vy = 18;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
// Flash and show game over after short delay for bomb to "land"
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}, 400);
}
// --- Check for 10 seconds of player inactivity ---
if (!bombedForNoPlayerMove && LK.ticks - lastPlayerMoveTick > 600) {
bombedForNoPlayerMove = true;
var bomb = new Bomb();
bomb.x = player.x;
bomb.y = player.y - 120;
bomb.vx = 0;
bomb.vy = 18;
bombs.push(bomb);
game.addChild(bomb);
LK.getSound('bombDrop').play();
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}, 400);
}
// Update bombs
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
bomb.update();
// Check collision with player (if not landed)
if (!bomb.landed && bomb.intersects(player)) {
// Player hit!
player.flash();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
};