User prompt
Topu sürüklemeyi sil
User prompt
Hataları düzelt
User prompt
Top sürüklemeyi kapdır
User prompt
Gol attığımızda yeee diye ses çıksın
User prompt
Topa falso verelim
User prompt
Saha yap
User prompt
Yarı sahayı geltiğimizde kontol bizden çıksın top dışarı çıksın
User prompt
Topu parmağımızla sürükliyerek oraya gitmesini sağla
User prompt
Bölümleri 50 yap
Code edit (1 edits merged)
Please save this source code
User prompt
Futbol Flick
Initial prompt
Futbol
/**** * 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();
});