User prompt
Y q la Ia solo golpee el balón hacia delante en 2vs2 y 1vs1
User prompt
Pero q tú compañero sea verde
User prompt
Q en el 2vs2 los dos contrincantes sean rojos
User prompt
Q en el 2vs2 tu compañero sea verde como tú y los otros los dos rojos
User prompt
Q en el menú los botones sean más grandes y naranjas y estén más abajo y arriba como una imagen del juego
User prompt
Añade q tenga un menú principal con dos botones uno de 1vs1 y otro de 2vs2 y si le das a 2vs2 sean encontrá dos ias y tú compañero tmb sea ia
User prompt
Q se vean las redes
User prompt
Se sigue quedando atascado y no se ven redes
User prompt
Lo de para q no se quede atascado
User prompt
Hazlo
User prompt
Pero en el medio sea una linea q haga un círculo como en un campo de fútbol no un círculo
User prompt
Q el circulo del medio sea blanco para q se vea más y q se vean las redes de la portería
User prompt
Pon los cuadrados más pequeños
User prompt
Los cuadrados solo están en un cuarto del fondo,q sean así de grandes pero en todo el fondo y q en las porterías se vea la red y q la Ia se pueda mover también hacia delante y hacia atrás porque solo se mueve a los lados y a veces se queda la pelota pillada entre la Ia y la pared
User prompt
El tamaño de los cuadrados está bien pero q no haya hueco entre ellos y hay un bug q si lo muevo muy rápido traspaso la bola y la golpeó hacia atrás
User prompt
Q los cuadrados sean más pequeños y haya más y q el circulo del medio sea como el de un campo de fútbol no un círculo malmpuesto
User prompt
Q el fondo tenga como cuadrados de verdes más oscuros y más claros q el circulo q muebo yo y el de la Ia sean más grandes,q en el medio este un círculo como el de un campo de fútbol y q la pelota en vez de ser blanca sea un balón de fútbol como este ⚽
User prompt
Q de fondo tenga el césped de un campo de fútbol y q se vea la portería,q no sea una linea
User prompt
Generate the first version of the source code of my game: Soccer Air Hockey. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Soccer Air Hockey
User prompt
Un juego como hockey de aire pero de fútbol q tengas q meter gol sin q te metan,q cada nivel sea ,mas difícil meter gol
User prompt
Please continue polishing my design document.
User prompt
Un juego como hockey de aire q tienes q meter gol sin que te metan,q tenga niveles y q en casa nivel sea más difícil meter gol
Initial prompt
Un juego como
/****
* 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 = 0;
self.velocityY = 0;
self.speed = 8;
self.maxSpeed = 15;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
// Store last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off left and right walls
if (self.x <= 40 || self.x >= 2048 - 40) {
self.velocityX = -self.velocityX;
self.x = self.x <= 40 ? 40 : 2048 - 40;
}
// Bounce off top and bottom walls (but not in goal areas)
if (self.y <= 40 && (self.x < 824 || self.x > 1224) || self.y >= 2732 - 40 && (self.x < 824 || self.x > 1224)) {
self.velocityY = -self.velocityY;
self.y = self.y <= 40 ? 40 : 2732 - 40;
}
};
self.reset = function () {
self.x = 1024;
self.y = 1366;
self.velocityX = 0;
self.velocityY = 0;
};
return self;
});
var MenuButton = Container.expand(function (text, onClick) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 60,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.onClick = onClick;
self.down = function (x, y, obj) {
if (self.onClick) {
self.onClick();
}
};
return self;
});
var Paddle = Container.expand(function (isPlayer) {
var self = Container.call(this);
var paddleGraphics = self.attachAsset(isPlayer ? 'playerPaddle' : 'aiPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.isPlayer = isPlayer;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Keep paddle in bounds
if (self.x < 80) self.x = 80;
if (self.x > 2048 - 80) self.x = 2048 - 80;
if (self.isPlayer) {
// Player paddle stays in bottom half
if (self.y < 1366 + 100) self.y = 1366 + 100;
if (self.y > 2732 - 80) self.y = 2732 - 80;
} else {
// AI paddle can move in top 2/3 of field for better positioning
if (self.y < 80) self.y = 80;
if (self.y > 1800) self.y = 1800; // Allow more forward movement
}
};
return self;
});
/****
* Initialize Game
****/
// Game variables
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
var gameMode = '1vs1'; // '1vs1' or '2vs2'
var gameState = 'menu'; // 'menu', 'playing'
// Game variables
var level = 1;
var playerScore = 0;
var aiScore = 0;
var goalsToWin = 3;
// Game objects (declared globally but created in game modes)
var ball;
var playerPaddle;
var aiPaddle;
var aiTeammate1; // For 2vs2 mode
var aiTeammate2; // For 2vs2 mode
var fieldElements = [];
var menuButtons = [];
var dragPaddle = null;
// UI elements
var levelText;
var scoreText;
var menuTitle;
// Show main menu
function showMainMenu() {
// Clear any existing field elements
clearField();
// Create menu title
menuTitle = new Text2('SOCCER GAME', {
size: 120,
fill: 0xFFFFFF
});
menuTitle.anchor.set(0.5, 0.5);
menuTitle.x = 1024;
menuTitle.y = 800;
game.addChild(menuTitle);
// Create 1vs1 button
var button1vs1 = game.addChild(new MenuButton('1 vs 1', function () {
startGame('1vs1');
}));
button1vs1.x = 1024;
button1vs1.y = 1200;
menuButtons.push(button1vs1);
// Create 2vs2 button
var button2vs2 = game.addChild(new MenuButton('2 vs 2', function () {
startGame('2vs2');
}));
button2vs2.x = 1024;
button2vs2.y = 1400;
menuButtons.push(button2vs2);
gameState = 'menu';
}
function clearField() {
// Remove all field elements
for (var i = fieldElements.length - 1; i >= 0; i--) {
fieldElements[i].destroy();
}
fieldElements = [];
// Remove menu buttons
for (var i = menuButtons.length - 1; i >= 0; i--) {
menuButtons[i].destroy();
}
menuButtons = [];
// Remove menu title
if (menuTitle) {
menuTitle.destroy();
menuTitle = null;
}
}
function createField() {
// Create checkered grass field background covering entire field
for (var row = 0; row < 43; row++) {
for (var col = 0; col < 32; col++) {
var isLight = (row + col) % 2 === 0;
var grassSquare = game.addChild(LK.getAsset(isLight ? 'grassSquareLight' : 'grassSquareDark', {
anchorX: 0,
anchorY: 0,
x: col * 64,
y: row * 64,
scaleX: 1.0,
scaleY: 1.0
}));
fieldElements.push(grassSquare);
}
}
// Create center circle line using multiple small white boxes in a circle (soccer field style)
var centerCircleRadius = 150;
var circleSegments = 60;
for (var i = 0; i < circleSegments; i++) {
var angle = i / circleSegments * Math.PI * 2;
var lineX = 1024 + Math.cos(angle) * centerCircleRadius;
var lineY = 1366 + Math.sin(angle) * centerCircleRadius;
var circleSegment = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.5,
x: lineX,
y: lineY,
scaleX: 0.01,
scaleY: 0.8,
rotation: angle + Math.PI / 2
}));
fieldElements.push(circleSegment);
}
// Create center dot
var centerDot = game.addChild(LK.getAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.2,
scaleY: 0.2
}));
fieldElements.push(centerDot);
// Create field elements
var centerLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
fieldElements.push(centerLine);
// Create top goal (AI goal)
var topGoalPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1.0,
x: 1024,
y: 80
}));
fieldElements.push(topGoalPost);
// Create top goal net with grid pattern - more visible
for (var i = 0; i < 9; i++) {
var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.0,
x: 824 + i * 44,
y: 10,
scaleX: 0.15,
scaleY: 20
}));
fieldElements.push(netLineVertical);
}
for (var j = 0; j < 5; j++) {
var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 10 + j * 18,
scaleX: 0.25,
scaleY: 4
}));
fieldElements.push(netLineHorizontal);
}
// Create bottom goal (Player goal)
var bottomGoalPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0.0,
x: 1024,
y: 2652
}));
fieldElements.push(bottomGoalPost);
// Create bottom goal net with grid pattern - more visible
for (var i = 0; i < 9; i++) {
var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 1.0,
x: 824 + i * 44,
y: 2722,
scaleX: 0.15,
scaleY: 20
}));
fieldElements.push(netLineVertical);
}
for (var j = 0; j < 5; j++) {
var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2722 - j * 18,
scaleX: 0.25,
scaleY: 4
}));
fieldElements.push(netLineHorizontal);
}
}
function startGame(mode) {
gameMode = mode;
clearField();
createField();
// Create game objects
ball = game.addChild(new Ball());
playerPaddle = game.addChild(new Paddle(true));
aiPaddle = game.addChild(new Paddle(false));
if (gameMode === '2vs2') {
// Create AI teammates
aiTeammate1 = game.addChild(new Paddle(false));
aiTeammate1.attachAsset('aiTeammate', {
anchorX: 0.5,
anchorY: 0.5
});
aiTeammate2 = game.addChild(new Paddle(true));
aiTeammate2.attachAsset('aiTeammate', {
anchorX: 0.5,
anchorY: 0.5
});
// Position teammates
aiTeammate1.x = 700; // Left side AI teammate
aiTeammate1.y = 800;
aiTeammate2.x = 1348; // Right side player teammate
aiTeammate2.y = 1900;
}
// Reset game state
level = 1;
playerScore = 0;
aiScore = 0;
// Position initial objects
ball.reset();
playerPaddle.x = 1024;
playerPaddle.y = 2200;
aiPaddle.x = 1024;
aiPaddle.y = 532;
// Create UI
levelText = new Text2('Level ' + level + ' (' + gameMode + ')', {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
scoreText = new Text2('You: ' + playerScore + ' - AI: ' + aiScore, {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 100;
LK.gui.top.addChild(scoreText);
gameState = 'playing';
}
// Touch controls
game.down = function (x, y, obj) {
if (gameState !== 'playing') return;
var distance = Math.sqrt(Math.pow(x - playerPaddle.x, 2) + Math.pow(y - playerPaddle.y, 2));
if (distance < 120) {
dragPaddle = playerPaddle;
}
};
game.move = function (x, y, obj) {
if (dragPaddle && gameState === 'playing') {
dragPaddle.x = x;
dragPaddle.y = y;
}
};
game.up = function (x, y, obj) {
dragPaddle = null;
};
function updateAI(paddle, isTeammate, position) {
var aiSpeed = 3 + (level - 1) * 0.5;
var ballTargetX = ball.x + ball.velocityX * 10;
var ballTargetY = ball.y + ball.velocityY * 5;
// Horizontal movement
if (paddle.x < ballTargetX - 20) {
paddle.x += aiSpeed;
} else if (paddle.x > ballTargetX + 20) {
paddle.x -= aiSpeed;
}
// Vertical movement based on position
if (position === 'defender') {
// Defensive AI behavior
if (ball.velocityY < 0 && ball.y < 1000) {
if (paddle.y > ballTargetY - 50 && paddle.y > 200) {
paddle.y -= aiSpeed * 0.7;
}
} else {
if (paddle.y < 400) {
paddle.y += aiSpeed * 0.5;
}
}
} else if (position === 'midfielder') {
// Midfielder AI behavior
if (paddle.y < ballTargetY - 30) {
paddle.y += aiSpeed * 0.6;
} else if (paddle.y > ballTargetY + 30) {
paddle.y -= aiSpeed * 0.6;
}
// Keep in middle area
if (paddle.y < 600) paddle.y = 600;
if (paddle.y > 1400) paddle.y = 1400;
} else if (position === 'support') {
// Support player AI behavior
if (paddle.y > ballTargetY + 30) {
paddle.y -= aiSpeed * 0.6;
} else if (paddle.y < ballTargetY - 30) {
paddle.y += aiSpeed * 0.6;
}
// Keep in player area
if (paddle.y < 1500) paddle.y = 1500;
if (paddle.y > 2500) paddle.y = 2500;
}
}
function handleBallCollision(paddle) {
var ballPaddleDistance = Math.sqrt(Math.pow(ball.x - paddle.x, 2) + Math.pow(ball.y - paddle.y, 2));
var lastBallPaddleDistance = Math.sqrt(Math.pow(ball.lastX - paddle.lastX, 2) + Math.pow(ball.lastY - paddle.lastY, 2));
var collisionRadius = 120;
if (ballPaddleDistance <= collisionRadius && lastBallPaddleDistance > collisionRadius || ball.intersects(paddle)) {
var dx = ball.x - paddle.x;
var dy = ball.y - paddle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var pushDistance = collisionRadius + 10;
var newBallX = paddle.x + dx / distance * pushDistance;
var newBallY = paddle.y + dy / distance * pushDistance;
newBallX = Math.max(40, Math.min(2048 - 40, newBallX));
newBallY = Math.max(40, Math.min(2732 - 40, newBallY));
ball.x = newBallX;
ball.y = newBallY;
var minVelocity = 3;
ball.velocityX = Math.max(Math.abs(dx / distance * ball.speed), minVelocity) * (dx > 0 ? 1 : -1);
ball.velocityY = Math.max(Math.abs(dy / distance * ball.speed), minVelocity) * (dy > 0 ? 1 : -1);
var paddleSpeedX = paddle.x - paddle.lastX;
var paddleSpeedY = paddle.y - paddle.lastY;
ball.velocityX += paddleSpeedX * 0.3;
ball.velocityY += paddleSpeedY * 0.3;
if (ball.x <= 80) ball.velocityX = Math.abs(ball.velocityX);
if (ball.x >= 2048 - 80) ball.velocityX = -Math.abs(ball.velocityX);
if (ball.y <= 80) ball.velocityY = Math.abs(ball.velocityY);
if (ball.y >= 2732 - 80) ball.velocityY = -Math.abs(ball.velocityY);
LK.getSound('hit').play();
}
}
}
game.update = function () {
if (gameState === 'menu') {
return;
}
if (gameState !== 'playing') return;
// AI Logic
updateAI(aiPaddle, false, 'defender');
if (gameMode === '2vs2') {
updateAI(aiTeammate1, true, 'midfielder');
updateAI(aiTeammate2, true, 'support');
}
// Ball collision detection
handleBallCollision(playerPaddle);
handleBallCollision(aiPaddle);
if (gameMode === '2vs2') {
handleBallCollision(aiTeammate1);
handleBallCollision(aiTeammate2);
}
// Goal detection
if (ball.y <= 20 && ball.x >= 824 && ball.x <= 1224) {
// Player scores
playerScore++;
LK.getSound('goal').play();
tween(ball, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(ball, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
checkWinCondition();
} else if (ball.y >= 2712 && ball.x >= 824 && ball.x <= 1224) {
// AI scores
aiScore++;
LK.getSound('goal').play();
tween(ball, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(ball, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
checkWinCondition();
}
// Emergency unstuck mechanism
var ballCurrentSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY);
var isNearWall = ball.x <= 100 || ball.x >= 2048 - 100 || ball.y <= 100 || ball.y >= 2732 - 100;
var paddleDistances = [Math.sqrt(Math.pow(ball.x - playerPaddle.x, 2) + Math.pow(ball.y - playerPaddle.y, 2)), Math.sqrt(Math.pow(ball.x - aiPaddle.x, 2) + Math.pow(ball.y - aiPaddle.y, 2))];
if (gameMode === '2vs2') {
paddleDistances.push(Math.sqrt(Math.pow(ball.x - aiTeammate1.x, 2) + Math.pow(ball.y - aiTeammate1.y, 2)));
paddleDistances.push(Math.sqrt(Math.pow(ball.x - aiTeammate2.x, 2) + Math.pow(ball.y - aiTeammate2.y, 2)));
}
var isNearPaddle = false;
for (var i = 0; i < paddleDistances.length; i++) {
if (paddleDistances[i] <= 140) {
isNearPaddle = true;
break;
}
}
if (ballCurrentSpeed < 2 || isNearWall && ballCurrentSpeed < 4 || isNearPaddle && ballCurrentSpeed < 3) {
var pushX = 0;
var pushY = 0;
if (ball.x <= 100) pushX = 6;
if (ball.x >= 2048 - 100) pushX = -6;
if (ball.y <= 100) pushY = 6;
if (ball.y >= 2732 - 100) pushY = -6;
// Push away from all paddles
var allPaddles = [playerPaddle, aiPaddle];
if (gameMode === '2vs2') {
allPaddles.push(aiTeammate1, aiTeammate2);
}
for (var i = 0; i < allPaddles.length; i++) {
var paddle = allPaddles[i];
var distance = Math.sqrt(Math.pow(ball.x - paddle.x, 2) + Math.pow(ball.y - paddle.y, 2));
if (distance <= 140 && distance > 0) {
pushX += (ball.x - paddle.x) / distance * 5;
pushY += (ball.y - paddle.y) / distance * 5;
}
}
if (pushX === 0 && pushY === 0) {
pushX = Math.random() > 0.5 ? 5 : -5;
pushY = Math.random() > 0.5 ? 5 : -5;
}
ball.velocityX = pushX;
ball.velocityY = pushY;
ball.x += pushX * 2;
ball.y += pushY * 2;
ball.x = Math.max(40, Math.min(2048 - 40, ball.x));
ball.y = Math.max(40, Math.min(2732 - 40, ball.y));
}
// Increase ball speed over time in current level
ball.speed = Math.min(ball.maxSpeed, 8 + (level - 1) * 1.5);
// Update score display
scoreText.setText('You: ' + playerScore + ' - AI: ' + aiScore);
};
function checkWinCondition() {
if (playerScore >= goalsToWin) {
// Player wins level
level++;
playerScore = 0;
aiScore = 0;
levelText.setText('Level ' + level + ' (' + gameMode + ')');
// Flash screen green for level completion
LK.effects.flashScreen(0x00ff00, 1000);
// Reset positions
ball.reset();
playerPaddle.x = 1024;
playerPaddle.y = 2200;
aiPaddle.x = 1024;
aiPaddle.y = 532;
if (gameMode === '2vs2') {
aiTeammate1.x = 700;
aiTeammate1.y = 800;
aiTeammate2.x = 1348;
aiTeammate2.y = 1900;
}
// Check for game completion
if (level > 10) {
LK.showYouWin();
}
} else if (aiScore >= goalsToWin) {
// AI wins - game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
} else {
// Continue playing - reset ball
LK.setTimeout(function () {
ball.reset();
}, 1000);
}
}
// Initialize game with menu
showMainMenu(); ===================================================================
--- original.js
+++ change.js
@@ -42,8 +42,28 @@
self.velocityY = 0;
};
return self;
});
+var MenuButton = Container.expand(function (text, onClick) {
+ var self = Container.call(this);
+ var buttonGraphics = self.attachAsset('menuButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ var buttonText = new Text2(text, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ buttonText.anchor.set(0.5, 0.5);
+ self.addChild(buttonText);
+ self.onClick = onClick;
+ self.down = function (x, y, obj) {
+ if (self.onClick) {
+ self.onClick();
+ }
+ };
+ return self;
+});
var Paddle = Container.expand(function (isPlayer) {
var self = Container.call(this);
var paddleGraphics = self.attachAsset(isPlayer ? 'playerPaddle' : 'aiPaddle', {
anchorX: 0.5,
@@ -81,146 +101,244 @@
/****
* Game Code
****/
+var gameMode = '1vs1'; // '1vs1' or '2vs2'
+var gameState = 'menu'; // 'menu', 'playing'
// Game variables
var level = 1;
var playerScore = 0;
var aiScore = 0;
var goalsToWin = 3;
-var gameState = 'playing';
-// Create checkered grass field background covering entire field
-var grassSquares = [];
-for (var row = 0; row < 43; row++) {
- for (var col = 0; col < 32; col++) {
- var isLight = (row + col) % 2 === 0;
- var grassSquare = game.addChild(LK.getAsset(isLight ? 'grassSquareLight' : 'grassSquareDark', {
- anchorX: 0,
- anchorY: 0,
- x: col * 64,
- y: row * 64,
- scaleX: 1.0,
- scaleY: 1.0
- }));
- grassSquares.push(grassSquare);
+// Game objects (declared globally but created in game modes)
+var ball;
+var playerPaddle;
+var aiPaddle;
+var aiTeammate1; // For 2vs2 mode
+var aiTeammate2; // For 2vs2 mode
+var fieldElements = [];
+var menuButtons = [];
+var dragPaddle = null;
+// UI elements
+var levelText;
+var scoreText;
+var menuTitle;
+// Show main menu
+function showMainMenu() {
+ // Clear any existing field elements
+ clearField();
+ // Create menu title
+ menuTitle = new Text2('SOCCER GAME', {
+ size: 120,
+ fill: 0xFFFFFF
+ });
+ menuTitle.anchor.set(0.5, 0.5);
+ menuTitle.x = 1024;
+ menuTitle.y = 800;
+ game.addChild(menuTitle);
+ // Create 1vs1 button
+ var button1vs1 = game.addChild(new MenuButton('1 vs 1', function () {
+ startGame('1vs1');
+ }));
+ button1vs1.x = 1024;
+ button1vs1.y = 1200;
+ menuButtons.push(button1vs1);
+ // Create 2vs2 button
+ var button2vs2 = game.addChild(new MenuButton('2 vs 2', function () {
+ startGame('2vs2');
+ }));
+ button2vs2.x = 1024;
+ button2vs2.y = 1400;
+ menuButtons.push(button2vs2);
+ gameState = 'menu';
+}
+function clearField() {
+ // Remove all field elements
+ for (var i = fieldElements.length - 1; i >= 0; i--) {
+ fieldElements[i].destroy();
}
+ fieldElements = [];
+ // Remove menu buttons
+ for (var i = menuButtons.length - 1; i >= 0; i--) {
+ menuButtons[i].destroy();
+ }
+ menuButtons = [];
+ // Remove menu title
+ if (menuTitle) {
+ menuTitle.destroy();
+ menuTitle = null;
+ }
}
-// Create center circle line using multiple small white boxes in a circle (soccer field style)
-var centerCircleRadius = 150;
-var circleSegments = 60;
-for (var i = 0; i < circleSegments; i++) {
- var angle = i / circleSegments * Math.PI * 2;
- var lineX = 1024 + Math.cos(angle) * centerCircleRadius;
- var lineY = 1366 + Math.sin(angle) * centerCircleRadius;
- var circleSegment = game.addChild(LK.getAsset('fieldLine', {
+function createField() {
+ // Create checkered grass field background covering entire field
+ for (var row = 0; row < 43; row++) {
+ for (var col = 0; col < 32; col++) {
+ var isLight = (row + col) % 2 === 0;
+ var grassSquare = game.addChild(LK.getAsset(isLight ? 'grassSquareLight' : 'grassSquareDark', {
+ anchorX: 0,
+ anchorY: 0,
+ x: col * 64,
+ y: row * 64,
+ scaleX: 1.0,
+ scaleY: 1.0
+ }));
+ fieldElements.push(grassSquare);
+ }
+ }
+ // Create center circle line using multiple small white boxes in a circle (soccer field style)
+ var centerCircleRadius = 150;
+ var circleSegments = 60;
+ for (var i = 0; i < circleSegments; i++) {
+ var angle = i / circleSegments * Math.PI * 2;
+ var lineX = 1024 + Math.cos(angle) * centerCircleRadius;
+ var lineY = 1366 + Math.sin(angle) * centerCircleRadius;
+ var circleSegment = game.addChild(LK.getAsset('fieldLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: lineX,
+ y: lineY,
+ scaleX: 0.01,
+ scaleY: 0.8,
+ rotation: angle + Math.PI / 2
+ }));
+ fieldElements.push(circleSegment);
+ }
+ // Create center dot
+ var centerDot = game.addChild(LK.getAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
- x: lineX,
- y: lineY,
- scaleX: 0.01,
- scaleY: 0.8,
- rotation: angle + Math.PI / 2
+ x: 1024,
+ y: 1366,
+ scaleX: 0.2,
+ scaleY: 0.2
}));
-}
-// Create center dot
-var centerDot = game.addChild(LK.getAsset('ball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 0.2,
- scaleY: 0.2
-}));
-// Create field elements
-var centerLine = game.addChild(LK.getAsset('fieldLine', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366
-}));
-// Create top goal (AI goal)
-var topGoalPost = game.addChild(LK.getAsset('goalPost', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1024,
- y: 80
-}));
-// Create top goal net with grid pattern - more visible
-for (var i = 0; i < 9; i++) {
- var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
+ fieldElements.push(centerDot);
+ // Create field elements
+ var centerLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
- anchorY: 0.0,
- x: 824 + i * 44,
- y: 10,
- scaleX: 0.15,
- scaleY: 20
- }));
-}
-for (var j = 0; j < 5; j++) {
- var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
- anchorX: 0.5,
anchorY: 0.5,
x: 1024,
- y: 10 + j * 18,
- scaleX: 0.25,
- scaleY: 4
+ y: 1366
}));
-}
-// Create bottom goal (Player goal)
-var bottomGoalPost = game.addChild(LK.getAsset('goalPost', {
- anchorX: 0.5,
- anchorY: 0.0,
- x: 1024,
- y: 2652
-}));
-// Create bottom goal net with grid pattern - more visible
-for (var i = 0; i < 9; i++) {
- var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
+ fieldElements.push(centerLine);
+ // Create top goal (AI goal)
+ var topGoalPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1.0,
- x: 824 + i * 44,
- y: 2722,
- scaleX: 0.15,
- scaleY: 20
+ x: 1024,
+ y: 80
}));
-}
-for (var j = 0; j < 5; j++) {
- var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
+ fieldElements.push(topGoalPost);
+ // Create top goal net with grid pattern - more visible
+ for (var i = 0; i < 9; i++) {
+ var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
+ anchorX: 0.5,
+ anchorY: 0.0,
+ x: 824 + i * 44,
+ y: 10,
+ scaleX: 0.15,
+ scaleY: 20
+ }));
+ fieldElements.push(netLineVertical);
+ }
+ for (var j = 0; j < 5; j++) {
+ var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1024,
+ y: 10 + j * 18,
+ scaleX: 0.25,
+ scaleY: 4
+ }));
+ fieldElements.push(netLineHorizontal);
+ }
+ // Create bottom goal (Player goal)
+ var bottomGoalPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
- anchorY: 0.5,
+ anchorY: 0.0,
x: 1024,
- y: 2722 - j * 18,
- scaleX: 0.25,
- scaleY: 4
+ y: 2652
}));
+ fieldElements.push(bottomGoalPost);
+ // Create bottom goal net with grid pattern - more visible
+ for (var i = 0; i < 9; i++) {
+ var netLineVertical = game.addChild(LK.getAsset('fieldLine', {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ x: 824 + i * 44,
+ y: 2722,
+ scaleX: 0.15,
+ scaleY: 20
+ }));
+ fieldElements.push(netLineVertical);
+ }
+ for (var j = 0; j < 5; j++) {
+ var netLineHorizontal = game.addChild(LK.getAsset('fieldLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1024,
+ y: 2722 - j * 18,
+ scaleX: 0.25,
+ scaleY: 4
+ }));
+ fieldElements.push(netLineHorizontal);
+ }
}
-// Create game objects
-var ball = game.addChild(new Ball());
-var playerPaddle = game.addChild(new Paddle(true));
-var aiPaddle = game.addChild(new Paddle(false));
-// Position initial objects
-ball.reset();
-playerPaddle.x = 1024;
-playerPaddle.y = 2200;
-aiPaddle.x = 1024;
-aiPaddle.y = 532;
-// Create UI
-var levelText = new Text2('Level ' + level, {
- size: 80,
- fill: 0xFFFFFF
-});
-levelText.anchor.set(0.5, 0);
-LK.gui.top.addChild(levelText);
-var scoreText = new Text2('You: ' + playerScore + ' - AI: ' + aiScore, {
- size: 60,
- fill: 0xFFFFFF
-});
-scoreText.anchor.set(0.5, 0);
-scoreText.y = 100;
-LK.gui.top.addChild(scoreText);
+function startGame(mode) {
+ gameMode = mode;
+ clearField();
+ createField();
+ // Create game objects
+ ball = game.addChild(new Ball());
+ playerPaddle = game.addChild(new Paddle(true));
+ aiPaddle = game.addChild(new Paddle(false));
+ if (gameMode === '2vs2') {
+ // Create AI teammates
+ aiTeammate1 = game.addChild(new Paddle(false));
+ aiTeammate1.attachAsset('aiTeammate', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ aiTeammate2 = game.addChild(new Paddle(true));
+ aiTeammate2.attachAsset('aiTeammate', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Position teammates
+ aiTeammate1.x = 700; // Left side AI teammate
+ aiTeammate1.y = 800;
+ aiTeammate2.x = 1348; // Right side player teammate
+ aiTeammate2.y = 1900;
+ }
+ // Reset game state
+ level = 1;
+ playerScore = 0;
+ aiScore = 0;
+ // Position initial objects
+ ball.reset();
+ playerPaddle.x = 1024;
+ playerPaddle.y = 2200;
+ aiPaddle.x = 1024;
+ aiPaddle.y = 532;
+ // Create UI
+ levelText = new Text2('Level ' + level + ' (' + gameMode + ')', {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ levelText.anchor.set(0.5, 0);
+ LK.gui.top.addChild(levelText);
+ scoreText = new Text2('You: ' + playerScore + ' - AI: ' + aiScore, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ scoreText.anchor.set(0.5, 0);
+ scoreText.y = 100;
+ LK.gui.top.addChild(scoreText);
+ gameState = 'playing';
+}
// Touch controls
-var dragPaddle = null;
game.down = function (x, y, obj) {
+ if (gameState !== 'playing') return;
var distance = Math.sqrt(Math.pow(x - playerPaddle.x, 2) + Math.pow(y - playerPaddle.y, 2));
if (distance < 120) {
dragPaddle = playerPaddle;
}
@@ -233,98 +351,101 @@
};
game.up = function (x, y, obj) {
dragPaddle = null;
};
-game.update = function () {
- if (gameState !== 'playing') return;
- // AI Logic - track ball with increasing difficulty and forward/backward movement
+function updateAI(paddle, isTeammate, position) {
var aiSpeed = 3 + (level - 1) * 0.5;
- var ballTargetX = ball.x + ball.velocityX * 10; // Predict ball position
- var ballTargetY = ball.y + ball.velocityY * 5; // Predict ball Y position
+ var ballTargetX = ball.x + ball.velocityX * 10;
+ var ballTargetY = ball.y + ball.velocityY * 5;
// Horizontal movement
- if (aiPaddle.x < ballTargetX - 20) {
- aiPaddle.x += aiSpeed;
- } else if (aiPaddle.x > ballTargetX + 20) {
- aiPaddle.x -= aiSpeed;
+ if (paddle.x < ballTargetX - 20) {
+ paddle.x += aiSpeed;
+ } else if (paddle.x > ballTargetX + 20) {
+ paddle.x -= aiSpeed;
}
- // Vertical movement - defensive positioning
- if (ball.velocityY < 0 && ball.y < 1000) {
- // Ball coming towards AI
- if (aiPaddle.y > ballTargetY - 50 && aiPaddle.y > 200) {
- aiPaddle.y -= aiSpeed * 0.7; // Move forward to intercept
+ // Vertical movement based on position
+ if (position === 'defender') {
+ // Defensive AI behavior
+ if (ball.velocityY < 0 && ball.y < 1000) {
+ if (paddle.y > ballTargetY - 50 && paddle.y > 200) {
+ paddle.y -= aiSpeed * 0.7;
+ }
+ } else {
+ if (paddle.y < 400) {
+ paddle.y += aiSpeed * 0.5;
+ }
}
- } else {
- // Ball moving away or stationary
- if (aiPaddle.y < 400) {
- // Return to defensive position
- aiPaddle.y += aiSpeed * 0.5;
+ } else if (position === 'midfielder') {
+ // Midfielder AI behavior
+ if (paddle.y < ballTargetY - 30) {
+ paddle.y += aiSpeed * 0.6;
+ } else if (paddle.y > ballTargetY + 30) {
+ paddle.y -= aiSpeed * 0.6;
}
+ // Keep in middle area
+ if (paddle.y < 600) paddle.y = 600;
+ if (paddle.y > 1400) paddle.y = 1400;
+ } else if (position === 'support') {
+ // Support player AI behavior
+ if (paddle.y > ballTargetY + 30) {
+ paddle.y -= aiSpeed * 0.6;
+ } else if (paddle.y < ballTargetY - 30) {
+ paddle.y += aiSpeed * 0.6;
+ }
+ // Keep in player area
+ if (paddle.y < 1500) paddle.y = 1500;
+ if (paddle.y > 2500) paddle.y = 2500;
}
- // Ball collision with player paddle - improved collision detection
- var ballPaddleDistance = Math.sqrt(Math.pow(ball.x - playerPaddle.x, 2) + Math.pow(ball.y - playerPaddle.y, 2));
- var lastBallPaddleDistance = Math.sqrt(Math.pow(ball.lastX - playerPaddle.lastX, 2) + Math.pow(ball.lastY - playerPaddle.lastY, 2));
- var collisionRadius = 120; // Combined radius of ball and paddle
- if (ballPaddleDistance <= collisionRadius && lastBallPaddleDistance > collisionRadius || ball.intersects(playerPaddle)) {
- var dx = ball.x - playerPaddle.x;
- var dy = ball.y - playerPaddle.y;
+}
+function handleBallCollision(paddle) {
+ var ballPaddleDistance = Math.sqrt(Math.pow(ball.x - paddle.x, 2) + Math.pow(ball.y - paddle.y, 2));
+ var lastBallPaddleDistance = Math.sqrt(Math.pow(ball.lastX - paddle.lastX, 2) + Math.pow(ball.lastY - paddle.lastY, 2));
+ var collisionRadius = 120;
+ if (ballPaddleDistance <= collisionRadius && lastBallPaddleDistance > collisionRadius || ball.intersects(paddle)) {
+ var dx = ball.x - paddle.x;
+ var dy = ball.y - paddle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
- // Push ball away from paddle to prevent sticking
var pushDistance = collisionRadius + 10;
- var newBallX = playerPaddle.x + dx / distance * pushDistance;
- var newBallY = playerPaddle.y + dy / distance * pushDistance;
- // Ensure ball stays within field bounds
+ var newBallX = paddle.x + dx / distance * pushDistance;
+ var newBallY = paddle.y + dy / distance * pushDistance;
newBallX = Math.max(40, Math.min(2048 - 40, newBallX));
newBallY = Math.max(40, Math.min(2732 - 40, newBallY));
ball.x = newBallX;
ball.y = newBallY;
- // Calculate new velocity with minimum speed to prevent sticking
- var minVelocity = 3; // Minimum velocity to prevent getting stuck
+ var minVelocity = 3;
ball.velocityX = Math.max(Math.abs(dx / distance * ball.speed), minVelocity) * (dx > 0 ? 1 : -1);
ball.velocityY = Math.max(Math.abs(dy / distance * ball.speed), minVelocity) * (dy > 0 ? 1 : -1);
- // Add paddle momentum
- var paddleSpeedX = playerPaddle.x - playerPaddle.lastX;
- var paddleSpeedY = playerPaddle.y - playerPaddle.lastY;
+ var paddleSpeedX = paddle.x - paddle.lastX;
+ var paddleSpeedY = paddle.y - paddle.lastY;
ball.velocityX += paddleSpeedX * 0.3;
ball.velocityY += paddleSpeedY * 0.3;
- // If ball is near walls, ensure it bounces away
if (ball.x <= 80) ball.velocityX = Math.abs(ball.velocityX);
if (ball.x >= 2048 - 80) ball.velocityX = -Math.abs(ball.velocityX);
if (ball.y <= 80) ball.velocityY = Math.abs(ball.velocityY);
if (ball.y >= 2732 - 80) ball.velocityY = -Math.abs(ball.velocityY);
LK.getSound('hit').play();
}
}
- // Ball collision with AI paddle - improved collision detection
- var ballAIPaddleDistance = Math.sqrt(Math.pow(ball.x - aiPaddle.x, 2) + Math.pow(ball.y - aiPaddle.y, 2));
- var lastBallAIPaddleDistance = Math.sqrt(Math.pow(ball.lastX - aiPaddle.lastX, 2) + Math.pow(ball.lastY - aiPaddle.lastY, 2));
- var collisionRadius = 120; // Combined radius of ball and paddle
- if (ballAIPaddleDistance <= collisionRadius && lastBallAIPaddleDistance > collisionRadius || ball.intersects(aiPaddle)) {
- var dx = ball.x - aiPaddle.x;
- var dy = ball.y - aiPaddle.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance > 0) {
- // Push ball away from paddle to prevent sticking
- var pushDistance = collisionRadius + 10;
- var newBallX = aiPaddle.x + dx / distance * pushDistance;
- var newBallY = aiPaddle.y + dy / distance * pushDistance;
- // Ensure ball stays within field bounds
- newBallX = Math.max(40, Math.min(2048 - 40, newBallX));
- newBallY = Math.max(40, Math.min(2732 - 40, newBallY));
- ball.x = newBallX;
- ball.y = newBallY;
- // Calculate new velocity with minimum speed to prevent sticking
- var minVelocity = 3; // Minimum velocity to prevent getting stuck
- ball.velocityX = Math.max(Math.abs(dx / distance * ball.speed), minVelocity) * (dx > 0 ? 1 : -1);
- ball.velocityY = Math.max(Math.abs(dy / distance * ball.speed), minVelocity) * (dy > 0 ? 1 : -1);
- // If ball is near walls, ensure it bounces away
- if (ball.x <= 80) ball.velocityX = Math.abs(ball.velocityX);
- if (ball.x >= 2048 - 80) ball.velocityX = -Math.abs(ball.velocityX);
- if (ball.y <= 80) ball.velocityY = Math.abs(ball.velocityY);
- if (ball.y >= 2732 - 80) ball.velocityY = -Math.abs(ball.velocityY);
- LK.getSound('hit').play();
- }
+}
+game.update = function () {
+ if (gameState === 'menu') {
+ return;
}
+ if (gameState !== 'playing') return;
+ // AI Logic
+ updateAI(aiPaddle, false, 'defender');
+ if (gameMode === '2vs2') {
+ updateAI(aiTeammate1, true, 'midfielder');
+ updateAI(aiTeammate2, true, 'support');
+ }
+ // Ball collision detection
+ handleBallCollision(playerPaddle);
+ handleBallCollision(aiPaddle);
+ if (gameMode === '2vs2') {
+ handleBallCollision(aiTeammate1);
+ handleBallCollision(aiTeammate2);
+ }
// Goal detection
if (ball.y <= 20 && ball.x >= 824 && ball.x <= 1224) {
// Player scores
playerScore++;
@@ -363,41 +484,51 @@
}
});
checkWinCondition();
}
- // Emergency unstuck mechanism - detect if ball is moving too slowly or stuck in corners
+ // Emergency unstuck mechanism
var ballCurrentSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY);
var isNearWall = ball.x <= 100 || ball.x >= 2048 - 100 || ball.y <= 100 || ball.y >= 2732 - 100;
- var isNearPaddle = ballPaddleDistance <= 140 || ballAIPaddleDistance <= 140;
+ var paddleDistances = [Math.sqrt(Math.pow(ball.x - playerPaddle.x, 2) + Math.pow(ball.y - playerPaddle.y, 2)), Math.sqrt(Math.pow(ball.x - aiPaddle.x, 2) + Math.pow(ball.y - aiPaddle.y, 2))];
+ if (gameMode === '2vs2') {
+ paddleDistances.push(Math.sqrt(Math.pow(ball.x - aiTeammate1.x, 2) + Math.pow(ball.y - aiTeammate1.y, 2)));
+ paddleDistances.push(Math.sqrt(Math.pow(ball.x - aiTeammate2.x, 2) + Math.pow(ball.y - aiTeammate2.y, 2)));
+ }
+ var isNearPaddle = false;
+ for (var i = 0; i < paddleDistances.length; i++) {
+ if (paddleDistances[i] <= 140) {
+ isNearPaddle = true;
+ break;
+ }
+ }
if (ballCurrentSpeed < 2 || isNearWall && ballCurrentSpeed < 4 || isNearPaddle && ballCurrentSpeed < 3) {
- // Ball is stuck or moving too slowly, give it a strong push away from obstacles
var pushX = 0;
var pushY = 0;
- // Push away from walls
if (ball.x <= 100) pushX = 6;
if (ball.x >= 2048 - 100) pushX = -6;
if (ball.y <= 100) pushY = 6;
if (ball.y >= 2732 - 100) pushY = -6;
- // Push away from paddles
- if (ballPaddleDistance <= 140) {
- pushX += (ball.x - playerPaddle.x) / ballPaddleDistance * 5;
- pushY += (ball.y - playerPaddle.y) / ballPaddleDistance * 5;
+ // Push away from all paddles
+ var allPaddles = [playerPaddle, aiPaddle];
+ if (gameMode === '2vs2') {
+ allPaddles.push(aiTeammate1, aiTeammate2);
}
- if (ballAIPaddleDistance <= 140) {
- pushX += (ball.x - aiPaddle.x) / ballAIPaddleDistance * 5;
- pushY += (ball.y - aiPaddle.y) / ballAIPaddleDistance * 5;
+ for (var i = 0; i < allPaddles.length; i++) {
+ var paddle = allPaddles[i];
+ var distance = Math.sqrt(Math.pow(ball.x - paddle.x, 2) + Math.pow(ball.y - paddle.y, 2));
+ if (distance <= 140 && distance > 0) {
+ pushX += (ball.x - paddle.x) / distance * 5;
+ pushY += (ball.y - paddle.y) / distance * 5;
+ }
}
- // If no specific direction, give random push
if (pushX === 0 && pushY === 0) {
pushX = Math.random() > 0.5 ? 5 : -5;
pushY = Math.random() > 0.5 ? 5 : -5;
}
ball.velocityX = pushX;
ball.velocityY = pushY;
- // Move ball slightly away from collision point
ball.x += pushX * 2;
ball.y += pushY * 2;
- // Keep ball in bounds
ball.x = Math.max(40, Math.min(2048 - 40, ball.x));
ball.y = Math.max(40, Math.min(2732 - 40, ball.y));
}
// Increase ball speed over time in current level
@@ -410,17 +541,23 @@
// Player wins level
level++;
playerScore = 0;
aiScore = 0;
- levelText.setText('Level ' + level);
+ levelText.setText('Level ' + level + ' (' + gameMode + ')');
// Flash screen green for level completion
LK.effects.flashScreen(0x00ff00, 1000);
// Reset positions
ball.reset();
playerPaddle.x = 1024;
playerPaddle.y = 2200;
aiPaddle.x = 1024;
aiPaddle.y = 532;
+ if (gameMode === '2vs2') {
+ aiTeammate1.x = 700;
+ aiTeammate1.y = 800;
+ aiTeammate2.x = 1348;
+ aiTeammate2.y = 1900;
+ }
// Check for game completion
if (level > 10) {
LK.showYouWin();
}
@@ -433,5 +570,7 @@
LK.setTimeout(function () {
ball.reset();
}, 1000);
}
-}
\ No newline at end of file
+}
+// Initialize game with menu
+showMainMenu();
\ No newline at end of file