/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.active = false; self.reset = function () { self.x = 2048 / 2; self.y = 2732 / 2; self.speedX = (Math.random() > 0.5 ? 1 : -1) * (5 + Math.random() * 3); self.speedY = (Math.random() > 0.5 ? 1 : -1) * (5 + Math.random() * 3); self.active = true; }; self.update = function () { if (!self.active) { return; } self.x += self.speedX; self.y += self.speedY; // Bounce off side walls if (self.x < 20 || self.x > 2048 - 20) { self.speedX *= -1; LK.getSound('hit').play(); } }; return self; }); var Paddle = Container.expand(function () { var self = Container.call(this); self.width = 300; self.height = 60; self.paddleSpeed = 15; self.score = 0; self.powerUpActive = false; self.powerUpType = null; self.powerUpTimer = null; var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.applyPowerUp = function (type) { self.powerUpActive = true; self.powerUpType = type; // Clear any existing power-up timer if (self.powerUpTimer) { LK.clearTimeout(self.powerUpTimer); } // Apply power-up effect switch (type) { case 'speed': self.paddleSpeed = 25; tween(paddleGraphics, { tint: 0xf1c40f }, { duration: 300 }); break; case 'size': tween(paddleGraphics, { width: self.width * 1.5, tint: 0xe74c3c }, { duration: 300 }); break; } // Set timer to reset power-up self.powerUpTimer = LK.setTimeout(function () { self.resetPowerUp(); }, 5000); // Power-ups last 5 seconds }; self.resetPowerUp = function () { self.powerUpActive = false; self.powerUpType = null; self.paddleSpeed = 15; tween(paddleGraphics, { width: self.width, tint: 0x3498db }, { duration: 300 }); }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'speed'; // Default type self.active = true; self.init = function (type) { self.type = type; // Set color based on power-up type if (type === 'speed') { powerUpGraphics.tint = 0xf1c40f; // Yellow } else if (type === 'size') { powerUpGraphics.tint = 0xe74c3c; // Red } }; self.update = function () { if (!self.active) { return; } // Make power-up float down slowly self.y += 2; // Rotate the power-up powerUpGraphics.rotation += 0.02; // Remove if it goes off screen if (self.y > 2732 + 50) { self.active = false; } }; return self; }); var ScoreDisplay = Container.expand(function () { var self = Container.call(this); self.scoreText = new Text2('0', { size: 120, fill: 0xFFFFFF }); self.scoreText.anchor.set(0.5, 0.5); self.addChild(self.scoreText); self.updateScore = function (score) { self.scoreText.setText(score.toString()); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var AI_DIFFICULTY = 0.6; // 0-1, higher is more difficult // Game state var gameState = 'waiting'; // waiting, playing, gameOver var frameCount = 0; var playerScore = 0; var aiScore = 0; var maxScore = 5; // First to reach this score wins // Create game objects var playerPaddle = new Paddle(); var aiPaddle = new Paddle(); var ball = new Ball(); var powerUps = []; var playerScoreDisplay = new ScoreDisplay(); var aiScoreDisplay = new ScoreDisplay(); // Initialize game field function initializeGame() { // Set up the center line var centerLine = LK.getAsset('centerLine', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 }); game.addChild(centerLine); // Set up paddles playerPaddle.x = GAME_WIDTH / 2; playerPaddle.y = GAME_HEIGHT - 100; game.addChild(playerPaddle); aiPaddle.x = GAME_WIDTH / 2; aiPaddle.y = 100; game.addChild(aiPaddle); // Set up ball ball.reset(); game.addChild(ball); // Set up score displays playerScoreDisplay.x = GAME_WIDTH / 4; playerScoreDisplay.y = GAME_HEIGHT / 2 + 200; game.addChild(playerScoreDisplay); aiScoreDisplay.x = GAME_WIDTH * 3 / 4; aiScoreDisplay.y = GAME_HEIGHT / 2 - 200; game.addChild(aiScoreDisplay); // Set up instruction text var instructionText = new Text2('Tap to start', { size: 80, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = GAME_WIDTH / 2; instructionText.y = GAME_HEIGHT / 2; game.addChild(instructionText); // Game state text that updates with game state var gameStateText = new Text2('', { size: 60, fill: 0xFFFFFF }); gameStateText.anchor.set(0.5, 0.5); gameStateText.x = GAME_WIDTH / 2; gameStateText.y = 200; game.addChild(gameStateText); // Start game on tap game.down = function () { if (gameState === 'waiting') { gameState = 'playing'; instructionText.visible = false; ball.reset(); // Reset scores playerScore = 0; aiScore = 0; playerScoreDisplay.updateScore(playerScore); aiScoreDisplay.updateScore(aiScore); // Play game music LK.playMusic('gameMusic'); } }; // Update game state text LK.setInterval(function () { if (gameState === 'waiting') { gameStateText.setText('Paddle Clash 2'); } else if (gameState === 'playing') { gameStateText.setText(''); } }, 100); } // Player paddle movement function setupPlayerControls() { var isDragging = false; var dragOffsetX = 0; game.down = function (x, y, obj) { if (y > GAME_HEIGHT / 2) { // Only allow control in bottom half isDragging = true; dragOffsetX = x - playerPaddle.x; } else if (gameState === 'waiting') { gameState = 'playing'; } }; game.move = function (x, y, obj) { if (isDragging && gameState === 'playing') { var targetX = x - dragOffsetX; // Ensure paddle stays within bounds targetX = Math.max(playerPaddle.width / 2, Math.min(GAME_WIDTH - playerPaddle.width / 2, targetX)); playerPaddle.x = targetX; } }; game.up = function () { isDragging = false; }; } // AI paddle movement function updateAIPaddle() { if (gameState !== 'playing') { return; } // Simple AI: follow the ball with some delay and error var targetX = ball.x; // Add some randomness to make it beatable targetX += (Math.random() - 0.5) * 200 * (1 - AI_DIFFICULTY); // Limit the paddle's movement speed var maxSpeed = 10 + AI_DIFFICULTY * 10; var moveDirection = targetX > aiPaddle.x ? 1 : -1; var moveAmount = Math.min(Math.abs(targetX - aiPaddle.x), maxSpeed); // Move the paddle aiPaddle.x += moveDirection * moveAmount; // Ensure paddle stays within bounds aiPaddle.x = Math.max(aiPaddle.width / 2, Math.min(GAME_WIDTH - aiPaddle.width / 2, aiPaddle.x)); } // Collision detection function checkCollisions() { // Ball with player paddle if (ball.y + 20 >= playerPaddle.y - 30 && ball.y - 20 <= playerPaddle.y + 30 && ball.x >= playerPaddle.x - 150 && ball.x <= playerPaddle.x + 150 && ball.speedY > 0) { // Calculate bounce angle based on where the ball hit the paddle var hitPosition = (ball.x - playerPaddle.x) / 150; // -1 to 1 ball.speedY *= -1.05; // Reverse and slightly increase speed ball.speedX = hitPosition * 10; // Adjust horizontal speed based on hit position LK.getSound('hit').play(); LK.effects.flashObject(playerPaddle, 0x3498db, 200); } // Ball with AI paddle if (ball.y - 20 <= aiPaddle.y + 30 && ball.y + 20 >= aiPaddle.y - 30 && ball.x >= aiPaddle.x - 150 && ball.x <= aiPaddle.x + 150 && ball.speedY < 0) { var hitPosition = (ball.x - aiPaddle.x) / 150; // -1 to 1 ball.speedY *= -1.05; // Reverse and slightly increase speed ball.speedX = hitPosition * 10; // Adjust horizontal speed based on hit position LK.getSound('hit').play(); LK.effects.flashObject(aiPaddle, 0x3498db, 200); } // Ball with top/bottom edges (scoring) if (ball.y > GAME_HEIGHT + 40) { // AI scores aiScore++; aiScoreDisplay.updateScore(aiScore); LK.getSound('score').play(); if (aiScore >= maxScore) { gameState = 'gameOver'; LK.showGameOver(); } else { ball.reset(); } } else if (ball.y < -40) { // Player scores playerScore++; playerScoreDisplay.updateScore(playerScore); LK.getSound('score').play(); if (playerScore >= maxScore) { gameState = 'gameOver'; LK.setScore(playerScore); if (playerScore > storage.highScore) { storage.highScore = playerScore; } LK.showYouWin(); } else { ball.reset(); } } // Power-up collisions for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; if (!powerUp.active) { powerUp.destroy(); powerUps.splice(i, 1); continue; } // Check if player paddle collects the power-up if (powerUp.y + 25 >= playerPaddle.y - 30 && powerUp.y - 25 <= playerPaddle.y + 30 && powerUp.x >= playerPaddle.x - 150 && powerUp.x <= playerPaddle.x + 150) { playerPaddle.applyPowerUp(powerUp.type); LK.getSound('powerUpCollect').play(); powerUp.active = false; powerUp.destroy(); powerUps.splice(i, 1); } } } // Spawn power-ups function spawnPowerUps() { if (gameState !== 'playing') { return; } // Random chance to spawn power-up every few seconds if (LK.ticks % 180 === 0 && Math.random() < 0.4) { var powerUp = new PowerUp(); powerUp.x = 100 + Math.random() * (GAME_WIDTH - 200); powerUp.y = GAME_HEIGHT / 2; // Randomly choose power-up type var powerUpType = Math.random() < 0.5 ? 'speed' : 'size'; powerUp.init(powerUpType); powerUps.push(powerUp); game.addChild(powerUp); } } // Main game update function game.update = function () { frameCount++; if (gameState === 'playing') { ball.update(); updateAIPaddle(); checkCollisions(); spawnPowerUps(); // Update all power-ups for (var i = 0; i < powerUps.length; i++) { powerUps[i].update(); } } }; // Initialize the game initializeGame(); setupPlayerControls(); // Play background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.active = false;
self.reset = function () {
self.x = 2048 / 2;
self.y = 2732 / 2;
self.speedX = (Math.random() > 0.5 ? 1 : -1) * (5 + Math.random() * 3);
self.speedY = (Math.random() > 0.5 ? 1 : -1) * (5 + Math.random() * 3);
self.active = true;
};
self.update = function () {
if (!self.active) {
return;
}
self.x += self.speedX;
self.y += self.speedY;
// Bounce off side walls
if (self.x < 20 || self.x > 2048 - 20) {
self.speedX *= -1;
LK.getSound('hit').play();
}
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
self.width = 300;
self.height = 60;
self.paddleSpeed = 15;
self.score = 0;
self.powerUpActive = false;
self.powerUpType = null;
self.powerUpTimer = null;
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.applyPowerUp = function (type) {
self.powerUpActive = true;
self.powerUpType = type;
// Clear any existing power-up timer
if (self.powerUpTimer) {
LK.clearTimeout(self.powerUpTimer);
}
// Apply power-up effect
switch (type) {
case 'speed':
self.paddleSpeed = 25;
tween(paddleGraphics, {
tint: 0xf1c40f
}, {
duration: 300
});
break;
case 'size':
tween(paddleGraphics, {
width: self.width * 1.5,
tint: 0xe74c3c
}, {
duration: 300
});
break;
}
// Set timer to reset power-up
self.powerUpTimer = LK.setTimeout(function () {
self.resetPowerUp();
}, 5000); // Power-ups last 5 seconds
};
self.resetPowerUp = function () {
self.powerUpActive = false;
self.powerUpType = null;
self.paddleSpeed = 15;
tween(paddleGraphics, {
width: self.width,
tint: 0x3498db
}, {
duration: 300
});
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'speed'; // Default type
self.active = true;
self.init = function (type) {
self.type = type;
// Set color based on power-up type
if (type === 'speed') {
powerUpGraphics.tint = 0xf1c40f; // Yellow
} else if (type === 'size') {
powerUpGraphics.tint = 0xe74c3c; // Red
}
};
self.update = function () {
if (!self.active) {
return;
}
// Make power-up float down slowly
self.y += 2;
// Rotate the power-up
powerUpGraphics.rotation += 0.02;
// Remove if it goes off screen
if (self.y > 2732 + 50) {
self.active = false;
}
};
return self;
});
var ScoreDisplay = Container.expand(function () {
var self = Container.call(this);
self.scoreText = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
self.scoreText.anchor.set(0.5, 0.5);
self.addChild(self.scoreText);
self.updateScore = function (score) {
self.scoreText.setText(score.toString());
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var AI_DIFFICULTY = 0.6; // 0-1, higher is more difficult
// Game state
var gameState = 'waiting'; // waiting, playing, gameOver
var frameCount = 0;
var playerScore = 0;
var aiScore = 0;
var maxScore = 5; // First to reach this score wins
// Create game objects
var playerPaddle = new Paddle();
var aiPaddle = new Paddle();
var ball = new Ball();
var powerUps = [];
var playerScoreDisplay = new ScoreDisplay();
var aiScoreDisplay = new ScoreDisplay();
// Initialize game field
function initializeGame() {
// Set up the center line
var centerLine = LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2
});
game.addChild(centerLine);
// Set up paddles
playerPaddle.x = GAME_WIDTH / 2;
playerPaddle.y = GAME_HEIGHT - 100;
game.addChild(playerPaddle);
aiPaddle.x = GAME_WIDTH / 2;
aiPaddle.y = 100;
game.addChild(aiPaddle);
// Set up ball
ball.reset();
game.addChild(ball);
// Set up score displays
playerScoreDisplay.x = GAME_WIDTH / 4;
playerScoreDisplay.y = GAME_HEIGHT / 2 + 200;
game.addChild(playerScoreDisplay);
aiScoreDisplay.x = GAME_WIDTH * 3 / 4;
aiScoreDisplay.y = GAME_HEIGHT / 2 - 200;
game.addChild(aiScoreDisplay);
// Set up instruction text
var instructionText = new Text2('Tap to start', {
size: 80,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = GAME_WIDTH / 2;
instructionText.y = GAME_HEIGHT / 2;
game.addChild(instructionText);
// Game state text that updates with game state
var gameStateText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
gameStateText.anchor.set(0.5, 0.5);
gameStateText.x = GAME_WIDTH / 2;
gameStateText.y = 200;
game.addChild(gameStateText);
// Start game on tap
game.down = function () {
if (gameState === 'waiting') {
gameState = 'playing';
instructionText.visible = false;
ball.reset();
// Reset scores
playerScore = 0;
aiScore = 0;
playerScoreDisplay.updateScore(playerScore);
aiScoreDisplay.updateScore(aiScore);
// Play game music
LK.playMusic('gameMusic');
}
};
// Update game state text
LK.setInterval(function () {
if (gameState === 'waiting') {
gameStateText.setText('Paddle Clash 2');
} else if (gameState === 'playing') {
gameStateText.setText('');
}
}, 100);
}
// Player paddle movement
function setupPlayerControls() {
var isDragging = false;
var dragOffsetX = 0;
game.down = function (x, y, obj) {
if (y > GAME_HEIGHT / 2) {
// Only allow control in bottom half
isDragging = true;
dragOffsetX = x - playerPaddle.x;
} else if (gameState === 'waiting') {
gameState = 'playing';
}
};
game.move = function (x, y, obj) {
if (isDragging && gameState === 'playing') {
var targetX = x - dragOffsetX;
// Ensure paddle stays within bounds
targetX = Math.max(playerPaddle.width / 2, Math.min(GAME_WIDTH - playerPaddle.width / 2, targetX));
playerPaddle.x = targetX;
}
};
game.up = function () {
isDragging = false;
};
}
// AI paddle movement
function updateAIPaddle() {
if (gameState !== 'playing') {
return;
}
// Simple AI: follow the ball with some delay and error
var targetX = ball.x;
// Add some randomness to make it beatable
targetX += (Math.random() - 0.5) * 200 * (1 - AI_DIFFICULTY);
// Limit the paddle's movement speed
var maxSpeed = 10 + AI_DIFFICULTY * 10;
var moveDirection = targetX > aiPaddle.x ? 1 : -1;
var moveAmount = Math.min(Math.abs(targetX - aiPaddle.x), maxSpeed);
// Move the paddle
aiPaddle.x += moveDirection * moveAmount;
// Ensure paddle stays within bounds
aiPaddle.x = Math.max(aiPaddle.width / 2, Math.min(GAME_WIDTH - aiPaddle.width / 2, aiPaddle.x));
}
// Collision detection
function checkCollisions() {
// Ball with player paddle
if (ball.y + 20 >= playerPaddle.y - 30 && ball.y - 20 <= playerPaddle.y + 30 && ball.x >= playerPaddle.x - 150 && ball.x <= playerPaddle.x + 150 && ball.speedY > 0) {
// Calculate bounce angle based on where the ball hit the paddle
var hitPosition = (ball.x - playerPaddle.x) / 150; // -1 to 1
ball.speedY *= -1.05; // Reverse and slightly increase speed
ball.speedX = hitPosition * 10; // Adjust horizontal speed based on hit position
LK.getSound('hit').play();
LK.effects.flashObject(playerPaddle, 0x3498db, 200);
}
// Ball with AI paddle
if (ball.y - 20 <= aiPaddle.y + 30 && ball.y + 20 >= aiPaddle.y - 30 && ball.x >= aiPaddle.x - 150 && ball.x <= aiPaddle.x + 150 && ball.speedY < 0) {
var hitPosition = (ball.x - aiPaddle.x) / 150; // -1 to 1
ball.speedY *= -1.05; // Reverse and slightly increase speed
ball.speedX = hitPosition * 10; // Adjust horizontal speed based on hit position
LK.getSound('hit').play();
LK.effects.flashObject(aiPaddle, 0x3498db, 200);
}
// Ball with top/bottom edges (scoring)
if (ball.y > GAME_HEIGHT + 40) {
// AI scores
aiScore++;
aiScoreDisplay.updateScore(aiScore);
LK.getSound('score').play();
if (aiScore >= maxScore) {
gameState = 'gameOver';
LK.showGameOver();
} else {
ball.reset();
}
} else if (ball.y < -40) {
// Player scores
playerScore++;
playerScoreDisplay.updateScore(playerScore);
LK.getSound('score').play();
if (playerScore >= maxScore) {
gameState = 'gameOver';
LK.setScore(playerScore);
if (playerScore > storage.highScore) {
storage.highScore = playerScore;
}
LK.showYouWin();
} else {
ball.reset();
}
}
// Power-up collisions
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.active) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check if player paddle collects the power-up
if (powerUp.y + 25 >= playerPaddle.y - 30 && powerUp.y - 25 <= playerPaddle.y + 30 && powerUp.x >= playerPaddle.x - 150 && powerUp.x <= playerPaddle.x + 150) {
playerPaddle.applyPowerUp(powerUp.type);
LK.getSound('powerUpCollect').play();
powerUp.active = false;
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Spawn power-ups
function spawnPowerUps() {
if (gameState !== 'playing') {
return;
}
// Random chance to spawn power-up every few seconds
if (LK.ticks % 180 === 0 && Math.random() < 0.4) {
var powerUp = new PowerUp();
powerUp.x = 100 + Math.random() * (GAME_WIDTH - 200);
powerUp.y = GAME_HEIGHT / 2;
// Randomly choose power-up type
var powerUpType = Math.random() < 0.5 ? 'speed' : 'size';
powerUp.init(powerUpType);
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Main game update function
game.update = function () {
frameCount++;
if (gameState === 'playing') {
ball.update();
updateAIPaddle();
checkCollisions();
spawnPowerUps();
// Update all power-ups
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].update();
}
}
};
// Initialize the game
initializeGame();
setupPlayerControls();
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});