User prompt
Score +1 when the ball hits the opponents goal
User prompt
Put the goal on the goal line on the pitch
User prompt
Put football goals on the middle right and on the middle left
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'box.x')' in or related to this line: 'var boxX = box.x;' Line Number: 303
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: net' in or related to this line: 'player1.x = Math.max(player1.width / 2, Math.min(player1.x + dx * movementRatio, 1024 - player1.width / 2 - net.width / 2));' Line Number: 424
User prompt
Make this game soccer
Remix started
Copy Slimy Volley
/****
* Classes
****/
// Goal class
var Goal = Container.expand(function (side) {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 1,
alpha: isDebug ? 0.5 : 0
});
self.side = side; // 1 = left, 2 = right
return self;
});
// Player class
var Player = Container.expand(function (index) {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1,
alpha: 0.98,
scaleX: index === 2 ? -1 : 1,
tint: index === 1 ? 0xADD8E6 : 0xFF6347 // Light blue for player 1, Tomato red for player 2
});
self.index = index;
self.scale.set(1, 1); // Initialize player scale to normal
self.jumping = false;
self.falling = false;
self.speedX = 0; // Initialize horizontal speed
var collidSize = 245;
self.collisionBody = LK.getAsset('collisionBody', {
anchorX: 0.5,
anchorY: 0.5,
alpha: isDebug ? 0.6 : 0,
width: collidSize,
height: collidSize,
x: 0,
y: -200
});
self.addChild(self.collisionBody);
self.update = function () {
var prevX = self.x; // Store previous x position
var prevY = self.y; // Store previous y position
if (self.jumping && !self.falling) {
self.y -= 20; // Increase jump speed
self.scale.set(1, 1 + 0.25 * (PLAYER_INITIAL_Y - self.y) / 700); // Progressive scaling when jumping
if (self.y <= 1300) {
self.falling = true;
}
}
if (self.falling && self.y < PLAYER_INITIAL_Y) {
self.y += 20; // Increase fall speed for smoother jump
if (self.y > PLAYER_INITIAL_Y - 256) {
self.scale.set(1 + 0.15 * (PLAYER_INITIAL_Y - self.y) / 700, 1 - 0.15 * (PLAYER_INITIAL_Y - self.y) / 700); // Progressive scaling when falling
}
}
if (self.y >= PLAYER_INITIAL_Y) {
self.jumping = false;
self.falling = false;
self.y = PLAYER_INITIAL_Y; // Ensure player lands on the ground
// Reset scale to normal when player stops moving
self.scale.set(1, 1);
}
if (self.y < 0) {
self.y = 0; // Prevent player1 from moving above the window
}
if (self.index === 2 && self.x > 1024 && self.x < 1024 + self.width / 2) {
self.x = 1024 + self.width / 2; // Prevent player2 from moving past the net
}
self.speedX = self.x - prevX; // Calculate horizontal speed based on movement
self.speedY = self.y - prevY; // Calculate vertical speed based on movement
};
});
// Initialize rotation speed
//<Assets used in the game will automatically appear here>
// SoccerBall class
var SoccerBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('soccerBall', {
anchorX: 0.5,
anchorY: 0.5
});
self.rotationSpeed = 0;
var half = self.width / 2;
self.speedX = 3;
self.speedY = 3;
self.accelerationY = 0.5; // Gravity
self.friction = 0.99; // Friction to slow down the ball over time
self.lastCollisionTime = 0; // Initialize last collision time
self.update = function (goalLeft, goalRight, player1, player2) {
if (!ballCanMove) {
return;
}
// Apply gravity
self.speedY += self.accelerationY;
// Apply friction
self.speedX *= self.friction;
self.speedY *= self.friction;
// Apply speed limit
self.speedX = Math.sign(self.speedX) * Math.min(Math.abs(self.speedX), SPEED_LIMIT);
self.speedY = Math.sign(self.speedY) * Math.min(Math.abs(self.speedY), SPEED_LIMIT);
// Update ball position
self.x += self.speedX;
self.y += self.speedY;
self.rotation += self.rotationSpeed * (self.speedX > 0 ? 1 : -1); // Update ball rotation based on direction
self.rotationSpeed *= 0.98; // Gradually decrease rotation speed
// Check for out of bounds (bottom = ground)
if (self.y + half > 2000) {
self.y = 2000 - half;
self.speedY = -Math.abs(self.speedY) * 0.7;
self.speedX *= 0.9;
playSound('whistle', 1000);
// If ball is in the left goal area, player 2 scores (ball hit rightwards into left goal)
if (customBoxCircleIntersect(goalLeft, self)) {
// Ball must be moving leftwards (from right to left) to count as a goal for player 2
if (self.speedX < 0) {
updateScore(2);
}
resetBall();
}
// If ball is in the right goal area, player 1 scores (ball hit leftwards into right goal)
else if (customBoxCircleIntersect(goalRight, self)) {
// Ball must be moving rightwards (from left to right) to count as a goal for player 1
if (self.speedX > 0) {
updateScore(1);
}
resetBall();
} else {
// No goal, just reset
servingPlayer = servingPlayer == 1 ? 2 : 1;
resetBall();
}
player1Touches = 0;
player2Touches = 0;
} else if (self.y - half < 0) {
self.y = half;
self.speedY = Math.abs(self.speedY) * 0.8;
}
// Check for x screen limits
if (self.x - half < 0) {
self.x = half;
self.speedX = Math.abs(self.speedX);
} else if (self.x + half > 2048) {
self.x = 2048 - half;
self.speedX = -Math.abs(self.speedX);
}
// Collision detection logic moved to game update
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
var PLAYER1_INITIAL_X = 256;
var PLAYER_INITIAL_Y = 2000;
var PLAYER2_INITIAL_X = 1792;
var BALL1_INITIAL_X = 640;
var BALL_INITIAL_Y = 1256;
var BALL2_INITIAL_X = 1408;
var gameStarted = false;
var startButton = null;
var joystick;
var joystickBasePosition;
var joystickDrag;
var touchTime; // Global variable to store the touch time
var prevMouseY;
var lastPlayedTime;
var ballCanMove;
var SPEED_LIMIT; // Define a global speed limit
var isDebug = false;
var player2Debug;
var player1Touches;
var player2Touches;
var resetTime; // Global variable to store the reset time
var nextRoundPauseDelay;
var score1;
var score2;
var finalScore = 15; // Define the final score for the game
var servingPlayer = 1; // Initialize serving player to player 1
var ballShadow;
var player1Shadow;
var player2Shadow;
var beachBall = null;
function playSound(soundId, cooldown) {
var currentTime = Date.now();
if (!lastPlayedTime[soundId] || currentTime - lastPlayedTime[soundId] > cooldown) {
LK.getSound(soundId).play();
lastPlayedTime[soundId] = currentTime;
}
}
function updateScore(index) {
if (index === 1) {
score1 += 1;
scoreTxt1.setText(score1.toString().padStart(2, '0'));
} else if (index === 2) {
score2 += 1;
scoreTxt2.setText(score2.toString().padStart(2, '0'));
}
// Check for game over condition
if ((score1 >= finalScore || score2 >= finalScore) && Math.abs(score1 - score2) >= 2) {
var resultText = new Text2(score1 > score2 ? 'VICTORY!' : 'DEFEAT!', {
size: 300,
fill: 0xFFFFFF,
fontWeight: "bold",
dropShadow: true
});
resultText.anchor.set(0.5, 2);
//resultText.x = 0;
//resultText.y = -512;
LK.gui.center.addChild(resultText);
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}
function handleJoystickLimits(x, y) {
if (joystickDrag) {
var dx = x - joystickBasePosition.x;
var dy = y - joystickBasePosition.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var maxDistance = joystick.width / 3; // Max distance joystick can move from center
if (distance > maxDistance) {
var angle = Math.atan2(dy, dx);
dx = Math.cos(angle) * maxDistance;
dy = Math.sin(angle) * maxDistance;
}
joystick.x = joystickBasePosition.x + dx;
joystick.y = joystickBasePosition.y + dy;
}
}
function aiUpdate() {
if (ball.x > 1024) {
if (ball.x > player2.x + player2.width / 2) {
player2.x += 5; // Move right
} else if (ball.x < player2.x - player2.width / 2) {
player2.x -= 5; // Move left
}
}
if (!player2.jumping && player2.y >= PLAYER_INITIAL_Y && ball.y < player2.y && Math.abs(ball.x - player2.x) < player2.width) {
player2.jumping = true;
}
}
function resetBall() {
ball.y = BALL_INITIAL_Y; // Set the ball's initial vertical position using BALL_INITIAL_Y
ball.speedX = 3;
ball.speedY = 3; // Reset speed
ball.accelerationY = 0.5; // Reset gravity
ball.friction = 0.99; // Reset friction
ballCanMove = false; // Reset ball movement flag
ball.rotation = 0; // Reset rotation angle
resetTime = Date.now(); // Update reset time
player1Touches = 0;
player2Touches = 0;
ball.alpha = 0;
joystick.alpha = 0.;
// Place ball in front of the serving player, near the center circle
if (servingPlayer === 1) {
ball.x = goalLeft.x + 180;
} else {
ball.x = goalRight.x - 180;
}
// Move players progressively to their initial X positions
var movePlayerToInitialX = function movePlayerToInitialX(player, initialX) {
var moveInterval = LK.setInterval(function () {
updateShadows();
if (Math.abs(player.x - initialX) < 5) {
player.x = initialX;
LK.clearInterval(moveInterval);
} else {
player.x += (initialX - player.x) * 0.1;
}
}, 16); // Move players every 16ms (approximately 60 FPS)
};
movePlayerToInitialX(player1, PLAYER1_INITIAL_X);
movePlayerToInitialX(player2, PLAYER2_INITIAL_X);
}
function customBoxCircleIntersect(box, circle) {
var circleX = circle.x;
var circleY = circle.y;
if (circle.parent) {
circleX += circle.parent.x;
circleY += circle.parent.y;
}
if (!box) {
return false;
}
var boxX = box.x;
var boxY = box.y;
var halfBoxWidth = box.width / 2;
var halfCircleWidth = circle.width / 2;
var netBuffer = 2; // Adjust netBuffer to control how far the ball bounces from the net
var left = boxX - halfBoxWidth;
var right = boxX + halfBoxWidth;
var top = boxY - box.height;
var bottom = boxY;
// Check if the circle intersects with the box (considering entire ball)
return circleX + halfCircleWidth > left && circleX - halfCircleWidth < right && circleY + halfCircleWidth > top + netBuffer && circleY - halfCircleWidth < bottom;
}
function customIntersect(circle1, circle2) {
//console.log("customIntersect ", circle1, circle2.parent);
var circle2X = circle2.x;
var circle2Y = circle2.y;
if (circle2.parent) {
circle2X += circle2.parent.x;
circle2Y += circle2.parent.y;
}
var dx = circle1.x - circle2X;
var dy = circle1.y - circle2Y;
var distance = Math.sqrt(dx * dx + dy * dy);
var radiusSum = circle1.width / 2 + circle2.width / 2;
//console.log("customIntersect ", distance.toFixed(0), radiusSum);
return distance < radiusSum;
}
var background;
gameInitialize();
game.update = function () {
if (Date.now() - resetTime < nextRoundPauseDelay) {
updateShadows();
return;
}
ball.alpha = 1;
joystick.alpha = 1;
if (!ballCanMove && (customIntersect(ball, player1.collisionBody) || customIntersect(ball, player2.collisionBody))) {
ballCanMove = true;
}
// Check for collision with the left or right goal posts (bounce off the posts, not the net)
if (customBoxCircleIntersect(goalLeft, ball)) {
// Only bounce if not already inside the goal (handled in SoccerBall.update)
if (ball.x > goalLeft.x) {
if (Date.now() - ball.lastCollisionTime > 0) {
playSound('bump', 500);
ball.speedX = Math.abs(ball.speedX) * 0.7 + (Math.random() - 0.5) * 0.2;
ball.lastCollisionTime = Date.now();
}
}
}
if (customBoxCircleIntersect(goalRight, ball)) {
if (ball.x < goalRight.x) {
if (Date.now() - ball.lastCollisionTime > 0) {
playSound('bump', 500);
ball.speedX = -Math.abs(ball.speedX) * 0.7 + (Math.random() - 0.5) * 0.2;
ball.lastCollisionTime = Date.now();
}
}
}
// Check for collisions with players
var touchIndex = 0;
if (ball.x + ball.width / 2 < 1024) {
player2Touches = 0;
} else if (ball.x - ball.width / 2 > 1024) {
player1Touches = 0;
}
if (ball.x < 1024 && customIntersect(ball, player1.collisionBody)) {
touchIndex = 1;
} else if (ball.x > 1024 && customIntersect(ball, player2.collisionBody)) {
touchIndex = 2;
}
if (touchIndex) {
playSound('bump', 500); // Play bump sound on collision with a cooldown of 0.5 seconds
// Increment touch counters
if (touchIndex === 1) {
if (Date.now() - touchTime >= 300) {
player1Touches++;
}
player2Touches = 0; // Reset opponent's touch counter
} else if (touchIndex === 2) {
if (Date.now() - touchTime >= 300) {
player2Touches++;
}
player1Touches = 0; // Reset opponent's touch counter
}
touchTime = Date.now(); // Update touchTime when a player touches the ball
// Check for touch limit
if (player1Touches >= 4) {
if (servingPlayer == 1) {
servingPlayer = 2;
} else {
updateScore(2);
}
} else if (player2Touches >= 4) {
if (servingPlayer == 2) {
servingPlayer = 1;
} else {
updateScore(1);
}
}
if (player1Touches >= 4 || player2Touches >= 4) {
playSound('whistle', 1000); // Play whistle sound
resetBall();
}
//console.log("Player collision detected 2");
var player = touchIndex === 1 ? player1 : player2;
var collisionAngle = Math.atan2(ball.y - player.y, ball.x - player.x);
var speed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY);
var playerSpeed = Math.sqrt(player.speedX * player.speedX + player.speedY * player.speedY);
var newSpeedX = Math.sign(speed * Math.cos(collisionAngle) + (playerSpeed + 0.1 * Math.sign(playerSpeed)) * Math.cos(collisionAngle)) * Math.min(Math.abs(speed * Math.cos(collisionAngle) + (playerSpeed + 0.1 * Math.sign(playerSpeed)) * Math.cos(collisionAngle)), SPEED_LIMIT);
var newSpeedY = Math.sign(speed * Math.sin(collisionAngle) + (playerSpeed + 0.1 * Math.sign(playerSpeed)) * Math.sin(collisionAngle)) * Math.min(Math.abs(speed * Math.sin(collisionAngle) + (playerSpeed + 0.1 * Math.sign(playerSpeed)) * Math.sin(collisionAngle)), SPEED_LIMIT);
// Add a bit of randomness to the ball's speed to avoid infinite stuck
ball.speedX = newSpeedX * 1.20 + (Math.random() - 0.5) * 0.05;
ball.speedY = newSpeedY * 1.20 + (Math.random() - 0.5) * 0.05;
}
ball.rotationSpeed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY) * 0.005; // Update rotation speed based on collision
aiUpdate();
if (joystickDrag) {
var dx = joystick.x - joystickBasePosition.x;
var dy = joystick.y - joystickBasePosition.y;
var movementRatio = 0.25; // Adjust this ratio to make the movement smoother
player1.x = Math.max(player1.width / 2, Math.min(player1.x + dx * movementRatio, 1024 - player1.width / 2));
player1.speedX = dx * movementRatio;
if (!player1.jumping && dy < -80 && Date.now() - resetTime >= nextRoundPauseDelay) {
player1.jumping = true;
}
//console.log("MOVE joystickDrag dx: ".concat(dx.toFixed(0), ", player1.speedX: ").concat(player1.speedX.toFixed(0), ", joystickDrag dy: ").concat(dy.toFixed(0)));
}
updateShadows();
};
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
startButton.destroy();
joystick.visible = true;
} else {
joystickDrag = true;
}
};
game.move = function (x, y, obj) {
if (Date.now() - resetTime < nextRoundPauseDelay) {
return;
}
handleJoystickLimits(x, y);
};
game.up = function (x, y, obj) {
joystickDrag = false;
//console.log("UP joystickDrag state:", joystickDrag);
joystick.x = joystickBasePosition.x;
joystick.y = joystickBasePosition.y;
};
function gameInitialize() {
background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
game.addChild(background);
initShadows();
var parasol = LK.getAsset('parasol', {
anchorX: 0.5,
anchorY: 1,
x: 1848,
y: 1450
});
game.addChild(parasol);
var chair = LK.getAsset('chair', {
anchorX: 0.5,
anchorY: 1,
x: 1948,
y: 1500
});
game.addChild(chair);
var towel = LK.getAsset('towel', {
anchorX: 0.5,
anchorY: 1,
x: 10,
y: 1540
});
game.addChild(towel);
beachBall = LK.getAsset('beachBall', {
anchorX: 0.5,
anchorY: 1,
x: 120,
y: 1465
});
game.addChild(beachBall);
player1 = new Player(1);
player2 = new Player(2);
game.addChild(player1);
game.addChild(player2);
player1.x = PLAYER1_INITIAL_X;
player1.y = PLAYER_INITIAL_Y;
player2.y = PLAYER_INITIAL_Y;
player2.x = PLAYER2_INITIAL_X;
ball = new SoccerBall();
ball.x = servingPlayer === 1 ? BALL1_INITIAL_X : BALL2_INITIAL_X;
ball.y = BALL_INITIAL_Y; // Set the ball's initial vertical position using BALL_INITIAL_Y
ball.rotationSpeed = 0;
game.addChild(ball);
scoreTxt1 = new Text2('00', {
size: 200,
fill: 0x0000D8,
fontWeight: "bold",
dropShadow: true
});
scoreTxt1.anchor.set(-1, 0);
LK.gui.topLeft.addChild(scoreTxt1);
scoreTxt2 = new Text2('00', {
size: 200,
fill: 0xFF6347,
fontWeight: "bold",
dropShadow: true
});
scoreTxt2.anchor.set(2, 0);
LK.gui.topRight.addChild(scoreTxt2);
joystick = game.addChild(LK.getAsset('joystick', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 - 330
}));
joystick.visible = false;
joystickBasePosition = {
x: joystick.x,
y: joystick.y
};
joystickBasePosition = {
x: joystick.x,
y: joystick.y
};
joystickDrag = false;
goalLeft = new Goal(1);
// Place left goal exactly on the left goal line, vertically centered
goalLeft.x = goalLeft.width / 2;
goalLeft.y = 2732 / 2;
game.addChild(goalLeft);
goalRight = new Goal(2);
// Place right goal exactly on the right goal line, vertically centered
goalRight.x = 2048 - goalRight.width / 2;
goalRight.y = 2732 / 2;
game.addChild(goalRight);
touchTime = 0; // Global variable to store the touch time
prevMouseY = null;
lastPlayedTime = {};
ballCanMove = false;
SPEED_LIMIT = 50; // Define a global speed limit
isDebug = false;
player2Debug = false;
player1Touches = 0;
player2Touches = 0;
resetTime = 0; // Global variable to store the reset time
nextRoundPauseDelay = 1600;
score1 = 0;
score2 = 0;
scoreTxt1.setText(score1.toString().padStart(2, '0'));
scoreTxt2.setText(score2.toString().padStart(2, '0'));
startButton = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
game.addChild(startButton);
}
function initShadows() {
ballShadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.33,
scaleX: 2.2,
scaleY: 0.6
});
player1Shadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.33,
scaleX: 2.7,
scaleY: 0.7
});
player2Shadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.33,
scaleX: 2.7,
scaleY: 0.7
});
var parasolShadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.33,
scaleX: 3.5,
scaleY: 0.65,
x: 1900 + 10,
y: 1445 + 10
});
var beachBallShadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.33,
scaleX: 0.75,
scaleY: 0.35,
x: 120 + 20,
y: 1465
});
ballShadow.x = BALL1_INITIAL_X;
ballShadow.y = PLAYER_INITIAL_Y;
player1Shadow.x = PLAYER1_INITIAL_X;
player1Shadow.y = PLAYER_INITIAL_Y;
player2Shadow.x = PLAYER2_INITIAL_X;
player2Shadow.y = PLAYER_INITIAL_Y;
game.addChild(parasolShadow);
game.addChild(beachBallShadow);
game.addChild(ballShadow);
game.addChild(player1Shadow);
game.addChild(player2Shadow);
}
function updateShadows() {
// Update ball shadow position and size
ballShadow.visible = ball.alpha != 0;
if (ballShadow.visible) {
ballShadow.x = ball.x;
ballShadow.scale.x = 2.2 * (1 + (ball.y - PLAYER_INITIAL_Y) / 3000);
ballShadow.scale.y = 0.6 * (1 + (ball.y - PLAYER_INITIAL_Y) / 3000);
}
// Update player1 shadow position and size
player1Shadow.x = player1.x;
player1Shadow.scale.x = 2.7 * (1 + (player1.y - PLAYER_INITIAL_Y) / 1500);
player1Shadow.scale.y = 0.7 * (1 + (player1.y - PLAYER_INITIAL_Y) / 1500);
// Update player2 shadow position and size
player2Shadow.x = player2.x;
player2Shadow.scale.x = 2.7 * (1 + (player2.y - PLAYER_INITIAL_Y) / 1500);
player2Shadow.scale.y = 0.7 * (1 + (player2.y - PLAYER_INITIAL_Y) / 1500);
} ===================================================================
--- original.js
+++ change.js
@@ -109,16 +109,22 @@
self.y = 2000 - half;
self.speedY = -Math.abs(self.speedY) * 0.7;
self.speedX *= 0.9;
playSound('whistle', 1000);
- // If ball is in the left goal area, player 2 scores
+ // If ball is in the left goal area, player 2 scores (ball hit rightwards into left goal)
if (customBoxCircleIntersect(goalLeft, self)) {
- updateScore(2);
+ // Ball must be moving leftwards (from right to left) to count as a goal for player 2
+ if (self.speedX < 0) {
+ updateScore(2);
+ }
resetBall();
}
- // If ball is in the right goal area, player 1 scores
+ // If ball is in the right goal area, player 1 scores (ball hit leftwards into right goal)
else if (customBoxCircleIntersect(goalRight, self)) {
- updateScore(1);
+ // Ball must be moving rightwards (from left to right) to count as a goal for player 1
+ if (self.speedX > 0) {
+ updateScore(1);
+ }
resetBall();
} else {
// No goal, just reset
servingPlayer = servingPlayer == 1 ? 2 : 1;
top view of a concave blue (0xADD8E6) plastic button. 4 small black directionnal chevrons engraved : right, left, top , bottom.. Photorealistic
Soccer pitch. In-Game asset. 2d. High contrast. No shadows
Soccer ball writes start in the middle. In-Game asset. 2d. High contrast. No shadows
Football goal. In-Game asset. 2d. High contrast. No shadows
Soccer ball. In-Game asset. 2d. High contrast. No shadows