/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Goalkeeper class var Goalkeeper = Container.expand(function () { var self = Container.call(this); var keeper = self.attachAsset('goalkeeper', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; // Initial speed self.direction = 1; // 1: right, -1: left // Update self.update = function () { self.x += self.speed * self.direction; // Bounce off posts if (self.x > goalRightX - keeper.width / 2) { self.x = goalRightX - keeper.width / 2; self.direction = -1; } if (self.x < goalLeftX + keeper.width / 2) { self.x = goalLeftX + keeper.width / 2; self.direction = 1; } }; // Increase speed self.increaseSpeed = function () { self.speed += 1.5; if (self.speed > 22) self.speed = 22; }; return self; }); // Soccer Ball class var SoccerBall = Container.expand(function () { var self = Container.call(this); // Shadow var shadow = self.attachAsset('ballShadow', { anchorX: 0.5, anchorY: 0.5, y: 80, alpha: 0.4 }); // Ball var ball = self.attachAsset('soccerBall', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.isShot = false; self.hasScored = false; self.hasMissed = false; // Feedback self.showGoal = function () { var goalFx = LK.getAsset('goalCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.addChild(goalFx); tween(goalFx, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { goalFx.destroy(); } }); }; self.showMiss = function () { var missFx = LK.getAsset('missCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.addChild(missFx); tween(missFx, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { missFx.destroy(); } }); }; // Ball update self.update = function () { if (self.isShot) { self.x += self.vx; self.y += self.vy; // Simulate friction/air resistance self.vx *= 0.99; self.vy *= 0.99; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a472a // Dark green pitch }); /**** * Game Code ****/ // Goal feedback (yellow) // Miss feedback (red) // Net posts (gray) // Ball shadow (gray) // Goal area (light green) // Goalkeeper (blue) // Soccer ball (white) // --- Game constants --- var goalWidth = 900; var goalHeight = 40; var goalY = 420; // Y position of goal line var goalX = (2048 - goalWidth) / 2; var goalLeftX = goalX; var goalRightX = goalX + goalWidth; var goalPostHeight = 180; var shotsTotal = 10; // --- Game state --- var balls = []; var shotsLeft = shotsTotal; var score = 0; var isShooting = false; var canShoot = true; var swipeStart = null; var swipeEnd = null; var currentBall = null; var goalkeeper = null; var lastGoalkeeperSpeedupScore = 0; // --- UI Elements --- var scoreTxt = new Text2('0', { size: 120, fill: 0xFFF700 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var shotsTxt = new Text2('Shots: ' + shotsLeft, { size: 70, fill: 0xFFFFFF }); shotsTxt.anchor.set(0.5, 0); LK.gui.top.addChild(shotsTxt); shotsTxt.y = 120; // --- Draw goal area --- var goalArea = LK.getAsset('goalArea', { anchorX: 0, anchorY: 0, x: goalX, y: goalY }); game.addChild(goalArea); // Goal posts var leftPost = LK.getAsset('goalPost', { anchorX: 0.5, anchorY: 1, x: goalLeftX, y: goalY + goalPostHeight }); var rightPost = LK.getAsset('goalPost', { anchorX: 0.5, anchorY: 1, x: goalRightX, y: goalY + goalPostHeight }); game.addChild(leftPost); game.addChild(rightPost); // --- Add goalkeeper --- goalkeeper = new Goalkeeper(); goalkeeper.x = 2048 / 2; goalkeeper.y = goalY + 40; game.addChild(goalkeeper); // --- Ball spawn position --- var ballStartX = 2048 / 2; var ballStartY = 2732 - 320; // --- Functions --- function spawnBall() { var ball = new SoccerBall(); ball.x = ballStartX; ball.y = ballStartY; balls.push(ball); game.addChild(ball); currentBall = ball; isShooting = false; canShoot = true; } function resetGame() { // Remove all balls for (var i = 0; i < balls.length; ++i) { balls[i].destroy(); } balls = []; shotsLeft = shotsTotal; score = 0; lastGoalkeeperSpeedupScore = 0; scoreTxt.setText(score); shotsTxt.setText('Shots: ' + shotsLeft); goalkeeper.speed = 8; goalkeeper.x = 2048 / 2; spawnBall(); } function shootBall(vx, vy) { if (!currentBall || !canShoot) return; currentBall.vx = vx; currentBall.vy = vy; currentBall.isShot = true; isShooting = true; canShoot = false; shotsLeft -= 1; shotsTxt.setText('Shots: ' + shotsLeft); } // --- Input handling (swipe or tap) --- game.down = function (x, y, obj) { if (!canShoot) return; // Only allow starting swipe/tap from lower half of screen if (y < 1800) return; swipeStart = { x: x, y: y }; swipeEnd = null; }; game.move = function (x, y, obj) { if (!canShoot || !swipeStart) return; swipeEnd = { x: x, y: y }; }; game.up = function (x, y, obj) { if (!canShoot || !swipeStart) return; swipeEnd = { x: x, y: y }; // Calculate direction and power var dx = swipeEnd.x - swipeStart.x; var dy = swipeEnd.y - swipeStart.y; // Only allow upward swipes/taps if (dy > -40) { // Not enough upward movement, treat as tap dx = 0; dy = -900; } // Clamp power var power = Math.sqrt(dx * dx + dy * dy); if (power < 200) power = 200; if (power > 1200) power = 1200; // Normalize var norm = Math.sqrt(dx * dx + dy * dy); var vx = 0, vy = 0; if (norm > 0) { vx = dx / norm * (power / 22); vy = dy / norm * (power / 18); } else { vx = 0; vy = -power / 18; } shootBall(vx, vy); swipeStart = null; swipeEnd = null; }; // --- Main update loop --- game.update = function () { // Update goalkeeper if (goalkeeper) goalkeeper.update(); // Update balls for (var i = balls.length - 1; i >= 0; --i) { var ball = balls[i]; ball.update(); // Only check for scoring/miss if ball is shot and not already scored/missed if (ball.isShot && !ball.hasScored && !ball.hasMissed) { // Check if ball crosses goal line (y <= goalY+goalHeight) if (ball.y <= goalY + goalHeight / 2 && ball.y > goalY - 80) { // Check if within goal posts if (ball.x > goalLeftX + 60 && ball.x < goalRightX - 60) { // Check collision with goalkeeper var keeperRect = { x: goalkeeper.x - 110, y: goalkeeper.y - 40, w: 220, h: 80 }; var ballRect = { x: ball.x - 60, y: ball.y - 60, w: 120, h: 120 }; var intersects = !(keeperRect.x + keeperRect.w < ballRect.x || keeperRect.x > ballRect.x + ballRect.w || keeperRect.y + keeperRect.h < ballRect.y || keeperRect.y > ballRect.y + ballRect.h); if (!intersects) { // GOAL! ball.hasScored = true; score += 1; scoreTxt.setText(score); ball.showGoal(); // Speed up goalkeeper every 2 goals if (score - lastGoalkeeperSpeedupScore >= 2) { goalkeeper.increaseSpeed(); lastGoalkeeperSpeedupScore = score; } } else { // Saved by keeper ball.hasMissed = true; ball.showMiss(); } } else { // Missed wide ball.hasMissed = true; ball.showMiss(); } } // Missed high if (ball.y < goalY - 100) { if (!ball.hasScored && !ball.hasMissed) { ball.hasMissed = true; ball.showMiss(); } } } // Remove ball if out of bounds if (ball.y < -200 || ball.x < -200 || ball.x > 2248) { ball.destroy(); balls.splice(i, 1); if (currentBall === ball) currentBall = null; } } // After shot, wait for ball to stop or leave screen, then spawn next ball or end game if (isShooting && !currentBall) { if (shotsLeft > 0) { spawnBall(); } else { // Game over LK.showGameOver(); } isShooting = false; } // If current ball is shot and has scored/missed, and is slow or out of bounds, remove it if (currentBall && currentBall.isShot && (currentBall.hasScored || currentBall.hasMissed)) { var speed = Math.sqrt(currentBall.vx * currentBall.vx + currentBall.vy * currentBall.vy); if (speed < 2 || currentBall.y < -200 || currentBall.x < -200 || currentBall.x > 2248) { currentBall.destroy(); for (var j = 0; j < balls.length; ++j) { if (balls[j] === currentBall) { balls.splice(j, 1); break; } } currentBall = null; } } // Win condition: score 10 goals if (score >= 10) { LK.showYouWin(); } }; // --- Start game --- resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Goalkeeper class
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeper = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8; // Initial speed
self.direction = 1; // 1: right, -1: left
// Update
self.update = function () {
self.x += self.speed * self.direction;
// Bounce off posts
if (self.x > goalRightX - keeper.width / 2) {
self.x = goalRightX - keeper.width / 2;
self.direction = -1;
}
if (self.x < goalLeftX + keeper.width / 2) {
self.x = goalLeftX + keeper.width / 2;
self.direction = 1;
}
};
// Increase speed
self.increaseSpeed = function () {
self.speed += 1.5;
if (self.speed > 22) self.speed = 22;
};
return self;
});
// Soccer Ball class
var SoccerBall = Container.expand(function () {
var self = Container.call(this);
// Shadow
var shadow = self.attachAsset('ballShadow', {
anchorX: 0.5,
anchorY: 0.5,
y: 80,
alpha: 0.4
});
// Ball
var ball = self.attachAsset('soccerBall', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.isShot = false;
self.hasScored = false;
self.hasMissed = false;
// Feedback
self.showGoal = function () {
var goalFx = LK.getAsset('goalCircle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.addChild(goalFx);
tween(goalFx, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
goalFx.destroy();
}
});
};
self.showMiss = function () {
var missFx = LK.getAsset('missCircle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.addChild(missFx);
tween(missFx, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
missFx.destroy();
}
});
};
// Ball update
self.update = function () {
if (self.isShot) {
self.x += self.vx;
self.y += self.vy;
// Simulate friction/air resistance
self.vx *= 0.99;
self.vy *= 0.99;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a472a // Dark green pitch
});
/****
* Game Code
****/
// Goal feedback (yellow)
// Miss feedback (red)
// Net posts (gray)
// Ball shadow (gray)
// Goal area (light green)
// Goalkeeper (blue)
// Soccer ball (white)
// --- Game constants ---
var goalWidth = 900;
var goalHeight = 40;
var goalY = 420; // Y position of goal line
var goalX = (2048 - goalWidth) / 2;
var goalLeftX = goalX;
var goalRightX = goalX + goalWidth;
var goalPostHeight = 180;
var shotsTotal = 10;
// --- Game state ---
var balls = [];
var shotsLeft = shotsTotal;
var score = 0;
var isShooting = false;
var canShoot = true;
var swipeStart = null;
var swipeEnd = null;
var currentBall = null;
var goalkeeper = null;
var lastGoalkeeperSpeedupScore = 0;
// --- UI Elements ---
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFF700
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var shotsTxt = new Text2('Shots: ' + shotsLeft, {
size: 70,
fill: 0xFFFFFF
});
shotsTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(shotsTxt);
shotsTxt.y = 120;
// --- Draw goal area ---
var goalArea = LK.getAsset('goalArea', {
anchorX: 0,
anchorY: 0,
x: goalX,
y: goalY
});
game.addChild(goalArea);
// Goal posts
var leftPost = LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: goalLeftX,
y: goalY + goalPostHeight
});
var rightPost = LK.getAsset('goalPost', {
anchorX: 0.5,
anchorY: 1,
x: goalRightX,
y: goalY + goalPostHeight
});
game.addChild(leftPost);
game.addChild(rightPost);
// --- Add goalkeeper ---
goalkeeper = new Goalkeeper();
goalkeeper.x = 2048 / 2;
goalkeeper.y = goalY + 40;
game.addChild(goalkeeper);
// --- Ball spawn position ---
var ballStartX = 2048 / 2;
var ballStartY = 2732 - 320;
// --- Functions ---
function spawnBall() {
var ball = new SoccerBall();
ball.x = ballStartX;
ball.y = ballStartY;
balls.push(ball);
game.addChild(ball);
currentBall = ball;
isShooting = false;
canShoot = true;
}
function resetGame() {
// Remove all balls
for (var i = 0; i < balls.length; ++i) {
balls[i].destroy();
}
balls = [];
shotsLeft = shotsTotal;
score = 0;
lastGoalkeeperSpeedupScore = 0;
scoreTxt.setText(score);
shotsTxt.setText('Shots: ' + shotsLeft);
goalkeeper.speed = 8;
goalkeeper.x = 2048 / 2;
spawnBall();
}
function shootBall(vx, vy) {
if (!currentBall || !canShoot) return;
currentBall.vx = vx;
currentBall.vy = vy;
currentBall.isShot = true;
isShooting = true;
canShoot = false;
shotsLeft -= 1;
shotsTxt.setText('Shots: ' + shotsLeft);
}
// --- Input handling (swipe or tap) ---
game.down = function (x, y, obj) {
if (!canShoot) return;
// Only allow starting swipe/tap from lower half of screen
if (y < 1800) return;
swipeStart = {
x: x,
y: y
};
swipeEnd = null;
};
game.move = function (x, y, obj) {
if (!canShoot || !swipeStart) return;
swipeEnd = {
x: x,
y: y
};
};
game.up = function (x, y, obj) {
if (!canShoot || !swipeStart) return;
swipeEnd = {
x: x,
y: y
};
// Calculate direction and power
var dx = swipeEnd.x - swipeStart.x;
var dy = swipeEnd.y - swipeStart.y;
// Only allow upward swipes/taps
if (dy > -40) {
// Not enough upward movement, treat as tap
dx = 0;
dy = -900;
}
// Clamp power
var power = Math.sqrt(dx * dx + dy * dy);
if (power < 200) power = 200;
if (power > 1200) power = 1200;
// Normalize
var norm = Math.sqrt(dx * dx + dy * dy);
var vx = 0,
vy = 0;
if (norm > 0) {
vx = dx / norm * (power / 22);
vy = dy / norm * (power / 18);
} else {
vx = 0;
vy = -power / 18;
}
shootBall(vx, vy);
swipeStart = null;
swipeEnd = null;
};
// --- Main update loop ---
game.update = function () {
// Update goalkeeper
if (goalkeeper) goalkeeper.update();
// Update balls
for (var i = balls.length - 1; i >= 0; --i) {
var ball = balls[i];
ball.update();
// Only check for scoring/miss if ball is shot and not already scored/missed
if (ball.isShot && !ball.hasScored && !ball.hasMissed) {
// Check if ball crosses goal line (y <= goalY+goalHeight)
if (ball.y <= goalY + goalHeight / 2 && ball.y > goalY - 80) {
// Check if within goal posts
if (ball.x > goalLeftX + 60 && ball.x < goalRightX - 60) {
// Check collision with goalkeeper
var keeperRect = {
x: goalkeeper.x - 110,
y: goalkeeper.y - 40,
w: 220,
h: 80
};
var ballRect = {
x: ball.x - 60,
y: ball.y - 60,
w: 120,
h: 120
};
var intersects = !(keeperRect.x + keeperRect.w < ballRect.x || keeperRect.x > ballRect.x + ballRect.w || keeperRect.y + keeperRect.h < ballRect.y || keeperRect.y > ballRect.y + ballRect.h);
if (!intersects) {
// GOAL!
ball.hasScored = true;
score += 1;
scoreTxt.setText(score);
ball.showGoal();
// Speed up goalkeeper every 2 goals
if (score - lastGoalkeeperSpeedupScore >= 2) {
goalkeeper.increaseSpeed();
lastGoalkeeperSpeedupScore = score;
}
} else {
// Saved by keeper
ball.hasMissed = true;
ball.showMiss();
}
} else {
// Missed wide
ball.hasMissed = true;
ball.showMiss();
}
}
// Missed high
if (ball.y < goalY - 100) {
if (!ball.hasScored && !ball.hasMissed) {
ball.hasMissed = true;
ball.showMiss();
}
}
}
// Remove ball if out of bounds
if (ball.y < -200 || ball.x < -200 || ball.x > 2248) {
ball.destroy();
balls.splice(i, 1);
if (currentBall === ball) currentBall = null;
}
}
// After shot, wait for ball to stop or leave screen, then spawn next ball or end game
if (isShooting && !currentBall) {
if (shotsLeft > 0) {
spawnBall();
} else {
// Game over
LK.showGameOver();
}
isShooting = false;
}
// If current ball is shot and has scored/missed, and is slow or out of bounds, remove it
if (currentBall && currentBall.isShot && (currentBall.hasScored || currentBall.hasMissed)) {
var speed = Math.sqrt(currentBall.vx * currentBall.vx + currentBall.vy * currentBall.vy);
if (speed < 2 || currentBall.y < -200 || currentBall.x < -200 || currentBall.x > 2248) {
currentBall.destroy();
for (var j = 0; j < balls.length; ++j) {
if (balls[j] === currentBall) {
balls.splice(j, 1);
break;
}
}
currentBall = null;
}
}
// Win condition: score 10 goals
if (score >= 10) {
LK.showYouWin();
}
};
// --- Start game ---
resetGame();