/****
* 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({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* 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 < 3; 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
@@ -191,9 +191,11 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x87ceeb // Sky blue
+ // No title, no description
+ // Always backgroundColor is black
+ backgroundColor: 0x000000
});
/****
* Game Code
@@ -319,13 +321,12 @@
// 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++) {
+ for (var i = 0; i < 3; i++) {
var p = new Pig();
p.x = 1200 + i * 120;
- // Place pigs higher: raise by 200px
- p.y = groundY - 90 - i % 2 * 80 - 200;
+ p.y = groundY - 90 - i % 2 * 80;
pigs.push(p);
game.addChild(p);
}
// Place blocks