User prompt
add start menu music that is diffrent from the game music
User prompt
make the ball bouce a bit higher when it hits the paddle
User prompt
the text is to big make it a bit smaller
User prompt
i cant read it
User prompt
make a descripition of the game on the start menu
User prompt
make the paddle all one color ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when you die start back up right away with out going into the start menu
User prompt
make the ball bounce in random directions
User prompt
just a bit slower
User prompt
make the ball bounce a little bit slower
User prompt
make the ball bounce faster
User prompt
the ball bounces to slow
User prompt
to slow make the ball bounce faster
User prompt
ok make the ball bounce slower too fast
User prompt
make the ball bounce way faster
User prompt
make it bounce farther
User prompt
make the ball bounce farther
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
/****
* 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.18; // Further reduced gravity for slower falling
self.airResistance = 0.995; // Slightly increased air resistance for slower movement
self.bounciness = 0.92; // Lower bounciness for less energetic bounces
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;
// Generate a random angle between 0 and 2π (full 360 degrees)
var randomAngle = Math.random() * Math.PI * 2;
// Set initial speed magnitude
var speedMagnitude = 15 * speedMultiplier;
// Calculate velocity components based on random angle
self.speedX = Math.cos(randomAngle) * speedMagnitude;
self.speedY = Math.sin(randomAngle) * speedMagnitude;
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 more random physics
if (self.x < 20 || self.x > 2028) {
// Flip the horizontal direction
self.speedX = -self.speedX * self.bounciness * 1.2;
// Add significant random variation to both speed components
self.speedX += Math.random() * 6 - 3; // Major randomness on x-axis
self.speedY += Math.random() * 4 - 2; // Add randomness to y-axis on wall bounce too
// Chance for a very wild bounce (20% chance)
if (Math.random() < 0.2) {
self.speedX *= 0.5 + Math.random();
self.speedY *= 0.5 + Math.random();
}
// 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 with more random bounces
if (self.y < 20) {
// Flip the vertical direction
self.speedY = -self.speedY * self.bounciness * 1.25;
// Add significant random variation to both speed components
self.speedX += Math.random() * 5 - 2.5; // Add randomness to x-axis on ceiling bounce
self.speedY += Math.random() * 5 - 2.5; // Major randomness on y-axis
// Chance for a very wild bounce (20% chance)
if (Math.random() < 0.2) {
// Completely random direction after ceiling hit
var randomAngle = Math.random() * Math.PI + Math.PI; // Angle in bottom half
var currentSpeed = Math.sqrt(self.speedX * self.speedX + self.speedY * self.speedY);
self.speedX = Math.cos(randomAngle) * currentSpeed;
self.speedY = Math.sin(randomAngle) * currentSpeed;
}
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 frantic paddle game where you\ncontrol a golden paddle to bounce balls away from\ndeadly red lava. Score points with each bounce,\nlevel up for increased speed and challenge.\nCan you set a new high score record?', {
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 reduced spin based on hit position and paddle movement
ball.spin = hitPos * 0.3 + paddleMovementEffect * 0.6; // Reduced spin effect
ball.lastHitPos = hitPos;
// Calculate angle based on where the ball hits the paddle with more randomness
// Wider angle range - full 180 degrees (0 to 180) instead of 120 degrees
var angle = Math.PI * Math.random() + Math.PI / 2; // Random angle in upper half (90 to 270 degrees)
// Add influence from hit position
angle = angle * 0.7 + (Math.PI / 3 * hitPos + Math.PI / 2) * 0.3;
// Calculate current speed with an adjustment
var currentSpeed = Math.sqrt(ball.speedX * ball.speedX + ball.speedY * ball.speedY);
var speed = Math.max(currentSpeed * 1.25, 12 * speedMultiplier);
// Adjust ball direction with more random bounce physics
ball.speedX = Math.cos(angle) * speed + paddleMovementEffect * 1.5;
ball.speedY = -Math.sin(angle) * speed * 1.15;
// Add larger random variations for more unpredictable bouncing
ball.speedX += (Math.random() * 4 - 2) * speedMultiplier; // Increased randomness
ball.speedY += (Math.random() * 4 - 2) * speedMultiplier; // Increased randomness
// 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 moderate speed boost for slightly slower progression
speedMultiplier += 0.4 + level * 0.08; // Reduced speed boost for slightly slower gameplay
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, 500);
// Restart the game after a short delay instead of showing menu
LK.setTimeout(function () {
// Keep the game elements visible, just restart game logic
// Clear any remaining balls
for (var i = 0; i < balls.length; i++) {
balls[i].destroy();
}
balls = [];
ballsInPlay = 0;
// Restart the game immediately
startGame();
// Ensure we're in playing state
currentState = GAME_STATE.PLAYING;
}, 500);
}
// Start the game
function startGame() {
// Reset variables
score = 0;
level = 1;
combo = 0;
lastBallHit = 0;
gameActive = true;
speedMultiplier = 1.5; // Further reduced initial speed multiplier for slower initial gameplay
maxBalls = 3; // Maintained same number of maximum balls
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
@@ -626,9 +626,9 @@
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?', {
+ var gameDescription = new Text2('Lava Bounce 2: A frantic paddle game where you\ncontrol a golden paddle to bounce balls away from\ndeadly red lava. Score points with each bounce,\nlevel up for increased speed and challenge.\nCan you set a new high score record?', {
size: 60,
fill: 0xFFFFFF
});
gameDescription.anchor.set(0.5, 0.5);