/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isLaunched = false;
self.gravity = 0.3;
self.bounce = 0.6;
self.launch = function (velocityX, velocityY) {
self.velocityX = velocityX;
self.velocityY = velocityY;
self.isLaunched = true;
LK.getSound('launch').play();
};
self.update = function () {
if (self.isLaunched) {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
// Ground collision
if (self.y > groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = -self.velocityY * self.bounce;
self.velocityX *= 0.8;
if (Math.abs(self.velocityY) < 2) {
self.velocityY = 0;
}
}
// Screen boundaries
if (self.x > 2048 + 100 || self.x < -100) {
self.isLaunched = false;
}
}
};
return self;
});
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.takeDamage = function (damage) {
self.health -= damage;
// Visual damage feedback
var damageAlpha = 1 - self.health / self.maxHealth;
blockGraphics.alpha = Math.max(0.3, 1 - damageAlpha);
if (self.health <= 0) {
self.destroy();
LK.getSound('destruction').play();
return true; // Block destroyed
}
return false;
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.destroy = function () {
if (!self.isDestroyed) {
self.isDestroyed = true;
LK.effects.flashObject(self, 0xff0000, 500);
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
onFinish: function onFinish() {
self.parent.removeChild(self);
}
});
LK.getSound('destruction').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var currentBird = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var slingshot = null;
var slingshotX = 300;
var slingshotY = 0;
var groundLevel = 2732 - 100;
var blocks = [];
var targets = [];
var trajectoryDots = [];
var shotsUsed = 0;
var maxShots = 3;
var level = 1;
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 1,
x: 0,
y: groundLevel
}));
// Create slingshot
var slingshotBase = game.addChild(LK.getAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX,
y: groundLevel
}));
var slingshotLeft = game.addChild(LK.getAsset('slingshot', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX - 30,
y: groundLevel
}));
var slingshotRight = game.addChild(LK.getAsset('slingshot', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX + 30,
y: groundLevel
}));
// UI Elements
var shotsText = new Text2('Shots: ' + shotsUsed + '/' + maxShots, {
size: 60,
fill: 0xFFFFFF
});
shotsText.anchor.set(0, 0);
LK.gui.topLeft.addChild(shotsText);
shotsText.x = 120;
shotsText.y = 20;
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
// Initialize level
function setupLevel() {
// Clear existing blocks and targets
for (var i = 0; i < blocks.length; i++) {
blocks[i].parent.removeChild(blocks[i]);
}
for (var i = 0; i < targets.length; i++) {
if (!targets[i].isDestroyed) {
targets[i].parent.removeChild(targets[i]);
}
}
blocks = [];
targets = [];
// Create structure
var structureX = 1200;
var structureY = groundLevel - 40;
// Create blocks in a simple tower
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 3; j++) {
var block = new Block();
block.x = structureX + j * 90 - 90;
block.y = structureY - i * 90;
blocks.push(block);
game.addChild(block);
}
}
// Create targets
var target1 = new Target();
target1.x = structureX - 90;
target1.y = structureY - 200;
targets.push(target1);
game.addChild(target1);
var target2 = new Target();
target2.x = structureX + 90;
target2.y = structureY - 200;
targets.push(target2);
game.addChild(target2);
// Reset shots
shotsUsed = 0;
updateShotsText();
// Create first bird
createNewBird();
}
function createNewBird() {
if (currentBird) {
currentBird.parent.removeChild(currentBird);
}
currentBird = new Bird();
currentBird.x = slingshotX;
currentBird.y = slingshotY - 100;
game.addChild(currentBird);
}
function updateShotsText() {
shotsText.setText('Shots: ' + shotsUsed + '/' + maxShots);
}
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
}
function createTrajectoryDots(startX, startY, velX, velY) {
// Clear existing trajectory dots
for (var i = 0; i < trajectoryDots.length; i++) {
trajectoryDots[i].parent.removeChild(trajectoryDots[i]);
}
trajectoryDots = [];
// Create trajectory prediction
var x = startX;
var y = startY;
var vx = velX;
var vy = velY;
for (var i = 0; i < 20; i++) {
x += vx;
y += vy;
vy += 0.3;
if (y > groundLevel - 30) break;
var dot = game.addChild(LK.getAsset('trajectory', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
alpha: 0.6
}));
trajectoryDots.push(dot);
}
}
function clearTrajectoryDots() {
for (var i = 0; i < trajectoryDots.length; i++) {
trajectoryDots[i].parent.removeChild(trajectoryDots[i]);
}
trajectoryDots = [];
}
function checkCollisions() {
if (!currentBird || !currentBird.isLaunched) return;
// Check collisions with blocks
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
if (currentBird.intersects(block)) {
var damage = Math.abs(currentBird.velocityX) + Math.abs(currentBird.velocityY);
var destroyed = block.takeDamage(damage * 2);
if (destroyed) {
blocks.splice(i, 1);
LK.setScore(LK.getScore() + 10);
} else {
LK.setScore(LK.getScore() + 5);
}
// Bounce bird
currentBird.velocityX *= -0.3;
currentBird.velocityY *= -0.3;
LK.getSound('impact').play();
updateScore();
}
}
// Check collisions with targets
for (var i = 0; i < targets.length; i++) {
var target = targets[i];
if (!target.isDestroyed && currentBird.intersects(target)) {
target.destroy();
LK.setScore(LK.getScore() + 50);
updateScore();
}
}
}
function checkLevelComplete() {
var allTargetsDestroyed = true;
for (var i = 0; i < targets.length; i++) {
if (!targets[i].isDestroyed) {
allTargetsDestroyed = false;
break;
}
}
if (allTargetsDestroyed) {
// Level complete
LK.setTimeout(function () {
level++;
LK.setScore(LK.getScore() + (maxShots - shotsUsed) * 20); // Bonus for unused shots
setupLevel();
}, 2000);
} else if (shotsUsed >= maxShots && (!currentBird || !currentBird.isLaunched)) {
// Game over
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Input handling
game.down = function (x, y, obj) {
if (currentBird && !currentBird.isLaunched && !isDragging) {
var distance = Math.sqrt((x - currentBird.x) * (x - currentBird.x) + (y - currentBird.y) * (y - currentBird.y));
if (distance < 100) {
isDragging = true;
dragStartX = x;
dragStartY = y;
}
}
};
game.move = function (x, y, obj) {
if (isDragging && currentBird && !currentBird.isLaunched) {
var deltaX = dragStartX - x;
var deltaY = dragStartY - y;
// Limit drag distance
var maxDrag = 150;
var dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (dragDistance > maxDrag) {
deltaX = deltaX / dragDistance * maxDrag;
deltaY = deltaY / dragDistance * maxDrag;
}
currentBird.x = slingshotX - deltaX;
currentBird.y = slingshotY - 100 - deltaY;
// Show trajectory
var velX = deltaX * 0.15;
var velY = deltaY * 0.15;
createTrajectoryDots(currentBird.x, currentBird.y, velX, velY);
}
};
game.up = function (x, y, obj) {
if (isDragging && currentBird && !currentBird.isLaunched) {
isDragging = false;
clearTrajectoryDots();
var deltaX = dragStartX - x;
var deltaY = dragStartY - y;
// Limit drag distance
var maxDrag = 150;
var dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (dragDistance > maxDrag) {
deltaX = deltaX / dragDistance * maxDrag;
deltaY = deltaY / dragDistance * maxDrag;
}
if (dragDistance > 20) {
// Minimum drag to launch
var velX = deltaX * 0.15;
var velY = deltaY * 0.15;
currentBird.launch(velX, velY);
shotsUsed++;
updateShotsText();
} else {
// Reset bird position if drag was too small
currentBird.x = slingshotX;
currentBird.y = slingshotY - 100;
}
}
};
// Initialize first level
setupLevel();
// Main game update loop
game.update = function () {
checkCollisions();
// Check if current bird is out of bounds or stopped
if (currentBird && currentBird.isLaunched) {
var isMoving = Math.abs(currentBird.velocityX) > 0.5 || Math.abs(currentBird.velocityY) > 0.5;
var isOnScreen = currentBird.x > -100 && currentBird.x < 2148;
if (!isMoving || !isOnScreen) {
LK.setTimeout(function () {
if (shotsUsed < maxShots) {
createNewBird();
}
checkLevelComplete();
}, 1000);
currentBird.isLaunched = false;
}
}
// Check for win condition (all targets destroyed)
checkLevelComplete();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isLaunched = false;
self.gravity = 0.3;
self.bounce = 0.6;
self.launch = function (velocityX, velocityY) {
self.velocityX = velocityX;
self.velocityY = velocityY;
self.isLaunched = true;
LK.getSound('launch').play();
};
self.update = function () {
if (self.isLaunched) {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
// Ground collision
if (self.y > groundLevel - 30) {
self.y = groundLevel - 30;
self.velocityY = -self.velocityY * self.bounce;
self.velocityX *= 0.8;
if (Math.abs(self.velocityY) < 2) {
self.velocityY = 0;
}
}
// Screen boundaries
if (self.x > 2048 + 100 || self.x < -100) {
self.isLaunched = false;
}
}
};
return self;
});
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.takeDamage = function (damage) {
self.health -= damage;
// Visual damage feedback
var damageAlpha = 1 - self.health / self.maxHealth;
blockGraphics.alpha = Math.max(0.3, 1 - damageAlpha);
if (self.health <= 0) {
self.destroy();
LK.getSound('destruction').play();
return true; // Block destroyed
}
return false;
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.destroy = function () {
if (!self.isDestroyed) {
self.isDestroyed = true;
LK.effects.flashObject(self, 0xff0000, 500);
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
onFinish: function onFinish() {
self.parent.removeChild(self);
}
});
LK.getSound('destruction').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var currentBird = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var slingshot = null;
var slingshotX = 300;
var slingshotY = 0;
var groundLevel = 2732 - 100;
var blocks = [];
var targets = [];
var trajectoryDots = [];
var shotsUsed = 0;
var maxShots = 3;
var level = 1;
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 1,
x: 0,
y: groundLevel
}));
// Create slingshot
var slingshotBase = game.addChild(LK.getAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX,
y: groundLevel
}));
var slingshotLeft = game.addChild(LK.getAsset('slingshot', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX - 30,
y: groundLevel
}));
var slingshotRight = game.addChild(LK.getAsset('slingshot', {
anchorX: 0.5,
anchorY: 1,
x: slingshotX + 30,
y: groundLevel
}));
// UI Elements
var shotsText = new Text2('Shots: ' + shotsUsed + '/' + maxShots, {
size: 60,
fill: 0xFFFFFF
});
shotsText.anchor.set(0, 0);
LK.gui.topLeft.addChild(shotsText);
shotsText.x = 120;
shotsText.y = 20;
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
// Initialize level
function setupLevel() {
// Clear existing blocks and targets
for (var i = 0; i < blocks.length; i++) {
blocks[i].parent.removeChild(blocks[i]);
}
for (var i = 0; i < targets.length; i++) {
if (!targets[i].isDestroyed) {
targets[i].parent.removeChild(targets[i]);
}
}
blocks = [];
targets = [];
// Create structure
var structureX = 1200;
var structureY = groundLevel - 40;
// Create blocks in a simple tower
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 3; j++) {
var block = new Block();
block.x = structureX + j * 90 - 90;
block.y = structureY - i * 90;
blocks.push(block);
game.addChild(block);
}
}
// Create targets
var target1 = new Target();
target1.x = structureX - 90;
target1.y = structureY - 200;
targets.push(target1);
game.addChild(target1);
var target2 = new Target();
target2.x = structureX + 90;
target2.y = structureY - 200;
targets.push(target2);
game.addChild(target2);
// Reset shots
shotsUsed = 0;
updateShotsText();
// Create first bird
createNewBird();
}
function createNewBird() {
if (currentBird) {
currentBird.parent.removeChild(currentBird);
}
currentBird = new Bird();
currentBird.x = slingshotX;
currentBird.y = slingshotY - 100;
game.addChild(currentBird);
}
function updateShotsText() {
shotsText.setText('Shots: ' + shotsUsed + '/' + maxShots);
}
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
}
function createTrajectoryDots(startX, startY, velX, velY) {
// Clear existing trajectory dots
for (var i = 0; i < trajectoryDots.length; i++) {
trajectoryDots[i].parent.removeChild(trajectoryDots[i]);
}
trajectoryDots = [];
// Create trajectory prediction
var x = startX;
var y = startY;
var vx = velX;
var vy = velY;
for (var i = 0; i < 20; i++) {
x += vx;
y += vy;
vy += 0.3;
if (y > groundLevel - 30) break;
var dot = game.addChild(LK.getAsset('trajectory', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
alpha: 0.6
}));
trajectoryDots.push(dot);
}
}
function clearTrajectoryDots() {
for (var i = 0; i < trajectoryDots.length; i++) {
trajectoryDots[i].parent.removeChild(trajectoryDots[i]);
}
trajectoryDots = [];
}
function checkCollisions() {
if (!currentBird || !currentBird.isLaunched) return;
// Check collisions with blocks
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
if (currentBird.intersects(block)) {
var damage = Math.abs(currentBird.velocityX) + Math.abs(currentBird.velocityY);
var destroyed = block.takeDamage(damage * 2);
if (destroyed) {
blocks.splice(i, 1);
LK.setScore(LK.getScore() + 10);
} else {
LK.setScore(LK.getScore() + 5);
}
// Bounce bird
currentBird.velocityX *= -0.3;
currentBird.velocityY *= -0.3;
LK.getSound('impact').play();
updateScore();
}
}
// Check collisions with targets
for (var i = 0; i < targets.length; i++) {
var target = targets[i];
if (!target.isDestroyed && currentBird.intersects(target)) {
target.destroy();
LK.setScore(LK.getScore() + 50);
updateScore();
}
}
}
function checkLevelComplete() {
var allTargetsDestroyed = true;
for (var i = 0; i < targets.length; i++) {
if (!targets[i].isDestroyed) {
allTargetsDestroyed = false;
break;
}
}
if (allTargetsDestroyed) {
// Level complete
LK.setTimeout(function () {
level++;
LK.setScore(LK.getScore() + (maxShots - shotsUsed) * 20); // Bonus for unused shots
setupLevel();
}, 2000);
} else if (shotsUsed >= maxShots && (!currentBird || !currentBird.isLaunched)) {
// Game over
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Input handling
game.down = function (x, y, obj) {
if (currentBird && !currentBird.isLaunched && !isDragging) {
var distance = Math.sqrt((x - currentBird.x) * (x - currentBird.x) + (y - currentBird.y) * (y - currentBird.y));
if (distance < 100) {
isDragging = true;
dragStartX = x;
dragStartY = y;
}
}
};
game.move = function (x, y, obj) {
if (isDragging && currentBird && !currentBird.isLaunched) {
var deltaX = dragStartX - x;
var deltaY = dragStartY - y;
// Limit drag distance
var maxDrag = 150;
var dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (dragDistance > maxDrag) {
deltaX = deltaX / dragDistance * maxDrag;
deltaY = deltaY / dragDistance * maxDrag;
}
currentBird.x = slingshotX - deltaX;
currentBird.y = slingshotY - 100 - deltaY;
// Show trajectory
var velX = deltaX * 0.15;
var velY = deltaY * 0.15;
createTrajectoryDots(currentBird.x, currentBird.y, velX, velY);
}
};
game.up = function (x, y, obj) {
if (isDragging && currentBird && !currentBird.isLaunched) {
isDragging = false;
clearTrajectoryDots();
var deltaX = dragStartX - x;
var deltaY = dragStartY - y;
// Limit drag distance
var maxDrag = 150;
var dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (dragDistance > maxDrag) {
deltaX = deltaX / dragDistance * maxDrag;
deltaY = deltaY / dragDistance * maxDrag;
}
if (dragDistance > 20) {
// Minimum drag to launch
var velX = deltaX * 0.15;
var velY = deltaY * 0.15;
currentBird.launch(velX, velY);
shotsUsed++;
updateShotsText();
} else {
// Reset bird position if drag was too small
currentBird.x = slingshotX;
currentBird.y = slingshotY - 100;
}
}
};
// Initialize first level
setupLevel();
// Main game update loop
game.update = function () {
checkCollisions();
// Check if current bird is out of bounds or stopped
if (currentBird && currentBird.isLaunched) {
var isMoving = Math.abs(currentBird.velocityX) > 0.5 || Math.abs(currentBird.velocityY) > 0.5;
var isOnScreen = currentBird.x > -100 && currentBird.x < 2148;
if (!isMoving || !isOnScreen) {
LK.setTimeout(function () {
if (shotsUsed < maxShots) {
createNewBird();
}
checkLevelComplete();
}, 1000);
currentBird.isLaunched = false;
}
}
// Check for win condition (all targets destroyed)
checkLevelComplete();
};