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