/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
// Ball graphics
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.vx = 0;
self.vy = 0;
self.gravity = 0.3;
self.friction = 0.99;
self.bounceForce = 10;
self.maxSpeed = 25;
self.lastTouched = 0;
// Bounce the ball when touched
self.bounce = function (touchX, touchY) {
// Calculate direction vector from touch point to ball center
var dx = self.x - touchX;
var dy = self.y - touchY;
// Normalize the direction vector
var length = Math.sqrt(dx * dx + dy * dy);
if (length > 0) {
dx /= length;
dy /= length;
}
// Apply bounce force in the direction away from touch
self.vx += dx * self.bounceForce;
self.vy += dy * self.bounceForce;
// Cap the speed
var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy);
if (speed > self.maxSpeed) {
self.vx = self.vx / speed * self.maxSpeed;
self.vy = self.vy / speed * self.maxSpeed;
}
// Scale the ball quickly
tween(ballGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
// Record the time of last touch
self.lastTouched = Date.now();
// Play bounce sound
LK.getSound('bounce').play();
return true;
};
// Change the color of the ball
self.changeColor = function () {
var colors = [0xFFCC00, 0xFF6666, 0x66FF66, 0x6666FF, 0xFF66FF, 0x66FFFF, 0xFFFF66];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
tween(ballGraphics, {
tint: randomColor
}, {
duration: 300
});
};
// Check if ball was touched recently (within the last second)
self.recentlyTouched = function () {
return Date.now() - self.lastTouched < 1000;
};
// Update ball physics
self.update = function () {
// Apply gravity
self.vy += self.gravity;
// Apply friction
self.vx *= self.friction;
self.vy *= self.friction;
// Update position
self.x += self.vx;
self.y += self.vy;
// Check boundaries - game width is 2048, height is 2732
var radius = ballGraphics.width / 2;
var bounced = false;
if (self.x < radius) {
self.x = radius;
self.vx = Math.abs(self.vx) * 0.8;
bounced = true;
} else if (self.x > 2048 - radius) {
self.x = 2048 - radius;
self.vx = -Math.abs(self.vx) * 0.8;
bounced = true;
}
if (self.y < radius) {
self.y = radius;
self.vy = Math.abs(self.vy) * 0.8;
bounced = true;
} else if (self.y > 2732 - radius) {
self.y = 2732 - radius;
self.vy = -Math.abs(self.vy) * 0.8;
bounced = true;
}
// Play edge bounce sound if we hit an edge
if (bounced) {
LK.getSound('edge').play();
}
// Rotate based on horizontal speed
ballGraphics.rotation += self.vx * 0.01;
};
// Handle touch/click on ball
self.down = function (x, y, obj) {
self.bounce(x, y);
};
return self;
});
var TouchEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('touchEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.init = function (x, y, color) {
self.x = x;
self.y = y;
effectGraphics.tint = color || 0xFFFFFF;
effectGraphics.scaleX = 0.1;
effectGraphics.scaleY = 0.1;
effectGraphics.alpha = 0.7;
// Animate the effect
tween(effectGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game variables
var ball;
var score = 0;
var scoreText;
var timeText;
var startTime;
var gameActive = false;
var touchEffects = [];
var difficulty = 1;
// Create and position score text
scoreText = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create and position time text
timeText = new Text2('Time: 0', {
size: 60,
fill: 0xCCCCCC
});
timeText.anchor.set(0.5, 0);
timeText.y = 130;
LK.gui.top.addChild(timeText);
// Create instructions text at the start
var instructionsText = new Text2('Tap the ball to keep it bouncing!', {
size: 80,
fill: 0xFFFFFF
});
instructionsText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsText);
// Initialize the game
function initGame() {
// Create the ball
ball = new Ball();
ball.x = 2048 / 2;
ball.y = 2732 / 3;
game.addChild(ball);
// Apply initial gentle force
ball.vx = Math.random() * 4 - 2;
ball.vy = -5;
// Reset game variables
score = 0;
difficulty = 1;
scoreText.setText('0');
startTime = Date.now();
gameActive = true;
// Remove instructions
if (instructionsText.parent) {
instructionsText.parent.removeChild(instructionsText);
}
// Play background music
LK.playMusic('gameplay');
}
// Create touch effect
function createTouchEffect(x, y) {
var colors = [0xFFCC00, 0xFF6666, 0x66FF66, 0x6666FF, 0xFF66FF, 0x66FFFF, 0xFFFF66];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
var effect = new TouchEffect();
effect.init(x, y, randomColor);
game.addChild(effect);
touchEffects.push(effect);
}
// Handle touch/click on the game
game.down = function (x, y, obj) {
// Start the game if not active
if (!gameActive) {
initGame();
return;
}
// Check if we directly touched the ball
var touchedBall = false;
// Calculate distance to ball
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If we're within the ball radius, the bounce was handled by ball.down
// If we're close to the ball, count it as a touch
if (distance < ball.children[0].width) {
touchedBall = true;
} else if (distance < ball.children[0].width * 2) {
// Close enough to count as a touch, but need to call bounce manually
touchedBall = ball.bounce(x, y);
}
// Create touch effect and update score if we touched the ball
if (touchedBall) {
createTouchEffect(x, y);
score += Math.floor(10 * difficulty);
scoreText.setText(score.toString());
ball.changeColor();
} else {
// We missed the ball
LK.getSound('miss').play();
}
};
// Update game state
game.update = function () {
if (!gameActive) {
return;
}
// Update game timer
var elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
timeText.setText('Time: ' + elapsedSeconds);
// Increase difficulty over time
difficulty = 1 + elapsedSeconds / 30;
// If difficulty increases, increase ball speed
ball.maxSpeed = 25 + difficulty * 3;
ball.gravity = 0.3 + difficulty * 0.05;
// Check if the ball is moving too slowly
var speed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy);
if (speed < 1 && !ball.recentlyTouched()) {
// Ball stopped moving for too long, game over
LK.effects.flashScreen(0xFF0000, 500);
LK.stopMusic();
LK.showGameOver();
gameActive = false;
}
// Handle cleanup of touch effects
for (var i = touchEffects.length - 1; i >= 0; i--) {
if (!touchEffects[i].parent) {
touchEffects.splice(i, 1);
}
}
};
// Start with a welcome screen - game will start on first touch
gameActive = false; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
// Ball graphics
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.vx = 0;
self.vy = 0;
self.gravity = 0.3;
self.friction = 0.99;
self.bounceForce = 10;
self.maxSpeed = 25;
self.lastTouched = 0;
// Bounce the ball when touched
self.bounce = function (touchX, touchY) {
// Calculate direction vector from touch point to ball center
var dx = self.x - touchX;
var dy = self.y - touchY;
// Normalize the direction vector
var length = Math.sqrt(dx * dx + dy * dy);
if (length > 0) {
dx /= length;
dy /= length;
}
// Apply bounce force in the direction away from touch
self.vx += dx * self.bounceForce;
self.vy += dy * self.bounceForce;
// Cap the speed
var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy);
if (speed > self.maxSpeed) {
self.vx = self.vx / speed * self.maxSpeed;
self.vy = self.vy / speed * self.maxSpeed;
}
// Scale the ball quickly
tween(ballGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
// Record the time of last touch
self.lastTouched = Date.now();
// Play bounce sound
LK.getSound('bounce').play();
return true;
};
// Change the color of the ball
self.changeColor = function () {
var colors = [0xFFCC00, 0xFF6666, 0x66FF66, 0x6666FF, 0xFF66FF, 0x66FFFF, 0xFFFF66];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
tween(ballGraphics, {
tint: randomColor
}, {
duration: 300
});
};
// Check if ball was touched recently (within the last second)
self.recentlyTouched = function () {
return Date.now() - self.lastTouched < 1000;
};
// Update ball physics
self.update = function () {
// Apply gravity
self.vy += self.gravity;
// Apply friction
self.vx *= self.friction;
self.vy *= self.friction;
// Update position
self.x += self.vx;
self.y += self.vy;
// Check boundaries - game width is 2048, height is 2732
var radius = ballGraphics.width / 2;
var bounced = false;
if (self.x < radius) {
self.x = radius;
self.vx = Math.abs(self.vx) * 0.8;
bounced = true;
} else if (self.x > 2048 - radius) {
self.x = 2048 - radius;
self.vx = -Math.abs(self.vx) * 0.8;
bounced = true;
}
if (self.y < radius) {
self.y = radius;
self.vy = Math.abs(self.vy) * 0.8;
bounced = true;
} else if (self.y > 2732 - radius) {
self.y = 2732 - radius;
self.vy = -Math.abs(self.vy) * 0.8;
bounced = true;
}
// Play edge bounce sound if we hit an edge
if (bounced) {
LK.getSound('edge').play();
}
// Rotate based on horizontal speed
ballGraphics.rotation += self.vx * 0.01;
};
// Handle touch/click on ball
self.down = function (x, y, obj) {
self.bounce(x, y);
};
return self;
});
var TouchEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('touchEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.init = function (x, y, color) {
self.x = x;
self.y = y;
effectGraphics.tint = color || 0xFFFFFF;
effectGraphics.scaleX = 0.1;
effectGraphics.scaleY = 0.1;
effectGraphics.alpha = 0.7;
// Animate the effect
tween(effectGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game variables
var ball;
var score = 0;
var scoreText;
var timeText;
var startTime;
var gameActive = false;
var touchEffects = [];
var difficulty = 1;
// Create and position score text
scoreText = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create and position time text
timeText = new Text2('Time: 0', {
size: 60,
fill: 0xCCCCCC
});
timeText.anchor.set(0.5, 0);
timeText.y = 130;
LK.gui.top.addChild(timeText);
// Create instructions text at the start
var instructionsText = new Text2('Tap the ball to keep it bouncing!', {
size: 80,
fill: 0xFFFFFF
});
instructionsText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsText);
// Initialize the game
function initGame() {
// Create the ball
ball = new Ball();
ball.x = 2048 / 2;
ball.y = 2732 / 3;
game.addChild(ball);
// Apply initial gentle force
ball.vx = Math.random() * 4 - 2;
ball.vy = -5;
// Reset game variables
score = 0;
difficulty = 1;
scoreText.setText('0');
startTime = Date.now();
gameActive = true;
// Remove instructions
if (instructionsText.parent) {
instructionsText.parent.removeChild(instructionsText);
}
// Play background music
LK.playMusic('gameplay');
}
// Create touch effect
function createTouchEffect(x, y) {
var colors = [0xFFCC00, 0xFF6666, 0x66FF66, 0x6666FF, 0xFF66FF, 0x66FFFF, 0xFFFF66];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
var effect = new TouchEffect();
effect.init(x, y, randomColor);
game.addChild(effect);
touchEffects.push(effect);
}
// Handle touch/click on the game
game.down = function (x, y, obj) {
// Start the game if not active
if (!gameActive) {
initGame();
return;
}
// Check if we directly touched the ball
var touchedBall = false;
// Calculate distance to ball
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If we're within the ball radius, the bounce was handled by ball.down
// If we're close to the ball, count it as a touch
if (distance < ball.children[0].width) {
touchedBall = true;
} else if (distance < ball.children[0].width * 2) {
// Close enough to count as a touch, but need to call bounce manually
touchedBall = ball.bounce(x, y);
}
// Create touch effect and update score if we touched the ball
if (touchedBall) {
createTouchEffect(x, y);
score += Math.floor(10 * difficulty);
scoreText.setText(score.toString());
ball.changeColor();
} else {
// We missed the ball
LK.getSound('miss').play();
}
};
// Update game state
game.update = function () {
if (!gameActive) {
return;
}
// Update game timer
var elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
timeText.setText('Time: ' + elapsedSeconds);
// Increase difficulty over time
difficulty = 1 + elapsedSeconds / 30;
// If difficulty increases, increase ball speed
ball.maxSpeed = 25 + difficulty * 3;
ball.gravity = 0.3 + difficulty * 0.05;
// Check if the ball is moving too slowly
var speed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy);
if (speed < 1 && !ball.recentlyTouched()) {
// Ball stopped moving for too long, game over
LK.effects.flashScreen(0xFF0000, 500);
LK.stopMusic();
LK.showGameOver();
gameActive = false;
}
// Handle cleanup of touch effects
for (var i = touchEffects.length - 1; i >= 0; i--) {
if (!touchEffects[i].parent) {
touchEffects.splice(i, 1);
}
}
};
// Start with a welcome screen - game will start on first touch
gameActive = false;