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