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; } // Apply physics only if not static if (!self.isStatic) { // Store previous position for continuous collision detection var prevX = self.x; var prevY = self.y; // Apply gravity self.velocityY += self.gravity; // Calculate intended new position var newX = self.x + self.velocityX; var newY = self.y + self.velocityY; // Continuous collision detection - check path from current to intended position var stepCount = Math.max(1, Math.ceil(Math.abs(self.velocityX) + Math.abs(self.velocityY)) / (self.radius * 0.5)); var stepX = (newX - self.x) / stepCount; var stepY = (newY - self.y) / stepCount; var collisionOccurred = false; // Check each step along the movement path for (var step = 1; step <= stepCount && !collisionOccurred; step++) { var testX = self.x + stepX * step; var testY = self.y + stepY * step; // Test collision with other balls for (var i = 0; i < balls.length; i++) { var otherBall = balls[i]; if (otherBall === self || otherBall.hasBeenMerged || otherBall.mergeTimer > 0) continue; var dx = otherBall.x - testX; var dy = otherBall.y - testY; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = self.radius + otherBall.radius; if (distance < minDistance) { // Collision detected - stop at safe position var safeDistance = minDistance + 2; // Add small buffer if (distance > 0) { var normalX = dx / distance; var normalY = dy / distance; self.x = otherBall.x - normalX * safeDistance; self.y = otherBall.y - normalY * safeDistance; // Check for merge first if (self.value === otherBall.value && self.mergeTimer === 0 && otherBall.mergeTimer === 0) { 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 response - calculate new velocities var relativeVelX = self.velocityX - otherBall.velocityX; var relativeVelY = self.velocityY - otherBall.velocityY; var relativeSpeed = relativeVelX * normalX + relativeVelY * normalY; if (relativeSpeed > 0) { var impulse = relativeSpeed * 0.9; // Damping factor self.velocityX -= impulse * normalX; self.velocityY -= impulse * normalY; otherBall.velocityX += impulse * normalX; otherBall.velocityY += impulse * normalY; // Apply friction self.velocityX *= self.friction; self.velocityY *= self.friction; otherBall.velocityX *= otherBall.friction; otherBall.velocityY *= otherBall.friction; } } collisionOccurred = true; break; } } } // If no collision occurred, move to intended position if (!collisionOccurred) { self.x = newX; self.y = newY; } // Boundary collisions after position update var localWidth = gameAreaRight - gameAreaLeft; var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height // Ground collision if (self.y + self.radius > localBottom) { self.y = localBottom - self.radius; self.velocityY *= -self.bounce; self.velocityX *= self.friction; if (Math.abs(self.velocityY) < 1) { self.velocityY = 0; self.isStatic = true; } } // Side walls collision if (self.x - self.radius < 0) { self.x = self.radius; self.velocityX *= -self.bounce; } if (self.x + self.radius > localWidth) { self.x = localWidth - self.radius; self.velocityX *= -self.bounce; } } // Secondary separation pass to handle any remaining overlaps for (var i = 0; i < balls.length; i++) { var otherBall = balls[i]; if (otherBall === self || otherBall.hasBeenMerged) continue; var dx = otherBall.x - self.x; var dy = otherBall.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = self.radius + otherBall.radius; if (distance < minDistance && distance > 0) { var overlap = minDistance - distance; var normalX = dx / distance; var normalY = dy / distance; var separationX = normalX * overlap * 0.51; // Slightly more than half var separationY = normalY * overlap * 0.51; self.x -= separationX; self.y -= separationY; // Ensure balls stay within bounds after separation var localWidth = gameAreaRight - gameAreaLeft; var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height 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)); } } }; 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--; } cleanupMergedBalls(); checkGameOver(); // Update score display scoreText.setText(LK.getScore()); };
===================================================================
--- original.js
+++ change.js
@@ -13,9 +13,9 @@
self.velocityY = 0;
self.gravity = 0.8;
self.bounce = 0.4;
self.friction = 0.98;
- self.radius = 75;
+ self.radius = 60;
self.isStatic = false;
self.mergeTimer = 0;
self.hasBeenMerged = false;
var ballAsset = self.attachAsset('ball' + self.value, {
@@ -33,14 +33,99 @@
if (self.mergeTimer > 0) {
self.mergeTimer--;
return;
}
+ // Apply physics only if not static
if (!self.isStatic) {
+ // Store previous position for continuous collision detection
+ var prevX = self.x;
+ var prevY = self.y;
+ // Apply gravity
self.velocityY += self.gravity;
- self.x += self.velocityX;
- self.y += self.velocityY;
- // Ground collision (local coordinates) - account for bottom wall thickness
+ // Calculate intended new position
+ var newX = self.x + self.velocityX;
+ var newY = self.y + self.velocityY;
+ // Continuous collision detection - check path from current to intended position
+ var stepCount = Math.max(1, Math.ceil(Math.abs(self.velocityX) + Math.abs(self.velocityY)) / (self.radius * 0.5));
+ var stepX = (newX - self.x) / stepCount;
+ var stepY = (newY - self.y) / stepCount;
+ var collisionOccurred = false;
+ // Check each step along the movement path
+ for (var step = 1; step <= stepCount && !collisionOccurred; step++) {
+ var testX = self.x + stepX * step;
+ var testY = self.y + stepY * step;
+ // Test collision with other balls
+ for (var i = 0; i < balls.length; i++) {
+ var otherBall = balls[i];
+ if (otherBall === self || otherBall.hasBeenMerged || otherBall.mergeTimer > 0) continue;
+ var dx = otherBall.x - testX;
+ var dy = otherBall.y - testY;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var minDistance = self.radius + otherBall.radius;
+ if (distance < minDistance) {
+ // Collision detected - stop at safe position
+ var safeDistance = minDistance + 2; // Add small buffer
+ if (distance > 0) {
+ var normalX = dx / distance;
+ var normalY = dy / distance;
+ self.x = otherBall.x - normalX * safeDistance;
+ self.y = otherBall.y - normalY * safeDistance;
+ // Check for merge first
+ if (self.value === otherBall.value && self.mergeTimer === 0 && otherBall.mergeTimer === 0) {
+ 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 response - calculate new velocities
+ var relativeVelX = self.velocityX - otherBall.velocityX;
+ var relativeVelY = self.velocityY - otherBall.velocityY;
+ var relativeSpeed = relativeVelX * normalX + relativeVelY * normalY;
+ if (relativeSpeed > 0) {
+ var impulse = relativeSpeed * 0.9; // Damping factor
+ self.velocityX -= impulse * normalX;
+ self.velocityY -= impulse * normalY;
+ otherBall.velocityX += impulse * normalX;
+ otherBall.velocityY += impulse * normalY;
+ // Apply friction
+ self.velocityX *= self.friction;
+ self.velocityY *= self.friction;
+ otherBall.velocityX *= otherBall.friction;
+ otherBall.velocityY *= otherBall.friction;
+ }
+ }
+ collisionOccurred = true;
+ break;
+ }
+ }
+ }
+ // If no collision occurred, move to intended position
+ if (!collisionOccurred) {
+ self.x = newX;
+ self.y = newY;
+ }
+ // Boundary collisions after position update
+ var localWidth = gameAreaRight - gameAreaLeft;
var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height
+ // Ground collision
if (self.y + self.radius > localBottom) {
self.y = localBottom - self.radius;
self.velocityY *= -self.bounce;
self.velocityX *= self.friction;
@@ -48,115 +133,39 @@
self.velocityY = 0;
self.isStatic = true;
}
}
- // Side walls collision (local coordinates)
- var localWidth = gameAreaRight - gameAreaLeft;
+ // Side walls collision
if (self.x - self.radius < 0) {
self.x = self.radius;
self.velocityX *= -self.bounce;
}
if (self.x + self.radius > localWidth) {
self.x = localWidth - self.radius;
self.velocityX *= -self.bounce;
}
- // Predictive collision detection - check future positions to prevent overlap
- for (var i = 0; i < balls.length; i++) {
- var otherBall = balls[i];
- if (otherBall === self || otherBall.hasBeenMerged) continue;
- // Current positions and distances
- var currentDx = otherBall.x - self.x;
- var currentDy = otherBall.y - self.y;
- var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
- var minDistance = self.radius + otherBall.radius;
- // Predict future positions after velocity is applied
- var futureX = self.x + self.velocityX;
- var futureY = self.y + self.velocityY;
- var otherFutureX = otherBall.x + otherBall.velocityX;
- var otherFutureY = otherBall.y + otherBall.velocityY;
- // Calculate future distance
- var futureDx = otherFutureX - futureX;
- var futureDy = otherFutureY - futureY;
- var futureDistance = Math.sqrt(futureDx * futureDx + futureDy * futureDy);
- // If balls will collide in the next frame, handle collision now
- var willCollide = futureDistance < minDistance;
- var isCurrentlyTouching = currentDistance <= minDistance;
- if (willCollide || isCurrentlyTouching) {
- // Use current position for collision calculations if already touching, future otherwise
- var dx = isCurrentlyTouching ? currentDx : futureDx;
- var dy = isCurrentlyTouching ? currentDy : futureDy;
- var distance = isCurrentlyTouching ? currentDistance : futureDistance;
- if (distance > 0) {
- // 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;
- }
- }
- // Predictive collision response - adjust velocities to prevent overlap
- 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 to prevent collision
- 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 already overlapping, separate them immediately
- if (isCurrentlyTouching && distance < minDistance) {
- var overlap = minDistance - distance;
- var separationX = normalX * overlap * 0.5;
- var separationY = normalY * overlap * 0.5;
- self.x -= separationX;
- self.y -= separationY;
- otherBall.x += separationX;
- otherBall.y += separationY;
- // Ensure balls stay within bounds after separation
- var localWidth = gameAreaRight - gameAreaLeft;
- var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height
- 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));
- }
- }
- }
+ }
+ // Secondary separation pass to handle any remaining overlaps
+ for (var i = 0; i < balls.length; i++) {
+ var otherBall = balls[i];
+ if (otherBall === self || otherBall.hasBeenMerged) continue;
+ var dx = otherBall.x - self.x;
+ var dy = otherBall.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var minDistance = self.radius + otherBall.radius;
+ if (distance < minDistance && distance > 0) {
+ var overlap = minDistance - distance;
+ var normalX = dx / distance;
+ var normalY = dy / distance;
+ var separationX = normalX * overlap * 0.51; // Slightly more than half
+ var separationY = normalY * overlap * 0.51;
+ self.x -= separationX;
+ self.y -= separationY;
+ // Ensure balls stay within bounds after separation
+ var localWidth = gameAreaRight - gameAreaLeft;
+ var localBottom = gameAreaHeight - 20; // gameAreaHeight minus bottom wall height
+ 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));
}
}
};
return self;
@@ -311,12 +320,12 @@
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(75, Math.min(localWidth - 75, localX));
+ var dropX = Math.max(60, Math.min(localWidth - 60, localX));
var newBall = new Ball(nextBallValue);
newBall.x = dropX;
- newBall.y = 185; // Start below the danger zone (100px) plus ball radius (75px) plus buffer
+ 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);
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