/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
self.gravity = 0.3;
self.friction = 0.98;
self.shoot = function (targetX, targetY, power) {
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.velocityX = deltaX / distance * power * 0.8;
self.velocityY = deltaY / distance * power * 0.8;
self.isMoving = true;
LK.getSound('kick').play();
};
self.update = function () {
if (self.isMoving) {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Check collision with players
if (typeof players !== 'undefined') {
for (var p = 0; p < players.length; p++) {
if (self.intersects(players[p])) {
// Bounce off player
self.velocityX *= -0.5;
self.velocityY *= -0.5;
// Move ball away from player to prevent sticking
var dx = self.x - players[p].x;
var dy = self.y - players[p].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x = players[p].x + dx / dist * 60;
self.y = players[p].y + dy / dist * 60;
}
break;
}
}
}
// Stop ball if moving too slowly
if (Math.abs(self.velocityX) < 0.5 && Math.abs(self.velocityY) < 0.5) {
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
}
}
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 1
});
self.direction = 1;
self.speed = 2;
self.minX = 0;
self.maxX = 0;
self.setMovementRange = function (minX, maxX) {
self.minX = minX;
self.maxX = maxX;
};
self.update = function () {
self.x += self.speed * self.direction;
if (self.x <= self.minX || self.x >= self.maxX) {
self.direction *= -1;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1
});
self.originalX = 0;
self.originalY = 0;
self.speed = 1.5;
self.maxChaseDistance = 200;
self.setOriginalPosition = function (x, y) {
self.originalX = x;
self.originalY = y;
};
self.update = function () {
// Only chase ball if it's moving and game is in shooting state
if (typeof ball !== 'undefined' && ball.isMoving && gameState === 'shooting') {
var deltaX = ball.x - self.x;
var deltaY = ball.y - self.y;
var distanceToBall = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if ball is within chase range
var distanceFromOriginal = Math.sqrt((self.x - self.originalX) * (self.x - self.originalX) + (self.y - self.originalY) * (self.y - self.originalY));
if (distanceToBall < 300 && distanceFromOriginal < self.maxChaseDistance) {
// Move towards ball
if (distanceToBall > 0) {
self.x += deltaX / distanceToBall * self.speed;
self.y += deltaY / distanceToBall * self.speed;
}
} else if (distanceFromOriginal > 10) {
// Return to original position if too far away
var returnDeltaX = self.originalX - self.x;
var returnDeltaY = self.originalY - self.y;
var returnDistance = Math.sqrt(returnDeltaX * returnDeltaX + returnDeltaY * returnDeltaY);
if (returnDistance > 0) {
self.x += returnDeltaX / returnDistance * self.speed * 0.5;
self.y += returnDeltaY / returnDistance * self.speed * 0.5;
}
}
} else if (typeof ball !== 'undefined' && !ball.isMoving) {
// Return to original position when ball is not moving
var returnDeltaX = self.originalX - self.x;
var returnDeltaY = self.originalY - self.y;
var returnDistance = Math.sqrt(returnDeltaX * returnDeltaX + returnDeltaY * returnDeltaY);
if (returnDistance > 5) {
self.x += returnDeltaX / returnDistance * self.speed * 0.3;
self.y += returnDeltaY / returnDistance * self.speed * 0.3;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentLevel = 1;
var gameState = 'aiming'; // 'aiming', 'shooting', 'scored', 'missed'
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
// Create field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0.5,
anchorY: 1,
x: 1024,
y: 2732
}));
// Goal posts
var leftPost = game.addChild(LK.getAsset('goalpost', {
anchorX: 0.5,
anchorY: 1,
x: 824,
y: 600
}));
var rightPost = game.addChild(LK.getAsset('goalpost', {
anchorX: 0.5,
anchorY: 1,
x: 1224,
y: 600
}));
var crossbar = game.addChild(LK.getAsset('crossbar', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 400
}));
// Create ball
var ball = game.addChild(new Ball());
ball.x = 1024;
ball.y = 2200;
// Create goalkeeper
var goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = 1024;
var goalY = 580;
goalkeeper.y = goalY;
goalkeeper.setMovementRange(850, 1198);
// Create 16 players positioned across the field
var players = [];
var playerPositions = [
// Defense line (4 players)
{
x: 600,
y: 800
}, {
x: 900,
y: 850
}, {
x: 1148,
y: 850
}, {
x: 1448,
y: 800
},
// Midfield line (6 players)
{
x: 400,
y: 1200
}, {
x: 700,
y: 1300
}, {
x: 1000,
y: 1250
}, {
x: 1348,
y: 1250
}, {
x: 1648,
y: 1300
}, {
x: 1900,
y: 1200
},
// Forward line (4 players)
{
x: 600,
y: 1700
}, {
x: 900,
y: 1650
}, {
x: 1148,
y: 1650
}, {
x: 1448,
y: 1700
},
// Additional midfield players (2 players)
{
x: 512,
y: 1500
}, {
x: 1536,
y: 1500
}];
for (var i = 0; i < playerPositions.length; i++) {
var player = game.addChild(new Player());
player.x = playerPositions[i].x;
player.y = playerPositions[i].y;
player.setOriginalPosition(playerPositions[i].x, playerPositions[i].y);
players.push(player);
}
// Aim line (initially hidden)
var aimLine = game.addChild(LK.getAsset('aimLine', {
anchorX: 0.5,
anchorY: 1,
alpha: 0
}));
// UI Elements
var scoreTxt = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionTxt = new Text2('Drag to aim, release to shoot!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionTxt);
function resetLevel() {
ball.x = 1024;
ball.y = 2200;
ball.velocityX = 0;
ball.velocityY = 0;
ball.isMoving = false;
gameState = 'aiming';
aimLine.alpha = 0;
// Increase goalkeeper speed with level
goalkeeper.speed = 2 + (currentLevel - 1) * 0.5;
scoreTxt.setText('Level: ' + currentLevel);
}
function checkGoal() {
// Check if ball is in goal area
if (ball.x > 824 && ball.x < 1224 && ball.y < 600 && ball.y > 400) {
// Check if goalkeeper didn't save it
var distanceToKeeper = Math.abs(ball.x - goalkeeper.x);
if (distanceToKeeper > 50) {
// Goal scored!
gameState = 'scored';
LK.getSound('goal').play();
LK.setScore(LK.getScore() + currentLevel * 10);
// Flash screen green
LK.effects.flashScreen(0x00ff00, 1000);
// Advance to next level after delay
LK.setTimeout(function () {
currentLevel++;
resetLevel();
}, 1500);
return true;
} else {
// Goalkeeper saved it
gameState = 'missed';
LK.getSound('save').play();
LK.effects.flashScreen(0xff0000, 500);
LK.setTimeout(function () {
resetLevel();
}, 1000);
return true;
}
}
return false;
}
function checkMiss() {
// Ball went off screen or stopped without scoring
if (ball.y < 300 || ball.x < 0 || ball.x > 2048 || !ball.isMoving && gameState === 'shooting') {
gameState = 'missed';
LK.setTimeout(function () {
resetLevel();
}, 1000);
return true;
}
return false;
}
// Touch/Mouse handlers
game.down = function (x, y, obj) {
if (gameState === 'aiming' && !ball.isMoving) {
isDragging = true;
dragStartX = x;
dragStartY = y;
aimLine.alpha = 0.7;
}
};
game.move = function (x, y, obj) {
if (isDragging && gameState === 'aiming') {
var deltaX = x - ball.x;
var deltaY = y - ball.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Update aim line position and rotation
aimLine.x = ball.x;
aimLine.y = ball.y;
aimLine.rotation = Math.atan2(deltaY, deltaX) + Math.PI / 2;
// Scale aim line based on power - increased sensitivity
var power = Math.min(distance / 1.5, 80);
aimLine.scaleY = power / 8;
}
};
game.up = function (x, y, obj) {
if (isDragging && gameState === 'aiming') {
isDragging = false;
aimLine.alpha = 0;
var deltaX = x - ball.x;
var deltaY = y - ball.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var power = Math.min(distance / 1.5, 80);
if (power > 3) {
ball.shoot(x, y, power);
gameState = 'shooting';
}
}
};
// Main game loop
game.update = function () {
// Update goalkeeper movement
if (gameState !== 'scored') {
goalkeeper.update();
}
// Update all players
for (var p = 0; p < players.length; p++) {
players[p].update();
}
// Update ball physics
ball.update();
// Check for goal or miss
if (gameState === 'shooting') {
if (!checkGoal()) {
checkMiss();
}
}
// Win condition - reaching level 10
if (currentLevel > 10) {
LK.showYouWin();
}
};
// Initialize first level
resetLevel(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
self.gravity = 0.3;
self.friction = 0.98;
self.shoot = function (targetX, targetY, power) {
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.velocityX = deltaX / distance * power * 0.8;
self.velocityY = deltaY / distance * power * 0.8;
self.isMoving = true;
LK.getSound('kick').play();
};
self.update = function () {
if (self.isMoving) {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Check collision with players
if (typeof players !== 'undefined') {
for (var p = 0; p < players.length; p++) {
if (self.intersects(players[p])) {
// Bounce off player
self.velocityX *= -0.5;
self.velocityY *= -0.5;
// Move ball away from player to prevent sticking
var dx = self.x - players[p].x;
var dy = self.y - players[p].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x = players[p].x + dx / dist * 60;
self.y = players[p].y + dy / dist * 60;
}
break;
}
}
}
// Stop ball if moving too slowly
if (Math.abs(self.velocityX) < 0.5 && Math.abs(self.velocityY) < 0.5) {
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
}
}
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 1
});
self.direction = 1;
self.speed = 2;
self.minX = 0;
self.maxX = 0;
self.setMovementRange = function (minX, maxX) {
self.minX = minX;
self.maxX = maxX;
};
self.update = function () {
self.x += self.speed * self.direction;
if (self.x <= self.minX || self.x >= self.maxX) {
self.direction *= -1;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1
});
self.originalX = 0;
self.originalY = 0;
self.speed = 1.5;
self.maxChaseDistance = 200;
self.setOriginalPosition = function (x, y) {
self.originalX = x;
self.originalY = y;
};
self.update = function () {
// Only chase ball if it's moving and game is in shooting state
if (typeof ball !== 'undefined' && ball.isMoving && gameState === 'shooting') {
var deltaX = ball.x - self.x;
var deltaY = ball.y - self.y;
var distanceToBall = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if ball is within chase range
var distanceFromOriginal = Math.sqrt((self.x - self.originalX) * (self.x - self.originalX) + (self.y - self.originalY) * (self.y - self.originalY));
if (distanceToBall < 300 && distanceFromOriginal < self.maxChaseDistance) {
// Move towards ball
if (distanceToBall > 0) {
self.x += deltaX / distanceToBall * self.speed;
self.y += deltaY / distanceToBall * self.speed;
}
} else if (distanceFromOriginal > 10) {
// Return to original position if too far away
var returnDeltaX = self.originalX - self.x;
var returnDeltaY = self.originalY - self.y;
var returnDistance = Math.sqrt(returnDeltaX * returnDeltaX + returnDeltaY * returnDeltaY);
if (returnDistance > 0) {
self.x += returnDeltaX / returnDistance * self.speed * 0.5;
self.y += returnDeltaY / returnDistance * self.speed * 0.5;
}
}
} else if (typeof ball !== 'undefined' && !ball.isMoving) {
// Return to original position when ball is not moving
var returnDeltaX = self.originalX - self.x;
var returnDeltaY = self.originalY - self.y;
var returnDistance = Math.sqrt(returnDeltaX * returnDeltaX + returnDeltaY * returnDeltaY);
if (returnDistance > 5) {
self.x += returnDeltaX / returnDistance * self.speed * 0.3;
self.y += returnDeltaY / returnDistance * self.speed * 0.3;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentLevel = 1;
var gameState = 'aiming'; // 'aiming', 'shooting', 'scored', 'missed'
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
// Create field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0.5,
anchorY: 1,
x: 1024,
y: 2732
}));
// Goal posts
var leftPost = game.addChild(LK.getAsset('goalpost', {
anchorX: 0.5,
anchorY: 1,
x: 824,
y: 600
}));
var rightPost = game.addChild(LK.getAsset('goalpost', {
anchorX: 0.5,
anchorY: 1,
x: 1224,
y: 600
}));
var crossbar = game.addChild(LK.getAsset('crossbar', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 400
}));
// Create ball
var ball = game.addChild(new Ball());
ball.x = 1024;
ball.y = 2200;
// Create goalkeeper
var goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = 1024;
var goalY = 580;
goalkeeper.y = goalY;
goalkeeper.setMovementRange(850, 1198);
// Create 16 players positioned across the field
var players = [];
var playerPositions = [
// Defense line (4 players)
{
x: 600,
y: 800
}, {
x: 900,
y: 850
}, {
x: 1148,
y: 850
}, {
x: 1448,
y: 800
},
// Midfield line (6 players)
{
x: 400,
y: 1200
}, {
x: 700,
y: 1300
}, {
x: 1000,
y: 1250
}, {
x: 1348,
y: 1250
}, {
x: 1648,
y: 1300
}, {
x: 1900,
y: 1200
},
// Forward line (4 players)
{
x: 600,
y: 1700
}, {
x: 900,
y: 1650
}, {
x: 1148,
y: 1650
}, {
x: 1448,
y: 1700
},
// Additional midfield players (2 players)
{
x: 512,
y: 1500
}, {
x: 1536,
y: 1500
}];
for (var i = 0; i < playerPositions.length; i++) {
var player = game.addChild(new Player());
player.x = playerPositions[i].x;
player.y = playerPositions[i].y;
player.setOriginalPosition(playerPositions[i].x, playerPositions[i].y);
players.push(player);
}
// Aim line (initially hidden)
var aimLine = game.addChild(LK.getAsset('aimLine', {
anchorX: 0.5,
anchorY: 1,
alpha: 0
}));
// UI Elements
var scoreTxt = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionTxt = new Text2('Drag to aim, release to shoot!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionTxt);
function resetLevel() {
ball.x = 1024;
ball.y = 2200;
ball.velocityX = 0;
ball.velocityY = 0;
ball.isMoving = false;
gameState = 'aiming';
aimLine.alpha = 0;
// Increase goalkeeper speed with level
goalkeeper.speed = 2 + (currentLevel - 1) * 0.5;
scoreTxt.setText('Level: ' + currentLevel);
}
function checkGoal() {
// Check if ball is in goal area
if (ball.x > 824 && ball.x < 1224 && ball.y < 600 && ball.y > 400) {
// Check if goalkeeper didn't save it
var distanceToKeeper = Math.abs(ball.x - goalkeeper.x);
if (distanceToKeeper > 50) {
// Goal scored!
gameState = 'scored';
LK.getSound('goal').play();
LK.setScore(LK.getScore() + currentLevel * 10);
// Flash screen green
LK.effects.flashScreen(0x00ff00, 1000);
// Advance to next level after delay
LK.setTimeout(function () {
currentLevel++;
resetLevel();
}, 1500);
return true;
} else {
// Goalkeeper saved it
gameState = 'missed';
LK.getSound('save').play();
LK.effects.flashScreen(0xff0000, 500);
LK.setTimeout(function () {
resetLevel();
}, 1000);
return true;
}
}
return false;
}
function checkMiss() {
// Ball went off screen or stopped without scoring
if (ball.y < 300 || ball.x < 0 || ball.x > 2048 || !ball.isMoving && gameState === 'shooting') {
gameState = 'missed';
LK.setTimeout(function () {
resetLevel();
}, 1000);
return true;
}
return false;
}
// Touch/Mouse handlers
game.down = function (x, y, obj) {
if (gameState === 'aiming' && !ball.isMoving) {
isDragging = true;
dragStartX = x;
dragStartY = y;
aimLine.alpha = 0.7;
}
};
game.move = function (x, y, obj) {
if (isDragging && gameState === 'aiming') {
var deltaX = x - ball.x;
var deltaY = y - ball.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Update aim line position and rotation
aimLine.x = ball.x;
aimLine.y = ball.y;
aimLine.rotation = Math.atan2(deltaY, deltaX) + Math.PI / 2;
// Scale aim line based on power - increased sensitivity
var power = Math.min(distance / 1.5, 80);
aimLine.scaleY = power / 8;
}
};
game.up = function (x, y, obj) {
if (isDragging && gameState === 'aiming') {
isDragging = false;
aimLine.alpha = 0;
var deltaX = x - ball.x;
var deltaY = y - ball.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var power = Math.min(distance / 1.5, 80);
if (power > 3) {
ball.shoot(x, y, power);
gameState = 'shooting';
}
}
};
// Main game loop
game.update = function () {
// Update goalkeeper movement
if (gameState !== 'scored') {
goalkeeper.update();
}
// Update all players
for (var p = 0; p < players.length; p++) {
players[p].update();
}
// Update ball physics
ball.update();
// Check for goal or miss
if (gameState === 'shooting') {
if (!checkGoal()) {
checkMiss();
}
}
// Win condition - reaching level 10
if (currentLevel > 10) {
LK.showYouWin();
}
};
// Initialize first level
resetLevel();