/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.power = 0; self.angle = 0; self.isMoving = false; self.isScored = false; self.shoot = function (power, angle) { self.power = power; self.angle = angle; self.vx = Math.sin(angle) * power; self.vy = -Math.cos(angle) * power; self.isMoving = true; LK.getSound('kick').play(); }; self.reset = function () { self.x = 1024; self.y = 2200; self.vx = 0; self.vy = 0; self.isMoving = false; self.isScored = false; self.alpha = 1; self.scale.set(1, 1); }; self.update = function () { if (self.isMoving) { // Apply gravity and friction self.vy += 0.2; self.vx *= 0.99; // Update position self.x += self.vx; self.y += self.vy; // Spin effect (visual) self.rotation += self.vx * 0.01; } }; return self; }); var Goal = Container.expand(function () { var self = Container.call(this); // Goal structure var goalNet = self.attachAsset('goalNet', { anchorX: 0.5, anchorY: 0, alpha: 0.3 }); var goalPost = self.attachAsset('goalPost', { anchorX: 0.5, anchorY: 0.5, y: -20 }); // Goal dimensions self.width = 1200; self.height = 400; self.postWidth = 1200; self.postHeight = 20; // Position the goal elements goalNet.y = 0; self.isInGoal = function (ball) { // Check if ball is in goal area var ballCenterX = ball.x; var ballCenterY = ball.y; var ballRadius = ball.width / 2; var goalLeft = self.x - self.width / 2; var goalRight = self.x + self.width / 2; var goalTop = self.y; var goalBottom = self.y + self.height; return ballCenterX + ballRadius > goalLeft && ballCenterX - ballRadius < goalRight && ballCenterY + ballRadius > goalTop && ballCenterY - ballRadius < goalBottom; }; self.hitPost = function (ball) { // Check if ball hit the post var ballCenterX = ball.x; var ballCenterY = ball.y; var ballRadius = ball.width / 2; var postLeft = self.x - self.postWidth / 2; var postRight = self.x + self.postWidth / 2; var postTop = self.y - self.postHeight / 2; var postBottom = self.y + self.postHeight / 2; // Check vertical proximity to post var verticalProximity = Math.abs(ballCenterY - self.y) < ballRadius + self.postHeight / 2; // Check horizontal position near posts var nearLeftPost = Math.abs(ballCenterX - postLeft) < ballRadius * 1.5; var nearRightPost = Math.abs(ballCenterX - postRight) < ballRadius * 1.5; return verticalProximity && (nearLeftPost || nearRightPost); }; return self; }); var Goalkeeper = Container.expand(function () { var self = Container.call(this); var keeperGraphics = self.attachAsset('goalkeeper', { anchorX: 0.5, anchorY: 0.5 }); self.targetX = 0; self.targetY = 0; self.isDiving = false; self.divingDirection = 0; // -1 left, 0 center, 1 right self.aiControlled = true; self.reset = function () { self.x = 1024; self.y = 900; self.isDiving = false; self.divingDirection = 0; tween.stop(self); }; self.dive = function (direction) { if (self.isDiving) { return; } self.isDiving = true; self.divingDirection = direction; var targetX = self.x; var targetY = self.y; // Dive direction (-1 left, 0 center, 1 right) if (direction < -0.33) { // Dive left targetX = 724; targetY = 950; } else if (direction > 0.33) { // Dive right targetX = 1324; targetY = 950; } else { // Stay center or slightly crouch targetY = 950; } tween(self, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut }); }; self.makeAIDecision = function (ballDirection) { if (!self.aiControlled) { return; } // 70% chance of diving in correct direction // 30% chance of diving wrong or staying in center var randomChance = Math.random(); var diveDirection; if (randomChance < 0.7) { // Correct direction with some variation diveDirection = ballDirection + (Math.random() * 0.4 - 0.2); } else { // Wrong direction diveDirection = -ballDirection + (Math.random() * 0.8 - 0.4); } // Clamp dive direction diveDirection = Math.max(-1, Math.min(1, diveDirection)); self.dive(diveDirection); }; return self; }); var ScoreBoard = Container.expand(function () { var self = Container.call(this); self.playerScoreMarkers = []; self.aiScoreMarkers = []; self.playerScore = 0; self.aiScore = 0; self.currentKick = 0; self.maxKicks = 5; var playerLabel = new Text2('Player', { size: 50, fill: 0xFFFFFF }); playerLabel.anchor.set(0, 0.5); playerLabel.x = 0; playerLabel.y = 0; self.addChild(playerLabel); var aiLabel = new Text2('Computer', { size: 50, fill: 0xFFFFFF }); aiLabel.anchor.set(0, 0.5); aiLabel.x = 0; aiLabel.y = 80; self.addChild(aiLabel); // Create score markers for (var i = 0; i < self.maxKicks; i++) { var playerMarker = LK.getAsset('scoreMarker', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); playerMarker.x = 200 + i * 60; playerMarker.y = 0; self.addChild(playerMarker); self.playerScoreMarkers.push(playerMarker); var aiMarker = LK.getAsset('scoreMarker', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); aiMarker.x = 200 + i * 60; aiMarker.y = 80; self.addChild(aiMarker); self.aiScoreMarkers.push(aiMarker); } self.updateScore = function (isPlayer, scored) { if (isPlayer) { if (scored) { self.playerScore++; self.playerScoreMarkers[self.currentKick].tint = 0x03a9f4; self.playerScoreMarkers[self.currentKick].alpha = 1; } else { self.playerScoreMarkers[self.currentKick].tint = 0xff5252; self.playerScoreMarkers[self.currentKick].alpha = 1; } } else { if (scored) { self.aiScore++; self.aiScoreMarkers[self.currentKick].tint = 0x03a9f4; self.aiScoreMarkers[self.currentKick].alpha = 1; } else { self.aiScoreMarkers[self.currentKick].tint = 0xff5252; self.aiScoreMarkers[self.currentKick].alpha = 1; } self.currentKick++; } }; self.reset = function () { self.playerScore = 0; self.aiScore = 0; self.currentKick = 0; for (var i = 0; i < self.maxKicks; i++) { self.playerScoreMarkers[i].tint = 0xffffff; self.playerScoreMarkers[i].alpha = 0.5; self.aiScoreMarkers[i].tint = 0xffffff; self.aiScoreMarkers[i].alpha = 0.5; } }; self.isGameOver = function () { // Check if all kicks have been taken if (self.currentKick >= self.maxKicks) { return true; } // Check if one team has an insurmountable lead var remainingKicks = self.maxKicks - self.currentKick; if (self.playerScore > self.aiScore + remainingKicks) { return true; } if (self.aiScore > self.playerScore + remainingKicks) { return true; } return false; }; return self; }); var StrikerTarget = Container.expand(function () { var self = Container.call(this); var targetGraphics = self.attachAsset('strikerTarget', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 }); self.show = function () { self.visible = true; self.alpha = 0; tween(self, { alpha: 0.6 }, { duration: 300 }); }; self.hide = function () { tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); }; self.down = function (x, y, obj) { // Handle touch events for the target }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2e7d32 }); /**** * Game Code ****/ // Game field var field = LK.getAsset('field', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); game.addChild(field); // Game state var gameState = "WAITING"; // WAITING, PLAYER_TURN, AI_TURN, TRANSITION var playerTurn = true; var shootPhase = false; // true for shooting, false for aiming // Goal var goal = new Goal(); goal.x = 1024; goal.y = 800; game.addChild(goal); // Goalkeeper var goalkeeper = new Goalkeeper(); goalkeeper.reset(); game.addChild(goalkeeper); // Ball var ball = new Ball(); ball.reset(); game.addChild(ball); // Target for striker aim var strikerTarget = new StrikerTarget(); strikerTarget.x = 1024; strikerTarget.y = 900; strikerTarget.visible = false; game.addChild(strikerTarget); // Power bar var powerBarBackground = LK.getAsset('goalPost', { anchorX: 0.5, anchorY: 0.5, tint: 0x333333, alpha: 0.5, scaleX: 0.8, scaleY: 1.5 }); powerBarBackground.x = 1024; powerBarBackground.y = 2500; powerBarBackground.visible = false; game.addChild(powerBarBackground); var powerBarFill = LK.getAsset('goalPost', { anchorX: 0, anchorY: 0.5, tint: 0xff9800, scaleY: 1.3 }); powerBarFill.x = powerBarBackground.x - powerBarBackground.width * 0.8 / 2; powerBarFill.y = powerBarBackground.y; powerBarFill.width = 0; powerBarFill.visible = false; game.addChild(powerBarFill); // Game UI var turnIndicator = new Text2('Your Turn: Aim & Shoot', { size: 80, fill: 0xFFFFFF }); turnIndicator.anchor.set(0.5, 0.5); turnIndicator.x = 1024; turnIndicator.y = 200; LK.gui.top.addChild(turnIndicator); var scoreText = new Text2('Player 0 - 0 Computer', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Scoreboard var scoreBoard = new ScoreBoard(); scoreBoard.x = 50; scoreBoard.y = 100; LK.gui.topLeft.addChild(scoreBoard); // Game variables var powerIncreasing = true; var currentPower = 0; var maxPower = 25; var shootAngle = 0; var dragStartX = 0; var dragStartY = 0; // Start game function startGame() { LK.playMusic('bgmusic'); scoreBoard.reset(); startPlayerTurn(); } function startPlayerTurn() { gameState = "PLAYER_TURN"; playerTurn = true; shootPhase = false; ball.reset(); goalkeeper.reset(); goalkeeper.aiControlled = true; strikerTarget.x = 1024; strikerTarget.y = 900; strikerTarget.show(); turnIndicator.setText('Your Turn: Aim & Shoot'); updateScoreDisplay(); } function startAITurn() { gameState = "AI_TURN"; playerTurn = false; shootPhase = false; ball.reset(); goalkeeper.reset(); goalkeeper.aiControlled = false; turnIndicator.setText('Computer\'s Turn'); updateScoreDisplay(); // AI simulates aiming LK.setTimeout(function () { // AI randomly chooses a target var targetX = 724 + Math.random() * 600; var targetY = 700 + Math.random() * 300; // Calculate angle var dx = targetX - ball.x; var dy = targetY - ball.y; var angle = Math.atan2(dx, -dy); // Calculate power var distance = Math.sqrt(dx * dx + dy * dy); var power = Math.min(maxPower, 15 + Math.random() * 5); // Shoot LK.getSound('whistle').play(); ball.shoot(power, angle); // Player decides which way to dive turnIndicator.setText('Dive to Save!'); }, 1500); } function handleGoal() { // Determine if the goal is valid var goalValid = false; if (goal.isInGoal(ball)) { // Check if goalkeeper saved it var ballCenterX = ball.x; var ballCenterY = ball.y; var ballRadius = ball.width / 2; var keeperCenterX = goalkeeper.x; var keeperCenterY = goalkeeper.y; var keeperRadius = goalkeeper.width / 2; var dx = ballCenterX - keeperCenterX; var dy = ballCenterY - keeperCenterY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ballRadius + keeperRadius) { // Goalkeeper saved it LK.getSound('save').play(); goalValid = false; } else { // Goal scored LK.getSound('crowd').play(); goalValid = true; ball.isScored = true; // Celebrate tween(ball, { alpha: 0.7 }, { duration: 1000 }); } } else if (goal.hitPost(ball)) { // Hit the post LK.getSound('goalpost').play(); // Bounce effect ball.vx = -ball.vx * 0.5; ball.vy = Math.abs(ball.vy) * 0.7; goalValid = false; } else { // Missed completely goalValid = false; } // Update score scoreBoard.updateScore(playerTurn, goalValid); updateScoreDisplay(); // Transition to next turn LK.setTimeout(function () { if (scoreBoard.isGameOver()) { endGame(); } else { if (playerTurn) { startAITurn(); } else { startPlayerTurn(); } } }, 2000); } function updateScoreDisplay() { scoreText.setText("Player ".concat(scoreBoard.playerScore, " - ").concat(scoreBoard.aiScore, " Computer")); } function endGame() { gameState = "WAITING"; // Determine winner var result = ""; if (scoreBoard.playerScore > scoreBoard.aiScore) { result = "You Win!"; // Check for high score if (scoreBoard.playerScore > storage.highScore) { storage.highScore = scoreBoard.playerScore; } } else if (scoreBoard.playerScore < scoreBoard.aiScore) { result = "Computer Wins!"; } else { result = "It's a Draw!"; } turnIndicator.setText(result); // Show game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } function updatePowerBar() { if (!shootPhase) { return; } if (powerIncreasing) { currentPower += 0.5; if (currentPower >= maxPower) { currentPower = maxPower; powerIncreasing = false; } } else { currentPower -= 0.5; if (currentPower <= 0) { currentPower = 0; powerIncreasing = true; } } // Update power bar visual var fillWidth = currentPower / maxPower * (powerBarBackground.width * 0.8); powerBarFill.width = fillWidth; // Update color based on power if (currentPower < maxPower * 0.33) { powerBarFill.tint = 0x4caf50; // Green } else if (currentPower < maxPower * 0.66) { powerBarFill.tint = 0xff9800; // Orange } else { powerBarFill.tint = 0xf44336; // Red } } // Game event handlers game.down = function (x, y, obj) { if (gameState !== "PLAYER_TURN") { return; } if (!shootPhase) { // Aiming phase - start drag dragStartX = x; dragStartY = y; // Check if clicked near target var dx = x - strikerTarget.x; var dy = y - strikerTarget.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { strikerTarget.x = x; strikerTarget.y = y; } } else { // Shooting phase - stop power bar powerBarBackground.visible = false; powerBarFill.visible = false; // Calculate angle var dx = strikerTarget.x - ball.x; var dy = strikerTarget.y - ball.y; shootAngle = Math.atan2(dx, -dy); // Goalkeeper AI makes a decision goalkeeper.makeAIDecision(dx > 0 ? 1 : -1); // Shoot the ball ball.shoot(currentPower, shootAngle); // Hide target strikerTarget.hide(); // Update game state shootPhase = false; } }; game.up = function (x, y, obj) { if (gameState !== "PLAYER_TURN" || shootPhase) { return; } // Check if we moved enough to consider it a drag var dx = x - dragStartX; var dy = y - dragStartY; var dragDistance = Math.sqrt(dx * dx + dy * dy); if (dragDistance < 10) { // Not a significant drag - if we clicked the target enter shoot phase dx = x - strikerTarget.x; dy = y - strikerTarget.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Enter shooting phase shootPhase = true; turnIndicator.setText('Tap to Shoot!'); // Show power bar powerBarBackground.visible = true; powerBarFill.visible = true; currentPower = 0; powerIncreasing = true; } } }; game.move = function (x, y, obj) { if (gameState !== "PLAYER_TURN" || shootPhase) { return; } // Check if we're dragging target var dx = x - dragStartX; var dy = y - dragStartY; var dragDistance = Math.sqrt(dx * dx + dy * dy); if (dragDistance > 10) { // Limit target to goal area + some margin var targetX = Math.max(goal.x - goal.width / 2 - 100, Math.min(goal.x + goal.width / 2 + 100, x)); var targetY = Math.max(goal.y - 100, Math.min(goal.y + goal.height + 100, y)); strikerTarget.x = targetX; strikerTarget.y = targetY; // Update drag start for smoother dragging dragStartX = x; dragStartY = y; } }; // Player goalkeeper controls game.move = function (x, y, obj) { if (gameState !== "PLAYER_TURN" || shootPhase) { return; } // Check if we're dragging target var dx = x - dragStartX; var dy = y - dragStartY; var dragDistance = Math.sqrt(dx * dx + dy * dy); if (dragDistance > 10) { // Limit target to goal area + some margin var targetX = Math.max(goal.x - goal.width / 2 - 100, Math.min(goal.x + goal.width / 2 + 100, x)); var targetY = Math.max(goal.y - 100, Math.min(goal.y + goal.height + 100, y)); strikerTarget.x = targetX; strikerTarget.y = targetY; // Update drag start for smoother dragging dragStartX = x; dragStartY = y; } // If it's AI's turn and ball is moving, allow player to control goalkeeper if (gameState === "AI_TURN" && ball.isMoving && !goalkeeper.isDiving) { // Calculate dive direction based on touch position relative to goal center var direction = (x - goal.x) / (goal.width / 2); direction = Math.max(-1, Math.min(1, direction)); goalkeeper.dive(direction); } }; // Game update loop game.update = function () { // Update ball physics ball.update(); // Check for ball stopping if (ball.isMoving && Math.abs(ball.vx) < 0.1 && Math.abs(ball.vy) < 0.1) { ball.isMoving = false; // Process goal or miss if (!ball.isScored) { handleGoal(); } } // Check for ball out of bounds if (ball.isMoving && (ball.y < 0 || ball.y > 2732 || ball.x < 0 || ball.x > 2048)) { ball.isMoving = false; handleGoal(); } // Update power bar in shooting phase if (shootPhase) { updatePowerBar(); } // Start the game if not started if (gameState === "WAITING") { startGame(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.power = 0;
self.angle = 0;
self.isMoving = false;
self.isScored = false;
self.shoot = function (power, angle) {
self.power = power;
self.angle = angle;
self.vx = Math.sin(angle) * power;
self.vy = -Math.cos(angle) * power;
self.isMoving = true;
LK.getSound('kick').play();
};
self.reset = function () {
self.x = 1024;
self.y = 2200;
self.vx = 0;
self.vy = 0;
self.isMoving = false;
self.isScored = false;
self.alpha = 1;
self.scale.set(1, 1);
};
self.update = function () {
if (self.isMoving) {
// Apply gravity and friction
self.vy += 0.2;
self.vx *= 0.99;
// Update position
self.x += self.vx;
self.y += self.vy;
// Spin effect (visual)
self.rotation += self.vx * 0.01;
}
};
return self;
});
var Goal = Container.expand(function () {
var self = Container.call(this);
// Goal structure
var goalNet = self.attachAsset('goalNet', {
anchorX: 0.5,
anchorY: 0,
alpha: 0.3
});
var goalPost = self.attachAsset('goalPost', {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
// Goal dimensions
self.width = 1200;
self.height = 400;
self.postWidth = 1200;
self.postHeight = 20;
// Position the goal elements
goalNet.y = 0;
self.isInGoal = function (ball) {
// Check if ball is in goal area
var ballCenterX = ball.x;
var ballCenterY = ball.y;
var ballRadius = ball.width / 2;
var goalLeft = self.x - self.width / 2;
var goalRight = self.x + self.width / 2;
var goalTop = self.y;
var goalBottom = self.y + self.height;
return ballCenterX + ballRadius > goalLeft && ballCenterX - ballRadius < goalRight && ballCenterY + ballRadius > goalTop && ballCenterY - ballRadius < goalBottom;
};
self.hitPost = function (ball) {
// Check if ball hit the post
var ballCenterX = ball.x;
var ballCenterY = ball.y;
var ballRadius = ball.width / 2;
var postLeft = self.x - self.postWidth / 2;
var postRight = self.x + self.postWidth / 2;
var postTop = self.y - self.postHeight / 2;
var postBottom = self.y + self.postHeight / 2;
// Check vertical proximity to post
var verticalProximity = Math.abs(ballCenterY - self.y) < ballRadius + self.postHeight / 2;
// Check horizontal position near posts
var nearLeftPost = Math.abs(ballCenterX - postLeft) < ballRadius * 1.5;
var nearRightPost = Math.abs(ballCenterX - postRight) < ballRadius * 1.5;
return verticalProximity && (nearLeftPost || nearRightPost);
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = 0;
self.targetY = 0;
self.isDiving = false;
self.divingDirection = 0; // -1 left, 0 center, 1 right
self.aiControlled = true;
self.reset = function () {
self.x = 1024;
self.y = 900;
self.isDiving = false;
self.divingDirection = 0;
tween.stop(self);
};
self.dive = function (direction) {
if (self.isDiving) {
return;
}
self.isDiving = true;
self.divingDirection = direction;
var targetX = self.x;
var targetY = self.y;
// Dive direction (-1 left, 0 center, 1 right)
if (direction < -0.33) {
// Dive left
targetX = 724;
targetY = 950;
} else if (direction > 0.33) {
// Dive right
targetX = 1324;
targetY = 950;
} else {
// Stay center or slightly crouch
targetY = 950;
}
tween(self, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
};
self.makeAIDecision = function (ballDirection) {
if (!self.aiControlled) {
return;
}
// 70% chance of diving in correct direction
// 30% chance of diving wrong or staying in center
var randomChance = Math.random();
var diveDirection;
if (randomChance < 0.7) {
// Correct direction with some variation
diveDirection = ballDirection + (Math.random() * 0.4 - 0.2);
} else {
// Wrong direction
diveDirection = -ballDirection + (Math.random() * 0.8 - 0.4);
}
// Clamp dive direction
diveDirection = Math.max(-1, Math.min(1, diveDirection));
self.dive(diveDirection);
};
return self;
});
var ScoreBoard = Container.expand(function () {
var self = Container.call(this);
self.playerScoreMarkers = [];
self.aiScoreMarkers = [];
self.playerScore = 0;
self.aiScore = 0;
self.currentKick = 0;
self.maxKicks = 5;
var playerLabel = new Text2('Player', {
size: 50,
fill: 0xFFFFFF
});
playerLabel.anchor.set(0, 0.5);
playerLabel.x = 0;
playerLabel.y = 0;
self.addChild(playerLabel);
var aiLabel = new Text2('Computer', {
size: 50,
fill: 0xFFFFFF
});
aiLabel.anchor.set(0, 0.5);
aiLabel.x = 0;
aiLabel.y = 80;
self.addChild(aiLabel);
// Create score markers
for (var i = 0; i < self.maxKicks; i++) {
var playerMarker = LK.getAsset('scoreMarker', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
playerMarker.x = 200 + i * 60;
playerMarker.y = 0;
self.addChild(playerMarker);
self.playerScoreMarkers.push(playerMarker);
var aiMarker = LK.getAsset('scoreMarker', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
aiMarker.x = 200 + i * 60;
aiMarker.y = 80;
self.addChild(aiMarker);
self.aiScoreMarkers.push(aiMarker);
}
self.updateScore = function (isPlayer, scored) {
if (isPlayer) {
if (scored) {
self.playerScore++;
self.playerScoreMarkers[self.currentKick].tint = 0x03a9f4;
self.playerScoreMarkers[self.currentKick].alpha = 1;
} else {
self.playerScoreMarkers[self.currentKick].tint = 0xff5252;
self.playerScoreMarkers[self.currentKick].alpha = 1;
}
} else {
if (scored) {
self.aiScore++;
self.aiScoreMarkers[self.currentKick].tint = 0x03a9f4;
self.aiScoreMarkers[self.currentKick].alpha = 1;
} else {
self.aiScoreMarkers[self.currentKick].tint = 0xff5252;
self.aiScoreMarkers[self.currentKick].alpha = 1;
}
self.currentKick++;
}
};
self.reset = function () {
self.playerScore = 0;
self.aiScore = 0;
self.currentKick = 0;
for (var i = 0; i < self.maxKicks; i++) {
self.playerScoreMarkers[i].tint = 0xffffff;
self.playerScoreMarkers[i].alpha = 0.5;
self.aiScoreMarkers[i].tint = 0xffffff;
self.aiScoreMarkers[i].alpha = 0.5;
}
};
self.isGameOver = function () {
// Check if all kicks have been taken
if (self.currentKick >= self.maxKicks) {
return true;
}
// Check if one team has an insurmountable lead
var remainingKicks = self.maxKicks - self.currentKick;
if (self.playerScore > self.aiScore + remainingKicks) {
return true;
}
if (self.aiScore > self.playerScore + remainingKicks) {
return true;
}
return false;
};
return self;
});
var StrikerTarget = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('strikerTarget', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.show = function () {
self.visible = true;
self.alpha = 0;
tween(self, {
alpha: 0.6
}, {
duration: 300
});
};
self.hide = function () {
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.down = function (x, y, obj) {
// Handle touch events for the target
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2e7d32
});
/****
* Game Code
****/
// Game field
var field = LK.getAsset('field', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
game.addChild(field);
// Game state
var gameState = "WAITING"; // WAITING, PLAYER_TURN, AI_TURN, TRANSITION
var playerTurn = true;
var shootPhase = false; // true for shooting, false for aiming
// Goal
var goal = new Goal();
goal.x = 1024;
goal.y = 800;
game.addChild(goal);
// Goalkeeper
var goalkeeper = new Goalkeeper();
goalkeeper.reset();
game.addChild(goalkeeper);
// Ball
var ball = new Ball();
ball.reset();
game.addChild(ball);
// Target for striker aim
var strikerTarget = new StrikerTarget();
strikerTarget.x = 1024;
strikerTarget.y = 900;
strikerTarget.visible = false;
game.addChild(strikerTarget);
// Power bar
var powerBarBackground = LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333,
alpha: 0.5,
scaleX: 0.8,
scaleY: 1.5
});
powerBarBackground.x = 1024;
powerBarBackground.y = 2500;
powerBarBackground.visible = false;
game.addChild(powerBarBackground);
var powerBarFill = LK.getAsset('goalPost', {
anchorX: 0,
anchorY: 0.5,
tint: 0xff9800,
scaleY: 1.3
});
powerBarFill.x = powerBarBackground.x - powerBarBackground.width * 0.8 / 2;
powerBarFill.y = powerBarBackground.y;
powerBarFill.width = 0;
powerBarFill.visible = false;
game.addChild(powerBarFill);
// Game UI
var turnIndicator = new Text2('Your Turn: Aim & Shoot', {
size: 80,
fill: 0xFFFFFF
});
turnIndicator.anchor.set(0.5, 0.5);
turnIndicator.x = 1024;
turnIndicator.y = 200;
LK.gui.top.addChild(turnIndicator);
var scoreText = new Text2('Player 0 - 0 Computer', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Scoreboard
var scoreBoard = new ScoreBoard();
scoreBoard.x = 50;
scoreBoard.y = 100;
LK.gui.topLeft.addChild(scoreBoard);
// Game variables
var powerIncreasing = true;
var currentPower = 0;
var maxPower = 25;
var shootAngle = 0;
var dragStartX = 0;
var dragStartY = 0;
// Start game
function startGame() {
LK.playMusic('bgmusic');
scoreBoard.reset();
startPlayerTurn();
}
function startPlayerTurn() {
gameState = "PLAYER_TURN";
playerTurn = true;
shootPhase = false;
ball.reset();
goalkeeper.reset();
goalkeeper.aiControlled = true;
strikerTarget.x = 1024;
strikerTarget.y = 900;
strikerTarget.show();
turnIndicator.setText('Your Turn: Aim & Shoot');
updateScoreDisplay();
}
function startAITurn() {
gameState = "AI_TURN";
playerTurn = false;
shootPhase = false;
ball.reset();
goalkeeper.reset();
goalkeeper.aiControlled = false;
turnIndicator.setText('Computer\'s Turn');
updateScoreDisplay();
// AI simulates aiming
LK.setTimeout(function () {
// AI randomly chooses a target
var targetX = 724 + Math.random() * 600;
var targetY = 700 + Math.random() * 300;
// Calculate angle
var dx = targetX - ball.x;
var dy = targetY - ball.y;
var angle = Math.atan2(dx, -dy);
// Calculate power
var distance = Math.sqrt(dx * dx + dy * dy);
var power = Math.min(maxPower, 15 + Math.random() * 5);
// Shoot
LK.getSound('whistle').play();
ball.shoot(power, angle);
// Player decides which way to dive
turnIndicator.setText('Dive to Save!');
}, 1500);
}
function handleGoal() {
// Determine if the goal is valid
var goalValid = false;
if (goal.isInGoal(ball)) {
// Check if goalkeeper saved it
var ballCenterX = ball.x;
var ballCenterY = ball.y;
var ballRadius = ball.width / 2;
var keeperCenterX = goalkeeper.x;
var keeperCenterY = goalkeeper.y;
var keeperRadius = goalkeeper.width / 2;
var dx = ballCenterX - keeperCenterX;
var dy = ballCenterY - keeperCenterY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ballRadius + keeperRadius) {
// Goalkeeper saved it
LK.getSound('save').play();
goalValid = false;
} else {
// Goal scored
LK.getSound('crowd').play();
goalValid = true;
ball.isScored = true;
// Celebrate
tween(ball, {
alpha: 0.7
}, {
duration: 1000
});
}
} else if (goal.hitPost(ball)) {
// Hit the post
LK.getSound('goalpost').play();
// Bounce effect
ball.vx = -ball.vx * 0.5;
ball.vy = Math.abs(ball.vy) * 0.7;
goalValid = false;
} else {
// Missed completely
goalValid = false;
}
// Update score
scoreBoard.updateScore(playerTurn, goalValid);
updateScoreDisplay();
// Transition to next turn
LK.setTimeout(function () {
if (scoreBoard.isGameOver()) {
endGame();
} else {
if (playerTurn) {
startAITurn();
} else {
startPlayerTurn();
}
}
}, 2000);
}
function updateScoreDisplay() {
scoreText.setText("Player ".concat(scoreBoard.playerScore, " - ").concat(scoreBoard.aiScore, " Computer"));
}
function endGame() {
gameState = "WAITING";
// Determine winner
var result = "";
if (scoreBoard.playerScore > scoreBoard.aiScore) {
result = "You Win!";
// Check for high score
if (scoreBoard.playerScore > storage.highScore) {
storage.highScore = scoreBoard.playerScore;
}
} else if (scoreBoard.playerScore < scoreBoard.aiScore) {
result = "Computer Wins!";
} else {
result = "It's a Draw!";
}
turnIndicator.setText(result);
// Show game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
function updatePowerBar() {
if (!shootPhase) {
return;
}
if (powerIncreasing) {
currentPower += 0.5;
if (currentPower >= maxPower) {
currentPower = maxPower;
powerIncreasing = false;
}
} else {
currentPower -= 0.5;
if (currentPower <= 0) {
currentPower = 0;
powerIncreasing = true;
}
}
// Update power bar visual
var fillWidth = currentPower / maxPower * (powerBarBackground.width * 0.8);
powerBarFill.width = fillWidth;
// Update color based on power
if (currentPower < maxPower * 0.33) {
powerBarFill.tint = 0x4caf50; // Green
} else if (currentPower < maxPower * 0.66) {
powerBarFill.tint = 0xff9800; // Orange
} else {
powerBarFill.tint = 0xf44336; // Red
}
}
// Game event handlers
game.down = function (x, y, obj) {
if (gameState !== "PLAYER_TURN") {
return;
}
if (!shootPhase) {
// Aiming phase - start drag
dragStartX = x;
dragStartY = y;
// Check if clicked near target
var dx = x - strikerTarget.x;
var dy = y - strikerTarget.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
strikerTarget.x = x;
strikerTarget.y = y;
}
} else {
// Shooting phase - stop power bar
powerBarBackground.visible = false;
powerBarFill.visible = false;
// Calculate angle
var dx = strikerTarget.x - ball.x;
var dy = strikerTarget.y - ball.y;
shootAngle = Math.atan2(dx, -dy);
// Goalkeeper AI makes a decision
goalkeeper.makeAIDecision(dx > 0 ? 1 : -1);
// Shoot the ball
ball.shoot(currentPower, shootAngle);
// Hide target
strikerTarget.hide();
// Update game state
shootPhase = false;
}
};
game.up = function (x, y, obj) {
if (gameState !== "PLAYER_TURN" || shootPhase) {
return;
}
// Check if we moved enough to consider it a drag
var dx = x - dragStartX;
var dy = y - dragStartY;
var dragDistance = Math.sqrt(dx * dx + dy * dy);
if (dragDistance < 10) {
// Not a significant drag - if we clicked the target enter shoot phase
dx = x - strikerTarget.x;
dy = y - strikerTarget.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Enter shooting phase
shootPhase = true;
turnIndicator.setText('Tap to Shoot!');
// Show power bar
powerBarBackground.visible = true;
powerBarFill.visible = true;
currentPower = 0;
powerIncreasing = true;
}
}
};
game.move = function (x, y, obj) {
if (gameState !== "PLAYER_TURN" || shootPhase) {
return;
}
// Check if we're dragging target
var dx = x - dragStartX;
var dy = y - dragStartY;
var dragDistance = Math.sqrt(dx * dx + dy * dy);
if (dragDistance > 10) {
// Limit target to goal area + some margin
var targetX = Math.max(goal.x - goal.width / 2 - 100, Math.min(goal.x + goal.width / 2 + 100, x));
var targetY = Math.max(goal.y - 100, Math.min(goal.y + goal.height + 100, y));
strikerTarget.x = targetX;
strikerTarget.y = targetY;
// Update drag start for smoother dragging
dragStartX = x;
dragStartY = y;
}
};
// Player goalkeeper controls
game.move = function (x, y, obj) {
if (gameState !== "PLAYER_TURN" || shootPhase) {
return;
}
// Check if we're dragging target
var dx = x - dragStartX;
var dy = y - dragStartY;
var dragDistance = Math.sqrt(dx * dx + dy * dy);
if (dragDistance > 10) {
// Limit target to goal area + some margin
var targetX = Math.max(goal.x - goal.width / 2 - 100, Math.min(goal.x + goal.width / 2 + 100, x));
var targetY = Math.max(goal.y - 100, Math.min(goal.y + goal.height + 100, y));
strikerTarget.x = targetX;
strikerTarget.y = targetY;
// Update drag start for smoother dragging
dragStartX = x;
dragStartY = y;
}
// If it's AI's turn and ball is moving, allow player to control goalkeeper
if (gameState === "AI_TURN" && ball.isMoving && !goalkeeper.isDiving) {
// Calculate dive direction based on touch position relative to goal center
var direction = (x - goal.x) / (goal.width / 2);
direction = Math.max(-1, Math.min(1, direction));
goalkeeper.dive(direction);
}
};
// Game update loop
game.update = function () {
// Update ball physics
ball.update();
// Check for ball stopping
if (ball.isMoving && Math.abs(ball.vx) < 0.1 && Math.abs(ball.vy) < 0.1) {
ball.isMoving = false;
// Process goal or miss
if (!ball.isScored) {
handleGoal();
}
}
// Check for ball out of bounds
if (ball.isMoving && (ball.y < 0 || ball.y > 2732 || ball.x < 0 || ball.x > 2048)) {
ball.isMoving = false;
handleGoal();
}
// Update power bar in shooting phase
if (shootPhase) {
updatePowerBar();
}
// Start the game if not started
if (gameState === "WAITING") {
startGame();
}
};