Creating a Low‑Poly 3D Browser Game with Three.js, React, and Cannon.js
This article demonstrates how to build a low‑poly 3D browser game using Three.js, React, and Cannon.js, covering resource loading, scene setup, physics with Heightfield terrain, joystick controls, animation handling, UI flow, and deployment, with full code examples and implementation details.
The article presents a complete tutorial for a low‑poly 3D game set on a distant habitable planet, where the player controls a fox avatar using a joystick‑style wheel to reach a base within a time limit. It explains the background story, gameplay objectives, and online preview links.
Technology Stack : The game is built with Three.js for 3D rendering, React for UI management, and CANNON (via cannon.js) for physics simulation. It also uses GLTFLoader to import models and a custom JoyStick class for input handling.
Page Structure : The HTML layout consists of four main containers – .webgl for the WebGL canvas, .tool for the in‑game toolbar, .loading for the loading screen, and .result for the end‑game screen. Buttons for "Start Game", "Reset", and "Free Explore" are placed inside these containers.
Scene Initialization : A THREE.WebGLRenderer with antialiasing and alpha is created, followed by a THREE.Scene, a perspective camera, ambient light, and directional light. Shadow mapping is enabled using THREE.PCFSoftShadowMap, and the article lists the four shadow types provided by Three.js.
Physics World : A CANNON.World is instantiated with SAP broadphase, gravity set to (0, -10, 0), and default contact material friction set to zero. Ground and wheel materials are defined, and a CANNON.Heightfield is used to generate a 128 × 128 × 60 terrain from a height‑map image.
Particle System : 1,000 particles are created using a custom shader material for a star‑field effect, leveraging GPU rendering for performance.
Loading Management : A THREE.LoadingManager tracks asset progress and updates a loading percentage state, revealing the start button when loading reaches 100%.
Base Model : A hidden THREE.Mesh named shelterLocation holds the base GLTF model. A point light and directional light are attached to illuminate the base and cast shadows.
Fox Model : The fox avatar is loaded via GLTFLoader, scaled, and added to a target mesh used for terrain ray‑casting. Two animation clips ( clip1 and clip2) are prepared with an THREE.AnimationMixer to switch between idle and running states based on joystick input.
Controls : The JoyStick class provides forward and turn values. An updateDrive function translates the fox mesh, plays the appropriate animation, and rotates the model. A third‑person camera follows the avatar using a helper THREE.Object3D.
Animation Loop : The animate function updates the camera, drive logic, animation mixers, physics world step ( fixedTimeStep = 1/60), and renders the scene each frame. It also calls a check function to keep the avatar on the terrain.
Responsive Resize : An event listener adjusts the renderer size and camera aspect ratio on window resize.
Game Logic : Starting the game resets state, begins a 60‑second countdown, and shows the loading screen. Resetting restores the avatar and camera to initial positions. "Free Explore" disables the timer and allows unlimited movement.
UI Effects : Loading, result, and "time‑travel" screens use a frosted‑glass style with background rgba(0, 67, 170, .5), backdrop-filter blur(10px), and drop‑shadow filters.
Conclusion : The article summarizes new knowledge points such as Three.js shadow types, particle systems, basic Cannon.js usage, Heightfield terrain creation, and joystick‑driven animation control, and provides references for further Three.js learning.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
