Now that you have a fully functioning WebXR game, it's time to add some finishing touches to enhance the overall experience. In this final chapter, we'll introduce audio, haptic feedback, and visual effects to make your game more immersive and engaging. These elements will provide immediate feedback to the player, making the game feel more polished and interactive.
We’ll start by adding audio feedback for firing the blaster and scoring points. Three.js provides a straightforward way to handle audio using its audio system, which we’ll leverage here.
First, we declare global variables for the sounds:
let laserSound, scoreSound;
Next, inside the setupScene
function, we create an audio listener and load the positional audio files:
function setupScene({ scene, camera, renderer, player, controllers }) {
// Other setup code...
// Load and set up positional audio
const listener = new THREE.AudioListener();
camera.add(listener);
const audioLoader = new THREE.AudioLoader();
// Laser sound
laserSound = new THREE.PositionalAudio(listener);
audioLoader.load('assets/laser.ogg', (buffer) => {
laserSound.setBuffer(buffer);
blasterGroup.add(laserSound);
});
// Score sound
scoreSound = new THREE.PositionalAudio(listener);
audioLoader.load('assets/score.ogg', (buffer) => {
scoreSound.setBuffer(buffer);
scoreText.add(scoreSound);
});
}
-
Audio Listener: The
AudioListener
is essentially the "ears" of the camera. It’s necessary for hearing the sounds in the scene. We attach it to the camera so that the audio follows the player's perspective. -
Positional Audio: We use
PositionalAudio
to make the sounds feel like they’re coming from specific points in the 3D space. The laser sound is attached to the blaster, and the score sound is attached to the scoreboard text.
We trigger the sounds when appropriate actions occur:
-
Firing the Blaster:
if (laserSound.isPlaying) laserSound.stop(); laserSound.play();
-
Scoring Points:
if (scoreSound.isPlaying) scoreSound.stop(); scoreSound.play();
This ensures that the sounds are played without overlap, providing clear audio feedback to the player.
To enhance the tactile experience, we add haptic feedback when the player fires the blaster. This simple vibration adds a layer of immersion, making the action feel more impactful:
try {
const hapticActuator = gamepad.getHapticActuator(0).pulse(0.6, 100);
} catch {}
- Haptic Feedback: The
pulse
method triggers a short vibration at 60% intensity for 100 milliseconds. - Try-Catch Block: We use a try-catch block to ensure that the application doesn’t crash on devices that don’t have haptic actuators.
Finally, we enhance the visual feedback when a target is hit by animating its disappearance and reappearance using GSAP. Instead of having the target abruptly disappear and reappear, we smoothly scale it down and back up. Let's first locate the target disappear/reappear logic based on setTimeout
:
target.visible = false;
setTimeout(() => {
target.visible = true;
target.position.x = Math.random() * 10 - 5;
target.position.z = -Math.random() * 5 - 5;
}, 2000);
And replace it with:
import { gsap } from 'gsap';
gsap.to(target.scale, {
duration: 0.3,
x: 0,
y: 0,
z: 0,
onComplete: () => {
target.visible = false;
setTimeout(() => {
target.visible = true;
target.position.x = Math.random() * 10 - 5;
target.position.z = -Math.random() * 5 - 5;
// Scale back up the target
gsap.to(target.scale, {
duration: 0.3,
x: 1,
y: 1,
z: 1,
});
}, 1000);
},
});
- Scaling Down: When a target is hit, it scales down to zero over 0.3 seconds, creating a smooth disappearing effect.
- Respawning with Animation: After 1 second, the target reappears, scaling back up to its original size over 0.3 seconds. This makes the reappearance feel smooth and natural.
To ensure GSAP animations are synchronized with your WebXR frame updates, include this at the end of your onFrame
function:
gsap.ticker.tick(delta);
Congratulations! You’ve completed the entire WebXR First Steps tutorial and built a fully immersive and interactive game. Here’s a final look at your game in action:
Although the tutorial is over, your journey with WebXR has just begun. There are countless ways to expand and enhance your game. Here are some ideas to get you started:
- Dual Wielding: Add a second blaster to the other controller for dual-wielding action.
- Timed Challenge: Introduce a timer to make it a race against the clock.
- Moving Targets: Make the targets move around to increase the difficulty.
- Exploding Targets: Add visual effects to make the targets explode when hit.
- And More!: Your imagination is the limit—experiment, add new features, and make the game truly your own!
Thank you for following along with this tutorial. I hope it’s been a fun and educational journey into the world of WebXR. Happy coding!