Concept
Suika Game is a popular Japanese puzzle game where players combine fruits of the same type to create larger and more complex fruit combinations. The goal is to strategically merge and stack the fruits to fill the board, aiming to reach the largest possible fruit before the space runs out.
For this assignment I decided to recreate the games using matter.js to create a simple interactive physics-based game.
Highlight I’m proud of
Matter.js powers the physics simulation, providing gravity, collisions, and interactions between objects.
const { Engine, World, Bodies, Composite } = Matter; let engine, world; // Create an engine and world engine = Engine.create(); world = engine.world;
When balls of the same size collide, they merge into a larger ball, and the score increases.
// Scoring values for each size index const scoreValues = [0, 2, 5, 7, 12, 15, 20, 25, 35, 50]; // Handle collisions to merge balls of the same size, update the score, and mark balls as "old" after any collision function handleCollisions(event) { if (gameOver) return; // Ignore collisions if the game is over const pairs = event.pairs; for (let pair of pairs) { let ballA = droppedBalls.find(b => b.body === pair.bodyA); let ballB = droppedBalls.find(b => b.body === pair.bodyB); if (ballA && ballB) { // Mark both balls as "old" since they've collided ballA.hasCollided = true; ballB.hasCollided = true; // Check if they are of the same size and can merge if (ballA.size === ballB.size) { const nextSizeIndex = ballA.body.sizeIndex + 1; if (nextSizeIndex < ballSizes.length) { const newSize = ballSizes[nextSizeIndex]; const newColor = colors[nextSizeIndex]; // Create a new merged ball at the midpoint of the two colliding balls const midX = (ballA.body.position.x + ballB.body.position.x) / 2; const midY = (ballA.body.position.y + ballB.body.position.y) / 2; const mergedBall = Bodies.circle(midX, midY, newSize, { restitution: 0.8 }); mergedBall.size = newSize; mergedBall.color = newColor; mergedBall.sizeIndex = nextSizeIndex; mergedBall.hasCollided = true; // Mark new merged ball as "old" Composite.add(world, mergedBall); droppedBalls.push({ body: mergedBall, size: newSize, color: newColor, hasCollided: true }); // Update the score based on the size of the merged ball score += scoreValues[nextSizeIndex]; // Play merge sound mergeSound.play(); // Remove the original balls from the world and array Composite.remove(world, ballA.body); Composite.remove(world, ballB.body); droppedBalls = droppedBalls.filter(b => b !== ballA && b !== ballB); } } } } }
Players click on the screen to drop a ball, and a preview ball appears under the mouse.
let previewBall = { size: 30, color: '#FF6347' }; // Drop the preview ball when mouse is clicked function mousePressed() { if (!gameOver) { dropBall(mouseX, previewBall.size, previewBall.color); } } function dropBall(x, size, color) { const ball = Bodies.circle(x, 0, size, { restitution: 0.4 }); ball.size = size; ball.color = color; Composite.add(world, ball); droppedBalls.push(ball); }
Embedded sketch
Edit Sketch: https://editor.p5js.org/mariamalkhoori/sketches/CaVEWClQZb
Reflection and ideas for future work or improvements
-I really wanted to make this more visually appealing, and I even got to draw some shapes for the game. However, it was quite difficult to detect the edges and make them fall properly, as well as assign the size alongside the merging.
-Adding a Start page and highest score system.
References
- https://suikagame.com/
- https://www.youtube.com/watch?v=zTNuMUsO-1g&ab_channel=Caleb%27sCodingCorner
- https://pixabay.com/sound-effects/search/silly/
- https://git.tombo.sh/tom/suika-game/src/branch/main/index.html