setup()
setup() runs once when the sketch loads. It is where you initialize your Three.js scene, add all permanent objects (lights, ground, house, trees), configure the camera and renderer, and set up UI. The separation of setup() and draw() mirrors p5.js tradition but uses Three.js for 3D rendering instead of 2D canvas drawing.
function setup() {
createCanvas(1, 1);
noLoop();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
camera.position.copy(playerPosition);
hemisphereLight = new THREE.HemisphereLight(0xadd8e6, 0x00008b, 0.5);
scene.add(hemisphereLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -20;
directionalLight.shadow.camera.right = 20;
directionalLight.shadow.camera.top = 20;
directionalLight.shadow.camera.bottom = -20;
scene.add(directionalLight);
houseInteriorLight = new THREE.PointLight(0xffffee, 0.8, 10);
houseInteriorLight.position.set(0, 3, 0);
houseInteriorLight.castShadow = true;
scene.add(houseInteriorLight);
createGround();
createMapBarriers();
createHouse();
createPalmTrees(10);
controls = new THREE.PointerLockControls(camera, renderer.domElement);
scene.add(controls.getObject());
uiDiv = createDiv();
uiDiv.id('ui');
uiDiv.style('position', 'absolute');
uiDiv.style('top', '10px');
uiDiv.style('left', '10px');
uiDiv.style('color', 'white');
uiDiv.style('font-family', 'monospace');
uiDiv.style('font-size', '16px');
uiDiv.style('z-index', '100');
healthSpan = createSpan(`Health: ${playerHealth}`);
healthSpan.id('health');
uiDiv.child(healthSpan);
uiDiv.child(createElement('br'));
ammoSpan = createSpan(`Ammo: ${playerAmmo}`);
ammoSpan.id('ammo');
uiDiv.child(ammoSpan);
uiDiv.child(createElement('br'));
hungerSpan = createSpan(`Hunger: ${playerHunger}`);
hungerSpan.id('hunger');
uiDiv.child(hungerSpan);
uiDiv.child(createElement('br'));
nightSpan = createSpan(`Nights Survived: ${nightsSurvived}`);
nightSpan.id('nights');
uiDiv.child(nightSpan);
uiDiv.child(createElement('br'));
messageDiv = createDiv('');
messageDiv.id('message');
messageDiv.style('font-size', '24px');
messageDiv.style('text-align', 'center');
messageDiv.style('position', 'absolute');
messageDiv.style('width', '100%');
messageDiv.style('top', '40%');
uiDiv.child(messageDiv);
instructionsDiv = createDiv(`
<p>Welcome to Island Survival!</p>
<p>Controls:</p>
<ul>
<li>W, A, S, D: Move</li>
<li>Space: Jump</li>
<li>Mouse: Look around</li>
<li>Left Click: Shoot (at night)</li>
<li>R: Reload (at night)</li>
<li>E: Interact (e.g., harvest fruit from trees, climb ladder)</li>
<li>Q: Hire a guard (${GUARD_COST_HUNGER} hunger)</li>
<li>Esc: Exit Pointer Lock</li>
</ul>
<p>Survive 7 nights to win. Zombies appear at night. A gun will appear when night falls. Keep your hunger up by eating fruit!</p>
<p>Watch out for different types of zombies: Regular 🧟, Fast 💨, and Tank 🛡️!</p>
`);
instructionsDiv.id('instructions');
instructionsDiv.style('position', 'absolute');
instructionsDiv.style('top', '50%');
instructionsDiv.style('left', '50%');
instructionsDiv.style('transform', 'translate(-50%, -50%)');
instructionsDiv.style('background', 'rgba(0,0,0,0.7)');
instructionsDiv.style('padding', '20px');
instructionsDiv.style('border-radius', '10px');
instructionsDiv.style('color', 'white');
instructionsDiv.style('text-align', 'left');
instructionsDiv.style('z-index', '101');
document.body.appendChild(instructionsDiv.elt);
startGameButton = createButton('Click to Start Game');
startGameButton.parent(instructionsDiv);
startGameButton.style('margin-top', '20px');
startGameButton.style('padding', '10px 20px');
startGameButton.style('font-size', '18px');
startGameButton.style('cursor', 'pointer');
startGameButton.mousePressed(startGame);
gunMesh = new THREE.Mesh(
new THREE.BoxGeometry(0.1, 0.1, 0.5),
new THREE.MeshStandardMaterial({ color: 0x808080 })
);
gunMesh.position.set(0.3, -0.2, -0.5);
gunMesh.castShadow = true;
gunMesh.receiveShadow = true;
gunMesh.visible = false;
camera.add(gunMesh);
renderer.domElement.addEventListener('mousedown', onMouseDown, false);
}
Line-by-line explanation (14 lines)
🔧 Subcomponents:
createCanvas(1, 1);
noLoop();
Creates a minimal p5.js canvas to satisfy p5.js lifecycle; noLoop() prevents p5.js draw from running until startGame() calls loop()
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.shadowMap.enabled = true;
Initializes the Three.js scene graph, a perspective camera with 75° field of view, and a WebGL renderer that fills the entire window with shadow mapping enabled
hemisphereLight = new THREE.HemisphereLight(0xadd8e6, 0x00008b, 0.5);
scene.add(hemisphereLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;
Creates ambient hemisphere lighting (sky blue above, dark blue below) and a directional sun light that casts shadows—both change during the day-night cycle
createGround();
createMapBarriers();
createHouse();
createPalmTrees(10);
Populates the scene with the ground plane, invisible map barriers at edges, the house structure, and 10 randomly-scattered palm trees
controls = new THREE.PointerLockControls(camera, renderer.domElement);
scene.add(controls.getObject());
Attaches PointerLockControls to the camera so mouse movement rotates the camera view in first-person
uiDiv = createDiv();
uiDiv.id('ui');
Creates a p5.js div to hold HUD elements like health, ammo, hunger, and nights survived
gunMesh = new THREE.Mesh(
new THREE.BoxGeometry(0.1, 0.1, 0.5),
new THREE.MeshStandardMaterial({ color: 0x808080 })
);
gunMesh.position.set(0.3, -0.2, -0.5);
gunMesh.visible = false;
camera.add(gunMesh);
Creates a simple grey box gun model and attaches it to the camera so it stays in the player's right hand; hidden until nightfall
createCanvas(1, 1);- Creates a 1x1 p5.js canvas (mostly invisible) to maintain p5.js event handling and lifecycle
noLoop();- Stops the p5.js draw loop from running automatically—the loop only starts when startGame() is called
scene = new THREE.Scene();- Creates a Three.js scene object that will hold all 3D objects (camera, lights, meshes, zombies)
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);- Creates a perspective camera with a 75-degree field of view; 0.1 to 1000 are near and far clipping planes
renderer = new THREE.WebGLRenderer({ antialias: true });- Creates a WebGL renderer with antialiasing enabled to smooth out jagged edges
renderer.shadowMap.enabled = true;- Enables shadow mapping so objects cast realistic shadows on surfaces
hemisphereLight = new THREE.HemisphereLight(0xadd8e6, 0x00008b, 0.5);- Creates ambient lighting: light blue from the sky, dark blue from below, intensity 0.5—simulates natural ambient light
directionalLight.castShadow = true;- Marks the directional (sun) light as shadow-casting so objects will have shadows on the ground
directionalLight.shadow.mapSize.width = 2048;- Sets the shadow map resolution to 2048 pixels for crisp shadow edges (higher = more detailed but slower)
createGround();- Calls a helper function that creates a large green plane to serve as the island terrain
controls = new THREE.PointerLockControls(camera, renderer.domElement);- Creates pointer lock controls that make the mouse control camera rotation; locked when the player clicks the canvas
scene.add(controls.getObject());- Adds the camera to the scene; the controls object wraps the camera and handles mouse look
gunMesh.visible = false;- Hides the gun initially; it becomes visible when night falls
camera.add(gunMesh);- Attaches the gun to the camera so it moves and rotates with the player's viewpoint