/****
* 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.gravity = 0.2;
self.moving = false;
self.update = function () {
if (self.moving) {
self.x += self.velocityX;
self.y += self.velocityY;
// Apply gravity for side view - increase after score 3
var currentGravity = LK.getScore() >= 3 ? self.gravity * 1.5 : self.gravity;
self.velocityY += currentGravity;
// Apply increased air resistance to make shots harder - more resistance after score 3
var airResistanceX = LK.getScore() >= 3 ? 0.992 : 0.995;
var airResistanceY = LK.getScore() >= 3 ? 0.993 : 0.996;
self.velocityX *= airResistanceX;
self.velocityY *= airResistanceY;
// Field boundaries
if (self.x <= 50) {
self.x = 50;
self.velocityX *= -0.7;
}
if (self.x >= screenWidth - 50) {
self.x = screenWidth - 50;
self.velocityX *= -0.7;
}
if (self.y <= 50) {
self.y = 50;
self.velocityY *= -0.7;
}
if (self.y >= screenHeight - 50) {
self.y = screenHeight - 50;
self.velocityY *= -0.7;
}
if (Math.abs(self.velocityX) < 0.3 && Math.abs(self.velocityY) < 0.3) {
self.moving = false;
self.velocityX = 0;
self.velocityY = 0;
tween.stop(ballGraphics, {
rotation: true
});
}
}
};
self.shoot = function (targetX, targetY, power) {
var distance = Math.sqrt((targetX - self.x) * (targetX - self.x) + (targetY - self.y) * (targetY - self.y));
self.velocityX = (targetX - self.x) / distance * power;
self.velocityY = (targetY - self.y) / distance * power;
self.moving = true;
// Add realistic ball spin during movement
var spinSpeed = power * 0.3;
tween(ballGraphics, {
rotation: ballGraphics.rotation + spinSpeed
}, {
duration: 2000,
easing: tween.linear
});
// Add ball scale effect for power visualization
tween(ballGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
LK.getSound('kick').play();
};
return self;
});
var Goalkeeper = Container.expand(function () {
var self = Container.call(this);
var keeperGraphics = self.attachAsset('goalkeeper', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.3,
scaleY: 1.3
});
// After score 3, increase speed much more dramatically
if (LK.getScore() >= 3) {
self.speed = 3.0 + (LK.getScore() - 3) * 1.0; // Much faster after score 3
} else {
self.speed = 1.5 + LK.getScore() * 0.5; // Normal progression before score 3
}
self.direction = 1;
self.directionX = Math.random() > 0.5 ? 1 : -1;
self.reactionTime = 0;
self.isDiving = false;
// After score 3, reduce reaction time much more aggressively
if (LK.getScore() >= 3) {
self.maxReactionTime = 10 - (LK.getScore() - 3) * 2; // Much faster reactions after score 3
} else {
self.maxReactionTime = 25 - LK.getScore() * 3; // Normal progression before score 3
}
if (self.maxReactionTime < 2) {
self.maxReactionTime = 2; // Minimum reaction time for playability
}
// Add realistic goalkeeper breathing animation
tween(keeperGraphics, {
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(keeperGraphics, {
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Repeat breathing animation
LK.setTimeout(function () {
if (!self.isDiving) {
tween(keeperGraphics, {
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}, 500);
}
});
}
});
self.update = function () {
// Track ball when it's shot - move towards ball position
if (ball.moving) {
var ballDistance = Math.sqrt((ball.x - self.x) * (ball.x - self.x) + (ball.y - self.y) * (ball.y - self.y));
var trackingSpeed = self.speed * 1.2;
// Move towards ball position when ball is moving
if (ballDistance > 20 && !self.isDiving) {
var directionToBallX = (ball.x - self.x) / ballDistance;
var directionToBallY = (ball.y - self.y) / ballDistance;
// Apply tracking movement with increased intensity
self.x += directionToBallX * trackingSpeed;
self.y += directionToBallY * trackingSpeed;
}
} else {
// Random movement when ball is not moving - both vertical and horizontal
if (!self.isDiving && Math.random() < 0.02) {
self.direction *= -1;
}
if (!self.isDiving && Math.random() < 0.015) {
self.directionX *= -1;
}
if (!self.isDiving) {
self.y += self.direction * self.speed;
// Add horizontal movement
self.x += self.directionX * (self.speed * 0.5);
}
}
// Keep within goal bounds (vertical movement for side view)
if (self.y <= goalY + 50) {
self.y = goalY + 50;
self.direction = 1;
}
if (self.y >= goalY + goalHeight - 50) {
self.y = goalY + goalHeight - 50;
self.direction = -1;
}
// Keep within horizontal bounds
if (self.x <= goalX - 120) {
self.x = goalX - 120;
self.directionX = 1;
}
if (self.x >= goalX - 20) {
self.x = goalX - 20;
self.directionX = -1;
}
// React to ball when it's moving toward goal
if (ball.moving && ball.x > goalX - 200) {
self.reactionTime++;
if (self.reactionTime > self.maxReactionTime && !self.isDiving) {
self.isDiving = true;
var targetY = ball.y;
var targetX = Math.max(goalX - 100, Math.min(goalX - 30, ball.x));
// Dive animation with tween - now includes horizontal movement
tween(self, {
y: targetY,
x: targetX,
rotation: self.y < targetY ? 0.5 : -0.5
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset after dive
LK.setTimeout(function () {
self.isDiving = false;
tween(self, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}, 1000);
}
});
}
} else {
self.reactionTime = 0;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.isKicking = false;
// Idle breathing animation
self.startIdleAnimation = function () {
if (!self.isKicking) {
tween(playerGraphics, {
scaleY: 1.05
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playerGraphics, {
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
self.startIdleAnimation();
}, 200);
}
});
}
});
}
};
// Kicking animation
self.performKick = function () {
if (self.isKicking) return;
self.isKicking = true;
// Stop any idle animations
tween.stop(playerGraphics);
// Lean back preparation
tween(playerGraphics, {
rotation: -0.2,
scaleX: 0.9
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
// Forward kick motion
tween(playerGraphics, {
rotation: 0.3,
scaleX: 1.2,
x: self.x + 30
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to normal position
tween(playerGraphics, {
rotation: 0,
scaleX: 1.0,
x: self.x - 30
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isKicking = false;
// Resume idle animation
LK.setTimeout(function () {
self.startIdleAnimation();
}, 500);
}
});
}
});
}
});
};
// Start idle animation initially
LK.setTimeout(function () {
self.startIdleAnimation();
}, 100);
return self;
});
var Spectator = Container.expand(function () {
var self = Container.call(this);
var spectatorGraphics = self.attachAsset('spectator', {
anchorX: 0.5,
anchorY: 1.0
});
var headGraphics = self.attachAsset('spectatorHead', {
anchorX: 0.5,
anchorY: 0.5
});
headGraphics.y = -50;
self.addChild(headGraphics);
self.animationDelay = Math.random() * 2000;
self.isCheering = false;
// Random spectator colors
var colors = [0x4169E1, 0xFF6347, 0x32CD32, 0xFFD700, 0xFF69B4, 0x8A2BE2];
spectatorGraphics.tint = colors[Math.floor(Math.random() * colors.length)];
self.update = function () {
// Random cheering animation
if (Math.random() < 0.005 && !self.isCheering) {
self.isCheering = true;
tween(self, {
scaleY: 1.2,
y: self.y - 20
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleY: 1.0,
y: self.y + 20
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isCheering = false;
}
});
}
});
}
};
self.celebrateGoal = function () {
self.isCheering = true;
tween(self, {
scaleX: 1.3,
scaleY: 1.3,
y: self.y - 30
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0,
y: self.y + 30
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isCheering = false;
}
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game dimensions and positions for side view (90 degrees rotated)
var screenWidth = 2048;
var screenHeight = 2732;
var fieldX = 0; // Position field from left edge for full visibility
var goalWidth = 80; // Thinner goal for side view
var goalHeight = 1000; // Taller goal for side view
var goalX = screenWidth - 200; // Goal positioned relative to centered field
var goalY = (screenHeight - goalHeight) / 2; // Center goal vertically
var ballStartX = 300; // Ball starts positioned for centered field
var ballStartY = screenHeight / 2;
// Game state
var isAiming = false;
var aimStartX = 0;
var aimStartY = 0;
var gameState = 'waiting'; // 'waiting', 'ready', 'aiming', 'shooting', 'reset'
var gameStarted = false;
// Create field
var field = game.addChild(LK.getAsset('field', {
anchorX: 0.5,
anchorY: 0.5,
x: screenWidth / 2,
y: screenHeight / 2,
width: screenWidth,
// Full screen width
height: screenHeight,
// Full screen height
rotation: Math.PI / 2 // Rotate 90 degrees
}));
// Create goal
var goal = game.addChild(LK.getAsset('goal', {
anchorX: 0,
anchorY: 0,
x: goalX,
y: goalY,
width: goalWidth,
height: goalHeight
}));
// Create goal posts (visual) for side view
var topPost = game.addChild(LK.getAsset('aimLine', {
anchorX: 0,
anchorY: 0.5,
x: goalX,
y: goalY,
width: goalWidth,
height: 12,
color: 0xffffff
}));
var bottomPost = game.addChild(LK.getAsset('aimLine', {
anchorX: 0,
anchorY: 0.5,
x: goalX,
y: goalY + goalHeight,
width: goalWidth,
height: 12,
color: 0xffffff
}));
var goalLine = game.addChild(LK.getAsset('aimLine', {
anchorX: 0.5,
anchorY: 0,
x: goalX,
y: goalY,
width: 12,
height: goalHeight,
color: 0xffffff
}));
// Create ball
var ball = game.addChild(new Ball());
ball.x = ballStartX;
ball.y = ballStartY;
// Create player
var player = game.addChild(new Player());
player.x = ballStartX - 80;
player.y = ballStartY + 50;
// Create goalkeeper
var goalkeeper = game.addChild(new Goalkeeper());
goalkeeper.x = goalX - 50; // Position in front of goal
goalkeeper.y = goalY + goalHeight / 2;
// Create spectators crowd
var spectators = [];
// Left side spectators (behind ball starting position)
for (var i = 0; i < 15; i++) {
var spec = new Spectator();
spec.x = 100 + Math.random() * 150;
spec.y = 200 + i * 150 + Math.random() * 50;
spectators.push(spec);
game.addChild(spec);
}
// Right side spectators (behind goal)
for (var j = 0; j < 12; j++) {
var spec2 = new Spectator();
spec2.x = screenWidth - 150 + Math.random() * 100;
spec2.y = 300 + j * 180 + Math.random() * 60;
spectators.push(spec2);
game.addChild(spec2);
}
// Top spectators
for (var k = 0; k < 8; k++) {
var spec3 = new Spectator();
spec3.x = 400 + k * 200 + Math.random() * 100;
spec3.y = 150 + Math.random() * 50;
spectators.push(spec3);
game.addChild(spec3);
}
// Bottom spectators
for (var l = 0; l < 8; l++) {
var spec4 = new Spectator();
spec4.x = 400 + l * 200 + Math.random() * 100;
spec4.y = screenHeight - 150 + Math.random() * 50;
spectators.push(spec4);
game.addChild(spec4);
}
// Create start button
var startButton = game.addChild(LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: screenWidth / 2,
y: screenHeight / 2
}));
var startButtonText = new Text2('START GAME', {
size: 50,
fill: 0xFFFFFF
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = screenWidth / 2;
startButtonText.y = screenHeight / 2;
game.addChild(startButtonText);
// Hide game elements initially
field.alpha = 0.3;
goal.alpha = 0.3;
topPost.alpha = 0.3;
bottomPost.alpha = 0.3;
goalLine.alpha = 0.3;
ball.alpha = 0.3;
goalkeeper.alpha = 0.3;
player.alpha = 0.3;
for (var s = 0; s < spectators.length; s++) {
spectators[s].alpha = 0.3;
}
// Create aim line (initially hidden)
var aimLine = game.addChild(LK.getAsset('aimLine', {
anchorX: 0,
anchorY: 0.5,
alpha: 0
}));
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create instruction text
var instructionTxt = new Text2('Click START GAME to begin!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 1);
instructionTxt.y = -50;
LK.gui.bottom.addChild(instructionTxt);
// Game event handlers
game.down = function (x, y, obj) {
if (!gameStarted && gameState === 'waiting') {
// Check if clicked on start button
var buttonBounds = {
left: screenWidth / 2 - 200,
right: screenWidth / 2 + 200,
top: screenHeight / 2 - 50,
bottom: screenHeight / 2 + 50
};
if (x >= buttonBounds.left && x <= buttonBounds.right && y >= buttonBounds.top && y <= buttonBounds.bottom) {
// Start the game
gameStarted = true;
gameState = 'ready';
// Hide start button
startButton.alpha = 0;
startButtonText.alpha = 0;
// Show game elements
field.alpha = 1;
goal.alpha = 1;
topPost.alpha = 1;
bottomPost.alpha = 1;
goalLine.alpha = 1;
ball.alpha = 1;
goalkeeper.alpha = 1;
player.alpha = 1;
for (var t = 0; t < spectators.length; t++) {
spectators[t].alpha = 1;
}
// Update instruction text
instructionTxt.setText('Drag to aim, release to shoot!');
}
} else if (gameState === 'ready') {
gameState = 'aiming';
isAiming = true;
aimStartX = x;
aimStartY = y;
aimLine.alpha = 1;
}
};
game.move = function (x, y, obj) {
if (isAiming && gameState === 'aiming') {
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
aimLine.x = ball.x;
aimLine.y = ball.y;
var targetWidth = Math.min(distance, 300);
// Smooth aim line width transition
tween(aimLine, {
width: targetWidth
}, {
duration: 50,
easing: tween.easeOut
});
aimLine.rotation = Math.atan2(dy, dx);
// Power visualization with color change
var power = Math.min(distance / 300, 1);
var red = Math.floor(255 * power);
var green = Math.floor(255 * (1 - power));
var color = red << 16 | green << 8 | 0;
tween(aimLine, {
tint: color
}, {
duration: 100,
easing: tween.linear
});
}
}
};
game.up = function (x, y, obj) {
if (isAiming && gameState === 'aiming') {
isAiming = false;
aimLine.alpha = 0;
gameState = 'shooting';
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var power = Math.min(distance / 12, 20);
ball.shoot(x, y, power);
player.performKick();
}
};
// Reset function
function resetGame() {
ball.x = ballStartX;
ball.y = ballStartY;
ball.moving = false;
ball.velocityX = 0;
ball.velocityY = 0;
gameState = 'ready';
goalkeeper.reactionTime = 0;
// After score 3, increase speed much more dramatically
if (LK.getScore() >= 3) {
goalkeeper.speed = 3.0 + (LK.getScore() - 3) * 1.0; // Much faster after score 3
} else {
goalkeeper.speed = 1.5 + LK.getScore() * 0.5; // Normal progression before score 3
}
// After score 3, reduce reaction time much more aggressively
if (LK.getScore() >= 3) {
goalkeeper.maxReactionTime = 10 - (LK.getScore() - 3) * 2; // Much faster reactions after score 3
} else {
goalkeeper.maxReactionTime = 25 - LK.getScore() * 3; // Normal progression before score 3
}
if (goalkeeper.maxReactionTime < 2) {
goalkeeper.maxReactionTime = 2; // Minimum reaction time for playability
}
}
// Game update loop
game.update = function () {
// Check for goal
if (ball.moving && ball.x > goalX && ball.y > goalY && ball.y < goalY + goalHeight && ball.lastX !== undefined && ball.lastX <= goalX) {
// Check if goalkeeper blocked it
if (!ball.intersects(goalkeeper)) {
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('goal').play();
LK.effects.flashScreen(0x00ff00, 500);
// Celebrate goal with ball bounce and goal shake
tween(ball, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(ball, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Goal shake effect
tween(goal, {
x: goalX + 10
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(goal, {
x: goalX - 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(goal, {
x: goalX
}, {
duration: 50
});
}
});
}
});
// Score text celebration
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300
});
}
});
// Make spectators celebrate goal
for (var u = 0; u < spectators.length; u++) {
LK.setTimeout(function () {
var randomSpec = spectators[Math.floor(Math.random() * spectators.length)];
if (randomSpec && randomSpec.celebrateGoal) {
randomSpec.celebrateGoal();
}
}, Math.random() * 500);
}
// Reset immediately for continuous play
resetGame();
}
}
// Check for goalkeeper block
if (ball.moving && ball.intersects(goalkeeper)) {
LK.getSound('block').play();
LK.effects.flashScreen(0xff0000, 500);
LK.showGameOver();
}
// Check if ball went off screen or stopped moving for too long
if (ball.moving && (ball.x < -100 || ball.x > screenWidth + 100 || ball.y < -100 || ball.y > screenHeight + 100)) {
LK.showGameOver();
}
// Check if ball stopped moving and didn't score
if (!ball.moving && gameState === 'shooting') {
if (!(ball.x > goalX && ball.y > goalY && ball.y < goalY + goalHeight)) {
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Track ball position for collision detection
ball.lastX = ball.x;
ball.lastY = ball.y;
}; ===================================================================
--- original.js
+++ change.js
@@ -19,13 +19,16 @@
self.update = function () {
if (self.moving) {
self.x += self.velocityX;
self.y += self.velocityY;
- // Apply gravity for side view
- self.velocityY += self.gravity;
- // Apply increased air resistance to make shots harder
- self.velocityX *= 0.995;
- self.velocityY *= 0.996;
+ // Apply gravity for side view - increase after score 3
+ var currentGravity = LK.getScore() >= 3 ? self.gravity * 1.5 : self.gravity;
+ self.velocityY += currentGravity;
+ // Apply increased air resistance to make shots harder - more resistance after score 3
+ var airResistanceX = LK.getScore() >= 3 ? 0.992 : 0.995;
+ var airResistanceY = LK.getScore() >= 3 ? 0.993 : 0.996;
+ self.velocityX *= airResistanceX;
+ self.velocityY *= airResistanceY;
// Field boundaries
if (self.x <= 50) {
self.x = 50;
self.velocityX *= -0.7;
@@ -93,17 +96,27 @@
anchorY: 1.0,
scaleX: 1.3,
scaleY: 1.3
});
- self.speed = 1.5 + LK.getScore() * 0.5;
+ // After score 3, increase speed much more dramatically
+ if (LK.getScore() >= 3) {
+ self.speed = 3.0 + (LK.getScore() - 3) * 1.0; // Much faster after score 3
+ } else {
+ self.speed = 1.5 + LK.getScore() * 0.5; // Normal progression before score 3
+ }
self.direction = 1;
self.directionX = Math.random() > 0.5 ? 1 : -1;
self.reactionTime = 0;
self.isDiving = false;
- self.maxReactionTime = 25 - LK.getScore() * 3;
- if (self.maxReactionTime < 5) {
- self.maxReactionTime = 5;
+ // After score 3, reduce reaction time much more aggressively
+ if (LK.getScore() >= 3) {
+ self.maxReactionTime = 10 - (LK.getScore() - 3) * 2; // Much faster reactions after score 3
+ } else {
+ self.maxReactionTime = 25 - LK.getScore() * 3; // Normal progression before score 3
}
+ if (self.maxReactionTime < 2) {
+ self.maxReactionTime = 2; // Minimum reaction time for playability
+ }
// Add realistic goalkeeper breathing animation
tween(keeperGraphics, {
scaleY: 1.1
}, {
@@ -622,13 +635,23 @@
ball.velocityX = 0;
ball.velocityY = 0;
gameState = 'ready';
goalkeeper.reactionTime = 0;
- goalkeeper.speed = 1.5 + LK.getScore() * 0.5;
- goalkeeper.maxReactionTime = 25 - LK.getScore() * 3;
- if (goalkeeper.maxReactionTime < 5) {
- goalkeeper.maxReactionTime = 5;
+ // After score 3, increase speed much more dramatically
+ if (LK.getScore() >= 3) {
+ goalkeeper.speed = 3.0 + (LK.getScore() - 3) * 1.0; // Much faster after score 3
+ } else {
+ goalkeeper.speed = 1.5 + LK.getScore() * 0.5; // Normal progression before score 3
}
+ // After score 3, reduce reaction time much more aggressively
+ if (LK.getScore() >= 3) {
+ goalkeeper.maxReactionTime = 10 - (LK.getScore() - 3) * 2; // Much faster reactions after score 3
+ } else {
+ goalkeeper.maxReactionTime = 25 - LK.getScore() * 3; // Normal progression before score 3
+ }
+ if (goalkeeper.maxReactionTime < 2) {
+ goalkeeper.maxReactionTime = 2; // Minimum reaction time for playability
+ }
}
// Game update loop
game.update = function () {
// Check for goal