/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12 + Math.random() * 8; // Random speed between 12-20 for music sync
self.lastY = 0;
self.lastCaught = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Crystal = Container.expand(function () {
var self = Container.call(this);
var crystalGraphics = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5
});
crystalGraphics.rotation = Math.PI / 4; // Rotate 45 degrees for visual distinction
self.speed = 10 + Math.random() * 6; // Slightly different speed range
self.lastY = 0;
self.lastCaught = false;
self.update = function () {
self.y += self.speed;
crystalGraphics.rotation += 0.1; // Rotate while falling
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var player;
var balls = [];
var crystals = [];
var dragNode = null;
var ballSpawnTimer = 0;
var ballSpawnInterval = 45; // Spawn every 0.75 seconds at 60fps for faster pace
// Background elements
var backgroundStars = [];
var backgroundNebulae = [];
var backgroundPlanets = [];
// Create animated starfield background
function createBackground() {
// Create stars
for (var i = 0; i < 150; i++) {
var star = game.addChild(LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
}));
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.alpha = 0.3 + Math.random() * 0.7;
star.speed = 0.5 + Math.random() * 2;
backgroundStars.push(star);
}
// Create big stars
for (var i = 0; i < 20; i++) {
var bigStar = game.addChild(LK.getAsset('bigStar', {
anchorX: 0.5,
anchorY: 0.5
}));
bigStar.x = Math.random() * 2048;
bigStar.y = Math.random() * 2732;
bigStar.alpha = 0.4 + Math.random() * 0.6;
bigStar.speed = 0.3 + Math.random() * 1;
backgroundStars.push(bigStar);
}
// Create nebulae
for (var i = 0; i < 8; i++) {
var nebula = game.addChild(LK.getAsset('nebula', {
anchorX: 0.5,
anchorY: 0.5
}));
nebula.x = Math.random() * 2048;
nebula.y = Math.random() * 2732;
nebula.alpha = 0.1 + Math.random() * 0.2;
nebula.speed = 0.2 + Math.random() * 0.8;
nebula.scaleX = 0.5 + Math.random() * 1.5;
nebula.scaleY = 0.5 + Math.random() * 1.5;
backgroundNebulae.push(nebula);
}
// Create planets
for (var i = 0; i < 3; i++) {
var planet = game.addChild(LK.getAsset(Math.random() > 0.5 ? 'planet1' : 'planet2', {
anchorX: 0.5,
anchorY: 0.5
}));
planet.x = Math.random() * 2048;
planet.y = Math.random() * 2732;
planet.alpha = 0.3 + Math.random() * 0.4;
planet.speed = 0.1 + Math.random() * 0.5;
backgroundPlanets.push(planet);
}
}
// Update background animation
function updateBackground() {
// Animate stars
for (var i = 0; i < backgroundStars.length; i++) {
var star = backgroundStars[i];
star.y += star.speed;
star.alpha += Math.sin(LK.ticks * 0.1 + i) * 0.01;
// Reset star position when it goes off screen
if (star.y > 2732 + 50) {
star.y = -50;
star.x = Math.random() * 2048;
}
}
// Animate nebulae
for (var i = 0; i < backgroundNebulae.length; i++) {
var nebula = backgroundNebulae[i];
nebula.y += nebula.speed;
nebula.rotation += 0.005;
// Reset nebula position when it goes off screen
if (nebula.y > 2732 + 200) {
nebula.y = -200;
nebula.x = Math.random() * 2048;
}
}
// Animate planets
for (var i = 0; i < backgroundPlanets.length; i++) {
var planet = backgroundPlanets[i];
planet.y += planet.speed;
planet.rotation += 0.002;
// Reset planet position when it goes off screen
if (planet.y > 2732 + 150) {
planet.y = -150;
planet.x = Math.random() * 2048;
}
}
}
// Initialize background
createBackground();
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create player
player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 150; // Near bottom of screen
// Music will start after first ball is caught
var musicStarted = false;
// Move handler
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
// Keep player within screen bounds
if (dragNode.x < 60) dragNode.x = 60;
if (dragNode.x > 2048 - 60) dragNode.x = 2048 - 60;
}
}
// Event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update loop
game.update = function () {
// Update animated background
updateBackground();
// Spawn balls and crystals
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
ballSpawnTimer = 0;
// Randomly spawn either a ball or crystal
if (Math.random() < 0.7) {
// 70% chance for ball
var newBall = new Ball();
newBall.x = 100 + Math.random() * (2048 - 200); // Random x position
newBall.y = -50; // Start above screen
newBall.lastY = newBall.y;
balls.push(newBall);
game.addChild(newBall);
} else {
// 30% chance for crystal
var newCrystal = new Crystal();
newCrystal.x = 100 + Math.random() * (2048 - 200); // Random x position
newCrystal.y = -50; // Start above screen
newCrystal.lastY = newCrystal.y;
crystals.push(newCrystal);
game.addChild(newCrystal);
}
}
// Update balls and check collisions
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
// Check if ball touches player
var currentCaught = ball.intersects(player);
if (!ball.lastCaught && currentCaught) {
// Start music when ball first touches player
if (!musicStarted) {
LK.playMusic('background');
musicStarted = true;
}
// Ball just got caught
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('catch').play();
ball.destroy();
balls.splice(i, 1);
continue;
}
// Check if ball hit the ground (missed)
if (ball.lastY < 2732 && ball.y >= 2732) {
// Ball just hit the ground - game over
LK.stopMusic();
LK.showGameOver();
return;
}
// Remove balls that are way off screen
if (ball.y > 2732 + 100) {
ball.destroy();
balls.splice(i, 1);
continue;
}
// Update last states
ball.lastY = ball.y;
ball.lastCaught = currentCaught;
}
// Update crystals and check collisions
for (var j = crystals.length - 1; j >= 0; j--) {
var crystal = crystals[j];
// Check if crystal touches player
var currentCrystalCaught = crystal.intersects(player);
if (!crystal.lastCaught && currentCrystalCaught) {
// Start music when crystal first touches player
if (!musicStarted) {
LK.playMusic('background');
musicStarted = true;
}
// Crystal just got caught - worth more points
LK.setScore(LK.getScore() + 2);
scoreTxt.setText(LK.getScore());
LK.getSound('catch').play();
crystal.destroy();
crystals.splice(j, 1);
continue;
}
// Check if crystal hit the ground (missed)
if (crystal.lastY < 2732 && crystal.y >= 2732) {
// Crystal just hit the ground - game over
LK.stopMusic();
LK.showGameOver();
return;
}
// Remove crystals that are way off screen
if (crystal.y > 2732 + 100) {
crystal.destroy();
crystals.splice(j, 1);
continue;
}
// Update last states
crystal.lastY = crystal.y;
crystal.lastCaught = currentCrystalCaught;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12 + Math.random() * 8; // Random speed between 12-20 for music sync
self.lastY = 0;
self.lastCaught = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Crystal = Container.expand(function () {
var self = Container.call(this);
var crystalGraphics = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5
});
crystalGraphics.rotation = Math.PI / 4; // Rotate 45 degrees for visual distinction
self.speed = 10 + Math.random() * 6; // Slightly different speed range
self.lastY = 0;
self.lastCaught = false;
self.update = function () {
self.y += self.speed;
crystalGraphics.rotation += 0.1; // Rotate while falling
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var player;
var balls = [];
var crystals = [];
var dragNode = null;
var ballSpawnTimer = 0;
var ballSpawnInterval = 45; // Spawn every 0.75 seconds at 60fps for faster pace
// Background elements
var backgroundStars = [];
var backgroundNebulae = [];
var backgroundPlanets = [];
// Create animated starfield background
function createBackground() {
// Create stars
for (var i = 0; i < 150; i++) {
var star = game.addChild(LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
}));
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.alpha = 0.3 + Math.random() * 0.7;
star.speed = 0.5 + Math.random() * 2;
backgroundStars.push(star);
}
// Create big stars
for (var i = 0; i < 20; i++) {
var bigStar = game.addChild(LK.getAsset('bigStar', {
anchorX: 0.5,
anchorY: 0.5
}));
bigStar.x = Math.random() * 2048;
bigStar.y = Math.random() * 2732;
bigStar.alpha = 0.4 + Math.random() * 0.6;
bigStar.speed = 0.3 + Math.random() * 1;
backgroundStars.push(bigStar);
}
// Create nebulae
for (var i = 0; i < 8; i++) {
var nebula = game.addChild(LK.getAsset('nebula', {
anchorX: 0.5,
anchorY: 0.5
}));
nebula.x = Math.random() * 2048;
nebula.y = Math.random() * 2732;
nebula.alpha = 0.1 + Math.random() * 0.2;
nebula.speed = 0.2 + Math.random() * 0.8;
nebula.scaleX = 0.5 + Math.random() * 1.5;
nebula.scaleY = 0.5 + Math.random() * 1.5;
backgroundNebulae.push(nebula);
}
// Create planets
for (var i = 0; i < 3; i++) {
var planet = game.addChild(LK.getAsset(Math.random() > 0.5 ? 'planet1' : 'planet2', {
anchorX: 0.5,
anchorY: 0.5
}));
planet.x = Math.random() * 2048;
planet.y = Math.random() * 2732;
planet.alpha = 0.3 + Math.random() * 0.4;
planet.speed = 0.1 + Math.random() * 0.5;
backgroundPlanets.push(planet);
}
}
// Update background animation
function updateBackground() {
// Animate stars
for (var i = 0; i < backgroundStars.length; i++) {
var star = backgroundStars[i];
star.y += star.speed;
star.alpha += Math.sin(LK.ticks * 0.1 + i) * 0.01;
// Reset star position when it goes off screen
if (star.y > 2732 + 50) {
star.y = -50;
star.x = Math.random() * 2048;
}
}
// Animate nebulae
for (var i = 0; i < backgroundNebulae.length; i++) {
var nebula = backgroundNebulae[i];
nebula.y += nebula.speed;
nebula.rotation += 0.005;
// Reset nebula position when it goes off screen
if (nebula.y > 2732 + 200) {
nebula.y = -200;
nebula.x = Math.random() * 2048;
}
}
// Animate planets
for (var i = 0; i < backgroundPlanets.length; i++) {
var planet = backgroundPlanets[i];
planet.y += planet.speed;
planet.rotation += 0.002;
// Reset planet position when it goes off screen
if (planet.y > 2732 + 150) {
planet.y = -150;
planet.x = Math.random() * 2048;
}
}
}
// Initialize background
createBackground();
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create player
player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 150; // Near bottom of screen
// Music will start after first ball is caught
var musicStarted = false;
// Move handler
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
// Keep player within screen bounds
if (dragNode.x < 60) dragNode.x = 60;
if (dragNode.x > 2048 - 60) dragNode.x = 2048 - 60;
}
}
// Event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update loop
game.update = function () {
// Update animated background
updateBackground();
// Spawn balls and crystals
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
ballSpawnTimer = 0;
// Randomly spawn either a ball or crystal
if (Math.random() < 0.7) {
// 70% chance for ball
var newBall = new Ball();
newBall.x = 100 + Math.random() * (2048 - 200); // Random x position
newBall.y = -50; // Start above screen
newBall.lastY = newBall.y;
balls.push(newBall);
game.addChild(newBall);
} else {
// 30% chance for crystal
var newCrystal = new Crystal();
newCrystal.x = 100 + Math.random() * (2048 - 200); // Random x position
newCrystal.y = -50; // Start above screen
newCrystal.lastY = newCrystal.y;
crystals.push(newCrystal);
game.addChild(newCrystal);
}
}
// Update balls and check collisions
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
// Check if ball touches player
var currentCaught = ball.intersects(player);
if (!ball.lastCaught && currentCaught) {
// Start music when ball first touches player
if (!musicStarted) {
LK.playMusic('background');
musicStarted = true;
}
// Ball just got caught
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('catch').play();
ball.destroy();
balls.splice(i, 1);
continue;
}
// Check if ball hit the ground (missed)
if (ball.lastY < 2732 && ball.y >= 2732) {
// Ball just hit the ground - game over
LK.stopMusic();
LK.showGameOver();
return;
}
// Remove balls that are way off screen
if (ball.y > 2732 + 100) {
ball.destroy();
balls.splice(i, 1);
continue;
}
// Update last states
ball.lastY = ball.y;
ball.lastCaught = currentCaught;
}
// Update crystals and check collisions
for (var j = crystals.length - 1; j >= 0; j--) {
var crystal = crystals[j];
// Check if crystal touches player
var currentCrystalCaught = crystal.intersects(player);
if (!crystal.lastCaught && currentCrystalCaught) {
// Start music when crystal first touches player
if (!musicStarted) {
LK.playMusic('background');
musicStarted = true;
}
// Crystal just got caught - worth more points
LK.setScore(LK.getScore() + 2);
scoreTxt.setText(LK.getScore());
LK.getSound('catch').play();
crystal.destroy();
crystals.splice(j, 1);
continue;
}
// Check if crystal hit the ground (missed)
if (crystal.lastY < 2732 && crystal.y >= 2732) {
// Crystal just hit the ground - game over
LK.stopMusic();
LK.showGameOver();
return;
}
// Remove crystals that are way off screen
if (crystal.y > 2732 + 100) {
crystal.destroy();
crystals.splice(j, 1);
continue;
}
// Update last states
crystal.lastY = crystal.y;
crystal.lastCaught = currentCrystalCaught;
}
};