User prompt
Top düşme sesi ekle
User prompt
Zeminden sürekli yeni toplar dogsun
User prompt
Oyun başlangıcında konteynerın yarısı topla dolu olsun
User prompt
Toplar durdukları yerde titriyor titremesinler
User prompt
Toplar durdukları yerde titriyor
User prompt
Oyun başlangıcta 5 sıra top dizilimiyle başlasın
User prompt
Top boyutlarını geri al
User prompt
Topları büyült
User prompt
Birleşme animasyonunu degiştir ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Birleşme animasyonunu farklı bir animasyonla degiştir ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Birleşme animasyonu ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Birleşme hassasiyeti arrtır
User prompt
Fizik kuralları çerçevesinde toplar birbirinin üzerinde yıgılabilir
User prompt
Her sıra için em fazla 12 top olabilir sıra dolduysa top diger topun üstünde durum devam eder
User prompt
Düzelt ozaöam
User prompt
Toplar birbirinin üzerinde durabilir
User prompt
Top birleşme sesi arttır
User prompt
Top birleşme sesi ekle
User prompt
Tehlike bölgesi varlıgını görünmez yap
User prompt
Oyın bitti alanı görünmez yap
User prompt
Tehlike alanı çizgisini görünmez yap
User prompt
Top birleşimleri hassaslaştır aynı numaralı toplar birbirine cok azda temas etse birleşsin
User prompt
Çözüm
User prompt
Topları biraz daha büyült
User prompt
Hepsini uygula
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function (value) { var self = Container.call(this); self.value = value || 2; self.velocityX = 0; self.velocityY = 0; self.gravity = 0.8; self.bounce = 0.4; self.friction = 0.98; self.radius = 60; self.isStatic = false; self.mergeTimer = 0; self.hasBeenMerged = false; var ballAsset = self.attachAsset('ball' + self.value, { anchorX: 0.5, anchorY: 0.5 }); var valueText = new Text2(self.value.toString(), { size: 42, fill: 0xFFFFFF }); valueText.anchor.set(0.5, 0.5); self.addChild(valueText); self.update = function () { if (self.hasBeenMerged) return; if (self.mergeTimer > 0) { self.mergeTimer--; return; } if (!self.isStatic) { // Apply gravity to velocity self.velocityY += self.gravity; // Store current position as backup var originalX = self.x; var originalY = self.y; // Calculate intended new position var intendedX = self.x + self.velocityX; var intendedY = self.y + self.velocityY; // Check boundary constraints first and adjust intended position var localWidth = gameAreaRight - gameAreaLeft; var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height // Wall collision checks with intended position if (intendedX - self.radius < 0) { intendedX = self.radius; self.velocityX *= -self.bounce; } if (intendedX + self.radius > localWidth) { intendedX = localWidth - self.radius; self.velocityX *= -self.bounce; } // Ground collision with intended position if (intendedY + self.radius > localBottom) { intendedY = localBottom - self.radius; self.velocityY *= -self.bounce; self.velocityX *= self.friction; if (Math.abs(self.velocityY) < 1) { self.velocityY = 0; self.isStatic = true; } } // Check for ball-to-ball collisions with intended position var canMoveSafely = true; for (var i = 0; i < balls.length; i++) { var otherBall = balls[i]; if (otherBall === self || otherBall.hasBeenMerged) continue; // Calculate distance at intended position var dx = otherBall.x - intendedX; var dy = otherBall.y - intendedY; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = self.radius + otherBall.radius; // Check if moving to intended position would cause overlap if (distance < minDistance) { // Check for merge first if (self.value === otherBall.value && self.mergeTimer === 0 && otherBall.mergeTimer === 0) { // Merge balls var newValue = self.value * 2; if (newValue <= 2048) { var newBall = new Ball(newValue); newBall.x = (self.x + otherBall.x) / 2; newBall.y = (self.y + otherBall.y) / 2; newBall.velocityX = (self.velocityX + otherBall.velocityX) / 2; newBall.velocityY = (self.velocityY + otherBall.velocityY) / 2; newBall.mergeTimer = 10; balls.push(newBall); gameArea.addChild(newBall); // Mark for removal self.hasBeenMerged = true; otherBall.hasBeenMerged = true; LK.getSound('merge').play(); LK.setScore(LK.getScore() + newValue); scoreText.setText(LK.getScore()); // Check win condition if (newValue === 2048) { LK.showYouWin(); } return; } } // Collision will occur, prevent movement and apply collision response canMoveSafely = false; // Calculate collision normal var normalX = dx / distance; var normalY = dy / distance; // Calculate relative velocity var relativeVelX = self.velocityX - otherBall.velocityX; var relativeVelY = self.velocityY - otherBall.velocityY; // Calculate collision speed along normal var speed = relativeVelX * normalX + relativeVelY * normalY; // Only resolve if objects are moving towards each other if (speed > 0) { // Calculate collision impulse var impulse = 2 * speed / 2; // Assume equal mass var impulseX = impulse * normalX * 0.8; // Add damping factor var impulseY = impulse * normalY * 0.8; // Apply impulse self.velocityX -= impulseX; self.velocityY -= impulseY; otherBall.velocityX += impulseX; otherBall.velocityY += impulseY; // Apply friction self.velocityX *= self.friction; self.velocityY *= self.friction; otherBall.velocityX *= otherBall.friction; otherBall.velocityY *= otherBall.friction; } // If balls are currently overlapping, separate them var currentDx = otherBall.x - self.x; var currentDy = otherBall.y - self.y; var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy); if (currentDistance < minDistance && currentDistance > 0) { var overlap = minDistance - currentDistance; var separationX = currentDx / currentDistance * overlap * 0.6; var separationY = currentDy / currentDistance * overlap * 0.6; self.x -= separationX; self.y -= separationY; otherBall.x += separationX; otherBall.y += separationY; // Ensure balls stay within bounds after separation self.x = Math.max(self.radius, Math.min(localWidth - self.radius, self.x)); self.y = Math.max(self.radius, Math.min(localBottom - self.radius, self.y)); otherBall.x = Math.max(otherBall.radius, Math.min(localWidth - otherBall.radius, otherBall.x)); otherBall.y = Math.max(otherBall.radius, Math.min(localBottom - otherBall.radius, otherBall.y)); } break; // Stop checking other balls for this frame } } // Only update position if it's safe to do so if (canMoveSafely) { self.x = intendedX; self.y = intendedY; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x34495e }); /**** * Game Code ****/ var balls = []; var nextBallValue = 2; var gameAreaLeft = 224; var gameAreaRight = 1824; var gameAreaTop = 400; var gameAreaBottom = 2600; var dropCooldown = 0; var gameAreaHeight = gameAreaBottom - gameAreaTop; // Create game area background var gameAreaBg = game.addChild(LK.getAsset('gameArea', { anchorX: 0.5, anchorY: 0, x: 1024, y: gameAreaTop })); // Create game area container for balls var gameArea = new Container(); gameArea.x = gameAreaLeft; gameArea.y = gameAreaTop; game.addChild(gameArea); // Create visible walls var leftWall = game.addChild(LK.getAsset('leftWall', { anchorX: 1, anchorY: 0, x: gameAreaLeft, y: gameAreaTop })); var rightWall = game.addChild(LK.getAsset('rightWall', { anchorX: 0, anchorY: 0, x: gameAreaRight, y: gameAreaTop })); var bottomWall = game.addChild(LK.getAsset('bottomWall', { anchorX: 0.5, anchorY: 0, x: 1024, y: gameAreaBottom })); // Create danger zone indicator var dangerZone = game.addChild(LK.getAsset('dangerZone', { anchorX: 0.5, anchorY: 0, x: 1024, y: gameAreaTop, alpha: 0.3 })); // Create game over line var gameOverLine = game.addChild(LK.getAsset('gameOverLine', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: gameAreaTop + 100 })); // Create score display var scoreText = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); scoreText.y = 100; // Create next ball preview var nextBallPreview = LK.getAsset('ball' + nextBallValue, { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 300, scaleX: 0.75, scaleY: 0.75 }); game.addChild(nextBallPreview); // Create next ball value text var nextBallText = new Text2(nextBallValue.toString(), { size: 24, fill: 0xFFFFFF }); nextBallText.anchor.set(0.5, 0.5); nextBallText.x = 1024; nextBallText.y = 300; game.addChild(nextBallText); // Create instruction text var instructionText = new Text2('Tap to drop ball', { size: 40, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0); instructionText.x = 1024; instructionText.y = 150; game.addChild(instructionText); function getRandomNextBallValue() { var values = [2, 4, 8]; return values[Math.floor(Math.random() * values.length)]; } function updateNextBallPreview() { game.removeChild(nextBallPreview); game.removeChild(nextBallText); nextBallPreview = LK.getAsset('ball' + nextBallValue, { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 300, scaleX: 0.75, scaleY: 0.75 }); game.addChild(nextBallPreview); nextBallText = new Text2(nextBallValue.toString(), { size: 24, fill: 0xFFFFFF }); nextBallText.anchor.set(0.5, 0.5); nextBallText.x = 1024; nextBallText.y = 300; game.addChild(nextBallText); } function checkGameOver() { for (var i = 0; i < balls.length; i++) { // Check if ball touches the danger zone (first 100 pixels of game area) // Since balls are in gameArea container, we use local coordinates // Only trigger game over if ball is static (not actively falling) and in danger zone if (balls[i].y - balls[i].radius <= 100 && balls[i].isStatic) { LK.showGameOver(); return; } } } function cleanupMergedBalls() { for (var i = balls.length - 1; i >= 0; i--) { if (balls[i].hasBeenMerged) { gameArea.removeChild(balls[i]); balls[i].destroy(); balls.splice(i, 1); } } } game.down = function (x, y, obj) { if (dropCooldown > 0) return; // Constrain drop position to game area (convert to local coordinates) var localWidth = gameAreaRight - gameAreaLeft; var localX = x - gameAreaLeft; var dropX = Math.max(60, Math.min(localWidth - 60, localX)); var newBall = new Ball(nextBallValue); newBall.x = dropX; newBall.y = 170; // Start below the danger zone (100px) plus ball radius (60px) plus buffer newBall.velocityX = 0; newBall.velocityY = 0; balls.push(newBall); gameArea.addChild(newBall); LK.getSound('drop').play(); // Update next ball nextBallValue = getRandomNextBallValue(); updateNextBallPreview(); dropCooldown = 30; // 0.5 seconds at 60fps }; game.update = function () { if (dropCooldown > 0) { dropCooldown--; } // Multi-pass collision resolution to handle complex scenarios for (var pass = 0; pass < 3; pass++) { var hasCollisions = false; for (var i = 0; i < balls.length; i++) { var ball1 = balls[i]; if (ball1.hasBeenMerged) continue; for (var j = i + 1; j < balls.length; j++) { var ball2 = balls[j]; if (ball2.hasBeenMerged) continue; var dx = ball2.x - ball1.x; var dy = ball2.y - ball1.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = ball1.radius + ball2.radius; // If balls are overlapping, separate them if (distance < minDistance && distance > 0) { hasCollisions = true; var overlap = minDistance - distance; var separationX = dx / distance * overlap * 0.5; var separationY = dy / distance * overlap * 0.5; // Only separate if balls are not in merge process if (ball1.mergeTimer === 0 && ball2.mergeTimer === 0) { ball1.x -= separationX; ball1.y -= separationY; ball2.x += separationX; ball2.y += separationY; // Ensure balls stay within bounds var localWidth = gameAreaRight - gameAreaLeft; var localBottom = gameAreaHeight - 20; ball1.x = Math.max(ball1.radius, Math.min(localWidth - ball1.radius, ball1.x)); ball1.y = Math.max(ball1.radius, Math.min(localBottom - ball1.radius, ball1.y)); ball2.x = Math.max(ball2.radius, Math.min(localWidth - ball2.radius, ball2.x)); ball2.y = Math.max(ball2.radius, Math.min(localBottom - ball2.radius, ball2.y)); // Dampen velocities to prevent oscillation ball1.velocityX *= 0.9; ball1.velocityY *= 0.9; ball2.velocityX *= 0.9; ball2.velocityY *= 0.9; } } } } // If no collisions detected in this pass, we can stop early if (!hasCollisions) break; } cleanupMergedBalls(); checkGameOver(); // Update score display scoreText.setText(LK.getScore()); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function (value) {
var self = Container.call(this);
self.value = value || 2;
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.8;
self.bounce = 0.4;
self.friction = 0.98;
self.radius = 60;
self.isStatic = false;
self.mergeTimer = 0;
self.hasBeenMerged = false;
var ballAsset = self.attachAsset('ball' + self.value, {
anchorX: 0.5,
anchorY: 0.5
});
var valueText = new Text2(self.value.toString(), {
size: 42,
fill: 0xFFFFFF
});
valueText.anchor.set(0.5, 0.5);
self.addChild(valueText);
self.update = function () {
if (self.hasBeenMerged) return;
if (self.mergeTimer > 0) {
self.mergeTimer--;
return;
}
if (!self.isStatic) {
// Apply gravity to velocity
self.velocityY += self.gravity;
// Store current position as backup
var originalX = self.x;
var originalY = self.y;
// Calculate intended new position
var intendedX = self.x + self.velocityX;
var intendedY = self.y + self.velocityY;
// Check boundary constraints first and adjust intended position
var localWidth = gameAreaRight - gameAreaLeft;
var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height
// Wall collision checks with intended position
if (intendedX - self.radius < 0) {
intendedX = self.radius;
self.velocityX *= -self.bounce;
}
if (intendedX + self.radius > localWidth) {
intendedX = localWidth - self.radius;
self.velocityX *= -self.bounce;
}
// Ground collision with intended position
if (intendedY + self.radius > localBottom) {
intendedY = localBottom - self.radius;
self.velocityY *= -self.bounce;
self.velocityX *= self.friction;
if (Math.abs(self.velocityY) < 1) {
self.velocityY = 0;
self.isStatic = true;
}
}
// Check for ball-to-ball collisions with intended position
var canMoveSafely = true;
for (var i = 0; i < balls.length; i++) {
var otherBall = balls[i];
if (otherBall === self || otherBall.hasBeenMerged) continue;
// Calculate distance at intended position
var dx = otherBall.x - intendedX;
var dy = otherBall.y - intendedY;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = self.radius + otherBall.radius;
// Check if moving to intended position would cause overlap
if (distance < minDistance) {
// Check for merge first
if (self.value === otherBall.value && self.mergeTimer === 0 && otherBall.mergeTimer === 0) {
// Merge balls
var newValue = self.value * 2;
if (newValue <= 2048) {
var newBall = new Ball(newValue);
newBall.x = (self.x + otherBall.x) / 2;
newBall.y = (self.y + otherBall.y) / 2;
newBall.velocityX = (self.velocityX + otherBall.velocityX) / 2;
newBall.velocityY = (self.velocityY + otherBall.velocityY) / 2;
newBall.mergeTimer = 10;
balls.push(newBall);
gameArea.addChild(newBall);
// Mark for removal
self.hasBeenMerged = true;
otherBall.hasBeenMerged = true;
LK.getSound('merge').play();
LK.setScore(LK.getScore() + newValue);
scoreText.setText(LK.getScore());
// Check win condition
if (newValue === 2048) {
LK.showYouWin();
}
return;
}
}
// Collision will occur, prevent movement and apply collision response
canMoveSafely = false;
// Calculate collision normal
var normalX = dx / distance;
var normalY = dy / distance;
// Calculate relative velocity
var relativeVelX = self.velocityX - otherBall.velocityX;
var relativeVelY = self.velocityY - otherBall.velocityY;
// Calculate collision speed along normal
var speed = relativeVelX * normalX + relativeVelY * normalY;
// Only resolve if objects are moving towards each other
if (speed > 0) {
// Calculate collision impulse
var impulse = 2 * speed / 2; // Assume equal mass
var impulseX = impulse * normalX * 0.8; // Add damping factor
var impulseY = impulse * normalY * 0.8;
// Apply impulse
self.velocityX -= impulseX;
self.velocityY -= impulseY;
otherBall.velocityX += impulseX;
otherBall.velocityY += impulseY;
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
otherBall.velocityX *= otherBall.friction;
otherBall.velocityY *= otherBall.friction;
}
// If balls are currently overlapping, separate them
var currentDx = otherBall.x - self.x;
var currentDy = otherBall.y - self.y;
var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
if (currentDistance < minDistance && currentDistance > 0) {
var overlap = minDistance - currentDistance;
var separationX = currentDx / currentDistance * overlap * 0.6;
var separationY = currentDy / currentDistance * overlap * 0.6;
self.x -= separationX;
self.y -= separationY;
otherBall.x += separationX;
otherBall.y += separationY;
// Ensure balls stay within bounds after separation
self.x = Math.max(self.radius, Math.min(localWidth - self.radius, self.x));
self.y = Math.max(self.radius, Math.min(localBottom - self.radius, self.y));
otherBall.x = Math.max(otherBall.radius, Math.min(localWidth - otherBall.radius, otherBall.x));
otherBall.y = Math.max(otherBall.radius, Math.min(localBottom - otherBall.radius, otherBall.y));
}
break; // Stop checking other balls for this frame
}
}
// Only update position if it's safe to do so
if (canMoveSafely) {
self.x = intendedX;
self.y = intendedY;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
var balls = [];
var nextBallValue = 2;
var gameAreaLeft = 224;
var gameAreaRight = 1824;
var gameAreaTop = 400;
var gameAreaBottom = 2600;
var dropCooldown = 0;
var gameAreaHeight = gameAreaBottom - gameAreaTop;
// Create game area background
var gameAreaBg = game.addChild(LK.getAsset('gameArea', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: gameAreaTop
}));
// Create game area container for balls
var gameArea = new Container();
gameArea.x = gameAreaLeft;
gameArea.y = gameAreaTop;
game.addChild(gameArea);
// Create visible walls
var leftWall = game.addChild(LK.getAsset('leftWall', {
anchorX: 1,
anchorY: 0,
x: gameAreaLeft,
y: gameAreaTop
}));
var rightWall = game.addChild(LK.getAsset('rightWall', {
anchorX: 0,
anchorY: 0,
x: gameAreaRight,
y: gameAreaTop
}));
var bottomWall = game.addChild(LK.getAsset('bottomWall', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: gameAreaBottom
}));
// Create danger zone indicator
var dangerZone = game.addChild(LK.getAsset('dangerZone', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: gameAreaTop,
alpha: 0.3
}));
// Create game over line
var gameOverLine = game.addChild(LK.getAsset('gameOverLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: gameAreaTop + 100
}));
// Create score display
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
// Create next ball preview
var nextBallPreview = LK.getAsset('ball' + nextBallValue, {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 300,
scaleX: 0.75,
scaleY: 0.75
});
game.addChild(nextBallPreview);
// Create next ball value text
var nextBallText = new Text2(nextBallValue.toString(), {
size: 24,
fill: 0xFFFFFF
});
nextBallText.anchor.set(0.5, 0.5);
nextBallText.x = 1024;
nextBallText.y = 300;
game.addChild(nextBallText);
// Create instruction text
var instructionText = new Text2('Tap to drop ball', {
size: 40,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
instructionText.x = 1024;
instructionText.y = 150;
game.addChild(instructionText);
function getRandomNextBallValue() {
var values = [2, 4, 8];
return values[Math.floor(Math.random() * values.length)];
}
function updateNextBallPreview() {
game.removeChild(nextBallPreview);
game.removeChild(nextBallText);
nextBallPreview = LK.getAsset('ball' + nextBallValue, {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 300,
scaleX: 0.75,
scaleY: 0.75
});
game.addChild(nextBallPreview);
nextBallText = new Text2(nextBallValue.toString(), {
size: 24,
fill: 0xFFFFFF
});
nextBallText.anchor.set(0.5, 0.5);
nextBallText.x = 1024;
nextBallText.y = 300;
game.addChild(nextBallText);
}
function checkGameOver() {
for (var i = 0; i < balls.length; i++) {
// Check if ball touches the danger zone (first 100 pixels of game area)
// Since balls are in gameArea container, we use local coordinates
// Only trigger game over if ball is static (not actively falling) and in danger zone
if (balls[i].y - balls[i].radius <= 100 && balls[i].isStatic) {
LK.showGameOver();
return;
}
}
}
function cleanupMergedBalls() {
for (var i = balls.length - 1; i >= 0; i--) {
if (balls[i].hasBeenMerged) {
gameArea.removeChild(balls[i]);
balls[i].destroy();
balls.splice(i, 1);
}
}
}
game.down = function (x, y, obj) {
if (dropCooldown > 0) return;
// Constrain drop position to game area (convert to local coordinates)
var localWidth = gameAreaRight - gameAreaLeft;
var localX = x - gameAreaLeft;
var dropX = Math.max(60, Math.min(localWidth - 60, localX));
var newBall = new Ball(nextBallValue);
newBall.x = dropX;
newBall.y = 170; // Start below the danger zone (100px) plus ball radius (60px) plus buffer
newBall.velocityX = 0;
newBall.velocityY = 0;
balls.push(newBall);
gameArea.addChild(newBall);
LK.getSound('drop').play();
// Update next ball
nextBallValue = getRandomNextBallValue();
updateNextBallPreview();
dropCooldown = 30; // 0.5 seconds at 60fps
};
game.update = function () {
if (dropCooldown > 0) {
dropCooldown--;
}
// Multi-pass collision resolution to handle complex scenarios
for (var pass = 0; pass < 3; pass++) {
var hasCollisions = false;
for (var i = 0; i < balls.length; i++) {
var ball1 = balls[i];
if (ball1.hasBeenMerged) continue;
for (var j = i + 1; j < balls.length; j++) {
var ball2 = balls[j];
if (ball2.hasBeenMerged) continue;
var dx = ball2.x - ball1.x;
var dy = ball2.y - ball1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = ball1.radius + ball2.radius;
// If balls are overlapping, separate them
if (distance < minDistance && distance > 0) {
hasCollisions = true;
var overlap = minDistance - distance;
var separationX = dx / distance * overlap * 0.5;
var separationY = dy / distance * overlap * 0.5;
// Only separate if balls are not in merge process
if (ball1.mergeTimer === 0 && ball2.mergeTimer === 0) {
ball1.x -= separationX;
ball1.y -= separationY;
ball2.x += separationX;
ball2.y += separationY;
// Ensure balls stay within bounds
var localWidth = gameAreaRight - gameAreaLeft;
var localBottom = gameAreaHeight - 20;
ball1.x = Math.max(ball1.radius, Math.min(localWidth - ball1.radius, ball1.x));
ball1.y = Math.max(ball1.radius, Math.min(localBottom - ball1.radius, ball1.y));
ball2.x = Math.max(ball2.radius, Math.min(localWidth - ball2.radius, ball2.x));
ball2.y = Math.max(ball2.radius, Math.min(localBottom - ball2.radius, ball2.y));
// Dampen velocities to prevent oscillation
ball1.velocityX *= 0.9;
ball1.velocityY *= 0.9;
ball2.velocityX *= 0.9;
ball2.velocityY *= 0.9;
}
}
}
}
// If no collisions detected in this pass, we can stop early
if (!hasCollisions) break;
}
cleanupMergedBalls();
checkGameOver();
// Update score display
scoreText.setText(LK.getScore());
};
Koyu yeşil bilye. In-Game asset. 2d. High contrast. No shadows
Kahverengi bilye. In-Game asset. 2d. High contrast. No shadows
Bprdo renk bilye. In-Game asset. 2d. High contrast. No shadows
Açık kahve bilye. In-Game asset. 2d. High contrast. No shadows
Gri bilye. In-Game asset. 2d. High contrast. No shadows