Browse Source
plMovementStrategy classes have been reworked and completely replace all plAvatarControllers. While based on the old implementation, plPhysicalControllerCore has essentially been rewritten. Remnants of long gone physical "actions" have been removed. 4 files removed - plAVCallbackAction.h & plAVCallbackAction.cpp plAntiGravAction.h & plAntiGravAction.cpp This revision will not compile, requires new plPXPhysicalControllerCore implementation.
33 changed files with 990 additions and 2327 deletions
@ -1,171 +0,0 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools |
||||
Copyright (C) 2011 Cyan Worlds, Inc. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7 |
||||
|
||||
If you modify this Program, or any covered work, by linking or |
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||
(or a modified version of those libraries), |
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||
licensors of this Program grant you additional |
||||
permission to convey the resulting work. Corresponding Source for a |
||||
non-source form of such a combination shall include the source code for |
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||
work. |
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||
or by snail mail at: |
||||
Cyan Worlds, Inc. |
||||
14617 N Newport Hwy |
||||
Mead, WA 99021 |
||||
|
||||
*==LICENSE==*/ |
||||
#if 0 |
||||
// havok first
|
||||
#include <hkdynamics/entity/rigidbody.h> |
||||
#include <hkdynamics/world/subspace.h> |
||||
|
||||
#include "plAntiGravAction.h" |
||||
|
||||
#include "pnSceneObject/plSceneObject.h" |
||||
#include "plHavok1/plHKPhysical.h" |
||||
#include "plAvatar/plSwimRegion.h" |
||||
#include "hsTimer.h" |
||||
|
||||
// This is meant to be a specific physicsAction for the swim behavior
|
||||
plAntiGravAction::plAntiGravAction(plHKPhysical *physical, plAGApplicator *rootApp) :
|
||||
plAnimatedCallbackAction(physical, rootApp), |
||||
fOnGround(false), |
||||
fBuoyancy(1.f), |
||||
fSurfaceHeight(0.f), |
||||
fCurrentRegion(nil), |
||||
fHadContacts(false) |
||||
{ |
||||
} |
||||
|
||||
plSimDefs::ActionType plAntiGravAction::GetType() |
||||
{ |
||||
return plSimDefs::kAntiGravAction; |
||||
} |
||||
|
||||
void plAntiGravAction::apply(Havok::Subspace &space, Havok::hkTime time) |
||||
{ |
||||
double elapsed = time.asDouble() - getRefresh().asDouble(); |
||||
setRefresh(time); |
||||
|
||||
IAdjustBuoyancy();
|
||||
Havok::RigidBody *body = fPhysical->GetBody(); |
||||
float mass = body->getMass(); |
||||
Havok::Vector3 gravity = space.getGravity(); |
||||
Havok::Vector3 force = -gravity * (mass * fBuoyancy); |
||||
body->applyForce(force); |
||||
|
||||
hsVector3 vel; |
||||
fPhysical->GetLinearVelocitySim(vel); |
||||
fAnimPosVel.fZ = vel.fZ; |
||||
|
||||
hsVector3 linCurrent(0.f, 0.f, 0.f); |
||||
float angCurrent = 0.f; |
||||
if (fCurrentRegion != nil) |
||||
fCurrentRegion->GetCurrent(fPhysical, linCurrent, angCurrent, (float)elapsed); |
||||
|
||||
int numContacts = fPhysical->GetNumContacts(); |
||||
fHadContacts = (numContacts > 0); |
||||
|
||||
const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
|
||||
fOnGround = false; |
||||
int i; |
||||
for (i = 0; i < numContacts; i++) |
||||
{ |
||||
const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i);
|
||||
float dotUp = straightUp.dot(contact->m_normal); |
||||
if (dotUp > .5) |
||||
{ |
||||
fOnGround = true; |
||||
break; |
||||
} |
||||
}
|
||||
|
||||
fPhysical->SetLinearVelocitySim(fAnimPosVel + linCurrent); |
||||
fPhysical->SetAngularVelocitySim(hsVector3(0.f, 0.f, fAnimAngVel + fTurnStr + angCurrent));
|
||||
} |
||||
|
||||
void plAntiGravAction::SetSurface(plSwimRegionInterface *region, float surfaceHeight) |
||||
{ |
||||
fCurrentRegion = region; |
||||
if (region != nil) |
||||
fSurfaceHeight = surfaceHeight; |
||||
} |
||||
|
||||
void plAntiGravAction::IAdjustBuoyancy() |
||||
{ |
||||
// "surface depth" refers to the depth our handle object should be below
|
||||
// the surface for the avatar to be "at the surface"
|
||||
static const float surfaceDepth = 4.0f; |
||||
// 1.0 = neutral buoyancy
|
||||
// 0 = no buoyancy (normal gravity)
|
||||
// 2.0 = opposite of gravity, floating upwards
|
||||
static const float buoyancyAtSurface = 1.0f; |
||||
|
||||
if (fCurrentRegion == nil) |
||||
{ |
||||
fBuoyancy = 0.f; |
||||
return; |
||||
} |
||||
|
||||
hsMatrix44 l2w, w2l; |
||||
fPhysical->GetTransform(l2w, w2l); |
||||
float depth = fSurfaceHeight - surfaceDepth - l2w.GetTranslate().fZ;
|
||||
if (depth < -1) |
||||
fBuoyancy = 0.f; // Same as being above ground. Plain old gravity.
|
||||
else if (depth < 0) |
||||
fBuoyancy = 1 + depth; |
||||
else
|
||||
{ |
||||
hsVector3 vel; |
||||
fPhysical->GetLinearVelocitySim(vel); |
||||
if (vel.fZ > 0) |
||||
{ |
||||
if (vel.fZ > fCurrentRegion->fMaxUpwardVel) |
||||
{ |
||||
vel.fZ = fCurrentRegion->fMaxUpwardVel; |
||||
fPhysical->SetLinearVelocitySim(vel); |
||||
} |
||||
else |
||||
{ |
||||
if (depth > 1) |
||||
fBuoyancy = fCurrentRegion->fUpBuoyancy; |
||||
else |
||||
fBuoyancy = (fCurrentRegion->fUpBuoyancy - 1) * depth + 1; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (depth > 1) |
||||
fBuoyancy = fCurrentRegion->fDownBuoyancy; |
||||
else |
||||
fBuoyancy = (fCurrentRegion->fDownBuoyancy - 1) * depth + 1; |
||||
} |
||||
}
|
||||
} |
||||
|
||||
#endif |
@ -1,79 +0,0 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools |
||||
Copyright (C) 2011 Cyan Worlds, Inc. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7 |
||||
|
||||
If you modify this Program, or any covered work, by linking or |
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||
(or a modified version of those libraries), |
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||
licensors of this Program grant you additional |
||||
permission to convey the resulting work. Corresponding Source for a |
||||
non-source form of such a combination shall include the source code for |
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||
work. |
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||
or by snail mail at: |
||||
Cyan Worlds, Inc. |
||||
14617 N Newport Hwy |
||||
Mead, WA 99021 |
||||
|
||||
*==LICENSE==*/ |
||||
#if 0//ndef PL_ANTI_GRAV_ACTION_H
|
||||
#define PL_ANTI_GRAV_ACTION_H |
||||
|
||||
#include "plAvCallbackAction.h" |
||||
|
||||
class plSwimRegionInterface; |
||||
|
||||
class plAntiGravAction : public plAnimatedCallbackAction |
||||
{ |
||||
public: |
||||
plAntiGravAction(plHKPhysical *physical, plAGApplicator *rootApp); |
||||
|
||||
/** Return the type of the action as defined in the enum plSimDefs::ActionType.
|
||||
Used to retrieve actions by entity/type indexing, and to |
||||
reuse actions that can be shared between entities. */ |
||||
virtual plSimDefs::ActionType GetType(); |
||||
|
||||
/** Called by Havok at substep frequency. */ |
||||
void apply(Havok::Subspace &s, Havok::hkTime time); |
||||
|
||||
void SetSurface(plSwimRegionInterface *region, float surfaceHeight); |
||||
float GetBuoyancy() { return fBuoyancy; } |
||||
bool IsOnGround() { return fOnGround; } |
||||
bool HadContacts() { return fHadContacts; } |
||||
|
||||
protected: |
||||
void IAdjustBuoyancy(); |
||||
|
||||
bool fOnGround; |
||||
bool fHadContacts; |
||||
float fBuoyancy; |
||||
float fSurfaceHeight; |
||||
plSwimRegionInterface *fCurrentRegion; |
||||
}; |
||||
|
||||
#endif |
||||
|
||||
|
@ -1,579 +0,0 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools |
||||
Copyright (C) 2011 Cyan Worlds, Inc. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7 |
||||
|
||||
If you modify this Program, or any covered work, by linking or |
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||
(or a modified version of those libraries), |
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||
licensors of this Program grant you additional |
||||
permission to convey the resulting work. Corresponding Source for a |
||||
non-source form of such a combination shall include the source code for |
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||
work. |
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||
or by snail mail at: |
||||
Cyan Worlds, Inc. |
||||
14617 N Newport Hwy |
||||
Mead, WA 99021 |
||||
|
||||
*==LICENSE==*/ |
||||
#include "plAvCallbackAction.h" |
||||
#include "plMessage/plLOSHitMsg.h" |
||||
|
||||
#include "plArmatureMod.h" // for LOS enum type |
||||
#include "plMatrixChannel.h" |
||||
#include "hsTimer.h" |
||||
#include "plPhysicalControllerCore.h" |
||||
|
||||
// Generic geom utils.
|
||||
static bool LinearVelocity(hsVector3 &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat); |
||||
static void AngularVelocity(float &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat); |
||||
static float AngleRad2d (float x1, float y1, float x3, float y3); |
||||
inline hsVector3 GetYAxis(hsMatrix44 &mat) |
||||
{ |
||||
return hsVector3(mat.fMap[1][0], mat.fMap[1][1], mat.fMap[1][2]); |
||||
} |
||||
|
||||
plAnimatedController::plAnimatedController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller) |
||||
: fRootObject(rootObject) |
||||
, fRootApp(rootApp) |
||||
, fController(controller) |
||||
, fTurnStr(0.f) |
||||
, fAnimAngVel(0.f) |
||||
, fAnimPosVel(0.f, 0.f, 0.f) |
||||
{ |
||||
}
|
||||
|
||||
void plAnimatedController::RecalcVelocity(double timeNow, double timePrev, bool useAnim /* = true */) |
||||
{ |
||||
if (useAnim) |
||||
{ |
||||
// while you may think it would be correct to cache this,
|
||||
// what we're actually asking is "what would the animation's
|
||||
// position be at the previous time given its *current*
|
||||
// parameters (particularly blends)"
|
||||
hsMatrix44 prevMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timePrev, true);
|
||||
hsMatrix44 curMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timeNow, true); |
||||
|
||||
// If we get a valid linear velocity (ie, we didn't wrap around in the anim),
|
||||
// use it. Otherwise just reuse the previous frames velocity.
|
||||
hsVector3 linearVel; |
||||
if (LinearVelocity(linearVel, (float)(timeNow - timePrev), prevMat, curMat)) |
||||
fAnimPosVel = linearVel; |
||||
|
||||
// Automatically sets fAnimAngVel
|
||||
AngularVelocity(fAnimAngVel, (float)(timeNow - timePrev), prevMat, curMat); |
||||
} |
||||
else |
||||
{ |
||||
fAnimPosVel.Set(0.f, 0.f, 0.f); |
||||
fAnimAngVel = 0.f; |
||||
} |
||||
|
||||
if (fController) |
||||
fController->SetVelocities(fAnimPosVel, fAnimAngVel + fTurnStr); |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const float plWalkingController::kControlledFlightThreshold = 1.f; // seconds
|
||||
|
||||
plWalkingController::plWalkingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller) |
||||
: plAnimatedController(rootObject, rootApp, controller) |
||||
, fHitGroundInThisAge(false) |
||||
, fWaitingForGround(false) |
||||
, fControlledFlightTime(0) |
||||
, fControlledFlight(0) |
||||
, fImpactTime(0.f) |
||||
, fImpactVelocity(0.f, 0.f, 0.f) |
||||
, fClearImpact(false) |
||||
, fGroundLastFrame(false) |
||||
{ |
||||
if (fController) |
||||
{ |
||||
fWalkingStrategy= new plWalkingStrategy(fController); |
||||
fController->SetMovementSimulationInterface(fWalkingStrategy); |
||||
} |
||||
else |
||||
fWalkingStrategy = nil; |
||||
} |
||||
|
||||
void plWalkingController::RecalcVelocity(double timeNow, double timePrev, bool useAnim) |
||||
{ |
||||
if (!fHitGroundInThisAge && fController && fController->IsEnabled() && fWalkingStrategy->IsOnGround()) |
||||
fHitGroundInThisAge = true; // if we're not pinned and we're not in an age yet, we are now.
|
||||
|
||||
if (fClearImpact) |
||||
{ |
||||
fImpactTime = 0.f; |
||||
fImpactVelocity.Set(0.f, 0.f, 0.f); |
||||
} |
||||
|
||||
if (fController && !fWalkingStrategy->IsOnGround()) |
||||
{ |
||||
// PhysX Hack: AchievedLinearVelocity is a Cyanic fix for superjumps. LinearVelocity is
|
||||
// always (0,0,0) outside of the controller update proc
|
||||
fImpactTime = fWalkingStrategy->GetAirTime(); |
||||
fImpactVelocity = fController->GetAchievedLinearVelocity(); |
||||
// convert orientation from subworld to avatar-local coordinates
|
||||
fImpactVelocity = (hsVector3)fController->GetLocalRotation().Rotate(&fImpactVelocity); |
||||
fClearImpact = false; |
||||
} |
||||
else |
||||
fClearImpact = true; |
||||
|
||||
if (IsControlledFlight()) |
||||
{ |
||||
if (fWalkingStrategy && fWalkingStrategy->IsOnGround()) |
||||
fControlledFlightTime = fWalkingStrategy->GetAirTime(); |
||||
if(fGroundLastFrame&&(fWalkingStrategy && !fWalkingStrategy->IsOnGround())) |
||||
{ |
||||
//we have started to leave the ground tell the movement strategy in case it cares
|
||||
fWalkingStrategy->StartJump(); |
||||
} |
||||
if (fControlledFlightTime > kControlledFlightThreshold) |
||||
EnableControlledFlight(false); |
||||
} |
||||
if (fWalkingStrategy) |
||||
fGroundLastFrame = fWalkingStrategy->IsOnGround(); |
||||
else |
||||
fGroundLastFrame=false; |
||||
plAnimatedController::RecalcVelocity(timeNow, timePrev, useAnim); |
||||
} |
||||
|
||||
void plWalkingController::Reset(bool newAge) |
||||
{ |
||||
|
||||
ActivateController(); |
||||
if (newAge) |
||||
{ |
||||
if (fWalkingStrategy) |
||||
fWalkingStrategy->ResetAirTime(); |
||||
fHitGroundInThisAge = false; |
||||
} |
||||
} |
||||
void plWalkingController::ActivateController() |
||||
{ |
||||
if (fWalkingStrategy) |
||||
{ |
||||
fWalkingStrategy->RefreshConnectionToControllerCore(); |
||||
} |
||||
else |
||||
{
|
||||
fWalkingStrategy= new plWalkingStrategy(fController); |
||||
fWalkingStrategy->RefreshConnectionToControllerCore(); |
||||
|
||||
} |
||||
} |
||||
|
||||
bool plWalkingController::EnableControlledFlight(bool status) |
||||
{ |
||||
if (status) |
||||
{ |
||||
if (fControlledFlight == 0) |
||||
fControlledFlightTime = 0.f; |
||||
|
||||
++fControlledFlight; |
||||
fWaitingForGround = true; |
||||
} |
||||
else |
||||
fControlledFlight = max(--fControlledFlight, 0); |
||||
|
||||
return status; |
||||
} |
||||
plWalkingController::~plWalkingController() |
||||
{ |
||||
delete fWalkingStrategy; |
||||
if (fController) |
||||
fController->SetMovementSimulationInterface(nil); |
||||
} |
||||
#if 0 |
||||
void plWalkingController::Update() |
||||
{ |
||||
// double elapsed = time.asDouble() - getRefresh().asDouble();
|
||||
// setRefresh(time);
|
||||
//
|
||||
// bool isPhysical = !fPhysical->GetProperty(plSimulationInterface::kPinned);
|
||||
// const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
|
||||
// bool alreadyInAge = fHitGroundInThisAge;
|
||||
//
|
||||
// int numContacts = fPhysical->GetNumContacts();
|
||||
// bool ground = false;
|
||||
// fPushingPhysical = nil;
|
||||
// int i, j;
|
||||
|
||||
/* for(i = 0; i < numContacts; i++)
|
||||
{ |
||||
plHKPhysical *contactPhys = fPhysical->GetContactPhysical(i); |
||||
if (!contactPhys) |
||||
continue; // Physical no longer exists. Skip it.
|
||||
|
||||
const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i); |
||||
float dotUp = straightUp.dot(contact->m_normal); |
||||
if (dotUp > .5) |
||||
ground = true; |
||||
else if (contactPhys->GetProperty(plSimulationInterface::kAvAnimPushable)) |
||||
{ |
||||
hsPoint3 position; |
||||
hsQuat rotation; |
||||
fPhysical->GetPositionAndRotationSim(&position, &rotation); |
||||
|
||||
hsQuat inverseRotation = rotation.Inverse(); |
||||
hsVector3 normal(contact->m_normal.x, contact->m_normal.y, contact->m_normal.z); |
||||
fFacingPushingPhysical = (inverseRotation.Rotate(&kAvatarForward).InnerProduct(normal) < 0 ? true : false); |
||||
|
||||
fPushingPhysical = contactPhys; |
||||
} |
||||
} |
||||
|
||||
// We need to check for the case where the avatar hasn't collided with "ground", but is colliding
|
||||
// with a few other objects so that he's not actually falling (wedged in between some slopes).
|
||||
// We do this by answering the following question (in 2d top-down space): "If you sort the contact
|
||||
// normals by angle, is there a large enough gap between normals?"
|
||||
//
|
||||
// If you think in terms of geometry, this means a collection of surfaces are all pushing on you.
|
||||
// If they're pushing from all sides, you have nowhere to go, and you won't fall. There needs to be
|
||||
// a gap, so that you're pushed out and have somewhere to fall. This is the same as finding a gap
|
||||
// larger than 180 degrees between sorted normals.
|
||||
//
|
||||
// The problem is that on top of that, the avatar needs enough force to shove him out that gap (he
|
||||
// has to overcome friction). I deal with that by making the threshold (360 - (180 - 60) = 240). I've
|
||||
// seen up to 220 reached in actual gameplay in a situation where we'd want this to take effect.
|
||||
// This is the same running into 2 walls where the angle between them is 60.
|
||||
const float threshold = hsDegreesToRadians(240); |
||||
if (!ground && numContacts >= 2) |
||||
{ |
||||
// Can probably do a special case for exactly 2 contacts. Not sure if it's worth it...
|
||||
|
||||
fCollisionAngles.SetCount(numContacts); |
||||
for (i = 0; i < numContacts; i++) |
||||
{ |
||||
const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i); |
||||
fCollisionAngles[i] = atan2(contact->m_normal.y, contact->m_normal.x); |
||||
} |
||||
|
||||
// numContacts is rarely larger than 6, so let's do a simple bubble sort.
|
||||
for (i = 0; i < numContacts; i++) |
||||
{ |
||||
for (j = i + 1; j < numContacts; j++) |
||||
{ |
||||
if (fCollisionAngles[i] > fCollisionAngles[j]) |
||||
{ |
||||
float tempAngle = fCollisionAngles[i]; |
||||
fCollisionAngles[i] = fCollisionAngles[j]; |
||||
fCollisionAngles[j] = tempAngle; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// sorted, now we check.
|
||||
for (i = 1; i < numContacts; i++) |
||||
{ |
||||
if (fCollisionAngles[i] - fCollisionAngles[i - 1] >= threshold) |
||||
break; |
||||
} |
||||
|
||||
if (i == numContacts) |
||||
{ |
||||
// We got to the end. Check the last with the first and make your decision.
|
||||
if (!(fCollisionAngles[0] - fCollisionAngles[numContacts - 1] >= (threshold - 2 * M_PI))) |
||||
ground = true; |
||||
} |
||||
} |
||||
*/ |
||||
|
||||
bool ground = fController ? fController->GotGroundHit() : true; |
||||
bool isPhysical = true; |
||||
|
||||
if (!fHitGroundInThisAge && isPhysical) |
||||
fHitGroundInThisAge = true; // if we're not pinned and we're not in an age yet, we are now.
|
||||
|
||||
if (IsControlledFlight()) |
||||
fControlledFlightTime += (float)elapsed; |
||||
if (fControlledFlightTime > kControlledFlightThreshold && numContacts > 0) |
||||
EnableControlledFlight(false); |
||||
|
||||
if (ground || !isPhysical) |
||||
{ |
||||
if (!IsControlledFlight() && !IsOnGround()) |
||||
{ |
||||
// The first ground contact in an age doesn't count.
|
||||
// if (alreadyInAge)
|
||||
// {
|
||||
// hsVector3 vel;
|
||||
// fPhysical->GetLinearVelocitySim(vel);
|
||||
// fImpactVel = vel.fZ;
|
||||
// fTimeInAirPeak = (float)(fTimeInAir + elapsed);
|
||||
// }
|
||||
|
||||
fWaitingForGround = false;
|
||||
}
|
||||
fTimeInAir = 0; |
||||
} |
||||
else if (elapsed < plSimulationMgr::GetInstance()->GetMaxDelta()) |
||||
{ |
||||
// If the simultation skipped a huge chunk of time, we didn't process the
|
||||
// collisions, which could trick us into thinking we've just gone a long
|
||||
// time without hitting ground. So we only count the time if this wasn't
|
||||
// the case.
|
||||
fTimeInAir += (float)elapsed; |
||||
} |
||||
|
||||
|
||||
// Tweakage so that we still fall under the right conditions.
|
||||
// If we're in controlled flight, or standing still with ground solidly under us (probe hit). We only use anim velocity.
|
||||
// if (!IsControlledFlight() && !(ground && fProbeHitGround && fAnimPosVel.fX == 0 && fAnimPosVel.fY == 0))
|
||||
// {
|
||||
// hsVector3 curV;
|
||||
// fPhysical->GetLinearVelocitySim(curV);
|
||||
// fAnimPosVel.fZ = curV.fZ;
|
||||
//
|
||||
// // Prevents us from going airborn from running up bumps/inclines.
|
||||
// if (IsOnGround() && fAnimPosVel.fZ > 0.f)
|
||||
// fAnimPosVel.fZ = 0.f;
|
||||
//
|
||||
// // Unless we're on the ground and moving, or standing still with a probe hit, we use the sim's other axes too.
|
||||
// if (!(IsOnGround() && (fProbeHitGround || fAnimPosVel.fX != 0 || fAnimPosVel.fY != 0)))
|
||||
// {
|
||||
// fAnimPosVel.fX = curV.fX;
|
||||
// fAnimPosVel.fY = curV.fY;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fPhysical->SetLinearVelocitySim(fAnimPosVel);
|
||||
// fPhysical->SetSpin(fAnimAngVel + fTurnStr, hsVector3(0.0f, 0.0f, 1.0f));
|
||||
} |
||||
#endif |
||||
|
||||
|
||||
#if 0 |
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSimDefs::ActionType plHorizontalFreezeAction::GetType() |
||||
{ |
||||
return plSimDefs::kHorizontalFreeze; |
||||
} |
||||
|
||||
void plHorizontalFreezeAction::apply(Havok::Subspace &s, Havok::hkTime time) |
||||
{ |
||||
double elapsed = time.asDouble() - getRefresh().asDouble(); |
||||
setRefresh(time); |
||||
|
||||
int numContacts = fPhysical->GetNumContacts(); |
||||
bool ground = false; |
||||
const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
|
||||
int i; |
||||
for(i = 0; i < numContacts; i++) |
||||
{ |
||||
const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i); |
||||
float dotUp = straightUp.dot(contact->m_normal); |
||||
if (dotUp > .5) |
||||
ground = true; |
||||
} |
||||
|
||||
hsVector3 vel; |
||||
fPhysical->GetLinearVelocitySim(vel); |
||||
vel.fX = 0.0; |
||||
vel.fY = 0.0; |
||||
if (ground) |
||||
vel.fZ = 0; |
||||
fPhysical->SetLinearVelocitySim(vel); |
||||
fPhysical->ClearContacts(); |
||||
} |
||||
#endif |
||||
plSwimmingController::plSwimmingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller) |
||||
:plAnimatedController(rootObject,rootApp,controller) |
||||
{ |
||||
if (controller) |
||||
fSwimmingStrategy= new plSwimStrategy(controller); |
||||
else |
||||
fSwimmingStrategy = nil; |
||||
} |
||||
plSwimmingController::~plSwimmingController() |
||||
{ |
||||
delete fSwimmingStrategy; |
||||
} |
||||
|
||||
plRidingAnimatedPhysicalController::plRidingAnimatedPhysicalController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller) |
||||
: plWalkingController(rootObject, rootApp, controller) |
||||
{ |
||||
if(controller) |
||||
fWalkingStrategy = new plRidingAnimatedPhysicalStrategy(controller); |
||||
else |
||||
fWalkingStrategy = nil; |
||||
} |
||||
plRidingAnimatedPhysicalController::~plRidingAnimatedPhysicalController() |
||||
{ |
||||
delete fWalkingStrategy; |
||||
fWalkingStrategy=nil; |
||||
} |
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
Purpose: |
||||
|
||||
ANGLE_RAD_2D returns the angle in radians swept out between two rays in 2D. |
||||
|
||||
Discussion: |
||||
|
||||
Except for the zero angle case, it should be true that |
||||
|
||||
ANGLE_RAD_2D(X1,Y1,X2,Y2,X3,Y3) |
||||
+ ANGLE_RAD_2D(X3,Y3,X2,Y2,X1,Y1) = 2 * PI |
||||
|
||||
Modified: |
||||
|
||||
19 April 1999 |
||||
|
||||
Author: |
||||
|
||||
John Burkardt |
||||
|
||||
Parameters: |
||||
|
||||
Input, float X1, Y1, X2, Y2, X3, Y3, define the rays |
||||
( X1-X2, Y1-Y2 ) and ( X3-X2, Y3-Y2 ) which in turn define the |
||||
angle, counterclockwise from ( X1-X2, Y1-Y2 ). |
||||
|
||||
Output, float ANGLE_RAD_2D, the angle swept out by the rays, measured |
||||
in radians. 0 <= ANGLE_DEG_2D < 2 PI. If either ray has zero length, |
||||
then ANGLE_RAD_2D is set to 0. |
||||
*/ |
||||
|
||||
static float AngleRad2d ( float x1, float y1, float x3, float y3 ) |
||||
{ |
||||
float value; |
||||
float x; |
||||
float y; |
||||
|
||||
x = ( x1 ) * ( x3 ) + ( y1 ) * ( y3 ); |
||||
y = ( x1 ) * ( y3 ) - ( y1 ) * ( x3 ); |
||||
|
||||
if ( x == 0.0 && y == 0.0 ) { |
||||
value = 0.0; |
||||
} |
||||
else
|
||||
{ |
||||
value = atan2 ( y, x ); |
||||
|
||||
if ( value < 0.0 )
|
||||
{ |
||||
value = (float)(value + TWO_PI); |
||||
} |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
static bool LinearVelocity(hsVector3 &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat) |
||||
{ |
||||
bool result = false; |
||||
|
||||
hsPoint3 startPos(0.0f, 0.0f, 0.0f); // default position (at start of anim)
|
||||
hsPoint3 prevPos = prevMat.GetTranslate(); // position previous frame
|
||||
hsPoint3 nowPos = curMat.GetTranslate(); // position current frame
|
||||
|
||||
hsVector3 prev2Now = (hsVector3)(nowPos - prevPos); // frame-to-frame delta
|
||||
|
||||
if (fabs(prev2Now.fX) < 0.0001f && fabs(prev2Now.fY) < 0.0001f && fabs(prev2Now.fZ) < 0.0001f) |
||||
{ |
||||
outputV.Set(0.f, 0.f, 0.f); |
||||
result = true; |
||||
}
|
||||
else
|
||||
{ |
||||
hsVector3 start2Now = (hsVector3)(nowPos - startPos); // start-to-frame delta
|
||||
|
||||
float prev2NowMagSqr = prev2Now.MagnitudeSquared(); |
||||
float start2NowMagSqr = start2Now.MagnitudeSquared(); |
||||
|
||||
float dot = prev2Now.InnerProduct(start2Now); |
||||
|
||||
// HANDLING ANIMATION WRAPPING:
|
||||
// the vector from the animation origin to the current frame should point in roughly
|
||||
// the same direction as the vector from the previous animation position to the
|
||||
// current animation position.
|
||||
//
|
||||
// If they don't agree (dot < 0,) then we probably mpst wrapped around.
|
||||
// The right answer would be to compare the current frame to the start of
|
||||
// the anim loop, but it's cheaper to cheat and return false,
|
||||
// telling the caller to use the previous frame's velocity.
|
||||
if (dot > 0.0f) |
||||
{ |
||||
prev2Now /= elapsed; |
||||
|
||||
float xfabs = fabs(prev2Now.fX); |
||||
float yfabs = fabs(prev2Now.fY); |
||||
float zfabs = fabs(prev2Now.fZ); |
||||
static const float maxVel = 20.0f; |
||||
bool valid = xfabs < maxVel && yfabs < maxVel && zfabs < maxVel; |
||||
|
||||
if (valid) |
||||
{ |
||||
outputV = prev2Now; |
||||
result = true; |
||||
} |
||||
}
|
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
static void AngularVelocity(float &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat) |
||||
{ |
||||
outputV = 0.f; |
||||
float appliedVelocity = 0.0f; |
||||
hsVector3 prevForward = GetYAxis(prevMat); |
||||
hsVector3 curForward = GetYAxis(curMat); |
||||
|
||||
float angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY); |
||||
bool sincePrevSign = angleSincePrev > 0.0f; |
||||
if (angleSincePrev > M_PI) |
||||
angleSincePrev = angleSincePrev - TWO_PI; |
||||
|
||||
const hsVector3 startForward = hsVector3(0, -1.0, 0); // the Y orientation of a "resting" armature....
|
||||
float angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY); |
||||
bool sinceStartSign = angleSinceStart > 0.0f; |
||||
if (angleSinceStart > M_PI) |
||||
angleSinceStart = angleSinceStart - TWO_PI; |
||||
|
||||
// HANDLING ANIMATION WRAPPING:
|
||||
// under normal conditions, the angle from rest to the current frame will have the same
|
||||
// sign as the angle from the previous frame to the current frame.
|
||||
// if it does not, we have (most likely) wrapped the motivating animation from frame n back
|
||||
// to frame zero, creating a large angle from the previous frame to the current one
|
||||
if (sincePrevSign == sinceStartSign) |
||||
{ |
||||
// signs are the same; didn't wrap; use the frame-to-frame angle difference
|
||||
appliedVelocity = angleSincePrev / elapsed; // rotation / time
|
||||
if (fabs(appliedVelocity) < 3) |
||||
{ |
||||
outputV = appliedVelocity; |
||||
} |
||||
} |
||||
} |
@ -1,217 +0,0 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools |
||||
Copyright (C) 2011 Cyan Worlds, Inc. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7 |
||||
|
||||
If you modify this Program, or any covered work, by linking or |
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||
(or a modified version of those libraries), |
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||
licensors of this Program grant you additional |
||||
permission to convey the resulting work. Corresponding Source for a |
||||
non-source form of such a combination shall include the source code for |
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||
work. |
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||
or by snail mail at: |
||||
Cyan Worlds, Inc. |
||||
14617 N Newport Hwy |
||||
Mead, WA 99021 |
||||
|
||||
*==LICENSE==*/ |
||||
#ifndef PL_HK_CALLBACK_ACTION_H |
||||
#define PL_HK_CALLBACK_ACTION_H |
||||
|
||||
#include "hsGeometry3.h" |
||||
#include "hsMatrix44.h" |
||||
#include "hsTemplates.h" |
||||
#include "pnKeyedObject/plKey.h" |
||||
#include "plPhysical/plSimDefs.h" |
||||
#include "pnMessage/plMessage.h" |
||||
#include "plPhysicalControllerCore.h" |
||||
class plLOSHitMsg; |
||||
class plAGApplicator; |
||||
class plSceneObject; |
||||
class plPhysical; |
||||
class plAvatarController; |
||||
class plCoordinateInterface; |
||||
class plPhysicalControllerCore; |
||||
// Used by the other controllers to actually move the avatar. The actual
|
||||
// implementation is in the physics system.
|
||||
/*class plPhysicalController
|
||||
{ |
||||
public: |
||||
// Implemented in the physics system. If you're linking this without that for
|
||||
// some reason, just stub this function out.
|
||||
//
|
||||
// Pass in the key to the root sceneobject for the avatar
|
||||
static plPhysicalController* Create(plKey ownerSO, float height, float width); |
||||
|
||||
virtual ~plPhysicalController() {} |
||||
|
||||
// A disabled avatar doesn't move or accumulate air time if he's off the ground.
|
||||
virtual void Enable(bool enable) = 0; |
||||
virtual bool IsEnabled() const = 0; |
||||
|
||||
// Set the LOS DB this avatar will be in (only one)
|
||||
virtual void SetLOSDB(plSimDefs::plLOSDB losDB) = 0; |
||||
|
||||
// Call this once per frame with the velocities of the avatar in avatar space.
|
||||
virtual void SetVelocities(const hsVector3& linearVel, float angVel) = 0; |
||||
|
||||
// Gets the actual velocity we achieved in the last step (relative to our subworld)
|
||||
virtual const hsVector3& GetLinearVelocity() const = 0; |
||||
virtual void ResetAchievedLinearVelocity() = 0; |
||||
|
||||
// Get and set the current subworld for the avatar. Use nil for the main world.
|
||||
virtual plKey GetSubworld() const = 0; |
||||
virtual void SetSubworld(plKey world) = 0; |
||||
|
||||
// If IsOnGround returns false, GetAirTime will tell you how long the avatar
|
||||
// has been airborne. Use ResetAirTime to reset the air time to zero, for
|
||||
// cases like when the avatar spawns into a new age.
|
||||
virtual bool IsOnGround() const = 0; |
||||
virtual bool IsOnFalseGround() const = 0; |
||||
virtual float GetAirTime() const = 0; |
||||
virtual void ResetAirTime() = 0; |
||||
|
||||
virtual plPhysical* GetPushingPhysical() const = 0; |
||||
virtual bool GetFacingPushingPhysical() const = 0; |
||||
|
||||
// A helper function to get the coordinate interface for the avatars current
|
||||
// world. Handy if you need to convert points to and from that. This will
|
||||
// return nil if the avatar is in the main world (ie, you don't need to do
|
||||
// any translation).
|
||||
virtual const plCoordinateInterface* GetSubworldCI() const = 0; |
||||
|
||||
// For the avatar SDL only
|
||||
virtual void GetState(hsPoint3& pos, float& zRot) = 0; |
||||
virtual void SetState(const hsPoint3& pos, float zRot) = 0; |
||||
|
||||
// kinematic stuff .... should be just for when playing a behavior...
|
||||
virtual void Kinematic(bool state) = 0; |
||||
virtual bool IsKinematic() = 0; |
||||
virtual void GetKinematicPosition(hsPoint3& pos) = 0; |
||||
|
||||
virtual const hsMatrix44& GetPrevSubworldW2L() = 0; |
||||
|
||||
//when seeking no longer want to interact with exclusion regions
|
||||
virtual void SetSeek(bool seek)=0; |
||||
|
||||
|
||||
}; |
||||
*/ |
||||
class plAvatarController |
||||
{ |
||||
public: |
||||
virtual ~plAvatarController() {} |
||||
}; |
||||
|
||||
class plAnimatedController : public plAvatarController |
||||
{ |
||||
public: |
||||
plAnimatedController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller); |
||||
|
||||
virtual void RecalcVelocity(double timeNow, double timePrev, bool useAnim = true); |
||||
void SetTurnStrength(float val) { fTurnStr = val; } |
||||
float GetTurnStrength() { return fTurnStr; } |
||||
virtual void ActivateController()=0; |
||||
protected: |
||||
plSceneObject* fRootObject; |
||||
plPhysicalControllerCore* fController; |
||||
plAGApplicator* fRootApp; |
||||
float fAnimAngVel; |
||||
hsVector3 fAnimPosVel; |
||||
float fTurnStr; // Explicit turning, separate from animations
|
||||
}; |
||||
|
||||
class plWalkingController : public plAnimatedController |
||||
{ |
||||
public: |
||||
plWalkingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller); |
||||
virtual ~plWalkingController(); |
||||
virtual void RecalcVelocity(double timeNow, double timePrev, bool useAnim = true); |
||||
|
||||
void Reset(bool newAge); |
||||
bool IsControlledFlight() const { return fControlledFlight != 0; }
|
||||
bool IsOnGround() const { return fWalkingStrategy ? fWalkingStrategy->IsOnGround() : true; } |
||||
bool IsOnFalseGround() const { return fWalkingStrategy ? fWalkingStrategy->IsOnFalseGround() : true; } |
||||
bool HitGroundInThisAge() const { return fHitGroundInThisAge; } |
||||
bool EnableControlledFlight(bool status); |
||||
float GetAirTime() const { return fWalkingStrategy ? fWalkingStrategy->GetAirTime() : 0.f; } |
||||
void ResetAirTime() { if (fWalkingStrategy) fWalkingStrategy->ResetAirTime(); } |
||||
float GetForwardVelocity() const; |
||||
void ActivateController(); |
||||
// Check these after the avatar the avatar hits the ground for his total
|
||||
// hangtime and impact velocity.
|
||||
float GetImpactTime() const { return fImpactTime; } |
||||
const hsVector3& GetImpactVelocity() const { return fImpactVelocity; } |
||||
|
||||
plPhysical* GetPushingPhysical() const
|
||||
{ |
||||
if(fController)return fController->GetPushingPhysical();
|
||||
else return nil; |
||||
} |
||||
bool GetFacingPushingPhysical() const
|
||||
{ if(fController)return fController->GetFacingPushingPhysical();
|
||||
else return false; |
||||
} |
||||
|
||||
|
||||
protected: |
||||
bool fHitGroundInThisAge; |
||||
bool fWaitingForGround; // We've gone airborne. IsOnGround() returns false until we hit ground again.
|
||||
float fControlledFlightTime; |
||||
int fControlledFlight; // Count of how many are currently forcing flight
|
||||
plWalkingStrategy* fWalkingStrategy; |
||||
float fImpactTime; |
||||
hsVector3 fImpactVelocity; |
||||
bool fClearImpact; |
||||
bool fGroundLastFrame;//used for a test to pass the event of first getting air during a jump
|
||||
static const float kControlledFlightThreshold; |
||||
}; |
||||
class plSwimmingController: public plAnimatedController
|
||||
{ |
||||
public : |
||||
plSwimmingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller); |
||||
virtual ~plSwimmingController(); |
||||
void SetSurface(plSwimRegionInterface *region, float surfaceHeight){ |
||||
fSwimmingStrategy->SetSurface(region,surfaceHeight); |
||||
} |
||||
float GetBuoyancy() { return fSwimmingStrategy->GetBuoyancy(); } |
||||
bool IsOnGround() { return fSwimmingStrategy->IsOnGround(); } |
||||
bool HadContacts() { return fSwimmingStrategy->HadContacts();} |
||||
void Enable(bool en){if (fController) fController->Enable(en);} |
||||
plPhysicalControllerCore* GetController(){return fController;} |
||||
virtual void ActivateController(){fSwimmingStrategy->RefreshConnectionToControllerCore();} |
||||
protected: |
||||
plSwimStrategy* fSwimmingStrategy; |
||||
|
||||
}; |
||||
class plRidingAnimatedPhysicalController: public plWalkingController |
||||
{ |
||||
public: |
||||
plRidingAnimatedPhysicalController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller); |
||||
virtual ~plRidingAnimatedPhysicalController(); |
||||
}; |
||||
#endif // PL_HK_CALLBACK_ACTION_H
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue