First Person Camera for Papervision3D
Hi all:
—
[EDIT : CLICK HERE FIND THE LATEST VERSION]
—
The current dependencies are Papervision3D and Tweener, but I’m sure with a little tweak here an there, it can be used with any 3D or tween engine out there.
FirstPersonCamera3D extends Papervision’s Camera3D class and adds the mouse and key methods in order to implement the first person functionality, here’s a sample:
Use arrow keys to navigate and mouse to look

I tried to comment the class as much as possible. By default, the motion keys are the arrow keys but you can use the mapKeys method to map any keys you wish. Here’s the FirstPersonCamera3D class and right below that is the document class used for the example above. Please feel free to optimize or edit it as much as possible!
{
import caurina.transitions.Tweener;
import flash.display.Stage;
import flash.events.KeyboardEvent;
import flash.utils.*;
import org.papervision3d.cameras.Camera3D;
/**
* Camera3D object with First Person functionality
* @author Reynaldo Columna
*
*/
public class FirstPersonCamera3D extends Camera3D
{
protected static const UP_ARROW:int = 38;
protected static const LEFT_ARROW:int = 37;
protected static const RIGHT_ARROW:int = 39;
protected static const DOWN_ARROW:int = 40;
private static var FORWARD_KEY:int;
private static var LEFT_KEY:int;
private static var RIGHT_KEY:int;
private static var BACK_KEY:int;
protected var _sensitivity:Number;
protected var _maxRotationX:Number;
protected var _maxRotationY:Number;
protected var _stageReference:Stage;
protected var _moveIncrement:Number;
private var forwardTrigger:uint;
private var leftTrigger:uint;
private var rightTrigger:uint;
private var backTrigger:uint;
private var intervals:Array;
private var movingForward:Boolean;
private var movingLeft:Boolean;
private var movingRight:Boolean;
private var movingBack:Boolean;
public function FirstPersonCamera3D(fov:Number=60, near:Number=10, far:Number=5000, useCulling:Boolean=false, useProjection:Boolean=false)
{
super(fov, near, far, useCulling, useProjection);
intervals = [forwardTrigger, leftTrigger, rightTrigger, backTrigger];
movingForward = false;
movingLeft = false;
movingRight = false;
movingBack = false;
}
/**
* Initializes the Camera functionality
* @param $stage A reference to the stage in order to add the key listeners
* @param $moveIncrement A number which represents the move increment
*
*/
public function initialize($stage:Stage, $moveIncrement:Number = 250):void
{
stageReference = $stage;
moveIncrement = $moveIncrement;
addListeners();
}
/**
* Maps the keys to be used for movement. If no keys are specified, the arrow keys are used as defauilt.
* @param $keys An object with the following values: forward, back, left and right. Each should be a key code.
*
*/
public function mapKeys($keys:Object = null):void
{
FirstPersonCamera3D.FORWARD_KEY = (($keys != null) ? $keys.forward : FirstPersonCamera3D.UP_ARROW) || FirstPersonCamera3D.UP_ARROW;
FirstPersonCamera3D.BACK_KEY = (($keys != null) ? $keys.back : FirstPersonCamera3D.DOWN_ARROW) || FirstPersonCamera3D.DOWN_ARROW;
FirstPersonCamera3D.LEFT_KEY = (($keys != null) ? $keys.left : FirstPersonCamera3D.LEFT_ARROW) || FirstPersonCamera3D.LEFT_ARROW;
FirstPersonCamera3D.RIGHT_KEY = (($keys != null) ? $keys.right : FirstPersonCamera3D.RIGHT_ARROW) || FirstPersonCamera3D.RIGHT_ARROW;
}
/**
* Makes the camera "look" around based on the mouse position
* @param $sensitivity Number 0 to 1 representing how sensible the camera is to the mouse movement.
* @param $maxRotationX Number representing the max horizontal rotation (0 to 360)
* @param $maxRotationY Number representing the max vertical rotation (0 to 360)
*
*/
public function look($sensitivity:Number = 0.5, $maxRotationX:Number = 90, $maxRotationY:Number = 90):void
{
sensitivity = $sensitivity;
maxRotationX = $maxRotationX;
maxRotationY = $maxRotationY;
var horizontalDegrees:Number = map(stageReference.mouseX, 0, stageReference.stageWidth, maxRotationX * -1, maxRotationX);
var verticalDegrees:Number = map(stageReference.mouseY, 0, stageReference.stageHeight, maxRotationY * -1, maxRotationY);
rotationX += (verticalDegrees - rotationX) * sensitivity;
rotationY += (horizontalDegrees - rotationY) * sensitivity;
}
/**
* Clears the camera
*
*/
public function clear():void
{
removeListeners();
for(var a:Number = 0; a<intervals.length; a++){
if(intervals[a] != undefined){
clearInterval(intervals[a]);
intervals[a] = null;
}
}
intervals = null;
stageReference = null;
}
private function addListeners():void
{
stageReference.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
stageReference.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
}
private function removeListeners():void
{
stageReference.removeEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
stageReference.removeEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
}
private function move($direction:String, $distance:Number):void
{
var distanceZ:Number
var distanceX:Number
switch ($direction) {
case "FORWARD" :
distanceZ = $distance * Math.cos(this.rotationY*(Math.PI/180));
distanceX = $distance * Math.sin(this.rotationY*(Math.PI/180));
Tweener.addTween(this, {z:z+distanceZ, x:x+distanceX, time:0.5, transition:"easeInOutStrong"});
break;
case "REVERSE" :
distanceZ = $distance * Math.cos(this.rotationY*(Math.PI/180));
distanceX = $distance * Math.sin(this.rotationY*(Math.PI/180));
Tweener.addTween(this, {z:z-distanceZ, x:x-distanceX, time:1, transition:"easeInOutStrong"});
break;
case "STRAFELEFT" :
distanceZ = $distance * Math.sin(this.rotationY*(Math.PI/180));
distanceX = $distance * Math.cos(this.rotationY*(Math.PI/180));
Tweener.addTween(this, {z:z+distanceZ, x:x-distanceX, time:1, transition:"easeInOutStrong"});
break;
case "STRAFERIGHT" :
distanceZ = $distance * Math.sin(this.rotationY*(Math.PI/180));
distanceX = $distance * Math.cos(this.rotationY*(Math.PI/180));
Tweener.addTween(this, {z:z-distanceZ, x:x+distanceX, time:1, transition:"easeInOutStrong"});
break;
}
}
private function map(value:Number, min1:Number, max1:Number, min2:Number, max2:Number):Number
{
return min2 + (max2 - min2) * (value - min1) / (max1 - min1);
}
/*
Properties
*/
/**
* Sets or returns the look sensitivity
* @return Number
*
*/
public function get sensitivity():Number { return _sensitivity }
public function set sensitivity(value:Number):void { _sensitivity = value; }
/**
* Sets or returns the maximum horizontal rotation
* @return Number
*
*/
public function get maxRotationX():Number { return _maxRotationX }
public function set maxRotationX(value:Number):void { _maxRotationX = value; }
/**
* Sets or returns the maximum vertical rotation
* @return Number
*
*/
public function get maxRotationY():Number { return _maxRotationY }
public function set maxRotationY(value:Number):void { _maxRotationY = value; }
/**
* Sets or returns a reference to the stage
* @return Number
*
*/
public function get stageReference():Stage { return _stageReference }
public function set stageReference(value:Stage):void { _stageReference = value; }
/**
* Sets or returns the movement increment
* @return Number
*
*/
public function get moveIncrement():Number { return _moveIncrement }
public function set moveIncrement(value:Number):void { _moveIncrement = value; }
/*
Handlers
*/
private function handleKeyDown(evt:KeyboardEvent):void
{
switch(evt.keyCode)
{
case FirstPersonCamera3D.FORWARD_KEY:
if(!movingForward){
forwardTrigger = setInterval(move, 100, "FORWARD", moveIncrement);
movingForward = true;
}
break;
case FirstPersonCamera3D.BACK_KEY:
if(!movingBack){
backTrigger = setInterval(move, 100, "REVERSE", moveIncrement);
movingBack = true;
}
break;
case FirstPersonCamera3D.LEFT_KEY:
if(!movingLeft){
leftTrigger = setInterval(move, 100, "STRAFELEFT", moveIncrement);
movingLeft = true;
}
break;
case FirstPersonCamera3D.RIGHT_KEY:
if(!movingRight){
rightTrigger = setInterval(move, 100, "STRAFERIGHT", moveIncrement);
movingRight = true;
}
break;
}
}
private function handleKeyUp(evt:KeyboardEvent):void
{
switch(evt.keyCode)
{
case FirstPersonCamera3D.FORWARD_KEY:
clearInterval(forwardTrigger);
movingForward = false;
break;
case FirstPersonCamera3D.BACK_KEY:
clearInterval(backTrigger);
movingBack = false;
break;
case FirstPersonCamera3D.LEFT_KEY:
clearInterval(leftTrigger);
movingLeft = false;
break;
case FirstPersonCamera3D.RIGHT_KEY:
clearInterval(rightTrigger);
movingRight = false;
break;
}
}
}
}
And here is the code used for the example above:
{
import flash.events.Event;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.special.CompositeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.view.BasicView;
public class CameraTest extends BasicView
{
private var firstPersonCamera:FirstPersonCamera3D;
public function CameraTest(viewportWidth:Number=640, viewportHeight:Number=480, scaleToStage:Boolean=true, interactive:Boolean=false, cameraType:String="Target")
{
super(640, 480, true, false);
setupCamera();
createObjects3D();
startRendering()
}
private function setupCamera():void
{
firstPersonCamera = new FirstPersonCamera3D();
firstPersonCamera.initialize(stage);
firstPersonCamera.y = 750;
firstPersonCamera.mapKeys();
}
private function createObjects3D():void
{
var cubeMat:WireframeMaterial = new WireframeMaterial(0xFF0000);
var colorMat:ColorMaterial = new ColorMaterial(0x00FF00);
var compMat:CompositeMaterial = new CompositeMaterial();
compMat.addMaterial(cubeMat);
compMat.addMaterial(colorMat);
var materialsList:MaterialsList = new MaterialsList({ all:compMat });
var alternate:String = "right";
for(var a:Number = 0; a<20; a++){
var cube:Cube = new Cube(materialsList);
cube.z = 1000 * a;
cube.y = 500;
if(alternate == "right"){
cube.x = 1000;
alternate = "left";
}else{
cube.x = -1000;
alternate = "right";
}
scene.addChild(cube);
}
var floor:Plane = new Plane(new WireframeMaterial(0xFFFFFF), 10000, 10000, 10, 10);
floor.rotationX = 90;
scene.addChild(floor);
}
override protected function onRenderTick(event:Event=null):void
{
firstPersonCamera.look(0.5, 180, 90);
renderer.renderScene(scene, firstPersonCamera, viewport);
}
}
}
Recent Comments