/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ShooterMarble = Container.expand(function () {
var self = Container.call(this);
var marbleGraphics = self.attachAsset('shooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.98;
self.maxVelocity = 25;
self.isMoving = false;
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (self.isMoving) {
self.velocityX *= self.friction;
self.velocityY *= self.friction;
self.x += self.velocityX;
self.y += self.velocityY;
if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
}
}
};
self.shoot = function (vx, vy) {
var speed = Math.sqrt(vx * vx + vy * vy);
if (speed > self.maxVelocity) {
var scale = self.maxVelocity / speed;
vx *= scale;
vy *= scale;
}
self.velocityX = vx;
self.velocityY = vy;
self.isMoving = true;
};
return self;
});
var TargetMarble = Container.expand(function () {
var self = Container.call(this);
var marbleGraphics = self.attachAsset('targetMarble', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.98;
self.isOutOfBounds = false;
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
self.x += self.velocityX;
self.y += self.velocityY;
if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
self.velocityX = 0;
self.velocityY = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF5DEB3
});
/****
* Game Code
****/
var currentLevel = storage.currentLevel || 1;
var attempsRemaining = 5;
var marblesHit = 0;
var targetMarbles = [];
var shooterMarble = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var playAreaBounds = null;
var levelText = new Text2('Level: ' + currentLevel, {
size: 100,
fill: '#FFFFFF'
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
var attemptsText = new Text2('Attempts: ' + attempsRemaining, {
size: 100,
fill: '#FFFFFF'
});
attemptsText.anchor.set(0.5, 0);
attemptsText.x = 500;
LK.gui.top.addChild(attemptsText);
var scoreText = new Text2('Hit: 0', {
size: 100,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 1000;
LK.gui.top.addChild(scoreText);
function initializeLevel() {
marblesHit = 0;
attempsRemaining = 5;
targetMarbles = [];
var playArea = LK.getAsset('playArea', {
anchorX: 0.5,
anchorY: 0.5
});
playArea.x = 1024;
playArea.y = 1400;
game.addChild(playArea);
playAreaBounds = {
x: 1024 - 750,
y: 400,
width: 1500,
height: 2000
};
shooterMarble = game.addChild(new ShooterMarble());
shooterMarble.x = 1024;
shooterMarble.y = 2350;
var marbleCount = 3 + currentLevel;
if (marbleCount > 12) marbleCount = 12;
for (var i = 0; i < marbleCount; i++) {
var marble = game.addChild(new TargetMarble());
if (currentLevel % 3 === 1) {
var triangleSpacing = 80;
var row = Math.floor(i / 3);
var col = i % 3;
marble.x = 1024 - 80 + col * triangleSpacing;
marble.y = 600 + row * triangleSpacing;
} else if (currentLevel % 3 === 2) {
var circleRadius = 150 + currentLevel * 20;
var angle = i / marbleCount * Math.PI * 2;
marble.x = 1024 + Math.cos(angle) * circleRadius;
marble.y = 1000 + Math.sin(angle) * circleRadius;
} else {
marble.x = 300 + i % 5 * 250;
marble.y = 500 + Math.floor(i / 5) * 200;
}
targetMarbles.push(marble);
}
}
function checkMarbleOutOfBounds(marble) {
return marble.x < playAreaBounds.x || marble.x > playAreaBounds.x + playAreaBounds.width || marble.y < playAreaBounds.y || marble.y > playAreaBounds.y + playAreaBounds.height;
}
function handleCollision(marble1, marble2) {
var dx = marble2.x - marble1.x;
var dy = marble2.y - marble1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = 70;
if (distance < minDistance && distance > 0) {
var angle = Math.atan2(dy, dx);
var sin = Math.sin(angle);
var cos = Math.cos(angle);
var vx1 = marble1.velocityX * cos + marble1.velocityY * sin;
var vy1 = marble1.velocityY * cos - marble1.velocityX * sin;
var vx2 = marble2.velocityX * cos + marble2.velocityY * sin;
var vy2 = marble2.velocityY * cos - marble2.velocityX * sin;
var temp = vx1;
vx1 = vx2;
vx2 = temp;
marble1.velocityX = vx1 * cos - vy1 * sin;
marble1.velocityY = vy1 * cos + vx1 * sin;
marble2.velocityX = vx2 * cos - vy2 * sin;
marble2.velocityY = vy2 * cos + vx2 * sin;
var overlap = minDistance - distance;
var moveX = overlap / 2 * cos;
var moveY = overlap / 2 * sin;
marble1.x -= moveX;
marble1.y -= moveY;
marble2.x += moveX;
marble2.y += moveY;
LK.getSound('hit').play();
}
}
function handleMove(x, y, obj) {
if (isDragging) {
var distX = x - dragStartX;
var distY = y - dragStartY;
shooterMarble.x = dragStartX + distX;
shooterMarble.y = dragStartY + distY;
}
}
function handleDown(x, y, obj) {
if (!shooterMarble.isMoving) {
isDragging = true;
dragStartX = shooterMarble.x;
dragStartY = shooterMarble.y;
}
}
function handleUp(x, y, obj) {
if (isDragging) {
isDragging = false;
var distX = dragStartX - shooterMarble.x;
var distY = dragStartY - shooterMarble.y;
shooterMarble.shoot(distX * 0.3, distY * 0.3);
attempsRemaining--;
attemptsText.setText('Attempts: ' + attempsRemaining);
LK.getSound('hit').play();
}
}
game.move = handleMove;
game.down = handleDown;
game.up = handleUp;
game.update = function () {
if (shooterMarble) {
shooterMarble.update();
for (var i = targetMarbles.length - 1; i >= 0; i--) {
var marble = targetMarbles[i];
marble.update();
if (!marble.isOutOfBounds && checkMarbleOutOfBounds(marble)) {
marble.isOutOfBounds = true;
marble.destroy();
targetMarbles.splice(i, 1);
marblesHit++;
scoreText.setText('Hit: ' + marblesHit);
LK.getSound('success').play();
continue;
}
if (shooterMarble.intersects(marble)) {
handleCollision(shooterMarble, marble);
}
for (var j = i - 1; j >= 0; j--) {
if (targetMarbles[j] && marble.intersects(targetMarbles[j])) {
handleCollision(marble, targetMarbles[j]);
}
}
}
if (targetMarbles.length === 0 && !shooterMarble.isMoving) {
storage.currentLevel = currentLevel + 1;
LK.showYouWin();
}
if (attempsRemaining === 0 && !shooterMarble.isMoving && targetMarbles.length > 0) {
LK.showGameOver();
}
}
};
initializeLevel();
LK.playMusic('bgmusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ShooterMarble = Container.expand(function () {
var self = Container.call(this);
var marbleGraphics = self.attachAsset('shooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.98;
self.maxVelocity = 25;
self.isMoving = false;
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (self.isMoving) {
self.velocityX *= self.friction;
self.velocityY *= self.friction;
self.x += self.velocityX;
self.y += self.velocityY;
if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
}
}
};
self.shoot = function (vx, vy) {
var speed = Math.sqrt(vx * vx + vy * vy);
if (speed > self.maxVelocity) {
var scale = self.maxVelocity / speed;
vx *= scale;
vy *= scale;
}
self.velocityX = vx;
self.velocityY = vy;
self.isMoving = true;
};
return self;
});
var TargetMarble = Container.expand(function () {
var self = Container.call(this);
var marbleGraphics = self.attachAsset('targetMarble', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.98;
self.isOutOfBounds = false;
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
self.x += self.velocityX;
self.y += self.velocityY;
if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
self.velocityX = 0;
self.velocityY = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF5DEB3
});
/****
* Game Code
****/
var currentLevel = storage.currentLevel || 1;
var attempsRemaining = 5;
var marblesHit = 0;
var targetMarbles = [];
var shooterMarble = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var playAreaBounds = null;
var levelText = new Text2('Level: ' + currentLevel, {
size: 100,
fill: '#FFFFFF'
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
var attemptsText = new Text2('Attempts: ' + attempsRemaining, {
size: 100,
fill: '#FFFFFF'
});
attemptsText.anchor.set(0.5, 0);
attemptsText.x = 500;
LK.gui.top.addChild(attemptsText);
var scoreText = new Text2('Hit: 0', {
size: 100,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 1000;
LK.gui.top.addChild(scoreText);
function initializeLevel() {
marblesHit = 0;
attempsRemaining = 5;
targetMarbles = [];
var playArea = LK.getAsset('playArea', {
anchorX: 0.5,
anchorY: 0.5
});
playArea.x = 1024;
playArea.y = 1400;
game.addChild(playArea);
playAreaBounds = {
x: 1024 - 750,
y: 400,
width: 1500,
height: 2000
};
shooterMarble = game.addChild(new ShooterMarble());
shooterMarble.x = 1024;
shooterMarble.y = 2350;
var marbleCount = 3 + currentLevel;
if (marbleCount > 12) marbleCount = 12;
for (var i = 0; i < marbleCount; i++) {
var marble = game.addChild(new TargetMarble());
if (currentLevel % 3 === 1) {
var triangleSpacing = 80;
var row = Math.floor(i / 3);
var col = i % 3;
marble.x = 1024 - 80 + col * triangleSpacing;
marble.y = 600 + row * triangleSpacing;
} else if (currentLevel % 3 === 2) {
var circleRadius = 150 + currentLevel * 20;
var angle = i / marbleCount * Math.PI * 2;
marble.x = 1024 + Math.cos(angle) * circleRadius;
marble.y = 1000 + Math.sin(angle) * circleRadius;
} else {
marble.x = 300 + i % 5 * 250;
marble.y = 500 + Math.floor(i / 5) * 200;
}
targetMarbles.push(marble);
}
}
function checkMarbleOutOfBounds(marble) {
return marble.x < playAreaBounds.x || marble.x > playAreaBounds.x + playAreaBounds.width || marble.y < playAreaBounds.y || marble.y > playAreaBounds.y + playAreaBounds.height;
}
function handleCollision(marble1, marble2) {
var dx = marble2.x - marble1.x;
var dy = marble2.y - marble1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = 70;
if (distance < minDistance && distance > 0) {
var angle = Math.atan2(dy, dx);
var sin = Math.sin(angle);
var cos = Math.cos(angle);
var vx1 = marble1.velocityX * cos + marble1.velocityY * sin;
var vy1 = marble1.velocityY * cos - marble1.velocityX * sin;
var vx2 = marble2.velocityX * cos + marble2.velocityY * sin;
var vy2 = marble2.velocityY * cos - marble2.velocityX * sin;
var temp = vx1;
vx1 = vx2;
vx2 = temp;
marble1.velocityX = vx1 * cos - vy1 * sin;
marble1.velocityY = vy1 * cos + vx1 * sin;
marble2.velocityX = vx2 * cos - vy2 * sin;
marble2.velocityY = vy2 * cos + vx2 * sin;
var overlap = minDistance - distance;
var moveX = overlap / 2 * cos;
var moveY = overlap / 2 * sin;
marble1.x -= moveX;
marble1.y -= moveY;
marble2.x += moveX;
marble2.y += moveY;
LK.getSound('hit').play();
}
}
function handleMove(x, y, obj) {
if (isDragging) {
var distX = x - dragStartX;
var distY = y - dragStartY;
shooterMarble.x = dragStartX + distX;
shooterMarble.y = dragStartY + distY;
}
}
function handleDown(x, y, obj) {
if (!shooterMarble.isMoving) {
isDragging = true;
dragStartX = shooterMarble.x;
dragStartY = shooterMarble.y;
}
}
function handleUp(x, y, obj) {
if (isDragging) {
isDragging = false;
var distX = dragStartX - shooterMarble.x;
var distY = dragStartY - shooterMarble.y;
shooterMarble.shoot(distX * 0.3, distY * 0.3);
attempsRemaining--;
attemptsText.setText('Attempts: ' + attempsRemaining);
LK.getSound('hit').play();
}
}
game.move = handleMove;
game.down = handleDown;
game.up = handleUp;
game.update = function () {
if (shooterMarble) {
shooterMarble.update();
for (var i = targetMarbles.length - 1; i >= 0; i--) {
var marble = targetMarbles[i];
marble.update();
if (!marble.isOutOfBounds && checkMarbleOutOfBounds(marble)) {
marble.isOutOfBounds = true;
marble.destroy();
targetMarbles.splice(i, 1);
marblesHit++;
scoreText.setText('Hit: ' + marblesHit);
LK.getSound('success').play();
continue;
}
if (shooterMarble.intersects(marble)) {
handleCollision(shooterMarble, marble);
}
for (var j = i - 1; j >= 0; j--) {
if (targetMarbles[j] && marble.intersects(targetMarbles[j])) {
handleCollision(marble, targetMarbles[j]);
}
}
}
if (targetMarbles.length === 0 && !shooterMarble.isMoving) {
storage.currentLevel = currentLevel + 1;
LK.showYouWin();
}
if (attempsRemaining === 0 && !shooterMarble.isMoving && targetMarbles.length > 0) {
LK.showGameOver();
}
}
};
initializeLevel();
LK.playMusic('bgmusic');