/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
self.type = 'red'; // 'red', 'blue', 'yellow'
self.radius = 60;
self.launched = false;
self.vx = 0;
self.vy = 0;
self.gravity = 1.2;
self.trailTimer = 0;
self.trailInterval = 3; // frames
self.trail = [];
self.powerUsed = false;
self.alive = true;
// Attach asset based on type
self.setType = function (type) {
self.type = type;
if (self.birdAsset) self.removeChild(self.birdAsset);
var assetId = 'birdRed';
if (type === 'blue') assetId = 'birdBlue';
if (type === 'yellow') assetId = 'birdYellow';
self.birdAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.birdAsset.width / 2;
};
self.setType('red');
// Launch bird with velocity
self.launch = function (vx, vy) {
self.vx = vx;
self.vy = vy;
self.launched = true;
self.trailTimer = 0;
self.powerUsed = false;
self.alive = true;
};
// Bird special power (tap in air)
self.usePower = function () {
if (self.powerUsed || !self.launched) return;
self.powerUsed = true;
if (self.type === 'blue') {
// Split into 3 birds
game.spawnSplitBirds(self);
} else if (self.type === 'yellow') {
// Speed boost
self.vx *= 1.7;
self.vy *= 1.1;
LK.effects.flashObject(self, 0xffff00, 300);
} else if (self.type === 'red') {
// Red: screen shake
game.cameraShake(20, 300);
}
};
// Update per frame
self.update = function () {
if (!self.launched || !self.alive) return;
self.vy += self.gravity;
self.x += self.vx;
self.y += self.vy;
// --- Vomit dot trail effect ---
if (!self.vomitTrail) self.vomitTrail = [];
if (!self.lastVomitX) self.lastVomitX = self.x;
if (!self.lastVomitY) self.lastVomitY = self.y;
// Only spawn a vomit dot if the bird is moving fast enough and in the air
if (self.launched && Math.abs(self.vx) + Math.abs(self.vy) > 6) {
// Place a dot every 40px of movement
var dx = self.x - self.lastVomitX;
var dy = self.y - self.lastVomitY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 40) {
var vomitDot = LK.getAsset('trailDot', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.7,
scaleX: 1.1,
scaleY: 0.7,
tint: 0xB8FF5A // light green/yellow for 'vomit'
});
game.addChild(vomitDot);
self.vomitTrail.push(vomitDot);
tween(vomitDot, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.2
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
vomitDot.destroy();
}
});
if (self.vomitTrail.length > 20) {
var oldVomit = self.vomitTrail.shift();
if (oldVomit) oldVomit.destroy();
}
self.lastVomitX = self.x;
self.lastVomitY = self.y;
}
}
// Trail effect
self.trailTimer++;
if (self.trailTimer >= self.trailInterval) {
self.trailTimer = 0;
var dot = LK.getAsset('trailDot', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(dot);
self.trail.push(dot);
tween(dot, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
dot.destroy();
}
});
if (self.trail.length > 12) {
var old = self.trail.shift();
if (old) old.destroy();
}
}
// Out of bounds
if (self.x < -200 || self.x > 2248 || self.y > 3000) {
self.alive = false;
self.destroy();
}
};
return self;
});
// Block class
var Block = Container.expand(function () {
var self = Container.call(this);
self.type = 'wood'; // 'wood', 'stone', 'glass'
self.hp = 3;
self.width = 200;
self.height = 60;
self.blockAsset = null;
self.broken = false;
self.setType = function (type) {
self.type = type;
if (self.blockAsset) self.removeChild(self.blockAsset);
var assetId = 'blockWood';
if (type === 'stone') assetId = 'blockStone';
if (type === 'glass') assetId = 'blockGlass';
self.blockAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.blockAsset.width;
self.height = self.blockAsset.height;
if (type === 'glass') self.hp = 1;else if (type === 'wood') self.hp = 2;else if (type === 'stone') self.hp = 4;
};
self.setType('wood');
self.hit = function (force) {
self.hp -= force;
LK.getSound('break').play();
LK.effects.flashObject(self, 0xffffff, 120);
if (self.hp <= 0 && !self.broken) {
self.broken = true;
game.spawnDebris(self.x, self.y, self.type);
self.destroy();
}
};
return self;
});
// Particle (for debris/explosion)
var Particle = Container.expand(function () {
var self = Container.call(this);
self.vx = 0;
self.vy = 0;
self.life = 30;
self.asset = null;
self.init = function (type, color) {
var assetId = 'debris';
if (type === 'explosion') assetId = 'explosion';
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
tint: color
});
};
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += 0.7;
self.life--;
self.asset.alpha = self.life / 30;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
// Pig class
var Pig = Container.expand(function () {
var self = Container.call(this);
self.radius = 60;
self.alive = true;
self.pigAsset = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 2;
self.hit = function (force) {
self.hp -= force;
LK.getSound('pigOink').play();
LK.effects.flashObject(self, 0xffffff, 200);
if (self.hp <= 0) {
self.die();
}
};
self.die = function () {
self.alive = false;
game.spawnExplosion(self.x, self.y, 0x7ed957);
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Camera shake variables
// Bird types
// Pig
// Block types
// Slingshot base
// Trail particle
// Debris particle
// Explosion particle
// Sound effects
// Music
var cameraShakeTime = 0;
var cameraShakeStrength = 0;
// Game state
var birds = [];
var pigs = [];
var blocks = [];
var particles = [];
var currentBird = null;
var slingshotBase = null;
var slingshotPos = {
x: 400,
y: 2000
};
var slingshotRadius = 180;
var dragStart = null;
var dragging = false;
var launchLine = null;
var birdsQueue = [];
var levelCleared = false;
var score = 0;
var scoreTxt = null;
var shotsTxt = null;
var shots = 0;
var slowmo = false;
var slowmoTimer = 0;
// GUI
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
shotsTxt = new Text2('Shots: 0', {
size: 70,
fill: "#fff"
});
shotsTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(shotsTxt);
// Combo system variables
var comboCount = 0;
var comboTimer = 0;
var comboTimerMax = 90; // 1.5 seconds at 60fps
var comboTxt = new Text2('', {
size: 110,
fill: 0xFF4081,
stroke: "#fff",
strokeThickness: 8
});
comboTxt.anchor.set(0.5, 0);
// Place combo text below the score, with good spacing for visibility
comboTxt.x = 2048 / 2;
comboTxt.y = scoreTxt.height + 60;
LK.gui.top.addChild(comboTxt);
// Level indicator
var levelTxtGui = new Text2('Level 1', {
size: 80,
fill: 0xFFEB3B,
stroke: "#333",
strokeThickness: 8
});
levelTxtGui.anchor.set(0.5, 0);
LK.gui.bottom.addChild(levelTxtGui);
// Update level indicator on level start
var oldSetupLevel = setupLevel;
setupLevel = function setupLevel() {
levelTxtGui.setText('Level ' + (currentLevel + 1));
oldSetupLevel();
};
// Add slingshot base
slingshotBase = LK.getAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1,
x: slingshotPos.x,
y: slingshotPos.y + 100
});
game.addChild(slingshotBase);
// Level definitions
var levels = [{
birds: ['red', 'blue', 'yellow'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}]
}, {
birds: ['red', 'red', 'blue', 'yellow'],
pigs: [{
x: 1550,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}]
}, {
birds: ['yellow', 'yellow', 'blue', 'red'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1750,
y: 2000
}, {
x: 1850,
y: 2200
}, {
x: 1700,
y: 2300
}],
blocks: [{
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2000
}, {
type: 'stone',
x: 1850,
y: 2200
}, {
type: 'wood',
x: 1700,
y: 2300
}, {
type: 'stone',
x: 1700,
y: 2240
}]
}, {
birds: ['blue', 'blue', 'yellow', 'red', 'red'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}, {
x: 1600,
y: 2000
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2200
}]
},
// Level 5: Tall tower, more blocks, more pigs
{
birds: ['yellow', 'red', 'blue', 'yellow', 'red'],
pigs: [{
x: 1700,
y: 1800
}, {
x: 1700,
y: 2000
}, {
x: 1700,
y: 2200
}],
blocks: [{
type: 'stone',
x: 1700,
y: 1850
}, {
type: 'wood',
x: 1700,
y: 1950
}, {
type: 'glass',
x: 1700,
y: 2050
}, {
type: 'wood',
x: 1700,
y: 2150
}, {
type: 'stone',
x: 1700,
y: 2250
}]
},
// Level 6: Wide fortress, more fun
{
birds: ['blue', 'blue', 'yellow', 'red', 'yellow'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1800,
y: 2100
}, {
x: 1650,
y: 2000
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1800,
y: 2200
}, {
type: 'stone',
x: 1650,
y: 2100
}, {
type: 'glass',
x: 1575,
y: 2150
}, {
type: 'glass',
x: 1725,
y: 2150
}, {
type: 'stone',
x: 1650,
y: 2000
}]
},
// Level 7: Pyramid
{
birds: ['red', 'yellow', 'blue', 'red', 'yellow'],
pigs: [{
x: 1650,
y: 2200
}, {
x: 1700,
y: 2100
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'stone',
x: 1700,
y: 2250
}, {
type: 'wood',
x: 1650,
y: 2250
}, {
type: 'wood',
x: 1750,
y: 2250
}, {
type: 'glass',
x: 1700,
y: 2200
}, {
type: 'glass',
x: 1675,
y: 2225
}, {
type: 'glass',
x: 1725,
y: 2225
}]
},
// Level 8: Pig bunker
{
birds: ['yellow', 'yellow', 'blue', 'red', 'blue'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1800,
y: 2100
}],
blocks: [{
type: 'stone',
x: 1600,
y: 2150
}, {
type: 'stone',
x: 1800,
y: 2150
}, {
type: 'wood',
x: 1700,
y: 2200
}, {
type: 'glass',
x: 1700,
y: 2100
}, {
type: 'wood',
x: 1700,
y: 2150
}]
},
// Level 9: Chaos fun
{
birds: ['blue', 'yellow', 'red', 'yellow', 'blue', 'red'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}, {
x: 1600,
y: 2000
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2200
}, {
type: 'glass',
x: 1700,
y: 2100
}]
},
// Level 10: The Grand Finale
{
birds: ['red', 'yellow', 'blue', 'yellow', 'red', 'blue'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1700,
y: 2000
}, {
x: 1800,
y: 2100
}, {
x: 1700,
y: 2200
}, {
x: 1750,
y: 2300
}],
blocks: [{
type: 'stone',
x: 1700,
y: 1950
}, {
type: 'wood',
x: 1600,
y: 2150
}, {
type: 'wood',
x: 1800,
y: 2150
}, {
type: 'glass',
x: 1700,
y: 2100
}, {
type: 'glass',
x: 1650,
y: 2200
}, {
type: 'glass',
x: 1750,
y: 2200
}, {
type: 'stone',
x: 1700,
y: 2250
}, {
type: 'wood',
x: 1700,
y: 2300
}]
}];
var currentLevel = 0;
// Level setup
function setupLevel() {
// Clear arrays
for (var i = 0; i < birds.length; i++) birds[i].destroy();
for (var i = 0; i < pigs.length; i++) pigs[i].destroy();
for (var i = 0; i < blocks.length; i++) blocks[i].destroy();
for (var i = 0; i < particles.length; i++) particles[i].destroy();
birds = [];
pigs = [];
blocks = [];
particles = [];
birdsQueue = [];
levelCleared = false;
score = 0;
shots = 0;
scoreTxt.setText('0');
shotsTxt.setText('Shots: 0');
slowmo = false;
slowmoTimer = 0;
comboCount = 0;
comboTimer = 0;
comboTxt.setText('');
// Clamp currentLevel to available levels
if (currentLevel < 0) currentLevel = 0;
if (currentLevel >= levels.length) currentLevel = levels.length - 1;
var level = levels[currentLevel];
// Birds queue
for (var i = 0; i < level.birds.length; i++) {
birdsQueue.push(level.birds[i]);
}
// Spawn first bird
spawnNextBird();
// Pigs
for (var i = 0; i < level.pigs.length; i++) {
var pig = new Pig();
pig.x = level.pigs[i].x;
pig.y = level.pigs[i].y;
game.addChild(pig);
pigs.push(pig);
}
// Blocks
for (var i = 0; i < level.blocks.length; i++) {
var block = new Block();
block.setType(level.blocks[i].type);
block.x = level.blocks[i].x;
block.y = level.blocks[i].y;
game.addChild(block);
blocks.push(block);
}
}
function spawnNextBird() {
if (birdsQueue.length === 0) {
// No more birds, check for loss
LK.setTimeout(function () {
if (!levelCleared) LK.showGameOver();
}, 1200);
return;
}
var type = birdsQueue.shift();
var bird = new Bird();
bird.setType(type);
bird.x = slingshotPos.x;
bird.y = slingshotPos.y;
game.addChild(bird);
birds.push(bird);
currentBird = bird;
dragging = false;
dragStart = null;
}
// Camera shake
game.cameraShake = function (strength, duration) {
cameraShakeStrength = strength;
cameraShakeTime = duration;
};
// Debris
game.spawnDebris = function (x, y, type) {
for (var i = 0; i < 8; i++) {
var p = new Particle();
p.init('debris', type === 'wood' ? 0xc2b280 : type === 'stone' ? 0xaaaaaa : 0x99e6ff);
p.x = x;
p.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = 8 + Math.random() * 8;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 4;
game.addChild(p);
particles.push(p);
}
};
// Explosion
game.spawnExplosion = function (x, y, color) {
LK.getSound('explosionSfx').play();
for (var i = 0; i < 12; i++) {
var p = new Particle();
p.init('explosion', color);
p.x = x;
p.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = 10 + Math.random() * 10;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 6;
game.addChild(p);
particles.push(p);
}
LK.effects.flashScreen(0xffff99, 200);
game.cameraShake(30, 400);
};
// Bird split (blue)
game.spawnSplitBirds = function (parentBird) {
for (var i = -1; i <= 1; i += 2) {
var bird = new Bird();
bird.setType('blue');
bird.x = parentBird.x;
bird.y = parentBird.y;
bird.launched = true;
bird.vx = parentBird.vx + i * 7;
bird.vy = parentBird.vy - 2;
bird.powerUsed = true;
game.addChild(bird);
birds.push(bird);
}
};
// SLOWMO
function triggerSlowmo() {
slowmo = true;
slowmoTimer = 40;
}
// Touch controls
game.down = function (x, y, obj) {
if (levelCleared) return;
if (!currentBird || currentBird.launched) return;
// Only allow drag if touch is near bird
var dx = x - currentBird.x,
dy = y - currentBird.y;
if (dx * dx + dy * dy < 180 * 180) {
dragging = true;
dragStart = {
x: x,
y: y
};
}
};
game.move = function (x, y, obj) {
if (dragging && currentBird && !currentBird.launched) {
// Limit drag distance
var dx = x - slingshotPos.x,
dy = y - slingshotPos.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > slingshotRadius) {
dx *= slingshotRadius / dist;
dy *= slingshotRadius / dist;
}
currentBird.x = slingshotPos.x + dx;
currentBird.y = slingshotPos.y + dy;
}
};
game.up = function (x, y, obj) {
if (dragging && currentBird && !currentBird.launched) {
// Launch
var dx = currentBird.x - slingshotPos.x,
dy = currentBird.y - slingshotPos.y;
currentBird.launch(-dx * 0.25, -dy * 0.25);
LK.getSound('launch').play();
shots++;
shotsTxt.setText('Shots: ' + shots);
dragging = false;
dragStart = null;
}
};
// Tap for bird power
game.on('down', function (x, y, obj) {
if (currentBird && currentBird.launched && !currentBird.powerUsed) {
currentBird.usePower();
}
});
// Main update
game.update = function () {
// Camera shake
if (cameraShakeTime > 0) {
cameraShakeTime -= 16;
var shakeX = (Math.random() - 0.5) * cameraShakeStrength;
var shakeY = (Math.random() - 0.5) * cameraShakeStrength;
game.x = shakeX;
game.y = shakeY;
} else {
game.x = 0;
game.y = 0;
}
// SLOWMO
var slowmoFactor = 1;
if (slowmo) {
slowmoFactor = 0.3;
slowmoTimer--;
if (slowmoTimer <= 0) slowmo = false;
}
// Update birds
for (var i = birds.length - 1; i >= 0; i--) {
var bird = birds[i];
if (bird.launched && bird.alive) {
// Slowmo
if (slowmo) {
bird.x += bird.vx * slowmoFactor;
bird.y += bird.vy * slowmoFactor;
bird.vy += bird.gravity * slowmoFactor;
} else {
bird.update();
}
// Collisions with blocks
for (var j = blocks.length - 1; j >= 0; j--) {
var block = blocks[j];
if (!block.broken && rectCircleCollide(block, bird)) {
block.hit(1);
LK.getSound('hit').play();
// Cartoonish bounce and squash effect
tween(block, {
scaleY: 0.7,
scaleX: 1.2
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(block, {
scaleY: 1,
scaleX: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(block, 0xff0000, 100);
// Exaggerated camera shake
game.cameraShake(18, 320);
// Add a burst of debris for extra cartoon effect
for (var d = 0; d < 3; d++) {
var p = new Particle();
p.init('debris', block.type === 'wood' ? 0xc2b280 : block.type === 'stone' ? 0xaaaaaa : 0x99e6ff);
p.x = block.x + (Math.random() - 0.5) * block.width * 0.7;
p.y = block.y + (Math.random() - 0.5) * block.height * 0.7;
var angle = Math.random() * Math.PI * 2;
var speed = 10 + Math.random() * 8;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 4;
game.addChild(p);
particles.push(p);
}
triggerSlowmo();
bird.vx *= 0.6;
bird.vy *= 0.6;
}
}
// Collisions with pigs
for (var j = pigs.length - 1; j >= 0; j--) {
var pig = pigs[j];
if (pig.alive && circleCircleCollide(bird, pig)) {
pig.hit(2);
LK.getSound('hit').play();
// Pig bounce and color flash
tween(pig, {
scaleY: 0.6,
scaleX: 1.3
}, {
duration: 90,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pig, {
scaleY: 1,
scaleX: 1
}, {
duration: 140,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(pig, 0x00ff00, 180);
// Big camera shake and a burst of confetti-like debris
game.cameraShake(28, 400);
for (var d = 0; d < 6; d++) {
var p = new Particle();
p.init('debris', 0x7ed957);
p.x = pig.x + (Math.random() - 0.5) * pig.radius * 1.2;
p.y = pig.y + (Math.random() - 0.5) * pig.radius * 1.2;
var angle = Math.random() * Math.PI * 2;
var speed = 12 + Math.random() * 10;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 6;
game.addChild(p);
particles.push(p);
}
triggerSlowmo();
bird.vx *= 0.7;
bird.vy *= 0.7;
score += 500;
scoreTxt.setText(score);
}
}
}
// Remove dead birds
if (!bird.alive) {
birds.splice(i, 1);
if (bird === currentBird) {
LK.setTimeout(function () {
spawnNextBird();
}, 700);
}
}
}
// Update pigs
for (var i = pigs.length - 1; i >= 0; i--) {
var pig = pigs[i];
if (!pig.alive) {
pigs.splice(i, 1);
score += 1000;
scoreTxt.setText(score);
// Combo system: pig destroyed triggers combo
comboCount++;
comboTimer = comboTimerMax;
comboTxt.setText('Combo x' + comboCount + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.25,
scaleY: 1.25,
alpha: 1
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
});
}
}
// Update blocks
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
if (block.broken) {
blocks.splice(i, 1);
score += 200;
scoreTxt.setText(score);
// Combo system: block destroyed triggers combo
comboCount++;
comboTimer = comboTimerMax;
comboTxt.setText('Combo x' + comboCount + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.18,
scaleY: 1.18,
alpha: 1
}, {
duration: 90,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 90,
easing: tween.easeOut
});
}
});
}
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var p = particles[i];
p.update();
if (p.life <= 0) {
particles.splice(i, 1);
}
}
// Combo timer logic
if (comboCount > 0) {
comboTimer--;
if (comboTimer <= 0) {
// Combo ended, award bonus if comboCount > 1
if (comboCount > 1) {
var bonus = comboCount * 300;
score += bonus;
scoreTxt.setText(score);
comboTxt.setText('Combo Bonus +' + bonus + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 1
}, {
duration: 180,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
comboTxt.setText('');
}
});
}
});
LK.effects.flashScreen(0xFF4081, 300);
game.cameraShake(18, 300);
} else {
comboTxt.setText('');
}
comboCount = 0;
comboTimer = 0;
}
}
// Win condition
if (!levelCleared && pigs.length === 0) {
levelCleared = true;
// Fun effects: screen flash, camera shake, confetti, sound, and more!
LK.effects.flashScreen(0x00ff00, 800);
LK.effects.flashScreen(0xff4081, 600);
LK.effects.flashScreen(0xffff00, 400);
game.cameraShake(60, 900);
LK.getSound('explosionSfx').play();
LK.getSound('break').play();
LK.getSound('hit').play();
LK.getSound('pigOink').play();
// Massive confetti burst (lots of colored particles)
for (var i = 0; i < 64; i++) {
var confetti = new Particle();
confetti.init('debris', [0xFFEB3B, 0xFF4081, 0x7ed957, 0x00bcd4, 0xffffff][Math.floor(Math.random() * 5)]);
confetti.x = 2048 / 2 + (Math.random() - 0.5) * 600;
confetti.y = 2732 / 2 + (Math.random() - 0.5) * 400;
var angle = Math.random() * Math.PI * 2;
var speed = 24 + Math.random() * 18;
confetti.vx = Math.cos(angle) * speed;
confetti.vy = Math.sin(angle) * speed - 12;
game.addChild(confetti);
particles.push(confetti);
}
// Multiple explosions across the screen
for (var e = 0; e < 8; e++) {
var ex = 400 + Math.random() * 1200;
var ey = 1200 + Math.random() * 1000;
game.spawnExplosion(ex, ey, [0xFFEB3B, 0xFF4081, 0x7ed957, 0x00bcd4, 0xffffff][Math.floor(Math.random() * 5)]);
}
// Show fun level complete text
var levelTxt = new Text2('Level ' + (currentLevel + 1) + ' Complete!', {
size: 180,
fill: 0xFFEB3B,
stroke: "#333",
strokeThickness: 10
});
levelTxt.anchor.set(0.5, 0.5);
levelTxt.x = 2048 / 2;
levelTxt.y = 2732 / 2;
game.addChild(levelTxt);
// Animate text: pop and fade out
levelTxt.scale.set(0.7, 0.7);
tween(levelTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelTxt, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 800,
delay: 800,
onFinish: function onFinish() {
levelTxt.destroy();
}
});
}
});
// Level progression and end logic
LK.setTimeout(function () {
currentLevel++;
if (currentLevel >= levels.length) {
// After level 10, show you win
LK.showYouWin();
} else {
// For levels 1-9, show "Level X Complete!" and proceed to next level
// (already handled by levelTxt and setupLevel)
setupLevel();
}
}, 1800);
}
};
// Helper: rectangle-circle collision
function rectCircleCollide(rect, circ) {
var rx = rect.x,
ry = rect.y,
rw = rect.width,
rh = rect.height;
var cx = circ.x,
cy = circ.y,
cr = circ.radius;
var testX = cx,
testY = cy;
if (cx < rx - rw / 2) testX = rx - rw / 2;else if (cx > rx + rw / 2) testX = rx + rw / 2;
if (cy < ry - rh / 2) testY = ry - rh / 2;else if (cy > ry + rh / 2) testY = ry + rh / 2;
var distX = cx - testX;
var distY = cy - testY;
return distX * distX + distY * distY <= cr * cr;
}
// Helper: circle-circle collision
function circleCircleCollide(a, b) {
var dx = a.x - b.x,
dy = a.y - b.y;
var r = a.radius + b.radius;
return dx * dx + dy * dy <= r * r;
}
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// Start level
setupLevel(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
self.type = 'red'; // 'red', 'blue', 'yellow'
self.radius = 60;
self.launched = false;
self.vx = 0;
self.vy = 0;
self.gravity = 1.2;
self.trailTimer = 0;
self.trailInterval = 3; // frames
self.trail = [];
self.powerUsed = false;
self.alive = true;
// Attach asset based on type
self.setType = function (type) {
self.type = type;
if (self.birdAsset) self.removeChild(self.birdAsset);
var assetId = 'birdRed';
if (type === 'blue') assetId = 'birdBlue';
if (type === 'yellow') assetId = 'birdYellow';
self.birdAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.birdAsset.width / 2;
};
self.setType('red');
// Launch bird with velocity
self.launch = function (vx, vy) {
self.vx = vx;
self.vy = vy;
self.launched = true;
self.trailTimer = 0;
self.powerUsed = false;
self.alive = true;
};
// Bird special power (tap in air)
self.usePower = function () {
if (self.powerUsed || !self.launched) return;
self.powerUsed = true;
if (self.type === 'blue') {
// Split into 3 birds
game.spawnSplitBirds(self);
} else if (self.type === 'yellow') {
// Speed boost
self.vx *= 1.7;
self.vy *= 1.1;
LK.effects.flashObject(self, 0xffff00, 300);
} else if (self.type === 'red') {
// Red: screen shake
game.cameraShake(20, 300);
}
};
// Update per frame
self.update = function () {
if (!self.launched || !self.alive) return;
self.vy += self.gravity;
self.x += self.vx;
self.y += self.vy;
// --- Vomit dot trail effect ---
if (!self.vomitTrail) self.vomitTrail = [];
if (!self.lastVomitX) self.lastVomitX = self.x;
if (!self.lastVomitY) self.lastVomitY = self.y;
// Only spawn a vomit dot if the bird is moving fast enough and in the air
if (self.launched && Math.abs(self.vx) + Math.abs(self.vy) > 6) {
// Place a dot every 40px of movement
var dx = self.x - self.lastVomitX;
var dy = self.y - self.lastVomitY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 40) {
var vomitDot = LK.getAsset('trailDot', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.7,
scaleX: 1.1,
scaleY: 0.7,
tint: 0xB8FF5A // light green/yellow for 'vomit'
});
game.addChild(vomitDot);
self.vomitTrail.push(vomitDot);
tween(vomitDot, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.2
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
vomitDot.destroy();
}
});
if (self.vomitTrail.length > 20) {
var oldVomit = self.vomitTrail.shift();
if (oldVomit) oldVomit.destroy();
}
self.lastVomitX = self.x;
self.lastVomitY = self.y;
}
}
// Trail effect
self.trailTimer++;
if (self.trailTimer >= self.trailInterval) {
self.trailTimer = 0;
var dot = LK.getAsset('trailDot', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(dot);
self.trail.push(dot);
tween(dot, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
dot.destroy();
}
});
if (self.trail.length > 12) {
var old = self.trail.shift();
if (old) old.destroy();
}
}
// Out of bounds
if (self.x < -200 || self.x > 2248 || self.y > 3000) {
self.alive = false;
self.destroy();
}
};
return self;
});
// Block class
var Block = Container.expand(function () {
var self = Container.call(this);
self.type = 'wood'; // 'wood', 'stone', 'glass'
self.hp = 3;
self.width = 200;
self.height = 60;
self.blockAsset = null;
self.broken = false;
self.setType = function (type) {
self.type = type;
if (self.blockAsset) self.removeChild(self.blockAsset);
var assetId = 'blockWood';
if (type === 'stone') assetId = 'blockStone';
if (type === 'glass') assetId = 'blockGlass';
self.blockAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.blockAsset.width;
self.height = self.blockAsset.height;
if (type === 'glass') self.hp = 1;else if (type === 'wood') self.hp = 2;else if (type === 'stone') self.hp = 4;
};
self.setType('wood');
self.hit = function (force) {
self.hp -= force;
LK.getSound('break').play();
LK.effects.flashObject(self, 0xffffff, 120);
if (self.hp <= 0 && !self.broken) {
self.broken = true;
game.spawnDebris(self.x, self.y, self.type);
self.destroy();
}
};
return self;
});
// Particle (for debris/explosion)
var Particle = Container.expand(function () {
var self = Container.call(this);
self.vx = 0;
self.vy = 0;
self.life = 30;
self.asset = null;
self.init = function (type, color) {
var assetId = 'debris';
if (type === 'explosion') assetId = 'explosion';
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
tint: color
});
};
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += 0.7;
self.life--;
self.asset.alpha = self.life / 30;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
// Pig class
var Pig = Container.expand(function () {
var self = Container.call(this);
self.radius = 60;
self.alive = true;
self.pigAsset = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 2;
self.hit = function (force) {
self.hp -= force;
LK.getSound('pigOink').play();
LK.effects.flashObject(self, 0xffffff, 200);
if (self.hp <= 0) {
self.die();
}
};
self.die = function () {
self.alive = false;
game.spawnExplosion(self.x, self.y, 0x7ed957);
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Camera shake variables
// Bird types
// Pig
// Block types
// Slingshot base
// Trail particle
// Debris particle
// Explosion particle
// Sound effects
// Music
var cameraShakeTime = 0;
var cameraShakeStrength = 0;
// Game state
var birds = [];
var pigs = [];
var blocks = [];
var particles = [];
var currentBird = null;
var slingshotBase = null;
var slingshotPos = {
x: 400,
y: 2000
};
var slingshotRadius = 180;
var dragStart = null;
var dragging = false;
var launchLine = null;
var birdsQueue = [];
var levelCleared = false;
var score = 0;
var scoreTxt = null;
var shotsTxt = null;
var shots = 0;
var slowmo = false;
var slowmoTimer = 0;
// GUI
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
shotsTxt = new Text2('Shots: 0', {
size: 70,
fill: "#fff"
});
shotsTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(shotsTxt);
// Combo system variables
var comboCount = 0;
var comboTimer = 0;
var comboTimerMax = 90; // 1.5 seconds at 60fps
var comboTxt = new Text2('', {
size: 110,
fill: 0xFF4081,
stroke: "#fff",
strokeThickness: 8
});
comboTxt.anchor.set(0.5, 0);
// Place combo text below the score, with good spacing for visibility
comboTxt.x = 2048 / 2;
comboTxt.y = scoreTxt.height + 60;
LK.gui.top.addChild(comboTxt);
// Level indicator
var levelTxtGui = new Text2('Level 1', {
size: 80,
fill: 0xFFEB3B,
stroke: "#333",
strokeThickness: 8
});
levelTxtGui.anchor.set(0.5, 0);
LK.gui.bottom.addChild(levelTxtGui);
// Update level indicator on level start
var oldSetupLevel = setupLevel;
setupLevel = function setupLevel() {
levelTxtGui.setText('Level ' + (currentLevel + 1));
oldSetupLevel();
};
// Add slingshot base
slingshotBase = LK.getAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1,
x: slingshotPos.x,
y: slingshotPos.y + 100
});
game.addChild(slingshotBase);
// Level definitions
var levels = [{
birds: ['red', 'blue', 'yellow'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}]
}, {
birds: ['red', 'red', 'blue', 'yellow'],
pigs: [{
x: 1550,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}]
}, {
birds: ['yellow', 'yellow', 'blue', 'red'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1750,
y: 2000
}, {
x: 1850,
y: 2200
}, {
x: 1700,
y: 2300
}],
blocks: [{
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2000
}, {
type: 'stone',
x: 1850,
y: 2200
}, {
type: 'wood',
x: 1700,
y: 2300
}, {
type: 'stone',
x: 1700,
y: 2240
}]
}, {
birds: ['blue', 'blue', 'yellow', 'red', 'red'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}, {
x: 1600,
y: 2000
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2200
}]
},
// Level 5: Tall tower, more blocks, more pigs
{
birds: ['yellow', 'red', 'blue', 'yellow', 'red'],
pigs: [{
x: 1700,
y: 1800
}, {
x: 1700,
y: 2000
}, {
x: 1700,
y: 2200
}],
blocks: [{
type: 'stone',
x: 1700,
y: 1850
}, {
type: 'wood',
x: 1700,
y: 1950
}, {
type: 'glass',
x: 1700,
y: 2050
}, {
type: 'wood',
x: 1700,
y: 2150
}, {
type: 'stone',
x: 1700,
y: 2250
}]
},
// Level 6: Wide fortress, more fun
{
birds: ['blue', 'blue', 'yellow', 'red', 'yellow'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1800,
y: 2100
}, {
x: 1650,
y: 2000
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1800,
y: 2200
}, {
type: 'stone',
x: 1650,
y: 2100
}, {
type: 'glass',
x: 1575,
y: 2150
}, {
type: 'glass',
x: 1725,
y: 2150
}, {
type: 'stone',
x: 1650,
y: 2000
}]
},
// Level 7: Pyramid
{
birds: ['red', 'yellow', 'blue', 'red', 'yellow'],
pigs: [{
x: 1650,
y: 2200
}, {
x: 1700,
y: 2100
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'stone',
x: 1700,
y: 2250
}, {
type: 'wood',
x: 1650,
y: 2250
}, {
type: 'wood',
x: 1750,
y: 2250
}, {
type: 'glass',
x: 1700,
y: 2200
}, {
type: 'glass',
x: 1675,
y: 2225
}, {
type: 'glass',
x: 1725,
y: 2225
}]
},
// Level 8: Pig bunker
{
birds: ['yellow', 'yellow', 'blue', 'red', 'blue'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1800,
y: 2100
}],
blocks: [{
type: 'stone',
x: 1600,
y: 2150
}, {
type: 'stone',
x: 1800,
y: 2150
}, {
type: 'wood',
x: 1700,
y: 2200
}, {
type: 'glass',
x: 1700,
y: 2100
}, {
type: 'wood',
x: 1700,
y: 2150
}]
},
// Level 9: Chaos fun
{
birds: ['blue', 'yellow', 'red', 'yellow', 'blue', 'red'],
pigs: [{
x: 1500,
y: 2100
}, {
x: 1700,
y: 1900
}, {
x: 1800,
y: 2200
}, {
x: 1600,
y: 2000
}, {
x: 1750,
y: 2200
}],
blocks: [{
type: 'wood',
x: 1500,
y: 2200
}, {
type: 'wood',
x: 1500,
y: 2140
}, {
type: 'stone',
x: 1700,
y: 2000
}, {
type: 'glass',
x: 1600,
y: 2100
}, {
type: 'stone',
x: 1800,
y: 2200
}, {
type: 'glass',
x: 1600,
y: 2160
}, {
type: 'wood',
x: 1750,
y: 2200
}, {
type: 'glass',
x: 1700,
y: 2100
}]
},
// Level 10: The Grand Finale
{
birds: ['red', 'yellow', 'blue', 'yellow', 'red', 'blue'],
pigs: [{
x: 1600,
y: 2100
}, {
x: 1700,
y: 2000
}, {
x: 1800,
y: 2100
}, {
x: 1700,
y: 2200
}, {
x: 1750,
y: 2300
}],
blocks: [{
type: 'stone',
x: 1700,
y: 1950
}, {
type: 'wood',
x: 1600,
y: 2150
}, {
type: 'wood',
x: 1800,
y: 2150
}, {
type: 'glass',
x: 1700,
y: 2100
}, {
type: 'glass',
x: 1650,
y: 2200
}, {
type: 'glass',
x: 1750,
y: 2200
}, {
type: 'stone',
x: 1700,
y: 2250
}, {
type: 'wood',
x: 1700,
y: 2300
}]
}];
var currentLevel = 0;
// Level setup
function setupLevel() {
// Clear arrays
for (var i = 0; i < birds.length; i++) birds[i].destroy();
for (var i = 0; i < pigs.length; i++) pigs[i].destroy();
for (var i = 0; i < blocks.length; i++) blocks[i].destroy();
for (var i = 0; i < particles.length; i++) particles[i].destroy();
birds = [];
pigs = [];
blocks = [];
particles = [];
birdsQueue = [];
levelCleared = false;
score = 0;
shots = 0;
scoreTxt.setText('0');
shotsTxt.setText('Shots: 0');
slowmo = false;
slowmoTimer = 0;
comboCount = 0;
comboTimer = 0;
comboTxt.setText('');
// Clamp currentLevel to available levels
if (currentLevel < 0) currentLevel = 0;
if (currentLevel >= levels.length) currentLevel = levels.length - 1;
var level = levels[currentLevel];
// Birds queue
for (var i = 0; i < level.birds.length; i++) {
birdsQueue.push(level.birds[i]);
}
// Spawn first bird
spawnNextBird();
// Pigs
for (var i = 0; i < level.pigs.length; i++) {
var pig = new Pig();
pig.x = level.pigs[i].x;
pig.y = level.pigs[i].y;
game.addChild(pig);
pigs.push(pig);
}
// Blocks
for (var i = 0; i < level.blocks.length; i++) {
var block = new Block();
block.setType(level.blocks[i].type);
block.x = level.blocks[i].x;
block.y = level.blocks[i].y;
game.addChild(block);
blocks.push(block);
}
}
function spawnNextBird() {
if (birdsQueue.length === 0) {
// No more birds, check for loss
LK.setTimeout(function () {
if (!levelCleared) LK.showGameOver();
}, 1200);
return;
}
var type = birdsQueue.shift();
var bird = new Bird();
bird.setType(type);
bird.x = slingshotPos.x;
bird.y = slingshotPos.y;
game.addChild(bird);
birds.push(bird);
currentBird = bird;
dragging = false;
dragStart = null;
}
// Camera shake
game.cameraShake = function (strength, duration) {
cameraShakeStrength = strength;
cameraShakeTime = duration;
};
// Debris
game.spawnDebris = function (x, y, type) {
for (var i = 0; i < 8; i++) {
var p = new Particle();
p.init('debris', type === 'wood' ? 0xc2b280 : type === 'stone' ? 0xaaaaaa : 0x99e6ff);
p.x = x;
p.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = 8 + Math.random() * 8;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 4;
game.addChild(p);
particles.push(p);
}
};
// Explosion
game.spawnExplosion = function (x, y, color) {
LK.getSound('explosionSfx').play();
for (var i = 0; i < 12; i++) {
var p = new Particle();
p.init('explosion', color);
p.x = x;
p.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = 10 + Math.random() * 10;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 6;
game.addChild(p);
particles.push(p);
}
LK.effects.flashScreen(0xffff99, 200);
game.cameraShake(30, 400);
};
// Bird split (blue)
game.spawnSplitBirds = function (parentBird) {
for (var i = -1; i <= 1; i += 2) {
var bird = new Bird();
bird.setType('blue');
bird.x = parentBird.x;
bird.y = parentBird.y;
bird.launched = true;
bird.vx = parentBird.vx + i * 7;
bird.vy = parentBird.vy - 2;
bird.powerUsed = true;
game.addChild(bird);
birds.push(bird);
}
};
// SLOWMO
function triggerSlowmo() {
slowmo = true;
slowmoTimer = 40;
}
// Touch controls
game.down = function (x, y, obj) {
if (levelCleared) return;
if (!currentBird || currentBird.launched) return;
// Only allow drag if touch is near bird
var dx = x - currentBird.x,
dy = y - currentBird.y;
if (dx * dx + dy * dy < 180 * 180) {
dragging = true;
dragStart = {
x: x,
y: y
};
}
};
game.move = function (x, y, obj) {
if (dragging && currentBird && !currentBird.launched) {
// Limit drag distance
var dx = x - slingshotPos.x,
dy = y - slingshotPos.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > slingshotRadius) {
dx *= slingshotRadius / dist;
dy *= slingshotRadius / dist;
}
currentBird.x = slingshotPos.x + dx;
currentBird.y = slingshotPos.y + dy;
}
};
game.up = function (x, y, obj) {
if (dragging && currentBird && !currentBird.launched) {
// Launch
var dx = currentBird.x - slingshotPos.x,
dy = currentBird.y - slingshotPos.y;
currentBird.launch(-dx * 0.25, -dy * 0.25);
LK.getSound('launch').play();
shots++;
shotsTxt.setText('Shots: ' + shots);
dragging = false;
dragStart = null;
}
};
// Tap for bird power
game.on('down', function (x, y, obj) {
if (currentBird && currentBird.launched && !currentBird.powerUsed) {
currentBird.usePower();
}
});
// Main update
game.update = function () {
// Camera shake
if (cameraShakeTime > 0) {
cameraShakeTime -= 16;
var shakeX = (Math.random() - 0.5) * cameraShakeStrength;
var shakeY = (Math.random() - 0.5) * cameraShakeStrength;
game.x = shakeX;
game.y = shakeY;
} else {
game.x = 0;
game.y = 0;
}
// SLOWMO
var slowmoFactor = 1;
if (slowmo) {
slowmoFactor = 0.3;
slowmoTimer--;
if (slowmoTimer <= 0) slowmo = false;
}
// Update birds
for (var i = birds.length - 1; i >= 0; i--) {
var bird = birds[i];
if (bird.launched && bird.alive) {
// Slowmo
if (slowmo) {
bird.x += bird.vx * slowmoFactor;
bird.y += bird.vy * slowmoFactor;
bird.vy += bird.gravity * slowmoFactor;
} else {
bird.update();
}
// Collisions with blocks
for (var j = blocks.length - 1; j >= 0; j--) {
var block = blocks[j];
if (!block.broken && rectCircleCollide(block, bird)) {
block.hit(1);
LK.getSound('hit').play();
// Cartoonish bounce and squash effect
tween(block, {
scaleY: 0.7,
scaleX: 1.2
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(block, {
scaleY: 1,
scaleX: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(block, 0xff0000, 100);
// Exaggerated camera shake
game.cameraShake(18, 320);
// Add a burst of debris for extra cartoon effect
for (var d = 0; d < 3; d++) {
var p = new Particle();
p.init('debris', block.type === 'wood' ? 0xc2b280 : block.type === 'stone' ? 0xaaaaaa : 0x99e6ff);
p.x = block.x + (Math.random() - 0.5) * block.width * 0.7;
p.y = block.y + (Math.random() - 0.5) * block.height * 0.7;
var angle = Math.random() * Math.PI * 2;
var speed = 10 + Math.random() * 8;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 4;
game.addChild(p);
particles.push(p);
}
triggerSlowmo();
bird.vx *= 0.6;
bird.vy *= 0.6;
}
}
// Collisions with pigs
for (var j = pigs.length - 1; j >= 0; j--) {
var pig = pigs[j];
if (pig.alive && circleCircleCollide(bird, pig)) {
pig.hit(2);
LK.getSound('hit').play();
// Pig bounce and color flash
tween(pig, {
scaleY: 0.6,
scaleX: 1.3
}, {
duration: 90,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pig, {
scaleY: 1,
scaleX: 1
}, {
duration: 140,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(pig, 0x00ff00, 180);
// Big camera shake and a burst of confetti-like debris
game.cameraShake(28, 400);
for (var d = 0; d < 6; d++) {
var p = new Particle();
p.init('debris', 0x7ed957);
p.x = pig.x + (Math.random() - 0.5) * pig.radius * 1.2;
p.y = pig.y + (Math.random() - 0.5) * pig.radius * 1.2;
var angle = Math.random() * Math.PI * 2;
var speed = 12 + Math.random() * 10;
p.vx = Math.cos(angle) * speed;
p.vy = Math.sin(angle) * speed - 6;
game.addChild(p);
particles.push(p);
}
triggerSlowmo();
bird.vx *= 0.7;
bird.vy *= 0.7;
score += 500;
scoreTxt.setText(score);
}
}
}
// Remove dead birds
if (!bird.alive) {
birds.splice(i, 1);
if (bird === currentBird) {
LK.setTimeout(function () {
spawnNextBird();
}, 700);
}
}
}
// Update pigs
for (var i = pigs.length - 1; i >= 0; i--) {
var pig = pigs[i];
if (!pig.alive) {
pigs.splice(i, 1);
score += 1000;
scoreTxt.setText(score);
// Combo system: pig destroyed triggers combo
comboCount++;
comboTimer = comboTimerMax;
comboTxt.setText('Combo x' + comboCount + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.25,
scaleY: 1.25,
alpha: 1
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
});
}
}
// Update blocks
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
if (block.broken) {
blocks.splice(i, 1);
score += 200;
scoreTxt.setText(score);
// Combo system: block destroyed triggers combo
comboCount++;
comboTimer = comboTimerMax;
comboTxt.setText('Combo x' + comboCount + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.18,
scaleY: 1.18,
alpha: 1
}, {
duration: 90,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 90,
easing: tween.easeOut
});
}
});
}
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var p = particles[i];
p.update();
if (p.life <= 0) {
particles.splice(i, 1);
}
}
// Combo timer logic
if (comboCount > 0) {
comboTimer--;
if (comboTimer <= 0) {
// Combo ended, award bonus if comboCount > 1
if (comboCount > 1) {
var bonus = comboCount * 300;
score += bonus;
scoreTxt.setText(score);
comboTxt.setText('Combo Bonus +' + bonus + '!');
comboTxt.alpha = 1;
tween(comboTxt, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 1
}, {
duration: 180,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
comboTxt.setText('');
}
});
}
});
LK.effects.flashScreen(0xFF4081, 300);
game.cameraShake(18, 300);
} else {
comboTxt.setText('');
}
comboCount = 0;
comboTimer = 0;
}
}
// Win condition
if (!levelCleared && pigs.length === 0) {
levelCleared = true;
// Fun effects: screen flash, camera shake, confetti, sound, and more!
LK.effects.flashScreen(0x00ff00, 800);
LK.effects.flashScreen(0xff4081, 600);
LK.effects.flashScreen(0xffff00, 400);
game.cameraShake(60, 900);
LK.getSound('explosionSfx').play();
LK.getSound('break').play();
LK.getSound('hit').play();
LK.getSound('pigOink').play();
// Massive confetti burst (lots of colored particles)
for (var i = 0; i < 64; i++) {
var confetti = new Particle();
confetti.init('debris', [0xFFEB3B, 0xFF4081, 0x7ed957, 0x00bcd4, 0xffffff][Math.floor(Math.random() * 5)]);
confetti.x = 2048 / 2 + (Math.random() - 0.5) * 600;
confetti.y = 2732 / 2 + (Math.random() - 0.5) * 400;
var angle = Math.random() * Math.PI * 2;
var speed = 24 + Math.random() * 18;
confetti.vx = Math.cos(angle) * speed;
confetti.vy = Math.sin(angle) * speed - 12;
game.addChild(confetti);
particles.push(confetti);
}
// Multiple explosions across the screen
for (var e = 0; e < 8; e++) {
var ex = 400 + Math.random() * 1200;
var ey = 1200 + Math.random() * 1000;
game.spawnExplosion(ex, ey, [0xFFEB3B, 0xFF4081, 0x7ed957, 0x00bcd4, 0xffffff][Math.floor(Math.random() * 5)]);
}
// Show fun level complete text
var levelTxt = new Text2('Level ' + (currentLevel + 1) + ' Complete!', {
size: 180,
fill: 0xFFEB3B,
stroke: "#333",
strokeThickness: 10
});
levelTxt.anchor.set(0.5, 0.5);
levelTxt.x = 2048 / 2;
levelTxt.y = 2732 / 2;
game.addChild(levelTxt);
// Animate text: pop and fade out
levelTxt.scale.set(0.7, 0.7);
tween(levelTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelTxt, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 800,
delay: 800,
onFinish: function onFinish() {
levelTxt.destroy();
}
});
}
});
// Level progression and end logic
LK.setTimeout(function () {
currentLevel++;
if (currentLevel >= levels.length) {
// After level 10, show you win
LK.showYouWin();
} else {
// For levels 1-9, show "Level X Complete!" and proceed to next level
// (already handled by levelTxt and setupLevel)
setupLevel();
}
}, 1800);
}
};
// Helper: rectangle-circle collision
function rectCircleCollide(rect, circ) {
var rx = rect.x,
ry = rect.y,
rw = rect.width,
rh = rect.height;
var cx = circ.x,
cy = circ.y,
cr = circ.radius;
var testX = cx,
testY = cy;
if (cx < rx - rw / 2) testX = rx - rw / 2;else if (cx > rx + rw / 2) testX = rx + rw / 2;
if (cy < ry - rh / 2) testY = ry - rh / 2;else if (cy > ry + rh / 2) testY = ry + rh / 2;
var distX = cx - testX;
var distY = cy - testY;
return distX * distX + distY * distY <= cr * cr;
}
// Helper: circle-circle collision
function circleCircleCollide(a, b) {
var dx = a.x - b.x,
dy = a.y - b.y;
var r = a.radius + b.radius;
return dx * dx + dy * dy <= r * r;
}
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// Start level
setupLevel();
Angry Birds red little bird Red. In-Game asset. 2d. High contrast. No shadows
Angry Birds blue little bird. In-Game asset. 2d. High contrast. No shadows
There is a yellow bird named Angry Birds Chuck, do that. In-Game asset. 2d. High contrast. No shadows
flat glass. In-Game asset. 2d. High contrast. No shadows
BloockWood. In-Game asset. 2d. High contrast. No shadows
Pig Angry Bids. In-Game asset. 2d. High contrast. No shadows