mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-12 19:31:41 +00:00
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:
parent
2805ec81c8
commit
660250cccf
10 changed files with 570 additions and 127 deletions
|
|
@ -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");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue