/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.15;
self.active = true;
self.update = function () {
if (!self.active) return;
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen (only bottom and left boundaries)
if (self.x < -50 || self.y > 2782) {
self.active = false;
}
};
return self;
});
var Slingshot = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1.0
});
var leftStrap = self.attachAsset('slingshotStrap', {
anchorX: 0.5,
anchorY: 1.0
});
var rightStrap = self.attachAsset('slingshotStrap', {
anchorX: 0.5,
anchorY: 1.0
});
leftStrap.x = -45;
rightStrap.x = 45;
self.aimX = 0;
self.aimY = 0;
self.aiming = false;
// Trajectory line
self.trajectoryContainer = self.addChild(new Container());
self.trajectoryDots = [];
self.setAim = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var maxDistance = 180;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > maxDistance) {
dx = dx / distance * maxDistance;
dy = dy / distance * maxDistance;
}
self.aimX = dx;
self.aimY = dy;
// Update strap positions
leftStrap.rotation = Math.atan2(dy, dx + 45) - Math.PI / 2;
rightStrap.rotation = Math.atan2(dy, dx - 45) - Math.PI / 2;
var strapLength = Math.sqrt(dx * dx + dy * dy) / 90;
leftStrap.scaleY = strapLength;
rightStrap.scaleY = strapLength;
// Show trajectory line
self.showTrajectory();
};
self.resetStraps = function () {
leftStrap.rotation = 0;
rightStrap.rotation = 0;
leftStrap.scaleY = 1;
rightStrap.scaleY = 1;
self.hideTrajectory();
};
self.showTrajectory = function () {
// Clear existing dots
self.hideTrajectory();
if (!self.aiming) return;
// Calculate launch parameters
var power = Math.sqrt(self.aimX * self.aimX + self.aimY * self.aimY) / 120;
power = Math.min(power, 1) * 35;
var angle = Math.atan2(self.aimY, self.aimX);
var velocityX = Math.cos(angle) * power;
var velocityY = Math.sin(angle) * power;
// Simulate trajectory
var simX = self.x;
var simY = self.y - 90;
var simVelX = velocityX;
var simVelY = velocityY;
var gravity = 0.15;
// Create dots along trajectory
for (var i = 0; i < 60; i += 4) {
// Update simulated position
simVelY += gravity;
simX += simVelX;
simY += simVelY;
// Stop if trajectory goes off screen
if (simX < 0 || simX > 2048 || simY > 2732) break;
// Create trajectory dot
var dot = LK.getAsset('trajectoryDot', {
anchorX: 0.5,
anchorY: 0.5
});
dot.x = simX - self.x;
dot.y = simY - self.y;
dot.alpha = 1 - i / 60; // Fade out over distance
self.trajectoryContainer.addChild(dot);
self.trajectoryDots.push(dot);
}
};
self.hideTrajectory = function () {
for (var i = 0; i < self.trajectoryDots.length; i++) {
self.trajectoryDots[i].destroy();
}
self.trajectoryDots = [];
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
var centerGraphics = self.attachAsset('targetCenter', {
anchorX: 0.5,
anchorY: 0.5
});
self.movementType = 'linear';
self.speed = 2;
self.direction = 1;
self.startX = 0;
self.startY = 0;
self.moveTimer = 0;
self.active = true;
self.update = function () {
if (!self.active) return;
self.moveTimer++;
switch (self.movementType) {
case 'linear':
self.x += self.speed * self.direction;
if (self.x > 2100 || self.x < -50) {
self.direction *= -1;
}
break;
case 'circular':
var radius = 100;
self.x = self.startX + Math.cos(self.moveTimer * 0.05) * radius;
self.y = self.startY + Math.sin(self.moveTimer * 0.05) * radius;
break;
case 'zigzag':
self.x += self.speed;
self.y = self.startY + Math.sin(self.moveTimer * 0.1) * 80;
if (self.x > 2100) {
self.x = -50;
}
break;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var slingshot = game.addChild(new Slingshot());
slingshot.x = 1024;
slingshot.y = 2600;
var projectiles = [];
var targets = [];
var score = 0;
var level = 1;
var projectilesRemaining = 5;
var targetsHit = 0;
var combo = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
var projectilesTxt = new Text2('Shots: 5', {
size: 60,
fill: 0xFFFFFF
});
projectilesTxt.anchor.set(0, 0);
projectilesTxt.y = 80;
LK.gui.topRight.addChild(projectilesTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// Initialize first level targets
function spawnTargets() {
targets = [];
var targetCount = Math.min(3 + level, 8);
for (var i = 0; i < targetCount; i++) {
var target = game.addChild(new Target());
var movementTypes = ['linear', 'circular', 'zigzag'];
target.movementType = movementTypes[Math.floor(Math.random() * movementTypes.length)];
switch (target.movementType) {
case 'linear':
target.x = Math.random() * 1800 + 100;
target.y = Math.random() * 800 + 400;
target.speed = 1 + level * 0.5;
break;
case 'circular':
target.startX = Math.random() * 1400 + 400;
target.startY = Math.random() * 600 + 600;
target.x = target.startX;
target.y = target.startY;
break;
case 'zigzag':
target.x = -50;
target.startY = Math.random() * 800 + 400;
target.y = target.startY;
target.speed = 2 + level * 0.3;
break;
}
targets.push(target);
}
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
projectilesTxt.setText('Shots: ' + projectilesRemaining);
levelTxt.setText('Level: ' + level);
}
function nextLevel() {
level++;
projectilesRemaining = 5 + level;
targetsHit = 0;
combo = 0;
spawnTargets();
updateUI();
}
function checkLevelComplete() {
if (targets.length === 0) {
// Bonus points for remaining projectiles
score += projectilesRemaining * 50;
LK.setTimeout(function () {
nextLevel();
}, 1000);
return true;
}
return false;
}
function checkGameOver() {
if (projectilesRemaining <= 0 && projectiles.length === 0 && targets.length > 0) {
LK.showGameOver();
return true;
}
return false;
}
spawnTargets();
updateUI();
var dragging = false;
game.down = function (x, y, obj) {
if (projectilesRemaining <= 0) return;
var dx = x - slingshot.x;
var dy = y - slingshot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
dragging = true;
slingshot.aiming = true;
slingshot.setAim(x, y);
}
};
game.move = function (x, y, obj) {
if (dragging && slingshot.aiming) {
slingshot.setAim(x, y);
}
};
game.up = function (x, y, obj) {
if (dragging && slingshot.aiming && projectilesRemaining > 0) {
// Launch projectile
var projectile = game.addChild(new Projectile());
projectile.x = slingshot.x;
projectile.y = slingshot.y - 90;
var power = Math.sqrt(slingshot.aimX * slingshot.aimX + slingshot.aimY * slingshot.aimY) / 120;
power = Math.min(power, 1) * 35;
var angle = Math.atan2(slingshot.aimY, slingshot.aimX);
projectile.velocityX = Math.cos(angle) * power;
projectile.velocityY = Math.sin(angle) * power;
projectiles.push(projectile);
projectilesRemaining--;
LK.getSound('launch').play();
slingshot.resetStraps();
slingshot.aiming = false;
updateUI();
}
dragging = false;
};
game.update = function () {
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
if (!projectile.active) {
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check collisions with targets
for (var j = targets.length - 1; j >= 0; j--) {
var target = targets[j];
if (target.active && projectile.intersects(target)) {
// Hit!
combo++;
var points = 100 + combo * 25;
score += points;
targetsHit++;
LK.getSound('hit').play();
LK.effects.flashObject(target, 0xFFFFFF, 200);
projectile.active = false;
target.active = false;
target.destroy();
targets.splice(j, 1);
break;
}
}
}
// Update targets
for (var k = targets.length - 1; k >= 0; k--) {
var target = targets[k];
if (!target.active) {
target.destroy();
targets.splice(k, 1);
}
}
// Check win/lose conditions
if (!checkLevelComplete()) {
checkGameOver();
}
updateUI();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.15;
self.active = true;
self.update = function () {
if (!self.active) return;
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen (only bottom and left boundaries)
if (self.x < -50 || self.y > 2782) {
self.active = false;
}
};
return self;
});
var Slingshot = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('slingshotBase', {
anchorX: 0.5,
anchorY: 1.0
});
var leftStrap = self.attachAsset('slingshotStrap', {
anchorX: 0.5,
anchorY: 1.0
});
var rightStrap = self.attachAsset('slingshotStrap', {
anchorX: 0.5,
anchorY: 1.0
});
leftStrap.x = -45;
rightStrap.x = 45;
self.aimX = 0;
self.aimY = 0;
self.aiming = false;
// Trajectory line
self.trajectoryContainer = self.addChild(new Container());
self.trajectoryDots = [];
self.setAim = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var maxDistance = 180;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > maxDistance) {
dx = dx / distance * maxDistance;
dy = dy / distance * maxDistance;
}
self.aimX = dx;
self.aimY = dy;
// Update strap positions
leftStrap.rotation = Math.atan2(dy, dx + 45) - Math.PI / 2;
rightStrap.rotation = Math.atan2(dy, dx - 45) - Math.PI / 2;
var strapLength = Math.sqrt(dx * dx + dy * dy) / 90;
leftStrap.scaleY = strapLength;
rightStrap.scaleY = strapLength;
// Show trajectory line
self.showTrajectory();
};
self.resetStraps = function () {
leftStrap.rotation = 0;
rightStrap.rotation = 0;
leftStrap.scaleY = 1;
rightStrap.scaleY = 1;
self.hideTrajectory();
};
self.showTrajectory = function () {
// Clear existing dots
self.hideTrajectory();
if (!self.aiming) return;
// Calculate launch parameters
var power = Math.sqrt(self.aimX * self.aimX + self.aimY * self.aimY) / 120;
power = Math.min(power, 1) * 35;
var angle = Math.atan2(self.aimY, self.aimX);
var velocityX = Math.cos(angle) * power;
var velocityY = Math.sin(angle) * power;
// Simulate trajectory
var simX = self.x;
var simY = self.y - 90;
var simVelX = velocityX;
var simVelY = velocityY;
var gravity = 0.15;
// Create dots along trajectory
for (var i = 0; i < 60; i += 4) {
// Update simulated position
simVelY += gravity;
simX += simVelX;
simY += simVelY;
// Stop if trajectory goes off screen
if (simX < 0 || simX > 2048 || simY > 2732) break;
// Create trajectory dot
var dot = LK.getAsset('trajectoryDot', {
anchorX: 0.5,
anchorY: 0.5
});
dot.x = simX - self.x;
dot.y = simY - self.y;
dot.alpha = 1 - i / 60; // Fade out over distance
self.trajectoryContainer.addChild(dot);
self.trajectoryDots.push(dot);
}
};
self.hideTrajectory = function () {
for (var i = 0; i < self.trajectoryDots.length; i++) {
self.trajectoryDots[i].destroy();
}
self.trajectoryDots = [];
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
var centerGraphics = self.attachAsset('targetCenter', {
anchorX: 0.5,
anchorY: 0.5
});
self.movementType = 'linear';
self.speed = 2;
self.direction = 1;
self.startX = 0;
self.startY = 0;
self.moveTimer = 0;
self.active = true;
self.update = function () {
if (!self.active) return;
self.moveTimer++;
switch (self.movementType) {
case 'linear':
self.x += self.speed * self.direction;
if (self.x > 2100 || self.x < -50) {
self.direction *= -1;
}
break;
case 'circular':
var radius = 100;
self.x = self.startX + Math.cos(self.moveTimer * 0.05) * radius;
self.y = self.startY + Math.sin(self.moveTimer * 0.05) * radius;
break;
case 'zigzag':
self.x += self.speed;
self.y = self.startY + Math.sin(self.moveTimer * 0.1) * 80;
if (self.x > 2100) {
self.x = -50;
}
break;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var slingshot = game.addChild(new Slingshot());
slingshot.x = 1024;
slingshot.y = 2600;
var projectiles = [];
var targets = [];
var score = 0;
var level = 1;
var projectilesRemaining = 5;
var targetsHit = 0;
var combo = 0;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
var projectilesTxt = new Text2('Shots: 5', {
size: 60,
fill: 0xFFFFFF
});
projectilesTxt.anchor.set(0, 0);
projectilesTxt.y = 80;
LK.gui.topRight.addChild(projectilesTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// Initialize first level targets
function spawnTargets() {
targets = [];
var targetCount = Math.min(3 + level, 8);
for (var i = 0; i < targetCount; i++) {
var target = game.addChild(new Target());
var movementTypes = ['linear', 'circular', 'zigzag'];
target.movementType = movementTypes[Math.floor(Math.random() * movementTypes.length)];
switch (target.movementType) {
case 'linear':
target.x = Math.random() * 1800 + 100;
target.y = Math.random() * 800 + 400;
target.speed = 1 + level * 0.5;
break;
case 'circular':
target.startX = Math.random() * 1400 + 400;
target.startY = Math.random() * 600 + 600;
target.x = target.startX;
target.y = target.startY;
break;
case 'zigzag':
target.x = -50;
target.startY = Math.random() * 800 + 400;
target.y = target.startY;
target.speed = 2 + level * 0.3;
break;
}
targets.push(target);
}
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
projectilesTxt.setText('Shots: ' + projectilesRemaining);
levelTxt.setText('Level: ' + level);
}
function nextLevel() {
level++;
projectilesRemaining = 5 + level;
targetsHit = 0;
combo = 0;
spawnTargets();
updateUI();
}
function checkLevelComplete() {
if (targets.length === 0) {
// Bonus points for remaining projectiles
score += projectilesRemaining * 50;
LK.setTimeout(function () {
nextLevel();
}, 1000);
return true;
}
return false;
}
function checkGameOver() {
if (projectilesRemaining <= 0 && projectiles.length === 0 && targets.length > 0) {
LK.showGameOver();
return true;
}
return false;
}
spawnTargets();
updateUI();
var dragging = false;
game.down = function (x, y, obj) {
if (projectilesRemaining <= 0) return;
var dx = x - slingshot.x;
var dy = y - slingshot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
dragging = true;
slingshot.aiming = true;
slingshot.setAim(x, y);
}
};
game.move = function (x, y, obj) {
if (dragging && slingshot.aiming) {
slingshot.setAim(x, y);
}
};
game.up = function (x, y, obj) {
if (dragging && slingshot.aiming && projectilesRemaining > 0) {
// Launch projectile
var projectile = game.addChild(new Projectile());
projectile.x = slingshot.x;
projectile.y = slingshot.y - 90;
var power = Math.sqrt(slingshot.aimX * slingshot.aimX + slingshot.aimY * slingshot.aimY) / 120;
power = Math.min(power, 1) * 35;
var angle = Math.atan2(slingshot.aimY, slingshot.aimX);
projectile.velocityX = Math.cos(angle) * power;
projectile.velocityY = Math.sin(angle) * power;
projectiles.push(projectile);
projectilesRemaining--;
LK.getSound('launch').play();
slingshot.resetStraps();
slingshot.aiming = false;
updateUI();
}
dragging = false;
};
game.update = function () {
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
if (!projectile.active) {
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Check collisions with targets
for (var j = targets.length - 1; j >= 0; j--) {
var target = targets[j];
if (target.active && projectile.intersects(target)) {
// Hit!
combo++;
var points = 100 + combo * 25;
score += points;
targetsHit++;
LK.getSound('hit').play();
LK.effects.flashObject(target, 0xFFFFFF, 200);
projectile.active = false;
target.active = false;
target.destroy();
targets.splice(j, 1);
break;
}
}
}
// Update targets
for (var k = targets.length - 1; k >= 0; k--) {
var target = targets[k];
if (!target.active) {
target.destroy();
targets.splice(k, 1);
}
}
// Check win/lose conditions
if (!checkLevelComplete()) {
checkGameOver();
}
updateUI();
};