/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Defender class (moves horizontally) var Defender = Container.expand(function () { var self = Container.call(this); // Attach defender asset (rectangle, blue) var defender = self.attachAsset('defender', { anchorX: 0.5, anchorY: 0.5 }); self.width = defender.width; self.height = defender.height; // Movement self.speed = 8 + Math.random() * 6; self.direction = Math.random() > 0.5 ? 1 : -1; // For collision self.left = function () { return self.x - self.width / 2; }; self.right = function () { return self.x + self.width / 2; }; self.top = function () { return self.y - self.height / 2; }; self.bottom = function () { return self.y + self.height / 2; }; self.update = function () { self.x += self.speed * self.direction; // Bounce at edges if (self.x < 300 + self.width / 2) { self.x = 300 + self.width / 2; self.direction *= -1; } if (self.x > 2048 - 300 - self.width / 2) { self.x = 2048 - 300 - self.width / 2; self.direction *= -1; } }; return self; }); // Goal class var Goal = Container.expand(function () { var self = Container.call(this); // Attach goal asset (rectangle, yellow) var goal = self.attachAsset('goal', { anchorX: 0.5, anchorY: 0.5 }); // Set size self.width = goal.width; self.height = goal.height; // For collision self.left = function () { return self.x - self.width / 2; }; self.right = function () { return self.x + self.width / 2; }; self.top = function () { return self.y - self.height / 2; }; self.bottom = function () { return self.y + self.height / 2; }; return self; }); // Obstacle class (static) var Obstacle = Container.expand(function () { var self = Container.call(this); // Attach obstacle asset (ellipse, gray) var obs = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.radius = obs.width / 2; return self; }); // Soccer Ball class var SoccerBall = Container.expand(function () { var self = Container.call(this); // Attach ball asset (ellipse, white) var ball = self.attachAsset('soccerBall', { anchorX: 0.5, anchorY: 0.5 }); // Ball state self.isMoving = false; self.vx = 0; self.vy = 0; // Ball radius for collision self.radius = ball.width / 2; // Reset ball to center self.reset = function () { self.x = 2048 / 2; self.y = 2732 - 400; self.vx = 0; self.vy = 0; self.spin = 0; self.isMoving = false; }; // Update ball position self.update = function () { // Track lastY for transition detection if (self.lastY === undefined) self.lastY = self.y; if (self.isMoving) { // Apply spin (curve/falso) to the ball's movement if (typeof self.spin === "number" && Math.abs(self.spin) > 0.01) { // The spin affects vx, causing the ball to curve as it moves // The effect increases as the ball moves up the field (simulate air time) // We'll apply a small portion of spin to vx each frame, proportional to vy self.vx += self.spin * 0.18 * (Math.abs(self.vy) / 18); // Gradually reduce spin over time (air resistance) self.spin *= 0.97; } self.x += self.vx; self.y += self.vy; // Friction self.vx *= 0.98; self.vy *= 0.98; // If ball crosses half field (y < 1366) for the first time, lose control and send it out if (self.lastY >= 1366 && self.y < 1366 && self.isMoving) { // Ball loses control: set a strong upward velocity and disable flicking self.vx = 0; self.vy = -40; self.spin = 0; canFlick = false; isDragging = false; // Prevent further flicks until reset self.isMoving = true; } // Stop if very slow if (Math.abs(self.vx) < 1 && Math.abs(self.vy) < 1) { self.vx = 0; self.vy = 0; self.spin = 0; self.isMoving = false; } } self.lastY = self.y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a7a2e // Green soccer field }); /**** * Game Code ****/ // Game variables // Tween for animations // Asset initialization var ball; var goal; var defenders = []; var obstacles = []; var score = 0; var timeLeft = 30; // seconds var isDragging = false; var dragStart = { x: 0, y: 0 }; var dragEnd = { x: 0, y: 0 }; var canFlick = true; var timerInterval; var scoreTxt; var timerTxt; var lastGoal = false; var lastMiss = false; var gameActive = true; // Draw soccer field background (field, center line, penalty areas) var field = LK.getAsset('centerCircle', { width: 2048, height: 2732, color: 0x1a7a2e, shape: 'box', anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(field); // Center line var centerLine = LK.getAsset('centerCircle', { width: 2048, height: 10, color: 0xffffff, shape: 'box', anchorX: 0, anchorY: 0.5, x: 0, y: 1366 }); game.addChild(centerLine); // Center circle var centerCircle = LK.getAsset('centerCircle', { width: 400, height: 400, color: 0xffffff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366 }); centerCircle.alpha = 0.25; game.addChild(centerCircle); // Penalty area (top) var penaltyTop = LK.getAsset('centerCircle', { width: 700, height: 180, color: 0xffffff, shape: 'box', anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 220 }); penaltyTop.alpha = 0.18; game.addChild(penaltyTop); // Penalty area (bottom) var penaltyBottom = LK.getAsset('centerCircle', { width: 700, height: 180, color: 0xffffff, shape: 'box', anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 2732 - 220 }); penaltyBottom.alpha = 0.18; game.addChild(penaltyBottom); // Add goal at top center goal = new Goal(); goal.x = 2048 / 2; goal.y = 220; game.addChild(goal); // Add ball at bottom center ball = new SoccerBall(); ball.reset(); game.addChild(ball); // Add defenders (start with 1, increase as score increases) function spawnDefenders(num) { // Remove old defenders for (var i = 0; i < defenders.length; i++) { defenders[i].destroy(); } defenders = []; for (var i = 0; i < num; i++) { var d = new Defender(); d.x = 2048 / 2 + (i - (num - 1) / 2) * 350; d.y = goal.y + 220 + i * 60; game.addChild(d); defenders.push(d); } } spawnDefenders(1); // Add obstacles (static, increase as score increases) function spawnObstacles(num) { for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; for (var i = 0; i < num; i++) { var obs = new Obstacle(); obs.x = 2048 / 2 + (i - (num - 1) / 2) * 250; obs.y = 1200 + i * 120; game.addChild(obs); obstacles.push(obs); } } spawnObstacles(0); // Score text scoreTxt = new Text2('0', { size: 120, fill: 0xFFF700 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Timer text timerTxt = new Text2('30', { size: 100, fill: 0xFFFFFF }); timerTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(timerTxt); // Timer logic function startTimer() { timeLeft = 30; timerTxt.setText(timeLeft); if (timerInterval) LK.clearInterval(timerInterval); timerInterval = LK.setInterval(function () { if (!gameActive) return; timeLeft -= 1; if (timeLeft < 0) timeLeft = 0; timerTxt.setText(timeLeft); if (timeLeft <= 0) { endGame(); } }, 1000); } startTimer(); // End game function endGame() { gameActive = false; canFlick = false; LK.effects.flashScreen(0x000000, 800); LK.showGameOver(); } // Flick controls game.down = function (x, y, obj) { if (!gameActive) return; // Only allow flick if ball is not moving and touch is near ball var dx = x - ball.x; var dy = y - ball.y; var dist = Math.sqrt(dx * dx + dy * dy); if (!ball.isMoving && dist < ball.radius + 40 && canFlick) { isDragging = true; dragStart.x = x; dragStart.y = y; dragEnd.x = x; dragEnd.y = y; } // Prevent dragging if ball has lost control (after half field) if (ball.isMoving && !canFlick) { isDragging = false; } }; game.move = function (x, y, obj) { if (!gameActive) return; if (isDragging) { dragEnd.x = x; dragEnd.y = y; } }; game.up = function (x, y, obj) { if (!gameActive) return; if (isDragging) { isDragging = false; // Prevent flick if ball has lost control (after half field) if (!canFlick) return; // Calculate flick vector var dx = dragEnd.x - dragStart.x; var dy = dragEnd.y - dragStart.y; // Only flick if drag is upwards and long enough if (dy < -60) { // Flick strength var strength = Math.min(Math.sqrt(dx * dx + dy * dy), 900); var angle = Math.atan2(dy, dx); // Set ball velocity ball.vx = Math.cos(angle) * (strength / 18); ball.vy = Math.sin(angle) * (strength / 18); // Calculate spin (falso) based on horizontal flick component // The more horizontal the flick, the more spin // Spin direction: right flick = right curve, left flick = left curve // Clamp spin to reasonable range var maxSpin = 2.5; var spin = Math.max(-maxSpin, Math.min(maxSpin, dx / 120)); ball.spin = spin; ball.isMoving = true; canFlick = false; } } }; // Main update loop game.update = function () { if (!gameActive) return; // Ball update ball.update(); // Defenders update for (var i = 0; i < defenders.length; i++) { defenders[i].update(); } // Check collisions with defenders if (ball.isMoving) { for (var i = 0; i < defenders.length; i++) { var d = defenders[i]; if (ball.x + ball.radius > d.left() && ball.x - ball.radius < d.right() && ball.y + ball.radius > d.top() && ball.y - ball.radius < d.bottom()) { // Hit defender: miss if (!lastMiss) { lastMiss = true; LK.effects.flashObject(ball, 0xff0000, 500); tween(ball, { x: ball.x, y: ball.y }, { duration: 200, onFinish: function onFinish() { ball.reset(); canFlick = true; lastMiss = false; } }); } return; } } } // Check collisions with obstacles if (ball.isMoving) { for (var i = 0; i < obstacles.length; i++) { var obs = obstacles[i]; var dx = ball.x - obs.x; var dy = ball.y - obs.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < ball.radius + obs.radius) { // Hit obstacle: miss if (!lastMiss) { lastMiss = true; LK.effects.flashObject(ball, 0xff0000, 500); tween(ball, { x: ball.x, y: ball.y }, { duration: 200, onFinish: function onFinish() { ball.reset(); canFlick = true; lastMiss = false; } }); } return; } } } // Check if ball enters goal if (ball.isMoving) { if (ball.y - ball.radius < goal.bottom() && ball.x > goal.left() + 40 && ball.x < goal.right() - 40) { // Goal! if (!lastGoal) { lastGoal = true; score += 1; LK.setScore(score); scoreTxt.setText(score); LK.effects.flashObject(goal, 0x00ff00, 400); // Animate ball into goal tween(ball, { y: goal.y }, { duration: 180, onFinish: function onFinish() { ball.reset(); canFlick = true; lastGoal = false; } }); // Increase difficulty for up to 50 levels // Level progression: every 2 goals, add a defender (up to 6), every 5 goals, add an obstacle (up to 6) var defendersToSpawn = 1 + Math.floor(score / 2); if (defendersToSpawn > 6) defendersToSpawn = 6; var obstaclesToSpawn = Math.floor(score / 5); if (obstaclesToSpawn > 6) obstaclesToSpawn = 6; // Only update defenders/obstacles when reaching a new level if (score > 0 && score <= 50) { if (score % 2 === 0 && defenders.length !== defendersToSpawn) { spawnDefenders(defendersToSpawn); } if (score % 5 === 0 && obstacles.length !== obstaclesToSpawn) { spawnObstacles(obstaclesToSpawn); } } } return; } } // If ball goes out of bounds (top, bottom, sides) if (ball.x < -100 || ball.x > 2048 + 100 || ball.y < -100 || ball.y > 2732 + 100) { if (!lastMiss) { lastMiss = true; LK.effects.flashObject(ball, 0xff0000, 500); tween(ball, { x: 2048 / 2, y: 2732 - 400 }, { duration: 200, onFinish: function onFinish() { ball.reset(); canFlick = true; lastMiss = false; } }); } return; } }; // Reset game state on game over game.on('destroy', function () { if (timerInterval) LK.clearInterval(timerInterval); defenders = []; obstacles = []; score = 0; timeLeft = 30; isDragging = false; canFlick = true; lastGoal = false; lastMiss = false; gameActive = true; }); // Play again: reset everything game.on('restart', function () { ball.reset(); score = 0; LK.setScore(0); scoreTxt.setText(0); timeLeft = 30; timerTxt.setText(timeLeft); spawnDefenders(1); spawnObstacles(0); canFlick = true; lastGoal = false; lastMiss = false; gameActive = true; startTimer(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Defender class (moves horizontally)
var Defender = Container.expand(function () {
var self = Container.call(this);
// Attach defender asset (rectangle, blue)
var defender = self.attachAsset('defender', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = defender.width;
self.height = defender.height;
// Movement
self.speed = 8 + Math.random() * 6;
self.direction = Math.random() > 0.5 ? 1 : -1;
// For collision
self.left = function () {
return self.x - self.width / 2;
};
self.right = function () {
return self.x + self.width / 2;
};
self.top = function () {
return self.y - self.height / 2;
};
self.bottom = function () {
return self.y + self.height / 2;
};
self.update = function () {
self.x += self.speed * self.direction;
// Bounce at edges
if (self.x < 300 + self.width / 2) {
self.x = 300 + self.width / 2;
self.direction *= -1;
}
if (self.x > 2048 - 300 - self.width / 2) {
self.x = 2048 - 300 - self.width / 2;
self.direction *= -1;
}
};
return self;
});
// Goal class
var Goal = Container.expand(function () {
var self = Container.call(this);
// Attach goal asset (rectangle, yellow)
var goal = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
});
// Set size
self.width = goal.width;
self.height = goal.height;
// For collision
self.left = function () {
return self.x - self.width / 2;
};
self.right = function () {
return self.x + self.width / 2;
};
self.top = function () {
return self.y - self.height / 2;
};
self.bottom = function () {
return self.y + self.height / 2;
};
return self;
});
// Obstacle class (static)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Attach obstacle asset (ellipse, gray)
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = obs.width / 2;
return self;
});
// Soccer Ball class
var SoccerBall = Container.expand(function () {
var self = Container.call(this);
// Attach ball asset (ellipse, white)
var ball = self.attachAsset('soccerBall', {
anchorX: 0.5,
anchorY: 0.5
});
// Ball state
self.isMoving = false;
self.vx = 0;
self.vy = 0;
// Ball radius for collision
self.radius = ball.width / 2;
// Reset ball to center
self.reset = function () {
self.x = 2048 / 2;
self.y = 2732 - 400;
self.vx = 0;
self.vy = 0;
self.spin = 0;
self.isMoving = false;
};
// Update ball position
self.update = function () {
// Track lastY for transition detection
if (self.lastY === undefined) self.lastY = self.y;
if (self.isMoving) {
// Apply spin (curve/falso) to the ball's movement
if (typeof self.spin === "number" && Math.abs(self.spin) > 0.01) {
// The spin affects vx, causing the ball to curve as it moves
// The effect increases as the ball moves up the field (simulate air time)
// We'll apply a small portion of spin to vx each frame, proportional to vy
self.vx += self.spin * 0.18 * (Math.abs(self.vy) / 18);
// Gradually reduce spin over time (air resistance)
self.spin *= 0.97;
}
self.x += self.vx;
self.y += self.vy;
// Friction
self.vx *= 0.98;
self.vy *= 0.98;
// If ball crosses half field (y < 1366) for the first time, lose control and send it out
if (self.lastY >= 1366 && self.y < 1366 && self.isMoving) {
// Ball loses control: set a strong upward velocity and disable flicking
self.vx = 0;
self.vy = -40;
self.spin = 0;
canFlick = false;
isDragging = false;
// Prevent further flicks until reset
self.isMoving = true;
}
// Stop if very slow
if (Math.abs(self.vx) < 1 && Math.abs(self.vy) < 1) {
self.vx = 0;
self.vy = 0;
self.spin = 0;
self.isMoving = false;
}
}
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a7a2e // Green soccer field
});
/****
* Game Code
****/
// Game variables
// Tween for animations
// Asset initialization
var ball;
var goal;
var defenders = [];
var obstacles = [];
var score = 0;
var timeLeft = 30; // seconds
var isDragging = false;
var dragStart = {
x: 0,
y: 0
};
var dragEnd = {
x: 0,
y: 0
};
var canFlick = true;
var timerInterval;
var scoreTxt;
var timerTxt;
var lastGoal = false;
var lastMiss = false;
var gameActive = true;
// Draw soccer field background (field, center line, penalty areas)
var field = LK.getAsset('centerCircle', {
width: 2048,
height: 2732,
color: 0x1a7a2e,
shape: 'box',
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(field);
// Center line
var centerLine = LK.getAsset('centerCircle', {
width: 2048,
height: 10,
color: 0xffffff,
shape: 'box',
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 1366
});
game.addChild(centerLine);
// Center circle
var centerCircle = LK.getAsset('centerCircle', {
width: 400,
height: 400,
color: 0xffffff,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366
});
centerCircle.alpha = 0.25;
game.addChild(centerCircle);
// Penalty area (top)
var penaltyTop = LK.getAsset('centerCircle', {
width: 700,
height: 180,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 220
});
penaltyTop.alpha = 0.18;
game.addChild(penaltyTop);
// Penalty area (bottom)
var penaltyBottom = LK.getAsset('centerCircle', {
width: 700,
height: 180,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2732 - 220
});
penaltyBottom.alpha = 0.18;
game.addChild(penaltyBottom);
// Add goal at top center
goal = new Goal();
goal.x = 2048 / 2;
goal.y = 220;
game.addChild(goal);
// Add ball at bottom center
ball = new SoccerBall();
ball.reset();
game.addChild(ball);
// Add defenders (start with 1, increase as score increases)
function spawnDefenders(num) {
// Remove old defenders
for (var i = 0; i < defenders.length; i++) {
defenders[i].destroy();
}
defenders = [];
for (var i = 0; i < num; i++) {
var d = new Defender();
d.x = 2048 / 2 + (i - (num - 1) / 2) * 350;
d.y = goal.y + 220 + i * 60;
game.addChild(d);
defenders.push(d);
}
}
spawnDefenders(1);
// Add obstacles (static, increase as score increases)
function spawnObstacles(num) {
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
for (var i = 0; i < num; i++) {
var obs = new Obstacle();
obs.x = 2048 / 2 + (i - (num - 1) / 2) * 250;
obs.y = 1200 + i * 120;
game.addChild(obs);
obstacles.push(obs);
}
}
spawnObstacles(0);
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFF700
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Timer text
timerTxt = new Text2('30', {
size: 100,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(timerTxt);
// Timer logic
function startTimer() {
timeLeft = 30;
timerTxt.setText(timeLeft);
if (timerInterval) LK.clearInterval(timerInterval);
timerInterval = LK.setInterval(function () {
if (!gameActive) return;
timeLeft -= 1;
if (timeLeft < 0) timeLeft = 0;
timerTxt.setText(timeLeft);
if (timeLeft <= 0) {
endGame();
}
}, 1000);
}
startTimer();
// End game
function endGame() {
gameActive = false;
canFlick = false;
LK.effects.flashScreen(0x000000, 800);
LK.showGameOver();
}
// Flick controls
game.down = function (x, y, obj) {
if (!gameActive) return;
// Only allow flick if ball is not moving and touch is near ball
var dx = x - ball.x;
var dy = y - ball.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (!ball.isMoving && dist < ball.radius + 40 && canFlick) {
isDragging = true;
dragStart.x = x;
dragStart.y = y;
dragEnd.x = x;
dragEnd.y = y;
}
// Prevent dragging if ball has lost control (after half field)
if (ball.isMoving && !canFlick) {
isDragging = false;
}
};
game.move = function (x, y, obj) {
if (!gameActive) return;
if (isDragging) {
dragEnd.x = x;
dragEnd.y = y;
}
};
game.up = function (x, y, obj) {
if (!gameActive) return;
if (isDragging) {
isDragging = false;
// Prevent flick if ball has lost control (after half field)
if (!canFlick) return;
// Calculate flick vector
var dx = dragEnd.x - dragStart.x;
var dy = dragEnd.y - dragStart.y;
// Only flick if drag is upwards and long enough
if (dy < -60) {
// Flick strength
var strength = Math.min(Math.sqrt(dx * dx + dy * dy), 900);
var angle = Math.atan2(dy, dx);
// Set ball velocity
ball.vx = Math.cos(angle) * (strength / 18);
ball.vy = Math.sin(angle) * (strength / 18);
// Calculate spin (falso) based on horizontal flick component
// The more horizontal the flick, the more spin
// Spin direction: right flick = right curve, left flick = left curve
// Clamp spin to reasonable range
var maxSpin = 2.5;
var spin = Math.max(-maxSpin, Math.min(maxSpin, dx / 120));
ball.spin = spin;
ball.isMoving = true;
canFlick = false;
}
}
};
// Main update loop
game.update = function () {
if (!gameActive) return;
// Ball update
ball.update();
// Defenders update
for (var i = 0; i < defenders.length; i++) {
defenders[i].update();
}
// Check collisions with defenders
if (ball.isMoving) {
for (var i = 0; i < defenders.length; i++) {
var d = defenders[i];
if (ball.x + ball.radius > d.left() && ball.x - ball.radius < d.right() && ball.y + ball.radius > d.top() && ball.y - ball.radius < d.bottom()) {
// Hit defender: miss
if (!lastMiss) {
lastMiss = true;
LK.effects.flashObject(ball, 0xff0000, 500);
tween(ball, {
x: ball.x,
y: ball.y
}, {
duration: 200,
onFinish: function onFinish() {
ball.reset();
canFlick = true;
lastMiss = false;
}
});
}
return;
}
}
}
// Check collisions with obstacles
if (ball.isMoving) {
for (var i = 0; i < obstacles.length; i++) {
var obs = obstacles[i];
var dx = ball.x - obs.x;
var dy = ball.y - obs.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < ball.radius + obs.radius) {
// Hit obstacle: miss
if (!lastMiss) {
lastMiss = true;
LK.effects.flashObject(ball, 0xff0000, 500);
tween(ball, {
x: ball.x,
y: ball.y
}, {
duration: 200,
onFinish: function onFinish() {
ball.reset();
canFlick = true;
lastMiss = false;
}
});
}
return;
}
}
}
// Check if ball enters goal
if (ball.isMoving) {
if (ball.y - ball.radius < goal.bottom() && ball.x > goal.left() + 40 && ball.x < goal.right() - 40) {
// Goal!
if (!lastGoal) {
lastGoal = true;
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
LK.effects.flashObject(goal, 0x00ff00, 400);
// Animate ball into goal
tween(ball, {
y: goal.y
}, {
duration: 180,
onFinish: function onFinish() {
ball.reset();
canFlick = true;
lastGoal = false;
}
});
// Increase difficulty for up to 50 levels
// Level progression: every 2 goals, add a defender (up to 6), every 5 goals, add an obstacle (up to 6)
var defendersToSpawn = 1 + Math.floor(score / 2);
if (defendersToSpawn > 6) defendersToSpawn = 6;
var obstaclesToSpawn = Math.floor(score / 5);
if (obstaclesToSpawn > 6) obstaclesToSpawn = 6;
// Only update defenders/obstacles when reaching a new level
if (score > 0 && score <= 50) {
if (score % 2 === 0 && defenders.length !== defendersToSpawn) {
spawnDefenders(defendersToSpawn);
}
if (score % 5 === 0 && obstacles.length !== obstaclesToSpawn) {
spawnObstacles(obstaclesToSpawn);
}
}
}
return;
}
}
// If ball goes out of bounds (top, bottom, sides)
if (ball.x < -100 || ball.x > 2048 + 100 || ball.y < -100 || ball.y > 2732 + 100) {
if (!lastMiss) {
lastMiss = true;
LK.effects.flashObject(ball, 0xff0000, 500);
tween(ball, {
x: 2048 / 2,
y: 2732 - 400
}, {
duration: 200,
onFinish: function onFinish() {
ball.reset();
canFlick = true;
lastMiss = false;
}
});
}
return;
}
};
// Reset game state on game over
game.on('destroy', function () {
if (timerInterval) LK.clearInterval(timerInterval);
defenders = [];
obstacles = [];
score = 0;
timeLeft = 30;
isDragging = false;
canFlick = true;
lastGoal = false;
lastMiss = false;
gameActive = true;
});
// Play again: reset everything
game.on('restart', function () {
ball.reset();
score = 0;
LK.setScore(0);
scoreTxt.setText(0);
timeLeft = 30;
timerTxt.setText(timeLeft);
spawnDefenders(1);
spawnObstacles(0);
canFlick = true;
lastGoal = false;
lastMiss = false;
gameActive = true;
startTimer();
});