User prompt
Add a 1vs1 mode where you face a bot, the first one to score or stop 5 goals wins ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add another mode where you have to stop goals that are increasingly difficult, unpredictable, and fast. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
After that, you have a menu with three difficulties: Easy, you only have to stop 25 slow goals, Normal, you have to stop 50 fast goals, and Hard, you have to stop 100 very fast goals.
Remix started
Copy Goalkeeper Hero
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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;
};
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;
// 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;
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);
// Ball spawning function
function spawnBall() {
var ball = new SoccerBall();
// Random spawn position across the field width
ball.x = Math.random() * 1600 + 224;
ball.y = 100;
// Calculate trajectory toward goal
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 + difficulty) * 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 () {
// Spawn balls
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
spawnBall();
ballSpawnTimer = 0;
// Increase difficulty over time
if (ballSpawnInterval > 60) {
ballSpawnInterval -= 2;
}
if (LK.ticks % 600 === 0) {
// Every 10 seconds
difficulty += 0.2;
}
}
// 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);
scoreTxt.setText('Saves: ' + saves);
// 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 - 50 saves
if (saves >= 50) {
LK.showYouWin();
}
};
// LK engine handles pause/play functionality automatically through built-in systems /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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;
};
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;
// 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;
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);
// Ball spawning function
function spawnBall() {
var ball = new SoccerBall();
// Random spawn position across the field width
ball.x = Math.random() * 1600 + 224;
ball.y = 100;
// Calculate trajectory toward goal
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 + difficulty) * 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 () {
// Spawn balls
ballSpawnTimer++;
if (ballSpawnTimer >= ballSpawnInterval) {
spawnBall();
ballSpawnTimer = 0;
// Increase difficulty over time
if (ballSpawnInterval > 60) {
ballSpawnInterval -= 2;
}
if (LK.ticks % 600 === 0) {
// Every 10 seconds
difficulty += 0.2;
}
}
// 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);
scoreTxt.setText('Saves: ' + saves);
// 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 - 50 saves
if (saves >= 50) {
LK.showYouWin();
}
};
// LK engine handles pause/play functionality automatically through built-in systems
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