The latest version of the ScriptENGINE 2010: 3D Engine is now available.
Download it now! No obligations or time limitations. Purchase a license at any time to activate the full version.

First Person Cameras in 3D Worlds

ScriptENGINE: Lua 3D Engine Article SeriesIn this article, we'll take a look at creating ScriptENGINE 3D Worlds with a FPS camera to navigate the scene.

ScriptENGINE 3D worlds can include a variety of different entity types including lights, cameras, units (static models), agents (animated models), waypoints, triggers, cursors. In this example we'll concentrate on units and cameras.

 

View the Demo Code

The demos are included in the ScriptENGINE SDK. Now's a great time to get the ScriptENGINE SDK from our website (including the SciTE code editor, Programmer's Reference and ScriptENGINE Demos).

Navigate to the ScriptENGINE SDK/[FPS] First person style with collision detection folder for the example.

Open the world.e76script in the SciTE code editor. We will be referring to the world.e76script for the rest of this article.

 

The ScriptENGINE Demo Framework

The ScriptENGINE Demos are run using the runDemo.e76script framework code in the ScriptENGINE SDK/Demos folder.


Side Note: Caching Physics Geometry

Before we get started discussing FPS cameras, we'll take a quick look at how to cache static geometry in the Physics Engine. Static geometry refers to ScriptENGINE Units with a mass >= the physics engine maximum (The max mass is specified in the IPhysics:init() function. The SDK uses 1000 as default).

Check if a cache file already exists for the static geometry:

geometryCacheFile = IPhysics:geometryCacheExists(idUnit_chapel)

If the geometry has been previously cached, geometryCacheExists() will return the filename of the cached geometry. Otherwise it will return nil.

Save the physics geometry to file:

IPhysics:saveGeometryCache(idUnit_chapel, IWorld:getNameLong())

It will automatically be used the next time the world is loaded into the engine to reduce the physics load times.

ScriptENGINE SDK 3D World Identifiers

The ScriptENGINE SDK 3D World Editor creates a worldIds.e76script file when saving a 3D world. This file contains a list of entity identifiers, and maps them to user-friendly names. You can load this script into your scripts to refer to your 3D world entities more easily. For example, instead of writing:

IWorld:getEntityName('fd18ca22-d812-41dd-a39d-ec9e755bd123') you can write:

IWorld:getEntityName(idCamera_cam) because the worldIds.e76script contains the line:

idCamera_cam    = 'fd18ca22-d812-41dd-a39d-ec9e755bd123';

 

The idUnit_chapel is a constant saved by the SDK 3D World Editor in the worldIds.e76script when the 3D world was saved. It maps the entity's name to its unique id.

 

Subscribe to Events

Subscribe to ScriptENGINE events:

subMouseButton = IEvents:subscribeMouseButton('OnMouseButton');
subTick = IEvents:subscribeTickPeriodic('OnTick', 25);

The subscribers are used to process mouse clicks and move the player using a timer.

 

Re-add the camera to the Physics Engine

The default camera was created with the 3D world using the ScriptENGINE SDK World Editor. But it was saved without being assigned a mass, and hence is not being simulated by the physics engine.

We want to simulate the camera motion using the physics engine, so that it will handle all collision detection for us. Plus we can apply forces & torques to the camera very easily.

Assign the camera a mass:

IPhysics:setEntityMass(idCamera_cam, 100);

This can be anything between the physics engine min/max limits which are specified in the IPhysics:init() function. The SDK 3D World Editor uses 0-1000 as it's default limits.

We make the camera collidable:

IPhysics:setEntityCollisionType(idCamera_cam, PHYSICS_COLLISION_SPHERE) changes the physical bounding entity to an ellipsoid instead of the default bounding box.

IPhysics:setEntityCollidable(idCamera_cam, true) enables collisions with the camera in the physics engine. By default, cameras are not collidable.

Readd the camera:

IWorld:addCamera(idCamera_cam)

It will now be added to the physics engine.

Enable the auto-management of the camera:

IWorld:setActiveCameraAutoProcessed(true);

The ScriptENGINE automatically moves the active camera based upon its type as defined in the IWorld:setCameraType() function. This camera type was set to 'pivot' in the SDK World Editor.

Keep the camera's bounding box upright in the physics engine using an Up-Vector joint:

IPhysics:createJointUpVector('camera', idCamera_cam, '0 1 0')

The camera can still move around, but its restricted to the Y-axis for rotations. so it can rotate about the XZ plane.

 

Moving the Camera

The camera look direction is automatically controlled by the ScriptENGINE in response to the mouse because it's type is 'pivot'. So we only need to move the camera's position in response to the user's key presses.

Define the tick subscriber callback function:

function OnTick(currentTime, lastTime, isWindowActive, userData)

 

Netwon's Laws of Motion

To move the camera using physics forces, we must follow Newton's Laws of Motion. Essentially, they boil down to this important function:

ForceRequired = massOfEntity * (velocityRequired - velocityInitial) / timePeriod

More info is included in the world.e76script about Newton's Laws of Motion.

 

Responding to Keys

There are two ways to respond to keypressed. Firstly, we can subscribe to key events and handle up/down key presses using a callback function. Alternatively, we can call the IKey:isActionOn(), IKey:isActionToggled(), IKey:isActionClicked() etc functions at any time to check if a specific key action has been activated.

The ScriptENGINE defines some standard key action names in the constantsCameraTypes.e76script included in the ScriptENGINE Runtime Distribution, including KEY_CAMERA_MOVE_FORWARD, KEY_CAMERA_MOVE_BACKWARD, KEY_CAMERA_STRAFE_LEFT, KEY_CAMERA_STRAFE_RIGHT.

The periodic tick subscriber checks the key actions at a regular interval and applies a force to the camera to move it in the required direction and speed according to Newton's Law of motion.


The ScriptENGINE Programmer's Reference

We recommend reading the IPhysics Interface in the Programmer's Reference for more info about the Physics Engine.