/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ball class var Ball = Container.expand(function () { var self = Container.call(this); var ballAsset = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); // Ball speed and direction self.vx = 0; self.vy = 0; // Ball radius for collision self.radius = ballAsset.width / 2; // Ball update self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Paddle class (for both player and AI) var Paddle = Container.expand(function () { var self = Container.call(this); // Default to player paddle var paddleAsset = self.attachAsset('paddlePlayer', { anchorX: 0.5, anchorY: 0.5 }); self.setAI = function () { // Remove old asset if any if (self.children.length > 0) { self.removeChild(self.children[0]); } paddleAsset = self.attachAsset('paddleAI', { anchorX: 0.5, anchorY: 0.5 }); }; // Paddle width/height for collision self.getWidth = function () { return paddleAsset.width; }; self.getHeight = function () { return paddleAsset.height; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Flash for rally // Ball // Paddle (AI) // Paddle (player) // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PADDLE_Y_OFFSET = 120; // Distance from top/bottom for paddles var BALL_START_SPEED = 22; var BALL_SPEED_INCREMENT = 2.5; var MAX_LEVEL = 10; // Game state var playerScore = 0; var aiScore = 0; var level = 1; var rallyCount = 0; var isGameActive = true; // Create paddles and ball var playerPaddle = new Paddle(); var aiPaddle = new Paddle(); aiPaddle.setAI(); var ball = new Ball(); // Add to game game.addChild(playerPaddle); game.addChild(aiPaddle); game.addChild(ball); // Position paddles and ball function resetPositions() { // Center paddles playerPaddle.x = GAME_WIDTH / 2; playerPaddle.y = GAME_HEIGHT - PADDLE_Y_OFFSET; aiPaddle.x = GAME_WIDTH / 2; aiPaddle.y = PADDLE_Y_OFFSET; // Center ball ball.x = GAME_WIDTH / 2; ball.y = GAME_HEIGHT / 2; } // Ball initial direction (randomize angle) function launchBall() { var angle = Math.PI / 2 + (Math.random() - 0.5) * Math.PI / 3; // Downwards, randomize a bit if (Math.random() < 0.5) angle = -angle; // Sometimes start upwards var speed = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT; ball.vx = Math.cos(angle) * speed; ball.vy = Math.sin(angle) * speed; // Ensure vy is not too small (avoid boring horizontal) if (Math.abs(ball.vy) < speed * 0.5) { ball.vy = (ball.vy < 0 ? -1 : 1) * speed * 0.7; } } // Score text var scoreTxt = new Text2('0 : 0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Level text var levelTxt = new Text2('Level 1', { size: 80, fill: 0xFFD700 }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 130; // Rally feedback var rallyTxt = new Text2('', { size: 90, fill: 0x00FF00 }); rallyTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(rallyTxt); // Flash overlay for rally/miss var rallyFlash = LK.getAsset('rallyFlash', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0 }); game.addChild(rallyFlash); // Reset game state for new round/level function startLevel(newLevel) { level = newLevel; playerScore = 0; aiScore = 0; rallyCount = 0; isGameActive = true; updateScoreText(); updateLevelText(); rallyTxt.setText(''); resetPositions(); launchBall(); } // Update score display function updateScoreText() { scoreTxt.setText(playerScore + ' : ' + aiScore); } // Update level display function updateLevelText() { levelTxt.setText('Level ' + level); } // Show rally feedback function showRally(count) { if (count > 1) { rallyTxt.setText('Rally! x' + count); rallyTxt.alpha = 1; tween(rallyTxt, { alpha: 0 }, { duration: 900, easing: tween.linear }); // Flash white rallyFlash.alpha = 0.18; tween(rallyFlash, { alpha: 0 }, { duration: 400, easing: tween.linear }); } } // Show miss feedback function showMiss(who) { rallyTxt.setText(who + ' Miss!'); rallyTxt.alpha = 1; tween(rallyTxt, { alpha: 0 }, { duration: 900, easing: tween.linear }); // Flash red rallyFlash.tint = 0xff0000; rallyFlash.alpha = 0.18; tween(rallyFlash, { alpha: 0 }, { duration: 400, easing: tween.linear, onFinish: function onFinish() { rallyFlash.tint = 0xffffff; } }); } // End game (player lost) function endGame() { isGameActive = false; LK.effects.flashScreen(0xff0000, 900); LK.showGameOver(); } // Win game (player beat all levels) function winGame() { isGameActive = false; LK.effects.flashScreen(0x00ff00, 900); LK.showYouWin(); } // Paddle movement (player drag) var dragPaddle = null; function handleMove(x, y, obj) { if (!isGameActive) return; if (dragPaddle) { // Clamp paddle within game bounds var halfW = dragPaddle.getWidth() / 2; var newX = x; if (newX < halfW) newX = halfW; if (newX > GAME_WIDTH - halfW) newX = GAME_WIDTH - halfW; dragPaddle.x = newX; } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if touch is on/near player paddle var paddleTop = playerPaddle.y - playerPaddle.getHeight() / 2; var paddleBottom = playerPaddle.y + playerPaddle.getHeight() / 2; var paddleLeft = playerPaddle.x - playerPaddle.getWidth() / 2; var paddleRight = playerPaddle.x + playerPaddle.getWidth() / 2; if (y >= paddleTop - 60 && y <= paddleBottom + 60 && x >= paddleLeft - 60 && x <= paddleRight + 60) { dragPaddle = playerPaddle; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragPaddle = null; }; // AI paddle logic function updateAIPaddle() { // AI difficulty increases with level var aiSpeed = 16 + (level - 1) * 3.5; // px per frame var aiReact = 0.18 + (level - 1) * 0.07; // how much of the distance to move per frame if (aiReact > 0.5) aiReact = 0.5; // Only move if ball is moving towards AI if (ball.vy < 0) { var dx = ball.x - aiPaddle.x; var move = dx * aiReact; if (Math.abs(move) > aiSpeed) move = (move > 0 ? 1 : -1) * aiSpeed; aiPaddle.x += move; // Clamp var halfW = aiPaddle.getWidth() / 2; if (aiPaddle.x < halfW) aiPaddle.x = halfW; if (aiPaddle.x > GAME_WIDTH - halfW) aiPaddle.x = GAME_WIDTH - halfW; } } // Ball collision with paddle function ballIntersectsPaddle(paddle) { var px = paddle.x; var py = paddle.y; var pw = paddle.getWidth(); var ph = paddle.getHeight(); // Closest point on paddle to ball var closestX = ball.x; if (ball.x < px - pw / 2) closestX = px - pw / 2;else if (ball.x > px + pw / 2) closestX = px + pw / 2; var closestY = ball.y; if (ball.y < py - ph / 2) closestY = py - ph / 2;else if (ball.y > py + ph / 2) closestY = py + ph / 2; // Distance to ball center var dx = ball.x - closestX; var dy = ball.y - closestY; return dx * dx + dy * dy <= ball.radius * ball.radius; } // Ball collision with wall function ballWallBounce() { // Left/right if (ball.x - ball.radius < 0) { ball.x = ball.radius; ball.vx = -ball.vx; } if (ball.x + ball.radius > GAME_WIDTH) { ball.x = GAME_WIDTH - ball.radius; ball.vx = -ball.vx; } } // Ball out of bounds (top/bottom) function checkScore() { if (ball.y - ball.radius < 0) { // Player scores playerScore += 1; updateScoreText(); showMiss('AI'); rallyCount = 0; if (playerScore >= 5) { // Next level or win if (level >= MAX_LEVEL) { winGame(); } else { startLevel(level + 1); } } else { resetPositions(); launchBall(); } return true; } if (ball.y + ball.radius > GAME_HEIGHT) { // AI scores aiScore += 1; updateScoreText(); showMiss('Player'); rallyCount = 0; if (aiScore >= 3) { endGame(); } else { resetPositions(); launchBall(); } return true; } return false; } // Ball-paddle bounce logic function handleBallPaddleBounce() { // Player paddle if (ball.vy > 0 && ballIntersectsPaddle(playerPaddle)) { // Bounce up ball.y = playerPaddle.y - playerPaddle.getHeight() / 2 - ball.radius; ball.vy = -Math.abs(ball.vy); // Add spin based on where hit var offset = (ball.x - playerPaddle.x) / (playerPaddle.getWidth() / 2); ball.vx += offset * 7; // Clamp vx var maxV = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT + 7; if (ball.vx > maxV) ball.vx = maxV; if (ball.vx < -maxV) ball.vx = -maxV; rallyCount += 1; showRally(rallyCount); } // AI paddle if (ball.vy < 0 && ballIntersectsPaddle(aiPaddle)) { // Bounce down ball.y = aiPaddle.y + aiPaddle.getHeight() / 2 + ball.radius; ball.vy = Math.abs(ball.vy); // Add spin var offset = (ball.x - aiPaddle.x) / (aiPaddle.getWidth() / 2); ball.vx += offset * 7; // Clamp vx var maxV = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT + 7; if (ball.vx > maxV) ball.vx = maxV; if (ball.vx < -maxV) ball.vx = -maxV; rallyCount += 1; showRally(rallyCount); } } // Game update loop game.update = function () { if (!isGameActive) return; // Ball movement ball.update(); // Wall bounce ballWallBounce(); // Paddle bounce handleBallPaddleBounce(); // AI paddle updateAIPaddle(); // Out of bounds/score checkScore(); }; // Start first level startLevel(1);
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,382 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Ball class
+var Ball = Container.expand(function () {
+ var self = Container.call(this);
+ var ballAsset = self.attachAsset('ball', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Ball speed and direction
+ self.vx = 0;
+ self.vy = 0;
+ // Ball radius for collision
+ self.radius = ballAsset.width / 2;
+ // Ball update
+ self.update = function () {
+ self.x += self.vx;
+ self.y += self.vy;
+ };
+ return self;
+});
+// Paddle class (for both player and AI)
+var Paddle = Container.expand(function () {
+ var self = Container.call(this);
+ // Default to player paddle
+ var paddleAsset = self.attachAsset('paddlePlayer', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.setAI = function () {
+ // Remove old asset if any
+ if (self.children.length > 0) {
+ self.removeChild(self.children[0]);
+ }
+ paddleAsset = self.attachAsset('paddleAI', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ };
+ // Paddle width/height for collision
+ self.getWidth = function () {
+ return paddleAsset.width;
+ };
+ self.getHeight = function () {
+ return paddleAsset.height;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x222222
+});
+
+/****
+* Game Code
+****/
+// Flash for rally
+// Ball
+// Paddle (AI)
+// Paddle (player)
+// Game constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var PADDLE_Y_OFFSET = 120; // Distance from top/bottom for paddles
+var BALL_START_SPEED = 22;
+var BALL_SPEED_INCREMENT = 2.5;
+var MAX_LEVEL = 10;
+// Game state
+var playerScore = 0;
+var aiScore = 0;
+var level = 1;
+var rallyCount = 0;
+var isGameActive = true;
+// Create paddles and ball
+var playerPaddle = new Paddle();
+var aiPaddle = new Paddle();
+aiPaddle.setAI();
+var ball = new Ball();
+// Add to game
+game.addChild(playerPaddle);
+game.addChild(aiPaddle);
+game.addChild(ball);
+// Position paddles and ball
+function resetPositions() {
+ // Center paddles
+ playerPaddle.x = GAME_WIDTH / 2;
+ playerPaddle.y = GAME_HEIGHT - PADDLE_Y_OFFSET;
+ aiPaddle.x = GAME_WIDTH / 2;
+ aiPaddle.y = PADDLE_Y_OFFSET;
+ // Center ball
+ ball.x = GAME_WIDTH / 2;
+ ball.y = GAME_HEIGHT / 2;
+}
+// Ball initial direction (randomize angle)
+function launchBall() {
+ var angle = Math.PI / 2 + (Math.random() - 0.5) * Math.PI / 3; // Downwards, randomize a bit
+ if (Math.random() < 0.5) angle = -angle; // Sometimes start upwards
+ var speed = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT;
+ ball.vx = Math.cos(angle) * speed;
+ ball.vy = Math.sin(angle) * speed;
+ // Ensure vy is not too small (avoid boring horizontal)
+ if (Math.abs(ball.vy) < speed * 0.5) {
+ ball.vy = (ball.vy < 0 ? -1 : 1) * speed * 0.7;
+ }
+}
+// Score text
+var scoreTxt = new Text2('0 : 0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Level text
+var levelTxt = new Text2('Level 1', {
+ size: 80,
+ fill: 0xFFD700
+});
+levelTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(levelTxt);
+levelTxt.y = 130;
+// Rally feedback
+var rallyTxt = new Text2('', {
+ size: 90,
+ fill: 0x00FF00
+});
+rallyTxt.anchor.set(0.5, 0.5);
+LK.gui.center.addChild(rallyTxt);
+// Flash overlay for rally/miss
+var rallyFlash = LK.getAsset('rallyFlash', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 0,
+ y: 0,
+ alpha: 0
+});
+game.addChild(rallyFlash);
+// Reset game state for new round/level
+function startLevel(newLevel) {
+ level = newLevel;
+ playerScore = 0;
+ aiScore = 0;
+ rallyCount = 0;
+ isGameActive = true;
+ updateScoreText();
+ updateLevelText();
+ rallyTxt.setText('');
+ resetPositions();
+ launchBall();
+}
+// Update score display
+function updateScoreText() {
+ scoreTxt.setText(playerScore + ' : ' + aiScore);
+}
+// Update level display
+function updateLevelText() {
+ levelTxt.setText('Level ' + level);
+}
+// Show rally feedback
+function showRally(count) {
+ if (count > 1) {
+ rallyTxt.setText('Rally! x' + count);
+ rallyTxt.alpha = 1;
+ tween(rallyTxt, {
+ alpha: 0
+ }, {
+ duration: 900,
+ easing: tween.linear
+ });
+ // Flash white
+ rallyFlash.alpha = 0.18;
+ tween(rallyFlash, {
+ alpha: 0
+ }, {
+ duration: 400,
+ easing: tween.linear
+ });
+ }
+}
+// Show miss feedback
+function showMiss(who) {
+ rallyTxt.setText(who + ' Miss!');
+ rallyTxt.alpha = 1;
+ tween(rallyTxt, {
+ alpha: 0
+ }, {
+ duration: 900,
+ easing: tween.linear
+ });
+ // Flash red
+ rallyFlash.tint = 0xff0000;
+ rallyFlash.alpha = 0.18;
+ tween(rallyFlash, {
+ alpha: 0
+ }, {
+ duration: 400,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ rallyFlash.tint = 0xffffff;
+ }
+ });
+}
+// End game (player lost)
+function endGame() {
+ isGameActive = false;
+ LK.effects.flashScreen(0xff0000, 900);
+ LK.showGameOver();
+}
+// Win game (player beat all levels)
+function winGame() {
+ isGameActive = false;
+ LK.effects.flashScreen(0x00ff00, 900);
+ LK.showYouWin();
+}
+// Paddle movement (player drag)
+var dragPaddle = null;
+function handleMove(x, y, obj) {
+ if (!isGameActive) return;
+ if (dragPaddle) {
+ // Clamp paddle within game bounds
+ var halfW = dragPaddle.getWidth() / 2;
+ var newX = x;
+ if (newX < halfW) newX = halfW;
+ if (newX > GAME_WIDTH - halfW) newX = GAME_WIDTH - halfW;
+ dragPaddle.x = newX;
+ }
+}
+game.move = handleMove;
+game.down = function (x, y, obj) {
+ // Only allow drag if touch is on/near player paddle
+ var paddleTop = playerPaddle.y - playerPaddle.getHeight() / 2;
+ var paddleBottom = playerPaddle.y + playerPaddle.getHeight() / 2;
+ var paddleLeft = playerPaddle.x - playerPaddle.getWidth() / 2;
+ var paddleRight = playerPaddle.x + playerPaddle.getWidth() / 2;
+ if (y >= paddleTop - 60 && y <= paddleBottom + 60 && x >= paddleLeft - 60 && x <= paddleRight + 60) {
+ dragPaddle = playerPaddle;
+ handleMove(x, y, obj);
+ }
+};
+game.up = function (x, y, obj) {
+ dragPaddle = null;
+};
+// AI paddle logic
+function updateAIPaddle() {
+ // AI difficulty increases with level
+ var aiSpeed = 16 + (level - 1) * 3.5; // px per frame
+ var aiReact = 0.18 + (level - 1) * 0.07; // how much of the distance to move per frame
+ if (aiReact > 0.5) aiReact = 0.5;
+ // Only move if ball is moving towards AI
+ if (ball.vy < 0) {
+ var dx = ball.x - aiPaddle.x;
+ var move = dx * aiReact;
+ if (Math.abs(move) > aiSpeed) move = (move > 0 ? 1 : -1) * aiSpeed;
+ aiPaddle.x += move;
+ // Clamp
+ var halfW = aiPaddle.getWidth() / 2;
+ if (aiPaddle.x < halfW) aiPaddle.x = halfW;
+ if (aiPaddle.x > GAME_WIDTH - halfW) aiPaddle.x = GAME_WIDTH - halfW;
+ }
+}
+// Ball collision with paddle
+function ballIntersectsPaddle(paddle) {
+ var px = paddle.x;
+ var py = paddle.y;
+ var pw = paddle.getWidth();
+ var ph = paddle.getHeight();
+ // Closest point on paddle to ball
+ var closestX = ball.x;
+ if (ball.x < px - pw / 2) closestX = px - pw / 2;else if (ball.x > px + pw / 2) closestX = px + pw / 2;
+ var closestY = ball.y;
+ if (ball.y < py - ph / 2) closestY = py - ph / 2;else if (ball.y > py + ph / 2) closestY = py + ph / 2;
+ // Distance to ball center
+ var dx = ball.x - closestX;
+ var dy = ball.y - closestY;
+ return dx * dx + dy * dy <= ball.radius * ball.radius;
+}
+// Ball collision with wall
+function ballWallBounce() {
+ // Left/right
+ if (ball.x - ball.radius < 0) {
+ ball.x = ball.radius;
+ ball.vx = -ball.vx;
+ }
+ if (ball.x + ball.radius > GAME_WIDTH) {
+ ball.x = GAME_WIDTH - ball.radius;
+ ball.vx = -ball.vx;
+ }
+}
+// Ball out of bounds (top/bottom)
+function checkScore() {
+ if (ball.y - ball.radius < 0) {
+ // Player scores
+ playerScore += 1;
+ updateScoreText();
+ showMiss('AI');
+ rallyCount = 0;
+ if (playerScore >= 5) {
+ // Next level or win
+ if (level >= MAX_LEVEL) {
+ winGame();
+ } else {
+ startLevel(level + 1);
+ }
+ } else {
+ resetPositions();
+ launchBall();
+ }
+ return true;
+ }
+ if (ball.y + ball.radius > GAME_HEIGHT) {
+ // AI scores
+ aiScore += 1;
+ updateScoreText();
+ showMiss('Player');
+ rallyCount = 0;
+ if (aiScore >= 3) {
+ endGame();
+ } else {
+ resetPositions();
+ launchBall();
+ }
+ return true;
+ }
+ return false;
+}
+// Ball-paddle bounce logic
+function handleBallPaddleBounce() {
+ // Player paddle
+ if (ball.vy > 0 && ballIntersectsPaddle(playerPaddle)) {
+ // Bounce up
+ ball.y = playerPaddle.y - playerPaddle.getHeight() / 2 - ball.radius;
+ ball.vy = -Math.abs(ball.vy);
+ // Add spin based on where hit
+ var offset = (ball.x - playerPaddle.x) / (playerPaddle.getWidth() / 2);
+ ball.vx += offset * 7;
+ // Clamp vx
+ var maxV = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT + 7;
+ if (ball.vx > maxV) ball.vx = maxV;
+ if (ball.vx < -maxV) ball.vx = -maxV;
+ rallyCount += 1;
+ showRally(rallyCount);
+ }
+ // AI paddle
+ if (ball.vy < 0 && ballIntersectsPaddle(aiPaddle)) {
+ // Bounce down
+ ball.y = aiPaddle.y + aiPaddle.getHeight() / 2 + ball.radius;
+ ball.vy = Math.abs(ball.vy);
+ // Add spin
+ var offset = (ball.x - aiPaddle.x) / (aiPaddle.getWidth() / 2);
+ ball.vx += offset * 7;
+ // Clamp vx
+ var maxV = BALL_START_SPEED + (level - 1) * BALL_SPEED_INCREMENT + 7;
+ if (ball.vx > maxV) ball.vx = maxV;
+ if (ball.vx < -maxV) ball.vx = -maxV;
+ rallyCount += 1;
+ showRally(rallyCount);
+ }
+}
+// Game update loop
+game.update = function () {
+ if (!isGameActive) return;
+ // Ball movement
+ ball.update();
+ // Wall bounce
+ ballWallBounce();
+ // Paddle bounce
+ handleBallPaddleBounce();
+ // AI paddle
+ updateAIPaddle();
+ // Out of bounds/score
+ checkScore();
+};
+// Start first level
+startLevel(1);
\ No newline at end of file