User prompt
remove the comment line shake button script. We need to see this button It need to work shown on the screenuฬ โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a button to lower screen. It shake the bottle left and right to better feeling โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
when colliders inside eacouther. Make a better push each other. Better powerful push. Reduce gravity to prevent shaking
User prompt
fix hold and drop system
User prompt
fix gravity move shaking. Fix left mouse click hold system. When hold its need to drop and drop and drop drop drop drop โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
improve collider fruits become inside and inside eachothers. + When I hold left mouse click it drop next and next fuirt like machine gun. โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
1) fix colliders. when merge happend it need to push other fruits like explode 2) add particles when merge 3) when I hold left click drop and drop even I release + I can click to drop 4) fix gravity. Its shaking when stacking 2 or 3 fruit up and up โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
1) dropped furit dont reackt the counter. After 3 second countdown start for that new fruit. 2) fix hitbox colliders sometimes fruits going inside eachothers
User prompt
The bigger dropable fruit is fruit_grape. Next fruit is visible on right top corner.
User prompt
the countdown count every second. 3 (1 sec later) 2 .....
User prompt
its insta gameover now. Check the code and fix that
User prompt
fix the game over state. Add 3 2 1 countdown
User prompt
current fruit follow the mose on x axis. when I click the left mouse button it must drop on the glass
User prompt
okay do like that. Add a line to furit. This line indicate the fruits drop spot
Code edit (1 edits merged)
Please save this source code
User prompt
Suika Merge Fruits
Initial prompt
make me a suika game clon
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Fruit class var Fruit = Container.expand(function () { var self = Container.call(this); // Properties self.fruitType = 0; // index in FRUIT_LIST self.radius = 60; // default, will be set below self.vx = 0; self.vy = 0; self.isDropping = false; // true if falling, false if held at top self.isMerging = false; // true if currently merging (to avoid double merges) self.lastMergedTick = -1; // to prevent double merges in one tick // Attach fruit asset self.setType = function (typeIdx) { self.fruitType = typeIdx; if (self.fruitAsset) { self.removeChild(self.fruitAsset); } var fruitId = FRUIT_LIST[typeIdx].id; self.fruitAsset = self.attachAsset(fruitId, { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.fruitAsset.width / 2; }; // Set initial type self.setType(0); // Set position self.setPosition = function (x, y) { self.x = x; self.y = y; }; // Physics update self.update = function () { if (!self.isDropping) return; // Gravity self.vy += 1.2; // gravity // Clamp vy if (self.vy > 40) self.vy = 40; // Move self.x += self.vx; self.y += self.vy; // Wall collision if (self.x - self.radius < containerLeftX + wallThickness) { self.x = containerLeftX + wallThickness + self.radius; self.vx *= -0.5; } if (self.x + self.radius > containerRightX - wallThickness) { self.x = containerRightX - wallThickness - self.radius; self.vx *= -0.5; } // Floor collision if (self.y + self.radius > containerBottomY) { self.y = containerBottomY - self.radius; if (Math.abs(self.vy) > 2) { self.vy *= -0.45; } else { self.vy = 0; } // Friction self.vx *= 0.98; if (Math.abs(self.vx) < 0.1) self.vx = 0; } }; // Merge animation self.playMergeAnim = function () { tween(self, { scaleX: 1.25, scaleY: 1.25 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); }; // Destroy self.destroyFruit = function () { if (self.parent) self.parent.removeChild(self); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222233 }); /**** * Game Code ****/ /**** * Fruit Progression Data ****/ // Container (the bin) // We'll use colored ellipses for each fruit, with increasing size and distinct colors. // Fruit progression: cherry โ strawberry โ grape โ dekopon โ orange โ apple โ pear โ peach โ pineapple โ melon โ watermelon // Container dimensions var FRUIT_LIST = [{ id: 'fruit_cherry', name: 'Cherry', score: 1 }, { id: 'fruit_strawberry', name: 'Strawberry', score: 2 }, { id: 'fruit_grape', name: 'Grape', score: 4 }, { id: 'fruit_dekopon', name: 'Dekopon', score: 8 }, { id: 'fruit_orange', name: 'Orange', score: 16 }, { id: 'fruit_apple', name: 'Apple', score: 32 }, { id: 'fruit_pear', name: 'Pear', score: 64 }, { id: 'fruit_peach', name: 'Peach', score: 128 }, { id: 'fruit_pineapple', name: 'Pineapple', score: 256 }, { id: 'fruit_melon', name: 'Melon', score: 512 }, { id: 'fruit_watermelon', name: 'Watermelon', score: 1024 }]; var containerWidth = 1200; var containerHeight = 1600; var wallThickness = 40; var containerLeftX = (2048 - containerWidth) / 2; var containerRightX = containerLeftX + containerWidth; var containerTopY = 400; var containerBottomY = containerTopY + containerHeight; // Draw container var containerBody = LK.getAsset('container_body', { anchorX: 0, anchorY: 0, x: containerLeftX, y: containerTopY }); game.addChild(containerBody); var leftWall = LK.getAsset('container_wall', { anchorX: 0, anchorY: 0, x: containerLeftX, y: containerTopY }); game.addChild(leftWall); var rightWall = LK.getAsset('container_wall', { anchorX: 0, anchorY: 0, x: containerRightX - wallThickness, y: containerTopY }); game.addChild(rightWall); // Fruits array var fruits = []; // Score var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Next fruit preview var nextFruitType = 0; var nextFruitAsset = LK.getAsset(FRUIT_LIST[nextFruitType].id, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: containerTopY - 120 }); game.addChild(nextFruitAsset); // Drop spot indicator line var dropLine = LK.getAsset('container_wall', { anchorX: 0.5, anchorY: 0, width: 8, height: containerHeight + 60, color: 0xffffff, x: 2048 / 2, y: containerTopY - 30 }); dropLine.alpha = 0.5; game.addChild(dropLine); // Current dropping fruit var currentFruit = null; // Helper: get random fruit type (first 5 types for balance) function getRandomFruitType() { return Math.floor(Math.random() * 5); } // Helper: spawn new fruit at top function spawnFruit() { var typeIdx = nextFruitType; currentFruit = new Fruit(); currentFruit.setType(typeIdx); currentFruit.setPosition(2048 / 2, containerTopY - 80); currentFruit.isDropping = false; currentFruit.vx = 0; currentFruit.vy = 0; currentFruit.scaleX = 1; currentFruit.scaleY = 1; game.addChild(currentFruit); // Move dropLine to center for new fruit if (dropLine) dropLine.x = 2048 / 2; // Next fruit nextFruitType = getRandomFruitType(); if (nextFruitAsset && nextFruitAsset.parent) nextFruitAsset.parent.removeChild(nextFruitAsset); nextFruitAsset = LK.getAsset(FRUIT_LIST[nextFruitType].id, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: containerTopY - 120 }); game.addChild(nextFruitAsset); } // Helper: check collision between two fruits function fruitsCollide(f1, f2) { var dx = f1.x - f2.x; var dy = f1.y - f2.y; var dist = Math.sqrt(dx * dx + dy * dy); return dist < (f1.radius + f2.radius) * 0.98; } // Helper: resolve collision between two fruits (physics bounce) function resolveFruitCollision(f1, f2) { var dx = f1.x - f2.x; var dy = f1.y - f2.y; var dist = Math.sqrt(dx * dx + dy * dy); var minDist = f1.radius + f2.radius; if (dist < minDist && dist > 0.1) { var overlap = minDist - dist; var nx = dx / dist; var ny = dy / dist; // Push fruits apart f1.x += nx * overlap / 2; f1.y += ny * overlap / 2; f2.x -= nx * overlap / 2; f2.y -= ny * overlap / 2; // Exchange velocity (simple elastic) var k = 0.7; var tx = nx; var ty = ny; var dp = (f1.vx - f2.vx) * tx + (f1.vy - f2.vy) * ty; if (dp < 0) { f1.vx -= dp * tx * k; f1.vy -= dp * ty * k; f2.vx += dp * tx * k; f2.vy += dp * ty * k; } } } // Helper: merge two fruits (returns new fruit or null) function tryMergeFruits(f1, f2, tick) { if (f1.isMerging || f2.isMerging) return null; if (f1.fruitType !== f2.fruitType) return null; if (f1.fruitType >= FRUIT_LIST.length - 1) return null; // Prevent double merge in one tick if (f1.lastMergedTick === tick || f2.lastMergedTick === tick) return null; // Mark as merging f1.isMerging = true; f2.isMerging = true; f1.lastMergedTick = tick; f2.lastMergedTick = tick; // New fruit at average position var newFruit = new Fruit(); newFruit.setType(f1.fruitType + 1); newFruit.setPosition((f1.x + f2.x) / 2, (f1.y + f2.y) / 2); newFruit.vx = (f1.vx + f2.vx) / 2; newFruit.vy = (f1.vy + f2.vy) / 2 - 8; // bounce up a bit newFruit.isDropping = true; newFruit.scaleX = 0.7; newFruit.scaleY = 0.7; game.addChild(newFruit); // Merge animation newFruit.playMergeAnim(); // Remove old fruits f1.destroyFruit(); f2.destroyFruit(); // Remove from fruits array for (var i = fruits.length - 1; i >= 0; i--) { if (fruits[i] === f1 || fruits[i] === f2) fruits.splice(i, 1); } fruits.push(newFruit); // Add score score += FRUIT_LIST[newFruit.fruitType].score; scoreTxt.setText(score); return newFruit; } // Helper: check for game over (if any fruit is above containerTopY) with 3-2-1 countdown var gameOverCounter = 0; var gameOverCountdownActive = false; var countdownText = null; function checkGameOver() { var anyAbove = false; for (var i = 0; i < fruits.length; i++) { if (fruits[i].y - fruits[i].radius < containerTopY + 10) { anyAbove = true; break; } } if (anyAbove) { gameOverCounter++; if (!gameOverCountdownActive) { // Show countdown text if (!countdownText) { countdownText = new Text2('3', { size: 220, fill: 0xFF3333 }); countdownText.anchor.set(0.5, 0.5); LK.gui.center.addChild(countdownText); } countdownText.visible = true; countdownText.setText(String(4 - gameOverCounter)); gameOverCountdownActive = true; } else if (countdownText) { countdownText.setText(String(4 - gameOverCounter)); } if (gameOverCounter === 1 && countdownText) { countdownText.setText("3"); } if (gameOverCounter === 2 && countdownText) { countdownText.setText("2"); } if (gameOverCounter === 3 && countdownText) { countdownText.setText("1"); } if (gameOverCounter >= 3) { if (countdownText) { countdownText.setText("0"); } LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { if (countdownText) { countdownText.visible = false; } LK.showGameOver(); }, 400); return true; } } else { gameOverCounter = 0; gameOverCountdownActive = false; if (countdownText) { countdownText.visible = false; } } return false; } // Drag and drop for current fruit var isDragging = false; var dragOffsetX = 0; // Only allow drop inside container function clampFruitX(x, fruit) { var minX = containerLeftX + wallThickness + fruit.radius; var maxX = containerRightX - wallThickness - fruit.radius; if (x < minX) x = minX; if (x > maxX) x = maxX; return x; } // Touch/mouse down: start drag if on current fruit game.down = function (x, y, obj) { if (!currentFruit || currentFruit.isDropping) return; // Drop the fruit immediately on any down event currentFruit.isDropping = true; currentFruit.vx = 0; currentFruit.vy = 0; fruits.push(currentFruit); // Hide dropLine while fruit is falling if (dropLine) dropLine.visible = false; currentFruit = null; // Spawn next fruit after short delay LK.setTimeout(function () { if (dropLine) dropLine.visible = true; spawnFruit(); }, 300); }; // Touch/mouse move: drag fruit horizontally game.move = function (x, y, obj) { if (!currentFruit || currentFruit.isDropping) return; // If dragging, keep old drag logic if (isDragging) { var nx = clampFruitX(x + dragOffsetX, currentFruit); currentFruit.x = nx; if (dropLine) dropLine.x = nx; } else { // Not dragging: always follow mouse/touch X axis var nx = clampFruitX(x, currentFruit); currentFruit.x = nx; if (dropLine) dropLine.x = nx; } }; // Touch/mouse up: drop fruit game.up = function (x, y, obj) { if (!currentFruit || currentFruit.isDropping) return; if (isDragging) { isDragging = false; currentFruit.isDropping = true; currentFruit.vx = 0; currentFruit.vy = 0; fruits.push(currentFruit); // Hide dropLine while fruit is falling if (dropLine) dropLine.visible = false; currentFruit = null; // Spawn next fruit after short delay LK.setTimeout(function () { if (dropLine) dropLine.visible = true; if (dropLine) dropLine.visible = true; spawnFruit(); }, 300); } }; // Main update loop game.update = function () { // Update all fruits for (var i = 0; i < fruits.length; i++) { fruits[i].update(); } // Fruit-to-fruit collision and merging var tick = LK.ticks; for (var i = 0; i < fruits.length; i++) { var f1 = fruits[i]; if (!f1.isDropping) continue; for (var j = i + 1; j < fruits.length; j++) { var f2 = fruits[j]; if (!f2.isDropping) continue; if (fruitsCollide(f1, f2)) { // Try merge var merged = tryMergeFruits(f1, f2, tick); if (merged) break; // f1 is gone, break inner loop // Else, resolve collision resolveFruitCollision(f1, f2); } } } // Check for game over checkGameOver(); }; // Start game score = 0; scoreTxt.setText(score); fruits = []; gameOverCounter = 0; gameOverCountdownActive = false; if (typeof countdownText !== "undefined" && countdownText && countdownText.parent) { countdownText.visible = false; } if (nextFruitAsset && nextFruitAsset.parent) nextFruitAsset.parent.removeChild(nextFruitAsset); nextFruitType = getRandomFruitType(); nextFruitAsset = LK.getAsset(FRUIT_LIST[nextFruitType].id, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: containerTopY - 120 }); game.addChild(nextFruitAsset); spawnFruit();
===================================================================
--- original.js
+++ change.js
@@ -319,16 +319,66 @@
score += FRUIT_LIST[newFruit.fruitType].score;
scoreTxt.setText(score);
return newFruit;
}
-// Helper: check for game over (if any fruit is above containerTopY)
+// Helper: check for game over (if any fruit is above containerTopY) with 3-2-1 countdown
+var gameOverCounter = 0;
+var gameOverCountdownActive = false;
+var countdownText = null;
function checkGameOver() {
+ var anyAbove = false;
for (var i = 0; i < fruits.length; i++) {
if (fruits[i].y - fruits[i].radius < containerTopY + 10) {
+ anyAbove = true;
+ break;
+ }
+ }
+ if (anyAbove) {
+ gameOverCounter++;
+ if (!gameOverCountdownActive) {
+ // Show countdown text
+ if (!countdownText) {
+ countdownText = new Text2('3', {
+ size: 220,
+ fill: 0xFF3333
+ });
+ countdownText.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(countdownText);
+ }
+ countdownText.visible = true;
+ countdownText.setText(String(4 - gameOverCounter));
+ gameOverCountdownActive = true;
+ } else if (countdownText) {
+ countdownText.setText(String(4 - gameOverCounter));
+ }
+ if (gameOverCounter === 1 && countdownText) {
+ countdownText.setText("3");
+ }
+ if (gameOverCounter === 2 && countdownText) {
+ countdownText.setText("2");
+ }
+ if (gameOverCounter === 3 && countdownText) {
+ countdownText.setText("1");
+ }
+ if (gameOverCounter >= 3) {
+ if (countdownText) {
+ countdownText.setText("0");
+ }
LK.effects.flashScreen(0xff0000, 1000);
- LK.showGameOver();
+ LK.setTimeout(function () {
+ if (countdownText) {
+ countdownText.visible = false;
+ }
+ LK.showGameOver();
+ }, 400);
return true;
}
+ } else {
+ gameOverCounter = 0;
+ gameOverCountdownActive = false;
+ if (countdownText) {
+ countdownText.visible = false;
+ }
}
return false;
}
// Drag and drop for current fruit
@@ -423,8 +473,13 @@
// Start game
score = 0;
scoreTxt.setText(score);
fruits = [];
+gameOverCounter = 0;
+gameOverCountdownActive = false;
+if (typeof countdownText !== "undefined" && countdownText && countdownText.parent) {
+ countdownText.visible = false;
+}
if (nextFruitAsset && nextFruitAsset.parent) nextFruitAsset.parent.removeChild(nextFruitAsset);
nextFruitType = getRandomFruitType();
nextFruitAsset = LK.getAsset(FRUIT_LIST[nextFruitType].id, {
anchorX: 0.5,