/****
* 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();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,680 @@
-/****
+/****
+* 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: 0x000000
-});
\ No newline at end of file
+ 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();
+ }
+};
\ No newline at end of file