User prompt
add back ground asset
User prompt
buat bola jatuh sesuai gaya gravitasi
User prompt
make realistik ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat pergerakkan ball halus ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ball jangan bergetar
User prompt
buat pantulan diding maze lemah
User prompt
buat bola tidak berat agar bisa melayang
User prompt
buat ball terlihat berat dan tidak ada animasi getaran ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
perbaiko musik background
User prompt
jangan buat bola bergetar. buat kaku bulat
User prompt
buat bola terlihat solid dan berat ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat black hole harus berada dalam maze jangan di luar maze
User prompt
buat bola berat pantulan ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat bola tidak bisa ke luar jalur
User prompt
posisikan black hold di dalam jalur
User prompt
buat control tap. tap layar kiri mantul ke kiri. tap layar tengah pantul vertikal. tap layar kanan mantul ke kanan.
User prompt
black hole diletakkan di ujung jalur maze paling bawah
User prompt
black hold selalu di tempat paling bawah
User prompt
tap untuk loncat memantul
User prompt
buat maze yang bagus
Code edit (1 edits merged)
Please save this source code
User prompt
Bounce Quest: Dynamic Maze Runner
Initial prompt
buat game control tap. tap bola pantul dalam labirinth acak yang berubah setiap satu menit. sebagai player mencari lubang hitam untuk finish game.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.gravity = 1.2; self.friction = 0.95; self.bounceForce = 0.6; self.maxSpeed = 20; self.update = function () { // Apply gravity self.velocityY += self.gravity; // Apply friction self.velocityX *= self.friction; self.velocityY *= self.friction; // Limit max speed var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY); if (speed > self.maxSpeed) { self.velocityX = self.velocityX / speed * self.maxSpeed; self.velocityY = self.velocityY / speed * self.maxSpeed; } // Update position self.x += self.velocityX; self.y += self.velocityY; // Check maze boundaries and collisions checkBallCollisions(); }; self.addForce = function (forceX, forceY) { self.velocityX += forceX; self.velocityY += forceY; }; return self; }); var MazeCell = Container.expand(function (cellType) { var self = Container.call(this); self.cellType = cellType || 'wall'; var cellGraphics; if (self.cellType === 'wall') { cellGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); } else if (self.cellType === 'path') { cellGraphics = self.attachAsset('path', { anchorX: 0.5, anchorY: 0.5 }); } else if (self.cellType === 'blackhole') { cellGraphics = self.attachAsset('blackhole', { anchorX: 0.5, anchorY: 0.5 }); } return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ var ball; var maze = []; var mazeWidth = 20; var mazeHeight = 30; var cellSize = 60; var mazeContainer; var blackholeX, blackholeY; var timeLeft = 60; var gameWon = false; // UI Elements var timerText = new Text2('60', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); var scoreText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 150; scoreText.y = 20; LK.gui.topLeft.addChild(scoreText); // Initialize maze container mazeContainer = game.addChild(new Container()); mazeContainer.x = (2048 - mazeWidth * cellSize) / 2; mazeContainer.y = (2732 - mazeHeight * cellSize) / 2; // Generate initial maze function generateMaze() { // Clear existing maze for (var i = 0; i < maze.length; i++) { for (var j = 0; j < maze[i].length; j++) { if (maze[i][j]) { maze[i][j].destroy(); } } } maze = []; // Initialize maze grid (all walls initially) var mazeGrid = []; for (var y = 0; y < mazeHeight; y++) { mazeGrid[y] = []; maze[y] = []; for (var x = 0; x < mazeWidth; x++) { // 0 = wall, 1 = path, 2 = visited mazeGrid[y][x] = 0; maze[y][x] = null; } } // Recursive backtracking maze generation var stack = []; var currentX = 1; var currentY = 1; mazeGrid[currentY][currentX] = 1; // Mark starting cell as path stack.push({ x: currentX, y: currentY }); while (stack.length > 0) { var neighbors = []; var directions = [{ x: 0, y: -2 }, // North { x: 2, y: 0 }, // East { x: 0, y: 2 }, // South { x: -2, y: 0 } // West ]; // Find unvisited neighbors for (var i = 0; i < directions.length; i++) { var nx = currentX + directions[i].x; var ny = currentY + directions[i].y; if (nx > 0 && nx < mazeWidth - 1 && ny > 0 && ny < mazeHeight - 1 && mazeGrid[ny][nx] === 0) { neighbors.push({ x: nx, y: ny, dir: directions[i] }); } } if (neighbors.length > 0) { // Choose random neighbor var randomNeighbor = neighbors[Math.floor(Math.random() * neighbors.length)]; var nextX = randomNeighbor.x; var nextY = randomNeighbor.y; var wallX = currentX + randomNeighbor.dir.x / 2; var wallY = currentY + randomNeighbor.dir.y / 2; // Remove wall between current and next cell mazeGrid[wallY][wallX] = 1; mazeGrid[nextY][nextX] = 1; // Move to next cell currentX = nextX; currentY = nextY; stack.push({ x: currentX, y: currentY }); } else { // Backtrack var prev = stack.pop(); if (stack.length > 0) { currentX = stack[stack.length - 1].x; currentY = stack[stack.length - 1].y; } } } // Add some random openings for better gameplay for (var y = 2; y < mazeHeight - 2; y += 2) { for (var x = 2; x < mazeWidth - 2; x += 2) { if (Math.random() < 0.15) { // Create random opening var openingDirs = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }]; var randomDir = openingDirs[Math.floor(Math.random() * openingDirs.length)]; var openX = x + randomDir.x; var openY = y + randomDir.y; if (openX > 0 && openX < mazeWidth - 1 && openY > 0 && openY < mazeHeight - 1) { mazeGrid[openY][openX] = 1; } } } } // Create visual maze from grid for (var y = 0; y < mazeHeight; y++) { for (var x = 0; x < mazeWidth; x++) { var cellType = mazeGrid[y][x] === 1 ? 'path' : 'wall'; var cell = new MazeCell(cellType); cell.x = x * cellSize + cellSize / 2; cell.y = y * cellSize + cellSize / 2; maze[y][x] = cell; mazeContainer.addChild(cell); } } // Place black hole exit placeBlackHole(); } function placeBlackHole() { // Find all path cells in the bottom areas of the maze var pathCells = []; // Start from bottom and work upward to find suitable path cells for (var y = mazeHeight - 2; y >= Math.max(1, mazeHeight - 6); y--) { for (var x = 1; x < mazeWidth - 1; x++) { if (maze[y] && maze[y][x] && maze[y][x].cellType === 'path') { // Count how many neighboring cells are paths var neighborCount = 0; var directions = [{ x: 0, y: -1 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 0 }]; for (var i = 0; i < directions.length; i++) { var nx = x + directions[i].x; var ny = y + directions[i].y; if (nx >= 0 && nx < mazeWidth && ny >= 0 && ny < mazeHeight && maze[ny] && maze[ny][nx] && maze[ny][nx].cellType === 'path') { neighborCount++; } } pathCells.push({ x: x, y: y, neighbors: neighborCount, priority: (mazeHeight - y) * 10 + (4 - neighborCount) // Prefer bottom cells with fewer neighbors }); } } } // If no path cells found in bottom area, expand search if (pathCells.length === 0) { for (var y = 1; y < mazeHeight - 1; y++) { for (var x = 1; x < mazeWidth - 1; x++) { if (maze[y] && maze[y][x] && maze[y][x].cellType === 'path') { pathCells.push({ x: x, y: y, neighbors: 1, priority: 1 }); } } } } // If still no path cells found, create one by forcing a path if (pathCells.length === 0) { // Find middle of bottom row and force it to be a path var bottomY = mazeHeight - 2; var middleX = Math.floor(mazeWidth / 2); if (maze[bottomY] && maze[bottomY][middleX]) { maze[bottomY][middleX].destroy(); var pathCell = new MazeCell('path'); pathCell.x = middleX * cellSize + cellSize / 2; pathCell.y = bottomY * cellSize + cellSize / 2; maze[bottomY][middleX] = pathCell; mazeContainer.addChild(pathCell); pathCells.push({ x: middleX, y: bottomY, neighbors: 1, priority: 100 }); } } if (pathCells.length > 0) { // Choose the path cell with highest priority (bottom-most with fewest neighbors) pathCells.sort(function (a, b) { return b.priority - a.priority; }); var bestCell = pathCells[0]; blackholeX = bestCell.x; blackholeY = bestCell.y; // Replace path with black hole if (maze[blackholeY] && maze[blackholeY][blackholeX]) { maze[blackholeY][blackholeX].destroy(); var blackhole = new MazeCell('blackhole'); blackhole.x = blackholeX * cellSize + cellSize / 2; blackhole.y = blackholeY * cellSize + cellSize / 2; maze[blackholeY][blackholeX] = blackhole; mazeContainer.addChild(blackhole); } } } function addBounceEffect() { // Add visual squash effect when bouncing tween.stop(ball, { scaleX: true, scaleY: true }); tween(ball, { scaleX: 1.3, scaleY: 0.7 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(ball, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.bounceOut }); } }); } function checkBallCollisions() { var ballMazeX = Math.floor((ball.x - mazeContainer.x) / cellSize); var ballMazeY = Math.floor((ball.y - mazeContainer.y) / cellSize); // Check if ball is trying to move outside maze boundaries if (ballMazeX < 0 || ballMazeX >= mazeWidth || ballMazeY < 0 || ballMazeY >= mazeHeight) { // Keep ball within maze bounds and bounce if (ball.x < mazeContainer.x + cellSize / 2) { ball.x = mazeContainer.x + cellSize / 2; ball.velocityX = Math.abs(ball.velocityX) * ball.bounceForce; } if (ball.x > mazeContainer.x + (mazeWidth - 1) * cellSize + cellSize / 2) { ball.x = mazeContainer.x + (mazeWidth - 1) * cellSize + cellSize / 2; ball.velocityX = -Math.abs(ball.velocityX) * ball.bounceForce; } if (ball.y < mazeContainer.y + cellSize / 2) { ball.y = mazeContainer.y + cellSize / 2; ball.velocityY = Math.abs(ball.velocityY) * ball.bounceForce; } if (ball.y > mazeContainer.y + (mazeHeight - 1) * cellSize + cellSize / 2) { ball.y = mazeContainer.y + (mazeHeight - 1) * cellSize + cellSize / 2; ball.velocityY = -Math.abs(ball.velocityY) * ball.bounceForce; } addBounceEffect(); LK.getSound('bounce').play(); return; } var currentCell = maze[ballMazeY][ballMazeX]; // Check if ball is in a wall cell - if so, push it back to nearest path if (currentCell && currentCell.cellType === 'wall') { // Find the nearest path cell var nearestPath = null; var minDistance = Infinity; for (var y = 0; y < mazeHeight; y++) { for (var x = 0; x < mazeWidth; x++) { if (maze[y] && maze[y][x] && (maze[y][x].cellType === 'path' || maze[y][x].cellType === 'blackhole')) { var pathCenterX = mazeContainer.x + x * cellSize + cellSize / 2; var pathCenterY = mazeContainer.y + y * cellSize + cellSize / 2; var distance = Math.sqrt(Math.pow(ball.x - pathCenterX, 2) + Math.pow(ball.y - pathCenterY, 2)); if (distance < minDistance) { minDistance = distance; nearestPath = { x: pathCenterX, y: pathCenterY }; } } } } if (nearestPath) { // Push ball to nearest path var directionX = nearestPath.x - ball.x; var directionY = nearestPath.y - ball.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); if (distance > 0) { directionX /= distance; directionY /= distance; ball.x = nearestPath.x - directionX * 10; ball.y = nearestPath.y - directionY * 10; } // Bounce off wall ball.velocityX = -ball.velocityX * ball.bounceForce; ball.velocityY = -ball.velocityY * ball.bounceForce; } addBounceEffect(); LK.getSound('bounce').play(); } else if (currentCell && currentCell.cellType === 'blackhole') { // Check if ball is close enough to black hole center var blackholeCenterX = mazeContainer.x + blackholeX * cellSize + cellSize / 2; var blackholeCenterY = mazeContainer.y + blackholeY * cellSize + cellSize / 2; var distance = Math.sqrt(Math.pow(ball.x - blackholeCenterX, 2) + Math.pow(ball.y - blackholeCenterY, 2)); if (distance < 30 && !gameWon) { gameWon = true; LK.getSound('win').play(); LK.setScore(LK.getScore() + 1); scoreText.setText('Level: ' + (LK.getScore() + 1)); // Flash effect LK.effects.flashScreen(0x00ff00, 1000); // Reset for next level LK.setTimeout(function () { resetLevel(); }, 1000); } } } function resetLevel() { gameWon = false; timeLeft = 60; // Reset ball position ball.x = mazeContainer.x + cellSize * 1.5; ball.y = mazeContainer.y + cellSize * 1.5; ball.velocityX = 0; ball.velocityY = 0; // Generate new maze generateMaze(); } // Initialize ball ball = game.addChild(new Ball()); ball.x = mazeContainer.x + cellSize * 1.5; ball.y = mazeContainer.y + cellSize * 1.5; // Touch controls game.down = function (x, y, obj) { if (gameWon) return; // Determine tap location and apply directional force var screenWidth = 2048; var tapX = x; var jumpForce = -15; // Negative for upward movement - increased for heavier ball var sideForce = 10; // Horizontal force for left/right bouncing - increased for heavier ball if (tapX < screenWidth / 3) { // Left tap - bounce left and up ball.addForce(-sideForce, jumpForce); } else if (tapX > screenWidth * 2 / 3) { // Right tap - bounce right and up ball.addForce(sideForce, jumpForce); } else { // Center tap - bounce straight up ball.addForce(0, jumpForce); } }; // Generate initial maze generateMaze(); // Timer countdown var timerInterval = LK.setInterval(function () { if (gameWon) return; timeLeft--; timerText.setText(timeLeft.toString()); if (timeLeft <= 0) { timeLeft = 60; generateMaze(); timerText.setText('60'); // Flash red to indicate maze change LK.effects.flashScreen(0xff0000, 500); } }, 1000); game.update = function () { // Game updates are handled by individual object update methods };
===================================================================
--- original.js
+++ change.js
@@ -13,12 +13,12 @@
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
- self.gravity = 0.5;
- self.friction = 0.98;
- self.bounceForce = 0.8;
- self.maxSpeed = 15;
+ self.gravity = 1.2;
+ self.friction = 0.95;
+ self.bounceForce = 0.6;
+ self.maxSpeed = 20;
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Apply friction
@@ -326,8 +326,31 @@
mazeContainer.addChild(blackhole);
}
}
}
+function addBounceEffect() {
+ // Add visual squash effect when bouncing
+ tween.stop(ball, {
+ scaleX: true,
+ scaleY: true
+ });
+ tween(ball, {
+ scaleX: 1.3,
+ scaleY: 0.7
+ }, {
+ duration: 150,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(ball, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.bounceOut
+ });
+ }
+ });
+}
function checkBallCollisions() {
var ballMazeX = Math.floor((ball.x - mazeContainer.x) / cellSize);
var ballMazeY = Math.floor((ball.y - mazeContainer.y) / cellSize);
// Check if ball is trying to move outside maze boundaries
@@ -348,8 +371,9 @@
if (ball.y > mazeContainer.y + (mazeHeight - 1) * cellSize + cellSize / 2) {
ball.y = mazeContainer.y + (mazeHeight - 1) * cellSize + cellSize / 2;
ball.velocityY = -Math.abs(ball.velocityY) * ball.bounceForce;
}
+ addBounceEffect();
LK.getSound('bounce').play();
return;
}
var currentCell = maze[ballMazeY][ballMazeX];
@@ -388,8 +412,9 @@
// Bounce off wall
ball.velocityX = -ball.velocityX * ball.bounceForce;
ball.velocityY = -ball.velocityY * ball.bounceForce;
}
+ addBounceEffect();
LK.getSound('bounce').play();
} else if (currentCell && currentCell.cellType === 'blackhole') {
// Check if ball is close enough to black hole center
var blackholeCenterX = mazeContainer.x + blackholeX * cellSize + cellSize / 2;
@@ -429,10 +454,10 @@
if (gameWon) return;
// Determine tap location and apply directional force
var screenWidth = 2048;
var tapX = x;
- var jumpForce = -12; // Negative for upward movement
- var sideForce = 8; // Horizontal force for left/right bouncing
+ var jumpForce = -15; // Negative for upward movement - increased for heavier ball
+ var sideForce = 10; // Horizontal force for left/right bouncing - increased for heavier ball
if (tapX < screenWidth / 3) {
// Left tap - bounce left and up
ball.addForce(-sideForce, jumpForce);
} else if (tapX > screenWidth * 2 / 3) {
lubang warp penuh warna. In-Game asset. 2d. High contrast. No shadows
warna pink dinding In-Game asset. 2d. High contrast. No shadows
bola penuh hitam. In-Game asset. 2d. High contrast. No shadows
malam bulan purnama diatas hutan dataran tinggi. di kejauhan nampak kota di malam hari. In-Game asset. 2d. High contrast. No shadows