/****
* Classes
****/
var AIPaddle = Container.expand(function () {
var self = Container.call(this);
var aiPaddleGraphics = self.attachAsset('aiPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.update = function () {
// AI follows puck with some lag
if (puck) {
var targetX = puck.x;
var diff = targetX - self.x;
if (Math.abs(diff) > 10) {
self.x += diff > 0 ? self.speed : -self.speed;
}
// AI also moves vertically to intercept puck when it's in AI territory
if (puck.y < 1366) {
var targetY = Math.max(300, Math.min(600, puck.y));
var diffY = targetY - self.y;
if (Math.abs(diffY) > 5) {
self.y += diffY > 0 ? self.speed : -self.speed;
}
} else {
// Return to center of AI half when puck is in player territory
var centerY = 500;
var diffY = centerY - self.y;
if (Math.abs(diffY) > 5) {
self.y += diffY > 0 ? self.speed * 0.5 : -self.speed * 0.5;
}
}
// Keep AI paddle in its half (top half)
self.y = Math.max(200, Math.min(800, self.y));
// Keep within bounds horizontally
self.x = Math.max(214, Math.min(1834, self.x));
}
};
return self;
});
var Goal = Container.expand(function () {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Puck = Container.expand(function () {
var self = Container.call(this);
var puckGraphics = self.attachAsset('puck', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.995;
self.lastIntersecting = false;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Bounce off side walls (left and right)
if (self.x <= 154 || self.x >= 1894) {
self.velocityX *= -0.8;
self.x = Math.max(154, Math.min(1894, self.x));
}
// Bounce off top and bottom walls (but not in goal areas)
if (self.y <= 124) {
// Top wall - check if not in goal area
if (self.x < 874 || self.x > 1174) {
self.velocityY *= -0.8;
self.y = Math.max(124, self.y);
}
} else if (self.y >= 2608) {
// Bottom wall - check if not in goal area
if (self.x < 874 || self.x > 1174) {
self.velocityY *= -0.8;
self.y = Math.min(2608, self.y);
}
}
// Keep puck within bounds to prevent getting stuck
self.x = Math.max(154, Math.min(1894, self.x));
self.y = Math.max(32, Math.min(2700, self.y));
// Stop very slow movement
if (Math.abs(self.velocityX) < 0.1) self.velocityX = 0;
if (Math.abs(self.velocityY) < 0.1) self.velocityY = 0;
// If puck is stuck with no velocity, give it a small push toward center
if (self.velocityX === 0 && self.velocityY === 0) {
var centerX = 1024;
var centerY = 1366;
var distX = centerX - self.x;
var distY = centerY - self.y;
if (Math.abs(distX) > 10 || Math.abs(distY) > 10) {
self.velocityX = distX > 0 ? 1 : -1;
self.velocityY = distY > 0 ? 1 : -1;
}
}
};
self.reset = function () {
self.x = 1024;
self.y = 1366;
self.velocityX = 0;
self.velocityY = 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228b22
});
/****
* Game Code
****/
// Game state variables
var gameState = 'menu'; // 'menu', 'playing', 'gameOver'
var currentDifficulty = null;
var playerScore = 0;
var aiScore = 0;
var targetScore = 5;
// Difficulty settings
var difficulties = {
easy: {
aiSpeed: 2,
name: 'EASY'
},
medium: {
aiSpeed: 3,
name: 'MEDIUM'
},
hard: {
aiSpeed: 4,
name: 'HARD'
}
};
// UI Elements
var titleText = new Text2('AIR HOCKEY 1VS1', {
size: 120,
fill: '#FFFFFF'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
var instructionText = new Text2('Choose your difficulty level:', {
size: 80,
fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 800;
var playerScoreText = new Text2('Player: 0', {
size: 100,
fill: '#FF0000'
});
playerScoreText.anchor.set(0.5, 0);
var aiScoreText = new Text2('AI: 0', {
size: 100,
fill: '#0000FF'
});
aiScoreText.anchor.set(0.5, 0);
// Difficulty buttons
var easyButton = new Text2('EASY', {
size: 100,
fill: '#00FF00'
});
easyButton.anchor.set(0.5, 0.5);
easyButton.x = 1024;
easyButton.y = 1100;
var mediumButton = new Text2('MEDIUM', {
size: 100,
fill: '#FFFF00'
});
mediumButton.anchor.set(0.5, 0.5);
mediumButton.x = 1024;
mediumButton.y = 1300;
var hardButton = new Text2('HARD', {
size: 100,
fill: '#FF0000'
});
hardButton.anchor.set(0.5, 0.5);
hardButton.x = 1024;
hardButton.y = 1500;
// Game objects
var rink = null;
var puck = null;
var playerPaddle = null;
var aiPaddle = null;
var playerGoal = null;
var aiGoal = null;
var isDragging = false;
// Initialize menu
function showMenu() {
gameState = 'menu';
game.addChild(titleText);
game.addChild(instructionText);
game.addChild(easyButton);
game.addChild(mediumButton);
game.addChild(hardButton);
}
function startGame(difficulty) {
gameState = 'playing';
currentDifficulty = difficulty;
playerScore = 0;
aiScore = 0;
// Clear menu
game.removeChild(titleText);
game.removeChild(instructionText);
game.removeChild(easyButton);
game.removeChild(mediumButton);
game.removeChild(hardButton);
// Create rink
rink = game.addChild(LK.getAsset('rink', {
anchorX: 0.5,
anchorY: 0.5
}));
rink.x = 1024;
rink.y = 1366;
// Create goals
playerGoal = game.addChild(new Goal());
playerGoal.x = 1024;
playerGoal.y = 2700;
aiGoal = game.addChild(new Goal());
aiGoal.x = 1024;
aiGoal.y = 32;
// Create puck
puck = game.addChild(new Puck());
puck.reset();
// Create paddles
playerPaddle = game.addChild(new Paddle());
playerPaddle.x = 1024;
playerPaddle.y = 2200;
aiPaddle = game.addChild(new AIPaddle());
aiPaddle.x = 1024;
aiPaddle.y = 500;
aiPaddle.speed = difficulties[difficulty].aiSpeed;
// Update UI
updateScore();
LK.gui.top.addChild(playerScoreText);
LK.gui.top.addChild(aiScoreText);
playerScoreText.y = 100;
aiScoreText.y = 200;
}
function updateScore() {
playerScoreText.setText('Player: ' + playerScore);
aiScoreText.setText('AI: ' + aiScore);
}
function resetGame() {
if (puck) {
puck.destroy();
puck = null;
}
if (playerPaddle) {
playerPaddle.destroy();
playerPaddle = null;
}
if (aiPaddle) {
aiPaddle.destroy();
aiPaddle = null;
}
if (playerGoal) {
playerGoal.destroy();
playerGoal = null;
}
if (aiGoal) {
aiGoal.destroy();
aiGoal = null;
}
if (rink) {
rink.destroy();
rink = null;
}
// Clear UI
if (playerScoreText.parent) {
LK.gui.top.removeChild(playerScoreText);
}
if (aiScoreText.parent) {
LK.gui.top.removeChild(aiScoreText);
}
showMenu();
}
function checkGoalScored() {
// Check if puck scored in AI goal (top)
if (puck.y <= 92) {
playerScore++;
updateScore();
LK.getSound('goal').play();
LK.effects.flashScreen(0x00FF00, 500);
if (playerScore >= targetScore) {
LK.showYouWin();
return;
}
puck.reset();
}
// Check if puck scored in player goal (bottom)
else if (puck.y >= 2640) {
aiScore++;
updateScore();
LK.getSound('goal').play();
LK.effects.flashScreen(0xFF0000, 500);
if (aiScore >= targetScore) {
LK.showGameOver();
return;
}
puck.reset();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (gameState === 'menu') {
// Check button clicks
var buttonHeight = 100;
var buttonWidth = 300;
if (x >= 1024 - buttonWidth / 2 && x <= 1024 + buttonWidth / 2) {
if (y >= 1100 - buttonHeight / 2 && y <= 1100 + buttonHeight / 2) {
startGame('easy');
} else if (y >= 1300 - buttonHeight / 2 && y <= 1300 + buttonHeight / 2) {
startGame('medium');
} else if (y >= 1500 - buttonHeight / 2 && y <= 1500 + buttonHeight / 2) {
startGame('hard');
}
}
} else if (gameState === 'playing') {
isDragging = true;
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && isDragging && playerPaddle) {
playerPaddle.x = x;
playerPaddle.y = y;
// Keep player paddle in bottom half and within bounds
playerPaddle.y = Math.max(playerPaddle.y, 1366);
playerPaddle.x = Math.max(214, Math.min(1834, playerPaddle.x));
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
isDragging = false;
}
};
game.update = function () {
if (gameState === 'playing' && puck && playerPaddle && aiPaddle) {
// Check paddle-puck collisions
var playerCollision = puck.intersects(playerPaddle);
var aiCollision = puck.intersects(aiPaddle);
if (playerCollision) {
var deltaX = puck.x - playerPaddle.x;
var deltaY = puck.y - playerPaddle.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
puck.velocityX += deltaX / distance * 12;
puck.velocityY += deltaY / distance * 12;
}
LK.getSound('hit').play();
}
if (aiCollision) {
var deltaX = puck.x - aiPaddle.x;
var deltaY = puck.y - aiPaddle.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
puck.velocityX += deltaX / distance * 10;
puck.velocityY += deltaY / distance * 10;
}
LK.getSound('hit').play();
}
checkGoalScored();
}
};
// Start with menu
showMenu(); /****
* Classes
****/
var AIPaddle = Container.expand(function () {
var self = Container.call(this);
var aiPaddleGraphics = self.attachAsset('aiPaddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.update = function () {
// AI follows puck with some lag
if (puck) {
var targetX = puck.x;
var diff = targetX - self.x;
if (Math.abs(diff) > 10) {
self.x += diff > 0 ? self.speed : -self.speed;
}
// AI also moves vertically to intercept puck when it's in AI territory
if (puck.y < 1366) {
var targetY = Math.max(300, Math.min(600, puck.y));
var diffY = targetY - self.y;
if (Math.abs(diffY) > 5) {
self.y += diffY > 0 ? self.speed : -self.speed;
}
} else {
// Return to center of AI half when puck is in player territory
var centerY = 500;
var diffY = centerY - self.y;
if (Math.abs(diffY) > 5) {
self.y += diffY > 0 ? self.speed * 0.5 : -self.speed * 0.5;
}
}
// Keep AI paddle in its half (top half)
self.y = Math.max(200, Math.min(800, self.y));
// Keep within bounds horizontally
self.x = Math.max(214, Math.min(1834, self.x));
}
};
return self;
});
var Goal = Container.expand(function () {
var self = Container.call(this);
var goalGraphics = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Puck = Container.expand(function () {
var self = Container.call(this);
var puckGraphics = self.attachAsset('puck', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.995;
self.lastIntersecting = false;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Bounce off side walls (left and right)
if (self.x <= 154 || self.x >= 1894) {
self.velocityX *= -0.8;
self.x = Math.max(154, Math.min(1894, self.x));
}
// Bounce off top and bottom walls (but not in goal areas)
if (self.y <= 124) {
// Top wall - check if not in goal area
if (self.x < 874 || self.x > 1174) {
self.velocityY *= -0.8;
self.y = Math.max(124, self.y);
}
} else if (self.y >= 2608) {
// Bottom wall - check if not in goal area
if (self.x < 874 || self.x > 1174) {
self.velocityY *= -0.8;
self.y = Math.min(2608, self.y);
}
}
// Keep puck within bounds to prevent getting stuck
self.x = Math.max(154, Math.min(1894, self.x));
self.y = Math.max(32, Math.min(2700, self.y));
// Stop very slow movement
if (Math.abs(self.velocityX) < 0.1) self.velocityX = 0;
if (Math.abs(self.velocityY) < 0.1) self.velocityY = 0;
// If puck is stuck with no velocity, give it a small push toward center
if (self.velocityX === 0 && self.velocityY === 0) {
var centerX = 1024;
var centerY = 1366;
var distX = centerX - self.x;
var distY = centerY - self.y;
if (Math.abs(distX) > 10 || Math.abs(distY) > 10) {
self.velocityX = distX > 0 ? 1 : -1;
self.velocityY = distY > 0 ? 1 : -1;
}
}
};
self.reset = function () {
self.x = 1024;
self.y = 1366;
self.velocityX = 0;
self.velocityY = 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228b22
});
/****
* Game Code
****/
// Game state variables
var gameState = 'menu'; // 'menu', 'playing', 'gameOver'
var currentDifficulty = null;
var playerScore = 0;
var aiScore = 0;
var targetScore = 5;
// Difficulty settings
var difficulties = {
easy: {
aiSpeed: 2,
name: 'EASY'
},
medium: {
aiSpeed: 3,
name: 'MEDIUM'
},
hard: {
aiSpeed: 4,
name: 'HARD'
}
};
// UI Elements
var titleText = new Text2('AIR HOCKEY 1VS1', {
size: 120,
fill: '#FFFFFF'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
var instructionText = new Text2('Choose your difficulty level:', {
size: 80,
fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 800;
var playerScoreText = new Text2('Player: 0', {
size: 100,
fill: '#FF0000'
});
playerScoreText.anchor.set(0.5, 0);
var aiScoreText = new Text2('AI: 0', {
size: 100,
fill: '#0000FF'
});
aiScoreText.anchor.set(0.5, 0);
// Difficulty buttons
var easyButton = new Text2('EASY', {
size: 100,
fill: '#00FF00'
});
easyButton.anchor.set(0.5, 0.5);
easyButton.x = 1024;
easyButton.y = 1100;
var mediumButton = new Text2('MEDIUM', {
size: 100,
fill: '#FFFF00'
});
mediumButton.anchor.set(0.5, 0.5);
mediumButton.x = 1024;
mediumButton.y = 1300;
var hardButton = new Text2('HARD', {
size: 100,
fill: '#FF0000'
});
hardButton.anchor.set(0.5, 0.5);
hardButton.x = 1024;
hardButton.y = 1500;
// Game objects
var rink = null;
var puck = null;
var playerPaddle = null;
var aiPaddle = null;
var playerGoal = null;
var aiGoal = null;
var isDragging = false;
// Initialize menu
function showMenu() {
gameState = 'menu';
game.addChild(titleText);
game.addChild(instructionText);
game.addChild(easyButton);
game.addChild(mediumButton);
game.addChild(hardButton);
}
function startGame(difficulty) {
gameState = 'playing';
currentDifficulty = difficulty;
playerScore = 0;
aiScore = 0;
// Clear menu
game.removeChild(titleText);
game.removeChild(instructionText);
game.removeChild(easyButton);
game.removeChild(mediumButton);
game.removeChild(hardButton);
// Create rink
rink = game.addChild(LK.getAsset('rink', {
anchorX: 0.5,
anchorY: 0.5
}));
rink.x = 1024;
rink.y = 1366;
// Create goals
playerGoal = game.addChild(new Goal());
playerGoal.x = 1024;
playerGoal.y = 2700;
aiGoal = game.addChild(new Goal());
aiGoal.x = 1024;
aiGoal.y = 32;
// Create puck
puck = game.addChild(new Puck());
puck.reset();
// Create paddles
playerPaddle = game.addChild(new Paddle());
playerPaddle.x = 1024;
playerPaddle.y = 2200;
aiPaddle = game.addChild(new AIPaddle());
aiPaddle.x = 1024;
aiPaddle.y = 500;
aiPaddle.speed = difficulties[difficulty].aiSpeed;
// Update UI
updateScore();
LK.gui.top.addChild(playerScoreText);
LK.gui.top.addChild(aiScoreText);
playerScoreText.y = 100;
aiScoreText.y = 200;
}
function updateScore() {
playerScoreText.setText('Player: ' + playerScore);
aiScoreText.setText('AI: ' + aiScore);
}
function resetGame() {
if (puck) {
puck.destroy();
puck = null;
}
if (playerPaddle) {
playerPaddle.destroy();
playerPaddle = null;
}
if (aiPaddle) {
aiPaddle.destroy();
aiPaddle = null;
}
if (playerGoal) {
playerGoal.destroy();
playerGoal = null;
}
if (aiGoal) {
aiGoal.destroy();
aiGoal = null;
}
if (rink) {
rink.destroy();
rink = null;
}
// Clear UI
if (playerScoreText.parent) {
LK.gui.top.removeChild(playerScoreText);
}
if (aiScoreText.parent) {
LK.gui.top.removeChild(aiScoreText);
}
showMenu();
}
function checkGoalScored() {
// Check if puck scored in AI goal (top)
if (puck.y <= 92) {
playerScore++;
updateScore();
LK.getSound('goal').play();
LK.effects.flashScreen(0x00FF00, 500);
if (playerScore >= targetScore) {
LK.showYouWin();
return;
}
puck.reset();
}
// Check if puck scored in player goal (bottom)
else if (puck.y >= 2640) {
aiScore++;
updateScore();
LK.getSound('goal').play();
LK.effects.flashScreen(0xFF0000, 500);
if (aiScore >= targetScore) {
LK.showGameOver();
return;
}
puck.reset();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (gameState === 'menu') {
// Check button clicks
var buttonHeight = 100;
var buttonWidth = 300;
if (x >= 1024 - buttonWidth / 2 && x <= 1024 + buttonWidth / 2) {
if (y >= 1100 - buttonHeight / 2 && y <= 1100 + buttonHeight / 2) {
startGame('easy');
} else if (y >= 1300 - buttonHeight / 2 && y <= 1300 + buttonHeight / 2) {
startGame('medium');
} else if (y >= 1500 - buttonHeight / 2 && y <= 1500 + buttonHeight / 2) {
startGame('hard');
}
}
} else if (gameState === 'playing') {
isDragging = true;
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && isDragging && playerPaddle) {
playerPaddle.x = x;
playerPaddle.y = y;
// Keep player paddle in bottom half and within bounds
playerPaddle.y = Math.max(playerPaddle.y, 1366);
playerPaddle.x = Math.max(214, Math.min(1834, playerPaddle.x));
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
isDragging = false;
}
};
game.update = function () {
if (gameState === 'playing' && puck && playerPaddle && aiPaddle) {
// Check paddle-puck collisions
var playerCollision = puck.intersects(playerPaddle);
var aiCollision = puck.intersects(aiPaddle);
if (playerCollision) {
var deltaX = puck.x - playerPaddle.x;
var deltaY = puck.y - playerPaddle.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
puck.velocityX += deltaX / distance * 12;
puck.velocityY += deltaY / distance * 12;
}
LK.getSound('hit').play();
}
if (aiCollision) {
var deltaX = puck.x - aiPaddle.x;
var deltaY = puck.y - aiPaddle.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
puck.velocityX += deltaX / distance * 10;
puck.velocityY += deltaY / distance * 10;
}
LK.getSound('hit').play();
}
checkGoalScored();
}
};
// Start with menu
showMenu();