Game cam and eye banking, control schemes

- ShapeBaseData has two new properties.  cameraCanBank indicates that
the game object may bank its eye/camera, if supported by the object.
mountedImagesBank indicates that mounted images should bank with the
eye/camera in first person view.  Both default to false.
- Player supports 1st person eye and 3rd person camera banking when
making use of the new ExtendedMove class.
- Camera class supports banking when making use of the new ExtendedMove
class.
- GameConnection now has an idea of a control scheme.  This determines
how game objects should respond to input events.  A control scheme may
be set by either the server or client.  Current control schemes are:
-- Absolute rotation (likely though the ExtendedMove class)
-- Add relative yaw (from mouse or gamepad) to absolute rotation.
-- Add relative pitch (from mouse or gamepad) to absolute rotation.
- Player class supports the new control schemes when using the
ExtendedMove class.
- Camera class supports the new control scheme when using the
ExtendedMove class.
This commit is contained in:
DavidWyand-GG 2013-04-09 16:14:19 -04:00
parent 2805ec81c8
commit 660250cccf
10 changed files with 570 additions and 127 deletions

View file

@ -35,6 +35,12 @@
#include "math/mathUtils.h"
#include "math/mTransform.h"
#ifdef TORQUE_EXTENDED_MOVE
#include "T3D/gameBase/extended/extendedMove.h"
#endif
S32 Camera::smExtendedMovePosRotIndex = 0; // The ExtendedMove position/rotation index used for camera movements
#define MaxPitch 1.5706f
#define CameraRadius 0.05f;
@ -254,6 +260,7 @@ Camera::Camera()
{
mNetFlags.clear(Ghostable);
mTypeMask |= CameraObjectType;
mDataBlock = 0;
mDelta.pos = Point3F(0.0f, 0.0f, 100.0f);
mDelta.rot = Point3F(0.0f, 0.0f, 0.0f);
mDelta.posVec = mDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f);
@ -270,6 +277,9 @@ Camera::Camera()
mObservingClientObject = false;
mMode = FlyMode;
mLastAbsoluteYaw = 0.0f;
mLastAbsolutePitch = 0.0f;
// For NewtonFlyMode
mNewtonRotation = false;
mAngularVelocity.set(0.0f, 0.0f, 0.0f);
@ -301,7 +311,7 @@ Camera::~Camera()
bool Camera::onAdd()
{
if(!Parent::onAdd())
if(!Parent::onAdd() || !mDataBlock)
return false;
mObjBox.maxExtents = mObjScale;
@ -310,6 +320,31 @@ bool Camera::onAdd()
resetWorldBox();
addToScene();
scriptOnAdd();
return true;
}
//----------------------------------------------------------------------------
void Camera::onRemove()
{
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
bool Camera::onNewDataBlock( GameBaseData *dptr, bool reload )
{
mDataBlock = dynamic_cast<CameraData*>(dptr);
if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
return false;
scriptOnNewDataBlock();
return true;
}
@ -329,14 +364,6 @@ void Camera::onEditorDisable()
//----------------------------------------------------------------------------
void Camera::onRemove()
{
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
// check if the object needs to be observed through its own camera...
void Camera::getCameraTransform(F32* pos, MatrixF* mat)
{
@ -460,79 +487,154 @@ void Camera::processTick(const Move* move)
VectorF rotVec(0, 0, 0);
// process input/determine rotation vector
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
bool doStandardMove = true;
#ifdef TORQUE_EXTENDED_MOVE
GameConnection* con = getControllingClient();
// Work with an absolute rotation from the ExtendedMove class?
if(con && con->getControlSchemeAbsoluteRotation())
{
if(!strafeMode)
doStandardMove = false;
const ExtendedMove* emove = dynamic_cast<const ExtendedMove*>(move);
U32 emoveIndex = smExtendedMovePosRotIndex;
if(emoveIndex >= ExtendedMove::MaxPositionsRotations)
emoveIndex = 0;
if(emove->EulerBasedRotation[emoveIndex])
{
rotVec.x = move->pitch;
rotVec.z = move->yaw;
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
{
// Pitch
mRot.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch);
// Do we also include the relative pitch value?
if(con->getControlSchemeAddPitchToAbsRot() && !strafeMode)
{
F32 x = move->pitch;
if (x > M_PI_F)
x -= M_2PI_F;
mRot.x += x;
}
// Constrain the range of mRot.x
while (mRot.x < -M_PI_F)
mRot.x += M_2PI_F;
while (mRot.x > M_PI_F)
mRot.x -= M_2PI_F;
// Yaw
mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
// Do we also include the relative yaw value?
if(con->getControlSchemeAddYawToAbsRot() && !strafeMode)
{
F32 z = move->yaw;
if (z > M_PI_F)
z -= M_2PI_F;
mRot.z += z;
}
// Constrain the range of mRot.z
while (mRot.z < -M_PI_F)
mRot.z += M_2PI_F;
while (mRot.z > M_PI_F)
mRot.z -= M_2PI_F;
mLastAbsoluteYaw = emove->rotZ[emoveIndex];
mLastAbsolutePitch = emove->rotX[emoveIndex];
// Bank
mRot.y = emove->rotY[emoveIndex];
// Constrain the range of mRot.y
while (mRot.y > M_PI_F)
mRot.y -= M_2PI_F;
}
}
}
else if(virtualMode == TrackObjectMode && bool(mOrbitObject))
#endif
if(doStandardMove)
{
// orient the camera to face the object
Point3F objPos;
// If this is a shapebase, use its render eye transform
// to avoid jittering.
ShapeBase *shape = dynamic_cast<ShapeBase*>((GameBase*)mOrbitObject);
if( shape != NULL )
// process input/determine rotation vector
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
{
MatrixF ret;
shape->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
if(!strafeMode)
{
rotVec.x = move->pitch;
rotVec.z = move->yaw;
}
}
else if(virtualMode == TrackObjectMode && bool(mOrbitObject))
{
// orient the camera to face the object
Point3F objPos;
// If this is a shapebase, use its render eye transform
// to avoid jittering.
ShapeBase *shape = dynamic_cast<ShapeBase*>((GameBase*)mOrbitObject);
if( shape != NULL )
{
MatrixF ret;
shape->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
}
else
{
mOrbitObject->getWorldBox().getCenter(&objPos);
}
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
}
// apply rotation vector according to physics rules
if(mNewtonRotation)
{
const F32 force = mAngularForce;
const F32 drag = mAngularDrag;
VectorF acc(0.0f, 0.0f, 0.0f);
rotVec.x *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
rotVec.z *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
F32 rotVecL = rotVec.len();
if(rotVecL > 0)
{
acc = (rotVec * force / mMass) * TickSec;
}
// Accelerate
mAngularVelocity += acc;
// Drag
mAngularVelocity -= mAngularVelocity * drag * TickSec;
// Rotate
mRot += mAngularVelocity * TickSec;
clampPitchAngle(mRot.x);
}
else
{
mOrbitObject->getWorldBox().getCenter(&objPos);
mRot.x += rotVec.x;
mRot.z += rotVec.z;
clampPitchAngle(mRot.x);
}
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
}
// apply rotation vector according to physics rules
if(mNewtonRotation)
{
const F32 force = mAngularForce;
const F32 drag = mAngularDrag;
VectorF acc(0.0f, 0.0f, 0.0f);
rotVec.x *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
rotVec.z *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
F32 rotVecL = rotVec.len();
if(rotVecL > 0)
{
acc = (rotVec * force / mMass) * TickSec;
}
// Accelerate
mAngularVelocity += acc;
// Drag
mAngularVelocity -= mAngularVelocity * drag * TickSec;
// Rotate
mRot += mAngularVelocity * TickSec;
clampPitchAngle(mRot.x);
}
else
{
mRot.x += rotVec.x;
mRot.z += rotVec.z;
clampPitchAngle(mRot.x);
}
// Update position
@ -667,6 +769,13 @@ void Camera::processTick(const Move* move)
mDelta.rot = mRot;
mDelta.posVec = mDelta.posVec - mDelta.pos;
mDelta.rotVec = mDelta.rotVec - mDelta.rot;
for(U32 i=0; i<3; ++i)
{
if (mDelta.rotVec[i] > M_PI_F)
mDelta.rotVec[i] -= M_2PI_F;
else if (mDelta.rotVec[i] < -M_PI_F)
mDelta.rotVec[i] += M_2PI_F;
}
}
if(mustValidateEyePoint)
@ -793,7 +902,21 @@ void Camera::_setPosition(const Point3F& pos, const Point3F& rot)
zRot.set(EulerF(0.0f, 0.0f, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
if(mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, pos);
Parent::setTransform(temp);
mRot = rot;
@ -808,7 +931,21 @@ void Camera::setRotation(const Point3F& rot)
zRot.set(EulerF(0.0f, 0.0f, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
if(mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, getPosition());
Parent::setTransform(temp);
mRot = rot;
@ -821,8 +958,25 @@ void Camera::_setRenderPosition(const Point3F& pos,const Point3F& rot)
MatrixF xRot, zRot;
xRot.set(EulerF(rot.x, 0, 0));
zRot.set(EulerF(0, 0, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
// mDataBlock may not be defined yet as this method is called during
// SceneObject::onAdd().
if(mDataBlock && mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, pos);
Parent::setRenderTransform(temp);
}
@ -839,6 +993,11 @@ void Camera::writePacketData(GameConnection *connection, BitStream *bstream)
bstream->setCompressionPoint(pos);
mathWrite(*bstream, pos);
bstream->write(mRot.x);
if(bstream->writeFlag(mDataBlock->cameraCanBank))
{
// Include mRot.y to allow for camera banking
bstream->write(mRot.y);
}
bstream->write(mRot.z);
U32 writeMode = mMode;
@ -912,6 +1071,11 @@ void Camera::readPacketData(GameConnection *connection, BitStream *bstream)
mathRead(*bstream, &pos);
bstream->setCompressionPoint(pos);
bstream->read(&rot.x);
if(bstream->readFlag())
{
// Include rot.y to allow for camera banking
bstream->read(&rot.y);
}
bstream->read(&rot.z);
GameBase* obj = 0;
@ -1184,6 +1348,11 @@ void Camera::consoleInit()
"- Fly Mode\n"
"- Overhead Mode\n"
"@ingroup BaseCamera\n");
// ExtendedMove support
Con::addVariable("$camera::extendedMovePosRotIndex", TypeS32, &smExtendedMovePosRotIndex,
"@brief The ExtendedMove position/rotation index used for camera movements.\n\n"
"@ingroup BaseCamera\n");
}
//-----------------------------------------------------------------------------