/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ball class var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = LK.getAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10 }); self.addChild(ballGraphics); // Ball properties self.vx = BALL_INITIAL_SPEED; self.vy = BALL_INITIAL_SPEED; self.speed = BALL_INITIAL_SPEED; // Initialize tracking variables self.lastX = 0; self.lastY = 0; self.lastLeftIntersect = false; self.lastRightIntersect = false; // Reset ball to center with random direction self.reset = function () { self.x = 2048 / 2; self.y = 2732 / 2; self.speed = BALL_INITIAL_SPEED; // Randomize direction but keep it horizontal var angle = Math.random() * Math.PI / 4 - Math.PI / 8; if (Math.random() > 0.5) { angle += Math.PI; } self.vx = Math.cos(angle) * self.speed; self.vy = Math.sin(angle) * self.speed; // Update last positions self.lastX = self.x; self.lastY = self.y; }; self.update = function () { // Move ball self.x += self.vx; self.y += self.vy; // Check top/bottom boundaries if (self.lastY >= 0 && self.y < 0 || self.lastY <= 2732 && self.y > 2732) { self.vy = -self.vy; self.y = self.y < 0 ? 0 : 2732; } // Check paddle collisions var leftIntersect = self.intersects(leftPaddle); var rightIntersect = self.intersects(rightPaddle); // Left paddle collision if (!self.lastLeftIntersect && leftIntersect) { // Play bounce sound on left paddle collision LK.getSound('bounce').play(); self.vx = -self.vx; // Increase speed self.speed += BALL_SPEED_INCREMENT; self.vx = self.vx > 0 ? self.speed : -self.speed; // Adjust angle based on where ball hit paddle var relativeY = (self.y - leftPaddle.y) / 200; self.vy = relativeY * self.speed; } // Right paddle collision if (!self.lastRightIntersect && rightIntersect) { // Play bounce sound on right paddle collision LK.getSound('bounce').play(); self.vx = -self.vx; // Increase speed self.speed += BALL_SPEED_INCREMENT; self.vx = self.vx > 0 ? self.speed : -self.speed; // Adjust angle based on where ball hit paddle var relativeY = (self.y - rightPaddle.y) / 200; self.vy = relativeY * self.speed; } // Check if ball passed the paddles (scoring) if (self.lastX >= 0 && self.x < 0) { // Right player scored LK.getSound('point').play(); rightScore++; rightScoreText.setText(rightScore); // Check win condition if (rightScore >= WINNING_SCORE) { startRainbowEffect(rightScoreText); LK.showYouWin(); } else { self.reset(); } } else if (self.lastX <= 2048 && self.x > 2048) { // Left player scored LK.getSound('point').play(); leftScore++; leftScoreText.setText(leftScore); // Check win condition if (leftScore >= WINNING_SCORE) { startRainbowEffect(leftScoreText); LK.showYouWin(); } else { self.reset(); } } // Update last states self.lastX = self.x; self.lastY = self.y; self.lastLeftIntersect = leftIntersect; self.lastRightIntersect = rightIntersect; }; return self; }); // Create center line var CenterLine = Container.expand(function () { var self = Container.call(this); // Create dashed line segments var lineCount = 20; var segmentHeight = 2732 / (lineCount * 2); for (var i = 0; i < lineCount; i++) { var segment = LK.getAsset('centerLine', { anchorX: 0.5, anchorY: 0.5 }); segment.y = i * segmentHeight * 2 + segmentHeight; self.addChild(segment); // Correctly using the method to add children } return self; }); // Initialize shapes for paddles and ball // Paddle class var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = LK.getAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(paddleGraphics); // Initialize tracking variables self.lastY = 0; // Boundary checking self.update = function () { // Keep paddle within screen bounds // New paddle visual height is 240 (asset width 240, orientation 1). Half height is 120. if (self.y < 120) self.y = 120; if (self.y > 2732 - 120) self.y = 2732 - 120; // Update last position self.lastY = self.y; }; self.down = function (x, y, obj) { activePaddle = self; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Rainbow animation variables and functions var rainbowColors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x9400D3]; // Classic rainbow var rainbowCurrentColorIndex = 0; var rainbowTargetText = null; // Stores the Text2 object currently being animated function _animateToNextRainbowColor() { // Ensure the target text object is still valid and part of the game scene if (!rainbowTargetText || !rainbowTargetText.parent) { rainbowTargetText = null; // Clear target if it's no longer valid return; } rainbowCurrentColorIndex = (rainbowCurrentColorIndex + 1) % rainbowColors.length; var nextColor = rainbowColors[rainbowCurrentColorIndex]; tween(rainbowTargetText, { fill: nextColor }, { duration: 300, // Duration for each color transition in milliseconds easing: tween.linear, // A smooth, linear transition onFinish: function onFinish() { // Continue the animation cycle if the target is still valid if (rainbowTargetText && rainbowTargetText.parent) { _animateToNextRainbowColor(); } else { rainbowTargetText = null; // Clear target if it became invalid during tween } } }); } function startRainbowEffect(textObject) { if (typeof tween === 'undefined') { console.log("Ava here: Tween plugin not available for rainbow effect. Skipping."); return; // Tween plugin isn't loaded } // If another text is already doing the rainbow, stop it. if (rainbowTargetText && rainbowTargetText !== textObject) { tween.stop(rainbowTargetText, { fill: true }); } rainbowTargetText = textObject; var currentFill = textObject.fill; var startIndex = rainbowColors.indexOf(currentFill); if (startIndex !== -1) { // Current color is already in our rainbow, start cycling from there rainbowCurrentColorIndex = startIndex; _animateToNextRainbowColor(); // Start the cycle } else { // Current color is not a rainbow color (e.g., white). // Tween to the first rainbow color, then start cycling. rainbowCurrentColorIndex = 0; // Target the first color in the rainbow array tween(rainbowTargetText, { fill: rainbowColors[rainbowCurrentColorIndex] }, { duration: 150, // Quick transition to the first rainbow color easing: tween.linear, onFinish: function onFinish() { if (rainbowTargetText && rainbowTargetText.parent) { _animateToNextRainbowColor(); // Start the main cycle } else { rainbowTargetText = null; } } }); } } // Game constants var WINNING_SCORE = 10; var PADDLE_SPEED = 15; var BALL_INITIAL_SPEED = 8; var BALL_SPEED_INCREMENT = 0.5; // Game variables var leftScore = 0; var rightScore = 0; var leftScoreText, rightScoreText; var leftPaddle, rightPaddle; var ball; var activePaddle = null; // Initialize shapes for paddles and ball // Create paddles leftPaddle = new Paddle(); leftPaddle.x = 100; leftPaddle.y = 2732 / 2; game.addChild(leftPaddle); rightPaddle = new Paddle(); rightPaddle.x = 2048 - 100; rightPaddle.y = 2732 / 2; game.addChild(rightPaddle); // Create ball ball = new Ball(); ball.reset(); game.addChild(ball); // Create score displays leftScoreText = new Text2('0', { size: 100, fill: 0xFFFFFF }); leftScoreText.anchor.set(0.5, 0); leftScoreText.x = 2048 / 4; leftScoreText.y = 50; game.addChild(leftScoreText); rightScoreText = new Text2('0', { size: 100, fill: 0xFFFFFF }); rightScoreText.anchor.set(0.5, 0); rightScoreText.x = 2048 * 3 / 4; rightScoreText.y = 50; game.addChild(rightScoreText); var centerLine = new CenterLine(); // Initialize center line segments centerLine.x = 2048 / 2; game.addChild(centerLine); // Game event handlers game.move = function (x, y, obj) { if (activePaddle) { activePaddle.y = y; } }; game.up = function (x, y, obj) { activePaddle = null; }; game.down = function (x, y, obj) { // Determine which paddle to control based on which side of the screen was touched if (x < 2048 / 2) { activePaddle = leftPaddle; } else { activePaddle = rightPaddle; } // Move the paddle to the touch position if (activePaddle) { activePaddle.y = y; } }; // Game update loop game.update = function () { // Update game objects ball.update(); leftPaddle.update(); rightPaddle.update(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Ball class
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = LK.getAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 10
});
self.addChild(ballGraphics);
// Ball properties
self.vx = BALL_INITIAL_SPEED;
self.vy = BALL_INITIAL_SPEED;
self.speed = BALL_INITIAL_SPEED;
// Initialize tracking variables
self.lastX = 0;
self.lastY = 0;
self.lastLeftIntersect = false;
self.lastRightIntersect = false;
// Reset ball to center with random direction
self.reset = function () {
self.x = 2048 / 2;
self.y = 2732 / 2;
self.speed = BALL_INITIAL_SPEED;
// Randomize direction but keep it horizontal
var angle = Math.random() * Math.PI / 4 - Math.PI / 8;
if (Math.random() > 0.5) {
angle += Math.PI;
}
self.vx = Math.cos(angle) * self.speed;
self.vy = Math.sin(angle) * self.speed;
// Update last positions
self.lastX = self.x;
self.lastY = self.y;
};
self.update = function () {
// Move ball
self.x += self.vx;
self.y += self.vy;
// Check top/bottom boundaries
if (self.lastY >= 0 && self.y < 0 || self.lastY <= 2732 && self.y > 2732) {
self.vy = -self.vy;
self.y = self.y < 0 ? 0 : 2732;
}
// Check paddle collisions
var leftIntersect = self.intersects(leftPaddle);
var rightIntersect = self.intersects(rightPaddle);
// Left paddle collision
if (!self.lastLeftIntersect && leftIntersect) {
// Play bounce sound on left paddle collision
LK.getSound('bounce').play();
self.vx = -self.vx;
// Increase speed
self.speed += BALL_SPEED_INCREMENT;
self.vx = self.vx > 0 ? self.speed : -self.speed;
// Adjust angle based on where ball hit paddle
var relativeY = (self.y - leftPaddle.y) / 200;
self.vy = relativeY * self.speed;
}
// Right paddle collision
if (!self.lastRightIntersect && rightIntersect) {
// Play bounce sound on right paddle collision
LK.getSound('bounce').play();
self.vx = -self.vx;
// Increase speed
self.speed += BALL_SPEED_INCREMENT;
self.vx = self.vx > 0 ? self.speed : -self.speed;
// Adjust angle based on where ball hit paddle
var relativeY = (self.y - rightPaddle.y) / 200;
self.vy = relativeY * self.speed;
}
// Check if ball passed the paddles (scoring)
if (self.lastX >= 0 && self.x < 0) {
// Right player scored
LK.getSound('point').play();
rightScore++;
rightScoreText.setText(rightScore);
// Check win condition
if (rightScore >= WINNING_SCORE) {
startRainbowEffect(rightScoreText);
LK.showYouWin();
} else {
self.reset();
}
} else if (self.lastX <= 2048 && self.x > 2048) {
// Left player scored
LK.getSound('point').play();
leftScore++;
leftScoreText.setText(leftScore);
// Check win condition
if (leftScore >= WINNING_SCORE) {
startRainbowEffect(leftScoreText);
LK.showYouWin();
} else {
self.reset();
}
}
// Update last states
self.lastX = self.x;
self.lastY = self.y;
self.lastLeftIntersect = leftIntersect;
self.lastRightIntersect = rightIntersect;
};
return self;
});
// Create center line
var CenterLine = Container.expand(function () {
var self = Container.call(this);
// Create dashed line segments
var lineCount = 20;
var segmentHeight = 2732 / (lineCount * 2);
for (var i = 0; i < lineCount; i++) {
var segment = LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5
});
segment.y = i * segmentHeight * 2 + segmentHeight;
self.addChild(segment); // Correctly using the method to add children
}
return self;
});
// Initialize shapes for paddles and ball
// Paddle class
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = LK.getAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(paddleGraphics);
// Initialize tracking variables
self.lastY = 0;
// Boundary checking
self.update = function () {
// Keep paddle within screen bounds
// New paddle visual height is 240 (asset width 240, orientation 1). Half height is 120.
if (self.y < 120) self.y = 120;
if (self.y > 2732 - 120) self.y = 2732 - 120;
// Update last position
self.lastY = self.y;
};
self.down = function (x, y, obj) {
activePaddle = self;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Rainbow animation variables and functions
var rainbowColors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x9400D3]; // Classic rainbow
var rainbowCurrentColorIndex = 0;
var rainbowTargetText = null; // Stores the Text2 object currently being animated
function _animateToNextRainbowColor() {
// Ensure the target text object is still valid and part of the game scene
if (!rainbowTargetText || !rainbowTargetText.parent) {
rainbowTargetText = null; // Clear target if it's no longer valid
return;
}
rainbowCurrentColorIndex = (rainbowCurrentColorIndex + 1) % rainbowColors.length;
var nextColor = rainbowColors[rainbowCurrentColorIndex];
tween(rainbowTargetText, {
fill: nextColor
}, {
duration: 300,
// Duration for each color transition in milliseconds
easing: tween.linear,
// A smooth, linear transition
onFinish: function onFinish() {
// Continue the animation cycle if the target is still valid
if (rainbowTargetText && rainbowTargetText.parent) {
_animateToNextRainbowColor();
} else {
rainbowTargetText = null; // Clear target if it became invalid during tween
}
}
});
}
function startRainbowEffect(textObject) {
if (typeof tween === 'undefined') {
console.log("Ava here: Tween plugin not available for rainbow effect. Skipping.");
return; // Tween plugin isn't loaded
}
// If another text is already doing the rainbow, stop it.
if (rainbowTargetText && rainbowTargetText !== textObject) {
tween.stop(rainbowTargetText, {
fill: true
});
}
rainbowTargetText = textObject;
var currentFill = textObject.fill;
var startIndex = rainbowColors.indexOf(currentFill);
if (startIndex !== -1) {
// Current color is already in our rainbow, start cycling from there
rainbowCurrentColorIndex = startIndex;
_animateToNextRainbowColor(); // Start the cycle
} else {
// Current color is not a rainbow color (e.g., white).
// Tween to the first rainbow color, then start cycling.
rainbowCurrentColorIndex = 0; // Target the first color in the rainbow array
tween(rainbowTargetText, {
fill: rainbowColors[rainbowCurrentColorIndex]
}, {
duration: 150,
// Quick transition to the first rainbow color
easing: tween.linear,
onFinish: function onFinish() {
if (rainbowTargetText && rainbowTargetText.parent) {
_animateToNextRainbowColor(); // Start the main cycle
} else {
rainbowTargetText = null;
}
}
});
}
}
// Game constants
var WINNING_SCORE = 10;
var PADDLE_SPEED = 15;
var BALL_INITIAL_SPEED = 8;
var BALL_SPEED_INCREMENT = 0.5;
// Game variables
var leftScore = 0;
var rightScore = 0;
var leftScoreText, rightScoreText;
var leftPaddle, rightPaddle;
var ball;
var activePaddle = null;
// Initialize shapes for paddles and ball
// Create paddles
leftPaddle = new Paddle();
leftPaddle.x = 100;
leftPaddle.y = 2732 / 2;
game.addChild(leftPaddle);
rightPaddle = new Paddle();
rightPaddle.x = 2048 - 100;
rightPaddle.y = 2732 / 2;
game.addChild(rightPaddle);
// Create ball
ball = new Ball();
ball.reset();
game.addChild(ball);
// Create score displays
leftScoreText = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
leftScoreText.anchor.set(0.5, 0);
leftScoreText.x = 2048 / 4;
leftScoreText.y = 50;
game.addChild(leftScoreText);
rightScoreText = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
rightScoreText.anchor.set(0.5, 0);
rightScoreText.x = 2048 * 3 / 4;
rightScoreText.y = 50;
game.addChild(rightScoreText);
var centerLine = new CenterLine();
// Initialize center line segments
centerLine.x = 2048 / 2;
game.addChild(centerLine);
// Game event handlers
game.move = function (x, y, obj) {
if (activePaddle) {
activePaddle.y = y;
}
};
game.up = function (x, y, obj) {
activePaddle = null;
};
game.down = function (x, y, obj) {
// Determine which paddle to control based on which side of the screen was touched
if (x < 2048 / 2) {
activePaddle = leftPaddle;
} else {
activePaddle = rightPaddle;
}
// Move the paddle to the touch position
if (activePaddle) {
activePaddle.y = y;
}
};
// Game update loop
game.update = function () {
// Update game objects
ball.update();
leftPaddle.update();
rightPaddle.update();
};