/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ball class var Ball = Container.expand(function () { var self = Container.call(this); // Color index self.colorIndex = 0; self.colorName = COLORS[self.colorIndex].name; // Attach ball asset self.ballAsset = self.attachAsset(COLORS[self.colorIndex].ball, { anchorX: 0.5, anchorY: 0.5 }); // Set color self.setColor = function (idx) { if (self.ballAsset) { self.removeChild(self.ballAsset); } self.colorIndex = idx; self.colorName = COLORS[idx].name; self.ballAsset = self.attachAsset(COLORS[idx].ball, { anchorX: 0.5, anchorY: 0.5 }); }; // Get current color name self.getColor = function () { return self.colorName; }; // Ball speed (pixels per frame) self.speed = 10; // Update method (called every tick) self.update = function () { self.y += self.speed; }; return self; }); // Paddle class var Paddle = Container.expand(function () { var self = Container.call(this); // Default color index self.colorIndex = 0; self.colorName = COLORS[self.colorIndex].name; // Attach paddle asset self.paddleAsset = self.attachAsset(COLORS[self.colorIndex].asset, { anchorX: 0.5, anchorY: 0.5 }); // Set color self.setColor = function (idx) { if (self.paddleAsset) { self.removeChild(self.paddleAsset); } self.colorIndex = idx; self.colorName = COLORS[idx].name; self.paddleAsset = self.attachAsset(COLORS[idx].asset, { anchorX: 0.5, anchorY: 0.5 }); }; // Get current color name self.getColor = function () { return self.colorName; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Color list for easy reference // Sound for catch and fail // Ball: circle, color will be set dynamically // Paddle: wide rectangle, color will be set dynamically // Game variables var COLORS = [{ name: 'red', asset: 'paddle_red', ball: 'ball_red' }, { name: 'green', asset: 'paddle_green', ball: 'ball_green' }, { name: 'blue', asset: 'paddle_blue', ball: 'ball_blue' }, { name: 'yellow', asset: 'paddle_yellow', ball: 'ball_yellow' }]; var paddle; var balls = []; var scoreTxt; var dragPaddle = false; var lastTouchX = 0; var gameOver = false; var ballInterval = 60; // frames between balls (start slow) var minBallInterval = 18; // minimum interval (max speed) var ballSpeed = 10; // initial speed var maxBallSpeed = 32; var speedupEvery = 5; // speed up every N points var lastBallTick = 0; // Score var score = 0; // Helper: get random color index (optionally not equal to excludeIdx) function getRandomColorIdx(excludeIdx) { var idx = Math.floor(Math.random() * COLORS.length); if (excludeIdx !== undefined && COLORS.length > 1) { while (idx === excludeIdx) { idx = Math.floor(Math.random() * COLORS.length); } } return idx; } // Helper: clamp paddle inside game area function clampPaddleX(x) { var halfWidth = paddle.paddleAsset.width / 2; if (x < halfWidth) return halfWidth; if (x > 2048 - halfWidth) return 2048 - halfWidth; return x; } // Create paddle paddle = new Paddle(); paddle.x = 2048 / 2; paddle.y = 2732 - 180; // 180px from bottom game.addChild(paddle); // Create score text scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Move handler (drag paddle horizontally) function handleMove(x, y, obj) { if (dragPaddle) { // Clamp to game area paddle.x = clampPaddleX(x); } } game.move = handleMove; // Down handler (start drag if touch is on/near paddle) game.down = function (x, y, obj) { // Only allow drag if touch is within paddle bounds (with some margin) var px = paddle.x, py = paddle.y; var w = paddle.paddleAsset.width, h = paddle.paddleAsset.height; if (x >= px - w / 2 - 60 && x <= px + w / 2 + 60 && y >= py - h / 2 - 60 && y <= py + h / 2 + 60) { dragPaddle = true; handleMove(x, y, obj); } }; // Up handler (stop drag) game.up = function (x, y, obj) { dragPaddle = false; }; // Ball spawn function function spawnBall() { var ball = new Ball(); // Random color var colorIdx = getRandomColorIdx(); ball.setColor(colorIdx); // Random x position (keep ball fully on screen) var bx = 100 + Math.random() * (2048 - 200); ball.x = bx; ball.y = -60; // just above screen // Set speed ball.speed = ballSpeed; // Track lastY for off-screen detection ball.lastY = ball.y; // Add to game balls.push(ball); game.addChild(ball); } // Game update loop game.update = function () { if (gameOver) return; // Spawn balls at interval if (LK.ticks - lastBallTick >= ballInterval) { spawnBall(); lastBallTick = LK.ticks; } // Update balls for (var i = balls.length - 1; i >= 0; i--) { var ball = balls[i]; ball.update(); // Off-screen detection if (ball.lastY < 2732 + 60 && ball.y >= 2732 + 60) { // Ball went off screen // If it was a matching color, player missed it: game over if (ball.getColor() === paddle.getColor()) { LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 800); gameOver = true; LK.showGameOver(); return; } else { // Remove non-matching ball ball.destroy(); balls.splice(i, 1); continue; } } // Collision detection (simple AABB) var px = paddle.x, py = paddle.y; var pw = paddle.paddleAsset.width, ph = paddle.paddleAsset.height; var bx = ball.x, by = ball.y; var bw = ball.ballAsset.width, bh = ball.ballAsset.height; var intersect = !(px + pw / 2 < bx - bw / 2 || px - pw / 2 > bx + bw / 2 || py + ph / 2 < by - bh / 2 || py - ph / 2 > by + bh / 2); if (intersect) { if (ball.getColor() === paddle.getColor()) { // Correct catch! LK.getSound('catch').play(); LK.effects.flashObject(paddle, 0xffffff, 200); score += 1; LK.setScore(score); scoreTxt.setText(score); // Speed up game every N points if (score % speedupEvery === 0) { if (ballInterval > minBallInterval) { ballInterval -= 6; if (ballInterval < minBallInterval) ballInterval = minBallInterval; } if (ballSpeed < maxBallSpeed) { ballSpeed += 2; if (ballSpeed > maxBallSpeed) ballSpeed = maxBallSpeed; } } // Change paddle color (not same as before) var newColorIdx = getRandomColorIdx(paddle.colorIndex); paddle.setColor(newColorIdx); // Remove ball ball.destroy(); balls.splice(i, 1); } else { // Wrong color: game over LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 800); gameOver = true; LK.showGameOver(); return; } } // Update lastY ball.lastY = ball.y; } }; // Reset game state on new game game.on('reset', function () { // Remove all balls for (var i = 0; i < balls.length; i++) { balls[i].destroy(); } balls = []; // Reset paddle color paddle.setColor(getRandomColorIdx()); // Reset paddle position paddle.x = 2048 / 2; // Reset score score = 0; LK.setScore(0); scoreTxt.setText('0'); // Reset speed ballInterval = 60; ballSpeed = 10; lastBallTick = LK.ticks; gameOver = false; dragPaddle = false; });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Ball class
var Ball = Container.expand(function () {
var self = Container.call(this);
// Color index
self.colorIndex = 0;
self.colorName = COLORS[self.colorIndex].name;
// Attach ball asset
self.ballAsset = self.attachAsset(COLORS[self.colorIndex].ball, {
anchorX: 0.5,
anchorY: 0.5
});
// Set color
self.setColor = function (idx) {
if (self.ballAsset) {
self.removeChild(self.ballAsset);
}
self.colorIndex = idx;
self.colorName = COLORS[idx].name;
self.ballAsset = self.attachAsset(COLORS[idx].ball, {
anchorX: 0.5,
anchorY: 0.5
});
};
// Get current color name
self.getColor = function () {
return self.colorName;
};
// Ball speed (pixels per frame)
self.speed = 10;
// Update method (called every tick)
self.update = function () {
self.y += self.speed;
};
return self;
});
// Paddle class
var Paddle = Container.expand(function () {
var self = Container.call(this);
// Default color index
self.colorIndex = 0;
self.colorName = COLORS[self.colorIndex].name;
// Attach paddle asset
self.paddleAsset = self.attachAsset(COLORS[self.colorIndex].asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Set color
self.setColor = function (idx) {
if (self.paddleAsset) {
self.removeChild(self.paddleAsset);
}
self.colorIndex = idx;
self.colorName = COLORS[idx].name;
self.paddleAsset = self.attachAsset(COLORS[idx].asset, {
anchorX: 0.5,
anchorY: 0.5
});
};
// Get current color name
self.getColor = function () {
return self.colorName;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Color list for easy reference
// Sound for catch and fail
// Ball: circle, color will be set dynamically
// Paddle: wide rectangle, color will be set dynamically
// Game variables
var COLORS = [{
name: 'red',
asset: 'paddle_red',
ball: 'ball_red'
}, {
name: 'green',
asset: 'paddle_green',
ball: 'ball_green'
}, {
name: 'blue',
asset: 'paddle_blue',
ball: 'ball_blue'
}, {
name: 'yellow',
asset: 'paddle_yellow',
ball: 'ball_yellow'
}];
var paddle;
var balls = [];
var scoreTxt;
var dragPaddle = false;
var lastTouchX = 0;
var gameOver = false;
var ballInterval = 60; // frames between balls (start slow)
var minBallInterval = 18; // minimum interval (max speed)
var ballSpeed = 10; // initial speed
var maxBallSpeed = 32;
var speedupEvery = 5; // speed up every N points
var lastBallTick = 0;
// Score
var score = 0;
// Helper: get random color index (optionally not equal to excludeIdx)
function getRandomColorIdx(excludeIdx) {
var idx = Math.floor(Math.random() * COLORS.length);
if (excludeIdx !== undefined && COLORS.length > 1) {
while (idx === excludeIdx) {
idx = Math.floor(Math.random() * COLORS.length);
}
}
return idx;
}
// Helper: clamp paddle inside game area
function clampPaddleX(x) {
var halfWidth = paddle.paddleAsset.width / 2;
if (x < halfWidth) return halfWidth;
if (x > 2048 - halfWidth) return 2048 - halfWidth;
return x;
}
// Create paddle
paddle = new Paddle();
paddle.x = 2048 / 2;
paddle.y = 2732 - 180; // 180px from bottom
game.addChild(paddle);
// Create score text
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Move handler (drag paddle horizontally)
function handleMove(x, y, obj) {
if (dragPaddle) {
// Clamp to game area
paddle.x = clampPaddleX(x);
}
}
game.move = handleMove;
// Down handler (start drag if touch is on/near paddle)
game.down = function (x, y, obj) {
// Only allow drag if touch is within paddle bounds (with some margin)
var px = paddle.x,
py = paddle.y;
var w = paddle.paddleAsset.width,
h = paddle.paddleAsset.height;
if (x >= px - w / 2 - 60 && x <= px + w / 2 + 60 && y >= py - h / 2 - 60 && y <= py + h / 2 + 60) {
dragPaddle = true;
handleMove(x, y, obj);
}
};
// Up handler (stop drag)
game.up = function (x, y, obj) {
dragPaddle = false;
};
// Ball spawn function
function spawnBall() {
var ball = new Ball();
// Random color
var colorIdx = getRandomColorIdx();
ball.setColor(colorIdx);
// Random x position (keep ball fully on screen)
var bx = 100 + Math.random() * (2048 - 200);
ball.x = bx;
ball.y = -60; // just above screen
// Set speed
ball.speed = ballSpeed;
// Track lastY for off-screen detection
ball.lastY = ball.y;
// Add to game
balls.push(ball);
game.addChild(ball);
}
// Game update loop
game.update = function () {
if (gameOver) return;
// Spawn balls at interval
if (LK.ticks - lastBallTick >= ballInterval) {
spawnBall();
lastBallTick = LK.ticks;
}
// Update balls
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
ball.update();
// Off-screen detection
if (ball.lastY < 2732 + 60 && ball.y >= 2732 + 60) {
// Ball went off screen
// If it was a matching color, player missed it: game over
if (ball.getColor() === paddle.getColor()) {
LK.getSound('fail').play();
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
} else {
// Remove non-matching ball
ball.destroy();
balls.splice(i, 1);
continue;
}
}
// Collision detection (simple AABB)
var px = paddle.x,
py = paddle.y;
var pw = paddle.paddleAsset.width,
ph = paddle.paddleAsset.height;
var bx = ball.x,
by = ball.y;
var bw = ball.ballAsset.width,
bh = ball.ballAsset.height;
var intersect = !(px + pw / 2 < bx - bw / 2 || px - pw / 2 > bx + bw / 2 || py + ph / 2 < by - bh / 2 || py - ph / 2 > by + bh / 2);
if (intersect) {
if (ball.getColor() === paddle.getColor()) {
// Correct catch!
LK.getSound('catch').play();
LK.effects.flashObject(paddle, 0xffffff, 200);
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Speed up game every N points
if (score % speedupEvery === 0) {
if (ballInterval > minBallInterval) {
ballInterval -= 6;
if (ballInterval < minBallInterval) ballInterval = minBallInterval;
}
if (ballSpeed < maxBallSpeed) {
ballSpeed += 2;
if (ballSpeed > maxBallSpeed) ballSpeed = maxBallSpeed;
}
}
// Change paddle color (not same as before)
var newColorIdx = getRandomColorIdx(paddle.colorIndex);
paddle.setColor(newColorIdx);
// Remove ball
ball.destroy();
balls.splice(i, 1);
} else {
// Wrong color: game over
LK.getSound('fail').play();
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
}
}
// Update lastY
ball.lastY = ball.y;
}
};
// Reset game state on new game
game.on('reset', function () {
// Remove all balls
for (var i = 0; i < balls.length; i++) {
balls[i].destroy();
}
balls = [];
// Reset paddle color
paddle.setColor(getRandomColorIdx());
// Reset paddle position
paddle.x = 2048 / 2;
// Reset score
score = 0;
LK.setScore(0);
scoreTxt.setText('0');
// Reset speed
ballInterval = 60;
ballSpeed = 10;
lastBallTick = LK.ticks;
gameOver = false;
dragPaddle = false;
});