Introduction
During an internship in an igaming service-based company, I developed the frontend for a lot of crash games and Arcade Casino games. One of the first games I built was Plinko.
I learnt a lot of things during the development period of that game, which I am going to share with you in this post.
So, Let's begin.
Our goal
Our goal is to build Plinko, an Arcade Casino Game using HTML Canvas and React.
What is Plinko?
Plinko is a game of chance in which a ball or puck is dropped from the top of a vertical board filled with pegs. As the ball falls, it randomly bounces left or right at each peg until it lands in one of several slots at the bottom, each associated with a different prize or payout.
Plinko working mechanism
The player drops a ball from the top, and it collides with obstacles positioned as a Pascal triangle; then it reaches the bottom level, where it collides with one of the multiplier blocks with multiplier X.
The player won betAmount * X money.
We cannot randomly drop a ball from any X position from top because casinos need a fixed RTP (Return to Player). To achieve that fixed RTP, we need to control the ball so it collides with a predetermined multiplier block.
How to control the ball?
The answer is simple. We map the initial x position, or you can say the dropping x position of the ball, to the multiplier blocks by running a lot of simulation.
In the simulation, we drop a ball from random x position from the top, track it to see which multiplier block it is going to collide with, and we repeat it for 5-10 thousand times until we map every multiplier block.
export const map = [
{
canvasWidth: 800,
canvasHeight: 600,
rows: 16,
records: {
0: [
{ initialX: 362.0786996500253, initialY: 30, multiplier: 1000},],
1: [
{ initialX: 357.44116222657084, initialY: 30, multiplier: 130},],
2: [
{ initialX: 351.58243647873775, initialY: 30, multiplier: 26},],
}
}
]
Plinko Physic
We are going to use the following physics concept :
- Collision
- Gravity
- Friction
Collision
If the ball collides with an obstacle, it will bounce off. There are two steps in this collision detection and bounce-back physics.
Collision detection physic
const dx = ball.x - obstacle.x;
const dy = ball.y - obstacle.y;
const distance = Math.hypot(dx, dy);
if (distance < ball.radius + obstacle.radius) {
// Collision
}
Bounce back physic
const angle = Math.atan2(dy, dx);
const speed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy);
ball.vx = Math.cos(angle) * speed * horizontalFriction;
ball.vy = Math.sin(angle) * speed * verticalFriction;
Gravity
We add gravity only for the ball not for obstacles, obstacles should be fixed.
const gravity = 0.3;
ball.vy = ball.vy + gravity;
Friction
As you already noticed, we used horizontal and vertical friction in bounce-back physics. Friction is crucial physics for this game because if we do not add friction, the ball will never loses it energy and it will eventually bounce off the canvas.
const horizontalFriction = 0.4;
const verticalFriction = 0.8;
Development
I divided the whole game into two parts: Game Panel and Betting Panel
Game Panel has the HTML Canvas element, and the Betting Panel controls the bet.
<gameContext.Provider value={{ ...values }}>
<GamePanel />
<BettingPanel />
</gameContext.Provider>
Context API is used to share state between components, and a custom-made EventEmitter is used to trigger events and share data.
eventEmitter.emit("ballDropEnd", {});
eventEmitter.emit("ballDropStart", {});
eventEmitter.emit("ballObstacleCollision", {
x: obstacle.x,
y: obstacle.y,
});
and more events...
Conclusion
Building Plinko taught me that arcade casino games are far more engineered than they appear. What looks like a simple ball-dropping game involves a careful balance of physics simulation, RTP control, and canvas rendering working together seamlessly.


Top comments (0)