User prompt
kaleciye top değidiği zaman gol sayılıyor bu olmasın kale çizgisi beyaz olarak belirlensin
User prompt
kale sahanın dışında olsun kaleci topa vurulduktan sonra hareket etsin
User prompt
karakter topa dokununca top direk kaleye gidiyor topa dokunuş açısına ve hızına göre top kaleye gitsin kalecide rastgele bir şekilde hareket etsin
Code edit (1 edits merged)
Please save this source code
User prompt
Pocket Soccer Strike
Initial prompt
Başkan bana 2d futbol oyunu yap
/**** * 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;
};