RTSCamera

@three-blocks/proPhysicsCameraRTSWebGPUWebGL
new RTSCamera(physics : Object, options : Object)
Extends
PhysicsCamera

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
physicsObject
Physics instance
optionsoptionalObject
Camera options
Default is {}.
  • canvasoptionalHTMLCanvasElement
    Canvas element for mouse events
  • targetoptionalTHREE.Object3D
    Target object to follow (auto-detects body index from mesh.userData)
  • playerBodyIndexoptionalnumber
    Explicit body index to follow (overrides auto-detection)
  • focusoptionalTHREE.Vector3
    Initial focus position (when not following)
  • panOffsetoptionalTHREE.Vector3
    Initial pan offset
  • followTargetoptionalboolean
    Follow target position each frame
    Default is true.
  • distanceoptionalnumber
    Camera distance from focus
    Default is 24.
  • zoomLimitsoptionalObject
    Zoom distance limits
    Default is { min: 14, max: 40 }.
  • zoomSpeedoptionalnumber
    Mouse wheel zoom sensitivity
    Default is 0.8.
  • zoomToCursoroptionalboolean
    Keep cursor point fixed when zooming
    Default is false.
  • groundPlaneYoptionalnumber
    Ground plane height for zoom-to-cursor
    Default is 0.
  • panSpeedoptionalnumber
    Edge scroll speed (units/sec at distance 10)
    Default is 15.
  • dragPanSpeedoptionalnumber
    Drag pan multiplier
    Default is 1.
  • edgeScrolloptionalObject
    Edge scroll options
    Default is { enabled: false, size: '15%', speed: 15 }.
  • rotateSpeedoptionalnumber
    Yaw rotation speed (rad per pixel)
    Default is 0.005.
  • yawoptionalnumber
    Initial yaw (radians)
    Default is 45deg.
  • tiltoptionalnumber
    Tilt angle in radians
    Default is 55deg.
  • allowPitchoptionalboolean
    Allow pitch changes when rotating
    Default is false.
  • minTiltoptionalnumber
    Minimum tilt (radians)
  • maxTiltoptionalnumber
    Maximum tilt (radians)
  • dampingoptionalnumber
    Focus translation damping strength
    Default is 6.
  • panButtonoptionalnumber
    Mouse button for drag pan (0=left,1=middle,2=right, -1 disables)
    Default is 1.
  • rotateButtonoptionalnumber
    Mouse button for rotate (-1 disables)
    Default is -1.
  • fovoptionalnumber
    Field of view
    Default is 50.
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
deltanumber
Time delta in seconds

resize#

resize(width : number, height : number) : this

Handle window resize. Updates aspect ratio and projection matrix.

Parameters
widthoptionalnumber
New width
heightoptionalnumber
New height
Returns
this — For chaining

setDistance#

setDistance(distance : number) : this

Set camera distance from focus.

Parameters
distancenumber
New distance
Returns
this — For chaining

setZoomLimits#

setZoomLimits(min : number, max : number) : this

Set zoom distance limits.

Parameters
minnumber
Minimum zoom distance
maxnumber
Maximum zoom distance
Returns
this — For chaining

setFocus#

setFocus(position : THREE.Vector3) : this

Set focus position and stop following target.

Parameters
positionTHREE.Vector3
New focus position
Returns
this — For chaining

setFollowTarget#

setFollowTarget(follow : boolean) : this

Enable or disable following the target. When enabling, clears pan offset and recenters on the target.

Parameters
followboolean
Follow target
Returns
this — For chaining

recenter#

recenter() : this

Clear pan offset and recenter on target when available.

Returns
this — For chaining

setGroundPlaneY#

setGroundPlaneY(y : number) : this

Set ground plane height for zoom-to-cursor.

Parameters
ynumber
New ground plane height
Returns
this — For chaining

getPointerIntersection#

getPointerIntersection(target : THREE.Vector3) : THREE.Vector3|null

Get the current pointer intersection position from physics raycast. Returns the world position where the pointer ray intersects geometry.

Parameters
targetoptionalTHREE.Vector3
Optional vector to store the result
Returns
THREE.Vector3 | null — The intersection position, or null if no intersection

dispose#

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.