/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, aiDifficulty: 0.7 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.radius = ballGraphics.width / 2; self.velocity = { x: 0, y: 0 }; self.baseSpeed = 12; self.speedMultiplier = 1.0; self.maxSpeedMultiplier = 2.5; self.reset = function () { self.x = 2048 / 2; self.y = 2732 / 2; self.speedMultiplier = 1.0; // Random initial direction var angle = Math.random() * Math.PI / 2 - Math.PI / 4; if (Math.random() < 0.5) { angle += Math.PI; } self.velocity.x = Math.cos(angle) * self.baseSpeed; self.velocity.y = Math.sin(angle) * self.baseSpeed; // Make sure horizontal speed is significant if (Math.abs(self.velocity.x) < self.baseSpeed * 0.6) { self.velocity.x = (self.velocity.x > 0 ? 1 : -1) * self.baseSpeed * 0.6; } }; self.update = function () { // Move ball based on velocity self.x += self.velocity.x * self.speedMultiplier; self.y += self.velocity.y * self.speedMultiplier; // Collision with top and bottom walls if (self.y < self.radius) { self.y = self.radius; self.velocity.y *= -1; LK.getSound('hit').play(); } else if (self.y > 2732 - self.radius) { self.y = 2732 - self.radius; self.velocity.y *= -1; LK.getSound('hit').play(); } }; self.hitPaddle = function (paddle) { // Normalize collision point (-1 to 1) from paddle center var relativeY = (self.y - paddle.y) / (paddle.height / 2); // Adjust angle based on where the ball hit the paddle var angle = relativeY * Math.PI / 3; // max ±60 degrees // Reverse x direction and apply new angle self.velocity.x = -Math.sign(self.velocity.x) * Math.cos(angle) * self.baseSpeed; self.velocity.y = Math.sin(angle) * self.baseSpeed; // Increase speed with each hit, up to a maximum self.speedMultiplier = Math.min(self.maxSpeedMultiplier, self.speedMultiplier + 0.05); // Play hit sound LK.getSound('hit').play(); }; return self; }); var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.width = paddleGraphics.width; self.height = paddleGraphics.height; self.speed = 0; self.target = 0; self.isAI = false; self.aiReactionSpeed = 0.7; // Default AI difficulty level (0.1-0.9) // AI paddle movement logic self.updateAI = function (ball, dt) { if (!self.isAI) { return; } // Only update target if ball is moving toward this paddle if (self.x < 1024 && ball.velocity.x < 0 || self.x > 1024 && ball.velocity.x > 0) { // Predict where the ball will be var distanceX = Math.abs(self.x - ball.x); var timeToReach = distanceX / Math.abs(ball.velocity.x); var futureY = ball.y + ball.velocity.y * timeToReach; // Keep the future position in bounds futureY = Math.max(self.height / 2, Math.min(2732 - self.height / 2, futureY)); // Add some imperfection based on AI difficulty var errorFactor = (1 - self.aiReactionSpeed) * 300; futureY += Math.random() * errorFactor * 2 - errorFactor; // Gradually move toward the predicted position self.target = futureY; } }; self.update = function (dt) { // Gradually move toward target position (whether controlled by player or AI) if (self.target !== null) { self.speed = (self.target - self.y) * 0.2; // Cap movement speed var maxSpeed = 40; self.speed = Math.max(-maxSpeed, Math.min(maxSpeed, self.speed)); self.y += self.speed; // Keep paddle in bounds self.y = Math.max(self.height / 2, Math.min(2732 - self.height / 2, self.y)); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game state var gameStarted = false; var gameMode = "single"; // "single" or "multi" var scoreLeft = 0; var scoreRight = 0; var maxScore = 11; var lastFrameTime = Date.now(); // Create paddles var leftPaddle = game.addChild(new Paddle()); leftPaddle.x = 100; leftPaddle.y = 2732 / 2; var rightPaddle = game.addChild(new Paddle()); rightPaddle.x = 2048 - 100; rightPaddle.y = 2732 / 2; rightPaddle.isAI = true; rightPaddle.aiReactionSpeed = storage.aiDifficulty; // Create ball var ball = game.addChild(new Ball()); ball.reset(); // Create center line var centerLineContainer = game.addChild(new Container()); centerLineContainer.x = 2048 / 2; for (var y = 15; y < 2732; y += 60) { var lineSegment = centerLineContainer.attachAsset('centerLine', { anchorX: 0.5, anchorY: 0.5, y: y }); } // Score text var scoreLeftText = new Text2(scoreLeft.toString(), { size: 150, fill: 0xFFFFFF }); scoreLeftText.anchor.set(1, 0); scoreLeftText.x = 2048 / 2 - 50; scoreLeftText.y = 50; LK.gui.addChild(scoreLeftText); var scoreRightText = new Text2(scoreRight.toString(), { size: 150, fill: 0xFFFFFF }); scoreRightText.anchor.set(0, 0); scoreRightText.x = 2048 / 2 + 50; scoreRightText.y = 50; LK.gui.addChild(scoreRightText); // Game mode button var singlePlayerButton = new Text2("1P", { size: 80, fill: gameMode === "single" ? "#ffffff" : "#888888" }); singlePlayerButton.anchor.set(1, 0); singlePlayerButton.x = 2048 / 2 - 20; singlePlayerButton.y = 220; LK.gui.addChild(singlePlayerButton); var multiPlayerButton = new Text2("2P", { size: 80, fill: gameMode === "multi" ? "#ffffff" : "#888888" }); multiPlayerButton.anchor.set(0, 0); multiPlayerButton.x = 2048 / 2 + 20; multiPlayerButton.y = 220; LK.gui.addChild(multiPlayerButton); // Start text var startText = new Text2("TAP TO START", { size: 100, fill: 0xFFFFFF }); startText.anchor.set(0.5, 0.5); startText.x = 2048 / 2; startText.y = 2732 / 2; LK.gui.addChild(startText); // Store which paddle the user is currently controlling var activePaddle = null; // Update scores function updateScore() { scoreLeftText.setText(scoreLeft.toString()); scoreRightText.setText(scoreRight.toString()); } // Check for win condition function checkWinCondition() { if (scoreLeft >= maxScore) { if (gameMode === "single") { // Update high score if playing single player if (scoreLeft > storage.highScore) { storage.highScore = scoreLeft; } } LK.showYouWin(); } else if (scoreRight >= maxScore) { if (gameMode === "multi") { LK.showYouWin(); // In multiplayer, right player winning is still a win } else { LK.showGameOver(); } } } // Handle touch events game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; startText.visible = false; LK.playMusic('gameMusic'); return; } // Check if game mode buttons were clicked if (!gameStarted && y < 300) { var centerX = 2048 / 2; if (x < centerX) { gameMode = "single"; rightPaddle.isAI = true; singlePlayerButton.style.fill = "#ffffff"; multiPlayerButton.style.fill = "#888888"; } else { gameMode = "multi"; rightPaddle.isAI = false; singlePlayerButton.style.fill = "#888888"; multiPlayerButton.style.fill = "#ffffff"; } return; } // Determine which paddle to control based on screen side if (gameMode === "multi") { if (x < 2048 / 2) { activePaddle = leftPaddle; } else { activePaddle = rightPaddle; } } else { // In single player, only control left paddle activePaddle = leftPaddle; } if (activePaddle) { activePaddle.target = y; } }; game.move = function (x, y, obj) { if (activePaddle) { activePaddle.target = y; } }; game.up = function (x, y, obj) { // Keep tracking the paddle's target position // This allows for smooth movement even after lifting finger }; // Main game update loop game.update = function () { // Calculate delta time for smoother animations var currentTime = Date.now(); var dt = (currentTime - lastFrameTime) / 16.67; // Normalize to 60fps lastFrameTime = currentTime; // Don't update game logic if not started if (!gameStarted) { return; } // Update AI rightPaddle.updateAI(ball, dt); // Update paddles leftPaddle.update(dt); rightPaddle.update(dt); // Update ball ball.update(); // Check for collisions with paddles if (ball.velocity.x < 0 && ball.x - ball.radius <= leftPaddle.x + leftPaddle.width / 2 && ball.x - ball.radius > leftPaddle.x - leftPaddle.width / 2 && ball.y >= leftPaddle.y - leftPaddle.height / 2 && ball.y <= leftPaddle.y + leftPaddle.height / 2) { // Position ball at paddle edge to prevent sticking ball.x = leftPaddle.x + leftPaddle.width / 2 + ball.radius; ball.hitPaddle(leftPaddle); } else if (ball.velocity.x > 0 && ball.x + ball.radius >= rightPaddle.x - rightPaddle.width / 2 && ball.x + ball.radius < rightPaddle.x + rightPaddle.width / 2 && ball.y >= rightPaddle.y - rightPaddle.height / 2 && ball.y <= rightPaddle.y + rightPaddle.height / 2) { // Position ball at paddle edge to prevent sticking ball.x = rightPaddle.x - rightPaddle.width / 2 - ball.radius; ball.hitPaddle(rightPaddle); } // Check for scoring if (ball.x < -ball.radius) { // Right scores scoreRight++; updateScore(); LK.getSound('score').play(); ball.reset(); checkWinCondition(); } else if (ball.x > 2048 + ball.radius) { // Left scores scoreLeft++; updateScore(); LK.getSound('score').play(); ball.reset(); checkWinCondition(); } // Flash effect for center line if ball crosses it if (ball.x < 1024 && ball.velocity.x > 0 && ball.x + ball.velocity.x >= 1024 || ball.x > 1024 && ball.velocity.x < 0 && ball.x + ball.velocity.x <= 1024) { tween(centerLineContainer, { alpha: 0.3 }, { duration: 100, onFinish: function onFinish() { tween(centerLineContainer, { alpha: 1 }, { duration: 100 }); } }); } };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,333 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ aiDifficulty: 0.7
+});
+
+/****
+* Classes
+****/
+var Ball = Container.expand(function () {
+ var self = Container.call(this);
+ var ballGraphics = self.attachAsset('ball', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = ballGraphics.width / 2;
+ self.velocity = {
+ x: 0,
+ y: 0
+ };
+ self.baseSpeed = 12;
+ self.speedMultiplier = 1.0;
+ self.maxSpeedMultiplier = 2.5;
+ self.reset = function () {
+ self.x = 2048 / 2;
+ self.y = 2732 / 2;
+ self.speedMultiplier = 1.0;
+ // Random initial direction
+ var angle = Math.random() * Math.PI / 2 - Math.PI / 4;
+ if (Math.random() < 0.5) {
+ angle += Math.PI;
+ }
+ self.velocity.x = Math.cos(angle) * self.baseSpeed;
+ self.velocity.y = Math.sin(angle) * self.baseSpeed;
+ // Make sure horizontal speed is significant
+ if (Math.abs(self.velocity.x) < self.baseSpeed * 0.6) {
+ self.velocity.x = (self.velocity.x > 0 ? 1 : -1) * self.baseSpeed * 0.6;
+ }
+ };
+ self.update = function () {
+ // Move ball based on velocity
+ self.x += self.velocity.x * self.speedMultiplier;
+ self.y += self.velocity.y * self.speedMultiplier;
+ // Collision with top and bottom walls
+ if (self.y < self.radius) {
+ self.y = self.radius;
+ self.velocity.y *= -1;
+ LK.getSound('hit').play();
+ } else if (self.y > 2732 - self.radius) {
+ self.y = 2732 - self.radius;
+ self.velocity.y *= -1;
+ LK.getSound('hit').play();
+ }
+ };
+ self.hitPaddle = function (paddle) {
+ // Normalize collision point (-1 to 1) from paddle center
+ var relativeY = (self.y - paddle.y) / (paddle.height / 2);
+ // Adjust angle based on where the ball hit the paddle
+ var angle = relativeY * Math.PI / 3; // max ±60 degrees
+ // Reverse x direction and apply new angle
+ self.velocity.x = -Math.sign(self.velocity.x) * Math.cos(angle) * self.baseSpeed;
+ self.velocity.y = Math.sin(angle) * self.baseSpeed;
+ // Increase speed with each hit, up to a maximum
+ self.speedMultiplier = Math.min(self.maxSpeedMultiplier, self.speedMultiplier + 0.05);
+ // Play hit sound
+ LK.getSound('hit').play();
+ };
+ return self;
+});
+var Paddle = Container.expand(function () {
+ var self = Container.call(this);
+ var paddleGraphics = self.attachAsset('paddle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = paddleGraphics.width;
+ self.height = paddleGraphics.height;
+ self.speed = 0;
+ self.target = 0;
+ self.isAI = false;
+ self.aiReactionSpeed = 0.7; // Default AI difficulty level (0.1-0.9)
+ // AI paddle movement logic
+ self.updateAI = function (ball, dt) {
+ if (!self.isAI) {
+ return;
+ }
+ // Only update target if ball is moving toward this paddle
+ if (self.x < 1024 && ball.velocity.x < 0 || self.x > 1024 && ball.velocity.x > 0) {
+ // Predict where the ball will be
+ var distanceX = Math.abs(self.x - ball.x);
+ var timeToReach = distanceX / Math.abs(ball.velocity.x);
+ var futureY = ball.y + ball.velocity.y * timeToReach;
+ // Keep the future position in bounds
+ futureY = Math.max(self.height / 2, Math.min(2732 - self.height / 2, futureY));
+ // Add some imperfection based on AI difficulty
+ var errorFactor = (1 - self.aiReactionSpeed) * 300;
+ futureY += Math.random() * errorFactor * 2 - errorFactor;
+ // Gradually move toward the predicted position
+ self.target = futureY;
+ }
+ };
+ self.update = function (dt) {
+ // Gradually move toward target position (whether controlled by player or AI)
+ if (self.target !== null) {
+ self.speed = (self.target - self.y) * 0.2;
+ // Cap movement speed
+ var maxSpeed = 40;
+ self.speed = Math.max(-maxSpeed, Math.min(maxSpeed, self.speed));
+ self.y += self.speed;
+ // Keep paddle in bounds
+ self.y = Math.max(self.height / 2, Math.min(2732 - self.height / 2, self.y));
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Game state
+var gameStarted = false;
+var gameMode = "single"; // "single" or "multi"
+var scoreLeft = 0;
+var scoreRight = 0;
+var maxScore = 11;
+var lastFrameTime = Date.now();
+// Create paddles
+var leftPaddle = game.addChild(new Paddle());
+leftPaddle.x = 100;
+leftPaddle.y = 2732 / 2;
+var rightPaddle = game.addChild(new Paddle());
+rightPaddle.x = 2048 - 100;
+rightPaddle.y = 2732 / 2;
+rightPaddle.isAI = true;
+rightPaddle.aiReactionSpeed = storage.aiDifficulty;
+// Create ball
+var ball = game.addChild(new Ball());
+ball.reset();
+// Create center line
+var centerLineContainer = game.addChild(new Container());
+centerLineContainer.x = 2048 / 2;
+for (var y = 15; y < 2732; y += 60) {
+ var lineSegment = centerLineContainer.attachAsset('centerLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: y
+ });
+}
+// Score text
+var scoreLeftText = new Text2(scoreLeft.toString(), {
+ size: 150,
+ fill: 0xFFFFFF
+});
+scoreLeftText.anchor.set(1, 0);
+scoreLeftText.x = 2048 / 2 - 50;
+scoreLeftText.y = 50;
+LK.gui.addChild(scoreLeftText);
+var scoreRightText = new Text2(scoreRight.toString(), {
+ size: 150,
+ fill: 0xFFFFFF
+});
+scoreRightText.anchor.set(0, 0);
+scoreRightText.x = 2048 / 2 + 50;
+scoreRightText.y = 50;
+LK.gui.addChild(scoreRightText);
+// Game mode button
+var singlePlayerButton = new Text2("1P", {
+ size: 80,
+ fill: gameMode === "single" ? "#ffffff" : "#888888"
+});
+singlePlayerButton.anchor.set(1, 0);
+singlePlayerButton.x = 2048 / 2 - 20;
+singlePlayerButton.y = 220;
+LK.gui.addChild(singlePlayerButton);
+var multiPlayerButton = new Text2("2P", {
+ size: 80,
+ fill: gameMode === "multi" ? "#ffffff" : "#888888"
+});
+multiPlayerButton.anchor.set(0, 0);
+multiPlayerButton.x = 2048 / 2 + 20;
+multiPlayerButton.y = 220;
+LK.gui.addChild(multiPlayerButton);
+// Start text
+var startText = new Text2("TAP TO START", {
+ size: 100,
+ fill: 0xFFFFFF
+});
+startText.anchor.set(0.5, 0.5);
+startText.x = 2048 / 2;
+startText.y = 2732 / 2;
+LK.gui.addChild(startText);
+// Store which paddle the user is currently controlling
+var activePaddle = null;
+// Update scores
+function updateScore() {
+ scoreLeftText.setText(scoreLeft.toString());
+ scoreRightText.setText(scoreRight.toString());
+}
+// Check for win condition
+function checkWinCondition() {
+ if (scoreLeft >= maxScore) {
+ if (gameMode === "single") {
+ // Update high score if playing single player
+ if (scoreLeft > storage.highScore) {
+ storage.highScore = scoreLeft;
+ }
+ }
+ LK.showYouWin();
+ } else if (scoreRight >= maxScore) {
+ if (gameMode === "multi") {
+ LK.showYouWin(); // In multiplayer, right player winning is still a win
+ } else {
+ LK.showGameOver();
+ }
+ }
+}
+// Handle touch events
+game.down = function (x, y, obj) {
+ if (!gameStarted) {
+ gameStarted = true;
+ startText.visible = false;
+ LK.playMusic('gameMusic');
+ return;
+ }
+ // Check if game mode buttons were clicked
+ if (!gameStarted && y < 300) {
+ var centerX = 2048 / 2;
+ if (x < centerX) {
+ gameMode = "single";
+ rightPaddle.isAI = true;
+ singlePlayerButton.style.fill = "#ffffff";
+ multiPlayerButton.style.fill = "#888888";
+ } else {
+ gameMode = "multi";
+ rightPaddle.isAI = false;
+ singlePlayerButton.style.fill = "#888888";
+ multiPlayerButton.style.fill = "#ffffff";
+ }
+ return;
+ }
+ // Determine which paddle to control based on screen side
+ if (gameMode === "multi") {
+ if (x < 2048 / 2) {
+ activePaddle = leftPaddle;
+ } else {
+ activePaddle = rightPaddle;
+ }
+ } else {
+ // In single player, only control left paddle
+ activePaddle = leftPaddle;
+ }
+ if (activePaddle) {
+ activePaddle.target = y;
+ }
+};
+game.move = function (x, y, obj) {
+ if (activePaddle) {
+ activePaddle.target = y;
+ }
+};
+game.up = function (x, y, obj) {
+ // Keep tracking the paddle's target position
+ // This allows for smooth movement even after lifting finger
+};
+// Main game update loop
+game.update = function () {
+ // Calculate delta time for smoother animations
+ var currentTime = Date.now();
+ var dt = (currentTime - lastFrameTime) / 16.67; // Normalize to 60fps
+ lastFrameTime = currentTime;
+ // Don't update game logic if not started
+ if (!gameStarted) {
+ return;
+ }
+ // Update AI
+ rightPaddle.updateAI(ball, dt);
+ // Update paddles
+ leftPaddle.update(dt);
+ rightPaddle.update(dt);
+ // Update ball
+ ball.update();
+ // Check for collisions with paddles
+ if (ball.velocity.x < 0 && ball.x - ball.radius <= leftPaddle.x + leftPaddle.width / 2 && ball.x - ball.radius > leftPaddle.x - leftPaddle.width / 2 && ball.y >= leftPaddle.y - leftPaddle.height / 2 && ball.y <= leftPaddle.y + leftPaddle.height / 2) {
+ // Position ball at paddle edge to prevent sticking
+ ball.x = leftPaddle.x + leftPaddle.width / 2 + ball.radius;
+ ball.hitPaddle(leftPaddle);
+ } else if (ball.velocity.x > 0 && ball.x + ball.radius >= rightPaddle.x - rightPaddle.width / 2 && ball.x + ball.radius < rightPaddle.x + rightPaddle.width / 2 && ball.y >= rightPaddle.y - rightPaddle.height / 2 && ball.y <= rightPaddle.y + rightPaddle.height / 2) {
+ // Position ball at paddle edge to prevent sticking
+ ball.x = rightPaddle.x - rightPaddle.width / 2 - ball.radius;
+ ball.hitPaddle(rightPaddle);
+ }
+ // Check for scoring
+ if (ball.x < -ball.radius) {
+ // Right scores
+ scoreRight++;
+ updateScore();
+ LK.getSound('score').play();
+ ball.reset();
+ checkWinCondition();
+ } else if (ball.x > 2048 + ball.radius) {
+ // Left scores
+ scoreLeft++;
+ updateScore();
+ LK.getSound('score').play();
+ ball.reset();
+ checkWinCondition();
+ }
+ // Flash effect for center line if ball crosses it
+ if (ball.x < 1024 && ball.velocity.x > 0 && ball.x + ball.velocity.x >= 1024 || ball.x > 1024 && ball.velocity.x < 0 && ball.x + ball.velocity.x <= 1024) {
+ tween(centerLineContainer, {
+ alpha: 0.3
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ tween(centerLineContainer, {
+ alpha: 1
+ }, {
+ duration: 100
+ });
+ }
+ });
+ }
+};
\ No newline at end of file