RTSCamera
new RTSCamera(physics : Object, options : Object)RTSCamera - RTS-style isometric camera with pan/rotate/zoom and click-to-go
Extends PhysicsCamera to provide RTS-style camera controls. Focus-based camera with edge scroll, drag pan, rotate, and zoom-to-cursor. Does NOT use pointer lock.
Constructor Parameters
physicsObjectoptionsoptionalObjectDefault is
{}.canvasoptionalHTMLCanvasElementCanvas element for mouse eventstargetoptionalTHREE.Object3DTarget object to follow (auto-detects body index from mesh.userData)playerBodyIndexoptionalnumberExplicit body index to follow (overrides auto-detection)focusoptionalTHREE.Vector3Initial focus position (when not following)panOffsetoptionalTHREE.Vector3Initial pan offsetfollowTargetoptionalbooleanFollow target position each frame
Default istrue.distanceoptionalnumberCamera distance from focus
Default is24.zoomLimitsoptionalObjectZoom distance limits
Default is{ min: 14, max: 40 }.zoomSpeedoptionalnumberMouse wheel zoom sensitivity
Default is0.8.zoomToCursoroptionalbooleanKeep cursor point fixed when zooming
Default isfalse.groundPlaneYoptionalnumberGround plane height for zoom-to-cursor
Default is0.panSpeedoptionalnumberEdge scroll speed (units/sec at distance 10)
Default is15.dragPanSpeedoptionalnumberDrag pan multiplier
Default is1.edgeScrolloptionalObjectEdge scroll options
Default is{ enabled: false, size: '15%', speed: 15 }.rotateSpeedoptionalnumberYaw rotation speed (rad per pixel)
Default is0.005.yawoptionalnumberInitial yaw (radians)
Default is45deg.tiltoptionalnumberTilt angle in radians
Default is55deg.allowPitchoptionalbooleanAllow pitch changes when rotating
Default isfalse.minTiltoptionalnumberMinimum tilt (radians)maxTiltoptionalnumberMaximum tilt (radians)dampingoptionalnumberFocus translation damping strength
Default is6.panButtonoptionalnumberMouse button for drag pan (0=left,1=middle,2=right, -1 disables)
Default is1.rotateButtonoptionalnumberMouse button for rotate (-1 disables)
Default is-1.fovoptionalnumberField of view
Default is50.
Example
Basic Setup
import { RTSCamera } from '@three-blocks/pro';
const camera = new RTSCamera( physics, {
canvas: renderer.domElement,
target: playerMesh,
distance: 24,
zoomLimits: { min: 14, max: 40 },
edgeScroll: { enabled: true, size: '25%', speed: 20 },
} );
// In animate loop
camera.update( delta );
renderer.render( scene, camera );Properties
# .canvas : HTMLCanvasElement
Canvas element for mouse events.
# .distance : number
Camera distance from focus.
# .zoomLimits : Object
Zoom distance limits.
# .zoomSpeed : number
Mouse wheel zoom sensitivity.
# .panSpeed : number
Edge scroll base speed (units/sec at distance 10).
# .dragPanSpeed : number
Drag pan multiplier.
# .edgeScroll : Object
Edge scroll settings.
# .rotateSpeed : number
Rotation speed (radians per pixel).
# .yaw : number
Yaw angle (radians).
# .tilt : number
Tilt angle (radians).
# .allowPitch : boolean
Allow pitch changes when rotating.
# .minTilt : number
Min tilt for pitch changes.
# .maxTilt : number
Max tilt for pitch changes.
# .zoomToCursor : boolean
Keep cursor point fixed when zooming.
# .groundPlaneY : number
Ground plane height for zoom-to-cursor.
# .followTarget : boolean
Follow target each frame.
# .damping : number
Damping strength for focus translation.
# .panButton : number
Mouse button for drag pan.
# .rotateButton : number
Mouse button for rotate.
Methods
update#
update(delta : number)Update camera state. Call each frame.
Parameters
deltanumberresize#
resize(width : number, height : number) : thisHandle window resize. Updates aspect ratio and projection matrix.
Parameters
widthoptionalnumberheightoptionalnumberReturns
this — For chainingsetDistance#
setDistance(distance : number) : thisSet camera distance from focus.
Parameters
distancenumberReturns
this — For chainingsetZoomLimits#
setZoomLimits(min : number, max : number) : thisSet zoom distance limits.
Parameters
minnumbermaxnumberReturns
this — For chainingsetFocus#
setFocus(position : THREE.Vector3) : thisSet focus position and stop following target.
Parameters
positionTHREE.Vector3Returns
this — For chainingsetFollowTarget#
setFollowTarget(follow : boolean) : thisEnable or disable following the target. When enabling, clears pan offset and recenters on the target.
Parameters
followbooleanReturns
this — For chainingrecenter#
recenter() : thisClear pan offset and recenter on target when available.
Returns
this — For chainingsetGroundPlaneY#
setGroundPlaneY(y : number) : thisSet ground plane height for zoom-to-cursor.
Parameters
ynumberReturns
this — For chaininggetPointerIntersection#
getPointerIntersection(target : THREE.Vector3) : THREE.Vector3|nullGet the current pointer intersection position from physics raycast. Returns the world position where the pointer ray intersects geometry.
Parameters
targetoptionalTHREE.Vector3Returns
THREE.Vector3 | null — The intersection position, or null if no intersectiondispose#
dispose()Clean up resources and event listeners.
Example
Click-to-Go with A* Pathfinding
import { RTSCamera, NavigationGrid } from '@three-blocks/pro';
// Create navigation grid for pathfinding
const navigationGrid = new NavigationGrid( { bounds: sceneBounds } );
await navigationGrid.init( physics );
// Enable pathfinding on player body
await playerBody.navigation.enable( navigationGrid );
// Create RTSCamera - auto-activates its physics mode on update()
const camera = new RTSCamera( physics, {
canvas: renderer.domElement,
target: playerMesh,
followTarget: true,
} );
// IMPORTANT: Use the isClick parameter to detect actual clicks (not hover)
physics.on( 'static_pointer_intersect_0', ( colliders, isClick ) => {
if ( ! isClick ) return; // Filter out hover events
if ( colliders?.[ 0 ]?.point ) {
const point = colliders[ 0 ].point;
// Navigate using the body.navigation API
playerBody.navigation.navigateTo( point );
}
} );
// In animate loop - navigation is handled automatically!
function animate() {
controller.update( delta );
camera.update( delta );
}
### Click-to-Go Best Practices
1. **Use `isClick` parameter**: The `static_pointer_intersect_0` event fires on both
hover and click. Always check `if (!isClick) return;` to only respond to clicks.
2. **Don't use separate pointer events**: Avoid `pointerdown`/`pointerup` with stored
hover positions - this causes stale destinations when clicking rapidly.
3. **Enable pathfinding**: Call `body.navigation.enable(grid)` for A* obstacle avoidance.
Without this, `navigateTo()` uses BASIC mode (straight-line movement).
4. **Check navigation state**: Use `playerBody.navigation.isNavigating` to check if
the player is currently navigating to a destination.