/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
playerGoals: 0,
playerSaves: 0,
gamesPlayed: 0,
currentRound: 1,
highScore: 0
});
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
// Ball graphics
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Ball properties
self.velocity = {
x: 0,
y: 0
};
self.power = 0;
self.inMotion = false;
self.scored = false;
self.saved = false;
// Reset ball to starting position
self.reset = function (isPlayerKicking) {
self.x = 2048 / 2;
self.y = isPlayerKicking ? 2200 : 900;
self.velocity = {
x: 0,
y: 0
};
self.power = 0;
self.inMotion = false;
self.scored = false;
self.saved = false;
self.scaleX = 1;
self.scaleY = 1;
};
// Kick the ball with direction and power
self.kick = function (targetX, targetY, power) {
if (self.inMotion) return;
LK.getSound('kick').play();
self.inMotion = true;
self.power = power;
// Add random variation to target position for more varied shots
var randomVariationX = (Math.random() - 0.5) * 200; // ±100 pixels horizontal variation
var randomVariationY = (Math.random() - 0.5) * 150; // ±75 pixels vertical variation
var finalTargetX = targetX + randomVariationX;
var finalTargetY = targetY + randomVariationY;
// Calculate duration based on power (higher power = faster)
var baseDuration = 1000; // Base duration in milliseconds
var duration = baseDuration / (power * 0.5 + 0.5); // Scale duration by power
// Animate ball directly to target position
tween(self, {
x: finalTargetX,
y: finalTargetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.inMotion = false;
}
});
};
// Update ball physics
self.update = function () {
if (!self.inMotion) return;
// Apply perspective scaling (ball gets smaller as it moves toward the goal)
if (self.y < 1400) {
var distance = (1400 - self.y) / 1000;
var scale = Math.max(0.5, 1 - distance * 0.5);
self.scaleX = scale;
self.scaleY = scale;
}
};
return self;
});
var Button = Container.expand(function () {
var self = Container.call(this);
// Button background
var bg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
// Button text
var label = new Text2("Button", {
size: 50,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
self.setText = function (text) {
label.setText(text);
};
self.down = function () {
tween(bg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.up = function () {
tween(bg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.onClick) {
self.onClick();
}
};
return self;
});
var GoalArea = Container.expand(function () {
var self = Container.call(this);
// Goal net
var goalNet = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0.3
});
// Left goalpost
var leftPost = self.attachAsset('goalpost', {
anchorX: 0.5,
anchorY: 1.0,
x: -goalNet.width / 2
});
// Right goalpost
var rightPost = self.attachAsset('goalpost', {
anchorX: 0.5,
anchorY: 1.0,
x: goalNet.width / 2
});
// Crossbar
var crossbar = self.attachAsset('crossbar', {
anchorX: 0.5,
anchorY: 0.5,
y: -goalNet.height
});
// Set up goal dimensions
self.width = goalNet.width;
self.height = goalNet.height;
self.leftX = -self.width / 2;
self.rightX = self.width / 2;
self.topY = -self.height;
// Check if ball went in goal
self.checkGoal = function (ball) {
if (ball.scored || ball.saved) return false;
// Get ball position relative to goal
var relX = ball.x - self.x;
var relY = ball.y - self.y;
// Check if ball is within goal boundaries
if (relX > self.leftX && relX < self.rightX && relY < 0 && relY > self.topY) {
ball.scored = true;
ball.inMotion = false;
LK.getSound('goal').play();
LK.getSound('crowd').play();
return true;
}
return false;
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
// Goalkeeper graphics
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.5
});
// Goalkeeper control bar
var controlBar = self.attachAsset('goalkeeper_control_bar', {
anchorX: 0.5,
anchorY: 0.5,
y: 200,
visible: false
});
// Keeper properties
self.diving = false;
self.divingDirection = {
x: 0,
y: 0
};
self.saveRange = 250; // How far the keeper can reach
self.originalX = 0;
self.originalY = 0;
self.isAI = false;
self.controlBar = controlBar;
// Initialize keeper
self.init = function (isAI) {
self.isAI = isAI;
self.originalX = 2048 / 2;
self.originalY = 550;
self.x = self.originalX;
self.y = self.originalY;
self.diving = false;
self.controlBar.visible = isAI;
};
// Dive in a direction
self.dive = function (targetX, targetY) {
if (self.diving) return;
self.diving = true;
// Calculate direction
var dirX = targetX - self.x;
var dirY = targetY - self.y;
// Normalize and limit dive distance
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > self.saveRange) {
dirX = dirX / length * self.saveRange;
dirY = dirY / length * self.saveRange;
}
self.divingDirection = {
x: dirX,
y: dirY
};
// Animate the dive
tween(self, {
x: self.x + dirX,
y: self.y + dirY
}, {
duration: 500,
easing: tween.easeOut
});
};
// AI make a decision to dive
self.aiDecide = function (ball) {
if (!self.isAI || self.diving || !ball.inMotion) return;
// Calculate where the ball will be
var futureX = ball.x + ball.velocity.x * 10;
var futureY = ball.y + ball.velocity.y * 10;
// Add some randomness to make it challenging
var difficulty = gameState.round * 0.1; // 0.1 to 1.0 based on round
var accuracy = Math.min(0.9, 0.5 + difficulty); // 50% to 90% accuracy
if (Math.random() < accuracy) {
// Good prediction
self.dive(futureX, futureY);
} else {
// Inaccurate dive
self.dive(futureX + (Math.random() * 400 - 200), futureY + (Math.random() * 200 - 100));
}
};
// Move goalkeeper left and right
self.moveLeft = function () {
if (self.diving) return;
var targetX = Math.max(goalArea.x + goalArea.leftX + 100, self.x - 150);
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
};
self.moveRight = function () {
if (self.diving) return;
var targetX = Math.min(goalArea.x + goalArea.rightX - 100, self.x + 150);
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
};
// Auto movement for goalkeeper
self.autoMove = function () {
if (self.diving) return;
// Move to random position within goal area
var minX = goalArea.x + goalArea.leftX + 100;
var maxX = goalArea.x + goalArea.rightX - 100;
var targetX = minX + Math.random() * (maxX - minX);
tween(self, {
x: targetX
}, {
duration: 500,
easing: tween.easeInOut
});
};
// Reset keeper position
self.reset = function () {
self.diving = false;
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 500,
easing: tween.easeOut
});
};
// Check if ball touches goalkeeper (collision detection)
self.checkCollision = function (ball) {
if (ball.saved || ball.scored) return false;
// Calculate distance between ball and keeper
var dx = ball.x - self.x;
var dy = ball.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If ball touches keeper, it's a save
if (distance < 120) {
ball.saved = true;
ball.inMotion = false;
// Stop the ball's tween animation
tween.stop(ball, {
x: true,
y: true
});
// Position ball at goalkeeper's location
ball.x = self.x;
ball.y = self.y;
LK.getSound('save').play();
return true;
}
return false;
};
// Check if keeper saved the ball
self.checkSave = function (ball) {
return self.checkCollision(ball);
};
return self;
});
var PowerMeter = Container.expand(function () {
var self = Container.call(this);
// Power meter background
var meterBg = self.attachAsset('power_meter', {
anchorX: 0.5,
anchorY: 1.0
});
// Power indicator
var indicator = self.attachAsset('power_indicator', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20
});
// Power meter properties
self.active = false;
self.increasing = true;
self.power = 0; // 0 to 1
self.maxPower = 1;
// Start power meter
self.start = function () {
self.active = true;
self.increasing = true;
self.power = 0;
self.updateIndicator();
};
// Stop and get final power
self.stop = function () {
self.active = false;
return self.power;
};
// Update power value
self.update = function () {
if (!self.active) return;
// Increase or decrease power
if (self.increasing) {
self.power += 0.02;
if (self.power >= self.maxPower) {
self.power = self.maxPower;
self.increasing = false;
}
} else {
self.power -= 0.02;
if (self.power <= 0) {
self.power = 0;
self.increasing = true;
}
}
self.updateIndicator();
};
// Update indicator position
self.updateIndicator = function () {
indicator.y = -meterBg.height * self.power;
// Change color based on power
if (self.power < 0.3) {
indicator.tint = 0x00FF00; // Green for low power
} else if (self.power < 0.7) {
indicator.tint = 0xFFFF00; // Yellow for medium power
} else {
indicator.tint = 0xFF0000; // Red for high power
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game state
var gameState = {
mode: "shooting",
round: storage.currentRound || 1,
scorePlayer: 0,
shotsPlayer: 0,
totalShots: 5
};
// Game elements
var ball, goalkeeper, goalArea, powerMeter;
var targetMarker;
var shootButton, nextButton;
// UI elements
var scoreText, roundText, instructionText;
// Initialize the game
function initGame() {
// Create goal area
goalArea = new GoalArea();
goalArea.x = 2048 / 2;
goalArea.y = 500;
game.addChild(goalArea);
// Create ball
ball = new Ball();
ball.reset(true);
game.addChild(ball);
// Create goalkeeper
goalkeeper = new Goalkeeper();
goalkeeper.init(false); // Player goalkeeper
game.addChild(goalkeeper);
// Create target marker for aiming
targetMarker = LK.getAsset('target', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
visible: false
});
game.addChild(targetMarker);
// Create power meter
powerMeter = new PowerMeter();
powerMeter.x = 100;
powerMeter.y = 2200;
powerMeter.visible = false;
game.addChild(powerMeter);
// Create shoot button
shootButton = new Button();
shootButton.x = 2048 - 200;
shootButton.y = 2500;
shootButton.setText("SHOOT");
shootButton.visible = false;
shootButton.onClick = function () {
if (gameState.mode === "shooting" && targetMarker.visible) {
var power = powerMeter.stop();
ball.kick(targetMarker.x, targetMarker.y, power);
targetMarker.visible = false;
shootButton.visible = false;
powerMeter.visible = false;
}
};
game.addChild(shootButton);
// Create next button
nextButton = new Button();
nextButton.x = 2048 / 2;
nextButton.y = 2500;
nextButton.setText("NEXT");
nextButton.visible = false;
nextButton.onClick = function () {
if (gameState.mode === "results") {
advanceTurn();
}
};
game.addChild(nextButton);
// Create score text
scoreText = new Text2("Score: 0", {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create round text
roundText = new Text2("Round " + gameState.round, {
size: 60,
fill: 0xFFFFFF
});
roundText.anchor.set(0.5, 0);
roundText.y = 100;
LK.gui.top.addChild(roundText);
// Create instruction text
instructionText = new Text2("Tap to aim, then tap SHOOT", {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 200;
LK.gui.top.addChild(instructionText);
// Start with player shooting
startShootingMode();
// Start background music
LK.playMusic('background_music');
}
// Start shooting mode (player kicks)
function startShootingMode() {
gameState.mode = "shooting";
// Set up scene
ball.reset(true);
goalkeeper.reset();
goalkeeper.visible = true;
goalkeeper.controlBar.visible = false;
// Position goalkeeper at random starting position for each round
var randomStartX = goalkeeper.originalX + (Math.random() - 0.5) * 400; // ±200 pixels from center
goalkeeper.x = randomStartX;
// Start goalkeeper auto movement
var keeperMoveTimer = LK.setInterval(function () {
if (gameState.mode === "shooting" && !ball.inMotion) {
goalkeeper.autoMove();
}
}, 1500 + Math.random() * 1000);
// Update UI
updateScoreText();
instructionText.setText("Tap to aim, then tap SHOOT");
// Reset target and power
targetMarker.visible = false;
powerMeter.visible = false;
shootButton.visible = false;
}
// Show results and next button
function showResults(isGoal) {
gameState.mode = "results";
gameState.shotsPlayer++;
if (isGoal) {
gameState.scorePlayer++;
storage.playerGoals++;
instructionText.setText("GOAL! You scored!");
} else {
instructionText.setText("SAVED! The goalkeeper stopped your shot!");
}
updateScoreText();
nextButton.visible = true;
}
// Advance to next turn or round
function advanceTurn() {
nextButton.visible = false;
// Check if round is complete
if (gameState.shotsPlayer >= gameState.totalShots) {
endRound();
} else {
startShootingMode();
}
}
// End current round and check results
function endRound() {
// Update storage
storage.gamesPlayed++;
// Update high score
if (gameState.scorePlayer > storage.highScore) {
storage.highScore = gameState.scorePlayer;
}
// Check if 5 rounds are completed
if (gameState.round >= 5) {
// Show PERFECT message
instructionText.setText("PERFECT");
return;
}
// Advance to next round
gameState.round++;
storage.currentRound = gameState.round;
instructionText.setText("Round " + (gameState.round - 1) + " complete! Score: " + gameState.scorePlayer + "/" + gameState.totalShots + ". Moving to Round " + gameState.round);
// Reset scores for next round
gameState.scorePlayer = 0;
gameState.shotsPlayer = 0;
// Start new round after delay
LK.setTimeout(function () {
roundText.setText("Round " + gameState.round);
startShootingMode();
}, 2000);
}
// Update score display
function updateScoreText() {
scoreText.setText("Score: " + gameState.scorePlayer + "/" + gameState.totalShots);
}
// Game input handlers
game.down = function (x, y, obj) {
if (gameState.mode === "shooting") {
// Set target for aiming
if (y < 1200) {
// Only allow targeting in the goal area
targetMarker.x = x;
targetMarker.y = y;
targetMarker.visible = true;
// Show shoot button and power meter
shootButton.visible = true;
powerMeter.visible = true;
powerMeter.start();
}
}
};
// Game loop
game.update = function () {
// Update ball physics
ball.update();
// Update power meter
powerMeter.update();
// AI goalkeeper decision making
if (gameState.mode === "shooting") {
goalkeeper.aiDecide(ball);
// Check if ball touches goalkeeper (collision detection)
if (ball.inMotion && goalkeeper.checkCollision(ball)) {
LK.setTimeout(function () {
showResults(false);
}, 1000);
}
// Check if ball went in goal
if (ball.inMotion && goalArea.checkGoal(ball)) {
LK.setTimeout(function () {
showResults(true);
}, 1000);
}
}
// Check if ball is out of bounds or stopped
if (ball.inMotion && (ball.x < 0 || ball.x > 2048 || ball.y < 0 || ball.y > 2732 || ball.y < 400 && !ball.scored && !ball.saved && !ball.inMotion)) {
// Ball went out or stopped, count as a miss
ball.inMotion = false;
LK.setTimeout(function () {
showResults(false);
}, 1000);
}
};
// Initialize the game
initGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
playerGoals: 0,
playerSaves: 0,
gamesPlayed: 0,
currentRound: 1,
highScore: 0
});
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
// Ball graphics
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Ball properties
self.velocity = {
x: 0,
y: 0
};
self.power = 0;
self.inMotion = false;
self.scored = false;
self.saved = false;
// Reset ball to starting position
self.reset = function (isPlayerKicking) {
self.x = 2048 / 2;
self.y = isPlayerKicking ? 2200 : 900;
self.velocity = {
x: 0,
y: 0
};
self.power = 0;
self.inMotion = false;
self.scored = false;
self.saved = false;
self.scaleX = 1;
self.scaleY = 1;
};
// Kick the ball with direction and power
self.kick = function (targetX, targetY, power) {
if (self.inMotion) return;
LK.getSound('kick').play();
self.inMotion = true;
self.power = power;
// Add random variation to target position for more varied shots
var randomVariationX = (Math.random() - 0.5) * 200; // ±100 pixels horizontal variation
var randomVariationY = (Math.random() - 0.5) * 150; // ±75 pixels vertical variation
var finalTargetX = targetX + randomVariationX;
var finalTargetY = targetY + randomVariationY;
// Calculate duration based on power (higher power = faster)
var baseDuration = 1000; // Base duration in milliseconds
var duration = baseDuration / (power * 0.5 + 0.5); // Scale duration by power
// Animate ball directly to target position
tween(self, {
x: finalTargetX,
y: finalTargetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.inMotion = false;
}
});
};
// Update ball physics
self.update = function () {
if (!self.inMotion) return;
// Apply perspective scaling (ball gets smaller as it moves toward the goal)
if (self.y < 1400) {
var distance = (1400 - self.y) / 1000;
var scale = Math.max(0.5, 1 - distance * 0.5);
self.scaleX = scale;
self.scaleY = scale;
}
};
return self;
});
var Button = Container.expand(function () {
var self = Container.call(this);
// Button background
var bg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
// Button text
var label = new Text2("Button", {
size: 50,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
self.setText = function (text) {
label.setText(text);
};
self.down = function () {
tween(bg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.up = function () {
tween(bg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.onClick) {
self.onClick();
}
};
return self;
});
var GoalArea = Container.expand(function () {
var self = Container.call(this);
// Goal net
var goalNet = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0.3
});
// Left goalpost
var leftPost = self.attachAsset('goalpost', {
anchorX: 0.5,
anchorY: 1.0,
x: -goalNet.width / 2
});
// Right goalpost
var rightPost = self.attachAsset('goalpost', {
anchorX: 0.5,
anchorY: 1.0,
x: goalNet.width / 2
});
// Crossbar
var crossbar = self.attachAsset('crossbar', {
anchorX: 0.5,
anchorY: 0.5,
y: -goalNet.height
});
// Set up goal dimensions
self.width = goalNet.width;
self.height = goalNet.height;
self.leftX = -self.width / 2;
self.rightX = self.width / 2;
self.topY = -self.height;
// Check if ball went in goal
self.checkGoal = function (ball) {
if (ball.scored || ball.saved) return false;
// Get ball position relative to goal
var relX = ball.x - self.x;
var relY = ball.y - self.y;
// Check if ball is within goal boundaries
if (relX > self.leftX && relX < self.rightX && relY < 0 && relY > self.topY) {
ball.scored = true;
ball.inMotion = false;
LK.getSound('goal').play();
LK.getSound('crowd').play();
return true;
}
return false;
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
// Goalkeeper graphics
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.5
});
// Goalkeeper control bar
var controlBar = self.attachAsset('goalkeeper_control_bar', {
anchorX: 0.5,
anchorY: 0.5,
y: 200,
visible: false
});
// Keeper properties
self.diving = false;
self.divingDirection = {
x: 0,
y: 0
};
self.saveRange = 250; // How far the keeper can reach
self.originalX = 0;
self.originalY = 0;
self.isAI = false;
self.controlBar = controlBar;
// Initialize keeper
self.init = function (isAI) {
self.isAI = isAI;
self.originalX = 2048 / 2;
self.originalY = 550;
self.x = self.originalX;
self.y = self.originalY;
self.diving = false;
self.controlBar.visible = isAI;
};
// Dive in a direction
self.dive = function (targetX, targetY) {
if (self.diving) return;
self.diving = true;
// Calculate direction
var dirX = targetX - self.x;
var dirY = targetY - self.y;
// Normalize and limit dive distance
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > self.saveRange) {
dirX = dirX / length * self.saveRange;
dirY = dirY / length * self.saveRange;
}
self.divingDirection = {
x: dirX,
y: dirY
};
// Animate the dive
tween(self, {
x: self.x + dirX,
y: self.y + dirY
}, {
duration: 500,
easing: tween.easeOut
});
};
// AI make a decision to dive
self.aiDecide = function (ball) {
if (!self.isAI || self.diving || !ball.inMotion) return;
// Calculate where the ball will be
var futureX = ball.x + ball.velocity.x * 10;
var futureY = ball.y + ball.velocity.y * 10;
// Add some randomness to make it challenging
var difficulty = gameState.round * 0.1; // 0.1 to 1.0 based on round
var accuracy = Math.min(0.9, 0.5 + difficulty); // 50% to 90% accuracy
if (Math.random() < accuracy) {
// Good prediction
self.dive(futureX, futureY);
} else {
// Inaccurate dive
self.dive(futureX + (Math.random() * 400 - 200), futureY + (Math.random() * 200 - 100));
}
};
// Move goalkeeper left and right
self.moveLeft = function () {
if (self.diving) return;
var targetX = Math.max(goalArea.x + goalArea.leftX + 100, self.x - 150);
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
};
self.moveRight = function () {
if (self.diving) return;
var targetX = Math.min(goalArea.x + goalArea.rightX - 100, self.x + 150);
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
};
// Auto movement for goalkeeper
self.autoMove = function () {
if (self.diving) return;
// Move to random position within goal area
var minX = goalArea.x + goalArea.leftX + 100;
var maxX = goalArea.x + goalArea.rightX - 100;
var targetX = minX + Math.random() * (maxX - minX);
tween(self, {
x: targetX
}, {
duration: 500,
easing: tween.easeInOut
});
};
// Reset keeper position
self.reset = function () {
self.diving = false;
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 500,
easing: tween.easeOut
});
};
// Check if ball touches goalkeeper (collision detection)
self.checkCollision = function (ball) {
if (ball.saved || ball.scored) return false;
// Calculate distance between ball and keeper
var dx = ball.x - self.x;
var dy = ball.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If ball touches keeper, it's a save
if (distance < 120) {
ball.saved = true;
ball.inMotion = false;
// Stop the ball's tween animation
tween.stop(ball, {
x: true,
y: true
});
// Position ball at goalkeeper's location
ball.x = self.x;
ball.y = self.y;
LK.getSound('save').play();
return true;
}
return false;
};
// Check if keeper saved the ball
self.checkSave = function (ball) {
return self.checkCollision(ball);
};
return self;
});
var PowerMeter = Container.expand(function () {
var self = Container.call(this);
// Power meter background
var meterBg = self.attachAsset('power_meter', {
anchorX: 0.5,
anchorY: 1.0
});
// Power indicator
var indicator = self.attachAsset('power_indicator', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20
});
// Power meter properties
self.active = false;
self.increasing = true;
self.power = 0; // 0 to 1
self.maxPower = 1;
// Start power meter
self.start = function () {
self.active = true;
self.increasing = true;
self.power = 0;
self.updateIndicator();
};
// Stop and get final power
self.stop = function () {
self.active = false;
return self.power;
};
// Update power value
self.update = function () {
if (!self.active) return;
// Increase or decrease power
if (self.increasing) {
self.power += 0.02;
if (self.power >= self.maxPower) {
self.power = self.maxPower;
self.increasing = false;
}
} else {
self.power -= 0.02;
if (self.power <= 0) {
self.power = 0;
self.increasing = true;
}
}
self.updateIndicator();
};
// Update indicator position
self.updateIndicator = function () {
indicator.y = -meterBg.height * self.power;
// Change color based on power
if (self.power < 0.3) {
indicator.tint = 0x00FF00; // Green for low power
} else if (self.power < 0.7) {
indicator.tint = 0xFFFF00; // Yellow for medium power
} else {
indicator.tint = 0xFF0000; // Red for high power
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game state
var gameState = {
mode: "shooting",
round: storage.currentRound || 1,
scorePlayer: 0,
shotsPlayer: 0,
totalShots: 5
};
// Game elements
var ball, goalkeeper, goalArea, powerMeter;
var targetMarker;
var shootButton, nextButton;
// UI elements
var scoreText, roundText, instructionText;
// Initialize the game
function initGame() {
// Create goal area
goalArea = new GoalArea();
goalArea.x = 2048 / 2;
goalArea.y = 500;
game.addChild(goalArea);
// Create ball
ball = new Ball();
ball.reset(true);
game.addChild(ball);
// Create goalkeeper
goalkeeper = new Goalkeeper();
goalkeeper.init(false); // Player goalkeeper
game.addChild(goalkeeper);
// Create target marker for aiming
targetMarker = LK.getAsset('target', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
visible: false
});
game.addChild(targetMarker);
// Create power meter
powerMeter = new PowerMeter();
powerMeter.x = 100;
powerMeter.y = 2200;
powerMeter.visible = false;
game.addChild(powerMeter);
// Create shoot button
shootButton = new Button();
shootButton.x = 2048 - 200;
shootButton.y = 2500;
shootButton.setText("SHOOT");
shootButton.visible = false;
shootButton.onClick = function () {
if (gameState.mode === "shooting" && targetMarker.visible) {
var power = powerMeter.stop();
ball.kick(targetMarker.x, targetMarker.y, power);
targetMarker.visible = false;
shootButton.visible = false;
powerMeter.visible = false;
}
};
game.addChild(shootButton);
// Create next button
nextButton = new Button();
nextButton.x = 2048 / 2;
nextButton.y = 2500;
nextButton.setText("NEXT");
nextButton.visible = false;
nextButton.onClick = function () {
if (gameState.mode === "results") {
advanceTurn();
}
};
game.addChild(nextButton);
// Create score text
scoreText = new Text2("Score: 0", {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create round text
roundText = new Text2("Round " + gameState.round, {
size: 60,
fill: 0xFFFFFF
});
roundText.anchor.set(0.5, 0);
roundText.y = 100;
LK.gui.top.addChild(roundText);
// Create instruction text
instructionText = new Text2("Tap to aim, then tap SHOOT", {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 200;
LK.gui.top.addChild(instructionText);
// Start with player shooting
startShootingMode();
// Start background music
LK.playMusic('background_music');
}
// Start shooting mode (player kicks)
function startShootingMode() {
gameState.mode = "shooting";
// Set up scene
ball.reset(true);
goalkeeper.reset();
goalkeeper.visible = true;
goalkeeper.controlBar.visible = false;
// Position goalkeeper at random starting position for each round
var randomStartX = goalkeeper.originalX + (Math.random() - 0.5) * 400; // ±200 pixels from center
goalkeeper.x = randomStartX;
// Start goalkeeper auto movement
var keeperMoveTimer = LK.setInterval(function () {
if (gameState.mode === "shooting" && !ball.inMotion) {
goalkeeper.autoMove();
}
}, 1500 + Math.random() * 1000);
// Update UI
updateScoreText();
instructionText.setText("Tap to aim, then tap SHOOT");
// Reset target and power
targetMarker.visible = false;
powerMeter.visible = false;
shootButton.visible = false;
}
// Show results and next button
function showResults(isGoal) {
gameState.mode = "results";
gameState.shotsPlayer++;
if (isGoal) {
gameState.scorePlayer++;
storage.playerGoals++;
instructionText.setText("GOAL! You scored!");
} else {
instructionText.setText("SAVED! The goalkeeper stopped your shot!");
}
updateScoreText();
nextButton.visible = true;
}
// Advance to next turn or round
function advanceTurn() {
nextButton.visible = false;
// Check if round is complete
if (gameState.shotsPlayer >= gameState.totalShots) {
endRound();
} else {
startShootingMode();
}
}
// End current round and check results
function endRound() {
// Update storage
storage.gamesPlayed++;
// Update high score
if (gameState.scorePlayer > storage.highScore) {
storage.highScore = gameState.scorePlayer;
}
// Check if 5 rounds are completed
if (gameState.round >= 5) {
// Show PERFECT message
instructionText.setText("PERFECT");
return;
}
// Advance to next round
gameState.round++;
storage.currentRound = gameState.round;
instructionText.setText("Round " + (gameState.round - 1) + " complete! Score: " + gameState.scorePlayer + "/" + gameState.totalShots + ". Moving to Round " + gameState.round);
// Reset scores for next round
gameState.scorePlayer = 0;
gameState.shotsPlayer = 0;
// Start new round after delay
LK.setTimeout(function () {
roundText.setText("Round " + gameState.round);
startShootingMode();
}, 2000);
}
// Update score display
function updateScoreText() {
scoreText.setText("Score: " + gameState.scorePlayer + "/" + gameState.totalShots);
}
// Game input handlers
game.down = function (x, y, obj) {
if (gameState.mode === "shooting") {
// Set target for aiming
if (y < 1200) {
// Only allow targeting in the goal area
targetMarker.x = x;
targetMarker.y = y;
targetMarker.visible = true;
// Show shoot button and power meter
shootButton.visible = true;
powerMeter.visible = true;
powerMeter.start();
}
}
};
// Game loop
game.update = function () {
// Update ball physics
ball.update();
// Update power meter
powerMeter.update();
// AI goalkeeper decision making
if (gameState.mode === "shooting") {
goalkeeper.aiDecide(ball);
// Check if ball touches goalkeeper (collision detection)
if (ball.inMotion && goalkeeper.checkCollision(ball)) {
LK.setTimeout(function () {
showResults(false);
}, 1000);
}
// Check if ball went in goal
if (ball.inMotion && goalArea.checkGoal(ball)) {
LK.setTimeout(function () {
showResults(true);
}, 1000);
}
}
// Check if ball is out of bounds or stopped
if (ball.inMotion && (ball.x < 0 || ball.x > 2048 || ball.y < 0 || ball.y > 2732 || ball.y < 400 && !ball.scored && !ball.saved && !ball.inMotion)) {
// Ball went out or stopped, count as a miss
ball.inMotion = false;
LK.setTimeout(function () {
showResults(false);
}, 1000);
}
};
// Initialize the game
initGame();