User prompt
the ball still goes trough the players
User prompt
stop the ball from going trough players
User prompt
Player to the right is controlled by human and the player to the left is cpu
Code edit (1 edits merged)
Please save this source code
User prompt
Tennis Championship
User prompt
Not 6 games. Player that wins the first set wins the game
User prompt
Sorry, first to 6 game/1 set wins the match
Initial prompt
A classic pong game but with two actual tennis players on an actual tennis court. A referee, audience and a ball. Points sytem like in a real tennis game. First to 6 sets wins.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AIPaddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('aiPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.difficulty = 0.7;
self.update = function () {
if (ball && ball.velocityX < 0) {
// Ball coming towards AI (left side)
var targetY = ball.y + (Math.random() - 0.5) * 80 * (1 - self.difficulty);
var diff = targetY - self.y;
var moveSpeed = self.speed * self.difficulty;
if (Math.abs(diff) > 8) {
if (diff > 0) {
self.y += moveSpeed;
} else {
self.y -= moveSpeed;
}
}
}
// Keep AI paddle within court bounds
if (self.y < courtTop + 60) self.y = courtTop + 60;
if (self.y > courtBottom - 60) self.y = courtBottom - 60;
};
return self;
});
var PlayerPaddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('playerPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.targetY = 0;
self.update = function () {
var diff = self.targetY - self.y;
if (Math.abs(diff) > 5) {
self.y += diff * 0.15;
}
};
return self;
});
var TennisBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 12;
self.lastPlayerHit = null;
self.reset = function () {
self.x = 1024;
self.y = 1366;
self.velocityX = (Math.random() > 0.5 ? 1 : -1) * self.speed;
self.velocityY = (Math.random() - 0.5) * 8;
self.lastPlayerHit = null;
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Ball collision with top and bottom court boundaries
if (self.y <= courtTop || self.y >= courtBottom) {
self.velocityY = -self.velocityY;
self.y = self.y <= courtTop ? courtTop : courtBottom;
}
// Ball collision with player paddle - prevent tunneling
if (self.velocityX < 0 && self.x <= playerPaddle.x + 20 && self.x >= playerPaddle.x - 20 && self.y >= playerPaddle.y - 60 && self.y <= playerPaddle.y + 60) {
self.velocityX = -self.velocityX * 1.05;
self.velocityY += (self.y - playerPaddle.y) * 0.1;
self.x = playerPaddle.x + 20; // Position ball at paddle edge to prevent tunneling
self.lastPlayerHit = 'player';
LK.getSound('hitBall').play();
rallyCount++;
}
// Ball collision with AI paddle - prevent tunneling
if (self.velocityX > 0 && self.x >= aiPaddle.x - 20 && self.x <= aiPaddle.x + 20 && self.y >= aiPaddle.y - 60 && self.y <= aiPaddle.y + 60) {
self.velocityX = -self.velocityX * 1.05;
self.velocityY += (self.y - aiPaddle.y) * 0.1;
self.x = aiPaddle.x - 20; // Position ball at paddle edge to prevent tunneling
self.lastPlayerHit = 'ai';
LK.getSound('hitBall').play();
rallyCount++;
}
// Ball out of bounds - score point
if (self.x < courtLeft - 50) {
scorePoint('ai');
} else if (self.x > courtRight + 50) {
scorePoint('player');
}
// Limit ball speed
var maxSpeed = 20;
if (Math.abs(self.velocityX) > maxSpeed) {
self.velocityX = self.velocityX > 0 ? maxSpeed : -maxSpeed;
}
if (Math.abs(self.velocityY) > maxSpeed) {
self.velocityY = self.velocityY > 0 ? maxSpeed : -maxSpeed;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Game variables
var playerScore = 0;
var aiScore = 0;
var playerGames = 0;
var aiGames = 0;
var rallyCount = 0;
var gameInProgress = true;
// Court dimensions
var courtLeft = 124;
var courtRight = 1924;
var courtTop = 766;
var courtBottom = 1966;
// Create court
var court = game.addChild(LK.getAsset('court', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// Create net
var net = game.addChild(LK.getAsset('net', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// Create court lines
var topLine = game.addChild(LK.getAsset('courtLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: courtTop
}));
var bottomLine = game.addChild(LK.getAsset('courtLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: courtBottom
}));
var leftLine = game.addChild(LK.getAsset('sideLine', {
anchorX: 0.5,
anchorY: 0.5,
x: courtLeft,
y: 1366
}));
var rightLine = game.addChild(LK.getAsset('sideLine', {
anchorX: 0.5,
anchorY: 0.5,
x: courtRight,
y: 1366
}));
// Service lines
var leftServiceLine = game.addChild(LK.getAsset('serviceLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 574,
y: 1366
}));
var rightServiceLine = game.addChild(LK.getAsset('serviceLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1474,
y: 1366
}));
// Center service line
var centerServiceLine = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1216
}));
// Create paddles
var aiPaddle = game.addChild(new AIPaddle());
aiPaddle.x = 200; // AI on the left
aiPaddle.y = 1366;
var playerPaddle = game.addChild(new PlayerPaddle());
playerPaddle.x = 1848; // Human player on the right
playerPaddle.y = 1366;
// Create ball
var ball = game.addChild(new TennisBall());
ball.reset();
// Score display
var scoreText = new Text2('0 - 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var gameScoreText = new Text2('Games: AI 0 - 0 Player', {
size: 60,
fill: 0xFFFFFF
});
gameScoreText.anchor.set(0.5, 0);
gameScoreText.y = 100;
LK.gui.top.addChild(gameScoreText);
// Touch controls
var dragActive = false;
game.down = function (x, y, obj) {
if (gameInProgress) {
dragActive = true;
playerPaddle.targetY = y;
}
};
game.move = function (x, y, obj) {
if (dragActive && gameInProgress) {
playerPaddle.targetY = y;
// Keep paddle within court bounds
if (playerPaddle.targetY < courtTop + 60) playerPaddle.targetY = courtTop + 60;
if (playerPaddle.targetY > courtBottom - 60) playerPaddle.targetY = courtBottom - 60;
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
// Tennis scoring system
var scoreNames = ['0', '15', '30', '40'];
function getScoreText() {
var playerScoreStr, aiScoreStr;
if (playerScore >= 3 && aiScore >= 3) {
// Deuce situation
if (playerScore === aiScore) {
return 'Deuce';
} else if (playerScore > aiScore) {
return 'Player Advantage';
} else {
return 'AI Advantage';
}
} else {
playerScoreStr = playerScore >= 4 ? '40' : scoreNames[playerScore];
aiScoreStr = aiScore >= 4 ? '40' : scoreNames[aiScore];
return 'AI ' + aiScoreStr + ' - ' + playerScoreStr + ' Player';
}
}
function scorePoint(winner) {
if (!gameInProgress) return;
LK.getSound('scorePoint').play();
if (winner === 'player') {
playerScore++;
} else {
aiScore++;
}
// Check if game is won
var gameWon = false;
if ((playerScore >= 4 || aiScore >= 4) && Math.abs(playerScore - aiScore) >= 2) {
gameWon = true;
if (playerScore > aiScore) {
playerGames++;
} else {
aiGames++;
}
// Reset point scores
playerScore = 0;
aiScore = 0;
}
// Check if set is won
if (gameWon) {
if ((playerGames >= 6 || aiGames >= 6) && Math.abs(playerGames - aiGames) >= 2) {
// Set won
gameInProgress = false;
if (playerGames > aiGames) {
LK.showYouWin();
} else {
LK.showGameOver();
}
} else if (playerGames === 6 && aiGames === 6) {
// Tiebreaker (simplified - first to 7 points wins)
// For simplicity, we'll just continue normal game scoring
}
}
// Update score displays
scoreText.setText(getScoreText());
gameScoreText.setText('Games: AI ' + aiGames + ' - ' + playerGames + ' Player');
// Reset ball and adjust AI difficulty
rallyCount = 0;
aiPaddle.difficulty = Math.min(0.9, 0.5 + (playerGames + aiGames) * 0.05);
ball.reset();
}
game.update = function () {
if (!gameInProgress) return;
// Update score display
scoreText.setText(getScoreText());
gameScoreText.setText('Games: AI ' + aiGames + ' - ' + playerGames + ' Player');
}; ===================================================================
--- original.js
+++ change.js
@@ -74,20 +74,22 @@
if (self.y <= courtTop || self.y >= courtBottom) {
self.velocityY = -self.velocityY;
self.y = self.y <= courtTop ? courtTop : courtBottom;
}
- // Ball collision with player paddle
- if (self.x <= playerPaddle.x + 20 && self.x >= playerPaddle.x - 20 && self.y >= playerPaddle.y - 60 && self.y <= playerPaddle.y + 60 && self.velocityX < 0) {
+ // Ball collision with player paddle - prevent tunneling
+ if (self.velocityX < 0 && self.x <= playerPaddle.x + 20 && self.x >= playerPaddle.x - 20 && self.y >= playerPaddle.y - 60 && self.y <= playerPaddle.y + 60) {
self.velocityX = -self.velocityX * 1.05;
self.velocityY += (self.y - playerPaddle.y) * 0.1;
+ self.x = playerPaddle.x + 20; // Position ball at paddle edge to prevent tunneling
self.lastPlayerHit = 'player';
LK.getSound('hitBall').play();
rallyCount++;
}
- // Ball collision with AI paddle
- if (self.x >= aiPaddle.x - 20 && self.x <= aiPaddle.x + 20 && self.y >= aiPaddle.y - 60 && self.y <= aiPaddle.y + 60 && self.velocityX > 0) {
+ // Ball collision with AI paddle - prevent tunneling
+ if (self.velocityX > 0 && self.x >= aiPaddle.x - 20 && self.x <= aiPaddle.x + 20 && self.y >= aiPaddle.y - 60 && self.y <= aiPaddle.y + 60) {
self.velocityX = -self.velocityX * 1.05;
self.velocityY += (self.y - aiPaddle.y) * 0.1;
+ self.x = aiPaddle.x - 20; // Position ball at paddle edge to prevent tunneling
self.lastPlayerHit = 'ai';
LK.getSound('hitBall').play();
rallyCount++;
}
pixel art tennis ball. In-Game asset. 2d. High contrast. No shadows
tennis referee, Top-down perspective, pixelart. In-Game asset. 2d. High contrast. No shadows
pixelart tennis player looking to the right. In-Game asset. 2d. High contrast. No shadows
pixelart tennis player looking to the left. In-Game asset. 2d. High contrast. No shadows
pixelart tennis audience, looking down. In-Game asset. 2d. High contrast. No shadows
playerHit
Sound effect
aiHit
Sound effect
audienceCheer
Sound effect
audienceCheerExtra
Sound effect
scoreDeuce
Sound effect
scorePlayerAdvantage
Sound effect
scoreAIAdvantage
Sound effect
scorePoint
Sound effect
audienceCheerMatch
Sound effect
refMatchWin
Sound effect
victoryMusic
Music