/****
* 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