/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Basketball = Container.expand(function () {
	var self = Container.call(this);
	// Visual components
	var ball = self.attachAsset('basketball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var lines = self.attachAsset('basketballLines', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.3
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.gravity = 0.5;
	self.bounce = 0.7;
	self.isMoving = false;
	self.hasScored = false;
	self.hasThroughNet = false;
	// Initialize last positions for collision detection
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		if (self.isMoving) {
			// Store last position
			self.lastX = self.x;
			self.lastY = self.y;
			// Apply physics
			self.velocityY += self.gravity;
			self.x += self.velocityX;
			self.y += self.velocityY;
			// Rotate ball based on movement
			ball.rotation += self.velocityX * 0.02;
			// Check boundaries
			if (self.x < 40 || self.x > 2008) {
				self.velocityX *= -self.bounce;
				self.x = self.x < 40 ? 40 : 2008;
			}
			if (self.y < 40) {
				self.y = 40;
				self.velocityY *= -self.bounce;
			}
			if (self.y > 2692) {
				self.y = 2692;
				self.velocityY *= -self.bounce;
				self.velocityX *= 0.9; // Friction
				if (Math.abs(self.velocityY) < 2) {
					self.isMoving = false;
					self.velocityX = 0;
					self.velocityY = 0;
				}
			}
		}
	};
	self.shoot = function (powerX, powerY) {
		self.velocityX = powerX;
		self.velocityY = powerY;
		self.isMoving = true;
		self.hasScored = false;
		self.hasThroughNet = false;
		LK.getSound('shoot').play();
	};
	self.reset = function () {
		self.x = 1024;
		self.y = 2400;
		self.velocityX = 0;
		self.velocityY = 0;
		self.isMoving = false;
		self.hasScored = false;
		self.hasThroughNet = false;
		ball.rotation = 0;
	};
	return self;
});
var Coin = Container.expand(function () {
	var self = Container.call(this);
	// Visual component
	var coinGraphics = self.attachAsset('coin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Properties
	self.hasBeenHit = false;
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		// Store last position for collision detection
		self.lastX = self.x;
		self.lastY = self.y;
	};
	self.startFloating = function () {
		// Create continuous sine wave floating animation
		var floatUp = function floatUp() {
			tween(self, {
				y: self.y - 20
			}, {
				duration: 2000,
				easing: tween.easeInOut,
				onFinish: floatDown
			});
		};
		var floatDown = function floatDown() {
			tween(self, {
				y: self.y + 20
			}, {
				duration: 2000,
				easing: tween.easeInOut,
				onFinish: floatUp
			});
		};
		floatUp();
	};
	self.checkCollision = function (ball) {
		// Check if ball intersects with coin
		if (ball.intersects(self) && !self.hasBeenHit) {
			self.hasBeenHit = true;
			// Play coin collect sound
			LK.getSound('coinCollect').play();
			// Animate coin collection
			tween(self, {
				scaleX: 0,
				scaleY: 0,
				alpha: 0
			}, {
				duration: 300,
				easing: tween.easeOut
			});
			return true;
		}
		return false;
	};
	self.moveToNewPosition = function () {
		// Move to new random position
		var newX = 200 + Math.random() * 1648; // Random X between 200 and 1848
		var newY = 400 + Math.random() * 1200; // Random Y between 400 and 1600
		self.x = newX;
		self.y = newY;
		self.hasBeenHit = false;
		self.scaleX = 1;
		self.scaleY = 1;
		self.alpha = 1;
		// Start floating animation
		self.startFloating();
	};
	return self;
});
var Hoop = Container.expand(function () {
	var self = Container.call(this);
	// Backboard
	var backboard = self.attachAsset('backboard', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 100,
		y: 0
	});
	// Hoop rim
	var rim = self.attachAsset('hoop', {
		anchorX: 0.5,
		anchorY: 0.5,
		y: 50
	});
	// Net
	var net = self.attachAsset('net', {
		anchorX: 0.5,
		anchorY: 0,
		y: 70,
		alpha: 0.6
	});
	// Scoring zone (invisible)
	self.scoringZone = {
		x: -90,
		y: 45,
		width: 180,
		height: 30
	};
	self.checkScore = function (ball) {
		// Define scoring zone boundaries
		var zoneLeft = self.x + self.scoringZone.x;
		var zoneRight = self.x + self.scoringZone.x + self.scoringZone.width;
		var zoneTop = self.y + self.scoringZone.y;
		var zoneBottom = self.y + self.scoringZone.y + self.scoringZone.height;
		// Check if ball is currently in zone
		var ballInZone = ball.x >= zoneLeft && ball.x <= zoneRight && ball.y >= zoneTop && ball.y <= zoneBottom;
		// Check if ball's trajectory crossed through the scoring zone from above
		var crossedFromAbove = false;
		if (ball.lastY < zoneTop && ball.y >= zoneTop && ball.velocityY > 0) {
			// Calculate where the ball was when it crossed the top of the zone
			var timeToZone = (zoneTop - ball.lastY) / (ball.y - ball.lastY);
			var crossX = ball.lastX + (ball.x - ball.lastX) * timeToZone;
			// Check if the crossing point is within the horizontal bounds
			if (crossX >= zoneLeft && crossX <= zoneRight) {
				crossedFromAbove = true;
			}
		}
		// Score if ball crossed from above or is in zone moving downward
		if ((ballInZone || crossedFromAbove) && ball.velocityY > 0 && !ball.hasScored) {
			ball.hasThroughNet = true;
			ball.hasScored = true;
			// Make ball bounce out of the net
			ball.velocityY = -Math.abs(ball.velocityY) * 0.3; // Reverse and reduce Y velocity
			ball.velocityX *= 0.7; // Reduce X velocity slightly
			// Animate net
			tween(net, {
				scaleY: 1.2
			}, {
				duration: 200,
				onFinish: function onFinish() {
					tween(net, {
						scaleY: 1
					}, {
						duration: 200
					});
				}
			});
			LK.getSound('score').play();
			return true;
		}
		return false;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
// Game variables
var game = new LK.Game({
	backgroundColor: 0x87CEEB // Sky blue background
});
/**** 
* Game Code
****/ 
//Minimalistic tween library for animations
// Sounds
// Trajectory line
// Hoop assets
// Basketball assets
// Game variables
var basketball = null;
var hoop = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var aimArrow = null;
var score = 0;
var scoreTxt = null;
var hasJustScored = false;
var coins = [];
var numCoins = 3;
var shots = 10;
var shotsTxt = null;
// Add single background
var background = game.addChild(LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
}));
// Initialize game elements
basketball = game.addChild(new Basketball());
basketball.reset();
hoop = game.addChild(new Hoop());
hoop.x = 1024;
hoop.y = 800;
// Score display
scoreTxt = new Text2('Score: 0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Shots counter display
shotsTxt = new Text2('Shots: 10', {
	size: 80,
	fill: 0xFFFFFF
});
shotsTxt.anchor.set(0.5, 0);
shotsTxt.x = 0;
shotsTxt.y = 100;
LK.gui.top.addChild(shotsTxt);
// Aim arrow
aimArrow = game.addChild(LK.getAsset('aimArrow', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
}));
// Initialize coins
for (var i = 0; i < numCoins; i++) {
	var coin = game.addChild(new Coin());
	coin.moveToNewPosition();
	coins.push(coin);
}
function updateAimLine(startX, startY, endX, endY) {
	var deltaX = endX - startX;
	var deltaY = endY - startY;
	var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
	// Position arrow at finger position (slightly below finger for visibility)
	aimArrow.x = endX;
	aimArrow.y = endY + 60;
	// Rotate arrow to point in shooting direction (opposite of drag direction)
	aimArrow.rotation = Math.atan2(deltaY, deltaX);
	// Show arrow when dragging
	aimArrow.alpha = isDragging ? 0.8 : 0;
}
function hideAimLine() {
	aimArrow.alpha = 0;
}
// Game input handling
game.down = function (x, y, obj) {
	if (!basketball.isMoving) {
		// Check if touch is near basketball
		var dx = x - basketball.x;
		var dy = y - basketball.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 100) {
			isDragging = true;
			dragStartX = x;
			dragStartY = y;
		}
	}
};
game.move = function (x, y, obj) {
	if (isDragging) {
		updateAimLine(basketball.x, basketball.y, x, y);
	}
};
game.up = function (x, y, obj) {
	if (isDragging) {
		isDragging = false;
		hideAimLine();
		// Calculate shooting power based on drag distance
		var deltaX = x - dragStartX;
		var deltaY = y - dragStartY;
		var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
		var powerMultiplier = Math.min(distance / 100, 1) * 28.8;
		var powerX = deltaX * powerMultiplier;
		var powerY = deltaY * powerMultiplier;
		// Limit power
		var maxPower = 90;
		var power = Math.sqrt(powerX * powerX + powerY * powerY);
		if (power > maxPower) {
			powerX = powerX / power * maxPower;
			powerY = powerY / power * maxPower;
		}
		basketball.shoot(powerX, powerY);
		// Decrease shots counter
		shots--;
		shotsTxt.setText('Shots: ' + shots);
	}
};
// Main game loop
game.update = function () {
	// Check for scoring
	if (basketball.isMoving && hoop.checkScore(basketball)) {
		score += 5;
		scoreTxt.setText('Score: ' + score);
		LK.setScore(score);
		hasJustScored = true;
	}
	// Check coin collisions
	for (var i = 0; i < coins.length; i++) {
		if (coins[i].checkCollision(basketball)) {
			score += 3;
			scoreTxt.setText('Score: ' + score);
			LK.setScore(score);
		}
	}
	// Reset ball if it goes off screen or stops moving
	if (!basketball.isMoving && (basketball.y > 2500 || basketball.x < -100 || basketball.x > 2148)) {
		LK.setTimeout(function () {
			basketball.reset();
			// Teleport hoop, net, and backboard to a new random position when ball resets after scoring
			if (hasJustScored) {
				var newX = 300 + Math.random() * 1448; // Random X between 300 and 1748
				var newY = 600 + Math.random() * 400; // Random Y between 600 and 1000
				hoop.x = newX;
				hoop.y = newY;
				// Move all coins to new positions
				for (var i = 0; i < coins.length; i++) {
					coins[i].moveToNewPosition();
				}
				hasJustScored = false; // Reset the flag
			}
			// Check for game over after ball reset
			if (shots <= 0) {
				LK.showGameOver();
			}
		}, 1000);
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Basketball = Container.expand(function () {
	var self = Container.call(this);
	// Visual components
	var ball = self.attachAsset('basketball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var lines = self.attachAsset('basketballLines', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.3
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.gravity = 0.5;
	self.bounce = 0.7;
	self.isMoving = false;
	self.hasScored = false;
	self.hasThroughNet = false;
	// Initialize last positions for collision detection
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		if (self.isMoving) {
			// Store last position
			self.lastX = self.x;
			self.lastY = self.y;
			// Apply physics
			self.velocityY += self.gravity;
			self.x += self.velocityX;
			self.y += self.velocityY;
			// Rotate ball based on movement
			ball.rotation += self.velocityX * 0.02;
			// Check boundaries
			if (self.x < 40 || self.x > 2008) {
				self.velocityX *= -self.bounce;
				self.x = self.x < 40 ? 40 : 2008;
			}
			if (self.y < 40) {
				self.y = 40;
				self.velocityY *= -self.bounce;
			}
			if (self.y > 2692) {
				self.y = 2692;
				self.velocityY *= -self.bounce;
				self.velocityX *= 0.9; // Friction
				if (Math.abs(self.velocityY) < 2) {
					self.isMoving = false;
					self.velocityX = 0;
					self.velocityY = 0;
				}
			}
		}
	};
	self.shoot = function (powerX, powerY) {
		self.velocityX = powerX;
		self.velocityY = powerY;
		self.isMoving = true;
		self.hasScored = false;
		self.hasThroughNet = false;
		LK.getSound('shoot').play();
	};
	self.reset = function () {
		self.x = 1024;
		self.y = 2400;
		self.velocityX = 0;
		self.velocityY = 0;
		self.isMoving = false;
		self.hasScored = false;
		self.hasThroughNet = false;
		ball.rotation = 0;
	};
	return self;
});
var Coin = Container.expand(function () {
	var self = Container.call(this);
	// Visual component
	var coinGraphics = self.attachAsset('coin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Properties
	self.hasBeenHit = false;
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		// Store last position for collision detection
		self.lastX = self.x;
		self.lastY = self.y;
	};
	self.startFloating = function () {
		// Create continuous sine wave floating animation
		var floatUp = function floatUp() {
			tween(self, {
				y: self.y - 20
			}, {
				duration: 2000,
				easing: tween.easeInOut,
				onFinish: floatDown
			});
		};
		var floatDown = function floatDown() {
			tween(self, {
				y: self.y + 20
			}, {
				duration: 2000,
				easing: tween.easeInOut,
				onFinish: floatUp
			});
		};
		floatUp();
	};
	self.checkCollision = function (ball) {
		// Check if ball intersects with coin
		if (ball.intersects(self) && !self.hasBeenHit) {
			self.hasBeenHit = true;
			// Play coin collect sound
			LK.getSound('coinCollect').play();
			// Animate coin collection
			tween(self, {
				scaleX: 0,
				scaleY: 0,
				alpha: 0
			}, {
				duration: 300,
				easing: tween.easeOut
			});
			return true;
		}
		return false;
	};
	self.moveToNewPosition = function () {
		// Move to new random position
		var newX = 200 + Math.random() * 1648; // Random X between 200 and 1848
		var newY = 400 + Math.random() * 1200; // Random Y between 400 and 1600
		self.x = newX;
		self.y = newY;
		self.hasBeenHit = false;
		self.scaleX = 1;
		self.scaleY = 1;
		self.alpha = 1;
		// Start floating animation
		self.startFloating();
	};
	return self;
});
var Hoop = Container.expand(function () {
	var self = Container.call(this);
	// Backboard
	var backboard = self.attachAsset('backboard', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 100,
		y: 0
	});
	// Hoop rim
	var rim = self.attachAsset('hoop', {
		anchorX: 0.5,
		anchorY: 0.5,
		y: 50
	});
	// Net
	var net = self.attachAsset('net', {
		anchorX: 0.5,
		anchorY: 0,
		y: 70,
		alpha: 0.6
	});
	// Scoring zone (invisible)
	self.scoringZone = {
		x: -90,
		y: 45,
		width: 180,
		height: 30
	};
	self.checkScore = function (ball) {
		// Define scoring zone boundaries
		var zoneLeft = self.x + self.scoringZone.x;
		var zoneRight = self.x + self.scoringZone.x + self.scoringZone.width;
		var zoneTop = self.y + self.scoringZone.y;
		var zoneBottom = self.y + self.scoringZone.y + self.scoringZone.height;
		// Check if ball is currently in zone
		var ballInZone = ball.x >= zoneLeft && ball.x <= zoneRight && ball.y >= zoneTop && ball.y <= zoneBottom;
		// Check if ball's trajectory crossed through the scoring zone from above
		var crossedFromAbove = false;
		if (ball.lastY < zoneTop && ball.y >= zoneTop && ball.velocityY > 0) {
			// Calculate where the ball was when it crossed the top of the zone
			var timeToZone = (zoneTop - ball.lastY) / (ball.y - ball.lastY);
			var crossX = ball.lastX + (ball.x - ball.lastX) * timeToZone;
			// Check if the crossing point is within the horizontal bounds
			if (crossX >= zoneLeft && crossX <= zoneRight) {
				crossedFromAbove = true;
			}
		}
		// Score if ball crossed from above or is in zone moving downward
		if ((ballInZone || crossedFromAbove) && ball.velocityY > 0 && !ball.hasScored) {
			ball.hasThroughNet = true;
			ball.hasScored = true;
			// Make ball bounce out of the net
			ball.velocityY = -Math.abs(ball.velocityY) * 0.3; // Reverse and reduce Y velocity
			ball.velocityX *= 0.7; // Reduce X velocity slightly
			// Animate net
			tween(net, {
				scaleY: 1.2
			}, {
				duration: 200,
				onFinish: function onFinish() {
					tween(net, {
						scaleY: 1
					}, {
						duration: 200
					});
				}
			});
			LK.getSound('score').play();
			return true;
		}
		return false;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
// Game variables
var game = new LK.Game({
	backgroundColor: 0x87CEEB // Sky blue background
});
/**** 
* Game Code
****/ 
//Minimalistic tween library for animations
// Sounds
// Trajectory line
// Hoop assets
// Basketball assets
// Game variables
var basketball = null;
var hoop = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var aimArrow = null;
var score = 0;
var scoreTxt = null;
var hasJustScored = false;
var coins = [];
var numCoins = 3;
var shots = 10;
var shotsTxt = null;
// Add single background
var background = game.addChild(LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
}));
// Initialize game elements
basketball = game.addChild(new Basketball());
basketball.reset();
hoop = game.addChild(new Hoop());
hoop.x = 1024;
hoop.y = 800;
// Score display
scoreTxt = new Text2('Score: 0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Shots counter display
shotsTxt = new Text2('Shots: 10', {
	size: 80,
	fill: 0xFFFFFF
});
shotsTxt.anchor.set(0.5, 0);
shotsTxt.x = 0;
shotsTxt.y = 100;
LK.gui.top.addChild(shotsTxt);
// Aim arrow
aimArrow = game.addChild(LK.getAsset('aimArrow', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0
}));
// Initialize coins
for (var i = 0; i < numCoins; i++) {
	var coin = game.addChild(new Coin());
	coin.moveToNewPosition();
	coins.push(coin);
}
function updateAimLine(startX, startY, endX, endY) {
	var deltaX = endX - startX;
	var deltaY = endY - startY;
	var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
	// Position arrow at finger position (slightly below finger for visibility)
	aimArrow.x = endX;
	aimArrow.y = endY + 60;
	// Rotate arrow to point in shooting direction (opposite of drag direction)
	aimArrow.rotation = Math.atan2(deltaY, deltaX);
	// Show arrow when dragging
	aimArrow.alpha = isDragging ? 0.8 : 0;
}
function hideAimLine() {
	aimArrow.alpha = 0;
}
// Game input handling
game.down = function (x, y, obj) {
	if (!basketball.isMoving) {
		// Check if touch is near basketball
		var dx = x - basketball.x;
		var dy = y - basketball.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 100) {
			isDragging = true;
			dragStartX = x;
			dragStartY = y;
		}
	}
};
game.move = function (x, y, obj) {
	if (isDragging) {
		updateAimLine(basketball.x, basketball.y, x, y);
	}
};
game.up = function (x, y, obj) {
	if (isDragging) {
		isDragging = false;
		hideAimLine();
		// Calculate shooting power based on drag distance
		var deltaX = x - dragStartX;
		var deltaY = y - dragStartY;
		var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
		var powerMultiplier = Math.min(distance / 100, 1) * 28.8;
		var powerX = deltaX * powerMultiplier;
		var powerY = deltaY * powerMultiplier;
		// Limit power
		var maxPower = 90;
		var power = Math.sqrt(powerX * powerX + powerY * powerY);
		if (power > maxPower) {
			powerX = powerX / power * maxPower;
			powerY = powerY / power * maxPower;
		}
		basketball.shoot(powerX, powerY);
		// Decrease shots counter
		shots--;
		shotsTxt.setText('Shots: ' + shots);
	}
};
// Main game loop
game.update = function () {
	// Check for scoring
	if (basketball.isMoving && hoop.checkScore(basketball)) {
		score += 5;
		scoreTxt.setText('Score: ' + score);
		LK.setScore(score);
		hasJustScored = true;
	}
	// Check coin collisions
	for (var i = 0; i < coins.length; i++) {
		if (coins[i].checkCollision(basketball)) {
			score += 3;
			scoreTxt.setText('Score: ' + score);
			LK.setScore(score);
		}
	}
	// Reset ball if it goes off screen or stops moving
	if (!basketball.isMoving && (basketball.y > 2500 || basketball.x < -100 || basketball.x > 2148)) {
		LK.setTimeout(function () {
			basketball.reset();
			// Teleport hoop, net, and backboard to a new random position when ball resets after scoring
			if (hasJustScored) {
				var newX = 300 + Math.random() * 1448; // Random X between 300 and 1748
				var newY = 600 + Math.random() * 400; // Random Y between 600 and 1000
				hoop.x = newX;
				hoop.y = newY;
				// Move all coins to new positions
				for (var i = 0; i < coins.length; i++) {
					coins[i].moveToNewPosition();
				}
				hasJustScored = false; // Reset the flag
			}
			// Check for game over after ball reset
			if (shots <= 0) {
				LK.showGameOver();
			}
		}, 1000);
	}
};
 Basketball 2d 2d facing the front of the camera In-Game asset. 2d. High contrast.
 Silver coin. In-Game asset. 2d. High contrast. No shadows
 Basketball net. Just the net not the hoop side view 2d 2d side view just the not the hoop or backboard In-Game asset. 2d. High contrast. No shadows
 Black arrow pointing up. In-Game asset. 2d. High contrast. No shadows