/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { level: 1, highScores: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }); /**** * Classes ****/ var AimingSystem = Container.expand(function () { var self = Container.call(this); // Create the aim arrow var arrow = self.attachAsset('aimArrow', { anchorX: 0, anchorY: 0.5, x: 0, y: 0 }); // Create power meter background var powerMeter = self.attachAsset('powerMeter', { anchorX: 0.5, anchorY: 1, x: 0, y: 0 }); // Create power indicator var powerIndicator = self.attachAsset('powerIndicator', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -powerMeter.height + 10 }); self.visible = false; self.angle = -45; self.power = 0; self.powerIncreasing = true; self.powerSpeed = 2; self.maxPower = 100; // Position offset from power meter to arrow var offsetX = 100; self.setPosition = function (x, y) { self.x = x; self.y = y; powerMeter.x = x - offsetX; powerMeter.y = y; }; self.setAngle = function (angle) { self.angle = angle; arrow.rotation = angle * Math.PI / 180; }; self.setPower = function (power) { self.power = power; var normalizedPower = power / self.maxPower; powerIndicator.y = -powerMeter.height * normalizedPower + 10; }; self.startPowerPhase = function () { self.power = 0; self.powerIncreasing = true; self.visible = true; }; self.update = function () { if (gameState === "power" && self.visible) { if (self.powerIncreasing) { self.power += self.powerSpeed; if (self.power >= self.maxPower) { self.power = self.maxPower; self.powerIncreasing = false; } } else { self.power -= self.powerSpeed; if (self.power <= 0) { self.power = 0; self.powerIncreasing = true; } } self.setPower(self.power); } }; return self; }); var BasketHoop = Container.expand(function () { var self = Container.call(this); // Create backboard var backboard = self.attachAsset('backboard', { anchorX: 0.5, anchorY: 0, x: 0, y: 0 }); // Create rim var hoop = self.attachAsset('hoop', { anchorX: 0.5, anchorY: 0, x: 0, y: backboard.height + 20 }); // Create net self.net = self.attachAsset('net', { anchorX: 0.5, anchorY: 0, x: 0, y: backboard.height + 20 + hoop.height / 2, alpha: 0.5 }); // For hoop movement self.originalX = 0; self.originalY = 0; self.moveSpeed = 0; self.moveRange = 0; self.moveDir = 1; self.setMoving = function (speed, range) { self.moveSpeed = speed; self.moveRange = range; self.originalX = self.x; }; self.update = function () { if (self.moveSpeed > 0) { self.x += self.moveSpeed * self.moveDir; if (self.x > self.originalX + self.moveRange) { self.x = self.originalX + self.moveRange; self.moveDir = -1; } else if (self.x < self.originalX - self.moveRange) { self.x = self.originalX - self.moveRange; self.moveDir = 1; } } }; return self; }); var Basketball = Container.expand(function () { var self = Container.call(this); var ball = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); var ballShine = self.attachAsset('ballShine', { anchorX: 0.5, anchorY: 0.5, x: -20, y: -20 }); self.velocity = { x: 0, y: 0 }; self.gravity = 0.5; self.bounceDecay = 0.65; self.friction = 0.98; self.active = false; self.scored = false; self.update = function () { if (!self.active) { return; } // Apply physics self.velocity.y += self.gravity; self.x += self.velocity.x; self.y += self.velocity.y; // Apply wind if present if (currentLevel.wind) { self.velocity.x += currentLevel.wind / 50; } // Ball rotation based on horizontal movement ball.rotation += self.velocity.x / 30; // Check floor collision if (self.y > floorY - ball.height / 2) { self.y = floorY - ball.height / 2; self.velocity.y = -self.velocity.y * self.bounceDecay; self.velocity.x *= self.friction; LK.getSound('bounce').play(); // Stop ball if it's bounced enough and is slow if (Math.abs(self.velocity.y) < 2 && Math.abs(self.velocity.x) < 1) { self.active = false; shotsRemaining--; updateShotsText(); if (shotsRemaining <= 0 && !levelComplete) { LK.setTimeout(function () { if (!levelComplete) { LK.showGameOver(); } }, 1500); } else if (!levelComplete) { resetShot(); } } } // Check wall collisions if (self.x < ball.width / 2) { self.x = ball.width / 2; self.velocity.x = -self.velocity.x * self.bounceDecay; LK.getSound('bounce').play(); } else if (self.x > 2048 - ball.width / 2) { self.x = 2048 - ball.width / 2; self.velocity.x = -self.velocity.x * self.bounceDecay; LK.getSound('bounce').play(); } // Check obstacle collisions for (var i = 0; i < obstacles.length; i++) { if (self.intersects(obstacles[i])) { // Basic collision response var dx = self.x - obstacles[i].x; var dy = self.y - obstacles[i].y; var dist = Math.sqrt(dx * dx + dy * dy); var nx = dx / dist; var ny = dy / dist; // Push ball away from obstacle self.x += nx * 5; self.y += ny * 5; // Reflect velocity var dotProduct = self.velocity.x * nx + self.velocity.y * ny; self.velocity.x = (self.velocity.x - 2 * dotProduct * nx) * self.bounceDecay; self.velocity.y = (self.velocity.y - 2 * dotProduct * ny) * self.bounceDecay; LK.getSound('bounce').play(); } } // Check defenders for (var i = 0; i < defenders.length; i++) { if (self.intersects(defenders[i])) { // Simplified collision with defenders - just bounce back self.velocity.x = -self.velocity.x * self.bounceDecay; self.velocity.y = -self.velocity.y * self.bounceDecay; LK.getSound('bounce').play(); } } // Check hoop scoring if (!self.scored && self.intersects(basketHoop.net)) { // Ball position relative to hoop var ballToHoop = self.toLocal(basketHoop.net.position, basketHoop); // Only count if the ball is going down and is near the center of the hoop if (self.velocity.y > 0 && Math.abs(ballToHoop.x) < basketHoop.net.width / 4) { self.scored = true; levelScore++; LK.setScore(LK.getScore() + 100); updateScoreText(); LK.getSound('swish').play(); // Check if level is complete if (levelScore >= currentLevel.requiredScores) { levelComplete = true; // Update high score if necessary var highScores = storage.highScores; if (LK.getScore() > highScores[currentLevelIndex]) { highScores[currentLevelIndex] = LK.getScore(); storage.highScores = highScores; } // Advance to next level currentLevelIndex++; if (currentLevelIndex < levels.length) { LK.setTimeout(function () { levelTitleText.setText("LEVEL " + (currentLevelIndex + 1) + " COMPLETE!"); LK.effects.flashScreen(0x27ae60, 1000); LK.getSound('levelUp').play(); LK.setTimeout(function () { loadLevel(currentLevelIndex); }, 2000); }, 1000); } else { // Game completed LK.setTimeout(function () { levelTitleText.setText("GAME COMPLETED!"); LK.effects.flashScreen(0x27ae60, 1000); LK.getSound('levelUp').play(); LK.setTimeout(function () { LK.showYouWin(); }, 2000); }, 1000); } } else { // Continue level with next shot LK.setTimeout(function () { if (!levelComplete) { resetShot(); } }, 1500); } } } }; return self; }); var Defender = Container.expand(function () { var self = Container.call(this); // Create defender body var body = self.attachAsset('player', { anchorX: 0.5, anchorY: 1, x: 0, y: 0, tint: 0xe74c3c }); // Create defender head var head = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 1, x: 0, y: -body.height, tint: 0xe74c3c }); // For defender movement self.originalX = 0; self.moveSpeed = 0; self.moveRange = 0; self.moveDir = 1; self.setMoving = function (speed, range) { self.moveSpeed = speed; self.moveRange = range; self.originalX = self.x; }; self.update = function () { if (self.moveSpeed > 0) { self.x += self.moveSpeed * self.moveDir; if (self.x > self.originalX + self.moveRange) { self.x = self.originalX + self.moveRange; self.moveDir = -1; } else if (self.x < self.originalX - self.moveRange) { self.x = self.originalX - self.moveRange; self.moveDir = 1; } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); // Create player body var body = self.attachAsset('player', { anchorX: 0.5, anchorY: 1, x: 0, y: 0 }); // Create player head var head = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 1, x: 0, y: -body.height }); self.canShoot = true; self.down = function (x, y, obj) { if (gameState === "aiming" && self.canShoot) { startAiming(self.x, self.y - body.height / 2); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x3498db }); /**** * Game Code ****/ // Game state management var gameState = "start"; // "start", "aiming", "power", "shooting" var currentLevelIndex = storage.level - 1; var currentLevel; var levels = []; var floorY = 2600; var levelComplete = false; var levelScore = 0; var shotsRemaining = 5; // Game elements var basketball; var basketHoop; var player; var aimingSystem; var obstacles = []; var defenders = []; // UI elements var levelTitleText; var scoreText; var shotsText; var windText; var levelInfoText; // Level definitions function initLevels() { levels = [{ title: "Rookie Shot", description: "Make simple shots to learn the basics", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 3, shotsAllowed: 5, movingHoop: false, wind: 0, obstacles: [], defenders: [] }, { title: "Side Angle", description: "Shoot from the side", hoopX: 1700, hoopY: 1600, playerX: 300, playerY: floorY, requiredScores: 3, shotsAllowed: 5, movingHoop: false, wind: 0, obstacles: [], defenders: [] }, { title: "Moving Target", description: "Hit a moving basket", hoopX: 1500, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 3, shotsAllowed: 6, movingHoop: true, hoopSpeed: 3, hoopRange: 300, wind: 0, obstacles: [], defenders: [] }, { title: "Obstacle Course", description: "Navigate around obstacles", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 5, movingHoop: false, wind: 0, obstacles: [{ x: 1000, y: 2000, width: 100, height: 100 }], defenders: [] }, { title: "Defender Pressure", description: "Shoot past defenders", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 5, movingHoop: false, wind: 0, obstacles: [], defenders: [{ x: 1000, y: floorY, speed: 0, range: 0 }] }, { title: "Windy Day", description: "Account for wind when shooting", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 6, movingHoop: false, wind: 1.5, obstacles: [], defenders: [] }, { title: "Moving Defenders", description: "Time your shots carefully", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 5, movingHoop: false, wind: 0, obstacles: [], defenders: [{ x: 800, y: floorY, speed: 4, range: 200 }, { x: 1200, y: floorY, speed: 3, range: 150 }] }, { title: "Complex Challenge", description: "Wind, moving hoop, and defenders", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 6, movingHoop: true, hoopSpeed: 2, hoopRange: 200, wind: 1, obstacles: [], defenders: [{ x: 1000, y: floorY, speed: 3, range: 200 }] }, { title: "Obstacle Maze", description: "Navigate through multiple obstacles", hoopX: 1600, hoopY: 1600, playerX: 400, playerY: floorY, requiredScores: 2, shotsAllowed: 6, movingHoop: false, wind: 0.5, obstacles: [{ x: 800, y: 2000, width: 100, height: 100 }, { x: 1200, y: 1800, width: 100, height: 100 }], defenders: [] }, { title: "Championship", description: "Use all your skills for the final challenge", hoopX: 1600, hoopY: 1500, playerX: 400, playerY: floorY, requiredScores: 3, shotsAllowed: 5, movingHoop: true, hoopSpeed: 4, hoopRange: 300, wind: 1.2, obstacles: [{ x: 900, y: 2000, width: 100, height: 100 }], defenders: [{ x: 1200, y: floorY, speed: 5, range: 250 }] }]; } // Function to load a specific level function loadLevel(levelIndex) { // Clear previous level objects clearLevel(); // Set current level currentLevel = levels[levelIndex]; storage.level = levelIndex + 1; // Reset level state levelComplete = false; levelScore = 0; shotsRemaining = currentLevel.shotsAllowed; // Create floor var floor = game.addChild(LK.getAsset('floor', { anchorX: 0, anchorY: 0, x: 0, y: floorY })); // Create basketball hoop basketHoop = game.addChild(new BasketHoop()); basketHoop.x = currentLevel.hoopX; basketHoop.y = currentLevel.hoopY; if (currentLevel.movingHoop) { basketHoop.setMoving(currentLevel.hoopSpeed, currentLevel.hoopRange); } // Create player player = game.addChild(new Player()); player.x = currentLevel.playerX; player.y = currentLevel.playerY; // Create obstacles for (var i = 0; i < currentLevel.obstacles.length; i++) { var obstacleData = currentLevel.obstacles[i]; var obstacle = game.addChild(LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, x: obstacleData.x, y: obstacleData.y })); obstacles.push(obstacle); } // Create defenders for (var i = 0; i < currentLevel.defenders.length; i++) { var defenderData = currentLevel.defenders[i]; var defender = game.addChild(new Defender()); defender.x = defenderData.x; defender.y = defenderData.y; if (defenderData.speed > 0) { defender.setMoving(defenderData.speed, defenderData.range); } defenders.push(defender); } // Create basketball basketball = game.addChild(new Basketball()); resetShot(); // Create aiming system aimingSystem = game.addChild(new AimingSystem()); aimingSystem.visible = false; // Update UI levelTitleText.setText("LEVEL " + (levelIndex + 1) + ": " + currentLevel.title); updateShotsText(); updateWindText(); levelInfoText.setText(currentLevel.description); // Reset game state gameState = "start"; // Show level intro effect LK.effects.flashScreen(0x3498db, 1000); } // Function to clear current level objects function clearLevel() { if (basketball) { basketball.destroy(); basketball = null; } if (basketHoop) { basketHoop.destroy(); basketHoop = null; } if (player) { player.destroy(); player = null; } if (aimingSystem) { aimingSystem.destroy(); aimingSystem = null; } // Clear obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; // Clear defenders for (var i = 0; i < defenders.length; i++) { defenders[i].destroy(); } defenders = []; } // Function to reset shot function resetShot() { basketball.x = player.x; basketball.y = player.y - 150; basketball.velocity.x = 0; basketball.velocity.y = 0; basketball.active = false; basketball.scored = false; gameState = "start"; // Make sure aiming system is hidden if (aimingSystem) { aimingSystem.visible = false; } } // Function to start aiming function startAiming(x, y) { gameState = "aiming"; aimingSystem.setPosition(x, y); aimingSystem.visible = true; } // Function to shoot the ball function shootBall() { var angle = aimingSystem.angle; var power = aimingSystem.power / 20; // Scale power appropriately basketball.velocity.x = Math.cos(angle * Math.PI / 180) * power; basketball.velocity.y = Math.sin(angle * Math.PI / 180) * power; basketball.active = true; gameState = "shooting"; aimingSystem.visible = false; } // Setup UI function setupUI() { // Level title text levelTitleText = new Text2("LEVEL 1", { size: 80, fill: 0xFFFFFF }); levelTitleText.anchor.set(0.5, 0); LK.gui.top.addChild(levelTitleText); // Score text scoreText = new Text2("SCORE: 0", { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 150; LK.gui.topRight.addChild(scoreText); // Shots text shotsText = new Text2("SHOTS: 5", { size: 60, fill: 0xFFFFFF }); shotsText.anchor.set(0, 0); shotsText.x = 150; shotsText.y = 80; LK.gui.topRight.addChild(shotsText); // Wind text windText = new Text2("WIND: 0", { size: 60, fill: 0xFFFFFF }); windText.anchor.set(0, 0); windText.x = 150; windText.y = 160; LK.gui.topRight.addChild(windText); // Level info text levelInfoText = new Text2("Make simple shots to learn the basics", { size: 40, fill: 0xFFFFFF }); levelInfoText.anchor.set(0.5, 0); levelInfoText.y = 100; LK.gui.top.addChild(levelInfoText); } // Update UI helper functions function updateScoreText() { scoreText.setText("SCORE: " + LK.getScore()); } function updateShotsText() { shotsText.setText("SHOTS: " + shotsRemaining); } function updateWindText() { if (currentLevel && currentLevel.wind) { var direction = currentLevel.wind > 0 ? "→" : "←"; var strength = Math.abs(currentLevel.wind); var windStr = ""; for (var i = 0; i < Math.ceil(strength); i++) { windStr += direction; } windText.setText("WIND: " + windStr); } else { windText.setText("WIND: NONE"); } } // Input handling game.down = function (x, y, obj) { if (gameState === "aiming") { gameState = "power"; aimingSystem.startPowerPhase(); } else if (gameState === "power") { gameState = "shooting"; shootBall(); } else if (gameState === "start" && player && player.canShoot) { startAiming(player.x, player.y - 150); } }; game.move = function (x, y, obj) { if (gameState === "aiming" && aimingSystem && aimingSystem.visible) { // Calculate angle based on mouse position relative to player var dx = x - player.x; var dy = y - player.y; var angle = Math.atan2(dy, dx) * 180 / Math.PI; // Constrain angle for shooting upward only if (angle > 0) { angle = 0; } if (angle < -90) { angle = -90; } aimingSystem.setAngle(angle); } }; // Game update loop game.update = function () { // Update game objects if (basketball) { basketball.update(); } if (basketHoop) { basketHoop.update(); } if (aimingSystem) { aimingSystem.update(); } // Update defenders for (var i = 0; i < defenders.length; i++) { defenders[i].update(); } }; // Initialize game function initGame() { // Initialize levels initLevels(); // Setup UI setupUI(); // Reset score LK.setScore(0); updateScoreText(); // Load first level loadLevel(currentLevelIndex); // Play background music LK.playMusic('gameMusic'); } // Start the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
level: 1,
highScores: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
});
/****
* Classes
****/
var AimingSystem = Container.expand(function () {
var self = Container.call(this);
// Create the aim arrow
var arrow = self.attachAsset('aimArrow', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 0
});
// Create power meter background
var powerMeter = self.attachAsset('powerMeter', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: 0
});
// Create power indicator
var powerIndicator = self.attachAsset('powerIndicator', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -powerMeter.height + 10
});
self.visible = false;
self.angle = -45;
self.power = 0;
self.powerIncreasing = true;
self.powerSpeed = 2;
self.maxPower = 100;
// Position offset from power meter to arrow
var offsetX = 100;
self.setPosition = function (x, y) {
self.x = x;
self.y = y;
powerMeter.x = x - offsetX;
powerMeter.y = y;
};
self.setAngle = function (angle) {
self.angle = angle;
arrow.rotation = angle * Math.PI / 180;
};
self.setPower = function (power) {
self.power = power;
var normalizedPower = power / self.maxPower;
powerIndicator.y = -powerMeter.height * normalizedPower + 10;
};
self.startPowerPhase = function () {
self.power = 0;
self.powerIncreasing = true;
self.visible = true;
};
self.update = function () {
if (gameState === "power" && self.visible) {
if (self.powerIncreasing) {
self.power += self.powerSpeed;
if (self.power >= self.maxPower) {
self.power = self.maxPower;
self.powerIncreasing = false;
}
} else {
self.power -= self.powerSpeed;
if (self.power <= 0) {
self.power = 0;
self.powerIncreasing = true;
}
}
self.setPower(self.power);
}
};
return self;
});
var BasketHoop = Container.expand(function () {
var self = Container.call(this);
// Create backboard
var backboard = self.attachAsset('backboard', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 0
});
// Create rim
var hoop = self.attachAsset('hoop', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: backboard.height + 20
});
// Create net
self.net = self.attachAsset('net', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: backboard.height + 20 + hoop.height / 2,
alpha: 0.5
});
// For hoop movement
self.originalX = 0;
self.originalY = 0;
self.moveSpeed = 0;
self.moveRange = 0;
self.moveDir = 1;
self.setMoving = function (speed, range) {
self.moveSpeed = speed;
self.moveRange = range;
self.originalX = self.x;
};
self.update = function () {
if (self.moveSpeed > 0) {
self.x += self.moveSpeed * self.moveDir;
if (self.x > self.originalX + self.moveRange) {
self.x = self.originalX + self.moveRange;
self.moveDir = -1;
} else if (self.x < self.originalX - self.moveRange) {
self.x = self.originalX - self.moveRange;
self.moveDir = 1;
}
}
};
return self;
});
var Basketball = Container.expand(function () {
var self = Container.call(this);
var ball = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
var ballShine = self.attachAsset('ballShine', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
y: -20
});
self.velocity = {
x: 0,
y: 0
};
self.gravity = 0.5;
self.bounceDecay = 0.65;
self.friction = 0.98;
self.active = false;
self.scored = false;
self.update = function () {
if (!self.active) {
return;
}
// Apply physics
self.velocity.y += self.gravity;
self.x += self.velocity.x;
self.y += self.velocity.y;
// Apply wind if present
if (currentLevel.wind) {
self.velocity.x += currentLevel.wind / 50;
}
// Ball rotation based on horizontal movement
ball.rotation += self.velocity.x / 30;
// Check floor collision
if (self.y > floorY - ball.height / 2) {
self.y = floorY - ball.height / 2;
self.velocity.y = -self.velocity.y * self.bounceDecay;
self.velocity.x *= self.friction;
LK.getSound('bounce').play();
// Stop ball if it's bounced enough and is slow
if (Math.abs(self.velocity.y) < 2 && Math.abs(self.velocity.x) < 1) {
self.active = false;
shotsRemaining--;
updateShotsText();
if (shotsRemaining <= 0 && !levelComplete) {
LK.setTimeout(function () {
if (!levelComplete) {
LK.showGameOver();
}
}, 1500);
} else if (!levelComplete) {
resetShot();
}
}
}
// Check wall collisions
if (self.x < ball.width / 2) {
self.x = ball.width / 2;
self.velocity.x = -self.velocity.x * self.bounceDecay;
LK.getSound('bounce').play();
} else if (self.x > 2048 - ball.width / 2) {
self.x = 2048 - ball.width / 2;
self.velocity.x = -self.velocity.x * self.bounceDecay;
LK.getSound('bounce').play();
}
// Check obstacle collisions
for (var i = 0; i < obstacles.length; i++) {
if (self.intersects(obstacles[i])) {
// Basic collision response
var dx = self.x - obstacles[i].x;
var dy = self.y - obstacles[i].y;
var dist = Math.sqrt(dx * dx + dy * dy);
var nx = dx / dist;
var ny = dy / dist;
// Push ball away from obstacle
self.x += nx * 5;
self.y += ny * 5;
// Reflect velocity
var dotProduct = self.velocity.x * nx + self.velocity.y * ny;
self.velocity.x = (self.velocity.x - 2 * dotProduct * nx) * self.bounceDecay;
self.velocity.y = (self.velocity.y - 2 * dotProduct * ny) * self.bounceDecay;
LK.getSound('bounce').play();
}
}
// Check defenders
for (var i = 0; i < defenders.length; i++) {
if (self.intersects(defenders[i])) {
// Simplified collision with defenders - just bounce back
self.velocity.x = -self.velocity.x * self.bounceDecay;
self.velocity.y = -self.velocity.y * self.bounceDecay;
LK.getSound('bounce').play();
}
}
// Check hoop scoring
if (!self.scored && self.intersects(basketHoop.net)) {
// Ball position relative to hoop
var ballToHoop = self.toLocal(basketHoop.net.position, basketHoop);
// Only count if the ball is going down and is near the center of the hoop
if (self.velocity.y > 0 && Math.abs(ballToHoop.x) < basketHoop.net.width / 4) {
self.scored = true;
levelScore++;
LK.setScore(LK.getScore() + 100);
updateScoreText();
LK.getSound('swish').play();
// Check if level is complete
if (levelScore >= currentLevel.requiredScores) {
levelComplete = true;
// Update high score if necessary
var highScores = storage.highScores;
if (LK.getScore() > highScores[currentLevelIndex]) {
highScores[currentLevelIndex] = LK.getScore();
storage.highScores = highScores;
}
// Advance to next level
currentLevelIndex++;
if (currentLevelIndex < levels.length) {
LK.setTimeout(function () {
levelTitleText.setText("LEVEL " + (currentLevelIndex + 1) + " COMPLETE!");
LK.effects.flashScreen(0x27ae60, 1000);
LK.getSound('levelUp').play();
LK.setTimeout(function () {
loadLevel(currentLevelIndex);
}, 2000);
}, 1000);
} else {
// Game completed
LK.setTimeout(function () {
levelTitleText.setText("GAME COMPLETED!");
LK.effects.flashScreen(0x27ae60, 1000);
LK.getSound('levelUp').play();
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
}, 1000);
}
} else {
// Continue level with next shot
LK.setTimeout(function () {
if (!levelComplete) {
resetShot();
}
}, 1500);
}
}
}
};
return self;
});
var Defender = Container.expand(function () {
var self = Container.call(this);
// Create defender body
var body = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: 0,
tint: 0xe74c3c
});
// Create defender head
var head = self.attachAsset('playerHead', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -body.height,
tint: 0xe74c3c
});
// For defender movement
self.originalX = 0;
self.moveSpeed = 0;
self.moveRange = 0;
self.moveDir = 1;
self.setMoving = function (speed, range) {
self.moveSpeed = speed;
self.moveRange = range;
self.originalX = self.x;
};
self.update = function () {
if (self.moveSpeed > 0) {
self.x += self.moveSpeed * self.moveDir;
if (self.x > self.originalX + self.moveRange) {
self.x = self.originalX + self.moveRange;
self.moveDir = -1;
} else if (self.x < self.originalX - self.moveRange) {
self.x = self.originalX - self.moveRange;
self.moveDir = 1;
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Create player body
var body = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: 0
});
// Create player head
var head = self.attachAsset('playerHead', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -body.height
});
self.canShoot = true;
self.down = function (x, y, obj) {
if (gameState === "aiming" && self.canShoot) {
startAiming(self.x, self.y - body.height / 2);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x3498db
});
/****
* Game Code
****/
// Game state management
var gameState = "start"; // "start", "aiming", "power", "shooting"
var currentLevelIndex = storage.level - 1;
var currentLevel;
var levels = [];
var floorY = 2600;
var levelComplete = false;
var levelScore = 0;
var shotsRemaining = 5;
// Game elements
var basketball;
var basketHoop;
var player;
var aimingSystem;
var obstacles = [];
var defenders = [];
// UI elements
var levelTitleText;
var scoreText;
var shotsText;
var windText;
var levelInfoText;
// Level definitions
function initLevels() {
levels = [{
title: "Rookie Shot",
description: "Make simple shots to learn the basics",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 3,
shotsAllowed: 5,
movingHoop: false,
wind: 0,
obstacles: [],
defenders: []
}, {
title: "Side Angle",
description: "Shoot from the side",
hoopX: 1700,
hoopY: 1600,
playerX: 300,
playerY: floorY,
requiredScores: 3,
shotsAllowed: 5,
movingHoop: false,
wind: 0,
obstacles: [],
defenders: []
}, {
title: "Moving Target",
description: "Hit a moving basket",
hoopX: 1500,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 3,
shotsAllowed: 6,
movingHoop: true,
hoopSpeed: 3,
hoopRange: 300,
wind: 0,
obstacles: [],
defenders: []
}, {
title: "Obstacle Course",
description: "Navigate around obstacles",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 5,
movingHoop: false,
wind: 0,
obstacles: [{
x: 1000,
y: 2000,
width: 100,
height: 100
}],
defenders: []
}, {
title: "Defender Pressure",
description: "Shoot past defenders",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 5,
movingHoop: false,
wind: 0,
obstacles: [],
defenders: [{
x: 1000,
y: floorY,
speed: 0,
range: 0
}]
}, {
title: "Windy Day",
description: "Account for wind when shooting",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 6,
movingHoop: false,
wind: 1.5,
obstacles: [],
defenders: []
}, {
title: "Moving Defenders",
description: "Time your shots carefully",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 5,
movingHoop: false,
wind: 0,
obstacles: [],
defenders: [{
x: 800,
y: floorY,
speed: 4,
range: 200
}, {
x: 1200,
y: floorY,
speed: 3,
range: 150
}]
}, {
title: "Complex Challenge",
description: "Wind, moving hoop, and defenders",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 6,
movingHoop: true,
hoopSpeed: 2,
hoopRange: 200,
wind: 1,
obstacles: [],
defenders: [{
x: 1000,
y: floorY,
speed: 3,
range: 200
}]
}, {
title: "Obstacle Maze",
description: "Navigate through multiple obstacles",
hoopX: 1600,
hoopY: 1600,
playerX: 400,
playerY: floorY,
requiredScores: 2,
shotsAllowed: 6,
movingHoop: false,
wind: 0.5,
obstacles: [{
x: 800,
y: 2000,
width: 100,
height: 100
}, {
x: 1200,
y: 1800,
width: 100,
height: 100
}],
defenders: []
}, {
title: "Championship",
description: "Use all your skills for the final challenge",
hoopX: 1600,
hoopY: 1500,
playerX: 400,
playerY: floorY,
requiredScores: 3,
shotsAllowed: 5,
movingHoop: true,
hoopSpeed: 4,
hoopRange: 300,
wind: 1.2,
obstacles: [{
x: 900,
y: 2000,
width: 100,
height: 100
}],
defenders: [{
x: 1200,
y: floorY,
speed: 5,
range: 250
}]
}];
}
// Function to load a specific level
function loadLevel(levelIndex) {
// Clear previous level objects
clearLevel();
// Set current level
currentLevel = levels[levelIndex];
storage.level = levelIndex + 1;
// Reset level state
levelComplete = false;
levelScore = 0;
shotsRemaining = currentLevel.shotsAllowed;
// Create floor
var floor = game.addChild(LK.getAsset('floor', {
anchorX: 0,
anchorY: 0,
x: 0,
y: floorY
}));
// Create basketball hoop
basketHoop = game.addChild(new BasketHoop());
basketHoop.x = currentLevel.hoopX;
basketHoop.y = currentLevel.hoopY;
if (currentLevel.movingHoop) {
basketHoop.setMoving(currentLevel.hoopSpeed, currentLevel.hoopRange);
}
// Create player
player = game.addChild(new Player());
player.x = currentLevel.playerX;
player.y = currentLevel.playerY;
// Create obstacles
for (var i = 0; i < currentLevel.obstacles.length; i++) {
var obstacleData = currentLevel.obstacles[i];
var obstacle = game.addChild(LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
x: obstacleData.x,
y: obstacleData.y
}));
obstacles.push(obstacle);
}
// Create defenders
for (var i = 0; i < currentLevel.defenders.length; i++) {
var defenderData = currentLevel.defenders[i];
var defender = game.addChild(new Defender());
defender.x = defenderData.x;
defender.y = defenderData.y;
if (defenderData.speed > 0) {
defender.setMoving(defenderData.speed, defenderData.range);
}
defenders.push(defender);
}
// Create basketball
basketball = game.addChild(new Basketball());
resetShot();
// Create aiming system
aimingSystem = game.addChild(new AimingSystem());
aimingSystem.visible = false;
// Update UI
levelTitleText.setText("LEVEL " + (levelIndex + 1) + ": " + currentLevel.title);
updateShotsText();
updateWindText();
levelInfoText.setText(currentLevel.description);
// Reset game state
gameState = "start";
// Show level intro effect
LK.effects.flashScreen(0x3498db, 1000);
}
// Function to clear current level objects
function clearLevel() {
if (basketball) {
basketball.destroy();
basketball = null;
}
if (basketHoop) {
basketHoop.destroy();
basketHoop = null;
}
if (player) {
player.destroy();
player = null;
}
if (aimingSystem) {
aimingSystem.destroy();
aimingSystem = null;
}
// Clear obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
// Clear defenders
for (var i = 0; i < defenders.length; i++) {
defenders[i].destroy();
}
defenders = [];
}
// Function to reset shot
function resetShot() {
basketball.x = player.x;
basketball.y = player.y - 150;
basketball.velocity.x = 0;
basketball.velocity.y = 0;
basketball.active = false;
basketball.scored = false;
gameState = "start";
// Make sure aiming system is hidden
if (aimingSystem) {
aimingSystem.visible = false;
}
}
// Function to start aiming
function startAiming(x, y) {
gameState = "aiming";
aimingSystem.setPosition(x, y);
aimingSystem.visible = true;
}
// Function to shoot the ball
function shootBall() {
var angle = aimingSystem.angle;
var power = aimingSystem.power / 20; // Scale power appropriately
basketball.velocity.x = Math.cos(angle * Math.PI / 180) * power;
basketball.velocity.y = Math.sin(angle * Math.PI / 180) * power;
basketball.active = true;
gameState = "shooting";
aimingSystem.visible = false;
}
// Setup UI
function setupUI() {
// Level title text
levelTitleText = new Text2("LEVEL 1", {
size: 80,
fill: 0xFFFFFF
});
levelTitleText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTitleText);
// Score text
scoreText = new Text2("SCORE: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
LK.gui.topRight.addChild(scoreText);
// Shots text
shotsText = new Text2("SHOTS: 5", {
size: 60,
fill: 0xFFFFFF
});
shotsText.anchor.set(0, 0);
shotsText.x = 150;
shotsText.y = 80;
LK.gui.topRight.addChild(shotsText);
// Wind text
windText = new Text2("WIND: 0", {
size: 60,
fill: 0xFFFFFF
});
windText.anchor.set(0, 0);
windText.x = 150;
windText.y = 160;
LK.gui.topRight.addChild(windText);
// Level info text
levelInfoText = new Text2("Make simple shots to learn the basics", {
size: 40,
fill: 0xFFFFFF
});
levelInfoText.anchor.set(0.5, 0);
levelInfoText.y = 100;
LK.gui.top.addChild(levelInfoText);
}
// Update UI helper functions
function updateScoreText() {
scoreText.setText("SCORE: " + LK.getScore());
}
function updateShotsText() {
shotsText.setText("SHOTS: " + shotsRemaining);
}
function updateWindText() {
if (currentLevel && currentLevel.wind) {
var direction = currentLevel.wind > 0 ? "→" : "←";
var strength = Math.abs(currentLevel.wind);
var windStr = "";
for (var i = 0; i < Math.ceil(strength); i++) {
windStr += direction;
}
windText.setText("WIND: " + windStr);
} else {
windText.setText("WIND: NONE");
}
}
// Input handling
game.down = function (x, y, obj) {
if (gameState === "aiming") {
gameState = "power";
aimingSystem.startPowerPhase();
} else if (gameState === "power") {
gameState = "shooting";
shootBall();
} else if (gameState === "start" && player && player.canShoot) {
startAiming(player.x, player.y - 150);
}
};
game.move = function (x, y, obj) {
if (gameState === "aiming" && aimingSystem && aimingSystem.visible) {
// Calculate angle based on mouse position relative to player
var dx = x - player.x;
var dy = y - player.y;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
// Constrain angle for shooting upward only
if (angle > 0) {
angle = 0;
}
if (angle < -90) {
angle = -90;
}
aimingSystem.setAngle(angle);
}
};
// Game update loop
game.update = function () {
// Update game objects
if (basketball) {
basketball.update();
}
if (basketHoop) {
basketHoop.update();
}
if (aimingSystem) {
aimingSystem.update();
}
// Update defenders
for (var i = 0; i < defenders.length; i++) {
defenders[i].update();
}
};
// Initialize game
function initGame() {
// Initialize levels
initLevels();
// Setup UI
setupUI();
// Reset score
LK.setScore(0);
updateScoreText();
// Load first level
loadLevel(currentLevelIndex);
// Play background music
LK.playMusic('gameMusic');
}
// Start the game
initGame();