Examples
Collection of examples showing different ways to use the React 3rd Person Character library.
Basic Example
A minimal setup with default settings:
import {
CharacterConfigProvider,
ExperienceWrapper,
Player,
Scenario,
StyledMobileControls,
FIBER,
THREE,
CharacterBuilder,
} from "react-3rd-person-character";
// Simple character configuration
const characterConfig = new CharacterBuilder({ fps: 60 })
.withName('Player')
.withCameraSettings({ radius: 5 })
.withMovement({ movementSpeed: 5 })
.with3DModels('/models/player', PlayerModel, Scenario3D)
.build();
// Simple player model
function PlayerModel() {
return (
<mesh>
<capsuleGeometry args={[0.5, 1, 4, 8]} />
<meshStandardMaterial color="blue" />
</mesh>
);
}
// Simple scenario
function Scenario3D() {
return (
<group>
<mesh position={[0, -0.5, 0]}>
<boxGeometry args={[20, 1, 20]} />
<meshStandardMaterial color="green" />
</mesh>
</group>
);
}
export default function BasicExample() {
return (
<CharacterConfigProvider character={characterConfig}>
<FIBER.Canvas shadows>
<ExperienceWrapper>
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
<StyledMobileControls />
</CharacterConfigProvider>
);
}
Advanced Character Configuration
A more detailed character setup with custom physics and movement:
const advancedCharacterConfig = new CharacterBuilder({ fps: 60 })
.withName('Adventure Hero')
.withCameraSettings({
radius: 6,
cameraOffsetY: 3,
cameraOffsetZ: 1
})
.withVelocity({
defaultVelocitySimulatorMass: 1.2,
defaultVelocitySimulatorDamping: 0.7,
defaultRotationSimulatorMass: 1.2,
defaultRotationSimulatorDamping: 0.7,
mass: 1.5
})
.withMovement({
movementSpeed: 6,
boostSpeed: 10,
jumpForce: 12
})
.with3DModels(
'/models/hero',
HeroModel,
ForestScenario,
LoadingSpinner,
[1.2, 1.2, 1.2]
)
.build();
// Custom loading component
function LoadingSpinner() {
return (
<div className="loading">
<div className="spinner" />
<p>Loading character...</p>
</div>
);
}
Custom 3D Models
Using GLTF models with animations:
import { useGLTF, useAnimations } from '@react-three/drei';
function HeroModel({ nodes, materials }) {
const { scene, animations } = useGLTF('/models/hero.glb');
const { actions } = useAnimations(animations);
// Handle animations based on character state
const { characterState } = useActorContext();
useEffect(() => {
if (characterState.matches('walking')) {
actions.walk?.play();
} else if (characterState.matches('running')) {
actions.run?.play();
} else {
actions.idle?.play();
}
}, [characterState, actions]);
return <primitive object={scene} />;
}
function ForestScenario() {
const { scene } = useGLTF('/models/forest.glb');
return (
<group>
<primitive object={scene} />
{/* Add physics colliders */}
<RAPIER.RigidBody type="fixed">
<RAPIER.CuboidCollider args={[10, 0.5, 10]} />
</RAPIER.RigidBody>
</group>
);
}
Custom Controls
Creating custom input handling:
import { useControls, useTouchControls } from 'react-3rd-person-character';
function CustomInputHandler() {
const controls = useControls();
const touchControls = useTouchControls();
// Custom input logic
useEffect(() => {
if (controls.forward && controls.run) {
// Handle sprint
console.log('Sprinting forward');
}
if (touchControls.joystick.isPressed) {
// Handle mobile joystick
console.log('Joystick angle:', touchControls.joystick.angle);
}
}, [controls, touchControls]);
return null;
}
// Use in your app
function App() {
return (
<CharacterConfigProvider character={characterConfig}>
<FIBER.Canvas>
<ExperienceWrapper>
<CustomInputHandler />
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
</CharacterConfigProvider>
);
}
Custom UI Integration
Integrating with your own UI components:
import { useActorContext } from 'react-3rd-person-character';
function CharacterUI() {
const { characterState, character } = useActorContext();
return (
<div className="character-ui">
<div className="character-name">{character.name}</div>
<div className="character-state">
State: {characterState.value}
</div>
<div className="character-stats">
<div>Speed: {character.movement.movementSpeed}</div>
<div>Mass: {character.velocity.mass}</div>
</div>
</div>
);
}
function GameUI() {
return (
<div className="game-ui">
<CharacterUI />
<div className="controls-hint">
WASD to move, Space to jump, Shift to run
</div>
</div>
);
}
Physics Integration
Custom physics setup and interactions:
function PhysicsExample() {
return (
<CharacterConfigProvider character={characterConfig}>
<FIBER.Canvas>
<RAPIER.Physics>
<ExperienceWrapper>
<Scenario />
<Player />
{/* Custom physics objects */}
<RAPIER.RigidBody position={[5, 2, 0]}>
<RAPIER.CuboidCollider args={[1, 1, 1]} />
<mesh>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="red" />
</mesh>
</RAPIER.RigidBody>
<RAPIER.RigidBody position={[-5, 1, 0]} type="fixed">
<RAPIER.CuboidCollider args={[2, 0.5, 2]} />
<mesh>
<boxGeometry args={[4, 1, 4]} />
<meshStandardMaterial color="yellow" />
</mesh>
</RAPIER.RigidBody>
</ExperienceWrapper>
</RAPIER.Physics>
</FIBER.Canvas>
</CharacterConfigProvider>
);
}
Mobile-First Design
Optimized for mobile devices:
import { useDevice } from 'use-device-react';
function MobileOptimizedApp() {
const { isDesktop, isMobile } = useDevice();
const mobileCharacterConfig = new CharacterBuilder({ fps: 60 })
.withName('Mobile Player')
.withCameraSettings({
radius: isMobile ? 4 : 6, // Closer camera on mobile
cameraOffsetY: isMobile ? 1.5 : 2
})
.withMovement({
movementSpeed: isMobile ? 4 : 6, // Slower on mobile
boostSpeed: isMobile ? 6 : 8
})
.with3DModels('/models/player', PlayerModel, Scenario3D)
.build();
return (
<CharacterConfigProvider character={mobileCharacterConfig}>
<FIBER.Canvas>
<ExperienceWrapper>
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
{/* Conditional mobile controls */}
{!isDesktop && (
<div className="mobile-controls">
<StyledMobileControls />
<div className="mobile-hints">
<p>Use joystick to move</p>
<p>Tap buttons for actions</p>
</div>
</div>
)}
</CharacterConfigProvider>
);
}
Performance Optimization
Optimized for high-performance applications:
function OptimizedApp() {
const characterConfig = new CharacterBuilder({ fps: 60 })
.withName('Optimized Player')
.withCameraSettings({ radius: 5 })
.withMovement({ movementSpeed: 5 })
.with3DModels('/models/player', OptimizedPlayerModel, OptimizedScenario)
.build();
return (
<CharacterConfigProvider character={characterConfig}>
<FIBER.Canvas
gl={{
powerPreference: "high-performance",
antialias: false, // Disable for performance
stencil: false,
depth: false
}}
shadows={false} // Disable shadows for performance
>
<ExperienceWrapper>
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
</CharacterConfigProvider>
);
}
// Optimized models with LOD
function OptimizedPlayerModel() {
return (
<LOD distances={[0, 10, 50]}>
<mesh>
<capsuleGeometry args={[0.5, 1, 8, 16]} />
<meshStandardMaterial color="blue" />
</mesh>
<mesh>
<capsuleGeometry args={[0.5, 1, 4, 8]} />
<meshStandardMaterial color="blue" />
</mesh>
<mesh>
<capsuleGeometry args={[0.5, 1, 2, 4]} />
<meshStandardMaterial color="blue" />
</mesh>
</LOD>
);
}
Multi-Character Setup
Managing multiple characters:
function MultiCharacterExample() {
const player1Config = new CharacterBuilder({ fps: 60 })
.withName('Player 1')
.withCameraSettings({ radius: 5 })
.withMovement({ movementSpeed: 5 })
.with3DModels('/models/player1', Player1Model, Scenario3D)
.build();
const player2Config = new CharacterBuilder({ fps: 60 })
.withName('Player 2')
.withCameraSettings({ radius: 5 })
.withMovement({ movementSpeed: 5 })
.with3DModels('/models/player2', Player2Model, Scenario3D)
.build();
return (
<div className="multi-player">
<CharacterConfigProvider character={player1Config}>
<FIBER.Canvas>
<ExperienceWrapper>
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
</CharacterConfigProvider>
<CharacterConfigProvider character={player2Config}>
<FIBER.Canvas>
<ExperienceWrapper>
<Scenario />
<Player />
</ExperienceWrapper>
</FIBER.Canvas>
</CharacterConfigProvider>
</div>
);
}
Complete Game Example
A more complete game setup:
function CompleteGame() {
const [gameState, setGameState] = useState('menu');
const [score, setScore] = useState(0);
const gameCharacterConfig = new CharacterBuilder({ fps: 60 })
.withName('Game Hero')
.withCameraSettings({ radius: 6 })
.withMovement({ movementSpeed: 6, boostSpeed: 10 })
.with3DModels('/models/hero', GameHeroModel, GameWorld)
.build();
if (gameState === 'menu') {
return (
<div className="menu">
<h1>Adventure Game</h1>
<button onClick={() => setGameState('playing')}>
Start Game
</button>
</div>
);
}
return (
<div className="game">
<CharacterConfigProvider character={gameCharacterConfig}>
<FIBER.Canvas shadows>
<ExperienceWrapper>
<Scenario />
<Player />
<GameObjects />
</ExperienceWrapper>
</FIBER.Canvas>
<div className="game-ui">
<div className="score">Score: {score}</div>
<button onClick={() => setGameState('menu')}>
Back to Menu
</button>
</div>
</CharacterConfigProvider>
</div>
);
}
These examples demonstrate various use cases and integration patterns. You can combine and modify them to suit your specific needs.