/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// LK engine handles pause/play functionality automatically through built-in systems
var BotGoalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.0
});
keeperGraphics.tint = 0xff6666; // Red tint for bot
self.targetX = 1024;
self.reactionTime = 0;
self.maxReactionDelay = 30; // frames
self.update = function () {
// Bot AI movement with reaction delay
if (self.reactionTime > 0) {
self.reactionTime--;
return;
}
// Find closest active ball
var closestBall = null;
var closestDistance = Infinity;
for (var i = 0; i < balls.length; i++) {
if (balls[i].active && balls[i].y < 1000) {
// Only react to balls in upper half
var distance = Math.abs(balls[i].x - self.x);
if (distance < closestDistance) {
closestDistance = distance;
closestBall = balls[i];
}
}
}
if (closestBall) {
// Predict where ball will be
var predictedX = closestBall.x + closestBall.speedX * 20;
self.targetX = predictedX;
// Add some error for difficulty
self.targetX += (Math.random() - 0.5) * 200;
}
// Move toward target
var dx = self.targetX - self.x;
if (Math.abs(dx) > 5) {
self.x += dx * 0.15; // Slightly slower than player
}
// Keep within bounds
var goalLeft = 424;
var goalRight = 1624;
self.x = Math.max(goalLeft, Math.min(goalRight, self.x));
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 1.0
});
self.targetX = 1024; // Center of goal
self.moveSpeed = 15;
self.update = function () {
// Smooth movement toward target position
var dx = self.targetX - self.x;
if (Math.abs(dx) > 5) {
self.x += dx * 0.2;
}
};
self.setTarget = function (x) {
// Keep goalkeeper within goal bounds
var goalLeft = 424;
var goalRight = 1624;
self.targetX = Math.max(goalLeft, Math.min(goalRight, x));
};
return self;
});
var SoccerBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('soccerBall', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.active = true;
self.update = function () {
if (!self.active) return;
self.x += self.speedX;
self.y += self.speedY;
// Add slight gravity effect
self.speedY += 0.2;
// Add curve effect if it exists
if (self.curveX) {
self.speedX += self.curveX;
}
// Add spin effect if it exists
if (self.spinSpeed) {
self.speedX += Math.sin(LK.ticks * 0.1) * self.spinSpeed;
}
// Add rotation if it exists
if (self.rotationSpeed) {
self.rotation += self.rotationSpeed;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var goalkeeper;
var balls = [];
var ballSpawnTimer = 0;
var ballSpawnInterval = 120; // 2 seconds at 60fps
var difficulty = 1;
var saves = 0;
var gameSpeed = 1;
var gameStarted = false;
var selectedDifficulty = null;
var survivalLevel = 1;
var survivalSavesForNextLevel = 10;
var difficultySettings = {
easy: {
goalTarget: 25,
ballSpeed: 1,
spawnRate: 150,
name: "Easy"
},
normal: {
goalTarget: 50,
ballSpeed: 1.5,
spawnRate: 120,
name: "Normal"
},
hard: {
goalTarget: 100,
ballSpeed: 2.5,
spawnRate: 90,
name: "Hard"
},
survival: {
goalTarget: Infinity,
ballSpeed: 1,
spawnRate: 180,
name: "Survival"
},
oneVsOne: {
goalTarget: 5,
ballSpeed: 1.5,
spawnRate: 120,
name: "1vs1"
}
};
// 1vs1 mode variables
var botGoalkeeper;
var playerScore = 0;
var botScore = 0;
var isPlayerTurn = true;
var turnTimer = 0;
var turnDuration = 300; // 5 seconds at 60fps
// Create field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0,
anchorY: 1,
x: 0,
y: 2732
}));
// Create goal structure
var goalNet = game.addChild(LK.getAsset('goalNet', {
width: 1200,
anchorX: 0.5,
anchorY: 1,
x: 1024,
y: 2732
}));
goalNet.alpha = 0.3;
// Create bot goal structure (initially hidden)
var botGoalNet = game.addChild(LK.getAsset('goalNet', {
width: 1200,
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: 0
}));
botGoalNet.alpha = 0.3;
botGoalNet.visible = false;
var botLeftPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0,
x: 424,
y: 0
}));
botLeftPost.visible = false;
var botRightPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0,
x: 1624,
y: 0
}));
botRightPost.visible = false;
var leftPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: 424,
y: 2732
}));
var rightPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: 1624,
y: 2732
}));
// Create goalkeeper
goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = 1024;
goalkeeper.y = 2732;
// Create UI
var scoreTxt = new Text2('Saves: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create difficulty selection menu
var menuContainer = new Container();
game.addChild(menuContainer);
var titleText = new Text2('Select Difficulty', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
menuContainer.addChild(titleText);
// Easy button
var easyButton = new Container();
var easyBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00ff00
});
var easyText = new Text2('Easy - 25 Goals', {
size: 60,
fill: 0x000000
});
easyText.anchor.set(0.5, 0.5);
easyButton.addChild(easyBg);
easyButton.addChild(easyText);
easyButton.x = 1024;
easyButton.y = 1200;
menuContainer.addChild(easyButton);
// Normal button
var normalButton = new Container();
var normalBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0xffff00
});
var normalText = new Text2('Normal - 50 Goals', {
size: 60,
fill: 0x000000
});
normalText.anchor.set(0.5, 0.5);
normalButton.addChild(normalBg);
normalButton.addChild(normalText);
normalButton.x = 1024;
normalButton.y = 1400;
menuContainer.addChild(normalButton);
// Hard button
var hardButton = new Container();
var hardBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0xff0000
});
var hardText = new Text2('Hard - 100 Goals', {
size: 60,
fill: 0x000000
});
hardText.anchor.set(0.5, 0.5);
hardButton.addChild(hardBg);
hardButton.addChild(hardText);
hardButton.x = 1024;
hardButton.y = 1600;
menuContainer.addChild(hardButton);
// Survival button
var survivalButton = new Container();
var survivalBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x800080
});
var survivalText = new Text2('Survival Mode', {
size: 60,
fill: 0xFFFFFF
});
survivalText.anchor.set(0.5, 0.5);
survivalButton.addChild(survivalBg);
survivalButton.addChild(survivalText);
survivalButton.x = 1024;
survivalButton.y = 1800;
menuContainer.addChild(survivalButton);
// 1vs1 button
var oneVsOneButton = new Container();
var oneVsOneBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00ffff
});
var oneVsOneText = new Text2('1vs1 Mode', {
size: 60,
fill: 0x000000
});
oneVsOneText.anchor.set(0.5, 0.5);
oneVsOneButton.addChild(oneVsOneBg);
oneVsOneButton.addChild(oneVsOneText);
oneVsOneButton.x = 1024;
oneVsOneButton.y = 2000;
menuContainer.addChild(oneVsOneButton);
// Button click handlers
easyButton.down = function (x, y, obj) {
startGame('easy');
};
normalButton.down = function (x, y, obj) {
startGame('normal');
};
hardButton.down = function (x, y, obj) {
startGame('hard');
};
survivalButton.down = function (x, y, obj) {
startGame('survival');
};
oneVsOneButton.down = function (x, y, obj) {
startGame('oneVsOne');
};
// Function to start game with selected difficulty
function startGame(difficultyLevel) {
selectedDifficulty = difficultyLevel;
gameStarted = true;
menuContainer.visible = false;
var settings = difficultySettings[difficultyLevel];
gameSpeed = settings.ballSpeed;
ballSpawnInterval = settings.spawnRate;
if (difficultyLevel === '1vs1' || difficultyLevel === 'oneVsOne') {
// Initialize 1vs1 mode
selectedDifficulty = 'oneVsOne';
playerScore = 0;
botScore = 0;
isPlayerTurn = true;
turnTimer = 0;
// Show bot goal and goalkeeper
botGoalNet.visible = true;
botLeftPost.visible = true;
botRightPost.visible = true;
// Create bot goalkeeper
botGoalkeeper = game.addChild(new BotGoalkeeper());
botGoalkeeper.x = 1024;
botGoalkeeper.y = 0;
scoreTxt.setText('Player: 0 - Bot: 0 (Your Turn)');
} else if (difficultyLevel === 'survival') {
survivalLevel = 1;
survivalSavesForNextLevel = 10;
scoreTxt.setText('Saves: 0 - Level 1 (Survival)');
} else {
scoreTxt.setText('Saves: 0/' + settings.goalTarget + ' (' + settings.name + ')');
}
}
// Ball spawning function
function spawnBall() {
var ball = new SoccerBall();
if (selectedDifficulty === 'oneVsOne') {
// 1vs1 mode: balls spawn from middle and go toward current defender
ball.x = Math.random() * 800 + 624; // Center area
ball.y = 1366; // Middle of field
var targetX, targetY;
if (isPlayerTurn) {
// Ball goes toward player's goal
targetX = Math.random() * 1200 + 424;
targetY = 2732 - 100;
} else {
// Ball goes toward bot's goal
targetX = Math.random() * 1200 + 424;
targetY = 100;
}
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
var speed = 3 * gameSpeed;
ball.speedX = (targetX - ball.x) / distance * speed;
ball.speedY = (targetY - ball.y) / distance * speed;
} else {
// Random spawn position across the field width
ball.x = Math.random() * 1600 + 224;
ball.y = 100;
if (selectedDifficulty === 'survival') {
// Survival mode: increasingly unpredictable and difficult shots
var currentSpeed = 3 + survivalLevel * 0.8;
var targetX = Math.random() * 1200 + 424;
var targetY = 2732 - 100;
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
ball.speedX = (targetX - ball.x) / distance * currentSpeed;
ball.speedY = (targetY - ball.y) / distance * currentSpeed;
// Add curve effect for higher levels
if (survivalLevel > 3) {
ball.curveX = (Math.random() - 0.5) * 0.5;
}
// Add spin effect for even higher levels
if (survivalLevel > 6) {
ball.spinSpeed = (Math.random() - 0.5) * 0.2;
ball.rotationSpeed = Math.random() * 0.3;
}
} else {
// Normal mode behavior
var targetX = Math.random() * 1200 + 424; // Random point in goal area
var targetY = 2732 - 100; // Goal height
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
var speed = 3 * gameSpeed;
ball.speedX = (targetX - ball.x) / distance * speed;
ball.speedY = (targetY - ball.y) / distance * speed;
}
}
balls.push(ball);
game.addChild(ball);
LK.getSound('kick').play();
}
// Touch controls
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
goalkeeper.setTarget(x);
};
game.move = function (x, y, obj) {
if (isDragging) {
goalkeeper.setTarget(x);
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Don't run game logic until difficulty is selected
if (!gameStarted) return;
// 1vs1 mode specific logic
if (selectedDifficulty === 'oneVsOne') {
// Turn timer
turnTimer++;
if (turnTimer >= turnDuration && balls.length === 0) {
// Switch turns when no balls are active
isPlayerTurn = !isPlayerTurn;
turnTimer = 0;
var turnText = isPlayerTurn ? 'Your Turn' : 'Bot Turn';
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (' + turnText + ')');
// Give bot goalkeeper reaction delay when it's player's turn
if (isPlayerTurn && botGoalkeeper) {
botGoalkeeper.reactionTime = botGoalkeeper.maxReactionDelay;
}
}
// Spawn balls for 1vs1
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval && balls.length === 0) {
spawnBall();
ballSpawnTimer = 0;
}
// Handle 1vs1 ball collision and scoring
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
if (!ball.active) continue;
// Check bot goal (player scores)
if (ball.y < 0 && isPlayerTurn) {
playerScore++;
LK.setScore(playerScore);
LK.getSound('goal').play();
LK.effects.flashScreen(0x00ff00, 500);
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (Goal!)');
ball.destroy();
balls.splice(i, 1);
if (playerScore >= 5) {
LK.showYouWin();
return;
}
continue;
}
// Check player goal (bot scores)
if (ball.y > 2732 && !isPlayerTurn) {
botScore++;
LK.getSound('goal').play();
LK.effects.flashScreen(0xff0000, 500);
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (Bot Goal!)');
ball.destroy();
balls.splice(i, 1);
if (botScore >= 5) {
LK.showGameOver();
return;
}
continue;
}
// Check saves
var savedBy = null;
if (isPlayerTurn && ball.intersects(botGoalkeeper) && ball.active && ball.y < 500) {
savedBy = 'bot';
} else if (!isPlayerTurn && ball.intersects(goalkeeper) && ball.active && ball.y > 2200) {
savedBy = 'player';
}
if (savedBy) {
ball.active = false;
var saveText = savedBy === 'player' ? 'You saved!' : 'Bot saved!';
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (' + saveText + ')');
LK.effects.flashObject(savedBy === 'player' ? goalkeeper : botGoalkeeper, 0x00ff00, 500);
LK.getSound('save').play();
ball.destroy();
balls.splice(i, 1);
continue;
}
// Remove out of bounds balls
if (ball.y < -100 || ball.y > 2832 || ball.x < -100 || ball.x > 2148) {
ball.destroy();
balls.splice(i, 1);
continue;
}
}
return; // Skip normal mode logic for 1vs1
}
// Spawn balls
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
spawnBall();
ballSpawnTimer = 0;
}
// Update and check balls
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
if (!ball.active) continue;
// Check if ball went past goal line (goal scored)
if (ball.y > 2732) {
LK.getSound('goal').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check for save (collision with goalkeeper)
if (ball.intersects(goalkeeper) && ball.active) {
ball.active = false;
saves++;
LK.setScore(saves);
if (selectedDifficulty === 'survival') {
// Check for level progression in survival mode
if (saves >= survivalSavesForNextLevel) {
survivalLevel++;
survivalSavesForNextLevel += 10 + survivalLevel * 2;
// Increase difficulty - faster spawn rate and more unpredictable shots
ballSpawnInterval = Math.max(45, 180 - survivalLevel * 15);
// Visual feedback for level up
LK.effects.flashScreen(0x00ff00, 500);
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
scoreTxt.setText('Saves: ' + saves + ' - Level ' + survivalLevel + ' (Survival)');
} else {
var settings = difficultySettings[selectedDifficulty];
scoreTxt.setText('Saves: ' + saves + '/' + settings.goalTarget + ' (' + settings.name + ')');
}
// Visual feedback for save
LK.effects.flashObject(goalkeeper, 0x00ff00, 500);
tween(goalkeeper, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goalkeeper, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
LK.getSound('save').play();
// Remove ball
ball.destroy();
balls.splice(i, 1);
continue;
}
// Remove balls that went off screen (missed)
if (ball.y < -100 || ball.x < -100 || ball.x > 2148) {
ball.destroy();
balls.splice(i, 1);
continue;
}
// Check if ball is out of bounds horizontally (safe)
if ((ball.x < 424 || ball.x > 1624) && ball.y > 2332) {
ball.active = false;
ball.destroy();
balls.splice(i, 1);
continue;
}
}
// Win condition - based on selected difficulty (survival mode never wins, only tracks progress)
if (selectedDifficulty !== 'survival') {
var settings = difficultySettings[selectedDifficulty];
if (saves >= settings.goalTarget) {
LK.showYouWin();
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// LK engine handles pause/play functionality automatically through built-in systems
var BotGoalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.0
});
keeperGraphics.tint = 0xff6666; // Red tint for bot
self.targetX = 1024;
self.reactionTime = 0;
self.maxReactionDelay = 30; // frames
self.update = function () {
// Bot AI movement with reaction delay
if (self.reactionTime > 0) {
self.reactionTime--;
return;
}
// Find closest active ball
var closestBall = null;
var closestDistance = Infinity;
for (var i = 0; i < balls.length; i++) {
if (balls[i].active && balls[i].y < 1000) {
// Only react to balls in upper half
var distance = Math.abs(balls[i].x - self.x);
if (distance < closestDistance) {
closestDistance = distance;
closestBall = balls[i];
}
}
}
if (closestBall) {
// Predict where ball will be
var predictedX = closestBall.x + closestBall.speedX * 20;
self.targetX = predictedX;
// Add some error for difficulty
self.targetX += (Math.random() - 0.5) * 200;
}
// Move toward target
var dx = self.targetX - self.x;
if (Math.abs(dx) > 5) {
self.x += dx * 0.15; // Slightly slower than player
}
// Keep within bounds
var goalLeft = 424;
var goalRight = 1624;
self.x = Math.max(goalLeft, Math.min(goalRight, self.x));
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 1.0
});
self.targetX = 1024; // Center of goal
self.moveSpeed = 15;
self.update = function () {
// Smooth movement toward target position
var dx = self.targetX - self.x;
if (Math.abs(dx) > 5) {
self.x += dx * 0.2;
}
};
self.setTarget = function (x) {
// Keep goalkeeper within goal bounds
var goalLeft = 424;
var goalRight = 1624;
self.targetX = Math.max(goalLeft, Math.min(goalRight, x));
};
return self;
});
var SoccerBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('soccerBall', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.active = true;
self.update = function () {
if (!self.active) return;
self.x += self.speedX;
self.y += self.speedY;
// Add slight gravity effect
self.speedY += 0.2;
// Add curve effect if it exists
if (self.curveX) {
self.speedX += self.curveX;
}
// Add spin effect if it exists
if (self.spinSpeed) {
self.speedX += Math.sin(LK.ticks * 0.1) * self.spinSpeed;
}
// Add rotation if it exists
if (self.rotationSpeed) {
self.rotation += self.rotationSpeed;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var goalkeeper;
var balls = [];
var ballSpawnTimer = 0;
var ballSpawnInterval = 120; // 2 seconds at 60fps
var difficulty = 1;
var saves = 0;
var gameSpeed = 1;
var gameStarted = false;
var selectedDifficulty = null;
var survivalLevel = 1;
var survivalSavesForNextLevel = 10;
var difficultySettings = {
easy: {
goalTarget: 25,
ballSpeed: 1,
spawnRate: 150,
name: "Easy"
},
normal: {
goalTarget: 50,
ballSpeed: 1.5,
spawnRate: 120,
name: "Normal"
},
hard: {
goalTarget: 100,
ballSpeed: 2.5,
spawnRate: 90,
name: "Hard"
},
survival: {
goalTarget: Infinity,
ballSpeed: 1,
spawnRate: 180,
name: "Survival"
},
oneVsOne: {
goalTarget: 5,
ballSpeed: 1.5,
spawnRate: 120,
name: "1vs1"
}
};
// 1vs1 mode variables
var botGoalkeeper;
var playerScore = 0;
var botScore = 0;
var isPlayerTurn = true;
var turnTimer = 0;
var turnDuration = 300; // 5 seconds at 60fps
// Create field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0,
anchorY: 1,
x: 0,
y: 2732
}));
// Create goal structure
var goalNet = game.addChild(LK.getAsset('goalNet', {
width: 1200,
anchorX: 0.5,
anchorY: 1,
x: 1024,
y: 2732
}));
goalNet.alpha = 0.3;
// Create bot goal structure (initially hidden)
var botGoalNet = game.addChild(LK.getAsset('goalNet', {
width: 1200,
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: 0
}));
botGoalNet.alpha = 0.3;
botGoalNet.visible = false;
var botLeftPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0,
x: 424,
y: 0
}));
botLeftPost.visible = false;
var botRightPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 0,
x: 1624,
y: 0
}));
botRightPost.visible = false;
var leftPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: 424,
y: 2732
}));
var rightPost = game.addChild(LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: 1624,
y: 2732
}));
// Create goalkeeper
goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = 1024;
goalkeeper.y = 2732;
// Create UI
var scoreTxt = new Text2('Saves: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create difficulty selection menu
var menuContainer = new Container();
game.addChild(menuContainer);
var titleText = new Text2('Select Difficulty', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
menuContainer.addChild(titleText);
// Easy button
var easyButton = new Container();
var easyBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00ff00
});
var easyText = new Text2('Easy - 25 Goals', {
size: 60,
fill: 0x000000
});
easyText.anchor.set(0.5, 0.5);
easyButton.addChild(easyBg);
easyButton.addChild(easyText);
easyButton.x = 1024;
easyButton.y = 1200;
menuContainer.addChild(easyButton);
// Normal button
var normalButton = new Container();
var normalBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0xffff00
});
var normalText = new Text2('Normal - 50 Goals', {
size: 60,
fill: 0x000000
});
normalText.anchor.set(0.5, 0.5);
normalButton.addChild(normalBg);
normalButton.addChild(normalText);
normalButton.x = 1024;
normalButton.y = 1400;
menuContainer.addChild(normalButton);
// Hard button
var hardButton = new Container();
var hardBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0xff0000
});
var hardText = new Text2('Hard - 100 Goals', {
size: 60,
fill: 0x000000
});
hardText.anchor.set(0.5, 0.5);
hardButton.addChild(hardBg);
hardButton.addChild(hardText);
hardButton.x = 1024;
hardButton.y = 1600;
menuContainer.addChild(hardButton);
// Survival button
var survivalButton = new Container();
var survivalBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x800080
});
var survivalText = new Text2('Survival Mode', {
size: 60,
fill: 0xFFFFFF
});
survivalText.anchor.set(0.5, 0.5);
survivalButton.addChild(survivalBg);
survivalButton.addChild(survivalText);
survivalButton.x = 1024;
survivalButton.y = 1800;
menuContainer.addChild(survivalButton);
// 1vs1 button
var oneVsOneButton = new Container();
var oneVsOneBg = LK.getAsset('goalPost', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00ffff
});
var oneVsOneText = new Text2('1vs1 Mode', {
size: 60,
fill: 0x000000
});
oneVsOneText.anchor.set(0.5, 0.5);
oneVsOneButton.addChild(oneVsOneBg);
oneVsOneButton.addChild(oneVsOneText);
oneVsOneButton.x = 1024;
oneVsOneButton.y = 2000;
menuContainer.addChild(oneVsOneButton);
// Button click handlers
easyButton.down = function (x, y, obj) {
startGame('easy');
};
normalButton.down = function (x, y, obj) {
startGame('normal');
};
hardButton.down = function (x, y, obj) {
startGame('hard');
};
survivalButton.down = function (x, y, obj) {
startGame('survival');
};
oneVsOneButton.down = function (x, y, obj) {
startGame('oneVsOne');
};
// Function to start game with selected difficulty
function startGame(difficultyLevel) {
selectedDifficulty = difficultyLevel;
gameStarted = true;
menuContainer.visible = false;
var settings = difficultySettings[difficultyLevel];
gameSpeed = settings.ballSpeed;
ballSpawnInterval = settings.spawnRate;
if (difficultyLevel === '1vs1' || difficultyLevel === 'oneVsOne') {
// Initialize 1vs1 mode
selectedDifficulty = 'oneVsOne';
playerScore = 0;
botScore = 0;
isPlayerTurn = true;
turnTimer = 0;
// Show bot goal and goalkeeper
botGoalNet.visible = true;
botLeftPost.visible = true;
botRightPost.visible = true;
// Create bot goalkeeper
botGoalkeeper = game.addChild(new BotGoalkeeper());
botGoalkeeper.x = 1024;
botGoalkeeper.y = 0;
scoreTxt.setText('Player: 0 - Bot: 0 (Your Turn)');
} else if (difficultyLevel === 'survival') {
survivalLevel = 1;
survivalSavesForNextLevel = 10;
scoreTxt.setText('Saves: 0 - Level 1 (Survival)');
} else {
scoreTxt.setText('Saves: 0/' + settings.goalTarget + ' (' + settings.name + ')');
}
}
// Ball spawning function
function spawnBall() {
var ball = new SoccerBall();
if (selectedDifficulty === 'oneVsOne') {
// 1vs1 mode: balls spawn from middle and go toward current defender
ball.x = Math.random() * 800 + 624; // Center area
ball.y = 1366; // Middle of field
var targetX, targetY;
if (isPlayerTurn) {
// Ball goes toward player's goal
targetX = Math.random() * 1200 + 424;
targetY = 2732 - 100;
} else {
// Ball goes toward bot's goal
targetX = Math.random() * 1200 + 424;
targetY = 100;
}
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
var speed = 3 * gameSpeed;
ball.speedX = (targetX - ball.x) / distance * speed;
ball.speedY = (targetY - ball.y) / distance * speed;
} else {
// Random spawn position across the field width
ball.x = Math.random() * 1600 + 224;
ball.y = 100;
if (selectedDifficulty === 'survival') {
// Survival mode: increasingly unpredictable and difficult shots
var currentSpeed = 3 + survivalLevel * 0.8;
var targetX = Math.random() * 1200 + 424;
var targetY = 2732 - 100;
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
ball.speedX = (targetX - ball.x) / distance * currentSpeed;
ball.speedY = (targetY - ball.y) / distance * currentSpeed;
// Add curve effect for higher levels
if (survivalLevel > 3) {
ball.curveX = (Math.random() - 0.5) * 0.5;
}
// Add spin effect for even higher levels
if (survivalLevel > 6) {
ball.spinSpeed = (Math.random() - 0.5) * 0.2;
ball.rotationSpeed = Math.random() * 0.3;
}
} else {
// Normal mode behavior
var targetX = Math.random() * 1200 + 424; // Random point in goal area
var targetY = 2732 - 100; // Goal height
var distance = Math.sqrt(Math.pow(targetX - ball.x, 2) + Math.pow(targetY - ball.y, 2));
var speed = 3 * gameSpeed;
ball.speedX = (targetX - ball.x) / distance * speed;
ball.speedY = (targetY - ball.y) / distance * speed;
}
}
balls.push(ball);
game.addChild(ball);
LK.getSound('kick').play();
}
// Touch controls
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
goalkeeper.setTarget(x);
};
game.move = function (x, y, obj) {
if (isDragging) {
goalkeeper.setTarget(x);
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Don't run game logic until difficulty is selected
if (!gameStarted) return;
// 1vs1 mode specific logic
if (selectedDifficulty === 'oneVsOne') {
// Turn timer
turnTimer++;
if (turnTimer >= turnDuration && balls.length === 0) {
// Switch turns when no balls are active
isPlayerTurn = !isPlayerTurn;
turnTimer = 0;
var turnText = isPlayerTurn ? 'Your Turn' : 'Bot Turn';
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (' + turnText + ')');
// Give bot goalkeeper reaction delay when it's player's turn
if (isPlayerTurn && botGoalkeeper) {
botGoalkeeper.reactionTime = botGoalkeeper.maxReactionDelay;
}
}
// Spawn balls for 1vs1
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval && balls.length === 0) {
spawnBall();
ballSpawnTimer = 0;
}
// Handle 1vs1 ball collision and scoring
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
if (!ball.active) continue;
// Check bot goal (player scores)
if (ball.y < 0 && isPlayerTurn) {
playerScore++;
LK.setScore(playerScore);
LK.getSound('goal').play();
LK.effects.flashScreen(0x00ff00, 500);
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (Goal!)');
ball.destroy();
balls.splice(i, 1);
if (playerScore >= 5) {
LK.showYouWin();
return;
}
continue;
}
// Check player goal (bot scores)
if (ball.y > 2732 && !isPlayerTurn) {
botScore++;
LK.getSound('goal').play();
LK.effects.flashScreen(0xff0000, 500);
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (Bot Goal!)');
ball.destroy();
balls.splice(i, 1);
if (botScore >= 5) {
LK.showGameOver();
return;
}
continue;
}
// Check saves
var savedBy = null;
if (isPlayerTurn && ball.intersects(botGoalkeeper) && ball.active && ball.y < 500) {
savedBy = 'bot';
} else if (!isPlayerTurn && ball.intersects(goalkeeper) && ball.active && ball.y > 2200) {
savedBy = 'player';
}
if (savedBy) {
ball.active = false;
var saveText = savedBy === 'player' ? 'You saved!' : 'Bot saved!';
scoreTxt.setText('Player: ' + playerScore + ' - Bot: ' + botScore + ' (' + saveText + ')');
LK.effects.flashObject(savedBy === 'player' ? goalkeeper : botGoalkeeper, 0x00ff00, 500);
LK.getSound('save').play();
ball.destroy();
balls.splice(i, 1);
continue;
}
// Remove out of bounds balls
if (ball.y < -100 || ball.y > 2832 || ball.x < -100 || ball.x > 2148) {
ball.destroy();
balls.splice(i, 1);
continue;
}
}
return; // Skip normal mode logic for 1vs1
}
// Spawn balls
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
spawnBall();
ballSpawnTimer = 0;
}
// Update and check balls
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
if (!ball.active) continue;
// Check if ball went past goal line (goal scored)
if (ball.y > 2732) {
LK.getSound('goal').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check for save (collision with goalkeeper)
if (ball.intersects(goalkeeper) && ball.active) {
ball.active = false;
saves++;
LK.setScore(saves);
if (selectedDifficulty === 'survival') {
// Check for level progression in survival mode
if (saves >= survivalSavesForNextLevel) {
survivalLevel++;
survivalSavesForNextLevel += 10 + survivalLevel * 2;
// Increase difficulty - faster spawn rate and more unpredictable shots
ballSpawnInterval = Math.max(45, 180 - survivalLevel * 15);
// Visual feedback for level up
LK.effects.flashScreen(0x00ff00, 500);
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
scoreTxt.setText('Saves: ' + saves + ' - Level ' + survivalLevel + ' (Survival)');
} else {
var settings = difficultySettings[selectedDifficulty];
scoreTxt.setText('Saves: ' + saves + '/' + settings.goalTarget + ' (' + settings.name + ')');
}
// Visual feedback for save
LK.effects.flashObject(goalkeeper, 0x00ff00, 500);
tween(goalkeeper, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goalkeeper, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
LK.getSound('save').play();
// Remove ball
ball.destroy();
balls.splice(i, 1);
continue;
}
// Remove balls that went off screen (missed)
if (ball.y < -100 || ball.x < -100 || ball.x > 2148) {
ball.destroy();
balls.splice(i, 1);
continue;
}
// Check if ball is out of bounds horizontally (safe)
if ((ball.x < 424 || ball.x > 1624) && ball.y > 2332) {
ball.active = false;
ball.destroy();
balls.splice(i, 1);
continue;
}
}
// Win condition - based on selected difficulty (survival mode never wins, only tracks progress)
if (selectedDifficulty !== 'survival') {
var settings = difficultySettings[selectedDifficulty];
if (saves >= settings.goalTarget) {
LK.showYouWin();
}
}
};
A common soccer ball made of leather. In-Game asset. 2d. High contrast. No shadows. Cartoon
5-year-old boy with his back turned wearing a worn t-shirt and work gloves. In-Game asset. 2d. High contrast. No shadows. Cartoon
A religious street area. In-Game asset. 2d. High contrast. No shadows
Goal net. In-Game asset. 2d. High contrast. No shadows