User prompt
Please arrange the fruits so that they are not crushed and cannot pass under the container border below.
User prompt
No, it's not like that. There should be fruits under the container for informational purposes to tell who will transform into whom in order, but these have nothing to do with the game, they are for visual purposes. Please bring the game back to its old state.
User prompt
I think the fruit pictures should be side by side at the bottom of the container.
User prompt
Awesome But container should be lower
User prompt
It would be better if the container was thinner, since we can add more fruits when the space is large. And game be so easy
User prompt
great but can you add a container border to the floor so it doesn't overflow from the bottom
User prompt
The fruits are intertwined, can you please adjust the collapse event well?
User prompt
It is very difficult to go up because the fruits on top of each other crush each other, so the game does not end, it would be better if they did not crush each other
User prompt
sometimes it gives game over error at wrong times, I think you should write the game over part again
User prompt
There is a bug in the game. When the fruits hit each other, they do not move to the next fruit.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var gamePos = game.toLocal(obj.parent.toGlobal(obj.position));' Line Number: 309
Code edit (1 edits merged)
Please save this source code
User prompt
Merge Fruits
Initial prompt
Hi, please make me a suika game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Fruit = Container.expand(function (type, x, y) {
var self = Container.call(this);
self.type = type;
self.settled = false;
self.mergeProcessed = false;
var fruitTypes = ['cherry', 'strawberry', 'grape', 'orange', 'apple', 'pear', 'peach', 'pineapple', 'melon', 'watermelon'];
var fruitSizes = [80, 100, 120, 140, 160, 180, 200, 220, 240, 280];
var fruitScores = [10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120];
self.typeIndex = fruitTypes.indexOf(type);
self.size = fruitSizes[self.typeIndex];
self.scoreValue = fruitScores[self.typeIndex];
var fruitGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.vx = 0;
self.vy = 0;
self.radius = self.size / 2;
self.canMergeWith = function (otherFruit) {
return !self.mergeProcessed && !otherFruit.mergeProcessed && self.type === otherFruit.type && self.typeIndex < 9;
};
self.getNextType = function () {
if (self.typeIndex < 9) {
return fruitTypes[self.typeIndex + 1];
}
return null;
};
self.update = function () {
if (!self.settled) {
self.vy += gravity;
self.x += self.vx;
self.y += self.vy;
// Container bounds collision
if (self.x - self.radius <= containerLeft) {
self.x = containerLeft + self.radius;
self.vx = -self.vx * friction;
}
if (self.x + self.radius >= containerRight) {
self.x = containerRight - self.radius;
self.vx = -self.vx * friction;
}
// Bottom collision
if (self.y + self.radius >= containerBottom) {
self.y = containerBottom - self.radius;
self.vy = 0;
self.vx *= groundFriction;
if (Math.abs(self.vx) < 0.5) {
self.vx = 0;
self.settled = true;
}
}
// Collision with other fruits
for (var i = 0; i < fruits.length; i++) {
var otherFruit = fruits[i];
if (otherFruit !== self) {
var dx = self.x - otherFruit.x;
var dy = self.y - otherFruit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = self.radius + otherFruit.radius;
if (distance < minDistance) {
// Handle overlapping/intertwined fruits more gracefully
if (distance < 0.1) {
// Fruits are nearly on top of each other - gentle separation
distance = 0.1;
dx = Math.random() * 2 - 1; // Random direction
dy = Math.random() * 2 - 1;
var len = Math.sqrt(dx * dx + dy * dy);
dx /= len;
dy /= len;
}
var overlap = minDistance - distance;
var normalX = dx / distance;
var normalY = dy / distance;
// Very gentle position correction for intertwined fruits
var correctionFactor = Math.min(0.1, overlap * 0.05); // Even gentler correction
var selfCorrection = correctionFactor;
var otherCorrection = correctionFactor;
// If other fruit is settled, don't move it as much
if (otherFruit.settled) {
selfCorrection = correctionFactor * 1.5;
otherCorrection = correctionFactor * 0.3;
}
self.x += normalX * overlap * selfCorrection;
self.y += normalY * overlap * selfCorrection;
otherFruit.x -= normalX * overlap * otherCorrection;
otherFruit.y -= normalY * overlap * otherCorrection;
// Dampen velocities when fruits are intertwined
var relativeVx = self.vx - otherFruit.vx;
var relativeVy = self.vy - otherFruit.vy;
var speed = relativeVx * normalX + relativeVy * normalY;
if (speed < 0) continue;
// Much reduced velocity response for stability
speed *= restitution * 0.1; // Even less bounce
var impulseX = speed * normalX * 0.3;
var impulseY = speed * normalY * 0.3;
self.vx -= impulseX;
self.vy -= impulseY;
otherFruit.vx += impulseX * 0.5; // Less impact on other fruit
otherFruit.vy += impulseY * 0.5;
// Aggressive damping for intertwined fruits
if (overlap > 10) {
// Significantly overlapping
self.vx *= 0.7;
self.vy *= 0.7;
otherFruit.vx *= 0.7;
otherFruit.vy *= 0.7;
}
}
}
}
// Stronger damping for more stability
self.vx *= 0.95;
self.vy *= 0.95;
// More generous settling conditions
if (Math.abs(self.vx) < 0.5 && Math.abs(self.vy) < 0.5) {
// Check if touching ground or another settled fruit
var touchingGround = self.y + self.radius >= containerBottom - 10;
var touchingSettledFruit = false;
for (var k = 0; k < fruits.length; k++) {
var otherFruit = fruits[k];
if (otherFruit !== self && otherFruit.settled) {
var dx = self.x - otherFruit.x;
var dy = self.y - otherFruit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var touchDistance = self.radius + otherFruit.radius + 5; // Small tolerance
if (distance <= touchDistance) {
touchingSettledFruit = true;
break;
}
}
}
if (touchingGround || touchingSettledFruit) {
self.settled = true;
self.vx = 0;
self.vy = 0;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game constants - reduced for more stable physics
var gravity = 0.4; // Even more reduced gravity
var friction = 0.9; // Higher friction
var groundFriction = 0.98; // Even higher ground friction
var restitution = 0.15; // Much lower bounce for stability
// Container setup
var containerWidth = 1600;
var containerHeight = 1200;
var containerX = (2048 - containerWidth) / 2;
var containerY = 1532 - containerHeight;
var containerLeft = containerX + 20;
var containerRight = containerX + containerWidth - 20;
var containerBottom = containerY + containerHeight - 20;
var overflowLine = containerY + 200;
// Game state
var fruits = [];
var nextFruitType = 'cherry';
var dropPosition = 1024;
var canDrop = true;
var gameActive = true;
// Fruit types for random generation
var initialFruitTypes = ['cherry', 'strawberry', 'grape', 'orange'];
// Create container
var container = game.addChild(LK.getAsset('container', {
anchorX: 0,
anchorY: 0,
x: containerX,
y: containerY
}));
// Create container borders
var leftBorder = game.addChild(LK.getAsset('containerBorder', {
anchorX: 0,
anchorY: 0,
x: containerX,
y: containerY
}));
var rightBorder = game.addChild(LK.getAsset('containerBorder', {
anchorX: 0,
anchorY: 0,
x: containerX + containerWidth - 20,
y: containerY
}));
// Create overflow line
var overflowLineGraphics = game.addChild(LK.getAsset('dropLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: overflowLine,
alpha: 0.5
}));
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var nextFruitTxt = new Text2('Next: Cherry', {
size: 60,
fill: 0xFFFFFF
});
nextFruitTxt.anchor.set(0, 0);
nextFruitTxt.x = 50;
nextFruitTxt.y = 150;
LK.gui.topLeft.addChild(nextFruitTxt);
// Preview fruit
var previewFruit = game.addChild(LK.getAsset(nextFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropPosition,
y: containerY - 100,
alpha: 0.7
}));
function getRandomInitialFruit() {
return initialFruitTypes[Math.floor(Math.random() * initialFruitTypes.length)];
}
function updatePreview() {
game.removeChild(previewFruit);
previewFruit = game.addChild(LK.getAsset(nextFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropPosition,
y: containerY - 100,
alpha: 0.7
}));
var capitalizedType = nextFruitType.charAt(0).toUpperCase() + nextFruitType.slice(1);
nextFruitTxt.setText('Next: ' + capitalizedType);
}
function dropFruit() {
if (!canDrop || !gameActive) return;
var newFruit = new Fruit(nextFruitType, dropPosition, containerY - 50);
fruits.push(newFruit);
game.addChild(newFruit);
LK.getSound('drop').play();
nextFruitType = getRandomInitialFruit();
updatePreview();
canDrop = false;
LK.setTimeout(function () {
canDrop = true;
}, 500);
}
function checkMerges() {
var fruitsToRemove = [];
var newFruitsToAdd = [];
for (var i = 0; i < fruits.length; i++) {
if (fruitsToRemove.indexOf(i) !== -1) continue;
for (var j = i + 1; j < fruits.length; j++) {
if (fruitsToRemove.indexOf(j) !== -1) continue;
var fruit1 = fruits[i];
var fruit2 = fruits[j];
if (fruit1.canMergeWith(fruit2)) {
var dx = fruit1.x - fruit2.x;
var dy = fruit1.y - fruit2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// More generous merge distance for intertwined fruits
var mergeDistance = (fruit1.radius + fruit2.radius) * 1.1; // 10% more generous
// Also allow merge if fruits are heavily overlapping (intertwined)
var isOverlapping = distance < (fruit1.radius + fruit2.radius) * 0.8;
if (distance <= mergeDistance || isOverlapping) {
var newType = fruit1.getNextType();
if (newType) {
var mergeX = (fruit1.x + fruit2.x) / 2;
var mergeY = (fruit1.y + fruit2.y) / 2;
var newFruit = new Fruit(newType, mergeX, mergeY);
// Give merged fruit slight upward velocity to help separate from pile
newFruit.vy = -2;
newFruitsToAdd.push(newFruit);
var scoreIncrease = newFruit.scoreValue;
LK.setScore(LK.getScore() + scoreIncrease);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('merge').play();
LK.effects.flashObject(newFruit, 0xffff00, 500);
}
fruitsToRemove.push(i);
fruitsToRemove.push(j);
fruit1.mergeProcessed = true;
fruit2.mergeProcessed = true;
break;
}
}
}
}
// Remove merged fruits (in reverse order to maintain indices)
fruitsToRemove.sort(function (a, b) {
return b - a;
});
for (var k = 0; k < fruitsToRemove.length; k++) {
var index = fruitsToRemove[k];
var fruitToRemove = fruits[index];
game.removeChild(fruitToRemove);
fruits.splice(index, 1);
}
// Add new merged fruits
for (var m = 0; m < newFruitsToAdd.length; m++) {
fruits.push(newFruitsToAdd[m]);
game.addChild(newFruitsToAdd[m]);
}
}
function checkGameOver() {
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
// Only trigger game over if fruit is settled/stable and clearly above overflow line
if (fruit.settled && fruit.y - fruit.radius < overflowLine - 20) {
gameActive = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
break;
}
}
}
// Game controls
game.down = function (x, y, obj) {
if (!gameActive) return;
dropPosition = Math.max(containerLeft + 50, Math.min(containerRight - 50, x));
previewFruit.x = dropPosition;
};
game.move = function (x, y, obj) {
if (!gameActive) return;
dropPosition = Math.max(containerLeft + 50, Math.min(containerRight - 50, x));
previewFruit.x = dropPosition;
};
game.up = function (x, y, obj) {
if (!gameActive) return;
dropFruit();
};
// Main game loop
game.update = function () {
if (!gameActive) return;
// Update all fruits
for (var i = 0; i < fruits.length; i++) {
fruits[i].update();
}
// Check for merges every few frames
if (LK.ticks % 3 === 0) {
checkMerges();
}
// Check game over condition
if (LK.ticks % 30 === 0) {
checkGameOver();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -66,38 +66,55 @@
var dx = self.x - otherFruit.x;
var dy = self.y - otherFruit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = self.radius + otherFruit.radius;
- if (distance < minDistance && distance > 0) {
- // Gentler collision response - reduce overlap correction
+ if (distance < minDistance) {
+ // Handle overlapping/intertwined fruits more gracefully
+ if (distance < 0.1) {
+ // Fruits are nearly on top of each other - gentle separation
+ distance = 0.1;
+ dx = Math.random() * 2 - 1; // Random direction
+ dy = Math.random() * 2 - 1;
+ var len = Math.sqrt(dx * dx + dy * dy);
+ dx /= len;
+ dy /= len;
+ }
var overlap = minDistance - distance;
var normalX = dx / distance;
var normalY = dy / distance;
- // Reduce position correction to prevent excessive pushing
- var correctionFactor = 0.2; // Much gentler than 0.5
- self.x += normalX * overlap * correctionFactor;
- self.y += normalY * overlap * correctionFactor;
- otherFruit.x -= normalX * overlap * correctionFactor;
- otherFruit.y -= normalY * overlap * correctionFactor;
- // Much gentler velocity response
+ // Very gentle position correction for intertwined fruits
+ var correctionFactor = Math.min(0.1, overlap * 0.05); // Even gentler correction
+ var selfCorrection = correctionFactor;
+ var otherCorrection = correctionFactor;
+ // If other fruit is settled, don't move it as much
+ if (otherFruit.settled) {
+ selfCorrection = correctionFactor * 1.5;
+ otherCorrection = correctionFactor * 0.3;
+ }
+ self.x += normalX * overlap * selfCorrection;
+ self.y += normalY * overlap * selfCorrection;
+ otherFruit.x -= normalX * overlap * otherCorrection;
+ otherFruit.y -= normalY * overlap * otherCorrection;
+ // Dampen velocities when fruits are intertwined
var relativeVx = self.vx - otherFruit.vx;
var relativeVy = self.vy - otherFruit.vy;
var speed = relativeVx * normalX + relativeVy * normalY;
if (speed < 0) continue;
- // Reduce restitution for more stable stacking
- speed *= restitution * 0.3;
- var impulseX = speed * normalX;
- var impulseY = speed * normalY;
- self.vx -= impulseX * 0.5;
- self.vy -= impulseY * 0.5;
- otherFruit.vx += impulseX * 0.5;
+ // Much reduced velocity response for stability
+ speed *= restitution * 0.1; // Even less bounce
+ var impulseX = speed * normalX * 0.3;
+ var impulseY = speed * normalY * 0.3;
+ self.vx -= impulseX;
+ self.vy -= impulseY;
+ otherFruit.vx += impulseX * 0.5; // Less impact on other fruit
otherFruit.vy += impulseY * 0.5;
- // If both fruits are moving very slowly, make them settle
- if (Math.abs(self.vx) < 1 && Math.abs(self.vy) < 1 && Math.abs(otherFruit.vx) < 1 && Math.abs(otherFruit.vy) < 1) {
- self.vx *= 0.5;
- self.vy *= 0.5;
- otherFruit.vx *= 0.5;
- otherFruit.vy *= 0.5;
+ // Aggressive damping for intertwined fruits
+ if (overlap > 10) {
+ // Significantly overlapping
+ self.vx *= 0.7;
+ self.vy *= 0.7;
+ otherFruit.vx *= 0.7;
+ otherFruit.vy *= 0.7;
}
}
}
}
@@ -143,12 +160,12 @@
/****
* Game Code
****/
// Game constants - reduced for more stable physics
-var gravity = 0.6; // Reduced gravity
-var friction = 0.8; // Increased friction
-var groundFriction = 0.95; // Higher ground friction
-var restitution = 0.3; // Much lower bounce
+var gravity = 0.4; // Even more reduced gravity
+var friction = 0.9; // Higher friction
+var groundFriction = 0.98; // Even higher ground friction
+var restitution = 0.15; // Much lower bounce for stability
// Container setup
var containerWidth = 1600;
var containerHeight = 1200;
var containerX = (2048 - containerWidth) / 2;
@@ -256,15 +273,20 @@
if (fruit1.canMergeWith(fruit2)) {
var dx = fruit1.x - fruit2.x;
var dy = fruit1.y - fruit2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
- var touchDistance = fruit1.radius + fruit2.radius;
- if (distance <= touchDistance) {
+ // More generous merge distance for intertwined fruits
+ var mergeDistance = (fruit1.radius + fruit2.radius) * 1.1; // 10% more generous
+ // Also allow merge if fruits are heavily overlapping (intertwined)
+ var isOverlapping = distance < (fruit1.radius + fruit2.radius) * 0.8;
+ if (distance <= mergeDistance || isOverlapping) {
var newType = fruit1.getNextType();
if (newType) {
var mergeX = (fruit1.x + fruit2.x) / 2;
var mergeY = (fruit1.y + fruit2.y) / 2;
var newFruit = new Fruit(newType, mergeX, mergeY);
+ // Give merged fruit slight upward velocity to help separate from pile
+ newFruit.vy = -2;
newFruitsToAdd.push(newFruit);
var scoreIncrease = newFruit.scoreValue;
LK.setScore(LK.getScore() + scoreIncrease);
scoreTxt.setText('Score: ' + LK.getScore());
Shiney Apple vecor. In-Game asset. 2d. High contrast. No shadows
Shiney Chery vector. In-Game asset. 2d. High contrast. No shadows
Shiney grape vector. In-Game asset. 2d. High contrast. No shadows
Shiney melon vector. In-Game asset. 2d. High contrast. No shadows
Shiney yellow melon vector. In-Game asset. 2d. High contrast. No shadows
Shiney orange fruit vector. In-Game asset. 2d. High contrast. No shadows
Shiney peach vector. In-Game asset. 2d. High contrast. No shadows
Shiney pear vector. In-Game asset. 2d. High contrast. No shadows
Shiney pineapple vector. In-Game asset. 2d. High contrast. No shadows
Shiney strawberry vector. In-Game asset. 2d. High contrast. No shadows
a background full of greenery and some flowers. In-Game asset. 3d. Realistic