You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
14 KiB
350 lines
14 KiB
/*==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 PLPHYSICALCONTROLLERCORE_H |
|
#define PLPHYSICALCONTROLLERCORE_H |
|
#include "hsGeometry3.h" |
|
#include "hsMatrix44.h" |
|
#include "hsTemplates.h" |
|
#include "pnKeyedObject/plKey.h" |
|
#include "plPhysical/plSimDefs.h" |
|
#include "pnMessage/plMessage.h" |
|
|
|
#include "hsQuat.h" |
|
#define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1 |
|
#define kSLOPELIMIT (cosf(hsDegreesToRadians(45.f))) |
|
|
|
class plCoordinateInterface; |
|
class plPhysical; |
|
class plPXPhysical; |
|
class plSwimRegionInterface; |
|
//Replacement for for plPhysicalController stripped out some walk specific code |
|
//plPhysicalControllerCore needs to have movement strategies registered to it these will then |
|
//be called by the controller during the simulation steps. The Strategies need to at least have an |
|
// Apply and Update definition. Everything else should be movement specific. I hope to come back and |
|
//and refactor when I have time this in the future. |
|
enum plControllerCollisionFlags |
|
{ |
|
kSides=1, |
|
kTop= (1<<1), |
|
kBottom=(1<<2), |
|
}; |
|
|
|
class plMovementStrategySimulationInterface |
|
{ |
|
public: |
|
|
|
virtual void Apply(float delSecs)=0; |
|
virtual void Update(float delSecs)=0; |
|
//most strategies don't require this. Only the ones that require behavior like a physical or need |
|
//something after the sim step. this used to be taken care of by Update, but this was moved to take care of |
|
//some of the frame lag |
|
virtual void PostStep(float delSecs){}; |
|
virtual void IAddContactNormals(hsVector3& vec){fContactNormals.Append(vec);} |
|
virtual void AddOnTopOfObject(plPhysical* phys){ fOnTopOf.Append(phys);} |
|
virtual void LeaveAge() |
|
{ |
|
fContactNormals.SetCount(0); |
|
fOnTopOf.SetCount(0); |
|
} |
|
protected: |
|
hsTArray<hsVector3> fContactNormals; |
|
hsTArray<plPhysical* > fOnTopOf; |
|
}; |
|
|
|
class plControllerSweepRecord |
|
{ |
|
public: |
|
plPhysical *ObjHit; |
|
hsPoint3 locHit;//World space |
|
float TimeHit;//Normalized between 0 and 1 |
|
hsVector3 Norm; |
|
}; |
|
bool operator<(const plControllerSweepRecord left, const plControllerSweepRecord right); |
|
class plPhysicalControllerCore |
|
{ |
|
public: |
|
virtual ~plPhysicalControllerCore(); |
|
virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults)=0; |
|
virtual void SetMovementSimulationInterface(plMovementStrategySimulationInterface* strat){fMovementInterface=strat;} |
|
virtual void Apply(float delSecs); |
|
virtual void Update(float delSecs); |
|
virtual void PostStep(float delSecs); |
|
// 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() {return fEnabled;} |
|
virtual plKey GetSubworld() {return fWorldKey;} |
|
virtual void SetSubworld(plKey world) = 0; |
|
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){fSeeking=seek;} |
|
virtual bool IsSeeking(){return fSeeking;} |
|
static plPhysicalControllerCore* Create(plKey ownerSO, float height, float radius); |
|
virtual plMovementStrategySimulationInterface* GetMovementInterface(){return fMovementInterface;} |
|
plPhysicalControllerCore(plKey ownerSceneObject, float height, float radius); |
|
virtual plKey GetOwner(){return fOwner;}; |
|
// Set the LOS DB this avatar will be in (only one) |
|
virtual void SetLOSDB(plSimDefs::plLOSDB losDB) { fLOSDB = losDB; } ; |
|
virtual plSimDefs::plLOSDB GetLOSDB() {return fLOSDB ; } |
|
virtual const hsMatrix44& GetLastGlobalLoc()=0; |
|
virtual void SetKinematicLoc(const hsMatrix44& l2w)=0; |
|
virtual void SetGlobalLoc(const hsMatrix44& l2w)=0; |
|
virtual bool IsEnabledChanged(){return fEnableChanged;} |
|
virtual void HandleEnableChanged()=0; |
|
virtual bool IsKinematicChanged(){return fKinematicChanged;} |
|
virtual void GetPositionSim(hsPoint3& pos)=0; |
|
virtual void HandleKinematicChanged()=0; |
|
virtual bool IsKinematicEnableNextUpdate(){return fKinematicEnableNextUpdate;} |
|
virtual void HandleKinematicEnableNextUpdate()=0; |
|
virtual void MoveKinematicToController(hsPoint3& pos)=0; |
|
virtual void UpdateControllerAndPhysicalRep()=0; |
|
virtual void CheckAndHandleAnyStateChanges(); |
|
virtual void UpdateSubstepNonPhysical(); |
|
virtual const hsPoint3& GetLocalPosition()=0; |
|
const hsQuat& GetLocalRotation() { return fLocalRotation; } |
|
virtual void MoveActorToSim(); |
|
|
|
virtual void OverrideAchievedVelocity(hsVector3 newAchievedVel) |
|
{//because of things like superjumps this is needed I'd rather not, but can't help it |
|
fAchievedLinearVelocity=newAchievedVel; |
|
} |
|
//any clean up for the controller should go here |
|
virtual void LeaveAge()=0; |
|
hsVector3 DisplacementLastStep(){return fDisplacementThisStep;} |
|
hsVector3 MeanVelocityForLastStep() |
|
{ |
|
hsVector3 vel=fDisplacementThisStep; |
|
return vel/fSimLength; |
|
} |
|
void SendCorrectionMessages(); |
|
void IncrementAngle(float deltaAngle); |
|
void UpdateWorldRelativePos(); |
|
virtual void SetLinearVelocity(const hsVector3& linearVel){fLinearVelocity=linearVel;} |
|
//should actually be a 3 vector but everywhere else it is assumed to be just around Z |
|
virtual void SetAngularVelocity(const float angvel){ fAngularVelocity=angvel;} |
|
virtual void SetVelocities(const hsVector3& linearVel, float angVel) |
|
{ |
|
fLinearVelocity=linearVel; |
|
fAngularVelocity=angVel; |
|
} |
|
|
|
virtual const hsVector3& GetLinearVelocity() ; |
|
virtual float GetAngularVelocity(){return fAngularVelocity;} |
|
virtual const hsVector3& GetAchievedLinearVelocity()const {return fAchievedLinearVelocity;} |
|
plPhysical* GetPushingPhysical(); |
|
bool GetFacingPushingPhysical(); |
|
virtual void SetPushingPhysical(plPhysical* pl){fPushingPhysical=pl;} |
|
virtual void SetFacingPushingPhysical(bool ans){fFacingPushingPhysical=ans;} |
|
//To be Used during runtime conversions, say to switch a tall controller to a ball for swimming |
|
virtual void SetControllerDimensions(float radius, float height)=0; |
|
virtual float GetControllerWidth(){return fRadius;} |
|
virtual float GetControllerHeight(){return fHeight;} |
|
virtual void ResetAchievedLinearVelocity() |
|
{ |
|
fAchievedLinearVelocity.Set(0.f,0.f,0.f); |
|
} |
|
virtual int SweepControllerPath(const hsPoint3& startPos,const hsPoint3& endPos, bool vsDynamics, bool vsStatics, uint32_t& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut)=0; |
|
//this should only be used to force a move it could place your head into a wall and that would be good |
|
virtual float GetHeight() {return fHeight;} |
|
virtual float GetRadius() {return fRadius;} |
|
//Wether the avatar thing has mass and forces things down or not, and changes the way things move |
|
//This is an attempt fix things like riding on an animated physical |
|
virtual void BehaveLikeAnimatedPhysical(bool actLikeAnAnimatedPhys)=0; |
|
virtual bool BehavingLikeAnAnimatedPhysical()=0; |
|
protected: |
|
|
|
plKey fOwner; |
|
float fHeight; |
|
float fRadius; |
|
plKey fWorldKey; |
|
plSimDefs::plLOSDB fLOSDB; |
|
bool fSeeking; |
|
bool fEnabled; |
|
bool fEnableChanged; |
|
bool fKinematic; |
|
bool fKinematicEnableNextUpdate; |
|
bool fKinematicChanged; |
|
plMovementStrategySimulationInterface* fMovementInterface; |
|
hsMatrix44 fLastGlobalLoc; |
|
hsPoint3 fLocalPosition; |
|
hsQuat fLocalRotation; |
|
hsMatrix44 fPrevSubworldW2L; |
|
hsVector3 fDisplacementThisStep; |
|
float fSimLength; |
|
|
|
//physical properties |
|
hsVector3 fLinearVelocity; |
|
float fAngularVelocity; |
|
hsVector3 fAchievedLinearVelocity; |
|
plPhysical* fPushingPhysical; |
|
bool fFacingPushingPhysical; |
|
bool fNeedsResize; |
|
}; |
|
|
|
class plMovementStrategy: public plMovementStrategySimulationInterface |
|
{ |
|
public: |
|
virtual void SetControllerCore(plPhysicalControllerCore* core) |
|
{ |
|
fCore=core; |
|
fCore->SetMovementSimulationInterface(this); |
|
} |
|
virtual void RefreshConnectionToControllerCore() |
|
{ |
|
fCore->SetMovementSimulationInterface(this); |
|
//fCore->SetControllerDimensions(fPreferedControllerWidth,fPreferedControllerHeight); |
|
fCore->BehaveLikeAnimatedPhysical(this->IRequireBehaviourLikeAnAnimatedPhysical()); |
|
} |
|
plMovementStrategy(plPhysicalControllerCore* core); |
|
//should actually be a 3 vector but everywhere else it is assumed to be just around Z |
|
virtual void SetLinearAcceleration(const hsVector3& accel){fLinearAcceleration=accel;} |
|
virtual const hsVector3& GetLinearAcceleration()const{return fLinearAcceleration;} |
|
//should actually be a 3 vector but everywhere else it is assumed to be just around Z |
|
virtual void ResetAchievedLinearVelocity() |
|
{ |
|
hsVector3 AchievedLinearVelocity(0.f,0.f,0.f); |
|
if(fCore)fCore->OverrideAchievedVelocity(AchievedLinearVelocity); |
|
} |
|
//proxy functions for Controller Core |
|
virtual float GetAirTime() const { return fTimeInAir; } |
|
virtual void ResetAirTime() { fTimeInAir = 0.f; } |
|
|
|
protected: |
|
virtual bool IRequireBehaviourLikeAnAnimatedPhysical()=0; |
|
virtual void IApplyKinematic(); |
|
plPhysicalControllerCore* fCore; |
|
hsVector3 fLinearAcceleration; |
|
float fAngularAcceleration; |
|
plKey fOwner; |
|
static const float kAirTimeThreshold; |
|
float fTimeInAir; |
|
float fPreferedControllerWidth; |
|
float fPreferedControllerHeight; |
|
|
|
|
|
}; |
|
|
|
class plWalkingStrategy: public plMovementStrategy |
|
{ |
|
public: |
|
plWalkingStrategy(plPhysicalControllerCore* core):plMovementStrategy(core) |
|
{ |
|
fGroundHit=false; |
|
fFalseGround=false; |
|
fHitHead=false; |
|
fCore->SetMovementSimulationInterface(this); |
|
fPreferedControllerWidth=core->GetControllerWidth(); |
|
fPreferedControllerHeight=core->GetControllerHeight(); |
|
fOnTopOfAnimatedPhysLastFrame=false; |
|
} |
|
virtual ~plWalkingStrategy(){}; |
|
virtual void Apply(float delSecs); |
|
virtual void Update(float delSecs); |
|
|
|
bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; } |
|
bool IsOnFalseGround() const { return fFalseGround && !fGroundHit; } |
|
void GroundHit() { fGroundHit = true; } |
|
virtual void IAddContactNormals(hsVector3& vec); |
|
virtual void StartJump(){}; |
|
|
|
|
|
protected: |
|
|
|
void ICheckForFalseGround(); |
|
bool fGroundHit; |
|
bool fFalseGround; |
|
bool fHitHead; |
|
bool fOnTopOfAnimatedPhysLastFrame; |
|
hsTArray<hsVector3> fPrevSlidingNormals; |
|
virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return true;} |
|
|
|
}; |
|
class plSwimStrategy: public plMovementStrategy |
|
{ |
|
public: |
|
plSwimStrategy(plPhysicalControllerCore *core); |
|
virtual ~plSwimStrategy(){}; |
|
void SetSurface(plSwimRegionInterface *region, float surfaceHeight); |
|
virtual void Apply(float delSecs); |
|
virtual void Update(float delSecs); |
|
float GetBuoyancy() { return fBuoyancy; } |
|
bool IsOnGround() { return fOnGround; } |
|
bool HadContacts() { return fHadContacts; } |
|
virtual void IAddContactNormals(hsVector3& vec); |
|
protected: |
|
virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return true;} |
|
private: |
|
void IAdjustBuoyancy(); |
|
float fBuoyancy; |
|
bool fOnGround; |
|
bool fHadContacts; |
|
float fSurfaceHeight; |
|
plSwimRegionInterface *fCurrentRegion; |
|
}; |
|
class plRidingAnimatedPhysicalStrategy : public plWalkingStrategy |
|
{ |
|
public: |
|
plRidingAnimatedPhysicalStrategy(plPhysicalControllerCore *core ) : |
|
fNeedVelocityOverride(false),fStartJump(false),plWalkingStrategy(core){}; |
|
virtual ~plRidingAnimatedPhysicalStrategy(){}; |
|
virtual void Apply(float delSecs); |
|
virtual void Update(float delSecs); |
|
virtual void PostStep(float delSecs); |
|
bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; } |
|
bool IsOnFalseGround() const { return fFalseGround && !fGroundHit; } |
|
void GroundHit() { fGroundHit = true; } |
|
virtual void StartJump(){fStartJump = true;} |
|
protected: |
|
virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return false;} |
|
bool ICheckMove(const hsPoint3& startPos, const hsPoint3& desiredPos); |
|
bool fNeedVelocityOverride; |
|
hsVector3 fOverrideVelocity; |
|
bool fStartJump; |
|
}; |
|
#endif// PLPHYSICALCONTROLLERCORE_H
|
|
|