/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Bird type: 'red', 'blue', 'yellow'
self.type = 'red';
self.isLaunched = false;
self.isActive = false;
self.velocity = {
x: 0,
y: 0
};
self.radius = 60; // default, will be set by asset
self.gravity = 1.2;
self.friction = 0.995;
self.bounce = 0.45;
self.hasAbility = false; // For future bird abilities
// Attach asset based on type
function setAsset() {
var assetId = 'birdRed';
if (self.type === 'blue') assetId = 'birdBlue';
if (self.type === 'yellow') assetId = 'birdYellow';
var asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = asset.width / 2;
}
self.setType = function (type) {
self.type = type;
setAsset();
};
setAsset();
// Called every tick
self.update = function () {
if (!self.isLaunched) return;
// Physics
self.velocity.y += self.gravity;
self.x += self.velocity.x;
self.y += self.velocity.y;
self.velocity.x *= self.friction;
self.velocity.y *= self.friction;
// Ground collision
if (self.y + self.radius > groundY) {
self.y = groundY - self.radius;
if (Math.abs(self.velocity.y) > 2) {
self.velocity.y *= -self.bounce;
self.velocity.x *= self.friction;
} else {
self.velocity.y = 0;
self.velocity.x *= 0.95;
if (Math.abs(self.velocity.x) < 1) {
self.velocity.x = 0;
self.isActive = false;
}
}
}
};
// Ability placeholder (for future expansion)
self.activateAbility = function () {
// e.g. blue splits, yellow speeds up
// Not implemented in MVP
};
return self;
});
// Block class
var Block = Container.expand(function () {
var self = Container.call(this);
self.type = 'wood'; // 'wood', 'stone', 'glass'
self.width = 180;
self.height = 60;
self.isStatic = false;
self.health = 2;
self.velocity = {
x: 0,
y: 0
};
self.gravity = 1.2;
self.friction = 0.98;
self.bounce = 0.2;
function setAsset() {
var assetId = 'blockWood';
if (self.type === 'stone') assetId = 'blockStone';
if (self.type === 'glass') assetId = 'blockGlass';
var asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = asset.width;
self.height = asset.height;
}
self.setType = function (type) {
self.type = type;
setAsset();
if (type === 'wood') self.health = 2;
if (type === 'stone') self.health = 4;
if (type === 'glass') self.health = 1;
};
setAsset();
self.update = function () {
if (self.isStatic) return;
self.velocity.y += self.gravity;
self.x += self.velocity.x;
self.y += self.velocity.y;
self.velocity.x *= self.friction;
self.velocity.y *= self.friction;
// Ground collision
if (self.y + self.height / 2 > groundY) {
self.y = groundY - self.height / 2;
if (Math.abs(self.velocity.y) > 2) {
self.velocity.y *= -self.bounce;
self.velocity.x *= self.friction;
} else {
self.velocity.y = 0;
self.velocity.x *= 0.95;
if (Math.abs(self.velocity.x) < 0.5) {
self.velocity.x = 0;
}
}
}
};
self.hit = function (force) {
self.health -= force;
if (self.health <= 0) {
LK.getSound('blockBreak').play();
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// Pig class
var Pig = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = asset.width / 2;
self.isAlive = true;
self.health = 1; // For MVP, 1 hit = dead
self.hit = function (force) {
if (!self.isAlive) return;
self.health -= 1;
if (self.health <= 0) {
self.isAlive = false;
LK.getSound('pigPop').play();
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// Slingshot class
var Slingshot = Container.expand(function () {
var self = Container.call(this);
// Base
var base = self.attachAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1
});
// Band (drawn dynamically in game code)
self.band = LK.getAsset('slingshotBand', {
anchorX: 0.5,
anchorY: 0
});
self.band.visible = false;
self.addChild(self.band);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Music
// Sounds
// Ground
// Blocks
// Slingshot
// Pigs
// Birds
// --- Global variables ---
var groundY = 2732 - 80; // y position of ground
var birds = [];
var pigs = [];
var blocks = [];
var currentBird = null;
var slingshot = null;
var isDragging = false;
var dragStart = {
x: 0,
y: 0
};
var dragEnd = {
x: 0,
y: 0
};
var maxDragDist = 350;
var shotsLeft = 0;
var level = 1;
var score = 0;
var scoreTxt = null;
var shotsTxt = null;
var levelTxt = null;
var ground = null;
var bandStart = {
x: 0,
y: 0
};
var bandEnd = {
x: 0,
y: 0
};
var bandVisible = false;
var winTimeout = null;
// --- GUI ---
scoreTxt = new Text2('Score: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
shotsTxt = new Text2('Birds: 0', {
size: 70,
fill: "#fff"
});
shotsTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(shotsTxt);
levelTxt = new Text2('Level 1', {
size: 70,
fill: "#fff"
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// --- Ground ---
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
});
ground.x = 0;
ground.y = groundY;
game.addChild(ground);
// --- Slingshot ---
slingshot = new Slingshot();
slingshot.x = 350;
slingshot.y = groundY;
game.addChild(slingshot);
// --- Level Setup ---
function setupLevel(lvl) {
// Clear previous
for (var i = birds.length - 1; i >= 0; i--) {
birds[i].destroy();
birds.splice(i, 1);
}
for (var i = pigs.length - 1; i >= 0; i--) {
pigs[i].destroy();
pigs.splice(i, 1);
}
for (var i = blocks.length - 1; i >= 0; i--) {
blocks[i].destroy();
blocks.splice(i, 1);
}
if (currentBird) {
currentBird.destroy();
currentBird = null;
}
if (winTimeout) {
LK.clearTimeout(winTimeout);
winTimeout = null;
}
// Level text
levelTxt.setText('Level ' + lvl);
// Birds for this level
var birdTypes = ['red', 'red', 'blue', 'yellow'];
if (lvl === 1) birdTypes = ['red', 'red', 'red'];
if (lvl === 2) birdTypes = ['red', 'blue', 'red'];
if (lvl === 3) birdTypes = ['red', 'blue', 'yellow', 'red'];
if (lvl > 3) birdTypes = ['red', 'blue', 'yellow', 'red', 'blue'];
shotsLeft = birdTypes.length;
shotsTxt.setText('Birds: ' + shotsLeft);
for (var i = 0; i < birdTypes.length; i++) {
var b = new Bird();
b.setType(birdTypes[i]);
b.x = 200 - i * 60;
b.y = groundY - 60;
birds.push(b);
game.addChild(b);
}
// Pigs and blocks arrangement
// Level 1: 2 pigs, 2 wood blocks
// Level 2: 3 pigs, 2 wood, 2 stone
// Level 3: 4 pigs, 2 wood, 2 stone, 2 glass
// Level 4+: 5 pigs, 3 wood, 3 stone, 2 glass
var pigCount = Math.min(2 + lvl, 5);
var blockCount = Math.min(2 + lvl, 8);
// Place pigs
for (var i = 0; i < pigCount; i++) {
var p = new Pig();
p.x = 1200 + i * 120;
p.y = groundY - 90 - i % 2 * 80;
pigs.push(p);
game.addChild(p);
}
// Place blocks
for (var i = 0; i < blockCount; i++) {
var bl = new Block();
if (i % 3 === 0) bl.setType('wood');else if (i % 3 === 1) bl.setType('stone');else bl.setType('glass');
bl.x = 1150 + i % 5 * 120;
bl.y = groundY - 60 - Math.floor(i / 5) * 80;
blocks.push(bl);
game.addChild(bl);
}
// Place first bird on slingshot
nextBird();
}
// --- Bird Launching ---
function nextBird() {
if (currentBird) {
currentBird.destroy();
currentBird = null;
}
if (birds.length === 0) {
// Out of birds, check for loss
checkWinOrLose();
return;
}
currentBird = birds.shift();
currentBird.x = slingshot.x;
currentBird.y = slingshot.y - 80;
currentBird.isLaunched = false;
currentBird.isActive = false;
currentBird.velocity = {
x: 0,
y: 0
};
shotsLeft = birds.length + 1;
shotsTxt.setText('Birds: ' + shotsLeft);
bandVisible = false;
slingshot.band.visible = false;
}
// --- Drag and Launch ---
game.down = function (x, y, obj) {
// Only allow drag if current bird is not launched and touch is near bird
if (!currentBird || currentBird.isLaunched) return;
var dx = x - currentBird.x;
var dy = y - currentBird.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < currentBird.radius + 40) {
isDragging = true;
dragStart.x = x;
dragStart.y = y;
dragEnd.x = x;
dragEnd.y = y;
bandVisible = true;
slingshot.band.visible = true;
}
};
game.move = function (x, y, obj) {
if (!isDragging || !currentBird || currentBird.isLaunched) return;
// Limit drag distance
var dx = x - slingshot.x;
var dy = y - (slingshot.y - 80);
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > maxDragDist) {
var ratio = maxDragDist / dist;
dx *= ratio;
dy *= ratio;
}
dragEnd.x = slingshot.x + dx;
dragEnd.y = slingshot.y - 80 + dy;
currentBird.x = dragEnd.x;
currentBird.y = dragEnd.y;
// Update band
bandStart.x = slingshot.x;
bandStart.y = slingshot.y - 80;
bandEnd.x = currentBird.x;
bandEnd.y = currentBird.y;
updateBand();
};
game.up = function (x, y, obj) {
if (!isDragging || !currentBird || currentBird.isLaunched) return;
isDragging = false;
bandVisible = false;
slingshot.band.visible = false;
// Calculate launch velocity
var dx = slingshot.x - currentBird.x;
var dy = slingshot.y - 80 - currentBird.y;
var power = Math.sqrt(dx * dx + dy * dy);
var maxPower = 32;
var minPower = 8;
var scale = Math.min(maxPower, Math.max(minPower, power / 10));
currentBird.velocity.x = dx / 10 * scale / 10;
currentBird.velocity.y = dy / 10 * scale / 10;
currentBird.isLaunched = true;
currentBird.isActive = true;
LK.getSound('birdLaunch').play();
};
// --- Band Drawing ---
function updateBand() {
if (!bandVisible) {
slingshot.band.visible = false;
return;
}
var dx = bandEnd.x - bandStart.x;
var dy = bandEnd.y - bandStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
slingshot.band.height = dist;
slingshot.band.rotation = Math.atan2(dy, dx) - Math.PI / 2;
slingshot.band.x = bandStart.x;
slingshot.band.y = bandStart.y;
slingshot.band.visible = true;
}
// --- Physics and Collisions ---
function checkCollisions() {
// Bird with blocks
if (currentBird && currentBird.isLaunched && currentBird.isActive) {
for (var i = blocks.length - 1; i >= 0; i--) {
var bl = blocks[i];
if (!bl) continue;
// AABB collision
var bx = bl.x,
by = bl.y,
bw = bl.width,
bh = bl.height;
var cx = currentBird.x,
cy = currentBird.y,
cr = currentBird.radius;
if (cx + cr > bx - bw / 2 && cx - cr < bx + bw / 2 && cy + cr > by - bh / 2 && cy - cr < by + bh / 2) {
// Hit!
var force = Math.max(1, Math.abs(currentBird.velocity.x) + Math.abs(currentBird.velocity.y)) / 8;
bl.hit(force);
// Bounce bird
if (Math.abs(currentBird.velocity.x) > Math.abs(currentBird.velocity.y)) {
currentBird.velocity.x *= -0.5;
} else {
currentBird.velocity.y *= -0.5;
}
}
}
// Bird with pigs
for (var i = pigs.length - 1; i >= 0; i--) {
var p = pigs[i];
if (!p || !p.isAlive) continue;
var dx = currentBird.x - p.x;
var dy = currentBird.y - p.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < currentBird.radius + p.radius - 10) {
// Hit!
p.hit(1);
score += 500;
scoreTxt.setText('Score: ' + score);
// Bounce bird
currentBird.velocity.x *= -0.5;
currentBird.velocity.y *= -0.5;
}
}
}
// Blocks with pigs
for (var i = blocks.length - 1; i >= 0; i--) {
var bl = blocks[i];
if (!bl) continue;
for (var j = pigs.length - 1; j >= 0; j--) {
var p = pigs[j];
if (!p || !p.isAlive) continue;
var bx = bl.x,
by = bl.y,
bw = bl.width,
bh = bl.height;
var px = p.x,
py = p.y,
pr = p.radius;
if (px + pr > bx - bw / 2 && px - pr < bx + bw / 2 && py + pr > by - bh / 2 && py - pr < by + bh / 2) {
// Hit!
p.hit(1);
score += 500;
scoreTxt.setText('Score: ' + score);
}
}
}
}
// --- Win/Lose Check ---
function checkWinOrLose() {
// Win: all pigs dead
var pigsLeft = 0;
for (var i = 0; i < pigs.length; i++) {
if (pigs[i] && pigs[i].isAlive) pigsLeft++;
}
if (pigsLeft === 0) {
// Win!
score += shotsLeft * 1000;
scoreTxt.setText('Score: ' + score);
winTimeout = LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
return;
}
// Lose: no birds left and pigs remain
if (birds.length === 0 && (!currentBird || !currentBird.isActive)) {
winTimeout = LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
}
}
// --- Main Update ---
game.update = function () {
// Update birds
if (currentBird) currentBird.update();
for (var i = 0; i < birds.length; i++) birds[i].update();
// Update blocks
for (var i = 0; i < blocks.length; i++) blocks[i].update();
// Check collisions
checkCollisions();
// Remove dead pigs/blocks
for (var i = pigs.length - 1; i >= 0; i--) {
if (pigs[i] && !pigs[i].isAlive) {
pigs.splice(i, 1);
}
}
for (var i = blocks.length - 1; i >= 0; i--) {
if (blocks[i] && blocks[i].health <= 0) {
blocks.splice(i, 1);
}
}
// If bird is stopped, go to next bird
if (currentBird && currentBird.isLaunched && !currentBird.isActive) {
nextBird();
checkWinOrLose();
}
};
// --- Start Game ---
score = 0;
scoreTxt.setText('Score: 0');
setupLevel(level);
// --- Music ---
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
}); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,567 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Bird class
+var Bird = Container.expand(function () {
+ var self = Container.call(this);
+ // Bird type: 'red', 'blue', 'yellow'
+ self.type = 'red';
+ self.isLaunched = false;
+ self.isActive = false;
+ self.velocity = {
+ x: 0,
+ y: 0
+ };
+ self.radius = 60; // default, will be set by asset
+ self.gravity = 1.2;
+ self.friction = 0.995;
+ self.bounce = 0.45;
+ self.hasAbility = false; // For future bird abilities
+ // Attach asset based on type
+ function setAsset() {
+ var assetId = 'birdRed';
+ if (self.type === 'blue') assetId = 'birdBlue';
+ if (self.type === 'yellow') assetId = 'birdYellow';
+ var asset = self.attachAsset(assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = asset.width / 2;
+ }
+ self.setType = function (type) {
+ self.type = type;
+ setAsset();
+ };
+ setAsset();
+ // Called every tick
+ self.update = function () {
+ if (!self.isLaunched) return;
+ // Physics
+ self.velocity.y += self.gravity;
+ self.x += self.velocity.x;
+ self.y += self.velocity.y;
+ self.velocity.x *= self.friction;
+ self.velocity.y *= self.friction;
+ // Ground collision
+ if (self.y + self.radius > groundY) {
+ self.y = groundY - self.radius;
+ if (Math.abs(self.velocity.y) > 2) {
+ self.velocity.y *= -self.bounce;
+ self.velocity.x *= self.friction;
+ } else {
+ self.velocity.y = 0;
+ self.velocity.x *= 0.95;
+ if (Math.abs(self.velocity.x) < 1) {
+ self.velocity.x = 0;
+ self.isActive = false;
+ }
+ }
+ }
+ };
+ // Ability placeholder (for future expansion)
+ self.activateAbility = function () {
+ // e.g. blue splits, yellow speeds up
+ // Not implemented in MVP
+ };
+ return self;
+});
+// Block class
+var Block = Container.expand(function () {
+ var self = Container.call(this);
+ self.type = 'wood'; // 'wood', 'stone', 'glass'
+ self.width = 180;
+ self.height = 60;
+ self.isStatic = false;
+ self.health = 2;
+ self.velocity = {
+ x: 0,
+ y: 0
+ };
+ self.gravity = 1.2;
+ self.friction = 0.98;
+ self.bounce = 0.2;
+ function setAsset() {
+ var assetId = 'blockWood';
+ if (self.type === 'stone') assetId = 'blockStone';
+ if (self.type === 'glass') assetId = 'blockGlass';
+ var asset = self.attachAsset(assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = asset.width;
+ self.height = asset.height;
+ }
+ self.setType = function (type) {
+ self.type = type;
+ setAsset();
+ if (type === 'wood') self.health = 2;
+ if (type === 'stone') self.health = 4;
+ if (type === 'glass') self.health = 1;
+ };
+ setAsset();
+ self.update = function () {
+ if (self.isStatic) return;
+ self.velocity.y += self.gravity;
+ self.x += self.velocity.x;
+ self.y += self.velocity.y;
+ self.velocity.x *= self.friction;
+ self.velocity.y *= self.friction;
+ // Ground collision
+ if (self.y + self.height / 2 > groundY) {
+ self.y = groundY - self.height / 2;
+ if (Math.abs(self.velocity.y) > 2) {
+ self.velocity.y *= -self.bounce;
+ self.velocity.x *= self.friction;
+ } else {
+ self.velocity.y = 0;
+ self.velocity.x *= 0.95;
+ if (Math.abs(self.velocity.x) < 0.5) {
+ self.velocity.x = 0;
+ }
+ }
+ }
+ };
+ self.hit = function (force) {
+ self.health -= force;
+ if (self.health <= 0) {
+ LK.getSound('blockBreak').play();
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ }
+ };
+ return self;
+});
+// Pig class
+var Pig = Container.expand(function () {
+ var self = Container.call(this);
+ var asset = self.attachAsset('pig', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = asset.width / 2;
+ self.isAlive = true;
+ self.health = 1; // For MVP, 1 hit = dead
+ self.hit = function (force) {
+ if (!self.isAlive) return;
+ self.health -= 1;
+ if (self.health <= 0) {
+ self.isAlive = false;
+ LK.getSound('pigPop').play();
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ }
+ };
+ return self;
+});
+// Slingshot class
+var Slingshot = Container.expand(function () {
+ var self = Container.call(this);
+ // Base
+ var base = self.attachAsset('slingshotBase', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ // Band (drawn dynamically in game code)
+ self.band = LK.getAsset('slingshotBand', {
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ self.band.visible = false;
+ self.addChild(self.band);
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x87ceeb // Sky blue
+});
+
+/****
+* Game Code
+****/
+// Music
+// Sounds
+// Ground
+// Blocks
+// Slingshot
+// Pigs
+// Birds
+// --- Global variables ---
+var groundY = 2732 - 80; // y position of ground
+var birds = [];
+var pigs = [];
+var blocks = [];
+var currentBird = null;
+var slingshot = null;
+var isDragging = false;
+var dragStart = {
+ x: 0,
+ y: 0
+};
+var dragEnd = {
+ x: 0,
+ y: 0
+};
+var maxDragDist = 350;
+var shotsLeft = 0;
+var level = 1;
+var score = 0;
+var scoreTxt = null;
+var shotsTxt = null;
+var levelTxt = null;
+var ground = null;
+var bandStart = {
+ x: 0,
+ y: 0
+};
+var bandEnd = {
+ x: 0,
+ y: 0
+};
+var bandVisible = false;
+var winTimeout = null;
+// --- GUI ---
+scoreTxt = new Text2('Score: 0', {
+ size: 90,
+ fill: "#fff"
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+shotsTxt = new Text2('Birds: 0', {
+ size: 70,
+ fill: "#fff"
+});
+shotsTxt.anchor.set(0.5, 0);
+LK.gui.topRight.addChild(shotsTxt);
+levelTxt = new Text2('Level 1', {
+ size: 70,
+ fill: "#fff"
+});
+levelTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(levelTxt);
+// --- Ground ---
+ground = LK.getAsset('ground', {
+ anchorX: 0,
+ anchorY: 0
+});
+ground.x = 0;
+ground.y = groundY;
+game.addChild(ground);
+// --- Slingshot ---
+slingshot = new Slingshot();
+slingshot.x = 350;
+slingshot.y = groundY;
+game.addChild(slingshot);
+// --- Level Setup ---
+function setupLevel(lvl) {
+ // Clear previous
+ for (var i = birds.length - 1; i >= 0; i--) {
+ birds[i].destroy();
+ birds.splice(i, 1);
+ }
+ for (var i = pigs.length - 1; i >= 0; i--) {
+ pigs[i].destroy();
+ pigs.splice(i, 1);
+ }
+ for (var i = blocks.length - 1; i >= 0; i--) {
+ blocks[i].destroy();
+ blocks.splice(i, 1);
+ }
+ if (currentBird) {
+ currentBird.destroy();
+ currentBird = null;
+ }
+ if (winTimeout) {
+ LK.clearTimeout(winTimeout);
+ winTimeout = null;
+ }
+ // Level text
+ levelTxt.setText('Level ' + lvl);
+ // Birds for this level
+ var birdTypes = ['red', 'red', 'blue', 'yellow'];
+ if (lvl === 1) birdTypes = ['red', 'red', 'red'];
+ if (lvl === 2) birdTypes = ['red', 'blue', 'red'];
+ if (lvl === 3) birdTypes = ['red', 'blue', 'yellow', 'red'];
+ if (lvl > 3) birdTypes = ['red', 'blue', 'yellow', 'red', 'blue'];
+ shotsLeft = birdTypes.length;
+ shotsTxt.setText('Birds: ' + shotsLeft);
+ for (var i = 0; i < birdTypes.length; i++) {
+ var b = new Bird();
+ b.setType(birdTypes[i]);
+ b.x = 200 - i * 60;
+ b.y = groundY - 60;
+ birds.push(b);
+ game.addChild(b);
+ }
+ // Pigs and blocks arrangement
+ // Level 1: 2 pigs, 2 wood blocks
+ // Level 2: 3 pigs, 2 wood, 2 stone
+ // Level 3: 4 pigs, 2 wood, 2 stone, 2 glass
+ // Level 4+: 5 pigs, 3 wood, 3 stone, 2 glass
+ var pigCount = Math.min(2 + lvl, 5);
+ var blockCount = Math.min(2 + lvl, 8);
+ // Place pigs
+ for (var i = 0; i < pigCount; i++) {
+ var p = new Pig();
+ p.x = 1200 + i * 120;
+ p.y = groundY - 90 - i % 2 * 80;
+ pigs.push(p);
+ game.addChild(p);
+ }
+ // Place blocks
+ for (var i = 0; i < blockCount; i++) {
+ var bl = new Block();
+ if (i % 3 === 0) bl.setType('wood');else if (i % 3 === 1) bl.setType('stone');else bl.setType('glass');
+ bl.x = 1150 + i % 5 * 120;
+ bl.y = groundY - 60 - Math.floor(i / 5) * 80;
+ blocks.push(bl);
+ game.addChild(bl);
+ }
+ // Place first bird on slingshot
+ nextBird();
+}
+// --- Bird Launching ---
+function nextBird() {
+ if (currentBird) {
+ currentBird.destroy();
+ currentBird = null;
+ }
+ if (birds.length === 0) {
+ // Out of birds, check for loss
+ checkWinOrLose();
+ return;
+ }
+ currentBird = birds.shift();
+ currentBird.x = slingshot.x;
+ currentBird.y = slingshot.y - 80;
+ currentBird.isLaunched = false;
+ currentBird.isActive = false;
+ currentBird.velocity = {
+ x: 0,
+ y: 0
+ };
+ shotsLeft = birds.length + 1;
+ shotsTxt.setText('Birds: ' + shotsLeft);
+ bandVisible = false;
+ slingshot.band.visible = false;
+}
+// --- Drag and Launch ---
+game.down = function (x, y, obj) {
+ // Only allow drag if current bird is not launched and touch is near bird
+ if (!currentBird || currentBird.isLaunched) return;
+ var dx = x - currentBird.x;
+ var dy = y - currentBird.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < currentBird.radius + 40) {
+ isDragging = true;
+ dragStart.x = x;
+ dragStart.y = y;
+ dragEnd.x = x;
+ dragEnd.y = y;
+ bandVisible = true;
+ slingshot.band.visible = true;
+ }
+};
+game.move = function (x, y, obj) {
+ if (!isDragging || !currentBird || currentBird.isLaunched) return;
+ // Limit drag distance
+ var dx = x - slingshot.x;
+ var dy = y - (slingshot.y - 80);
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist > maxDragDist) {
+ var ratio = maxDragDist / dist;
+ dx *= ratio;
+ dy *= ratio;
+ }
+ dragEnd.x = slingshot.x + dx;
+ dragEnd.y = slingshot.y - 80 + dy;
+ currentBird.x = dragEnd.x;
+ currentBird.y = dragEnd.y;
+ // Update band
+ bandStart.x = slingshot.x;
+ bandStart.y = slingshot.y - 80;
+ bandEnd.x = currentBird.x;
+ bandEnd.y = currentBird.y;
+ updateBand();
+};
+game.up = function (x, y, obj) {
+ if (!isDragging || !currentBird || currentBird.isLaunched) return;
+ isDragging = false;
+ bandVisible = false;
+ slingshot.band.visible = false;
+ // Calculate launch velocity
+ var dx = slingshot.x - currentBird.x;
+ var dy = slingshot.y - 80 - currentBird.y;
+ var power = Math.sqrt(dx * dx + dy * dy);
+ var maxPower = 32;
+ var minPower = 8;
+ var scale = Math.min(maxPower, Math.max(minPower, power / 10));
+ currentBird.velocity.x = dx / 10 * scale / 10;
+ currentBird.velocity.y = dy / 10 * scale / 10;
+ currentBird.isLaunched = true;
+ currentBird.isActive = true;
+ LK.getSound('birdLaunch').play();
+};
+// --- Band Drawing ---
+function updateBand() {
+ if (!bandVisible) {
+ slingshot.band.visible = false;
+ return;
+ }
+ var dx = bandEnd.x - bandStart.x;
+ var dy = bandEnd.y - bandStart.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ slingshot.band.height = dist;
+ slingshot.band.rotation = Math.atan2(dy, dx) - Math.PI / 2;
+ slingshot.band.x = bandStart.x;
+ slingshot.band.y = bandStart.y;
+ slingshot.band.visible = true;
+}
+// --- Physics and Collisions ---
+function checkCollisions() {
+ // Bird with blocks
+ if (currentBird && currentBird.isLaunched && currentBird.isActive) {
+ for (var i = blocks.length - 1; i >= 0; i--) {
+ var bl = blocks[i];
+ if (!bl) continue;
+ // AABB collision
+ var bx = bl.x,
+ by = bl.y,
+ bw = bl.width,
+ bh = bl.height;
+ var cx = currentBird.x,
+ cy = currentBird.y,
+ cr = currentBird.radius;
+ if (cx + cr > bx - bw / 2 && cx - cr < bx + bw / 2 && cy + cr > by - bh / 2 && cy - cr < by + bh / 2) {
+ // Hit!
+ var force = Math.max(1, Math.abs(currentBird.velocity.x) + Math.abs(currentBird.velocity.y)) / 8;
+ bl.hit(force);
+ // Bounce bird
+ if (Math.abs(currentBird.velocity.x) > Math.abs(currentBird.velocity.y)) {
+ currentBird.velocity.x *= -0.5;
+ } else {
+ currentBird.velocity.y *= -0.5;
+ }
+ }
+ }
+ // Bird with pigs
+ for (var i = pigs.length - 1; i >= 0; i--) {
+ var p = pigs[i];
+ if (!p || !p.isAlive) continue;
+ var dx = currentBird.x - p.x;
+ var dy = currentBird.y - p.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < currentBird.radius + p.radius - 10) {
+ // Hit!
+ p.hit(1);
+ score += 500;
+ scoreTxt.setText('Score: ' + score);
+ // Bounce bird
+ currentBird.velocity.x *= -0.5;
+ currentBird.velocity.y *= -0.5;
+ }
+ }
+ }
+ // Blocks with pigs
+ for (var i = blocks.length - 1; i >= 0; i--) {
+ var bl = blocks[i];
+ if (!bl) continue;
+ for (var j = pigs.length - 1; j >= 0; j--) {
+ var p = pigs[j];
+ if (!p || !p.isAlive) continue;
+ var bx = bl.x,
+ by = bl.y,
+ bw = bl.width,
+ bh = bl.height;
+ var px = p.x,
+ py = p.y,
+ pr = p.radius;
+ if (px + pr > bx - bw / 2 && px - pr < bx + bw / 2 && py + pr > by - bh / 2 && py - pr < by + bh / 2) {
+ // Hit!
+ p.hit(1);
+ score += 500;
+ scoreTxt.setText('Score: ' + score);
+ }
+ }
+ }
+}
+// --- Win/Lose Check ---
+function checkWinOrLose() {
+ // Win: all pigs dead
+ var pigsLeft = 0;
+ for (var i = 0; i < pigs.length; i++) {
+ if (pigs[i] && pigs[i].isAlive) pigsLeft++;
+ }
+ if (pigsLeft === 0) {
+ // Win!
+ score += shotsLeft * 1000;
+ scoreTxt.setText('Score: ' + score);
+ winTimeout = LK.setTimeout(function () {
+ LK.showYouWin();
+ }, 1200);
+ return;
+ }
+ // Lose: no birds left and pigs remain
+ if (birds.length === 0 && (!currentBird || !currentBird.isActive)) {
+ winTimeout = LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 1200);
+ }
+}
+// --- Main Update ---
+game.update = function () {
+ // Update birds
+ if (currentBird) currentBird.update();
+ for (var i = 0; i < birds.length; i++) birds[i].update();
+ // Update blocks
+ for (var i = 0; i < blocks.length; i++) blocks[i].update();
+ // Check collisions
+ checkCollisions();
+ // Remove dead pigs/blocks
+ for (var i = pigs.length - 1; i >= 0; i--) {
+ if (pigs[i] && !pigs[i].isAlive) {
+ pigs.splice(i, 1);
+ }
+ }
+ for (var i = blocks.length - 1; i >= 0; i--) {
+ if (blocks[i] && blocks[i].health <= 0) {
+ blocks.splice(i, 1);
+ }
+ }
+ // If bird is stopped, go to next bird
+ if (currentBird && currentBird.isLaunched && !currentBird.isActive) {
+ nextBird();
+ checkWinOrLose();
+ }
+};
+// --- Start Game ---
+score = 0;
+scoreTxt.setText('Score: 0');
+setupLevel(level);
+// --- Music ---
+LK.playMusic('bgmusic', {
+ fade: {
+ start: 0,
+ end: 0.7,
+ duration: 1000
+ }
});
\ No newline at end of file