/****
* 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;
}
};