Current games in gamestack:
- Minesweeper
- Solitaire
- Asteroids
- 8 Ball Pool
A personal project to create a react MERN stack app which has a number of simple games. I used trial and error and ChatGPT prompting. This was built with React, Matter.js, Node, Javascript, and CSS. Game was divided up into the smallest working components/units. It reused my asteroids code as template, changing the asteroids to pool balls.
The hardest part was getting the shot-taking mechanic to work and took a lot of playing around.
Things learned:
- More experience with Matter.js; '2D.5' ball physics and
- Implementing 3D ('2D.5') textures into 2D matter.js objects with 'render.sprite'
- Instead of z-index, matter.js layers objects based on order of rendering. So, the pool stick is on top of everything else because it's created last (see Pool.jsx)
git clone https://github.com/sifzerda/pool.git
cd pool
npm install
npm run startControls:
- Click and hold mouse button on the cue ball to begin shot, drag mouse back to add power, release to fire.
Technologies:
- useRef and requestAnimationFrame: API library to update game state at fps matching the display refresh rate, creating animation, by default 60fps.
- matter-js: physics and collision detection engine.
Canvas: API for creating and drawing on a canvas.Used this initially to draw aim line but took it out and drew with SVG instead.
The main functions of code:
(A) Game:
(A.1) PoolTable component:
- 'const greenTable' : creates pool table rectangle, non-moving (isStatic) and non-physical (isSensor)
- 'const wallThickness....' : creates pool table walls/boundaries non-moving (isStatic), interactive with balls.
- 'const pocketPositions', 'pockets' : creates pockets
(A.2) Pool component:
- 'const initialBalls' : holds ball data, I did this the same as creating cards in my solitaire code.
- 'useEffect...const render' : creates game world.
- 'const cueBallRadius...' 'const cueBallBody' : creates cue ball.
- 'const createBall' : makes all other balls taking in data from initialBalls
- 'const ballSpacing' : positions balls on game start.
(B) Movement:
(A) Pocket Sensors:
You can remove:
const sensorRadius = 10;and
const pocketSensor = Bodies.circle(pos.x, pos.y, sensorRadius, {
label: 'pocketSensor',
isSensor: true,
isStatic: true,
render: {
visible: false,
},
});Pocket sensors create smaller objects inside each pocket which must be touched for ball to get removed. Without it, balls need only touch any part of pocket to fall in. Pocket sensors allow pocket detection radius to be configurable, so balls can sit right at the edge of the pocket, touching it, but not trip detection.
(B) Change Background:
There are some alternate pool table colours in the public/images folder. You can switch the green table out by replacing 'greenTablePic' inside PoolTable.jsx with one of the other variables (and uncommenting it)
const greenTable = Bodies.rectangle(745, 340, 1295, 590, {
isStatic: true,
isSensor: true,
render: {
sprite: {
texture: greenTablePic,- Balls go through walls if hit hard enough
- Pool stick doesn't slide back when you take a shot
- Draggable Rack in spare file, haven't put it in game
- Dragging only extends within canvas rather than full browser window
- No ball pot order
- Potting cue ball needs cue ball reset to initial position or penalty
- Light blue ball doesn't move on deployed app (it does on local)
Optimization:
- use react-virtualized to only render visible stuff
- once game basically running, convert it into Redux or Zustand
- use a bundler like Webpack or Parcel to optimize build output: Enable code splitting, tree-shaking, and minification to reduce bundle size and improve load times.
- Consider memoizing components using React.memo to prevent unnecessary re-renders, especially if their props rarely change.
-
Make a cue ball
-
Get mouse drag shot mechanic
-
Make aim line when dragging
-
make stick and aimline not visible when cue ball is moving
-
Make 15 balls
-
set world gravity = 0 and give world borders
-
make table;
- Table has to be 4 enclosing rods or non physically interacting, solid table interupts object physics
-
make draggable cue ball
- limit draggability to when cue ball or no balls in motion, i.e. each turn
- Limit draggability to turn after cue ball pocketed ??
- Ideally, cue ball draggable only after opposing player pockets it
- Limit draggability to turn after cue ball pocketed ??
- limit draggability to when cue ball or no balls in motion, i.e. each turn
-
make pool rack
- Rack needs to be non physical, or physical until first move (to keep balls in place before being hit)
-
Make pool stick [x]
- Refine pool stick to rotate or slide back and then disappear on releasing mouse button
- Pool stick only appears when its your turn (in multiplayer), it disappears when ever balls are in motion, or after turn taken
-
Make pockets accept balls, or balls disappear when they 'collide' with center of pocket
-
MUCH LATER - Drag and drop cue ball on potting it
-
drag and drop cue ball on first move
-
Create triangle rack: through Matter.js 'chamfer' option to round corners.
-
Ball potting order: if you pocket a stripes ball first, you are stripes, or vice versa (multiplyer logic)
-
Split balls into solids and stripes (tracked by UseState)
-
Give balls colors (non tracked by UseState)
- This may be tracked by useState later to display as image of balls needing to be potted (sort of like life display at top of screen)
-
Give balls 3d textures
-
maybe upgrade table appearance
-
STYLE:
-
[ ] Green pool table (or radio switches to change table color; green default, red, blue, yellow, white, black - or fluro colors)made this but creates issues changing background pre-game initialization; -
[ ] change stick color; beige (default), brown, black, red, blue, greensame issue as above -
sound fx (game start initializing sound, cue hitting ball, stick hitting cue, ball hitting pocket, ball rolling along pocket rail)
Navigation:
- Game Start screen
- Game win/loss screen
- Timer potentially player turn is on a timer (e.g. 1 minute), after which, other player's turn
- Score: each ball pocketed + time bonus
- Exit game through main game
- Highscores (from start screen)
- Submit highscores
- Profile scores and logging in
For support, users can contact tydamon@hotmail.com.
Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
- Fork the Project
- Create your Feature Branch (git checkout -b feature/NewFeature)
- Commit your Changes (git commit -m 'Add some NewFeature')
- Push to the Branch (git push origin feature/NewFeature)
- Open a Pull Request
The author acknowledges and credits those who have contributed to this project including:
- ChatGPT
- Matter.js 'Slingshot' example (to make pool balls in a pyramid composite structure)
Distributed under the MIT License. See LICENSE.txt for more information.
This project is complete.


