/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, difficulty: 1 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.width = ballGraphics.width; self.height = ballGraphics.height; self.speedX = 0; self.speedY = 0; self.maxSpeed = 20; self.active = false; self.serveDirection = 1; // 1 = right, -1 = left self.lastHitBy = null; self.reset = function () { self.x = 2048 / 2; self.y = 2732 / 2; self.active = false; self.speedX = 0; self.speedY = 0; // Alternate serve direction self.serveDirection = -self.serveDirection; }; self.serve = function () { // Serve in the direction determined self.speedX = 10 * self.serveDirection; self.speedY = 5 * (Math.random() > 0.5 ? 1 : -1); self.active = true; }; self.update = function () { if (!self.active) { return; } // Move the ball self.x += self.speedX; self.y += self.speedY; // Handle vertical wall collisions if (self.y < self.height / 2 || self.y > 2732 - self.height / 2) { self.speedY = -self.speedY; self.y = self.y < self.height / 2 ? self.height / 2 : 2732 - self.height / 2; LK.getSound('hit').play(); } }; self.checkPaddleCollision = function (paddle) { if (!self.active) { return false; } if (self.intersects(paddle)) { // Calculate bounce angle based on where the ball hits the paddle var relativeIntersectY = (paddle.y - self.y) / (paddle.height / 2); var bounceAngle = relativeIntersectY * (Math.PI / 4); // Max 45 degrees // Calculate new speeds var direction = self.x < 2048 / 2 ? 1 : -1; var speed = Math.min(Math.sqrt(self.speedX * self.speedX + self.speedY * self.speedY) + 0.5, self.maxSpeed); self.speedX = direction * speed * Math.cos(bounceAngle); self.speedY = speed * -Math.sin(bounceAngle); // Move ball away from paddle to prevent multiple collisions if (direction > 0) { self.x = paddle.x + paddle.width / 2 + self.width / 2; } else { self.x = paddle.x - paddle.width / 2 - self.width / 2; } self.lastHitBy = paddle; LK.getSound('hit').play(); return true; } return false; }; self.applyPowerup = function (powerupType) { switch (powerupType) { case 'speed': var currentSpeed = Math.sqrt(self.speedX * self.speedX + self.speedY * self.speedY); self.speedX = self.speedX / currentSpeed * (currentSpeed + 3); self.speedY = self.speedY / currentSpeed * (currentSpeed + 3); break; case 'size': tween(ballGraphics, { scale: 1.5 }, { duration: 300 }); self.width = ballGraphics.width * 1.5; self.height = ballGraphics.height * 1.5; LK.setTimeout(function () { tween(ballGraphics, { scale: 1 }, { duration: 300 }); self.width = ballGraphics.width / 1.5; self.height = ballGraphics.height / 1.5; }, 5000); break; case 'curve': self.speedY += Math.random() * 10 - 5; break; } }; return self; }); var Paddle = Container.expand(function (isPlayer) { var self = Container.call(this); self.isPlayer = isPlayer === undefined ? true : isPlayer; self.speed = 12; self.score = 0; var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.width = paddleGraphics.width; self.height = paddleGraphics.height; self.ai = { difficulty: storage.difficulty || 1, reactionDelay: 0, targetY: 0, thinkTime: 0 }; self.move = function (x, y) { if (y < self.height / 2) { self.y = self.height / 2; } else if (y > 2732 - self.height / 2) { self.y = 2732 - self.height / 2; } else { self.y = y; } }; self.updateAI = function (ballY, ballSpeedY) { // Decrease AI think time if (self.ai.thinkTime > 0) { self.ai.thinkTime--; return; } // Calculate where the ball will be var errorMargin = (4 - self.ai.difficulty) * 60; self.ai.targetY = ballY + Math.random() * errorMargin - errorMargin / 2; // Set a new think time self.ai.thinkTime = Math.floor(Math.random() * (8 - self.ai.difficulty * 2)); }; self.runAI = function () { if (self.y < self.ai.targetY - self.speed) { self.y += self.speed; } else if (self.y > self.ai.targetY + self.speed) { self.y -= self.speed; } // Constrain paddle to field if (self.y < self.height / 2) { self.y = self.height / 2; } else if (self.y > 2732 - self.height / 2) { self.y = 2732 - self.height / 2; } }; 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.types = ['speed', 'size', 'curve']; self.spawn = function () { // Position randomly in the middle third of the court self.x = Math.random() * (2048 * 0.6) + 2048 * 0.2; self.y = Math.random() * (2732 * 0.6) + 2732 * 0.2; // Set random type self.type = self.types[Math.floor(Math.random() * self.types.length)]; // Set color based on type switch (self.type) { case 'speed': powerupGraphics.tint = 0xFF5500; // Orange break; case 'size': powerupGraphics.tint = 0x00AAFF; // Blue break; case 'curve': powerupGraphics.tint = 0xFFAA00; // Yellow break; } self.active = true; // Create a pulsing animation tween(self, { alpha: 0.6 }, { duration: 500, easing: tween.sinusoidal, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 500, easing: tween.sinusoidal, onFinish: function onFinish() { if (self.active) { self.spawn(); // Restart the pulse animation } } }); } }); // Auto-remove after 10 seconds LK.setTimeout(function () { if (self.active) { self.deactivate(); } }, 10000); }; self.deactivate = function () { self.active = false; tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); } } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game state var gameState = 'title'; // title, serving, playing, gameover var gameTime = 0; var touchPaddle = null; var servingTimeout = null; var powerupTimeout = null; var powerupActive = false; // Game elements var playerPaddle; var aiPaddle; var ball; var powerup; var scoreLeft; var scoreRight; var centerLine; var titleText; var subtitleText; var gameOverText; // Initialize game elements function setupGame() { // Create center line centerLine = new Container(); for (var i = 0; i < 34; i++) { var linePart = centerLine.attachAsset('dividerLine', { anchorX: 0.5, anchorY: 0.5, y: i * 80 }); } centerLine.x = 2048 / 2; game.addChild(centerLine); // Create player paddle playerPaddle = new Paddle(true); playerPaddle.x = 100; playerPaddle.y = 2732 / 2; game.addChild(playerPaddle); // Create AI paddle aiPaddle = new Paddle(false); aiPaddle.x = 2048 - 100; aiPaddle.y = 2732 / 2; game.addChild(aiPaddle); // Create ball ball = new Ball(); ball.reset(); game.addChild(ball); // Create score text scoreLeft = new Text2('0', { size: 150, fill: 0xFFFFFF }); scoreLeft.anchor.set(0.5, 0.5); scoreLeft.x = 2048 / 4; scoreLeft.y = 200; game.addChild(scoreLeft); scoreRight = new Text2('0', { size: 150, fill: 0xFFFFFF }); scoreRight.anchor.set(0.5, 0.5); scoreRight.x = 2048 * 3 / 4; scoreRight.y = 200; game.addChild(scoreRight); // Title text titleText = new Text2('PIXEL PONG', { size: 200, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 2732 / 3; game.addChild(titleText); subtitleText = new Text2('TAP TO START\n\nDRAG TO MOVE PADDLE', { size: 80, fill: 0xFFFFFF }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 2732 / 2; game.addChild(subtitleText); gameOverText = new Text2('', { size: 150, fill: 0xFFFFFF }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 2048 / 2; gameOverText.y = 2732 / 2; gameOverText.visible = false; game.addChild(gameOverText); // Set title screen setGameState('title'); // Start background music LK.playMusic('bgMusic'); } function setGameState(state) { gameState = state; switch (state) { case 'title': ball.reset(); playerPaddle.score = 0; aiPaddle.score = 0; updateScoreDisplay(); titleText.visible = true; subtitleText.visible = true; gameOverText.visible = false; break; case 'serving': titleText.visible = false; subtitleText.visible = false; gameOverText.visible = false; // Set serving timeout servingTimeout = LK.setTimeout(function () { ball.serve(); setGameState('playing'); }, 1500); break; case 'playing': // Schedule powerup schedulePowerup(); break; case 'gameover': gameOverText.visible = true; // Check for new high score if (playerPaddle.score > storage.highScore) { storage.highScore = playerPaddle.score; gameOverText.setText('GAME OVER\nNEW HIGH SCORE: ' + storage.highScore); } else { gameOverText.setText('GAME OVER\nSCORE: ' + playerPaddle.score + '\nHIGH SCORE: ' + storage.highScore); } // Clear timeouts if (servingTimeout) { LK.clearTimeout(servingTimeout); servingTimeout = null; } if (powerupTimeout) { LK.clearTimeout(powerupTimeout); powerupTimeout = null; } // Remove any active powerup if (powerupActive && powerup && powerup.parent) { powerup.deactivate(); powerupActive = false; } break; } } function schedulePowerup() { if (powerupTimeout) { LK.clearTimeout(powerupTimeout); } // Schedule next powerup between 5-15 seconds powerupTimeout = LK.setTimeout(function () { spawnPowerup(); }, 5000 + Math.random() * 10000); } function spawnPowerup() { // Only one powerup at a time if (powerupActive) { return; } powerup = new Powerup(); powerup.spawn(); game.addChild(powerup); powerupActive = true; } function updateScoreDisplay() { scoreLeft.setText(playerPaddle.score.toString()); scoreRight.setText(aiPaddle.score.toString()); } function scorePoint(forLeft) { if (forLeft) { playerPaddle.score++; } else { aiPaddle.score++; } updateScoreDisplay(); LK.getSound('score').play(); // Check for game over if (playerPaddle.score >= 11 || aiPaddle.score >= 11) { LK.setTimeout(function () { setGameState('gameover'); }, 1000); } else { // Reset for next round ball.reset(); setGameState('serving'); } } // Event handlers game.down = function (x, y, obj) { if (gameState === 'title') { setGameState('serving'); } else if (gameState === 'gameover') { setGameState('title'); } else { touchPaddle = playerPaddle; touchPaddle.move(x, y); } }; game.move = function (x, y, obj) { if (touchPaddle) { touchPaddle.move(x, y); } }; game.up = function (x, y, obj) { touchPaddle = null; }; // Main game update loop game.update = function () { if (gameState === 'playing' || gameState === 'serving') { // Update ball ball.update(); // Check for paddle collisions ball.checkPaddleCollision(playerPaddle); ball.checkPaddleCollision(aiPaddle); // Check for scoring if (ball.x < -ball.width) { scorePoint(false); } else if (ball.x > 2048 + ball.width) { scorePoint(true); } // Update AI paddle if (ball.active) { if (ball.speedX > 0) { aiPaddle.updateAI(ball.y, ball.speedY); } aiPaddle.runAI(); } // Check for powerup collision if (powerupActive && powerup && ball.intersects(powerup)) { ball.applyPowerup(powerup.type); powerup.deactivate(); powerupActive = false; LK.getSound('powerup').play(); schedulePowerup(); } } // Animate title on title screen if (gameState === 'title') { gameTime++; titleText.scale.set(1 + Math.sin(gameTime / 30) * 0.05); } }; // Initialize everything setupGame();
===================================================================
--- original.js
+++ change.js
@@ -245,9 +245,8 @@
* Game Code
****/
// Game state
var gameState = 'title'; // title, serving, playing, gameover
-var isTwoPlayer = false;
var gameTime = 0;
var touchPaddle = null;
var servingTimeout = null;
var powerupTimeout = null;
@@ -275,13 +274,14 @@
});
}
centerLine.x = 2048 / 2;
game.addChild(centerLine);
- // Create paddles
+ // Create player paddle
playerPaddle = new Paddle(true);
playerPaddle.x = 100;
playerPaddle.y = 2732 / 2;
game.addChild(playerPaddle);
+ // Create AI paddle
aiPaddle = new Paddle(false);
aiPaddle.x = 2048 - 100;
aiPaddle.y = 2732 / 2;
game.addChild(aiPaddle);
@@ -464,9 +464,9 @@
} else if (ball.x > 2048 + ball.width) {
scorePoint(true);
}
// Update AI paddle
- if (!isTwoPlayer && ball.active) {
+ if (ball.active) {
if (ball.speedX > 0) {
aiPaddle.updateAI(ball.y, ball.speedY);
}
aiPaddle.runAI();