Skip to main content

Player Control

RigidControls handles walking, running, jumping, flying, and collision detection. It wraps ThreeJS's PointerLockControls.

Setup Controls

main.js
const inputs = new VOXELIZE.Inputs();

const rigidControls = new VOXELIZE.RigidControls(
camera,
renderer.domElement,
world,
{
initialPosition: [0, 40, 0],
}
);

rigidControls.connect(inputs);

connect registers default movement keys (WASD, Space, Shift).

Update Loop

main.js
function animate() {
requestAnimationFrame(animate);

if (world.isInitialized) {
world.update(
camera.getWorldPosition(new THREE.Vector3()),
camera.getWorldDirection(new THREE.Vector3())
);

rigidControls.update();
}

renderer.render(world, camera);
}

Click the canvas to lock the pointer and start moving:

Add Fly and Ghost Mode

main.js
inputs.bind("g", rigidControls.toggleGhostMode);
inputs.bind("f", rigidControls.toggleFly);
  • Press F to toggle flying
  • Press G to toggle ghost mode (no-clip)

Full Code

main.js
import * as VOXELIZE from "@voxelize/core";
import * as THREE from "three";

const canvas = document.getElementById("canvas");

const world = new VOXELIZE.World({
textureUnitDimension: 16,
});

const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
3000
);

const renderer = new THREE.WebGLRenderer({
antialias: true,
powerPreference: "high-performance",
canvas,
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio || 1);
renderer.outputColorSpace = THREE.SRGBColorSpace;

window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});

const network = new VOXELIZE.Network();
network.register(world);

const inputs = new VOXELIZE.Inputs();

const rigidControls = new VOXELIZE.RigidControls(
camera,
renderer.domElement,
world,
{
initialPosition: [0, 40, 0],
}
);

rigidControls.connect(inputs);

inputs.bind("g", rigidControls.toggleGhostMode);
inputs.bind("f", rigidControls.toggleFly);

function animate() {
requestAnimationFrame(animate);

if (world.isInitialized) {
world.update(
camera.getWorldPosition(new THREE.Vector3()),
camera.getWorldDirection(new THREE.Vector3())
);

rigidControls.update();
}

renderer.render(world, camera);
}

async function start() {
animate();

await network.connect("http://localhost:4000");
await network.join("tutorial");

await world.initialize();

world.sky.setShadingPhases([
{
name: "sunrise",
color: {
top: new THREE.Color("#7694CF"),
middle: new THREE.Color("#B0483A"),
bottom: new THREE.Color("#222"),
},
skyOffset: 0.05,
voidOffset: 0.6,
start: 0.2,
},
{
name: "daylight",
color: {
top: new THREE.Color("#73A3FB"),
middle: new THREE.Color("#B1CCFD"),
bottom: new THREE.Color("#222"),
},
skyOffset: 0,
voidOffset: 0.6,
start: 0.25,
},
{
name: "sunset",
color: {
top: new THREE.Color("#A57A59"),
middle: new THREE.Color("#FC5935"),
bottom: new THREE.Color("#222"),
},
skyOffset: 0.05,
voidOffset: 0.6,
start: 0.7,
},
{
name: "night",
color: {
top: new THREE.Color("#000"),
middle: new THREE.Color("#000"),
bottom: new THREE.Color("#000"),
},
skyOffset: 0.1,
voidOffset: 0.6,
start: 0.75,
},
]);

world.sky.paint("bottom", VOXELIZE.artFunctions.drawSun());
world.sky.paint("top", VOXELIZE.artFunctions.drawStars());
world.sky.paint("top", VOXELIZE.artFunctions.drawMoon());
world.sky.paint("sides", VOXELIZE.artFunctions.drawStars());

const allFaces = ["px", "nx", "py", "ny", "pz", "nz"];
await world.applyBlockTexture("Dirt", allFaces, "/blocks/dirt.png");
await world.applyBlockTexture("Stone", allFaces, "/blocks/stone.png");
await world.applyBlockTexture(
"Grass Block",
["px", "pz", "nx", "nz"],
"/blocks/grass_side.png"
);
await world.applyBlockTexture("Grass Block", "py", "/blocks/grass_top.png");
await world.applyBlockTexture("Grass Block", "ny", "/blocks/dirt.png");
}

start();

This matches the code in the tutorial repository.