User prompt
make the physics of the ball more realisic ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the ends of the paddle this color #FFB612
User prompt
make the ends of the paddle rounded
User prompt
make the ends of the paddle beveld
User prompt
add a trail to the ball for when it movesa
User prompt
make each level make the ball go faster and faster
User prompt
make it so when the cursor is over the "Play Game" button the button swings back and forth quickly. @upit/tween.v1
User prompt
when the cursor is over the start game button make the button rotate back and forth quickly until the cursor is not on the button @upit/tween.v1
User prompt
it didnt work man come on make it work
User prompt
when the cursor is over the start game button make the button rotate back and forth quickly until the cursor is not on the button ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
move the high score counter thats in settings down a bit
User prompt
make the high score counter when in game bigger
User prompt
make the high score text smaller\
User prompt
make the high score counter bigger
User prompt
make the text on the hits to next level just a #/25
User prompt
add a click sound for when the mouse is clicked
User prompt
add a discription of the game in the settings menu
User prompt
make the text Lava Bounce rotate back and forth ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
In the settings menu, there is text to display your high score. Move that to the center.
User prompt
move the button in settings that resets high score to true center
User prompt
put that text in the true center
User prompt
put the reset high score text in the center of the settings menu
User prompt
remove the ability to change the colors of the lava, ball, and paddle
User prompt
make a bounce sound for when the ball hits the wall\
User prompt
make the colors that you can pick to change the lava color, ball color, and paddle color to these four colors: Steelers Gold: #FFB612 Black: #101820 Blue: #003087 Red: #C60C30 Silver: #A5ACAF
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphic = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.active = true; self.trailCounter = 0; self.gravity = 0.15; // Gravity constant self.airResistance = 0.99; // Air resistance factor self.bounciness = 0.85; // Energy loss on bounce self.spin = 0; // Ball spin (affects horizontal movement) self.lastHitPos = 0; // Last hit position on paddle (for spin calculation) self.reset = function (speedMultiplier) { // Set position to center of screen self.x = 2048 / 2; self.y = 2732 / 2; // Increased speeds for faster gameplay self.speedX = (Math.random() * 12 - 6) * speedMultiplier; self.speedY = (Math.random() * 3 + 5) * speedMultiplier; self.active = true; self.spin = 0; // Reset spin self.lastHitPos = 0; // Reset last hit position }; self.update = function () { if (!self.active) { return; } // Store last positions for collision detection var lastX = self.x; var lastY = self.y; // Apply gravity - increases vertical speed over time self.speedY += self.gravity; // Apply air resistance self.speedX *= self.airResistance; self.speedY *= self.airResistance; // Apply spin effect to horizontal movement self.speedX += self.spin * 0.1; // Gradually reduce spin over time self.spin *= 0.98; // Apply velocity self.x += self.speedX; self.y += self.speedY; // Add trail effect based on speed self.trailCounter++; // Adjust trail frequency based on speed - faster speed = more frequent trails var trailFrequency = Math.max(1, 5 - Math.floor((Math.abs(self.speedX) + Math.abs(self.speedY)) / 10)); // Create more trails at higher speeds if (self.trailCounter > trailFrequency) { self.trailCounter = 0; var trail = LK.getAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: lastX, y: lastY }); // Adjust trail size based on ball speed var speedFactor = Math.min(1, (Math.abs(self.speedX) + Math.abs(self.speedY)) / 40); trail.scale.set(self.scale.x * (0.7 - speedFactor * 0.2), self.scale.y * (0.7 - speedFactor * 0.2)); trail.tint = gameColors.ball; // Higher alpha for faster speeds trail.alpha = 0.5 + speedFactor * 0.3; game.addChildAt(trail, game.getChildIndex(self)); // Fade out and remove trail - faster trails disappear quicker var trailDuration = 300 - speedFactor * 150; tween(trail, { alpha: 0, scaleX: trail.scale.x * 0.5, scaleY: trail.scale.y * 0.5 }, { duration: trailDuration, onFinish: function onFinish() { trail.destroy(); } }); } // Rotate the ball based on horizontal speed to show rolling effect ballGraphic.rotation += self.speedX * 0.05; // Bounce off sides with realistic physics if (self.x < 20 || self.x > 2028) { self.speedX = -self.speedX * self.bounciness; // Lose some energy on wall bounce // Add some random variation to make bounces less predictable self.speedX += Math.random() * 0.4 - 0.2; // Keep the ball within the game boundaries self.x = Math.max(20, Math.min(2028, self.x)); // Play bounce sound if soundEnabled is true if (soundEnabled) { LK.getSound('bounce').play(); } } // Check if ball hits the top of the screen if (self.y < 20) { self.speedY = -self.speedY * self.bounciness; // Lose some energy on ceiling bounce // Add some random variation to make bounces less predictable self.speedY += Math.random() * 0.4 - 0.2; self.y = 20; // Play bounce sound if soundEnabled is true if (soundEnabled) { LK.getSound('bounce').play(); } } }; return self; }); var DiagonalStripe = Container.expand(function () { var self = Container.call(this); // Create a shape for the diagonal stripe var stripeGraphic = self.attachAsset('background', { anchorX: 0, anchorY: 0 }); // Configure the stripe appearance stripeGraphic.width = 3000; // Increased width to extend past screen edges stripeGraphic.height = 100; stripeGraphic.tint = 0xffffff; // White // Initial position and rotation stripeGraphic.rotation = Math.PI / 4; // 45 degrees in radians // Position it to extend past screen edges stripeGraphic.x = -500; // Start before the left edge // Empty update method (stripe will be still) self.update = function () { // No animation - stripe remains still }; return self; }); var Paddle = Container.expand(function () { var self = Container.call(this); // Create the main paddle base - middle rectangle section var paddleGraphic = self.attachAsset('paddle', { anchorX: 0.5, anchorY: 0.5 }); paddleGraphic.tint = 0xFFB612; // Set paddle color to #FFB612 // Create the left rounded end (circle shape) var leftEnd = LK.getAsset('ball', { // Using the ball asset as it's a circle anchorX: 0.5, anchorY: 0.5, width: paddleGraphic.height, height: paddleGraphic.height, tint: 0xFFB612 }); leftEnd.x = -paddleGraphic.width / 2 + leftEnd.width / 2; self.addChild(leftEnd); // Create the right rounded end (circle shape) var rightEnd = LK.getAsset('ball', { // Using the ball asset as it's a circle anchorX: 0.5, anchorY: 0.5, width: paddleGraphic.height, height: paddleGraphic.height, tint: 0xffb612 }); rightEnd.x = paddleGraphic.width / 2 - rightEnd.width / 2; // Make sure the right end is the correct color rightEnd.tint = 0xFFB612; self.addChild(rightEnd); // Trim the main paddle to accommodate rounded ends paddleGraphic.width = paddleGraphic.width - paddleGraphic.height; self.width = paddleGraphic.width + paddleGraphic.height; // Total width includes the circles self.height = paddleGraphic.height; self.update = function () { // Keep paddle within screen bounds self.x = Math.max(self.width / 2, Math.min(2048 - self.width / 2, self.x)); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffffff // Light sky blue for a calmer atmosphere }); /**** * Game Code ****/ // Game state management var GAME_STATE = { MENU: 0, PLAYING: 1, SETTINGS: 2 }; var currentState = GAME_STATE.MENU; // Default colors for game elements - softer, more calming colors var gameColors = { paddle: 0xffb612, // Changed to requested color #ffb612 ball: 0xFFB612, // Changed to requested color #FFB612 lava: 0xC60C30 // Changed to requested color #C60C30 }; // Color saving/loading disabled // Make game accessible to other functions var gameInstance = game; // Game variables var background; var paddle; var lava; var balls = []; var score = 0; var highScore = storage.highScore || 0; var level = 1; var combo = 0; var lastBallHit = 0; var gameActive = false; var speedMultiplier = 1.0; var maxBalls = 1; var ballsInPlay = 0; var spawnInterval; var hitsToNextLevel = 25; var currentHits = 0; var hitCounterText; // UI elements var scoreTxt; var levelTxt; var comboTxt; var highScoreTxt; var speedTxt; // Default sound settings var soundEnabled = true; var musicEnabled = true; // Load stored sound settings var soundSetting = storage.soundEnabled; if (soundSetting !== undefined) { soundEnabled = soundSetting; } // Initialize game elements (called when starting game) function initializeGameElements() { if (!background) { // Create background background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(background); // Initialize lava lava = LK.getAsset('lava', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 2732 - 200 }); lava.tint = gameColors.lava; game.addChild(lava); // Initialize paddle paddle = new Paddle(); paddle.x = 2048 / 2; paddle.y = 2732 - 250; paddle.getChildAt(0).tint = 0xffb612; game.addChild(paddle); // Diagonal stripe removed from here and placed in menu // Create hit counter text scoreTxt = new Text2('0', { size: 180, fill: 0x101820 }); scoreTxt.anchor.set(0.5, 0.5); // Position score text precisely in the center of the screen scoreTxt.x = 2048 / 2; // True center horizontally scoreTxt.y = 2732 / 2; // True center vertically game.addChild(scoreTxt); // Create level text levelTxt = new Text2('Level: 1', { size: 80, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); levelTxt.x = 2000; levelTxt.y = 50; LK.gui.addChild(levelTxt); // Create combo text comboTxt = new Text2('', { size: 60, fill: 0xFFFFFF }); comboTxt.anchor.set(0.5, 0); comboTxt.x = 1024; comboTxt.y = 50; comboTxt.alpha = 0; LK.gui.addChild(comboTxt); // Create high score text highScoreTxt = new Text2('High Score: ' + highScore, { size: 100, fill: 0xffb612 }); highScoreTxt.anchor.set(1, 0); highScoreTxt.x = 2000; highScoreTxt.y = 130; // Position below hit counter game.addChild(highScoreTxt); // Add directly to game to ensure visibility // Create speed indicator text speedTxt = new Text2('Speed: x' + speedMultiplier.toFixed(1), { size: 80, fill: 0xffb612 }); speedTxt.anchor.set(0, 0); speedTxt.x = 48; speedTxt.y = 50; game.addChild(speedTxt); // Create hit counter text hitCounterText = new Text2(currentHits + '/25', { size: 100, fill: 0x003087 }); hitCounterText.anchor.set(0.5, 0); hitCounterText.x = 1024; hitCounterText.y = 150; // More visible position at top of screen game.addChild(hitCounterText); // Add directly to game to ensure visibility } // Show game elements background.visible = true; lava.visible = true; paddle.visible = true; scoreTxt.visible = true; levelTxt.visible = true; comboTxt.visible = true; highScoreTxt.visible = true; hitCounterText.visible = true; } // Create menu elements var titleText; var startButton; var settingsButton; var settingsPanel; var menuBackground; // Initialize menu initializeMenu(); function initializeMenu() { // Create menu background menuBackground = new Container(); var menuBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, tint: 0xFFFFFF // White color for menu background }); // Create a border by adding a slightly larger background behind it var menuBorder = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, tint: 0xA5ACAF // Border color set to #A5ACAF }); menuBorder.width = 2048 + 10 * 2; // Adding 10px on each side menuBorder.height = 2732 + 10 * 2; // Adding 10px on each side menuBorder.x = -10; // Position it 10px to the left menuBorder.y = -10; // Position it 10px to the top menuBackground.addChild(menuBorder); menuBackground.addChild(menuBg); game.addChild(menuBackground); // Diagonal stripe removed from menu // Create game title titleText = new Text2('Lava Bounce', { size: 150, fill: 0x101820 }); titleText.anchor.set(0.5, 0); titleText.x = 1024; titleText.y = 200; game.addChild(titleText); // Animate the title to rotate back and forth function animateTitleRotation() { // Rotate to one side tween(titleText, { rotation: 0.1 // Slight rotation to the right (in radians) }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Rotate to the other side tween(titleText, { rotation: -0.1 // Slight rotation to the left (in radians) }, { duration: 1000, easing: tween.easeInOut, onFinish: animateTitleRotation // Loop the animation }); } }); } // Start the title rotation animation animateTitleRotation(); // Create the "2" as a separate, larger text element var titleNumber = new Text2('2', { size: 250, // Bigger than the main title text fill: 0xFFB612 // Gold color }); titleNumber.anchor.set(0.5, 0); titleNumber.x = 1024; // Centered horizontally titleNumber.y = 350; // Positioned below the main title game.addChild(titleNumber); // Animate the "2" with a continuous bounce effect function animateTitle2() { // Bounce up animation tween(titleNumber, { y: 320, // Move up slightly scaleX: 1.1, scaleY: 1.1 }, { duration: 700, onFinish: function onFinish() { // Bounce down animation tween(titleNumber, { y: 350, // Back to original position scaleX: 1, scaleY: 1 }, { duration: 700, onFinish: animateTitle2 // Loop the animation }); } }); } // Start the animation animateTitle2(); // Create start button startButton = new Text2('Start Game', { size: 100, fill: 0xFFB612 }); startButton.anchor.set(0.5, 0.5); startButton.x = 1024; startButton.y = 1200; startButton.interactive = true; startButton.isHovered = false; // Track hover state startButton.move = function (x, y, obj) { // Check if cursor is over the button if (x >= startButton.x - startButton.width / 2 && x <= startButton.x + startButton.width / 2 && y >= startButton.y - startButton.height / 2 && y <= startButton.y + startButton.height / 2) { // Start animation only if not already hovering if (!startButton.isHovered) { startButton.isHovered = true; // Apply a slight scale increase when hovered tween(startButton, { scaleX: 1.05, scaleY: 1.05 }, { duration: 200, easing: tween.easeOut }); animateStartButton(); } } else { // Stop animation when cursor moves away if (startButton.isHovered) { startButton.isHovered = false; tween.stop(startButton, { rotation: true }); tween(startButton, { rotation: 0, scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } } }; // Function to animate the start button function animateStartButton() { if (!startButton.isHovered) { return; } // Rotate to one side tween(startButton, { rotation: 0.08 // Slight rotation (in radians) }, { duration: 50, // Very quick rotation for more responsive feel easing: tween.easeInOut, onFinish: function onFinish() { if (!startButton.isHovered) { startButton.rotation = 0; return; } // Rotate to the other side tween(startButton, { rotation: -0.08 // Slight rotation in opposite direction }, { duration: 50, // Very quick rotation for more responsive feel easing: tween.easeInOut, onFinish: animateStartButton // Continue the animation }); } }); } game.addChild(startButton); // Create settings button settingsButton = new Text2('Settings', { size: 100, fill: 0x101820 }); settingsButton.anchor.set(0.5, 0.5); settingsButton.x = 1024; settingsButton.y = 1400; settingsButton.interactive = true; game.addChild(settingsButton); // Set up event handlers for menu startButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } hideMenu(); initializeGameElements(); startGame(); }; settingsButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } hideMenu(); showSettings(); }; } function hideMenu() { if (menuBackground) { menuBackground.visible = false; } if (titleText) { titleText.visible = false; } if (startButton) { startButton.visible = false; } if (settingsButton) { settingsButton.visible = false; } // Make sure high score is visible in game if (highScoreTxt) { highScoreTxt.visible = true; } } function showMenu() { currentState = GAME_STATE.MENU; if (menuBackground) { menuBackground.visible = true; } if (titleText) { titleText.visible = true; } if (startButton) { startButton.visible = true; } if (settingsButton) { settingsButton.visible = true; } if (settingsPanel) { settingsPanel.visible = false; } } function showSettings() { currentState = GAME_STATE.SETTINGS; // Create settings panel if it doesn't exist if (!settingsPanel) { settingsPanel = new Container(); game.addChild(settingsPanel); // Settings panel background without border var panelContainer = new Container(); panelContainer.x = 1024; panelContainer.y = 1366; // Set initial scale to zero for animation panelContainer.scale.x = 0; panelContainer.scale.y = 0; // Inner panel background (without blue border) var panelBg = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); panelBg.width = 1600; panelBg.height = 1000; panelBg.tint = 0x101820; // Dark blue/black color for settings panel panelContainer.addChild(panelBg); settingsPanel.addChild(panelContainer); // Settings title var settingsTitle = new Text2('Settings', { size: 120, fill: 0xFFFFFF }); settingsTitle.anchor.set(0.5, 0); settingsTitle.x = 1024; settingsTitle.y = 500; settingsPanel.addChild(settingsTitle); // Color selectors have been removed // Game description text var gameDescription = new Text2('Lava Bounce 2: A fast-paced paddle game\nwhere you bounce balls to avoid the lava.\nHow high can your score go?', { size: 60, fill: 0xFFFFFF }); gameDescription.anchor.set(0.5, 0.5); gameDescription.x = 1024; // True center horizontally gameDescription.y = 700; settingsPanel.addChild(gameDescription); // High score display in settings var highScoreDisplay = new Text2('High Score: ' + highScore, { size: 80, fill: 0xFFFFFF }); highScoreDisplay.anchor.set(0, 0.5); highScoreDisplay.x = 400; highScoreDisplay.y = 970; // Moved down a bit settingsPanel.addChild(highScoreDisplay); // Reset high score button var resetButton = new Text2('Reset High Score', { size: 80, fill: 0xFF6B6B }); resetButton.anchor.set(0.5, 0.5); resetButton.x = 1024; // True center horizontally resetButton.y = 1366; // True center vertically resetButton.interactive = true; resetButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } showResetConfirmation(); }; settingsPanel.addChild(resetButton); // Back to menu button var backButton = new Text2('Back to Menu', { size: 80, fill: 0xFFFFFF }); backButton.anchor.set(0.5, 0.5); backButton.x = 1024; backButton.y = 1100; backButton.interactive = true; backButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } // Animate settings panel closing tween(settingsPanel.getChildAt(0), { scaleX: 0, scaleY: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { settingsPanel.visible = false; showMenu(); } }); }; settingsPanel.addChild(backButton); } else { settingsPanel.visible = true; // Reset scale for animation if panel already exists settingsPanel.getChildAt(0).scale.x = 0; settingsPanel.getChildAt(0).scale.y = 0; } // Animate the settings panel opening with bounce effect tween(settingsPanel.getChildAt(0), { scaleX: 1, scaleY: 1 }, { duration: 600, easing: tween.elasticOut }); // Color buttons function has been removed } // Initialize balls array function createBall() { if (ballsInPlay >= maxBalls || !gameActive) { return; } var ball = new Ball(); ball.reset(speedMultiplier); ball.getChildAt(0).tint = gameColors.ball; // Visual indicator of speed - make ball slightly smaller as it gets faster var scale = Math.max(0.6, 1 - (speedMultiplier - 1) * 0.15); ball.scale.set(scale, scale); balls.push(ball); game.addChild(ball); ballsInPlay++; } // Handle input events based on current state game.down = function (x, y, obj) { if (currentState === GAME_STATE.PLAYING) { paddle.x = x; } // Check if we hit any interactive elements if (obj && obj.event && obj.event.target && obj.event.target.down) { obj.event.target.down(x, y, obj); } }; game.move = function (x, y, obj) { if (currentState === GAME_STATE.PLAYING) { paddle.x = x; } }; // Update function game.update = function () { // Update any diagonal stripes in the game (always update even when not playing) for (var i = 0; i < game.children.length; i++) { if (game.children[i] instanceof DiagonalStripe) { game.children[i].update(); } } // Check if in playing state if (currentState !== GAME_STATE.PLAYING) { return; } // Game play state if (!gameActive) { return; } // Update speed indicator if it exists if (speedTxt) { speedTxt.setText('Speed: x' + speedMultiplier.toFixed(1)); } // Only create a ball if none exists if (ballsInPlay === 0) { createBall(); } // Update paddle and track position for physics calculations game.lastPaddleX = paddle.x; // Store current position for next frame paddle.update(); // Update all balls for (var i = balls.length - 1; i >= 0; i--) { var ball = balls[i]; if (!ball.active) { continue; } ball.update(); // Check if ball hits paddle with improved collision detection if (ball.speedY > 0 && ball.y + 20 >= paddle.y - paddle.height / 2 && ball.y - 20 <= paddle.y + paddle.height / 2 && ball.x + 20 >= paddle.x - paddle.width / 2 && ball.x - 20 <= paddle.x + paddle.width / 2) { // Calculate hit position from -1 (left edge) to 1 (right edge) var hitPos = (ball.x - paddle.x) / (paddle.width / 2); // Calculate spin based on the difference between current and last hit position // This simulates the effect of a moving paddle hitting the ball var paddleMovementEffect = 0; if (game.lastPaddleX !== undefined) { paddleMovementEffect = (paddle.x - game.lastPaddleX) * 0.1; } // Apply spin based on hit position and paddle movement ball.spin = hitPos * 0.5 + paddleMovementEffect; ball.lastHitPos = hitPos; // Calculate angle based on where the ball hits the paddle var angle = Math.PI / 3 * hitPos + Math.PI / 2; // Angle between 30 and 150 degrees // Calculate current speed with a slight boost var currentSpeed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY); var speed = Math.max(currentSpeed * 1.05, 7 * speedMultiplier); // Slightly increase speed on each bounce // Adjust ball direction with more realistic physics ball.speedX = Math.cos(angle) * speed + paddleMovementEffect; ball.speedY = -Math.sin(angle) * speed; // Always go up // Add small random variations to make bouncing less predictable ball.speedX += (Math.random() * 0.6 - 0.3) * speedMultiplier; ball.speedY += (Math.random() * 0.6 - 0.3) * speedMultiplier; // Create a bounce effect with the paddle - make it visually respond to the hit tween(paddle, { scaleY: 0.85, y: paddle.y + 5 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(paddle, { scaleY: 1.0, y: paddle.y - 5 }, { duration: 100, easing: tween.elasticOut }); } }); // Move ball above paddle to prevent multiple collisions ball.y = paddle.y - paddle.height / 2 - 20; // Add a visual impact effect var impactEffect = LK.getAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: ball.x, y: ball.y + 10, tint: 0xFFFFFF }); impactEffect.scale.set(1.5, 0.5); impactEffect.alpha = 0.7; game.addChild(impactEffect); // Animate and remove the impact effect tween(impactEffect, { alpha: 0, scaleX: 2.5, scaleY: 0.2 }, { duration: 200, onFinish: function onFinish() { impactEffect.destroy(); } }); // Simple scoring - always add 1 point score += 1; // Hide combo text comboTxt.alpha = 0; // Update hit counter scoreTxt.setText('' + score); // Center the score text scoreTxt.x = 2048 / 2; // True center horizontally scoreTxt.y = 2732 / 2; // True center vertically // Make it fade and gently grow when updated tween(scoreTxt, { scaleX: 1.1, // Smaller scale change scaleY: 1.1, // Smaller scale change alpha: 0.8 // Slight fade out }, { duration: 300, // Longer duration for smoother animation easing: tween.easeInOut, // Smoother easing onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1, scaleY: 1, alpha: 1 // Back to full opacity }, { duration: 300, // Longer duration easing: tween.easeInOut // Smoother easing }); } }); LK.setScore(score); // Play bounce sound if enabled if (soundEnabled) { LK.getSound('bounce').play(); } // Update hit counter for level system currentHits++; hitCounterText.setText(currentHits + '/' + hitsToNextLevel); // Level up based on hits if (currentHits >= hitsToNextLevel) { currentHits = 0; levelUp(); hitCounterText.setText('Hits to Next Level: ' + hitsToNextLevel); // Animate hit counter text tween(hitCounterText, { scaleX: 1.2, scaleY: 1.2, alpha: 0.8 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(hitCounterText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300, easing: tween.easeInOut }); } }); } } // Check if ball falls into lava if (ball.y > lava.y) { // Play lava sound if enabled if (soundEnabled) { LK.getSound('lava').play(); } // Flash the lava tween(lava, { tint: 0xffffff }, { duration: 200, onFinish: function onFinish() { tween(lava, { tint: 0xe74c3c }, { duration: 200 }); } }); // Remove ball ball.active = false; ball.destroy(); balls.splice(i, 1); ballsInPlay--; // Check game over if (balls.length === 0 && ballsInPlay === 0) { gameOver(); } } } }; // Reset confirmation popup function showResetConfirmation() { // Create popup container var popup = new Container(); game.addChild(popup); // Popup background var popupBg = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); popupBg.width = 1200; popupBg.height = 700; popupBg.tint = 0x101820; popup.addChild(popupBg); // Border for popup var popupBorder = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); popupBorder.width = 1210; popupBorder.height = 710; popupBorder.tint = 0xFFB612; popup.addChildAt(popupBorder, 0); // Confirmation text var confirmText = new Text2('Reset High Score?', { size: 90, fill: 0xFFFFFF }); confirmText.anchor.set(0.5, 0); confirmText.x = 1024; confirmText.y = 1200; popup.addChild(confirmText); // Yes button var yesButton = new Text2('Yes', { size: 80, fill: 0xFF6B6B }); yesButton.anchor.set(0.5, 0.5); yesButton.x = 824; yesButton.y = 1450; yesButton.interactive = true; yesButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } // Reset high score highScore = 0; storage.highScore = 0; // Update high score display if (highScoreTxt) { highScoreTxt.setText('High Score: 0'); } // Update settings display settingsPanel.children.forEach(function (child) { if (child instanceof Text2 && child.text && child.text.startsWith('High Score:')) { child.setText('High Score: 0'); } }); // Remove popup with animation tween(popup, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, onFinish: function onFinish() { popup.destroy(); } }); }; popup.addChild(yesButton); // No button var noButton = new Text2('No', { size: 80, fill: 0xFFFFFF }); noButton.anchor.set(0.5, 0.5); noButton.x = 1224; noButton.y = 1450; noButton.interactive = true; noButton.down = function () { if (soundEnabled) { LK.getSound('click').play(); } // Remove popup with animation tween(popup, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, onFinish: function onFinish() { popup.destroy(); } }); }; popup.addChild(noButton); // Animate popup appearing popup.scale.set(0.8, 0.8); popup.alpha = 0; tween(popup, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } function levelUp() { level++; levelTxt.setText('Level: ' + level); // Show level up message with speed information var levelUpTxt = new Text2('LEVEL UP!\nSpeed x' + speedMultiplier.toFixed(1), { size: 120, fill: 0xFFFFFF }); levelUpTxt.anchor.set(0.5, 0.5); levelUpTxt.x = 1024; levelUpTxt.y = 1366; LK.gui.addChild(levelUpTxt); // Animate level up message tween(levelUpTxt, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 1000, onFinish: function onFinish() { levelUpTxt.destroy(); } }); // Increase difficulty with a higher speed boost that grows with each level speedMultiplier += 0.2 + level * 0.1; // Dynamically increase speed based on level maxBalls = 1; // Keep maxBalls at 1 // Reset hit counter for next level currentHits = 0; // Increase hits required for next level for increasing challenge hitsToNextLevel = 25 + (level - 1) * 5; hitCounterText.setText('0/' + hitsToNextLevel); } function gameOver() { gameActive = false; // Check if we have a new high score if (score > highScore) { highScore = score; storage.highScore = highScore; // Show new high score message var newHighScoreTxt = new Text2('NEW HIGH SCORE!', { size: 120, fill: 0xFFB612 }); newHighScoreTxt.anchor.set(0.5, 0.5); newHighScoreTxt.x = 1024; newHighScoreTxt.y = 1000; LK.gui.addChild(newHighScoreTxt); // Animate high score message tween(newHighScoreTxt, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 1500, onFinish: function onFinish() { newHighScoreTxt.destroy(); } }); // Update high score display if (highScoreTxt) { highScoreTxt.setText('High Score: ' + highScore); } } // Flash the screen red to indicate death LK.effects.flashScreen(0xff0000, 1000); // Return to menu after a short delay LK.setTimeout(function () { // Hide game elements if (background) { background.visible = false; } if (lava) { lava.visible = false; } if (paddle) { paddle.visible = false; } if (scoreTxt) { scoreTxt.visible = false; } if (levelTxt) { levelTxt.visible = false; } if (comboTxt) { comboTxt.visible = false; } if (hitCounterText) { hitCounterText.visible = false; } if (highScoreTxt) { highScoreTxt.visible = false; } if (speedTxt) { speedTxt.visible = false; } // Clear any remaining balls for (var i = 0; i < balls.length; i++) { balls[i].destroy(); } balls = []; ballsInPlay = 0; // Show menu instead of restarting game showMenu(); }, 1000); } // Start the game function startGame() { // Reset variables score = 0; level = 1; combo = 0; lastBallHit = 0; gameActive = true; speedMultiplier = 1.5; // Increased initial speed multiplier for faster gameplay maxBalls = 3; // Fewer maximum balls for less chaotic gameplay ballsInPlay = 0; currentHits = 0; hitsToNextLevel = 25; // Update UI scoreTxt.setText('0'); scoreTxt.scale.set(1, 1); // Reset any scaling from animations scoreTxt.x = 2048 / 2; // True center horizontally scoreTxt.y = 2732 / 2; // True center vertically levelTxt.setText('Level: 1'); comboTxt.setText(''); comboTxt.alpha = 0; hitCounterText.setText('0/' + hitsToNextLevel); // Update high score display if (highScoreTxt) { highScoreTxt.setText('High Score: ' + highScore); } // Clear any existing balls for (var i = 0; i < balls.length; i++) { balls[i].destroy(); } balls = []; // Start with one ball createBall(); // Play music if enabled - softer volume for a calmer feel if (musicEnabled) { LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, // Lower volume duration: 2000 // Longer fade in } }); } // Ensure the current state is set to playing currentState = GAME_STATE.PLAYING; } // Game will start when player presses the Play button in the menu
===================================================================
--- original.js
+++ change.js
@@ -18,24 +18,40 @@
self.speedX = 0;
self.speedY = 0;
self.active = true;
self.trailCounter = 0;
+ self.gravity = 0.15; // Gravity constant
+ self.airResistance = 0.99; // Air resistance factor
+ self.bounciness = 0.85; // Energy loss on bounce
+ self.spin = 0; // Ball spin (affects horizontal movement)
+ self.lastHitPos = 0; // Last hit position on paddle (for spin calculation)
self.reset = function (speedMultiplier) {
// Set position to center of screen
self.x = 2048 / 2;
self.y = 2732 / 2;
// Increased speeds for faster gameplay
self.speedX = (Math.random() * 12 - 6) * speedMultiplier;
self.speedY = (Math.random() * 3 + 5) * speedMultiplier;
self.active = true;
+ self.spin = 0; // Reset spin
+ self.lastHitPos = 0; // Reset last hit position
};
self.update = function () {
if (!self.active) {
return;
}
// Store last positions for collision detection
var lastX = self.x;
var lastY = self.y;
+ // Apply gravity - increases vertical speed over time
+ self.speedY += self.gravity;
+ // Apply air resistance
+ self.speedX *= self.airResistance;
+ self.speedY *= self.airResistance;
+ // Apply spin effect to horizontal movement
+ self.speedX += self.spin * 0.1;
+ // Gradually reduce spin over time
+ self.spin *= 0.98;
// Apply velocity
self.x += self.speedX;
self.y += self.speedY;
// Add trail effect based on speed
@@ -70,11 +86,15 @@
trail.destroy();
}
});
}
- // Bounce off sides
+ // Rotate the ball based on horizontal speed to show rolling effect
+ ballGraphic.rotation += self.speedX * 0.05;
+ // Bounce off sides with realistic physics
if (self.x < 20 || self.x > 2028) {
- self.speedX = -self.speedX;
+ self.speedX = -self.speedX * self.bounciness; // Lose some energy on wall bounce
+ // Add some random variation to make bounces less predictable
+ self.speedX += Math.random() * 0.4 - 0.2;
// Keep the ball within the game boundaries
self.x = Math.max(20, Math.min(2028, self.x));
// Play bounce sound if soundEnabled is true
if (soundEnabled) {
@@ -82,9 +102,11 @@
}
}
// Check if ball hits the top of the screen
if (self.y < 20) {
- self.speedY = -self.speedY;
+ self.speedY = -self.speedY * self.bounciness; // Lose some energy on ceiling bounce
+ // Add some random variation to make bounces less predictable
+ self.speedY += Math.random() * 0.4 - 0.2;
self.y = 20;
// Play bounce sound if soundEnabled is true
if (soundEnabled) {
LK.getSound('bounce').play();
@@ -713,28 +735,83 @@
// Only create a ball if none exists
if (ballsInPlay === 0) {
createBall();
}
- // Update paddle
+ // Update paddle and track position for physics calculations
+ game.lastPaddleX = paddle.x; // Store current position for next frame
paddle.update();
// Update all balls
for (var i = balls.length - 1; i >= 0; i--) {
var ball = balls[i];
if (!ball.active) {
continue;
}
ball.update();
- // Check if ball hits paddle
+ // Check if ball hits paddle with improved collision detection
if (ball.speedY > 0 && ball.y + 20 >= paddle.y - paddle.height / 2 && ball.y - 20 <= paddle.y + paddle.height / 2 && ball.x + 20 >= paddle.x - paddle.width / 2 && ball.x - 20 <= paddle.x + paddle.width / 2) {
- // Calculate angle based on where the ball hits the paddle for more predictable bounces
- var hitPos = (ball.x - paddle.x) / (paddle.width / 2); // -1 to 1 based on hit position
+ // Calculate hit position from -1 (left edge) to 1 (right edge)
+ var hitPos = (ball.x - paddle.x) / (paddle.width / 2);
+ // Calculate spin based on the difference between current and last hit position
+ // This simulates the effect of a moving paddle hitting the ball
+ var paddleMovementEffect = 0;
+ if (game.lastPaddleX !== undefined) {
+ paddleMovementEffect = (paddle.x - game.lastPaddleX) * 0.1;
+ }
+ // Apply spin based on hit position and paddle movement
+ ball.spin = hitPos * 0.5 + paddleMovementEffect;
+ ball.lastHitPos = hitPos;
+ // Calculate angle based on where the ball hits the paddle
var angle = Math.PI / 3 * hitPos + Math.PI / 2; // Angle between 30 and 150 degrees
- var speed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY); // Maintain speed magnitude
- speed = Math.max(speed, 7 * speedMultiplier); // Increased minimum speed
- ball.speedX = Math.cos(angle) * speed; // More predictable direction based on hit position
+ // Calculate current speed with a slight boost
+ var currentSpeed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY);
+ var speed = Math.max(currentSpeed * 1.05, 7 * speedMultiplier); // Slightly increase speed on each bounce
+ // Adjust ball direction with more realistic physics
+ ball.speedX = Math.cos(angle) * speed + paddleMovementEffect;
ball.speedY = -Math.sin(angle) * speed; // Always go up
+ // Add small random variations to make bouncing less predictable
+ ball.speedX += (Math.random() * 0.6 - 0.3) * speedMultiplier;
+ ball.speedY += (Math.random() * 0.6 - 0.3) * speedMultiplier;
+ // Create a bounce effect with the paddle - make it visually respond to the hit
+ tween(paddle, {
+ scaleY: 0.85,
+ y: paddle.y + 5
+ }, {
+ duration: 100,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(paddle, {
+ scaleY: 1.0,
+ y: paddle.y - 5
+ }, {
+ duration: 100,
+ easing: tween.elasticOut
+ });
+ }
+ });
// Move ball above paddle to prevent multiple collisions
ball.y = paddle.y - paddle.height / 2 - 20;
+ // Add a visual impact effect
+ var impactEffect = LK.getAsset('ball', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: ball.x,
+ y: ball.y + 10,
+ tint: 0xFFFFFF
+ });
+ impactEffect.scale.set(1.5, 0.5);
+ impactEffect.alpha = 0.7;
+ game.addChild(impactEffect);
+ // Animate and remove the impact effect
+ tween(impactEffect, {
+ alpha: 0,
+ scaleX: 2.5,
+ scaleY: 0.2
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ impactEffect.destroy();
+ }
+ });
// Simple scoring - always add 1 point
score += 1;
// Hide combo text
comboTxt.alpha = 0;