/**** * 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();
};