/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.friction = 0.98; self.bounceReduction = 0.7; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Apply friction self.velocityX *= self.friction; self.velocityY *= self.friction; // Bounce off field boundaries if (self.x <= 50 || self.x >= 1998) { self.velocityX *= -self.bounceReduction; self.x = Math.max(50, Math.min(1998, self.x)); } if (self.y <= 300 || self.y >= 1650) { self.velocityY *= -self.bounceReduction; self.y = Math.max(300, Math.min(1650, self.y)); } }; return self; }); var Goalkeeper = Container.expand(function () { var self = Container.call(this); var keeperGraphics = self.attachAsset('goalkeeper', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.targetX = 1024; self.update = function () { // Only move if goalkeeper is active (ball has been kicked) if (goalkeeperActive) { // More frequent and aggressive movement every 15 ticks (0.25 seconds) if (LK.ticks % 15 === 0) { self.targetX = 874 + Math.random() * 300; // Random position within goal area } var diffX = self.targetX - self.x; if (Math.abs(diffX) > 2) { self.x += diffX > 0 ? self.speed : -self.speed; } // Keep goalkeeper within goal area self.x = Math.max(874, Math.min(1174, self.x)); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2E7D32 }); /**** * Game Code ****/ // Game field var field = game.addChild(LK.getAsset('field', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 975 })); // Goal var goal = game.addChild(LK.getAsset('goal', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 200 })); // Goal line (white line marking the goal) var goalLine = game.addChild(LK.getAsset('goalLine', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 300 })); // Player var player = game.addChild(new Player()); player.x = 1024; player.y = 1400; // Penalty spot var penaltySpot = game.addChild(LK.getAsset('penaltySpot', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1000 })); // Ball var ball = game.addChild(new Ball()); ball.x = 1024; ball.y = 1000; // Goalkeeper var goalkeeper = game.addChild(new Goalkeeper()); goalkeeper.x = 1024; goalkeeper.y = 250; // Game variables var gameStarted = false; var dragNode = null; var lastBallDistance = 0; var lastPlayerX = 0; var lastPlayerY = 0; var playerVelocityX = 0; var playerVelocityY = 0; var goalkeeperActive = false; var ballKicked = false; var ballActionComplete = false; var playerLives = 3; var consecutiveGoals = 0; var shotTimer = 10; var shotTimerActive = true; var ballLastY = 1000; // Track ball's previous Y position for goal line crossing detection var playersCanMove = true; // Flag to control player movement when text is displayed var gamePaused = false; // Flag to pause entire game system during text display // UI Elements - Hearts display with 5 fixed containers var heartContainers = []; var heartIcons = []; var heartsContainer = new Container(); LK.gui.bottom.addChild(heartsContainer); heartsContainer.x = 0; heartsContainer.y = -120; // Create 5 fixed heart container frames for (var i = 0; i < 5; i++) { // Create outer frame (always visible) var heartFrame = LK.getAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); heartFrame.x = (i - 2) * 80; // Center 5 hearts around container heartFrame.y = 0; heartFrame.alpha = 0.3; // Make frame semi-transparent heartFrame.tint = 0x888888; // Gray color for empty frames heartsContainer.addChild(heartFrame); heartContainers.push(heartFrame); // Create heart icon (visibility based on lives) var heartIcon = LK.getAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); heartIcon.x = (i - 2) * 80; // Same position as frame heartIcon.y = 0; heartIcon.visible = i < playerLives; // Show based on current lives heartsContainer.addChild(heartIcon); heartIcons.push(heartIcon); } // Persistent score display above hearts var persistentScoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); persistentScoreText.anchor.set(0.5, 1); LK.gui.bottom.addChild(persistentScoreText); persistentScoreText.y = -200; // Streak display above score var streakText = new Text2('Streak: 0', { size: 50, fill: 0xFFD700 }); streakText.anchor.set(0.5, 1); LK.gui.bottom.addChild(streakText); streakText.y = -260; // Goal text display var goalText = new Text2('GOOOL!', { size: 120, fill: 0xFFD700 }); goalText.anchor.set(0.5, 0.5); goalText.visible = false; LK.gui.center.addChild(goalText); var scoreText = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0.5); scoreText.visible = false; LK.gui.center.addChild(scoreText); scoreText.y = 80; // Saved text display var savedText = new Text2('SAVED!', { size: 120, fill: 0xFF4444 }); savedText.anchor.set(0.5, 0.5); savedText.visible = false; LK.gui.center.addChild(savedText); function updateHeartsDisplay() { // Update visibility of heart icons based on current lives for (var i = 0; i < 5; i++) { heartIcons[i].visible = i < playerLives; } } // Initialize hearts display updateHeartsDisplay(); var shotTimerText = new Text2('Shot Timer: 10', { size: 60, fill: 0xFFFF00 }); shotTimerText.anchor.set(0.5, 1); LK.gui.bottom.addChild(shotTimerText); // Game timer var gameTimer = LK.setInterval(function () { // Shot timer countdown (only if ball hasn't been kicked yet) if (shotTimerActive && shotTimer > 0 && !ballKicked) { shotTimer--; shotTimerText.setText('Shot Timer: ' + shotTimer); if (shotTimer <= 0) { // Time up - lose a life playerLives--; consecutiveGoals = 0; streakText.setText('Streak: ' + consecutiveGoals); updateHeartsDisplay(); if (playerLives <= 0) { LK.showGameOver(); return; } // Reset game to initial state ball.x = 1024; ball.y = 1000; ball.velocityX = 0; ball.velocityY = 0; ballLastY = 1000; // Reset ball last Y position player.x = 1024; player.y = 1400; goalkeeper.x = 1024; goalkeeper.y = 250; goalkeeperActive = false; ballKicked = false; ballActionComplete = false; shotTimer = 10; // Reset shot timer for next attempt shotTimerActive = true; // Reactivate shot timer shotTimerText.setText('Shot Timer: 10'); penaltySpot.visible = true; // Show penalty spot again } } }, 1000); // Input handling game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; } if (playersCanMove) { dragNode = player; } }; game.move = function (x, y, obj) { if (dragNode && gameStarted && playersCanMove) { // Track player velocity for kick calculation playerVelocityX = x - dragNode.x; playerVelocityY = y - dragNode.y; dragNode.x = Math.max(50, Math.min(1998, x)); dragNode.y = Math.max(600, Math.min(1650, y)); } }; game.up = function (x, y, obj) { if (playersCanMove) { dragNode = null; } }; // Game update loop game.update = function () { if (!gameStarted) return; if (gamePaused) return; // Stop all game logic when paused // Check player-ball collision for kicking var playerBallDistance = Math.sqrt(Math.pow(player.x - ball.x, 2) + Math.pow(player.y - ball.y, 2)); if (playerBallDistance < 60 && lastBallDistance >= 60 && !ballKicked) { // Calculate kick direction based on player movement and ball position var ballDirection = Math.atan2(ball.y - player.y, ball.x - player.x); // Base kick power on player velocity magnitude var velocityMagnitude = Math.sqrt(playerVelocityX * playerVelocityX + playerVelocityY * playerVelocityY); var kickPower = Math.max(8, Math.min(20, velocityMagnitude * 2)); // Power between 8-20 // If player has significant velocity, use movement direction, otherwise use ball direction var kickAngle; if (velocityMagnitude > 2) { kickAngle = Math.atan2(playerVelocityY, playerVelocityX); } else { kickAngle = ballDirection; } ball.velocityX = Math.cos(kickAngle) * kickPower; ball.velocityY = Math.sin(kickAngle) * kickPower; goalkeeperActive = true; // Activate goalkeeper movement ballKicked = true; // Mark ball as kicked shotTimer = 10; // Reset to 10 seconds for next shot penaltySpot.visible = false; // Hide penalty spot after ball is kicked LK.getSound('kick').play(); } lastBallDistance = playerBallDistance; // Increase goalkeeper speed based on score goalkeeper.speed = 4 + LK.getScore() * 0.5; // Check goalkeeper collision (save) var keeperBallDistance = Math.sqrt(Math.pow(goalkeeper.x - ball.x, 2) + Math.pow(goalkeeper.y - ball.y, 2)); if (keeperBallDistance < 80 && ball.y <= 350 && ballKicked && !ballActionComplete) { // Goalkeeper save LK.getSound('save').play(); ball.velocityX = 0; ball.velocityY = 0; ballActionComplete = true; // Decrease lives by 1 when goalkeeper saves playerLives--; consecutiveGoals = 0; // Reset consecutive goals on save streakText.setText('Streak: ' + consecutiveGoals); updateHeartsDisplay(); // Check if player lost (no lives remaining) if (playerLives <= 0) { LK.showGameOver(); return; } // Show saved text savedText.visible = true; playersCanMove = false; // Disable player movement while text is shown gamePaused = true; // Pause entire game system while text is shown // Animate saved text tween(savedText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(savedText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } }); // Hide saved text and reset game after 10 seconds LK.setTimeout(function () { savedText.visible = false; playersCanMove = true; // Re-enable player movement when text is hidden gamePaused = false; // Resume game system when text is hidden // Reset game to initial state ball.x = 1024; ball.y = 1000; ball.velocityX = 0; ball.velocityY = 0; ballLastY = 1000; // Reset ball last Y position player.x = 1024; player.y = 1400; goalkeeper.x = 1024; goalkeeper.y = 250; goalkeeperActive = false; ballKicked = false; ballActionComplete = false; shotTimer = 10; // Reset shot timer for next attempt shotTimerActive = true; // Reactivate shot timer shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display penaltySpot.visible = true; // Show penalty spot again }, 10000); } // Check goal scoring (ball crosses goal line) - improved detection // Check if ball crossed the goal line (Y=300) from above and is within goal width // Expanded goal area to include shots near the goalpost edges if (ball.x >= 824 && ball.x <= 1224 && ballLastY > 300 && ball.y <= 300) { // Goal scored! LK.setScore(LK.getScore() + 1); persistentScoreText.setText('Score: ' + LK.getScore()); consecutiveGoals++; streakText.setText('Streak: ' + consecutiveGoals); // Increase lives every 2 consecutive goals, max 5 lives if (consecutiveGoals >= 2 && playerLives < 5) { playerLives++; updateHeartsDisplay(); consecutiveGoals = 0; // Reset consecutive goals counter streakText.setText('Streak: ' + consecutiveGoals); } LK.getSound('goal').play(); // Flash effect LK.effects.flashScreen(0x00FF00, 500); // Show goal text with score goalText.visible = true; scoreText.setText('Score: ' + LK.getScore()); scoreText.visible = true; playersCanMove = false; // Disable player movement while text is shown gamePaused = true; // Pause entire game system while text is shown // Animate goal text tween(goalText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(goalText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } }); // Hide goal text and reset game after 6 seconds LK.setTimeout(function () { goalText.visible = false; scoreText.visible = false; playersCanMove = true; // Re-enable player movement when text is hidden gamePaused = false; // Resume game system when text is hidden // Reset game to initial state ball.x = 1024; ball.y = 1000; ball.velocityX = 0; ball.velocityY = 0; ballLastY = 1000; // Reset ball last Y position player.x = 1024; player.y = 1400; goalkeeper.x = 1024; goalkeeper.y = 250; goalkeeperActive = false; ballKicked = false; // Allow player to kick again ballActionComplete = false; // Reset action complete flag shotTimer = 10; // Reset shot timer for next attempt shotTimerActive = true; // Reactivate shot timer shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display penaltySpot.visible = true; // Show penalty spot again }, 6000); } // Check goalpost collision (left and right posts) if (ball.y <= 334 && ball.y >= 66) { // Ball is at goal height // Left goalpost collision if (ball.x >= 820 && ball.x <= 874 && ball.velocityX > 0) { ball.velocityX *= -0.8; ball.x = 820; // Push ball away from post // Visual effects LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash tween(goal, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(goal, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeIn }); } }); } // Right goalpost collision if (ball.x >= 1174 && ball.x <= 1228 && ball.velocityX < 0) { ball.velocityX *= -0.8; ball.x = 1228; // Push ball away from post // Visual effects LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash tween(goal, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(goal, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeIn }); } }); } } // Check crossbar collision if (ball.y >= 66 && ball.y <= 120 && ball.x >= 824 && ball.x <= 1224 && ball.velocityY < 0) { ball.velocityY *= -0.8; ball.y = 120; // Push ball down from crossbar // Visual effects LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash tween(goal, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(goal, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeIn }); } }); } // Check if ball goes behind goal line but outside goal if (ball.y <= 100) { ball.y = 100; ball.velocityY *= -0.7; } // Check if ball action is complete (ball has stopped moving after being kicked) if (ballKicked && !ballActionComplete) { var ballSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY); if (ballSpeed < 0.5) { // Ball has stopped, action is complete ballActionComplete = true; // Decrease lives by 1 if no goal was scored (miss) playerLives--; consecutiveGoals = 0; // Reset consecutive goals on miss streakText.setText('Streak: ' + consecutiveGoals); updateHeartsDisplay(); // Check if player lost (no lives remaining) if (playerLives <= 0) { LK.showGameOver(); return; } // Reset game to initial state ball.x = 1024; ball.y = 1000; ball.velocityX = 0; ball.velocityY = 0; ballLastY = 1000; // Reset ball last Y position player.x = 1024; player.y = 1400; goalkeeper.x = 1024; goalkeeper.y = 250; goalkeeperActive = false; ballKicked = false; ballActionComplete = false; shotTimer = 10; // Reset shot timer for next attempt shotTimerActive = true; // Reactivate shot timer shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display penaltySpot.visible = true; // Show penalty spot again } } // Update ball's last Y position for next frame ballLastY = ball.y; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.friction = 0.98;
self.bounceReduction = 0.7;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Bounce off field boundaries
if (self.x <= 50 || self.x >= 1998) {
self.velocityX *= -self.bounceReduction;
self.x = Math.max(50, Math.min(1998, self.x));
}
if (self.y <= 300 || self.y >= 1650) {
self.velocityY *= -self.bounceReduction;
self.y = Math.max(300, Math.min(1650, self.y));
}
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 1024;
self.update = function () {
// Only move if goalkeeper is active (ball has been kicked)
if (goalkeeperActive) {
// More frequent and aggressive movement every 15 ticks (0.25 seconds)
if (LK.ticks % 15 === 0) {
self.targetX = 874 + Math.random() * 300; // Random position within goal area
}
var diffX = self.targetX - self.x;
if (Math.abs(diffX) > 2) {
self.x += diffX > 0 ? self.speed : -self.speed;
}
// Keep goalkeeper within goal area
self.x = Math.max(874, Math.min(1174, self.x));
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E7D32
});
/****
* Game Code
****/
// Game field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 975
}));
// Goal
var goal = game.addChild(LK.getAsset('goal', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 200
}));
// Goal line (white line marking the goal)
var goalLine = game.addChild(LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 300
}));
// Player
var player = game.addChild(new Player());
player.x = 1024;
player.y = 1400;
// Penalty spot
var penaltySpot = game.addChild(LK.getAsset('penaltySpot', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1000
}));
// Ball
var ball = game.addChild(new Ball());
ball.x = 1024;
ball.y = 1000;
// Goalkeeper
var goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = 1024;
goalkeeper.y = 250;
// Game variables
var gameStarted = false;
var dragNode = null;
var lastBallDistance = 0;
var lastPlayerX = 0;
var lastPlayerY = 0;
var playerVelocityX = 0;
var playerVelocityY = 0;
var goalkeeperActive = false;
var ballKicked = false;
var ballActionComplete = false;
var playerLives = 3;
var consecutiveGoals = 0;
var shotTimer = 10;
var shotTimerActive = true;
var ballLastY = 1000; // Track ball's previous Y position for goal line crossing detection
var playersCanMove = true; // Flag to control player movement when text is displayed
var gamePaused = false; // Flag to pause entire game system during text display
// UI Elements - Hearts display with 5 fixed containers
var heartContainers = [];
var heartIcons = [];
var heartsContainer = new Container();
LK.gui.bottom.addChild(heartsContainer);
heartsContainer.x = 0;
heartsContainer.y = -120;
// Create 5 fixed heart container frames
for (var i = 0; i < 5; i++) {
// Create outer frame (always visible)
var heartFrame = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heartFrame.x = (i - 2) * 80; // Center 5 hearts around container
heartFrame.y = 0;
heartFrame.alpha = 0.3; // Make frame semi-transparent
heartFrame.tint = 0x888888; // Gray color for empty frames
heartsContainer.addChild(heartFrame);
heartContainers.push(heartFrame);
// Create heart icon (visibility based on lives)
var heartIcon = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heartIcon.x = (i - 2) * 80; // Same position as frame
heartIcon.y = 0;
heartIcon.visible = i < playerLives; // Show based on current lives
heartsContainer.addChild(heartIcon);
heartIcons.push(heartIcon);
}
// Persistent score display above hearts
var persistentScoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
persistentScoreText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(persistentScoreText);
persistentScoreText.y = -200;
// Streak display above score
var streakText = new Text2('Streak: 0', {
size: 50,
fill: 0xFFD700
});
streakText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(streakText);
streakText.y = -260;
// Goal text display
var goalText = new Text2('GOOOL!', {
size: 120,
fill: 0xFFD700
});
goalText.anchor.set(0.5, 0.5);
goalText.visible = false;
LK.gui.center.addChild(goalText);
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0.5);
scoreText.visible = false;
LK.gui.center.addChild(scoreText);
scoreText.y = 80;
// Saved text display
var savedText = new Text2('SAVED!', {
size: 120,
fill: 0xFF4444
});
savedText.anchor.set(0.5, 0.5);
savedText.visible = false;
LK.gui.center.addChild(savedText);
function updateHeartsDisplay() {
// Update visibility of heart icons based on current lives
for (var i = 0; i < 5; i++) {
heartIcons[i].visible = i < playerLives;
}
}
// Initialize hearts display
updateHeartsDisplay();
var shotTimerText = new Text2('Shot Timer: 10', {
size: 60,
fill: 0xFFFF00
});
shotTimerText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(shotTimerText);
// Game timer
var gameTimer = LK.setInterval(function () {
// Shot timer countdown (only if ball hasn't been kicked yet)
if (shotTimerActive && shotTimer > 0 && !ballKicked) {
shotTimer--;
shotTimerText.setText('Shot Timer: ' + shotTimer);
if (shotTimer <= 0) {
// Time up - lose a life
playerLives--;
consecutiveGoals = 0;
streakText.setText('Streak: ' + consecutiveGoals);
updateHeartsDisplay();
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Reset game to initial state
ball.x = 1024;
ball.y = 1000;
ball.velocityX = 0;
ball.velocityY = 0;
ballLastY = 1000; // Reset ball last Y position
player.x = 1024;
player.y = 1400;
goalkeeper.x = 1024;
goalkeeper.y = 250;
goalkeeperActive = false;
ballKicked = false;
ballActionComplete = false;
shotTimer = 10; // Reset shot timer for next attempt
shotTimerActive = true; // Reactivate shot timer
shotTimerText.setText('Shot Timer: 10');
penaltySpot.visible = true; // Show penalty spot again
}
}
}, 1000);
// Input handling
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
}
if (playersCanMove) {
dragNode = player;
}
};
game.move = function (x, y, obj) {
if (dragNode && gameStarted && playersCanMove) {
// Track player velocity for kick calculation
playerVelocityX = x - dragNode.x;
playerVelocityY = y - dragNode.y;
dragNode.x = Math.max(50, Math.min(1998, x));
dragNode.y = Math.max(600, Math.min(1650, y));
}
};
game.up = function (x, y, obj) {
if (playersCanMove) {
dragNode = null;
}
};
// Game update loop
game.update = function () {
if (!gameStarted) return;
if (gamePaused) return; // Stop all game logic when paused
// Check player-ball collision for kicking
var playerBallDistance = Math.sqrt(Math.pow(player.x - ball.x, 2) + Math.pow(player.y - ball.y, 2));
if (playerBallDistance < 60 && lastBallDistance >= 60 && !ballKicked) {
// Calculate kick direction based on player movement and ball position
var ballDirection = Math.atan2(ball.y - player.y, ball.x - player.x);
// Base kick power on player velocity magnitude
var velocityMagnitude = Math.sqrt(playerVelocityX * playerVelocityX + playerVelocityY * playerVelocityY);
var kickPower = Math.max(8, Math.min(20, velocityMagnitude * 2)); // Power between 8-20
// If player has significant velocity, use movement direction, otherwise use ball direction
var kickAngle;
if (velocityMagnitude > 2) {
kickAngle = Math.atan2(playerVelocityY, playerVelocityX);
} else {
kickAngle = ballDirection;
}
ball.velocityX = Math.cos(kickAngle) * kickPower;
ball.velocityY = Math.sin(kickAngle) * kickPower;
goalkeeperActive = true; // Activate goalkeeper movement
ballKicked = true; // Mark ball as kicked
shotTimer = 10; // Reset to 10 seconds for next shot
penaltySpot.visible = false; // Hide penalty spot after ball is kicked
LK.getSound('kick').play();
}
lastBallDistance = playerBallDistance;
// Increase goalkeeper speed based on score
goalkeeper.speed = 4 + LK.getScore() * 0.5;
// Check goalkeeper collision (save)
var keeperBallDistance = Math.sqrt(Math.pow(goalkeeper.x - ball.x, 2) + Math.pow(goalkeeper.y - ball.y, 2));
if (keeperBallDistance < 80 && ball.y <= 350 && ballKicked && !ballActionComplete) {
// Goalkeeper save
LK.getSound('save').play();
ball.velocityX = 0;
ball.velocityY = 0;
ballActionComplete = true;
// Decrease lives by 1 when goalkeeper saves
playerLives--;
consecutiveGoals = 0; // Reset consecutive goals on save
streakText.setText('Streak: ' + consecutiveGoals);
updateHeartsDisplay();
// Check if player lost (no lives remaining)
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Show saved text
savedText.visible = true;
playersCanMove = false; // Disable player movement while text is shown
gamePaused = true; // Pause entire game system while text is shown
// Animate saved text
tween(savedText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(savedText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// Hide saved text and reset game after 10 seconds
LK.setTimeout(function () {
savedText.visible = false;
playersCanMove = true; // Re-enable player movement when text is hidden
gamePaused = false; // Resume game system when text is hidden
// Reset game to initial state
ball.x = 1024;
ball.y = 1000;
ball.velocityX = 0;
ball.velocityY = 0;
ballLastY = 1000; // Reset ball last Y position
player.x = 1024;
player.y = 1400;
goalkeeper.x = 1024;
goalkeeper.y = 250;
goalkeeperActive = false;
ballKicked = false;
ballActionComplete = false;
shotTimer = 10; // Reset shot timer for next attempt
shotTimerActive = true; // Reactivate shot timer
shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display
penaltySpot.visible = true; // Show penalty spot again
}, 10000);
}
// Check goal scoring (ball crosses goal line) - improved detection
// Check if ball crossed the goal line (Y=300) from above and is within goal width
// Expanded goal area to include shots near the goalpost edges
if (ball.x >= 824 && ball.x <= 1224 && ballLastY > 300 && ball.y <= 300) {
// Goal scored!
LK.setScore(LK.getScore() + 1);
persistentScoreText.setText('Score: ' + LK.getScore());
consecutiveGoals++;
streakText.setText('Streak: ' + consecutiveGoals);
// Increase lives every 2 consecutive goals, max 5 lives
if (consecutiveGoals >= 2 && playerLives < 5) {
playerLives++;
updateHeartsDisplay();
consecutiveGoals = 0; // Reset consecutive goals counter
streakText.setText('Streak: ' + consecutiveGoals);
}
LK.getSound('goal').play();
// Flash effect
LK.effects.flashScreen(0x00FF00, 500);
// Show goal text with score
goalText.visible = true;
scoreText.setText('Score: ' + LK.getScore());
scoreText.visible = true;
playersCanMove = false; // Disable player movement while text is shown
gamePaused = true; // Pause entire game system while text is shown
// Animate goal text
tween(goalText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goalText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// Hide goal text and reset game after 6 seconds
LK.setTimeout(function () {
goalText.visible = false;
scoreText.visible = false;
playersCanMove = true; // Re-enable player movement when text is hidden
gamePaused = false; // Resume game system when text is hidden
// Reset game to initial state
ball.x = 1024;
ball.y = 1000;
ball.velocityX = 0;
ball.velocityY = 0;
ballLastY = 1000; // Reset ball last Y position
player.x = 1024;
player.y = 1400;
goalkeeper.x = 1024;
goalkeeper.y = 250;
goalkeeperActive = false;
ballKicked = false; // Allow player to kick again
ballActionComplete = false; // Reset action complete flag
shotTimer = 10; // Reset shot timer for next attempt
shotTimerActive = true; // Reactivate shot timer
shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display
penaltySpot.visible = true; // Show penalty spot again
}, 6000);
}
// Check goalpost collision (left and right posts)
if (ball.y <= 334 && ball.y >= 66) {
// Ball is at goal height
// Left goalpost collision
if (ball.x >= 820 && ball.x <= 874 && ball.velocityX > 0) {
ball.velocityX *= -0.8;
ball.x = 820; // Push ball away from post
// Visual effects
LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash
tween(goal, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goal, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Right goalpost collision
if (ball.x >= 1174 && ball.x <= 1228 && ball.velocityX < 0) {
ball.velocityX *= -0.8;
ball.x = 1228; // Push ball away from post
// Visual effects
LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash
tween(goal, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goal, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
}
// Check crossbar collision
if (ball.y >= 66 && ball.y <= 120 && ball.x >= 824 && ball.x <= 1224 && ball.velocityY < 0) {
ball.velocityY *= -0.8;
ball.y = 120; // Push ball down from crossbar
// Visual effects
LK.effects.flashScreen(0xFFFF00, 300); // Yellow flash
tween(goal, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goal, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Check if ball goes behind goal line but outside goal
if (ball.y <= 100) {
ball.y = 100;
ball.velocityY *= -0.7;
}
// Check if ball action is complete (ball has stopped moving after being kicked)
if (ballKicked && !ballActionComplete) {
var ballSpeed = Math.sqrt(ball.velocityX * ball.velocityX + ball.velocityY * ball.velocityY);
if (ballSpeed < 0.5) {
// Ball has stopped, action is complete
ballActionComplete = true;
// Decrease lives by 1 if no goal was scored (miss)
playerLives--;
consecutiveGoals = 0; // Reset consecutive goals on miss
streakText.setText('Streak: ' + consecutiveGoals);
updateHeartsDisplay();
// Check if player lost (no lives remaining)
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Reset game to initial state
ball.x = 1024;
ball.y = 1000;
ball.velocityX = 0;
ball.velocityY = 0;
ballLastY = 1000; // Reset ball last Y position
player.x = 1024;
player.y = 1400;
goalkeeper.x = 1024;
goalkeeper.y = 250;
goalkeeperActive = false;
ballKicked = false;
ballActionComplete = false;
shotTimer = 10; // Reset shot timer for next attempt
shotTimerActive = true; // Reactivate shot timer
shotTimerText.setText('Shot Timer: 10'); // Reset shot timer display
penaltySpot.visible = true; // Show penalty spot again
}
}
// Update ball's last Y position for next frame
ballLastY = ball.y;
};