/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 6; self.velocityY = 4; self.maxSpeed = 15; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Bounce off top and bottom walls if (self.y <= 20 || self.y >= 2732 - 20) { self.velocityY = -self.velocityY; LK.getSound('wallHit').play(); } // Check collision with left paddle if (self.intersects(leftPaddle) && self.velocityX < 0) { self.velocityX = -self.velocityX; self.velocityY += (Math.random() - 0.5) * 2; // Increase speed slightly if (Math.abs(self.velocityX) < self.maxSpeed) { self.velocityX *= 1.05; } if (Math.abs(self.velocityY) < self.maxSpeed) { self.velocityY *= 1.05; } LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('paddleHit').play(); // Show message when ball is touched tween.stop(messageTxt, { alpha: true }); messageTxt.alpha = 0; tween(messageTxt, { alpha: 1 }, { duration: 200, onFinish: function onFinish() { tween(messageTxt, { alpha: 0 }, { duration: 1000 }); } }); } // Check collision with right paddle if (self.intersects(rightPaddle) && self.velocityX > 0) { self.velocityX = -self.velocityX; self.velocityY += (Math.random() - 0.5) * 2; // Increase speed slightly if (Math.abs(self.velocityX) < self.maxSpeed) { self.velocityX *= 1.05; } if (Math.abs(self.velocityY) < self.maxSpeed) { self.velocityY *= 1.05; } LK.getSound('paddleHit').play(); } // Check collision with middle line if (game.middleLine && self.intersects(game.middleLine)) { self.velocityX = -self.velocityX; LK.getSound('wallHit').play(); } // Check if ball goes off screen - decrease lives if (self.x < -60) { // Player loses a life (ball went past left side) playerLives--; playerLivesTxt.setText('Player Lives: ' + playerLives); if (playerLives <= 0) { LK.showGameOver(); } else { // Reset ball position self.x = 2048 / 2; self.y = 2732 / 2; self.velocityX = Math.abs(self.velocityX); self.velocityY = (Math.random() - 0.5) * 8; } } else if (self.x > 2048 + 60) { // AI loses a life (ball went past right side) aiLives--; aiLivesTxt.setText('AI Lives: ' + aiLives); if (aiLives <= 0) { LK.showYouWin(); } else { // Reset ball position self.x = 2048 / 2; self.y = 2732 / 2; self.velocityX = -Math.abs(self.velocityX); self.velocityY = (Math.random() - 0.5) * 8; } } }; return self; }); var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.isPlayerControlled = false; return self; }); var XPaddle = Container.expand(function () { var self = Container.call(this); // Create X shape using two rotated rectangles var xBar1 = self.attachAsset('xPaddle', { anchorX: 0.5, anchorY: 0.5, scaleY: 0.1, rotation: Math.PI / 4 }); var xBar2 = self.attachAsset('xPaddle', { anchorX: 0.5, anchorY: 0.5, scaleY: 0.1, rotation: -Math.PI / 4 }); self.speed = 8; self.isPlayerControlled = false; // Custom intersects method for X-shaped collision self.intersects = function (other) { var dx = Math.abs(self.x - other.x); var dy = Math.abs(self.y - other.y); // Check if ball is within X bounds (increased for larger X) if (dx <= 90 && dy <= 90) { // Check if ball hits the X lines (diagonal collision) var relX = other.x - self.x; var relY = other.y - self.y; // Check diagonal lines of X (thicker lines) var onDiagonal1 = Math.abs(relY - relX) < 35; var onDiagonal2 = Math.abs(relY + relX) < 35; return onDiagonal1 || onDiagonal2; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var leftPaddle = game.addChild(new Paddle()); leftPaddle.x = 30; leftPaddle.y = 2732 / 2; leftPaddle.isPlayerControlled = true; var rightPaddle = game.addChild(new Paddle()); rightPaddle.x = 2048 - 30; rightPaddle.y = 2732 / 2; var ball = game.addChild(new Ball()); ball.x = 2048 / 2; ball.y = 2732 / 2; // Randomize initial ball direction if (Math.random() < 0.5) { ball.velocityX = -ball.velocityX; } var playerLives = 3; var aiLives = 3; var scareShown = false; var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.setText(LK.getScore()); var playerLivesTxt = new Text2('Player Lives: 3', { size: 60, fill: 0xFFFFFF }); playerLivesTxt.anchor.set(0, 0); playerLivesTxt.x = 150; playerLivesTxt.y = 50; game.addChild(playerLivesTxt); var aiLivesTxt = new Text2('AI Lives: 3', { size: 60, fill: 0xFFFFFF }); aiLivesTxt.anchor.set(1, 0); aiLivesTxt.x = 2048 - 50; aiLivesTxt.y = 50; game.addChild(aiLivesTxt); var messageTxt = new Text2('+1 point', { size: 80, fill: 0xFFFFFF }); messageTxt.anchor.set(0.5, 0.5); messageTxt.x = 2048 / 2; messageTxt.y = 2732 / 2; messageTxt.alpha = 0; game.addChild(messageTxt); var dragPaddle = null; game.down = function (x, y, obj) { // Only allow dragging on the left side of screen (player paddle) if (x < 2048 / 2) { dragPaddle = leftPaddle; } }; game.move = function (x, y, obj) { if (dragPaddle) { dragPaddle.y = y; // Keep paddle within screen bounds if (dragPaddle.y < 75) { dragPaddle.y = 75; } if (dragPaddle.y > 2732 - 75) { dragPaddle.y = 2732 - 75; } } }; game.up = function (x, y, obj) { dragPaddle = null; }; // Play background music LK.playMusic('Musica'); game.update = function () { // Get current score for difficulty adjustment var currentScore = LK.getScore(); var aiSpeed = rightPaddle.speed; var aiAccuracy = 5; var ballSpeedMultiplier = 1; // Switch to X-shaped paddle when reaching 3 points if (currentScore >= 3 && leftPaddle.constructor === Paddle) { var oldX = leftPaddle.x; var oldY = leftPaddle.y; game.removeChild(leftPaddle); leftPaddle = game.addChild(new XPaddle()); leftPaddle.x = oldX; leftPaddle.y = oldY; leftPaddle.isPlayerControlled = true; } // Add middle line when reaching 5 points if (currentScore >= 5 && !game.middleLine) { game.middleLine = game.addChild(LK.getAsset('middleLine', { anchorX: 0.5, anchorY: 0.5 })); game.middleLine.x = 2048 / 2; game.middleLine.y = 2732 / 2; } // Adjust AI difficulty and ball speed based on score if (currentScore >= 0 && currentScore < 1) { // Starting difficulty aiSpeed = 5; aiAccuracy = 40; ballSpeedMultiplier = 1; } else if (currentScore >= 1 && currentScore < 3) { // Ball goes faster at 1 point aiSpeed = 5; aiAccuracy = 40; ballSpeedMultiplier = 1.3; // Faster ball when reaching 1 point } else if (currentScore >= 3 && currentScore < 5) { // Smarter AI: improved speed and accuracy, faster ball aiSpeed = 5; aiAccuracy = 30; // More accurate tracking ballSpeedMultiplier = 1.4; // Even faster ball when reaching 3 points } else if (currentScore >= 5 && currentScore <= 15) { // Medium AI with X-paddle and middle line: more challenging aiSpeed = 6; aiAccuracy = 25; ballSpeedMultiplier = 1.5; } else if (currentScore >= 16 && currentScore <= 25) { // Hard AI: even faster ball, smarter AI aiSpeed = 8; aiAccuracy = 15; ballSpeedMultiplier = 1.7; } // Trigger scare effect at 23 points if (currentScore >= 23 && !scareShown) { scareShown = true; // Pause all game objects ball.velocityX = 0; ball.velocityY = 0; leftPaddle.speed = 0; rightPaddle.speed = 0; // Create full screen scare image var scareImg = game.addChild(LK.getAsset('scareImage', { anchorX: 0.5, anchorY: 0.5 })); scareImg.x = 2048 / 2; scareImg.y = 2732 / 2; scareImg.alpha = 0; // Scale to cover full screen scareImg.scaleX = 2048 / 400; scareImg.scaleY = 2732 / 400; // Play scare sound LK.getSound('scareSound').play(); // Animate scare image appearing tween(scareImg, { alpha: 1 }, { duration: 300, onFinish: function onFinish() { // Keep image visible for 2 seconds then show game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } }); return; // Stop all game updates while scare is showing } // Check for win condition if (currentScore >= 25) { // Hide all game elements leftPaddle.visible = false; rightPaddle.visible = false; ball.visible = false; messageTxt.visible = false; // Show win message var winMessage = new Text2('Ganaste', { size: 120, fill: 0xFFFFFF }); winMessage.anchor.set(0.5, 0.5); winMessage.x = 2048 / 2; winMessage.y = 2732 / 2; game.addChild(winMessage); return; // Stop game update } // Apply ball speed multiplier ball.maxSpeed = 15 * ballSpeedMultiplier; // AI for right paddle with difficulty adjustment var targetY = ball.y; var paddleCenter = rightPaddle.y; if (Math.abs(targetY - paddleCenter) > aiAccuracy) { if (targetY > paddleCenter) { rightPaddle.y += aiSpeed; } else { rightPaddle.y -= aiSpeed; } } // Keep AI paddle within screen bounds if (rightPaddle.y < 75) { rightPaddle.y = 75; } if (rightPaddle.y > 2732 - 75) { rightPaddle.y = 2732 - 75; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 6;
self.velocityY = 4;
self.maxSpeed = 15;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off top and bottom walls
if (self.y <= 20 || self.y >= 2732 - 20) {
self.velocityY = -self.velocityY;
LK.getSound('wallHit').play();
}
// Check collision with left paddle
if (self.intersects(leftPaddle) && self.velocityX < 0) {
self.velocityX = -self.velocityX;
self.velocityY += (Math.random() - 0.5) * 2;
// Increase speed slightly
if (Math.abs(self.velocityX) < self.maxSpeed) {
self.velocityX *= 1.05;
}
if (Math.abs(self.velocityY) < self.maxSpeed) {
self.velocityY *= 1.05;
}
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('paddleHit').play();
// Show message when ball is touched
tween.stop(messageTxt, {
alpha: true
});
messageTxt.alpha = 0;
tween(messageTxt, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
tween(messageTxt, {
alpha: 0
}, {
duration: 1000
});
}
});
}
// Check collision with right paddle
if (self.intersects(rightPaddle) && self.velocityX > 0) {
self.velocityX = -self.velocityX;
self.velocityY += (Math.random() - 0.5) * 2;
// Increase speed slightly
if (Math.abs(self.velocityX) < self.maxSpeed) {
self.velocityX *= 1.05;
}
if (Math.abs(self.velocityY) < self.maxSpeed) {
self.velocityY *= 1.05;
}
LK.getSound('paddleHit').play();
}
// Check collision with middle line
if (game.middleLine && self.intersects(game.middleLine)) {
self.velocityX = -self.velocityX;
LK.getSound('wallHit').play();
}
// Check if ball goes off screen - decrease lives
if (self.x < -60) {
// Player loses a life (ball went past left side)
playerLives--;
playerLivesTxt.setText('Player Lives: ' + playerLives);
if (playerLives <= 0) {
LK.showGameOver();
} else {
// Reset ball position
self.x = 2048 / 2;
self.y = 2732 / 2;
self.velocityX = Math.abs(self.velocityX);
self.velocityY = (Math.random() - 0.5) * 8;
}
} else if (self.x > 2048 + 60) {
// AI loses a life (ball went past right side)
aiLives--;
aiLivesTxt.setText('AI Lives: ' + aiLives);
if (aiLives <= 0) {
LK.showYouWin();
} else {
// Reset ball position
self.x = 2048 / 2;
self.y = 2732 / 2;
self.velocityX = -Math.abs(self.velocityX);
self.velocityY = (Math.random() - 0.5) * 8;
}
}
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.isPlayerControlled = false;
return self;
});
var XPaddle = Container.expand(function () {
var self = Container.call(this);
// Create X shape using two rotated rectangles
var xBar1 = self.attachAsset('xPaddle', {
anchorX: 0.5,
anchorY: 0.5,
scaleY: 0.1,
rotation: Math.PI / 4
});
var xBar2 = self.attachAsset('xPaddle', {
anchorX: 0.5,
anchorY: 0.5,
scaleY: 0.1,
rotation: -Math.PI / 4
});
self.speed = 8;
self.isPlayerControlled = false;
// Custom intersects method for X-shaped collision
self.intersects = function (other) {
var dx = Math.abs(self.x - other.x);
var dy = Math.abs(self.y - other.y);
// Check if ball is within X bounds (increased for larger X)
if (dx <= 90 && dy <= 90) {
// Check if ball hits the X lines (diagonal collision)
var relX = other.x - self.x;
var relY = other.y - self.y;
// Check diagonal lines of X (thicker lines)
var onDiagonal1 = Math.abs(relY - relX) < 35;
var onDiagonal2 = Math.abs(relY + relX) < 35;
return onDiagonal1 || onDiagonal2;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var leftPaddle = game.addChild(new Paddle());
leftPaddle.x = 30;
leftPaddle.y = 2732 / 2;
leftPaddle.isPlayerControlled = true;
var rightPaddle = game.addChild(new Paddle());
rightPaddle.x = 2048 - 30;
rightPaddle.y = 2732 / 2;
var ball = game.addChild(new Ball());
ball.x = 2048 / 2;
ball.y = 2732 / 2;
// Randomize initial ball direction
if (Math.random() < 0.5) {
ball.velocityX = -ball.velocityX;
}
var playerLives = 3;
var aiLives = 3;
var scareShown = false;
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
var playerLivesTxt = new Text2('Player Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
playerLivesTxt.anchor.set(0, 0);
playerLivesTxt.x = 150;
playerLivesTxt.y = 50;
game.addChild(playerLivesTxt);
var aiLivesTxt = new Text2('AI Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
aiLivesTxt.anchor.set(1, 0);
aiLivesTxt.x = 2048 - 50;
aiLivesTxt.y = 50;
game.addChild(aiLivesTxt);
var messageTxt = new Text2('+1 point', {
size: 80,
fill: 0xFFFFFF
});
messageTxt.anchor.set(0.5, 0.5);
messageTxt.x = 2048 / 2;
messageTxt.y = 2732 / 2;
messageTxt.alpha = 0;
game.addChild(messageTxt);
var dragPaddle = null;
game.down = function (x, y, obj) {
// Only allow dragging on the left side of screen (player paddle)
if (x < 2048 / 2) {
dragPaddle = leftPaddle;
}
};
game.move = function (x, y, obj) {
if (dragPaddle) {
dragPaddle.y = y;
// Keep paddle within screen bounds
if (dragPaddle.y < 75) {
dragPaddle.y = 75;
}
if (dragPaddle.y > 2732 - 75) {
dragPaddle.y = 2732 - 75;
}
}
};
game.up = function (x, y, obj) {
dragPaddle = null;
};
// Play background music
LK.playMusic('Musica');
game.update = function () {
// Get current score for difficulty adjustment
var currentScore = LK.getScore();
var aiSpeed = rightPaddle.speed;
var aiAccuracy = 5;
var ballSpeedMultiplier = 1;
// Switch to X-shaped paddle when reaching 3 points
if (currentScore >= 3 && leftPaddle.constructor === Paddle) {
var oldX = leftPaddle.x;
var oldY = leftPaddle.y;
game.removeChild(leftPaddle);
leftPaddle = game.addChild(new XPaddle());
leftPaddle.x = oldX;
leftPaddle.y = oldY;
leftPaddle.isPlayerControlled = true;
}
// Add middle line when reaching 5 points
if (currentScore >= 5 && !game.middleLine) {
game.middleLine = game.addChild(LK.getAsset('middleLine', {
anchorX: 0.5,
anchorY: 0.5
}));
game.middleLine.x = 2048 / 2;
game.middleLine.y = 2732 / 2;
}
// Adjust AI difficulty and ball speed based on score
if (currentScore >= 0 && currentScore < 1) {
// Starting difficulty
aiSpeed = 5;
aiAccuracy = 40;
ballSpeedMultiplier = 1;
} else if (currentScore >= 1 && currentScore < 3) {
// Ball goes faster at 1 point
aiSpeed = 5;
aiAccuracy = 40;
ballSpeedMultiplier = 1.3; // Faster ball when reaching 1 point
} else if (currentScore >= 3 && currentScore < 5) {
// Smarter AI: improved speed and accuracy, faster ball
aiSpeed = 5;
aiAccuracy = 30; // More accurate tracking
ballSpeedMultiplier = 1.4; // Even faster ball when reaching 3 points
} else if (currentScore >= 5 && currentScore <= 15) {
// Medium AI with X-paddle and middle line: more challenging
aiSpeed = 6;
aiAccuracy = 25;
ballSpeedMultiplier = 1.5;
} else if (currentScore >= 16 && currentScore <= 25) {
// Hard AI: even faster ball, smarter AI
aiSpeed = 8;
aiAccuracy = 15;
ballSpeedMultiplier = 1.7;
}
// Trigger scare effect at 23 points
if (currentScore >= 23 && !scareShown) {
scareShown = true;
// Pause all game objects
ball.velocityX = 0;
ball.velocityY = 0;
leftPaddle.speed = 0;
rightPaddle.speed = 0;
// Create full screen scare image
var scareImg = game.addChild(LK.getAsset('scareImage', {
anchorX: 0.5,
anchorY: 0.5
}));
scareImg.x = 2048 / 2;
scareImg.y = 2732 / 2;
scareImg.alpha = 0;
// Scale to cover full screen
scareImg.scaleX = 2048 / 400;
scareImg.scaleY = 2732 / 400;
// Play scare sound
LK.getSound('scareSound').play();
// Animate scare image appearing
tween(scareImg, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
// Keep image visible for 2 seconds then show game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
});
return; // Stop all game updates while scare is showing
}
// Check for win condition
if (currentScore >= 25) {
// Hide all game elements
leftPaddle.visible = false;
rightPaddle.visible = false;
ball.visible = false;
messageTxt.visible = false;
// Show win message
var winMessage = new Text2('Ganaste', {
size: 120,
fill: 0xFFFFFF
});
winMessage.anchor.set(0.5, 0.5);
winMessage.x = 2048 / 2;
winMessage.y = 2732 / 2;
game.addChild(winMessage);
return; // Stop game update
}
// Apply ball speed multiplier
ball.maxSpeed = 15 * ballSpeedMultiplier;
// AI for right paddle with difficulty adjustment
var targetY = ball.y;
var paddleCenter = rightPaddle.y;
if (Math.abs(targetY - paddleCenter) > aiAccuracy) {
if (targetY > paddleCenter) {
rightPaddle.y += aiSpeed;
} else {
rightPaddle.y -= aiSpeed;
}
}
// Keep AI paddle within screen bounds
if (rightPaddle.y < 75) {
rightPaddle.y = 75;
}
if (rightPaddle.y > 2732 - 75) {
rightPaddle.y = 2732 - 75;
}
};