User prompt
level 5 te top asağı yukarı hareket etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
level 3 te potayı yukarı taşı
User prompt
level 2 de potayı yukarı taşı
User prompt
bütün bölümlerde sadece top ortada olsun diğer engelleri rastgele koy
Code edit (10 edits merged)
Please save this source code
User prompt
admin butonu ekle ekstradan önceki bölüme dönmek için
Code edit (2 edits merged)
Please save this source code
User prompt
You are working with a JavaScript-based 2D basketball game. In the game, each level has a ballX, ballY, hoopX, and hoopY position. Rewrite the entire levels array so that in every level, ballX, ballY, hoopX, and hoopY are all set to 1024 and 1366. Do not remove any levels, and preserve the rest of the structure exactly. Also, update the positions of spikes, walls, and rotatingBlocks so that they are also centered at 1024, 1366. Output only the modified levels array, nothing else.
User prompt
topu hep ortada tut
User prompt
son promtu geri al
User prompt
5.bölümde topun yeri aşağı yukarı hareket etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bölüm 5 de topun yerini değiştir y düzleminde
User prompt
bölüm 17 de pota asağı yukarı hareket etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
For Level 5 only, adjust the ball’s starting position as follows: Instead of placing the ball at the vertical center of the screen, move it downward. Lower the ball’s starting Y position by 25% of the total screen height: Example: If screenHeight = 1000, then move the ball down by 1000 * 0.25 = 250 pixels. New Y position: y = screenHeight / 2 + (screenHeight * 0.25) The ball should still be horizontally centered, but placed visibly lower than usual. This creates a new aiming angle for the level without changing the overall layout. This gives Level 5 a slight twist in challenge while keeping everything clean and predictable for the player.
User prompt
son promtu geri al ve topun yerini değiştir 5.levelde 3 birim aşağıda dursun top
User prompt
5. levelde topu daha aşağı bir noktaya koy
User prompt
5.görevde ortadaki engeli kaldır ve topu ortanın yarısı mesafesinde asağı noktaya koy
User prompt
ortadaki engeli kaldır 4.görevdek
User prompt
4.level görevini değiştirir misin 1 kere sektirerek atılsın
User prompt
bütün bölümlerde pota hep en sağ duvara tam dayalı olsun
User prompt
2.ci bölümde potayı en sağdaki duvara tam dayar mısın
User prompt
şimdilik bölümleri kontrol edebilmem için yönetici olarak ekstradan bir nex level boutonu koyar mısın sabit her bölüme
User prompt
For every level, adjust the basketball hoop visuals as follows: Wall Alignment: The entire hoop structure, including the rim and backboard, must be fully attached to the right wall. There should be no visible gap between the backboard and the wall — it must look flush-mounted, as if it's drilled into the wall. Backboard Line Styling: The backboard edge line (visible part of the board from the side) should be: Slightly taller, extending more upward above the rim. A bit thicker, to make it more visually solid and realistic. The line should not sag or extend downward behind the rim — it must stay above or aligned with the rim, never dipping below. Visual Consistency: Keep the board’s position fixed in every level. Ensure the backboard edge visually represents a rigid vertical support, not something floating or flimsy. These changes will make the hoop appear firmly mounted, clean, and visually correct — avoiding any awkward drop or gap, and giving the player a consistent and fair target.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Backboard = Container.expand(function () { var self = Container.call(this); var pole = self.attachAsset('backboardPole', { anchorX: 0.5, anchorY: 1 }); pole.x = 0; pole.y = 0; var board = self.attachAsset('backboard', { anchorX: 0.5, anchorY: 1 }); board.x = 0; board.y = -50; return self; }); var Basketball = Container.expand(function () { var self = Container.call(this); var ball = self.attachAsset('basketball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.isLaunched = false; self.gravity = 0.3; self.bounceDecay = 0.8; self.startX = 0; self.startY = 0; self.reset = function () { self.x = self.startX; self.y = self.startY; self.velocityX = 0; self.velocityY = 0; self.isLaunched = false; // Restart vertical movement if this is Level 5 if (self.isMovingVertically) { // Re-enable movement and restart animation var currentLevel = storage.currentLevel || 1; if (currentLevel === 5) { // Restart the movement animation var _restartBallMovement = function restartBallMovement() { if (self.isMovingVertically && !self.isLaunched) { tween(self, { y: self.moveDirection === 1 ? self.maxY : self.minY }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.moveDirection *= -1; self.startY = self.y; if (self.shadow) { self.shadow.y = self.y + 90; } _restartBallMovement(); } }); } }; _restartBallMovement(); } } // Update shadow position if it exists if (self.shadow) { self.shadow.x = self.x; self.shadow.y = self.y + 90; } }; self.launch = function (forceX, forceY) { self.velocityX = forceX; self.velocityY = forceY; self.isLaunched = true; // Stop vertical movement animation when ball is launched if (self.isMovingVertically) { self.isMovingVertically = false; tween.stop(self, { y: true }); // Stop any ongoing vertical movement tweens } LK.getSound('launch').play(); }; self.update = function () { if (self.isLaunched) { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += self.gravity; // Realistic physics for all four screen edges var ballRadius = 80; // Half of basketball width/height var energyLoss = 0.85; // Energy retained after bounce (realistic friction) var minVelocity = 0.5; // Minimum velocity to prevent infinite micro-bounces // Left wall collision if (self.x <= ballRadius) { self.x = ballRadius; if (self.velocityX < 0) { // Only bounce if moving toward wall self.velocityX = -self.velocityX * energyLoss; self.velocityY = self.velocityY * energyLoss; // Slight energy loss on Y too if (Math.abs(self.velocityX) < minVelocity) { self.velocityX = 0; } LK.getSound('bounce').play(); } } // Right wall collision if (self.x >= 2048 - ballRadius) { self.x = 2048 - ballRadius; if (self.velocityX > 0) { // Only bounce if moving toward wall self.velocityX = -self.velocityX * energyLoss; self.velocityY = self.velocityY * energyLoss; // Slight energy loss on Y too if (Math.abs(self.velocityX) < minVelocity) { self.velocityX = 0; } LK.getSound('bounce').play(); } } // Top wall collision if (self.y <= ballRadius) { self.y = ballRadius; if (self.velocityY < 0) { // Only bounce if moving toward wall self.velocityY = -self.velocityY * energyLoss; self.velocityX = self.velocityX * energyLoss; // Slight energy loss on X too if (Math.abs(self.velocityY) < minVelocity) { self.velocityY = 0; } LK.getSound('bounce').play(); } } // Bottom wall collision if (self.y >= 2732 - ballRadius) { self.y = 2732 - ballRadius; if (self.velocityY > 0) { // Only bounce if moving toward wall self.velocityY = -self.velocityY * energyLoss; self.velocityX = self.velocityX * energyLoss; // Slight energy loss on X too if (Math.abs(self.velocityY) < minVelocity) { self.velocityY = 0; } LK.getSound('bounce').play(); } } } // Update shadow position if it exists if (self.shadow) { self.shadow.x = self.x; self.shadow.y = self.y + 90; } }; return self; }); var Hoop = Container.expand(function () { var self = Container.call(this); // Create backboard as slim vertical bar (only thickness visible) - flush mounted to wall var backboard = self.attachAsset('wall', { anchorX: 1.0, // Right edge anchor for wall attachment anchorY: 0.5, scaleX: 0.2, // Slightly thicker for better visibility scaleY: 2.8, // Much taller backboard extending well above rim tint: 0xFFFFFF }); backboard.x = 0; // Completely flush with wall position (no gap) backboard.y = -80; // Positioned higher so it extends above rim // Create support bracket connecting backboard to wall var wallBracket = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.2, tint: 0x808080 }); wallBracket.x = 12; // Closer to wall for flush mounting wallBracket.y = -50; // Create horizontal rim extending toward left (side view) - made extra wide var rim = self.attachAsset('hoop', { anchorX: 1.0, // Right edge anchored to backboard anchorY: 0.5, scaleX: 2.4, // Extended horizontally toward player - extra wide for very forgiving scoring scaleY: 0.2, // Thin rim profile from side tint: 0xFF4500 }); rim.x = -2; // Closer to backboard for flush mounting rim.y = -80; // Create rim support bracket var rimBracket = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.15, tint: 0x808080 }); rimBracket.x = -35; // Adjusted for better alignment rimBracket.y = -70; // Create vertical backboard support line behind the rim - taller and thicker var supportLine = self.attachAsset('backboardSupport', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, // Thicker for more visual solidity scaleY: 2.0, // Taller extending well above rim tint: 0xC0C0C0, alpha: 0.9 }); supportLine.x = -8; // Closer to backboard for flush mounting supportLine.y = -130; // Positioned much higher above the rim, never dipping below // Create realistic side-view net hanging from rim - positioned to hang naturally below var netSegments = []; for (var i = 0; i < 8; i++) { var netSegment = self.attachAsset('netSegment', { anchorX: 0.5, anchorY: 0, scaleX: 0.8 - i * 0.06, // Tapers as it hangs down scaleY: 1.0, tint: 0xFFFFFF, alpha: 0.7 }); netSegment.x = -140 + i * 10; // Spread across rim width netSegment.y = -60 + i * 12; // Hangs lower below rim with more natural drape netSegments.push(netSegment); } // Store references for animations self.netSegments = netSegments; self.rim = rim; self.backboard = backboard; self.supportLine = supportLine; // Physics collision zones for realistic ball interaction - ultra forgiving self.rimCollisionZone = { x: -110, // Extends even further left from backboard y: -80, width: 320, // Ultra wide rim width for maximum forgiving scoring height: 50 // Extra thick rim height for easiest scoring }; self.backboardCollisionZone = { x: 0, // At wall position - completely flush y: -80, // Positioned higher to match visual backboard width: 40, // Thicker to match visual appearance height: 420 // Much taller backboard height matching visual }; // Vertical support line collision zone for soft redirection self.supportLineCollisionZone = { x: -8, // Closer to backboard for flush mounting y: -130, // Positioned higher above rim width: 12, // Thicker support line width height: 240 // Taller support line height extending well above rim }; self.isMoving = false; self.moveSpeed = 2; self.moveDirection = 1; self.minX = 1700; self.maxX = 1900; self.minY = 200; self.maxY = 2000; self.moveHorizontal = true; self.update = function () { if (self.isMoving) { if (self.moveHorizontal) { self.x += self.moveSpeed * self.moveDirection; if (self.x <= self.minX || self.x >= self.maxX) { self.moveDirection *= -1; } } else { self.y += self.moveSpeed * self.moveDirection; if (self.y <= self.minY || self.y >= self.maxY) { self.moveDirection *= -1; } } } }; return self; }); var RotatingBlock = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('rotatingBlock', { anchorX: 0.5, anchorY: 0.5 }); self.rotationSpeed = 0.05; self.update = function () { blockGraphics.rotation += self.rotationSpeed; }; return self; }); var Spike = Container.expand(function () { var self = Container.call(this); var spikeGraphics = self.attachAsset('spike', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var TrajectoryDot = Container.expand(function () { var self = Container.call(this); var dot = self.attachAsset('trajectory', { anchorX: 0.5, anchorY: 0.5 }); dot.alpha = 0.6; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F4F }); /**** * Game Code ****/ // Game state var currentLevel = storage.currentLevel || 1; var maxLevel = storage.maxLevel || 1; var gameState = 'playing'; // playing, levelComplete, gameOver var attempts = 0; var maxAttempts = 0; var scored = false; var levelGoal = ''; // Objective tracking var wallBounces = 0; var requiredBounces = 0; var touchedWall = false; var objectiveFailed = false; var failureReason = ''; // Timer challenge system var ballReleaseTime = 0; var timerChallenge = false; var timerCountdown = 0; var inputDisabled = false; var timerCountdownText = null; // Global 3-second timer for all levels var globalTimerActive = false; var globalTimerStartTime = 0; // Game objects var basketball = null; var hoop = null; var walls = []; var spikes = []; var rotatingBlocks = []; var trajectoryDots = []; // Input tracking var isDragging = false; var dragStartX = 0; var dragStartY = 0; // Level definitions var levels = [ // Level 1-4: Basic shots { ballX: 200, ballY: 2400, hoopX: 2048, hoopY: 1366, goal: 'Make your first shot!', objective: 'score', // Just score walls: [], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 200, ballY: 2400, hoopX: 2048, hoopY: 800, goal: 'Higher target challenge!', objective: 'score', // Just score walls: [], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 1024, ballY: 2400, hoopX: 1900, hoopY: 600, goal: 'Straight shot challenge!', objective: 'no_wall', // Don't touch any wall walls: [], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 500, ballY: 2000, hoopX: 2048, hoopY: 900, goal: 'Bounce off one wall to score!', objective: 'bounce_once', // Must bounce off exactly one wall walls: [], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, // Level 5-10: Bank shots and obstacles { ballX: 1024, ballY: 2400, hoopX: 1850, hoopY: 600, goal: 'Bounce off one wall!', objective: 'bounce_once', // Must bounce off exactly one wall walls: [], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0, movingBall: true }, { ballX: 300, ballY: 7000, hoopX: 1820, hoopY: 500, goal: 'Avoid the spikes!', objective: 'no_wall', // Don't touch any wall (spikes auto-fail) walls: [], spikes: [{ x: 800, y: 1500 }], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 1700, ballY: 3500, hoopX: 1800, hoopY: 750, goal: 'Navigate the rotating block!', objective: 'score', // Just score while avoiding blocks walls: [], spikes: [], rotatingBlocks: [{ x: 1500, y: 450 }], movingHoop: false, maxAttempts: 0 }, { ballX: 1024, ballY: 2400, hoopX: 1850, hoopY: 400, goal: 'Multiple walls challenge!', objective: 'no_wall', // Don't touch any wall walls: [{ x: 600, y: 1800, width: 30, height: 200 }, { x: 1448, y: 1200, width: 30, height: 200 }], spikes: [], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 200, ballY: 2000, hoopX: 1800, hoopY: 850, goal: 'Precision bank shot!', walls: [{ x: 1024, y: 1366, width: 400, height: 30 }], spikes: [{ x: 1200, y: 1100 }], rotatingBlocks: [], movingHoop: false, maxAttempts: 0 }, { ballX: 1500, ballY: 2300, hoopX: 1820, hoopY: 650, goal: 'Complex obstacle course!', walls: [{ x: 800, y: 1600, width: 30, height: 300 }], spikes: [{ x: 1000, y: 1200 }, { x: 600, y: 1000 }], rotatingBlocks: [{ x: 1200, y: 1800 }], movingHoop: false, maxAttempts: 0 }, // Level 11-19: Moving hoops and restrictions { ballX: 1024, ballY: 2400, hoopX: 1800, hoopY: 800, goal: 'Hit the moving hoop!', walls: [], spikes: [], rotatingBlocks: [], movingHoop: true, maxAttempts: 0 }, { ballX: 400, ballY: 2200, hoopX: 1850, hoopY: 600, goal: 'Moving target with walls!', walls: [{ x: 1024, y: 1500, width: 30, height: 300 }], spikes: [], rotatingBlocks: [], movingHoop: true, maxAttempts: 0 }, { ballX: 1600, ballY: 2300, hoopX: 1820, hoopY: 700, goal: 'One shot only!', walls: [], spikes: [{ x: 1024, y: 1366 }], rotatingBlocks: [], movingHoop: false, maxAttempts: 1 }, { ballX: 300, ballY: 2100, hoopX: 1800, hoopY: 550, goal: 'Moving hoop precision!', walls: [{ x: 800, y: 1200, width: 200, height: 30 }], spikes: [{ x: 1200, y: 1500 }], rotatingBlocks: [], movingHoop: true, maxAttempts: 3 }, { ballX: 1024, ballY: 2500, hoopX: 1850, hoopY: 450, goal: 'Vertical moving hoop!', walls: [{ x: 500, y: 1366, width: 30, height: 400 }, { x: 1548, y: 1366, width: 30, height: 400 }], spikes: [], rotatingBlocks: [], movingHoop: true, maxAttempts: 0 }, { ballX: 200, ballY: 2000, hoopX: 1800, hoopY: 850, goal: 'Ultimate obstacle course!', walls: [{ x: 600, y: 1600, width: 30, height: 200 }, { x: 1200, y: 1000, width: 200, height: 30 }], spikes: [{ x: 800, y: 1300 }, { x: 1400, y: 1400 }], rotatingBlocks: [{ x: 1000, y: 1800 }], movingHoop: false, maxAttempts: 2 }, { ballX: 1700, ballY: 2200, hoopX: 1820, hoopY: 650, goal: 'Moving maze challenge!', walls: [{ x: 800, y: 1800, width: 30, height: 300 }, { x: 1200, y: 1200, width: 30, height: 300 }], spikes: [{ x: 600, y: 1500 }, { x: 1000, y: 1000 }], rotatingBlocks: [{ x: 1400, y: 1600 }], movingHoop: true, maxAttempts: 3 }, { ballX: 1024, ballY: 2600, hoopX: 1850, hoopY: 350, goal: 'Narrow passage challenge!', walls: [{ x: 400, y: 1366, width: 30, height: 600 }, { x: 1648, y: 1366, width: 30, height: 600 }], spikes: [{ x: 1024, y: 1800 }, { x: 1024, y: 900 }], rotatingBlocks: [], movingHoop: false, maxAttempts: 1 }, { ballX: 500, ballY: 2400, hoopX: 1800, hoopY: 550, goal: 'Complex moving target!', walls: [{ x: 700, y: 1500, width: 200, height: 30 }, { x: 1300, y: 1000, width: 200, height: 30 }], spikes: [{ x: 900, y: 1800 }, { ballX: 1024, ballY: 2400, hoopX: 1850, hoopY: 800, goal: 'Vertical moving hoop challenge!', walls: [{ x: 600, y: 1500, width: 30, height: 300 }], spikes: [], rotatingBlocks: [], movingHoop: true, maxAttempts: 0 }, { x: 1100, y: 1300 }], rotatingBlocks: [{ x: 1024, y: 1900 }], movingHoop: true, maxAttempts: 2 }, // Level 20: Ultimate challenge { ballX: 1024, ballY: 2500, hoopX: 1850, hoopY: 450, goal: 'Ultimate Basket Challenge!', walls: [{ x: 300, y: 1366, width: 30, height: 400 }, { x: 800, y: 1800, width: 200, height: 30 }, { x: 1248, y: 1800, width: 200, height: 30 }, { x: 1748, y: 1366, width: 30, height: 400 }], spikes: [{ x: 600, y: 1600 }, { x: 1024, y: 1200 }, { x: 1448, y: 1600 }], rotatingBlocks: [{ x: 512, y: 1000 }, { x: 1536, y: 1000 }], movingHoop: true, maxAttempts: 1 }]; // UI elements var levelText = new Text2('Level 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); var goalText = new Text2('', { size: 40, fill: 0xFFFF00 }); goalText.anchor.set(0.5, 0); goalText.y = 80; LK.gui.top.addChild(goalText); var attemptsText = new Text2('', { size: 35, fill: 0xFFFFFF }); attemptsText.anchor.set(1, 0); LK.gui.topRight.addChild(attemptsText); // Timer countdown text timerCountdownText = new Text2('', { size: 80, fill: 0xFF0000 }); timerCountdownText.anchor.set(0.5, 0.5); LK.gui.center.addChild(timerCountdownText); timerCountdownText.visible = false; // Next Level button var nextLevelButton = new Text2('Next Level →', { size: 60, fill: 0x00FF00 }); nextLevelButton.anchor.set(0.5, 0.5); nextLevelButton.x = 1024; nextLevelButton.y = 2200; nextLevelButton.visible = false; game.addChild(nextLevelButton); // Add button click functionality nextLevelButton.down = function (x, y, obj) { if (nextLevelButton.visible && gameState === 'levelComplete') { // Hide button nextLevelButton.visible = false; // Proceed to next level if (currentLevel < levels.length) { currentLevel++; if (currentLevel > maxLevel) { maxLevel = currentLevel; storage.maxLevel = maxLevel; } storage.currentLevel = currentLevel; initializeLevel(currentLevel); } else { LK.showYouWin(); } } }; // Admin Next Level button for testing var adminNextButton = new Text2('ADMIN: Next →', { size: 40, fill: 0xFF00FF }); adminNextButton.anchor.set(1, 0); adminNextButton.x = -20; adminNextButton.y = 120; adminNextButton.visible = true; LK.gui.topRight.addChild(adminNextButton); // Admin button click functionality adminNextButton.down = function (x, y, obj) { // Always allow advancing to next level for testing if (currentLevel < levels.length) { currentLevel++; if (currentLevel > maxLevel) { maxLevel = currentLevel; storage.maxLevel = maxLevel; } storage.currentLevel = currentLevel; initializeLevel(currentLevel); } else { // Reset to level 1 if at the end currentLevel = 1; storage.currentLevel = 1; initializeLevel(currentLevel); } }; function initializeLevel(levelNum) { if (levelNum > levels.length || levelNum < 1) { return; } // Clear existing objects if (basketball) { if (basketball.shadow) { basketball.shadow.destroy(); } basketball.destroy(); } if (hoop) { hoop.destroy(); } walls.forEach(function (wall) { wall.destroy(); }); spikes.forEach(function (spike) { spike.destroy(); }); rotatingBlocks.forEach(function (block) { block.destroy(); }); trajectoryDots.forEach(function (dot) { dot.destroy(); }); walls = []; spikes = []; rotatingBlocks = []; trajectoryDots = []; var level = levels[levelNum - 1]; // Create basketball basketball = game.addChild(new Basketball()); basketball.x = level.ballX; basketball.y = level.ballY; basketball.startX = level.ballX; basketball.startY = level.ballY; // Level 5 specific ball movement if (levelNum === 5 && level.movingBall) { // Start continuous vertical movement animation var _animateBallMovement = function animateBallMovement() { if (basketball.isMovingVertically && !basketball.isLaunched) { tween(basketball, { y: basketball.moveDirection === 1 ? basketball.maxY : basketball.minY }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { basketball.moveDirection *= -1; basketball.startY = basketball.y; // Update start position if (basketball.shadow) { basketball.shadow.y = basketball.y + 90; } _animateBallMovement(); // Continue animation } }); } }; basketball.isMovingVertically = true; basketball.moveSpeed = 2; basketball.moveDirection = 1; basketball.minY = level.ballY - 300; basketball.maxY = level.ballY + 300; _animateBallMovement(); } // Add shadow ring under basketball to indicate it's draggable var shadow = LK.getAsset('basketball', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 0.3, tint: 0x000000, alpha: 0.3 }); shadow.x = basketball.x; shadow.y = basketball.y + 90; // Position below ball game.addChild(shadow); basketball.shadow = shadow; // Create hoop hoop = game.addChild(new Hoop()); hoop.x = 2048; // Always position flush against rightmost wall hoop.y = level.hoopY; hoop.isMoving = level.movingHoop; // Configure vertical movement for level 17 if (levelNum === 17) { hoop.moveHorizontal = false; hoop.minY = 300; hoop.maxY = 1500; hoop.moveSpeed = 3; } // Create walls level.walls.forEach(function (wallData) { var wall = game.addChild(new Wall()); wall.x = wallData.x; wall.y = wallData.y; if (wallData.width) { wall.scaleX = wallData.width / 200; } if (wallData.height) { wall.scaleY = wallData.height / 30; } walls.push(wall); }); // Create spikes level.spikes.forEach(function (spikeData) { var spike = game.addChild(new Spike()); spike.x = spikeData.x; spike.y = spikeData.y; spikes.push(spike); }); // Create rotating blocks level.rotatingBlocks.forEach(function (blockData) { var block = game.addChild(new RotatingBlock()); block.x = blockData.x; block.y = blockData.y; rotatingBlocks.push(block); }); // Reset game state gameState = 'playing'; attempts = 0; maxAttempts = level.maxAttempts; scored = false; levelGoal = level.goal; // Reset objective tracking wallBounces = 0; requiredBounces = level.objective === 'bounce_once' ? 1 : 0; touchedWall = false; objectiveFailed = false; failureReason = ''; // Reset timer challenge variables timerChallenge = level.objective === 'timer_challenge'; ballReleaseTime = 0; timerCountdown = 0; inputDisabled = false; globalTimerActive = false; globalTimerStartTime = 0; if (timerCountdownText) { timerCountdownText.visible = false; } // Hide Next Level button if (nextLevelButton) { nextLevelButton.visible = false; } // Update UI levelText.setText('Level ' + levelNum); goalText.setText(levelGoal); updateAttemptsText(); } function updateAttemptsText() { if (maxAttempts > 0) { attemptsText.setText('Attempts: ' + attempts + '/' + maxAttempts); } else { attemptsText.setText('Attempts: ' + attempts); } } function checkCollisions() { if (!basketball.isLaunched) { return; } // Check wall collisions (level walls) walls.forEach(function (wall) { if (basketball.intersects(wall)) { var ballCenterX = basketball.x; var ballCenterY = basketball.y; var wallCenterX = wall.x; var wallCenterY = wall.y; var wallWidth = wall.width * wall.scaleX; var wallHeight = wall.height * wall.scaleY; var overlapX = Math.abs(ballCenterX - wallCenterX) - (80 + wallWidth / 2); var overlapY = Math.abs(ballCenterY - wallCenterY) - (80 + wallHeight / 2); // Realistic physics collision with angle-based reflection var energyLoss = 0.85; if (overlapX < overlapY) { basketball.velocityX = -basketball.velocityX * energyLoss; basketball.velocityY = basketball.velocityY * energyLoss; // Apply energy loss to perpendicular component too basketball.x += ballCenterX < wallCenterX ? -5 : 5; } else { basketball.velocityY = -basketball.velocityY * energyLoss; basketball.velocityX = basketball.velocityX * energyLoss; // Apply energy loss to perpendicular component too basketball.y += ballCenterY < wallCenterY ? -5 : 5; } LK.getSound('bounce').play(); // Track wall bounces and check objectives wallBounces++; touchedWall = true; var level = levels[currentLevel - 1]; if (level.objective === 'no_wall') { objectiveFailed = true; failureReason = 'You touched the wall!'; } } }); // Check spike collisions spikes.forEach(function (spike) { if (basketball.intersects(spike)) { objectiveFailed = true; failureReason = 'You hit the spikes!'; } }); // Check rotating block collisions rotatingBlocks.forEach(function (block) { if (basketball.intersects(block)) { var ballCenterX = basketball.x; var ballCenterY = basketball.y; var blockCenterX = block.x; var blockCenterY = block.y; var overlapX = Math.abs(ballCenterX - blockCenterX) - 120; var overlapY = Math.abs(ballCenterY - blockCenterY) - 120; if (overlapX < overlapY) { basketball.velocityX = -basketball.velocityX * basketball.bounceDecay; basketball.x += ballCenterX < blockCenterX ? -5 : 5; } else { basketball.velocityY = -basketball.velocityY * basketball.bounceDecay; basketball.y += ballCenterY < blockCenterY ? -5 : 5; } LK.getSound('bounce').play(); } }); // Check backboard collision for realistic physics var ballCenterX = basketball.x; var ballCenterY = basketball.y; var hoopCenterX = hoop.x + hoop.backboardCollisionZone.x; var hoopCenterY = hoop.y + hoop.backboardCollisionZone.y; if (Math.abs(ballCenterX - hoopCenterX) < 80 + hoop.backboardCollisionZone.width / 2 && Math.abs(ballCenterY - hoopCenterY) < 80 + hoop.backboardCollisionZone.height / 2) { // Ball hit backboard basketball.velocityX = -basketball.velocityX * basketball.bounceDecay * 0.9; basketball.velocityY = basketball.velocityY * 0.95; basketball.x += basketball.velocityX > 0 ? -8 : 8; LK.getSound('bounce').play(); // Flash backboard LK.effects.flashObject(hoop, 0xFFFFFF, 200); } // Check vertical support line collision for soft redirection helping var supportLineCenterX = hoop.x + hoop.supportLineCollisionZone.x; var supportLineCenterY = hoop.y + hoop.supportLineCollisionZone.y; if (Math.abs(ballCenterX - supportLineCenterX) < 80 + hoop.supportLineCollisionZone.width / 2 && Math.abs(ballCenterY - supportLineCenterY) < 80 + hoop.supportLineCollisionZone.height / 2) { // Ball hit vertical support line - apply soft downward redirection instead of hard bounce var distanceFromRim = Math.abs(ballCenterY - (hoop.y + hoop.rimCollisionZone.y)); var redirectionStrength = Math.max(0.1, 1.0 - distanceFromRim / 80); // Stronger redirection when closer to rim // Gently redirect ball downward into the hoop if shot is close if (basketball.velocityX < 0) { // Ball moving toward hoop from right side var rimCenterX = hoop.x + hoop.rimCollisionZone.x; var rimCenterY = hoop.y + hoop.rimCollisionZone.y; var directionToRimX = rimCenterX - ballCenterX; var directionToRimY = rimCenterY - ballCenterY; // Apply gentle redirection toward rim center basketball.velocityX += directionToRimX * 0.003 * redirectionStrength; basketball.velocityY += Math.abs(directionToRimY) * 0.002 * redirectionStrength; // Gentle downward push // Reduce horizontal velocity to prevent harsh deflection basketball.velocityX *= 0.85; // Small position adjustment to prevent getting stuck basketball.x -= 3; // Subtle flash effect for support line hit LK.effects.flashObject(hoop.supportLine, 0xFFFFAA, 150); } } // Check rim collision for realistic bouncing - extra forgiving scoring zone var rimCenterX = hoop.x + hoop.rimCollisionZone.x; var rimCenterY = hoop.y + hoop.rimCollisionZone.y; if (Math.abs(ballCenterX - rimCenterX) < 80 + hoop.rimCollisionZone.width / 2 && Math.abs(ballCenterY - rimCenterY) < 80 + hoop.rimCollisionZone.height / 2) { // Check if ball is going through the hoop (scoring) - ultra wide scoring zone with auto-absorption var scoringZoneWidth = 140; // Even wider invisible scoring zone for maximum forgiveness var scoringZoneHeight = 40; // Taller scoring zone for easier front rim entry var autoAbsorptionZone = 80; // Larger zone where ball gets gently pulled toward center // Auto-absorption: if ball is close to center, gently guide it inward var distanceFromCenterX = Math.abs(ballCenterX - rimCenterX); var distanceFromCenterY = Math.abs(ballCenterY - rimCenterY); if (distanceFromCenterX < autoAbsorptionZone && distanceFromCenterY < autoAbsorptionZone && basketball.velocityY > 0) { // Gently pull ball toward center for easier scoring var pullStrength = 0.15; // Subtle pull force if (ballCenterX < rimCenterX) { basketball.velocityX += pullStrength; } else if (ballCenterX > rimCenterX) { basketball.velocityX -= pullStrength; } } if (basketball.velocityY > 0 && ballCenterX > rimCenterX - scoringZoneWidth && ballCenterX < rimCenterX + scoringZoneWidth && ballCenterY > rimCenterY - scoringZoneHeight && ballCenterY < rimCenterY + scoringZoneHeight) { // Check if objective was met before scoring var level = levels[currentLevel - 1]; var objectiveMet = true; var objectiveFailureMessage = ''; if (level.objective === 'bounce_once' && wallBounces !== 1) { objectiveMet = false; objectiveFailureMessage = wallBounces === 0 ? 'You must bounce off one wall!' : 'You bounced too many times!'; } else if (level.objective === 'no_wall' && touchedWall) { objectiveMet = false; objectiveFailureMessage = 'You were not supposed to touch any walls!'; } if (!objectiveMet) { // Objective failed LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); }, 2000); return; // Don't continue with scoring } // Score! scored = true; LK.getSound('score').play(); // Check if it's a clean swish (ball passes through center of rim) var distanceFromCenter = Math.abs(ballCenterX - rimCenterX); var isCleanShot = distanceFromCenter < 30; // Within 30 pixels of center if (isCleanShot) { // Clean swish - special effects LK.effects.flashObject(hoop, 0x00FFFF, 800); // Cyan flash for perfect shot // Slow down ball slightly for dramatic effect basketball.velocityX *= 0.8; basketball.velocityY *= 0.9; } else { // Regular score LK.effects.flashObject(hoop, 0x00FF00, 500); } // Let global timer handle level progression for all levels // Animate net swish effect with enhanced 3D movement if (hoop.netSegments) { hoop.netSegments.forEach(function (segment, index) { var swishIntensity = isCleanShot ? 1.5 : 1.0; // More dramatic swish for clean shots // First phase: compress and sway tween(segment, { scaleY: 0.05 * swishIntensity, alpha: 0.2, rotation: segment.rotation + 0.3 * swishIntensity, y: segment.y + 15 // Pull net segments down more }, { duration: isCleanShot ? 200 : 150, easing: tween.easeOut }); LK.setTimeout(function () { // Second phase: bounce back with realistic sway tween(segment, { scaleY: 0.15, alpha: 0.8, rotation: segment.rotation - 0.1 * swishIntensity, y: segment.y - 10 // Natural bounce back position }, { duration: isCleanShot ? 600 : 400, easing: tween.bounceOut }); }, index * (isCleanShot ? 40 : 30)); }); } // Level complete - show success display and Next Level button gameState = 'levelComplete'; // Show immediate success feedback if (timerCountdownText) { timerCountdownText.setText('Level Complete!'); timerCountdownText.tint = 0x00FF00; timerCountdownText.visible = true; timerCountdownText.scaleX = 1.5; timerCountdownText.scaleY = 1.5; // Animate success text tween(timerCountdownText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.bounceOut }); } // Show Next Level button nextLevelButton.visible = true; tween(nextLevelButton, { scaleX: 1.2, scaleY: 1.2, alpha: 1 }, { duration: 500, easing: tween.bounceOut }); // Lock input immediately upon scoring inputDisabled = true; } else { // Ball hit rim but didn't score - ultra soft rim bounce for maximum forgiveness var overlapX = Math.abs(ballCenterX - rimCenterX) - (80 + hoop.rimCollisionZone.width / 2); var overlapY = Math.abs(ballCenterY - rimCenterY) - (80 + hoop.rimCollisionZone.height / 2); // Ultra soft bounces with minimal energy loss for maximum forgiveness var softBounceDecay = 0.2; // Even softer bounce - less harsh rejection var energyLoss = 0.9; // Higher energy retention - keep more momentum var distanceFromCenter = Math.abs(ballCenterX - rimCenterX); var distanceFromFrontEdge = Math.abs(ballCenterX - (rimCenterX - hoop.rimCollisionZone.width / 2)); // Make front edge (facing player) extremely forgiving if (distanceFromFrontEdge < 30 && basketball.velocityX < 0) { // Front edge hit - minimal bounce with downward guidance softBounceDecay = 0.1; energyLoss = 0.95; // Add slight downward velocity to help ball drop into hoop basketball.velocityY += 0.5; } else if (distanceFromCenter < 50) { // Very close to center - barely bounce at all softBounceDecay = 0.15; energyLoss = 0.92; } else if (distanceFromCenter < 100) { // Moderately close - gentle bounce softBounceDecay = 0.25; energyLoss = 0.88; } if (overlapX < overlapY) { basketball.velocityX = -basketball.velocityX * softBounceDecay; basketball.velocityY = basketball.velocityY * energyLoss; // Keep more perpendicular velocity basketball.x += ballCenterX < rimCenterX ? -1 : 1; // Minimal position adjustment } else { basketball.velocityY = -basketball.velocityY * softBounceDecay; basketball.velocityX = basketball.velocityX * energyLoss; // Keep more perpendicular velocity basketball.y += ballCenterY < rimCenterY ? -1 : 1; // Minimal position adjustment } LK.getSound('bounce').play(); // Flash rim on hit with gentler color LK.effects.flashObject(hoop.rim, 0xFFAA00, 300); } } } function resetBall() { basketball.reset(); clearTrajectory(); clearPowerIndicators(); gameState = 'playing'; // Reset objective tracking for new attempt wallBounces = 0; touchedWall = false; objectiveFailed = false; failureReason = ''; // Reset timer challenge variables ballReleaseTime = 0; timerCountdown = 0; inputDisabled = false; globalTimerActive = false; globalTimerStartTime = 0; if (timerCountdownText) { timerCountdownText.visible = false; } // Hide Next Level button if (nextLevelButton) { nextLevelButton.visible = false; } } function showTrajectory(forceX, forceY) { clearTrajectory(); var simX = basketball.x; var simY = basketball.y; var simVelX = forceX; var simVelY = forceY; var simGravity = 0.3; var forceMagnitude = Math.sqrt(forceX * forceX + forceY * forceY); var powerPercent = Math.min(forceMagnitude / 40, 1.0); for (var i = 0; i < 30; i++) { simX += simVelX; simY += simVelY; simVelY += simGravity; if (i % 3 === 0) { var dot = game.addChild(new TrajectoryDot()); dot.x = simX; dot.y = simY; // Scale dots based on power level dot.scaleX = 0.5 + powerPercent * 0.8; dot.scaleY = 0.5 + powerPercent * 0.8; // Color dots based on power dot.tint = powerPercent > 0.8 ? 0xff0000 : powerPercent > 0.5 ? 0xffff00 : 0x00ff00; trajectoryDots.push(dot); } if (simX <= 80 || simX >= 1968 || simY <= 80) { break; } } } function clearTrajectory() { trajectoryDots.forEach(function (dot) { dot.destroy(); }); trajectoryDots = []; } function updatePowerIndicators(currentX, currentY, dragDistance, forceMagnitude) { // Clear existing indicators clearPowerIndicators(); // Calculate power percentage (0 to 1) var powerPercent = Math.min(forceMagnitude / 40, 1.0); // Create aim line from ball to current drag position var aimLineAsset = LK.getAsset('trajectory', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.max(1, dragDistance / 8), scaleY: Math.max(2, 2 + powerPercent * 3) }); aimLineAsset.x = (basketball.x + currentX) / 2; aimLineAsset.y = (basketball.y + currentY) / 2; aimLineAsset.rotation = Math.atan2(currentY - basketball.y, currentX - basketball.x); aimLineAsset.alpha = 0.8; aimLineAsset.tint = powerPercent > 0.8 ? 0xff0000 : powerPercent > 0.5 ? 0xffff00 : 0x00ff00; game.addChild(aimLineAsset); aimLine = aimLineAsset; // Create power bar indicator var powerBarWidth = 300; var powerBarHeight = 20; var powerBarX = basketball.x - powerBarWidth / 2; var powerBarY = basketball.y - 120; // Power bar background var powerBarBg = LK.getAsset('wall', { anchorX: 0, anchorY: 0, scaleX: powerBarWidth / 200, scaleY: powerBarHeight / 30, tint: 0x333333 }); powerBarBg.x = powerBarX; powerBarBg.y = powerBarY; powerBarBg.alpha = 0.7; game.addChild(powerBarBg); // Power bar fill var fillWidth = powerBarWidth * powerPercent; if (fillWidth > 0) { var powerBarFill = LK.getAsset('wall', { anchorX: 0, anchorY: 0, scaleX: fillWidth / 200, scaleY: powerBarHeight / 30, tint: powerPercent > 0.8 ? 0xff0000 : powerPercent > 0.5 ? 0xffff00 : 0x00ff00 }); powerBarFill.x = powerBarX; powerBarFill.y = powerBarY; powerBarFill.alpha = 0.9; game.addChild(powerBarFill); powerBar = [powerBarBg, powerBarFill]; } else { powerBar = [powerBarBg]; } } function clearPowerIndicators() { if (aimLine) { aimLine.destroy(); aimLine = null; } if (powerBar) { powerBar.forEach(function (bar) { bar.destroy(); }); powerBar = null; } } // Power indicator variables var powerBar = null; var aimLine = null; var maxDragDistance = 400; // Maximum pixel distance for full power // Input handling game.down = function (x, y, obj) { if (gameState !== 'playing' || basketball.isLaunched || inputDisabled) { return; } isDragging = true; dragStartX = x; dragStartY = y; }; game.move = function (x, y, obj) { if (!isDragging || gameState !== 'playing' || basketball.isLaunched || inputDisabled) { return; } // Calculate drag distance and force with increased sensitivity var dragX = dragStartX - x; var dragY = dragStartY - y; var dragDistance = Math.sqrt(dragX * dragX + dragY * dragY); var dragMultiplier = Math.min(dragDistance / maxDragDistance, 1.0); var forceX = dragX * 0.08 * dragMultiplier; var forceY = dragY * 0.08 * dragMultiplier; // Limit force to maximum power var magnitude = Math.sqrt(forceX * forceX + forceY * forceY); if (magnitude > 40) { forceX = forceX / magnitude * 40; forceY = forceY / magnitude * 40; } // Update visual feedback updatePowerIndicators(x, y, dragDistance, magnitude); showTrajectory(forceX, forceY); }; game.up = function (x, y, obj) { if (!isDragging || gameState !== 'playing' || basketball.isLaunched || inputDisabled) { return; } isDragging = false; // Calculate final force with increased sensitivity var dragX = dragStartX - x; var dragY = dragStartY - y; var dragDistance = Math.sqrt(dragX * dragX + dragY * dragY); var dragMultiplier = Math.min(dragDistance / maxDragDistance, 1.0); var forceX = dragX * 0.08 * dragMultiplier; var forceY = dragY * 0.08 * dragMultiplier; // Limit force to maximum power var magnitude = Math.sqrt(forceX * forceX + forceY * forceY); if (magnitude > 40) { forceX = forceX / magnitude * 40; forceY = forceY / magnitude * 40; } // Clear visual indicators clearPowerIndicators(); if (magnitude > 1) { attempts++; updateAttemptsText(); basketball.launch(forceX, forceY); clearTrajectory(); // Start global 3-second timer for all levels ballReleaseTime = LK.ticks; globalTimerActive = true; globalTimerStartTime = LK.ticks; inputDisabled = true; timerCountdownText.visible = true; // Check if out of attempts if (maxAttempts > 0 && attempts >= maxAttempts && !scored) { LK.setTimeout(function () { if (!scored) { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); } }, 3000); } } }; // Main update loop game.update = function () { if (gameState === 'playing') { // Handle global 3-second timer countdown for all levels if (globalTimerActive && globalTimerStartTime > 0) { var timeSinceRelease = (LK.ticks - globalTimerStartTime) * (1000 / 60); // Convert to milliseconds var remainingTime = Math.max(0, 3000 - timeSinceRelease); var secondsLeft = Math.ceil(remainingTime / 1000); if (timerCountdownText) { timerCountdownText.setText(secondsLeft.toString()); timerCountdownText.visible = true; timerCountdownText.tint = 0xFFFFFF; // Reset tint to white // Animate countdown text var scale = 1.0 + Math.sin(LK.ticks * 0.3) * 0.2; timerCountdownText.scaleX = scale; timerCountdownText.scaleY = scale; } // Check if 3 seconds have passed - end level regardless of success/failure if (remainingTime <= 0) { globalTimerActive = false; var level = levels[currentLevel - 1]; var wasSuccessful = scored; // Check objective completion if (level.objective === 'bounce_once' && wallBounces !== 1) { wasSuccessful = false; } else if (level.objective === 'no_wall' && touchedWall) { wasSuccessful = false; } else if (level.objective === 'timer_challenge') { // For timer challenge, must score within 1 second var timeSinceReleaseForTimer = (LK.ticks - ballReleaseTime) * (1000 / 60); if (!scored || timeSinceReleaseForTimer > 1000) { wasSuccessful = false; } } if (wasSuccessful) { // Flash screen with success color LK.effects.flashScreen(0x00FF00, 500); // Add sparkle effect to hoop if (hoop) { tween(hoop, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut }); LK.setTimeout(function () { tween(hoop, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.bounceOut }); }, 200); } // Hide timer countdown as level is complete if (timerCountdownText) { timerCountdownText.visible = false; } // Lock input but don't auto-progress - wait for button click inputDisabled = true; } else { // Level failed if (timerCountdownText) { timerCountdownText.setText('FAIL'); timerCountdownText.tint = 0xFF0000; } LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); }, 2000); } return; } } // Track screen edge bounces for objectives (before calling checkCollisions) if (basketball.isLaunched) { var ballRadius = 80; var lastWallBounces = wallBounces; // Check if ball just bounced off any screen edge this frame if (basketball.x <= ballRadius && basketball.velocityX > 0 || basketball.x >= 2048 - ballRadius && basketball.velocityX < 0 || basketball.y <= ballRadius && basketball.velocityY > 0 || basketball.y >= 2732 - ballRadius && basketball.velocityY < 0) { // Ball just bounced off a screen edge if (wallBounces === lastWallBounces) { // Prevent double counting wallBounces++; touchedWall = true; var level = levels[currentLevel - 1]; if (level.objective === 'no_wall') { objectiveFailed = true; failureReason = 'You touched the wall!'; } } } } checkCollisions(); // Check for objective failures if (objectiveFailed && !scored) { LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); }, 2000); return; } // Check if ball is off screen (reset) if (basketball.isLaunched && basketball.y > 2800) { if (!scored) { // Ball missed - check if this constitutes objective failure var level = levels[currentLevel - 1]; var missedObjectiveMessage = 'Missed the hoop!'; if (level.objective === 'bounce_once' && wallBounces !== 1) { missedObjectiveMessage = wallBounces === 0 ? 'You must bounce off one wall!' : 'You bounced too many times!'; } else if (level.objective === 'no_wall' && touchedWall) { missedObjectiveMessage = 'You touched the wall!'; } LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); }, 2000); } else if (maxAttempts > 0 && attempts >= maxAttempts) { currentLevel = 1; storage.currentLevel = 1; LK.showGameOver(); } else { resetBall(); } } } }; // Initialize first level initializeLevel(currentLevel);
===================================================================
--- original.js
+++ change.js
@@ -41,8 +41,35 @@
self.y = self.startY;
self.velocityX = 0;
self.velocityY = 0;
self.isLaunched = false;
+ // Restart vertical movement if this is Level 5
+ if (self.isMovingVertically) {
+ // Re-enable movement and restart animation
+ var currentLevel = storage.currentLevel || 1;
+ if (currentLevel === 5) {
+ // Restart the movement animation
+ var _restartBallMovement = function restartBallMovement() {
+ if (self.isMovingVertically && !self.isLaunched) {
+ tween(self, {
+ y: self.moveDirection === 1 ? self.maxY : self.minY
+ }, {
+ duration: 2000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ self.moveDirection *= -1;
+ self.startY = self.y;
+ if (self.shadow) {
+ self.shadow.y = self.y + 90;
+ }
+ _restartBallMovement();
+ }
+ });
+ }
+ };
+ _restartBallMovement();
+ }
+ }
// Update shadow position if it exists
if (self.shadow) {
self.shadow.x = self.x;
self.shadow.y = self.y + 90;
@@ -51,8 +78,15 @@
self.launch = function (forceX, forceY) {
self.velocityX = forceX;
self.velocityY = forceY;
self.isLaunched = true;
+ // Stop vertical movement animation when ball is launched
+ if (self.isMovingVertically) {
+ self.isMovingVertically = false;
+ tween.stop(self, {
+ y: true
+ }); // Stop any ongoing vertical movement tweens
+ }
LK.getSound('launch').play();
};
self.update = function () {
if (self.isLaunched) {
@@ -409,9 +443,10 @@
walls: [],
spikes: [],
rotatingBlocks: [],
movingHoop: false,
- maxAttempts: 0
+ maxAttempts: 0,
+ movingBall: true
}, {
ballX: 300,
ballY: 7000,
hoopX: 1820,
@@ -892,12 +927,40 @@
trajectoryDots = [];
var level = levels[levelNum - 1];
// Create basketball
basketball = game.addChild(new Basketball());
- basketball.x = 1024; // Center horizontally (2048 / 2)
- basketball.y = 1366; // Center vertically (2732 / 2)
- basketball.startX = 1024;
- basketball.startY = 1366;
+ basketball.x = level.ballX;
+ basketball.y = level.ballY;
+ basketball.startX = level.ballX;
+ basketball.startY = level.ballY;
+ // Level 5 specific ball movement
+ if (levelNum === 5 && level.movingBall) {
+ // Start continuous vertical movement animation
+ var _animateBallMovement = function animateBallMovement() {
+ if (basketball.isMovingVertically && !basketball.isLaunched) {
+ tween(basketball, {
+ y: basketball.moveDirection === 1 ? basketball.maxY : basketball.minY
+ }, {
+ duration: 2000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ basketball.moveDirection *= -1;
+ basketball.startY = basketball.y; // Update start position
+ if (basketball.shadow) {
+ basketball.shadow.y = basketball.y + 90;
+ }
+ _animateBallMovement(); // Continue animation
+ }
+ });
+ }
+ };
+ basketball.isMovingVertically = true;
+ basketball.moveSpeed = 2;
+ basketball.moveDirection = 1;
+ basketball.minY = level.ballY - 300;
+ basketball.maxY = level.ballY + 300;
+ _animateBallMovement();
+ }
// Add shadow ring under basketball to indicate it's draggable
var shadow = LK.getAsset('basketball', {
anchorX: 0.5,
anchorY: 0.5,
Modern App Store icon, high definition, square with rounded corners, for a game titled "Basket Bounce Challenge" and with the description "A colorful basketball puzzle game with slingshot mechanics across 20 challenging levels. Drag and release the ball to score, progressing from simple shots to complex bank shot puzzles with moving hoops and obstacles.". No text on icon!
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Basket Bounce Challenge" and with the description "A colorful basketball puzzle game with slingshot mechanics across 20 challenging levels. Drag and release the ball to score, progressing from simple shots to complex bank shot puzzles with moving hoops and obstacles.". No text on banner!
A minimalist black and white basketball court background. The court is shown from a side view or slightly isometric angle. It includes clear outlines for the hoop, backboard, half court line, and three-point arc, all in clean black lines on a white surface (or vice versa). The style is modern, simple, and flat — no players, just the environment.. In-Game asset. 2d. High contrast. No shadows