/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Obstacle: Acid Pool var AcidPool = Container.expand(function () { var self = Container.call(this); var acid = self.attachAsset('acid_pool', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 1; return self; }); // Bird class: each bird has a type, unique ability, and can be controlled var Bird = Container.expand(function () { var self = Container.call(this); // Properties self.type = 'red'; // 'red', 'blue', 'yellow' self.isActive = false; self.isOnGround = false; self.isBubbled = false; self.bubbleTimer = 0; // Attach correct asset var assetId = 'bird_red'; if (self.type === 'blue') assetId = 'bird_blue'; if (self.type === 'yellow') assetId = 'bird_yellow'; var birdSprite = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Physics self.vx = 0; self.vy = 0; self.gravity = 1.5; self.jumpPower = -38; self.moveSpeed = 18; // Ability cooldowns self.abilityReady = true; self.abilityCooldown = 0; // Set bird type and adjust stats self.setType = function (type) { self.type = type; if (type === 'red') { birdSprite.assetId = 'bird_red'; self.jumpPower = -38; self.moveSpeed = 18; } else if (type === 'blue') { birdSprite.assetId = 'bird_blue'; self.jumpPower = -32; self.moveSpeed = 24; } else if (type === 'yellow') { birdSprite.assetId = 'bird_yellow'; self.jumpPower = -28; self.moveSpeed = 16; } }; // Activate/deactivate self.setActive = function (active) { self.isActive = active; birdSprite.alpha = active ? 1 : 0.5; if (active) { tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); } }; // Bird jump self.jump = function () { if (self.isOnGround && !self.isBubbled) { self.vy = self.jumpPower; self.isOnGround = false; LK.getSound('jump').play(); } }; // Bird ability self.useAbility = function () { if (!self.abilityReady || self.isBubbled) return; if (self.type === 'red') { // Red: invulnerable for 1s (flashes) self.abilityReady = false; self.invulnerable = true; var flashCount = 0; var flashTimer = LK.setInterval(function () { birdSprite.alpha = birdSprite.alpha === 1 ? 0.3 : 1; flashCount++; if (flashCount > 8) { LK.clearInterval(flashTimer); birdSprite.alpha = self.isActive ? 1 : 0.5; self.invulnerable = false; self.abilityCooldown = 60; } }, 120); } else if (self.type === 'blue') { // Blue: dash forward self.abilityReady = false; self.vx += (self.facingRight ? 1 : -1) * 60; self.abilityCooldown = 60; } else if (self.type === 'yellow') { // Yellow: bubble float (becomes bubbled for 1.2s) self.abilityReady = false; self.isBubbled = true; self.bubbleTimer = 72; LK.getSound('bubble_pop').play(); self.abilityCooldown = 90; } }; // Update per frame self.update = function () { // Ability cooldown if (!self.abilityReady) { self.abilityCooldown--; if (self.abilityCooldown <= 0) { self.abilityReady = true; } } // Bubble float if (self.isBubbled) { self.vy = -6; self.bubbleTimer--; if (self.bubbleTimer <= 0) { self.isBubbled = false; } } else { // Gravity self.vy += self.gravity; } // Clamp vy if (self.vy > 40) self.vy = 40; // Move self.x += self.vx; self.y += self.vy; // Friction self.vx *= 0.82; if (Math.abs(self.vx) < 1) self.vx = 0; // Clamp to stomach bounds if (self.x < 200) self.x = 200; if (self.x > 2048 - 200) self.x = 2048 - 200; if (self.y < 300) self.y = 300; if (self.y > 2732 - 200) { self.y = 2732 - 200; self.vy = 0; self.isOnGround = true; } }; return self; }); // Obstacle: Bubble (for yellow bird to float) var Bubble = Container.expand(function () { var self = Container.call(this); var bubble = self.attachAsset('bubble', { anchorX: 0.5, anchorY: 0.5 }); self.active = true; return self; }); // Exit: Esophagus var Exit = Container.expand(function () { var self = Container.call(this); var exit = self.attachAsset('exit', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Obstacle: Spike var Spike = Container.expand(function () { var self = Container.call(this); var spike = self.attachAsset('spike', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Music // Sound effects // Exit: esophagus (brown ellipse) // Obstacles: acid pool (green), spike (purple triangle), bubble (blue ellipse) // Crab stomach background (large ellipse, light pink) // Bird assets: three birds, each with a unique color and shape // Play music LK.playMusic('crabbelly_theme'); // Add stomach background var stomach = LK.getAsset('crab_stomach', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); game.addChild(stomach); // Obstacles var obstacles = []; var acid1 = new AcidPool(); acid1.x = 1024; acid1.y = 1800; game.addChild(acid1); obstacles.push(acid1); var acid2 = new AcidPool(); acid2.x = 600; acid2.y = 1200; game.addChild(acid2); obstacles.push(acid2); var spike1 = new Spike(); spike1.x = 1500; spike1.y = 900; game.addChild(spike1); obstacles.push(spike1); var spike2 = new Spike(); spike2.x = 500; spike2.y = 600; game.addChild(spike2); obstacles.push(spike2); var bubble1 = new Bubble(); bubble1.x = 900; bubble1.y = 1550; game.addChild(bubble1); obstacles.push(bubble1); var bubble2 = new Bubble(); bubble2.x = 1300; bubble2.y = 700; game.addChild(bubble2); obstacles.push(bubble2); // Exit var exit = new Exit(); exit.x = 1024; exit.y = 400; game.addChild(exit); // Birds var birds = []; var birdRed = new Bird(); birdRed.setType('red'); birdRed.x = 1024; birdRed.y = 2200; birdRed.facingRight = true; game.addChild(birdRed); birds.push(birdRed); var birdBlue = new Bird(); birdBlue.setType('blue'); birdBlue.x = 1124; birdBlue.y = 2250; birdBlue.facingRight = true; game.addChild(birdBlue); birds.push(birdBlue); var birdYellow = new Bird(); birdYellow.setType('yellow'); birdYellow.x = 924; birdYellow.y = 2250; birdYellow.facingRight = true; game.addChild(birdYellow); birds.push(birdYellow); // Active bird index var activeBirdIndex = 0; birds[activeBirdIndex].setActive(true); // Health and timer var health = 3; var maxTime = 60 * 30; // 30 seconds var timeLeft = maxTime; // Score text (shows time left) var timerTxt = new Text2('Time: 30', { size: 90, fill: '#fff' }); timerTxt.anchor.set(0.5, 0); LK.gui.top.addChild(timerTxt); var healthTxt = new Text2('❤️❤️❤️', { size: 90, fill: '#fff' }); healthTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(healthTxt); // Switch bird button (bottom center) var switchTxt = new Text2('Switch Bird', { size: 80, fill: '#fff' }); switchTxt.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(switchTxt); // Ability button (bottom right) var abilityTxt = new Text2('Ability', { size: 80, fill: '#fff' }); abilityTxt.anchor.set(0.5, 0.5); LK.gui.bottomRight.addChild(abilityTxt); // Dragging var dragNode = null; var dragOffsetX = 0; var dragOffsetY = 0; // Touch controls: tap left/right to move, tap above to jump, tap switch/ability var lastTouchX = 0; var lastTouchY = 0; // Helper: update health display function updateHealth() { var s = ''; for (var i = 0; i < health; i++) s += '❤️'; healthTxt.setText(s); } // Helper: update timer display function updateTimer() { var t = Math.ceil(timeLeft / 60); timerTxt.setText('Time: ' + t); } // Helper: switch active bird function switchBird() { birds[activeBirdIndex].setActive(false); activeBirdIndex = (activeBirdIndex + 1) % birds.length; birds[activeBirdIndex].setActive(true); LK.getSound('switch').play(); } // Helper: use ability function useAbility() { birds[activeBirdIndex].useAbility(); } // Helper: check collision between two objects function collides(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); var r1 = (a.width ? a.width : 120) / 2; var r2 = (b.width ? b.width : 120) / 2; return dist < (r1 + r2) * 0.8; } // Game move handler (drag to move bird, tap to jump) game.move = function (x, y, obj) { // Only allow drag if started on bird if (dragNode) { dragNode.x = x - dragOffsetX; dragNode.y = y - dragOffsetY; } lastTouchX = x; lastTouchY = y; }; // Touch down: check if on bird, switch, or ability game.down = function (x, y, obj) { // Check if on switch button var guiSwitch = LK.gui.bottom.toLocal({ x: x, y: y }); if (switchTxt.containsPoint && switchTxt.containsPoint(guiSwitch)) { switchBird(); return; } // Check if on ability button var guiAbility = LK.gui.bottomRight.toLocal({ x: x, y: y }); if (abilityTxt.containsPoint && abilityTxt.containsPoint(guiAbility)) { useAbility(); return; } // Check if on active bird var bird = birds[activeBirdIndex]; var bx = bird.x, by = bird.y; var dx = x - bx, dy = y - by; if (dx * dx + dy * dy < 100 * 100) { dragNode = bird; dragOffsetX = x - bird.x; dragOffsetY = y - bird.y; } else { // If tap above bird, jump if (y < bird.y - 80) { bird.jump(); } else if (x < bird.x - 60) { bird.vx = -bird.moveSpeed; bird.facingRight = false; } else if (x > bird.x + 60) { bird.vx = bird.moveSpeed; bird.facingRight = true; } } }; // Touch up: stop drag game.up = function (x, y, obj) { dragNode = null; }; // Main update loop game.update = function () { // Timer timeLeft--; if (timeLeft < 0) { LK.getSound('lose').play(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } updateTimer(); // Update birds for (var i = 0; i < birds.length; i++) { birds[i].update(); } // Collisions: obstacles for (var i = 0; i < birds.length; i++) { var bird = birds[i]; // Acid for (var j = 0; j < obstacles.length; j++) { var obs = obstacles[j]; if (obs instanceof AcidPool) { if (collides(bird, obs)) { if (!bird.invulnerable && !bird.isBubbled) { health--; updateHealth(); LK.getSound('acid_sizzle').play(); LK.effects.flashObject(bird, 0x00ff00, 600); bird.invulnerable = true; // Temporary invulnerability (function (b) { var t = LK.setTimeout(function () { b.invulnerable = false; }, 900); })(bird); if (health <= 0) { LK.getSound('lose').play(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } } // Spikes if (obs instanceof Spike) { if (collides(bird, obs)) { if (!bird.invulnerable && !bird.isBubbled) { health--; updateHealth(); LK.effects.flashObject(bird, 0xaa00ff, 600); bird.invulnerable = true; (function (b) { var t = LK.setTimeout(function () { b.invulnerable = false; }, 900); })(bird); if (health <= 0) { LK.getSound('lose').play(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } } // Bubbles if (obs instanceof Bubble && obs.active) { if (collides(bird, obs)) { if (bird.type === 'yellow' && !bird.isBubbled) { bird.isBubbled = true; bird.bubbleTimer = 72; obs.active = false; obs.visible = false; LK.getSound('bubble_pop').play(); } } } } // Exit if (collides(bird, exit)) { // Only if all birds reach exit, win var allAtExit = true; for (var k = 0; k < birds.length; k++) { if (!collides(birds[k], exit)) allAtExit = false; } if (allAtExit) { LK.getSound('win').play(); LK.effects.flashScreen(0x00ff00, 1000); LK.showYouWin(); return; } } } }; // Initial health/timer display updateHealth(); updateTimer();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Obstacle: Acid Pool
var AcidPool = Container.expand(function () {
var self = Container.call(this);
var acid = self.attachAsset('acid_pool', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 1;
return self;
});
// Bird class: each bird has a type, unique ability, and can be controlled
var Bird = Container.expand(function () {
var self = Container.call(this);
// Properties
self.type = 'red'; // 'red', 'blue', 'yellow'
self.isActive = false;
self.isOnGround = false;
self.isBubbled = false;
self.bubbleTimer = 0;
// Attach correct asset
var assetId = 'bird_red';
if (self.type === 'blue') assetId = 'bird_blue';
if (self.type === 'yellow') assetId = 'bird_yellow';
var birdSprite = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Physics
self.vx = 0;
self.vy = 0;
self.gravity = 1.5;
self.jumpPower = -38;
self.moveSpeed = 18;
// Ability cooldowns
self.abilityReady = true;
self.abilityCooldown = 0;
// Set bird type and adjust stats
self.setType = function (type) {
self.type = type;
if (type === 'red') {
birdSprite.assetId = 'bird_red';
self.jumpPower = -38;
self.moveSpeed = 18;
} else if (type === 'blue') {
birdSprite.assetId = 'bird_blue';
self.jumpPower = -32;
self.moveSpeed = 24;
} else if (type === 'yellow') {
birdSprite.assetId = 'bird_yellow';
self.jumpPower = -28;
self.moveSpeed = 16;
}
};
// Activate/deactivate
self.setActive = function (active) {
self.isActive = active;
birdSprite.alpha = active ? 1 : 0.5;
if (active) {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeIn
});
}
});
}
};
// Bird jump
self.jump = function () {
if (self.isOnGround && !self.isBubbled) {
self.vy = self.jumpPower;
self.isOnGround = false;
LK.getSound('jump').play();
}
};
// Bird ability
self.useAbility = function () {
if (!self.abilityReady || self.isBubbled) return;
if (self.type === 'red') {
// Red: invulnerable for 1s (flashes)
self.abilityReady = false;
self.invulnerable = true;
var flashCount = 0;
var flashTimer = LK.setInterval(function () {
birdSprite.alpha = birdSprite.alpha === 1 ? 0.3 : 1;
flashCount++;
if (flashCount > 8) {
LK.clearInterval(flashTimer);
birdSprite.alpha = self.isActive ? 1 : 0.5;
self.invulnerable = false;
self.abilityCooldown = 60;
}
}, 120);
} else if (self.type === 'blue') {
// Blue: dash forward
self.abilityReady = false;
self.vx += (self.facingRight ? 1 : -1) * 60;
self.abilityCooldown = 60;
} else if (self.type === 'yellow') {
// Yellow: bubble float (becomes bubbled for 1.2s)
self.abilityReady = false;
self.isBubbled = true;
self.bubbleTimer = 72;
LK.getSound('bubble_pop').play();
self.abilityCooldown = 90;
}
};
// Update per frame
self.update = function () {
// Ability cooldown
if (!self.abilityReady) {
self.abilityCooldown--;
if (self.abilityCooldown <= 0) {
self.abilityReady = true;
}
}
// Bubble float
if (self.isBubbled) {
self.vy = -6;
self.bubbleTimer--;
if (self.bubbleTimer <= 0) {
self.isBubbled = false;
}
} else {
// Gravity
self.vy += self.gravity;
}
// Clamp vy
if (self.vy > 40) self.vy = 40;
// Move
self.x += self.vx;
self.y += self.vy;
// Friction
self.vx *= 0.82;
if (Math.abs(self.vx) < 1) self.vx = 0;
// Clamp to stomach bounds
if (self.x < 200) self.x = 200;
if (self.x > 2048 - 200) self.x = 2048 - 200;
if (self.y < 300) self.y = 300;
if (self.y > 2732 - 200) {
self.y = 2732 - 200;
self.vy = 0;
self.isOnGround = true;
}
};
return self;
});
// Obstacle: Bubble (for yellow bird to float)
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubble = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
return self;
});
// Exit: Esophagus
var Exit = Container.expand(function () {
var self = Container.call(this);
var exit = self.attachAsset('exit', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Obstacle: Spike
var Spike = Container.expand(function () {
var self = Container.call(this);
var spike = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Music
// Sound effects
// Exit: esophagus (brown ellipse)
// Obstacles: acid pool (green), spike (purple triangle), bubble (blue ellipse)
// Crab stomach background (large ellipse, light pink)
// Bird assets: three birds, each with a unique color and shape
// Play music
LK.playMusic('crabbelly_theme');
// Add stomach background
var stomach = LK.getAsset('crab_stomach', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
game.addChild(stomach);
// Obstacles
var obstacles = [];
var acid1 = new AcidPool();
acid1.x = 1024;
acid1.y = 1800;
game.addChild(acid1);
obstacles.push(acid1);
var acid2 = new AcidPool();
acid2.x = 600;
acid2.y = 1200;
game.addChild(acid2);
obstacles.push(acid2);
var spike1 = new Spike();
spike1.x = 1500;
spike1.y = 900;
game.addChild(spike1);
obstacles.push(spike1);
var spike2 = new Spike();
spike2.x = 500;
spike2.y = 600;
game.addChild(spike2);
obstacles.push(spike2);
var bubble1 = new Bubble();
bubble1.x = 900;
bubble1.y = 1550;
game.addChild(bubble1);
obstacles.push(bubble1);
var bubble2 = new Bubble();
bubble2.x = 1300;
bubble2.y = 700;
game.addChild(bubble2);
obstacles.push(bubble2);
// Exit
var exit = new Exit();
exit.x = 1024;
exit.y = 400;
game.addChild(exit);
// Birds
var birds = [];
var birdRed = new Bird();
birdRed.setType('red');
birdRed.x = 1024;
birdRed.y = 2200;
birdRed.facingRight = true;
game.addChild(birdRed);
birds.push(birdRed);
var birdBlue = new Bird();
birdBlue.setType('blue');
birdBlue.x = 1124;
birdBlue.y = 2250;
birdBlue.facingRight = true;
game.addChild(birdBlue);
birds.push(birdBlue);
var birdYellow = new Bird();
birdYellow.setType('yellow');
birdYellow.x = 924;
birdYellow.y = 2250;
birdYellow.facingRight = true;
game.addChild(birdYellow);
birds.push(birdYellow);
// Active bird index
var activeBirdIndex = 0;
birds[activeBirdIndex].setActive(true);
// Health and timer
var health = 3;
var maxTime = 60 * 30; // 30 seconds
var timeLeft = maxTime;
// Score text (shows time left)
var timerTxt = new Text2('Time: 30', {
size: 90,
fill: '#fff'
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
var healthTxt = new Text2('❤️❤️❤️', {
size: 90,
fill: '#fff'
});
healthTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(healthTxt);
// Switch bird button (bottom center)
var switchTxt = new Text2('Switch Bird', {
size: 80,
fill: '#fff'
});
switchTxt.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(switchTxt);
// Ability button (bottom right)
var abilityTxt = new Text2('Ability', {
size: 80,
fill: '#fff'
});
abilityTxt.anchor.set(0.5, 0.5);
LK.gui.bottomRight.addChild(abilityTxt);
// Dragging
var dragNode = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Touch controls: tap left/right to move, tap above to jump, tap switch/ability
var lastTouchX = 0;
var lastTouchY = 0;
// Helper: update health display
function updateHealth() {
var s = '';
for (var i = 0; i < health; i++) s += '❤️';
healthTxt.setText(s);
}
// Helper: update timer display
function updateTimer() {
var t = Math.ceil(timeLeft / 60);
timerTxt.setText('Time: ' + t);
}
// Helper: switch active bird
function switchBird() {
birds[activeBirdIndex].setActive(false);
activeBirdIndex = (activeBirdIndex + 1) % birds.length;
birds[activeBirdIndex].setActive(true);
LK.getSound('switch').play();
}
// Helper: use ability
function useAbility() {
birds[activeBirdIndex].useAbility();
}
// Helper: check collision between two objects
function collides(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var r1 = (a.width ? a.width : 120) / 2;
var r2 = (b.width ? b.width : 120) / 2;
return dist < (r1 + r2) * 0.8;
}
// Game move handler (drag to move bird, tap to jump)
game.move = function (x, y, obj) {
// Only allow drag if started on bird
if (dragNode) {
dragNode.x = x - dragOffsetX;
dragNode.y = y - dragOffsetY;
}
lastTouchX = x;
lastTouchY = y;
};
// Touch down: check if on bird, switch, or ability
game.down = function (x, y, obj) {
// Check if on switch button
var guiSwitch = LK.gui.bottom.toLocal({
x: x,
y: y
});
if (switchTxt.containsPoint && switchTxt.containsPoint(guiSwitch)) {
switchBird();
return;
}
// Check if on ability button
var guiAbility = LK.gui.bottomRight.toLocal({
x: x,
y: y
});
if (abilityTxt.containsPoint && abilityTxt.containsPoint(guiAbility)) {
useAbility();
return;
}
// Check if on active bird
var bird = birds[activeBirdIndex];
var bx = bird.x,
by = bird.y;
var dx = x - bx,
dy = y - by;
if (dx * dx + dy * dy < 100 * 100) {
dragNode = bird;
dragOffsetX = x - bird.x;
dragOffsetY = y - bird.y;
} else {
// If tap above bird, jump
if (y < bird.y - 80) {
bird.jump();
} else if (x < bird.x - 60) {
bird.vx = -bird.moveSpeed;
bird.facingRight = false;
} else if (x > bird.x + 60) {
bird.vx = bird.moveSpeed;
bird.facingRight = true;
}
}
};
// Touch up: stop drag
game.up = function (x, y, obj) {
dragNode = null;
};
// Main update loop
game.update = function () {
// Timer
timeLeft--;
if (timeLeft < 0) {
LK.getSound('lose').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
updateTimer();
// Update birds
for (var i = 0; i < birds.length; i++) {
birds[i].update();
}
// Collisions: obstacles
for (var i = 0; i < birds.length; i++) {
var bird = birds[i];
// Acid
for (var j = 0; j < obstacles.length; j++) {
var obs = obstacles[j];
if (obs instanceof AcidPool) {
if (collides(bird, obs)) {
if (!bird.invulnerable && !bird.isBubbled) {
health--;
updateHealth();
LK.getSound('acid_sizzle').play();
LK.effects.flashObject(bird, 0x00ff00, 600);
bird.invulnerable = true;
// Temporary invulnerability
(function (b) {
var t = LK.setTimeout(function () {
b.invulnerable = false;
}, 900);
})(bird);
if (health <= 0) {
LK.getSound('lose').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
}
// Spikes
if (obs instanceof Spike) {
if (collides(bird, obs)) {
if (!bird.invulnerable && !bird.isBubbled) {
health--;
updateHealth();
LK.effects.flashObject(bird, 0xaa00ff, 600);
bird.invulnerable = true;
(function (b) {
var t = LK.setTimeout(function () {
b.invulnerable = false;
}, 900);
})(bird);
if (health <= 0) {
LK.getSound('lose').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
}
// Bubbles
if (obs instanceof Bubble && obs.active) {
if (collides(bird, obs)) {
if (bird.type === 'yellow' && !bird.isBubbled) {
bird.isBubbled = true;
bird.bubbleTimer = 72;
obs.active = false;
obs.visible = false;
LK.getSound('bubble_pop').play();
}
}
}
}
// Exit
if (collides(bird, exit)) {
// Only if all birds reach exit, win
var allAtExit = true;
for (var k = 0; k < birds.length; k++) {
if (!collides(birds[k], exit)) allAtExit = false;
}
if (allAtExit) {
LK.getSound('win').play();
LK.effects.flashScreen(0x00ff00, 1000);
LK.showYouWin();
return;
}
}
}
};
// Initial health/timer display
updateHealth();
updateTimer();