/**** * Classes ****/ //<Assets used in the game will automatically appear here> // Ball class var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.speedY = 4.0; self.speedX = 0; self.update = function () { self.y += self.speedY; self.x += self.speedX; if (self.y <= 50 || self.y >= 2682) { self.speedY *= -1; LK.getSound('ballsound').play(); } if (self.x <= 150 || self.x >= 1898) { self.speedX *= -1; LK.getSound('ballsound').play(); if ((self.y <= 200 || self.y >= 2532) && (lastCornerHit === null || Date.now() - lastCornerHit > 1000)) { cornerHits++; lastCornerHit = Date.now(); if (cornerHits >= 3) { opponentPaddle.y -= 50; // Move opponent closer to iceGateTop cornerHits = 0; // Reset counter } } } // Removed redundant check for ball going out sideways if (self.y >= 2732 || self.y <= 0) { self.speedY *= -1; // Bounce back vertically LK.getSound('ballsound').play(); } else if (self.speedX === 0 && self.speedY === 0) { // If the ball stops, move the paddle to iceGateTop and push the ball paddle.y = topGoal.y + 50; // Move paddle to iceGateTop self.speedY = 4; // Push the ball away } // Removed redundant check for ball going out sideways if (self.y >= 2732) { self.speedY *= -1; } // Removed redundant check for ball going out sideways if (self.y >= 2732) { self.speedY *= -1; } // Removed redundant check for ball going out sideways if (self.y >= 2732) { self.speedY *= -1; } // Removed redundant check for ball going out sideways if (self.y >= 2732) { self.speedY *= -1; } if (self.x <= 0 || self.x >= 2048) { self.speedX *= -1; // Bounce back horizontally } if (self.y >= 2732) { self.speedY *= -1; } if (self.x <= 0 || self.x >= 2048) { self.speedX *= -1; } if (self.x <= 0 || self.x >= 2048) { self.speedX *= -1; } // Check for collision with player paddle if (self.intersects(paddle)) { LK.getSound('paddles').play(); // Calculate the angle of incidence based on where the ball hits the paddle var relativeIntersectX = (paddle.x - self.x) / (paddle.width / 2); var bounceAngle = relativeIntersectX * Math.PI / 4; // Max bounce angle of 45 degrees // Calculate paddle movement speed var paddleSpeed = Math.sqrt(Math.pow(paddle.x - paddle.prevX, 2) + Math.pow(paddle.y - paddle.prevY, 2)); // Update ball speed and direction, adding paddle speed influence self.speedX = self.speedY * Math.sin(bounceAngle) + paddleSpeed * 0.2; // Increase influence factor self.speedY = -Math.abs(self.speedY * Math.cos(bounceAngle)) - paddleSpeed * 0.1; // Add vertical influence self.speedX = self.speedX === 0 ? 1 : self.speedX; // Ensure non-zero speed self.speedY = self.speedY === 0 ? 1 : self.speedY; // Ensure non-zero speed } // Check for collision with opponent paddle if (self.intersects(opponentPaddle)) { LK.getSound('paddles').play(); // Calculate the angle of incidence based on where the ball hits the paddle var relativeIntersectX = (opponentPaddle.x - self.x) / (opponentPaddle.width / 2); var bounceAngle = relativeIntersectX * Math.PI / 4; // Max bounce angle of 45 degrees // Update ball speed and direction self.speedX = self.speedY * Math.sin(bounceAngle); self.speedY = Math.abs(self.speedY * Math.cos(bounceAngle)); self.speedX = self.speedX === 0 ? 1 : self.speedX; // Ensure non-zero speed self.speedY = self.speedY === 0 ? 1 : self.speedY; // Ensure non-zero speed } }; }); var IceGate = Container.expand(function (color) { var self = Container.call(this); var gateGraphics = self.attachAsset(color === 'top' ? 'iceGateTop' : 'iceGateBottom', { anchorX: 0.5, anchorY: 0.5 }); }); // Opponent Paddle class var OpponentPaddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('playerPaddle', { anchorX: 0.5, anchorY: 0.5 }); self.idleTime = 0; self.update = function () { if (self.prevX === self.x && self.prevY === self.y) { self.idleTime += 1 / 60; // Increment idle time by 1/60th of a second } else { self.idleTime = 0; // Reset idle time if paddle has moved } self.prevX = self.x; self.prevY = self.y; if (self.idleTime > 1) { // Retreat towards the center of the track if (self.x < 2048 / 2) { self.x += 5; } else if (self.x > 2048 / 2) { self.x -= 5; } if (self.y < 1366 / 2) { self.y += 5; } else if (self.y > 1366 / 2) { self.y -= 5; } } // Opponent paddle AI logic with adjusted target var targetY = ball.y - 100; // Aim closer to the ball for more aggressive tracking var targetX = ball.x; // Move vertically towards the target position with increased speed self.y += (targetY - self.y) * 0.2; // Increase speed for more aggressive movement // Move horizontally towards the target position with increased speed self.x += (targetX - self.x) * 0.2; // Increase speed for more aggressive movement // Removed opponent paddle intersection logic to prevent blocking the ball // Check if ball is in the corner of the field if (ball.x <= 200 && ball.y <= 200 || ball.x >= 1848 && ball.y <= 200) { // Pull opponent paddle towards its own goal if (self.y < 200) { self.y += 5; } } // Apply damping to reduce jitter self.y = Math.max(200 + self.height / 2, Math.min(self.y, 1366 - 200 - self.height / 2)); self.x = Math.max(200 + self.width / 2, Math.min(self.x, 2048 - 200 - self.width / 2)); self.y *= 0.95; // Apply damping to vertical movement self.x *= 0.95; // Apply damping to horizontal movement // Ensure opponent paddle does not overlap with the ball if (self.intersects(ball)) { if (self.y < ball.y) { self.y = ball.y - self.height - 1; // Add a small buffer to prevent squeezing } else { self.y = ball.y + ball.height + 1; // Add a small buffer to prevent squeezing } } // Prevent overlap with player paddle if (self.intersects(paddle)) { if (self.y < paddle.y) { self.y = paddle.y - self.height; } else { self.y = paddle.y + paddle.height; } } // Ensure opponent paddle stays within the screen bounds if (self.y < 200) { self.y = 200; } }; }); // Paddle class var Paddle = Container.expand(function () { var self = Container.call(this); var paddleGraphics = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Store previous position self.prevX = self.x; self.prevY = self.y; // Ensure player paddle does not overlap with opponent paddle if (self.intersects(opponentPaddle)) { if (self.y < opponentPaddle.y) { self.y = opponentPaddle.y - self.height; } else { self.y = opponentPaddle.y + opponentPaddle.height; } } // Ensure the paddle stays within the screen bounds self.y = Math.max(self.height / 2, Math.min(self.y, 2732 - self.height / 2)); self.x = Math.max(self.width / 2, Math.min(self.x, 2048 - self.width / 2)); // Ensure player paddle does not overlap with the ball if (self.intersects(ball)) { if (self.y < ball.y) { self.y = ball.y - self.height - 1; // Add a small buffer to prevent squeezing } else { self.y = ball.y + ball.height + 1; // Add a small buffer to prevent squeezing } } }; }); var ResetButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('resetButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { ball.x = 2048 / 2; ball.y = 1366; ball.speedX = 0; ball.speedY = 4.0; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000, //Init game with black background scaleMode: 'fullScreen' // Enable full screen scaling for smartphones }); /**** * Game Code ****/ // Attach white background asset var cornerHits = 0; var lastCornerHit = null; var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 2048 / 2000, // Scale to fit the screen width scaleY: 2732 / 2730.54, // Scale to fit the screen height x: 2048 / 2, y: 2732 / 2 }); game.addChild(background); // Initialize ice hockey goals var topGoal = game.addChild(new IceGate('top')); topGoal.x = 2048 / 2 - 10; topGoal.y = 50 - 45; var bottomGoal = game.addChild(new IceGate('bottom')); bottomGoal.x = 2048 / 2 - 10; bottomGoal.y = 2732 - 50 + 40; // Initialize ball and paddles var ball = game.addChild(new Ball()); ball.x = 2048 / 2; ball.y = 1366; // Center of the field var paddle = game.addChild(new Paddle()); paddle.x = 2048 / 2; paddle.y = 2500 + 500; var opponentPaddle = game.addChild(new OpponentPaddle()); opponentPaddle.prevX = opponentPaddle.x; opponentPaddle.prevY = opponentPaddle.y; opponentPaddle.x = 2048 / 2; opponentPaddle.y = 200; opponentPaddle.x = 2048 / 2; // Score display var playerScore = 0; var opponentScore = 0; var scoreTxt = new Text2('0-0', { size: 150, fill: "#39FF14" // Neon green color }); scoreTxt.anchor.set(0.5, 0.5); scoreTxt.rotation = -Math.PI / 2; // Rotate 180 degrees to the left scoreTxt.x = 2048 - 100; // Position 100 units from the right edge of the screen scoreTxt.y = 1366 - 25; // Move up by 25 units game.addChild(scoreTxt); // Add reset button to the game var resetButton = game.addChild(new ResetButton()); resetButton.x = 2048 - resetButton.width / 2; resetButton.y = 2732 - resetButton.height / 2; // Handle paddle movement game.move = function (x, y, obj) { paddle.x = x; paddle.y = y; }; // Update game logic game.update = function () { ball.update(); paddle.update(); opponentPaddle.update(); // Check for collision between ball and iceGateTop if (ball.intersects(topGoal)) { playerScore++; scoreTxt.setText(playerScore + '-' + opponentScore); LK.getSound('scoreSound').play(); LK.getSound('scoreSound').play(); LK.getSound('scoreSound').play(); ball.x = 2048 / 2; ball.y = 1366; // Center of the field ball.speedX = 0; // Reset horizontal speed ball.speedY = 4.0; // Reset vertical speed } // Check if ball hits the bottom of the screen if (ball.y >= 2732 || ball.y <= 0) {} // Check for collision between ball and iceGateBottom if (ball.intersects(bottomGoal)) { opponentScore++; scoreTxt.setText(playerScore + '-' + opponentScore); LK.getSound('scoreSound').play(); ball.x = 2048 / 2; ball.y = 1366; // Center of the field ball.speedX = 0; ball.speedY = 4.0; cornerHits = 0; // Reset cornerHits counter lastCornerHit = null; // Reset lastCornerHit timestamp } };
/****
* Classes
****/
//<Assets used in the game will automatically appear here>
// Ball class
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedY = 4.0;
self.speedX = 0;
self.update = function () {
self.y += self.speedY;
self.x += self.speedX;
if (self.y <= 50 || self.y >= 2682) {
self.speedY *= -1;
LK.getSound('ballsound').play();
}
if (self.x <= 150 || self.x >= 1898) {
self.speedX *= -1;
LK.getSound('ballsound').play();
if ((self.y <= 200 || self.y >= 2532) && (lastCornerHit === null || Date.now() - lastCornerHit > 1000)) {
cornerHits++;
lastCornerHit = Date.now();
if (cornerHits >= 3) {
opponentPaddle.y -= 50; // Move opponent closer to iceGateTop
cornerHits = 0; // Reset counter
}
}
}
// Removed redundant check for ball going out sideways
if (self.y >= 2732 || self.y <= 0) {
self.speedY *= -1; // Bounce back vertically
LK.getSound('ballsound').play();
} else if (self.speedX === 0 && self.speedY === 0) {
// If the ball stops, move the paddle to iceGateTop and push the ball
paddle.y = topGoal.y + 50; // Move paddle to iceGateTop
self.speedY = 4; // Push the ball away
}
// Removed redundant check for ball going out sideways
if (self.y >= 2732) {
self.speedY *= -1;
}
// Removed redundant check for ball going out sideways
if (self.y >= 2732) {
self.speedY *= -1;
}
// Removed redundant check for ball going out sideways
if (self.y >= 2732) {
self.speedY *= -1;
}
// Removed redundant check for ball going out sideways
if (self.y >= 2732) {
self.speedY *= -1;
}
if (self.x <= 0 || self.x >= 2048) {
self.speedX *= -1; // Bounce back horizontally
}
if (self.y >= 2732) {
self.speedY *= -1;
}
if (self.x <= 0 || self.x >= 2048) {
self.speedX *= -1;
}
if (self.x <= 0 || self.x >= 2048) {
self.speedX *= -1;
}
// Check for collision with player paddle
if (self.intersects(paddle)) {
LK.getSound('paddles').play();
// Calculate the angle of incidence based on where the ball hits the paddle
var relativeIntersectX = (paddle.x - self.x) / (paddle.width / 2);
var bounceAngle = relativeIntersectX * Math.PI / 4; // Max bounce angle of 45 degrees
// Calculate paddle movement speed
var paddleSpeed = Math.sqrt(Math.pow(paddle.x - paddle.prevX, 2) + Math.pow(paddle.y - paddle.prevY, 2));
// Update ball speed and direction, adding paddle speed influence
self.speedX = self.speedY * Math.sin(bounceAngle) + paddleSpeed * 0.2; // Increase influence factor
self.speedY = -Math.abs(self.speedY * Math.cos(bounceAngle)) - paddleSpeed * 0.1; // Add vertical influence
self.speedX = self.speedX === 0 ? 1 : self.speedX; // Ensure non-zero speed
self.speedY = self.speedY === 0 ? 1 : self.speedY; // Ensure non-zero speed
}
// Check for collision with opponent paddle
if (self.intersects(opponentPaddle)) {
LK.getSound('paddles').play();
// Calculate the angle of incidence based on where the ball hits the paddle
var relativeIntersectX = (opponentPaddle.x - self.x) / (opponentPaddle.width / 2);
var bounceAngle = relativeIntersectX * Math.PI / 4; // Max bounce angle of 45 degrees
// Update ball speed and direction
self.speedX = self.speedY * Math.sin(bounceAngle);
self.speedY = Math.abs(self.speedY * Math.cos(bounceAngle));
self.speedX = self.speedX === 0 ? 1 : self.speedX; // Ensure non-zero speed
self.speedY = self.speedY === 0 ? 1 : self.speedY; // Ensure non-zero speed
}
};
});
var IceGate = Container.expand(function (color) {
var self = Container.call(this);
var gateGraphics = self.attachAsset(color === 'top' ? 'iceGateTop' : 'iceGateBottom', {
anchorX: 0.5,
anchorY: 0.5
});
});
// Opponent Paddle class
var OpponentPaddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('playerPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.idleTime = 0;
self.update = function () {
if (self.prevX === self.x && self.prevY === self.y) {
self.idleTime += 1 / 60; // Increment idle time by 1/60th of a second
} else {
self.idleTime = 0; // Reset idle time if paddle has moved
}
self.prevX = self.x;
self.prevY = self.y;
if (self.idleTime > 1) {
// Retreat towards the center of the track
if (self.x < 2048 / 2) {
self.x += 5;
} else if (self.x > 2048 / 2) {
self.x -= 5;
}
if (self.y < 1366 / 2) {
self.y += 5;
} else if (self.y > 1366 / 2) {
self.y -= 5;
}
}
// Opponent paddle AI logic with adjusted target
var targetY = ball.y - 100; // Aim closer to the ball for more aggressive tracking
var targetX = ball.x;
// Move vertically towards the target position with increased speed
self.y += (targetY - self.y) * 0.2; // Increase speed for more aggressive movement
// Move horizontally towards the target position with increased speed
self.x += (targetX - self.x) * 0.2; // Increase speed for more aggressive movement
// Removed opponent paddle intersection logic to prevent blocking the ball
// Check if ball is in the corner of the field
if (ball.x <= 200 && ball.y <= 200 || ball.x >= 1848 && ball.y <= 200) {
// Pull opponent paddle towards its own goal
if (self.y < 200) {
self.y += 5;
}
}
// Apply damping to reduce jitter
self.y = Math.max(200 + self.height / 2, Math.min(self.y, 1366 - 200 - self.height / 2));
self.x = Math.max(200 + self.width / 2, Math.min(self.x, 2048 - 200 - self.width / 2));
self.y *= 0.95; // Apply damping to vertical movement
self.x *= 0.95; // Apply damping to horizontal movement
// Ensure opponent paddle does not overlap with the ball
if (self.intersects(ball)) {
if (self.y < ball.y) {
self.y = ball.y - self.height - 1; // Add a small buffer to prevent squeezing
} else {
self.y = ball.y + ball.height + 1; // Add a small buffer to prevent squeezing
}
}
// Prevent overlap with player paddle
if (self.intersects(paddle)) {
if (self.y < paddle.y) {
self.y = paddle.y - self.height;
} else {
self.y = paddle.y + paddle.height;
}
}
// Ensure opponent paddle stays within the screen bounds
if (self.y < 200) {
self.y = 200;
}
};
});
// Paddle class
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Store previous position
self.prevX = self.x;
self.prevY = self.y;
// Ensure player paddle does not overlap with opponent paddle
if (self.intersects(opponentPaddle)) {
if (self.y < opponentPaddle.y) {
self.y = opponentPaddle.y - self.height;
} else {
self.y = opponentPaddle.y + opponentPaddle.height;
}
}
// Ensure the paddle stays within the screen bounds
self.y = Math.max(self.height / 2, Math.min(self.y, 2732 - self.height / 2));
self.x = Math.max(self.width / 2, Math.min(self.x, 2048 - self.width / 2));
// Ensure player paddle does not overlap with the ball
if (self.intersects(ball)) {
if (self.y < ball.y) {
self.y = ball.y - self.height - 1; // Add a small buffer to prevent squeezing
} else {
self.y = ball.y + ball.height + 1; // Add a small buffer to prevent squeezing
}
}
};
});
var ResetButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('resetButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
ball.x = 2048 / 2;
ball.y = 1366;
ball.speedX = 0;
ball.speedY = 4.0;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000,
//Init game with black background
scaleMode: 'fullScreen' // Enable full screen scaling for smartphones
});
/****
* Game Code
****/
// Attach white background asset
var cornerHits = 0;
var lastCornerHit = null;
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2048 / 2000,
// Scale to fit the screen width
scaleY: 2732 / 2730.54,
// Scale to fit the screen height
x: 2048 / 2,
y: 2732 / 2
});
game.addChild(background);
// Initialize ice hockey goals
var topGoal = game.addChild(new IceGate('top'));
topGoal.x = 2048 / 2 - 10;
topGoal.y = 50 - 45;
var bottomGoal = game.addChild(new IceGate('bottom'));
bottomGoal.x = 2048 / 2 - 10;
bottomGoal.y = 2732 - 50 + 40;
// Initialize ball and paddles
var ball = game.addChild(new Ball());
ball.x = 2048 / 2;
ball.y = 1366; // Center of the field
var paddle = game.addChild(new Paddle());
paddle.x = 2048 / 2;
paddle.y = 2500 + 500;
var opponentPaddle = game.addChild(new OpponentPaddle());
opponentPaddle.prevX = opponentPaddle.x;
opponentPaddle.prevY = opponentPaddle.y;
opponentPaddle.x = 2048 / 2;
opponentPaddle.y = 200;
opponentPaddle.x = 2048 / 2;
// Score display
var playerScore = 0;
var opponentScore = 0;
var scoreTxt = new Text2('0-0', {
size: 150,
fill: "#39FF14" // Neon green color
});
scoreTxt.anchor.set(0.5, 0.5);
scoreTxt.rotation = -Math.PI / 2; // Rotate 180 degrees to the left
scoreTxt.x = 2048 - 100; // Position 100 units from the right edge of the screen
scoreTxt.y = 1366 - 25; // Move up by 25 units
game.addChild(scoreTxt);
// Add reset button to the game
var resetButton = game.addChild(new ResetButton());
resetButton.x = 2048 - resetButton.width / 2;
resetButton.y = 2732 - resetButton.height / 2;
// Handle paddle movement
game.move = function (x, y, obj) {
paddle.x = x;
paddle.y = y;
};
// Update game logic
game.update = function () {
ball.update();
paddle.update();
opponentPaddle.update();
// Check for collision between ball and iceGateTop
if (ball.intersects(topGoal)) {
playerScore++;
scoreTxt.setText(playerScore + '-' + opponentScore);
LK.getSound('scoreSound').play();
LK.getSound('scoreSound').play();
LK.getSound('scoreSound').play();
ball.x = 2048 / 2;
ball.y = 1366; // Center of the field
ball.speedX = 0; // Reset horizontal speed
ball.speedY = 4.0; // Reset vertical speed
}
// Check if ball hits the bottom of the screen
if (ball.y >= 2732 || ball.y <= 0) {}
// Check for collision between ball and iceGateBottom
if (ball.intersects(bottomGoal)) {
opponentScore++;
scoreTxt.setText(playerScore + '-' + opponentScore);
LK.getSound('scoreSound').play();
ball.x = 2048 / 2;
ball.y = 1366; // Center of the field
ball.speedX = 0;
ball.speedY = 4.0;
cornerHits = 0; // Reset cornerHits counter
lastCornerHit = null; // Reset lastCornerHit timestamp
}
};
New ball button. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
air hockey table with neon lights. top view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Air hockey disk with neon green lights. top view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Air hockey disk with neon yellow lights. top view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Air hockey disk with neon orange lights. top view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.