123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "T3D/components/physics/playerControllercomponent.h"
- #include "platform/platform.h"
- #include "console/consoleTypes.h"
- #include "core/util/safeDelete.h"
- #include "core/resourceManager.h"
- #include "core/stream/fileStream.h"
- #include "console/consoleTypes.h"
- #include "console/consoleObject.h"
- #include "ts/tsShapeInstance.h"
- #include "core/stream/bitStream.h"
- #include "gfx/gfxTransformSaver.h"
- #include "console/engineAPI.h"
- #include "lighting/lightQuery.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "collision/collision.h"
- #include "T3D/physics/physicsPlayer.h"
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/components/collision/collisionInterfaces.h"
- #include "T3D/trigger.h"
- #include "T3D/components/collision/collisionTrigger.h"
- // Movement constants
- static F32 sVerticalStepDot = 0.173f; // 80
- static F32 sMinFaceDistance = 0.01f;
- static F32 sTractionDistance = 0.04f;
- static F32 sNormalElasticity = 0.01f;
- static U32 sMoveRetryCount = 5;
- static F32 sMaxImpulseVelocity = 200.0f;
- //////////////////////////////////////////////////////////////////////////
- // Callbacks
- IMPLEMENT_CALLBACK(PlayerControllerComponent, updateMove, void, (PlayerControllerComponent* obj), (obj),
- "Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n"
- "@param obj the Player object\n");
- //////////////////////////////////////////////////////////////////////////
- // Constructor/Destructor
- //////////////////////////////////////////////////////////////////////////
- PlayerControllerComponent::PlayerControllerComponent() : Component()
- {
- addComponentField("isStatic", "If enabled, object will not simulate physics", "bool", "0", "");
- addComponentField("gravity", "The direction of gravity affecting this object, as a vector", "vector", "0 0 -9", "");
- addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", "");
- addComponentField("mass", "The mass of the object", "float", "1", "");
- mBuoyancy = 0.f;
- mFriction = 0.3f;
- mElasticity = 0.4f;
- mMaxVelocity = 3000.f;
- mSticky = false;
-
- mFalling = false;
- mSwimming = false;
- mInWater = false;
- mDelta.pos = mDelta.posVec = Point3F::Zero;
- mDelta.warpTicks = mDelta.warpCount = 0;
- mDelta.rot[0].identity();
- mDelta.rot[1].identity();
- mDelta.dt = 1;
- mUseDirectMoveInput = false;
- mFriendlyName = "Player Controller";
- mComponentType = "Physics";
- mDescription = getDescriptionText("A general-purpose physics player controller.");
- mNetFlags.set(Ghostable | ScopeAlways);
- mMass = 9.0f; // from ShapeBase
- mDrag = 1.0f; // from ShapeBase
- maxStepHeight = 1.0f;
- moveSurfaceAngle = 60.0f;
- contactSurfaceAngle = 85.0f;
- fallingSpeedThreshold = -10.0f;
- horizMaxSpeed = 80.0f;
- horizMaxAccel = 100.0f;
- horizResistSpeed = 38.0f;
- horizResistFactor = 1.0f;
- upMaxSpeed = 80.0f;
- upMaxAccel = 100.0f;
- upResistSpeed = 38.0f;
- upResistFactor = 1.0f;
- // Air control
- airControl = 0.0f;
- //Grav mod
- mGravityMod = 1;
- mInputVelocity = Point3F(0, 0, 0);
- mPhysicsRep = NULL;
- mPhysicsWorld = NULL;
- }
- PlayerControllerComponent::~PlayerControllerComponent()
- {
- for (S32 i = 0; i < mFields.size(); ++i)
- {
- ComponentField &field = mFields[i];
- SAFE_DELETE_ARRAY(field.mFieldDescription);
- }
- SAFE_DELETE_ARRAY(mDescription);
- }
- IMPLEMENT_CO_NETOBJECT_V1(PlayerControllerComponent);
- //////////////////////////////////////////////////////////////////////////
- bool PlayerControllerComponent::onAdd()
- {
- if (!Parent::onAdd())
- return false;
- return true;
- }
- void PlayerControllerComponent::onRemove()
- {
- Parent::onRemove();
- SAFE_DELETE(mPhysicsRep);
- }
- void PlayerControllerComponent::onComponentAdd()
- {
- Parent::onComponentAdd();
- updatePhysics();
- }
- void PlayerControllerComponent::componentAddedToOwner(Component *comp)
- {
- if (comp->getId() == getId())
- return;
- //test if this is a shape component!
- CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
- if (collisionInterface)
- {
- collisionInterface->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
- mOwnerCollisionInterface = collisionInterface;
- updatePhysics();
- }
- }
- void PlayerControllerComponent::componentRemovedFromOwner(Component *comp)
- {
- if (comp->getId() == getId()) //?????????
- return;
- //test if this is a shape component!
- CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
- if (collisionInterface)
- {
- collisionInterface->onCollisionChanged.remove(this, &PlayerControllerComponent::updatePhysics);
- mOwnerCollisionInterface = NULL;
- updatePhysics();
- }
- }
- void PlayerControllerComponent::updatePhysics(PhysicsCollision *collision)
- {
- if (!PHYSICSMGR)
- return;
- mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
- //first, clear the old physRep
- SAFE_DELETE(mPhysicsRep);
- mPhysicsRep = PHYSICSMGR->createPlayer();
- F32 runSurfaceCos = mCos(mDegToRad(moveSurfaceAngle));
- Point3F ownerBounds = mOwner->getObjBox().getExtents() * mOwner->getScale();
- mPhysicsRep->init("", ownerBounds, runSurfaceCos, maxStepHeight, mOwner, mPhysicsWorld);
- mPhysicsRep->setTransform(mOwner->getTransform());
- }
- void PlayerControllerComponent::initPersistFields()
- {
- Parent::initPersistFields();
- addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), "");
- addField("useDirectMoveInput", TypePoint3F, Offset(mUseDirectMoveInput, PlayerControllerComponent), "");
- }
- U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- return retMask;
- }
- void PlayerControllerComponent::unpackUpdate(NetConnection *con, BitStream *stream)
- {
- Parent::unpackUpdate(con, stream);
- }
- //
- void PlayerControllerComponent::processTick()
- {
- Parent::processTick();
- if (!isServerObject() || !isActive())
- return;
- // Warp to catch up to server
- if (mDelta.warpCount < mDelta.warpTicks)
- {
- mDelta.warpCount++;
- // Set new pos.
- mDelta.pos = mOwner->getPosition();
- mDelta.pos += mDelta.warpOffset;
- mDelta.rot[0] = mDelta.rot[1];
- mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks);
-
- MatrixF trans;
- mDelta.rot[1].setMatrix(&trans);
- trans.setPosition(mDelta.pos);
- mOwner->setTransform(trans);
- // Pos backstepping
- mDelta.posVec.x = -mDelta.warpOffset.x;
- mDelta.posVec.y = -mDelta.warpOffset.y;
- mDelta.posVec.z = -mDelta.warpOffset.z;
- }
- else
- {
- // Save current rigid state interpolation
- mDelta.posVec = mOwner->getPosition();
- mDelta.rot[0] = mOwner->getTransform();
- updateMove();
- updatePos(TickSec);
- // Wrap up interpolation info
- mDelta.pos = mOwner->getPosition();
- mDelta.posVec -= mOwner->getPosition();
- mDelta.rot[1] = mOwner->getTransform();
- // Update container database
- setTransform(mOwner->getTransform());
-
- setMaskBits(VelocityMask);
- setMaskBits(PositionMask);
- }
- }
- void PlayerControllerComponent::interpolateTick(F32 dt)
- {
- }
- void PlayerControllerComponent::ownerTransformSet(MatrixF *mat)
- {
- if (mPhysicsRep)
- mPhysicsRep->setTransform(mOwner->getTransform());
- }
- void PlayerControllerComponent::setTransform(const MatrixF& mat)
- {
- mOwner->setTransform(mat);
- setMaskBits(UpdateMask);
- }
- //
- void PlayerControllerComponent::updateMove()
- {
- if (!PHYSICSMGR)
- return;
- Move *move = &mOwner->lastMove;
- //If we're not set to use mUseDirectMoveInput, then we allow for an override in the form of mInputVelocity
- if (!mUseDirectMoveInput)
- {
- move->x = mInputVelocity.x;
- move->y = mInputVelocity.y;
- move->z = mInputVelocity.z;
- }
- // Is waterCoverage high enough to be 'swimming'?
- {
- bool swimming = mOwner->getContainerInfo().waterCoverage > 0.65f/* && canSwim()*/;
- if (swimming != mSwimming)
- {
- mSwimming = swimming;
- }
- }
- // Update current orientation
- bool doStandardMove = true;
- GameConnection* con = mOwner->getControllingClient();
- #ifdef TORQUE_EXTENDED_MOVE
- // Work with an absolute rotation from the ExtendedMove class?
- if (con && con->getControlSchemeAbsoluteRotation())
- {
- doStandardMove = false;
- const ExtendedMove* emove = dynamic_cast<const ExtendedMove*>(move);
- U32 emoveIndex = smExtendedMoveHeadPosRotIndex;
- if (emoveIndex >= ExtendedMove::MaxPositionsRotations)
- emoveIndex = 0;
- if (emove->EulerBasedRotation[emoveIndex])
- {
- // Head pitch
- mHead.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch);
- // Do we also include the relative yaw value?
- if (con->getControlSchemeAddPitchToAbsRot())
- {
- F32 x = move->pitch;
- if (x > M_PI_F)
- x -= M_2PI_F;
- mHead.x += x;
- }
- // Constrain the range of mHead.x
- while (mHead.x < -M_PI_F)
- mHead.x += M_2PI_F;
- while (mHead.x > M_PI_F)
- mHead.x -= M_2PI_F;
- // Rotate (heading) head or body?
- if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
- {
- // Rotate head
- mHead.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
- // Do we also include the relative yaw value?
- if (con->getControlSchemeAddYawToAbsRot())
- {
- F32 z = move->yaw;
- if (z > M_PI_F)
- z -= M_2PI_F;
- mHead.z += z;
- }
- // Constrain the range of mHead.z
- while (mHead.z < 0.0f)
- mHead.z += M_2PI_F;
- while (mHead.z > M_2PI_F)
- mHead.z -= M_2PI_F;
- }
- else
- {
- // Rotate body
- mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
- // Do we also include the relative yaw value?
- if (con->getControlSchemeAddYawToAbsRot())
- {
- 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 < 0.0f)
- mRot.z += M_2PI_F;
- while (mRot.z > M_2PI_F)
- mRot.z -= M_2PI_F;
- }
- mLastAbsoluteYaw = emove->rotZ[emoveIndex];
- mLastAbsolutePitch = emove->rotX[emoveIndex];
- // Head bank
- mHead.y = emove->rotY[emoveIndex];
- // Constrain the range of mHead.y
- while (mHead.y > M_PI_F)
- mHead.y -= M_2PI_F;
- }
- }
- #endif
- MatrixF zRot;
- zRot.set(EulerF(0.0f, 0.0f, mOwner->getRotation().asEulerF().z));
- // Desired move direction & speed
- VectorF moveVec;
- F32 moveSpeed = mInputVelocity.len();
- zRot.getColumn(0, &moveVec);
- moveVec *= move->x;
- VectorF tv;
- zRot.getColumn(1, &tv);
- moveVec += tv * move->y;
- // Acceleration due to gravity
- VectorF acc(mPhysicsWorld->getGravity() * mGravityMod * TickSec);
- // Determine ground contact normal. Only look for contacts if
- // we can move and aren't mounted.
- mContactInfo.contactNormal = VectorF::Zero;
- mContactInfo.jump = false;
- mContactInfo.run = false;
- bool jumpSurface = false, runSurface = false;
- if (!mOwner->isMounted())
- findContact(&mContactInfo.run, &mContactInfo.jump, &mContactInfo.contactNormal);
- if (mContactInfo.jump)
- mJumpSurfaceNormal = mContactInfo.contactNormal;
- // If we don't have a runSurface but we do have a contactNormal,
- // then we are standing on something that is too steep.
- // Deflect the force of gravity by the normal so we slide.
- // We could also try aligning it to the runSurface instead,
- // but this seems to work well.
- if (!mContactInfo.run && !mContactInfo.contactNormal.isZero())
- acc = (acc - 2 * mContactInfo.contactNormal * mDot(acc, mContactInfo.contactNormal));
- // Acceleration on run surface
- if (mContactInfo.run && !mSwimming)
- {
- mContactTimer = 0;
- VectorF pv = moveVec;
- // Adjust the player's requested dir. to be parallel
- // to the contact surface.
- F32 pvl = pv.len();
- // Convert to acceleration
- if (pvl)
- pv *= moveSpeed / pvl;
- VectorF runAcc = pv - (mVelocity + acc);
- F32 runSpeed = runAcc.len();
- // Clamp acceleration, player also accelerates faster when
- // in his hard landing recover state.
- F32 maxAcc;
- maxAcc = (horizMaxAccel / mMass) * TickSec;
- if (runSpeed > maxAcc)
- runAcc *= maxAcc / runSpeed;
- acc += runAcc;
- }
- else if (!mSwimming && airControl > 0.0f)
- {
- VectorF pv;
- pv = moveVec;
- F32 pvl = pv.len();
- if (pvl)
- pv *= moveSpeed / pvl;
- VectorF runAcc = pv - (mVelocity + acc);
- runAcc.z = 0;
- runAcc.x = runAcc.x * airControl;
- runAcc.y = runAcc.y * airControl;
- F32 runSpeed = runAcc.len();
- // We don't test for sprinting when performing air control
- F32 maxAcc = (horizMaxAccel / mMass) * TickSec * 0.3f;
- if (runSpeed > maxAcc)
- runAcc *= maxAcc / runSpeed;
- acc += runAcc;
- // There are no special air control animations
- // so... increment this unless you really want to
- // play the run anims in the air.
- mContactTimer++;
- }
- else if (mSwimming)
- {
- // Remove acc into contact surface (should only be gravity)
- // Clear out floating point acc errors, this will allow
- // the player to "rest" on the ground.
- F32 vd = -mDot(acc, mContactInfo.contactNormal);
- if (vd > 0.0f)
- {
- VectorF dv = mContactInfo.contactNormal * (vd + 0.002f);
- acc += dv;
- if (acc.len() < 0.0001f)
- acc.set(0.0f, 0.0f, 0.0f);
- }
- // get the head pitch and add it to the moveVec
- // This more accurate swim vector calc comes from Matt Fairfax
- MatrixF xRot, zRot;
- xRot.set(EulerF(mOwner->getRotation().asEulerF().x, 0, 0));
- zRot.set(EulerF(0, 0, mOwner->getRotation().asEulerF().z));
- MatrixF rot;
- rot.mul(zRot, xRot);
- rot.getColumn(0, &moveVec);
- moveVec *= move->x;
- VectorF tv;
- rot.getColumn(1, &tv);
- moveVec += tv * move->y;
- rot.getColumn(2, &tv);
- moveVec += tv * move->z;
- // Force a 0 move if there is no energy, and only drain
- // move energy if we're moving.
- VectorF swimVec = moveVec;
- // If we are swimming but close enough to the shore/ground
- // we can still have a surface-normal. In this case align the
- // velocity to the normal to make getting out of water easier.
- moveVec.normalize();
- F32 isSwimUp = mDot(moveVec, mContactInfo.contactNormal);
- if (!mContactInfo.contactNormal.isZero() && isSwimUp < 0.1f)
- {
- F32 pvl = swimVec.len();
- if (pvl)
- {
- VectorF nn;
- mCross(swimVec, VectorF(0.0f, 0.0f, 1.0f), &nn);
- nn *= 1.0f / pvl;
- VectorF cv = mContactInfo.contactNormal;
- cv -= nn * mDot(nn, cv);
- swimVec -= cv * mDot(swimVec, cv);
- }
- }
- F32 swimVecLen = swimVec.len();
- // Convert to acceleration.
- if (swimVecLen)
- swimVec *= moveSpeed / swimVecLen;
- VectorF swimAcc = swimVec - (mVelocity + acc);
- F32 swimSpeed = swimAcc.len();
- // Clamp acceleration.
- F32 maxAcc = (horizMaxAccel / mMass) * TickSec;
- if (swimSpeed > maxAcc)
- swimAcc *= maxAcc / swimSpeed;
- acc += swimAcc;
- mContactTimer++;
- }
- else
- mContactTimer++;
- // Add in force from physical zones...
- acc += (mOwner->getContainerInfo().appliedForce / mMass) * TickSec;
- // Adjust velocity with all the move & gravity acceleration
- // TG: I forgot why doesn't the TickSec multiply happen here...
- mVelocity += acc;
- // apply horizontal air resistance
- F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
- if (hvel > horizResistSpeed)
- {
- F32 speedCap = hvel;
- if (speedCap > horizMaxSpeed)
- speedCap = horizMaxSpeed;
- speedCap -= horizResistFactor * TickSec * (speedCap - horizResistSpeed);
- F32 scale = speedCap / hvel;
- mVelocity.x *= scale;
- mVelocity.y *= scale;
- }
- if (mVelocity.z > upResistSpeed)
- {
- if (mVelocity.z > upMaxSpeed)
- mVelocity.z = upMaxSpeed;
- mVelocity.z -= upResistFactor * TickSec * (mVelocity.z - upResistSpeed);
- }
- // Apply drag
- mVelocity -= mVelocity * mDrag * TickSec;
- // Clamp very small velocity to zero
- if (mVelocity.isZero())
- mVelocity = Point3F::Zero;
- // If we are not touching anything and have sufficient -z vel,
- // we are falling.
- if (mContactInfo.run)
- {
- mFalling = false;
- }
- else
- {
- VectorF vel;
- mOwner->getWorldToObj().mulV(mVelocity, &vel);
- mFalling = vel.z < fallingSpeedThreshold;
- }
- // Enter/Leave Liquid
- if (!mInWater && mOwner->getContainerInfo().waterCoverage > 0.0f)
- {
- mInWater = true;
- }
- else if (mInWater && mOwner->getContainerInfo().waterCoverage <= 0.0f)
- {
- mInWater = false;
- }
- }
- void PlayerControllerComponent::updatePos(const F32 travelTime)
- {
- if (!PHYSICSMGR)
- return;
- PROFILE_SCOPE(PlayerControllerComponent_UpdatePos);
- Point3F newPos;
- Collision col;
- dMemset(&col, 0, sizeof(col));
- static CollisionList collisionList;
- collisionList.clear();
- newPos = mPhysicsRep->move(mVelocity * travelTime, collisionList);
- bool haveCollisions = false;
- bool wasFalling = mFalling;
- if (collisionList.getCount() > 0)
- {
- mFalling = false;
- haveCollisions = true;
- //TODO: clean this up so the phys component doesn't have to tell the col interface to do this
- CollisionInterface* colInterface = mOwner->getComponent<CollisionInterface>();
- if (colInterface)
- {
- colInterface->handleCollisionList(collisionList, mVelocity);
- }
- }
- if (haveCollisions)
- {
- // Pick the collision that most closely matches our direction
- VectorF velNormal = mVelocity;
- velNormal.normalizeSafe();
- const Collision *collision = &collisionList[0];
- F32 collisionDot = mDot(velNormal, collision->normal);
- const Collision *cp = collision + 1;
- const Collision *ep = collision + collisionList.getCount();
- for (; cp != ep; cp++)
- {
- F32 dp = mDot(velNormal, cp->normal);
- if (dp < collisionDot)
- {
- collisionDot = dp;
- collision = cp;
- }
- }
- // Modify our velocity based on collisions
- for (U32 i = 0; i<collisionList.getCount(); ++i)
- {
- F32 bd = -mDot(mVelocity, collisionList[i].normal);
- VectorF dv = collisionList[i].normal * (bd + sNormalElasticity);
- mVelocity += dv;
- }
- // Store the last collision for use later on. The handle collision
- // code only expects a single collision object.
- if (collisionList.getCount() > 0)
- col = collisionList[collisionList.getCount() - 1];
- // We'll handle any player-to-player collision, and the last collision
- // with other obejct types.
- for (U32 i = 0; i<collisionList.getCount(); ++i)
- {
- Collision& colCheck = collisionList[i];
- if (colCheck.object)
- {
- col = colCheck;
- }
- }
- }
-
- MatrixF newMat;
- newMat.setPosition(newPos);
- mPhysicsRep->setTransform(newMat);
- mOwner->setPosition(newPos);
- }
- //
- void PlayerControllerComponent::setVelocity(const VectorF& vel)
- {
- mVelocity = vel;
- // Clamp against the maximum velocity.
- if (mMaxVelocity > 0)
- {
- F32 len = mVelocity.magnitudeSafe();
- if (len > mMaxVelocity)
- {
- Point3F excess = mVelocity * (1.0f - (mMaxVelocity / len));
- mVelocity -= excess;
- }
- }
- setMaskBits(VelocityMask);
- }
- void PlayerControllerComponent::findContact(bool *run, bool *jump, VectorF *contactNormal)
- {
- SceneObject *contactObject = NULL;
- Vector<SceneObject*> overlapObjects;
- mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects);
- F32 vd = (*contactNormal).z;
- *run = vd > mCos(mDegToRad(moveSurfaceAngle));
- *jump = vd > mCos(mDegToRad(contactSurfaceAngle));
- // Check for triggers
- for (U32 i = 0; i < overlapObjects.size(); i++)
- {
- SceneObject *obj = overlapObjects[i];
- U32 objectMask = obj->getTypeMask();
- // Check: triggers, corpses and items...
- //
- if (objectMask & TriggerObjectType)
- {
- if (Trigger* pTrigger = dynamic_cast<Trigger*>(obj))
- {
- pTrigger->potentialEnterObject(mOwner);
- }
- else if (CollisionTrigger* pTriggerEx = dynamic_cast<CollisionTrigger*>(obj))
- {
- if (pTriggerEx)
- pTriggerEx->potentialEnterObject(mOwner);
- }
- //Add any other custom classes and the sort here that should be filtered against
- /*else if (TriggerExample* pTriggerEx = dynamic_cast<TriggerExample*>(obj))
- {
- if (pTriggerEx)
- pTriggerEx->potentialEnterObject(mOwner);
- }*/
- }
- }
- mContactInfo.contacted = contactObject != NULL;
- mContactInfo.contactObject = contactObject;
- if (mContactInfo.contacted)
- mContactInfo.contactNormal = *contactNormal;
- }
- void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec)
- {
- AssertFatal(!mIsNaN(vec), "Player::applyImpulse() - The vector is NaN!");
- // Players ignore angular velocity
- VectorF vel;
- vel.x = vec.x / getMass();
- vel.y = vec.y / getMass();
- vel.z = vec.z / getMass();
- // Make sure the impulse isn't too bigg
- F32 len = vel.magnitudeSafe();
- if (len > sMaxImpulseVelocity)
- {
- Point3F excess = vel * (1.0f - (sMaxImpulseVelocity / len));
- vel -= excess;
- }
- setVelocity(mVelocity + vel);
- }
- DefineEngineMethod(PlayerControllerComponent, applyImpulse, bool, (Point3F pos, VectorF vel), ,
- "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
- "@param pos impulse world position\n"
- "@param vel impulse velocity (impulse force F = m * v)\n"
- "@return Always true\n"
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- object->applyImpulse(pos, vel);
- return true;
- }
- DefineEngineMethod(PlayerControllerComponent, getContactNormal, Point3F, (), ,
- "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
- "@param pos impulse world position\n"
- "@param vel impulse velocity (impulse force F = m * v)\n"
- "@return Always true\n"
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- return object->getContactNormal();
- }
- DefineEngineMethod(PlayerControllerComponent, getContactObject, SceneObject*, (), ,
- "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
- "@param pos impulse world position\n"
- "@param vel impulse velocity (impulse force F = m * v)\n"
- "@return Always true\n"
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- return object->getContactObject();
- }
- DefineEngineMethod(PlayerControllerComponent, isContacted, bool, (), ,
- "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
- "@param pos impulse world position\n"
- "@param vel impulse velocity (impulse force F = m * v)\n"
- "@return Always true\n"
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- return object->isContacted();
- }
|