[Bleeding] and Characters (again)

moagames

09-11-2008 14:48:00

Hi all,

since now i am still working with 0.9 because it has a working character class.
I would really like to upgrade to bleeding, at least to use the latest Physx SDK.
So my question: did anyone manage to get Characters working with Bleeding and wants to share his sourcecode ?

Thank you very much for your help.

NoodlesOnMyBack

09-11-2008 22:05:32

I can share what i have until now... the only problem is that it has a lot of references to other "components" so you have to change the code for that, but if you delete all of those references should work by its own,this is only the physics of the actor shape, not rendering stuff.
I think soon i'll finish something better.
It can jump, accelerate and reach max speed.
Its using PhysX 2.8.0, should work without NxOgre,but im using it with bleeding 1.0 '21).



#ifndef _CCHARACTER_H_
#define _CCHARACTER_H_

#include <stdio.h>
#define NOMINMAX
#include <Windows.h>

#include "GameComponent.h"
#include "Physics.h"
#include "NxOgre.h"
#include "Ogre.h"
#include "NxPhysics.h"
#include "NxUserAllocator.h"
#include "UserAllocator.h"
#include "ErrorStream.h"
#include "NxScene.h"
#include "NxControllerManager.h"
#include "NxController.h"
#include "NxBoxController.h"
#include "NxCapsuleController.h"
#include "OgreRender.h"
#include "ObjectManager.h"
#include "MouseFilter.h"
#include "CAnimation.h"

#include "CPosition.h"
#include "COrientation.h"
#include "CMesh.h"

class CAnimation;
class InputManager;
class ObjectManager;
class OgreRender;
class Physics;
class NxScene;
class ErrorStream;
class UserAllocator;
class NxUserAllocator;
class NxController;
class NxControllerManager;

enum GameGroup
{
GROUP_NON_COLLIDABLE,
GROUP_COLLIDABLE_NON_PUSHABLE,
GROUP_COLLIDABLE_PUSHABLE,
};

#define COLLIDABLE_MASK (1<<GROUP_COLLIDABLE_NON_PUSHABLE) | (1<<GROUP_COLLIDABLE_PUSHABLE)
#define MAX_NB_PTS 100

enum Direction {
MOVE_FORWARD,
MOVE_BACKWARD,
MOVE_LEFT,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN,
JUMP
};

class CCharacter : public NxUserControllerHitReport, public GameComponent { // : public NxUserControllerHitReport
private:
static const std::string mFamilyID;
static const std::string mComponentID;

OgreRender* mOgre;
Physics* mPhysics;
ObjectManager* mObjMan;
InputHandler* mInput;

CAnimation* mCAnim;

bool mWalk;
Real mWalkTime;
bool mStopWalk;

NxVec3 mStartPos;
UserAllocator* mMyAllocator;
ErrorStream mErrorStream;
NxPhysicsSDK* mPhysicsSDK;
NxVec3 mDefaultGravity;
bool mPause;
NxF32 G;
NxF32 mTimestepMultiplier;
//NxU32 mControlledCharacterIndex;
bool mApplyGravity;
bool mDrawSkinWidth;

bool mMotion;


NxF32 mCharacterSpeed;
NxF32 mSpeedMultiplier;
NxF32 mScale;
NxF32 mV0;
NxF32 mJumpTime;
NxF32 mFallTime;
bool mJump;
bool mFall;
NxF32 mJumpStrength;

bool mRotating;

NxRay mWorldRay;
NxControllerManager* mManager;
float mSkinwidth; // 0.2f
NxF32 mInitialRadius; // = 0.5f;
NxF32 mInitialHeight; // = 2.0f;
NxScene* mScene;
NxU32 mNbPts;
NxVec3 mPts[MAX_NB_PTS];

Ogre::Real mSpeed;
Ogre::Real mAcceleration;
Ogre::Vector3 mNextMovement;
Ogre::Quaternion mDirection;
Ogre::SceneManager* mSceneMgr;
//Ogre::Camera* mCamera;
Ogre::SceneNode* mEntityNode;
Ogre::Entity* mEntity;
//CameraView mCurrentView;
NxSceneQuery* mSceneQueryObject;
Ogre::Real mTurnReactionSpeed;

Real mSensibility;
Real mMouseSpeed;
//Real mZoom;
//Vector3 mNodeOffset;
enum animState mCurrentState;
enum animState mAnimState;
//Vector3 mNextMovement;
//Quaternion mDirection;

public:

CCharacter(Ogre::String characterName);

void update();
void setup();

virtual const std::string& familyID() const {
return mFamilyID;
}

virtual const std::string& componentID() const {
return mComponentID;
}

//int getCharacterState();
void startFall(NxF32 v0);
void stopFall();

void startWalking(NxF32 v0);
void stopWalking();

void enableMotion(bool _motion);
void enableRotation(bool _rotation);
bool isRotating();
bool isMoving();
Real getTurnReactionSpeed();
void setDisplacement(Ogre::Vector3 dispVector);
void setWalkState(bool state);

NxF32 rayHitGroundDistance();
NxF32 rayHitDistance(Vector3 cpos, Vector3 dir);
void setDirection(Ogre::Quaternion q);
void setCamera(Ogre::Camera* cam);
bool startJump(NxF32 v0);
void stopJump();

NxF32 getJumpHeight(NxF32 elapsedTime);
NxF32 getFallHeight(NxF32 elapsedTime);

void updateCharacter();
void createControllerManager(NxUserAllocator* a);
void releaseControllerManager();
void updateControllers();
NxController* initCharacterControllers(const NxVec3 startPos, NxReal scale, NxScene& scene);
void releaseCharacterControllers(NxScene& scene);
const NxVec3& getCharacterPos();
NxActor* getCharacterActor(NxU32 characterIndex);
bool resetCharacterPos(NxU32 index, const NxVec3& pos);
bool updateCharacterExtents(NxU32 index, bool& increase);
NxControllerAction onShapeHit(const NxControllerShapeHit& hit);
NxControllerAction onControllerHit(const NxControllersHit& hit);

};

#endif



#include "CCharacter.h"
#include "NxOgreConverter.h"
#include "ApeManager.h"

/*static*/
const std::string CCharacter::mFamilyID = "CCharacter";
const std::string CCharacter::mComponentID = "CCharacter";

NxControllerAction CCharacter::onShapeHit(const NxControllerShapeHit& hit)
{
if(1 && hit.shape)
{
NxCollisionGroup group = hit.shape->getGroup();
if(group!=GROUP_COLLIDABLE_NON_PUSHABLE)
{
NxActor& actor = hit.shape->getActor();
if(actor.isDynamic())
{
if ((mPts[mNbPts].x != hit.worldPos.x) || (mPts[mNbPts].y != hit.worldPos.y) || (mPts[mNbPts].z != hit.worldPos.z))
{
mPts[mNbPts++].x = hit.worldPos.x;
mPts[mNbPts++].y = hit.worldPos.y;
mPts[mNbPts++].z = hit.worldPos.z;
if (mNbPts==MAX_NB_PTS) mNbPts = 0;
}

// We only allow horizontal pushes. Vertical pushes when we stand on dynamic objects creates
// useless stress on the solver. It would be possible to enable/disable vertical pushes on
// particular objects, if the gameplay requires it.
if(hit.dir.y==0.0f)
{
NxF32 coeff = actor.getMass() * hit.length * 10.0f;
actor.addForceAtLocalPos(hit.dir*coeff, NxVec3(0,0,0), NX_IMPULSE);
// actor.addForceAtPos(hit.dir*coeff, hit.controller->getPosition(), NX_IMPULSE);
// actor.addForceAtPos(hit.dir*coeff, hit.worldPos, NX_IMPULSE);
}
}
}
}

return NX_ACTION_NONE;
}

NxControllerAction CCharacter::onControllerHit(const NxControllersHit& hit)
{
return NX_ACTION_NONE;
}


bool CCharacter::startJump(NxF32 v0)
{
if(mJump) return false;
mJumpTime = 0.0f;
mV0 = v0;
mJump = true;
}
void CCharacter::startFall(NxF32 v0)
{
if(mFall) return;
mFallTime = 0.0f;
mV0 = v0;
mFall = true;
}
void CCharacter::stopFall()
{
if(!mFall) return;
mFall = false;
}

void CCharacter::startWalking(NxF32 v0)
{
if(mWalk) return;
//mWalkTime = 0.0f;
mV0 = v0;
mWalk = true;
}
void CCharacter::stopWalking()
{
if(!mWalk) return;
mWalk = false;
}
void CCharacter::stopJump()
{
if(!mJump) return;
mJump = false;
}


NxF32 CCharacter::getJumpHeight(NxF32 elapsedTime)
{

if(mJump) {
mJumpTime += elapsedTime * 12.0;
NxF32 h = G*mJumpTime*mJumpTime + mV0*mJumpTime;
NxF32 height = (h - mDefaultGravity.y)*elapsedTime;
return height;
} else {
return -0.1f;
}

}

NxF32 CCharacter::getFallHeight(NxF32 elapsedTime)
{
if(mJump)
return -0.1f;
//if(mJump) {
// mJumpTime += elapsedTime * 6.0;
//
// }

if(mFall) {
mFallTime += elapsedTime * 12.0;
//NxF32 h = G*mFallTime*mFallTime;
NxF32 h = G*mFallTime*mFallTime - mV0*mFallTime;
NxF32 height = (h - mDefaultGravity.y)*elapsedTime;
if(height > 0)
return -0.1;
//else
return height;
} else {
return -0.1; //mDefaultGravity.y
}
}

class myRaycastQueryReport : public NxSceneQueryReport
{
virtual NxQueryReportResult onBooleanQuery(void* userData, bool result){ return NX_SQR_CONTINUE; };
virtual NxQueryReportResult onShapeQuery(void* userData, NxU32 nbHits, NxShape** hits){ return NX_SQR_CONTINUE; };
virtual NxQueryReportResult onSweepQuery(void* userData, NxU32 nbHits, NxSweepQueryHit* hits){ return NX_SQR_CONTINUE; };

virtual NxQueryReportResult onRaycastQuery(void* userData, NxU32 nbHits, const NxRaycastHit* hits)
{
unsigned int i = (unsigned int)userData;
if (nbHits > 0) {
// gHits[i] = hits[0];
} else {
// gHits[i].shape = NULL;
}
return NX_SQR_CONTINUE;
}
}gQueryReport;

//, UserAllocator* userAlloc, NxScene* scene,

CCharacter::CCharacter(Ogre::String characterName) : mSceneQueryObject(0),

mOgre = OgreRender::getSingletonPtr();
mPhysics = Physics::getSingletonPtr();
mObjMan = ObjectManager::getSingletonPtr();

mMyAllocator = (UserAllocator*)mPhysics->getWorld()->getPhysXDriver()->getUserAllocator();
mScene = mPhysics->getWorld()->getScenes()->get("Main")->getNxScene();

//////////////////////////////////////////////////////////////////////////

mSceneQueryObject = NULL;
NxSceneQueryDesc sceneQueryDesc;
sceneQueryDesc.report = &gQueryReport;
mSceneQueryObject = mScene->createSceneQuery(sceneQueryDesc);

//.
}

void CCharacter::setCamera(Ogre::Camera* cam) {
//mCamera = cam;
}

Real CCharacter::getTurnReactionSpeed() {
return mTurnReactionSpeed;
}

float getElapsedTime()
{
static LARGE_INTEGER previousTime;
static LARGE_INTEGER freq;
static bool init = false;
if(!init){
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&previousTime);
init=true;
}
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
unsigned long long elapsedTime = currentTime.QuadPart - previousTime.QuadPart;
previousTime = currentTime;
return (float)(elapsedTime)/(freq.QuadPart);
}

void CCharacter::createControllerManager(NxUserAllocator* a)
{
mManager = NxCreateControllerManager(a);
}

void CCharacter::releaseControllerManager()
{
NxReleaseControllerManager(mManager);
}

void CCharacter::updateControllers()
{
mManager->updateControllers();
}

NxController* CCharacter::initCharacterControllers(const NxVec3 startPos, NxReal scale, NxScene& scene)
{
NxCapsuleControllerDesc desc;
NxVec3 tmp = startPos;
desc.position.x = tmp.x;
desc.position.y = tmp.y;
desc.position.z = tmp.z;
desc.radius = mInitialRadius * mScale;
desc.height = mInitialHeight * mScale;
desc.upDirection = NX_Y;
// desc.slopeLimit = cosf(NxMath::degToRad(45.0f));
desc.slopeLimit = 0;
desc.skinWidth = mSkinwidth;
desc.stepOffset = 0.5;
desc.stepOffset = mInitialRadius * 0.5 * mScale;
// desc.stepOffset = 0.01f;
// desc.stepOffset = 0; // Fixes some issues
// desc.stepOffset = 10;
desc.callback = this; //&gControllerHitReport;

NxController* c = mManager->createController(&scene, desc);
c->setCollision(true);
NxActor* mActor = c->getActor();
mActor->setGroup(1);

return mManager->getController(0);
}

void CCharacter::releaseCharacterControllers(NxScene& scene)
{
mManager->purgeControllers();
}

const NxVec3& CCharacter::getCharacterPos() //NxU32 characterIndex
{
NxExtendedVec3 pos = mManager->getController(0)->getFilteredPosition();
return NxVec3(pos.x,pos.y,pos.z);
}

NxActor* CCharacter::getCharacterActor(NxU32 characterIndex)
{
return mManager->getController(characterIndex)->getActor();
}

bool CCharacter::resetCharacterPos(NxU32 index, const NxVec3& pos)
{
return mManager->getController(index)->setPosition(NxExtendedVec3(pos.x, pos.y, pos.z));
}

bool CCharacter::updateCharacterExtents(NxU32 index, bool& increase)
{
if(index&1)
{
NxBoxController* c = static_cast<NxBoxController*>(mManager->getController(index));
NxVec3 extents = c->getExtents();
NxF32 inc = 1.0f;
NxVec3 pos = getCharacterPos();
if (increase)
{
extents.y += inc;
pos.y += inc;
}
else
{
extents.y -= inc;
pos.y -= inc;
}

if(1)
{
NxBounds3 worldBounds;
worldBounds.setCenterExtents(NxVec3(pos.x, pos.y, pos.z), extents);
c->setCollision(false); // Avoid checking overlap with ourself
bool Status = mScene->checkOverlapAABB(worldBounds);
c->setCollision(true);
if(Status)
{
printf("Can not resize box!\n");
return false;
}
}

increase = !increase; // Increase or decrease height each time we're called

// WARNING: the SDK currently doesn't check for collisions when changing extents, so if you're close
// to a wall you might end up penetrating it. In some cases you might also fall through the level.
// A more advanced implementation will take care of that later.
c->setPosition(NxExtendedVec3(pos.x,pos.y,pos.z));
return c->setExtents(extents);
}
else
{
NxCapsuleController* c = static_cast<NxCapsuleController*>(mManager->getController(index));
NxF32 height = c->getHeight();
NxF32 radius = c->getRadius();
NxF32 inc = 1.0f;
NxVec3 pos = getCharacterPos();
if (increase)
{
height += inc;
pos.y += inc*0.5f;
}
else
{
height -= inc;
pos.y -= inc*0.5f;
}

if(1)
{
NxCapsule worldCapsule;
worldCapsule.p0.x = worldCapsule.p1.x = pos.x;
worldCapsule.p0.y = worldCapsule.p1.y = pos.y;
worldCapsule.p0.z = worldCapsule.p1.z = pos.z;
worldCapsule.p0.y -= height*0.5f;
worldCapsule.p1.y += height*0.5f;
worldCapsule.radius = radius;
c->setCollision(false); // Avoid checking overlap with ourself
bool Status = mScene->checkOverlapCapsule(worldCapsule);
c->setCollision(true);
if(Status)
{
printf("Can not resize capsule!\n");
return false;
}
}

increase = !increase; // Increase or decrease height each time we're called

// WARNING: the SDK currently doesn't check for collisions when changing height, so if you're close
// to a wall you might end up penetrating it. In some cases you might also fall through the level.
// A more advanced implementation will take care of that later.
c->setPosition(NxExtendedVec3(pos.x, pos.y, pos.z));
return c->setHeight(height);
}
}


void CCharacter::update() {

//updateCharacter();

}
void CCharacter::setup() {

mSpeed = 50.0;
mAcceleration = 0.9f;
mInitialRadius = 4.0f;
mInitialHeight = 12.0f;
mScale = 1.5;
mCurrentState = IDLE;
mPause = false;
mApplyGravity = true;
mMotion = false;
mManager = NULL;
mSkinwidth = 0.2f;
mNbPts = 0;
mJump = false;
mV0 = 0.0f;
mJumpTime = 0.0f;
mJumpStrength = 200; //160
mTurnReactionSpeed = 5.0;
mTimestepMultiplier = 1.0f;
mSpeedMultiplier= 1.0f;
mCharacterSpeed = 0.1f;
mAnimState = IDLE;
mWalk = false;
mFall = false;
mWalkTime = 0;
mFallTime = 0;
mStopWalk = false;

G = -9.8f;
mDefaultGravity = NxVec3(0.0f, -9.8f, 0.0f);


Vector3 mPos = dynamic_cast<CPosition*>(getOwnerObject()->getComponent("CPosition"))->Position;
mCAnim = dynamic_cast<CAnimation*>(getOwnerObject()->getComponent("CAnimation"));

mStartPos = NxVec3(mPos.x,mPos.y,mPos.z); //
mSensibility = 0.005f;
mMouseSpeed = 0.10;

createControllerManager(mMyAllocator); //getUserAllocator()
initCharacterControllers(mStartPos, 1, *mScene);

}
void CCharacter::setWalkState(bool state) {
mStopWalk = state;
}


//NxF32 CCharacter::cameraHit(NxVec3 cpos, NxVec3 dir)
NxF32 CCharacter::rayHitDistance(Vector3 cpos, Vector3 dir)
{

NxShape* characterShape = getCharacterActor(0)->getShapes()[0];

NxRay worldRay;
//worldRay.orig = NxVec3(588.064,900.998,988.782);
worldRay.orig = NxTools::convert(cpos);
worldRay.dir = NxTools::convert(dir);

NxRaycastHit hit;
characterShape->setFlag(NX_SF_DISABLE_RAYCASTING, true);
NxShape* shape = mScene->raycastClosestShape(worldRay, NX_ALL_SHAPES, hit);
characterShape->setFlag(NX_SF_DISABLE_RAYCASTING, false);

if(!mPause)
mWorldRay = worldRay;

return shape ? hit.distance : 0; //NX_MAX_F32
}

NxF32 CCharacter::rayHitGroundDistance()
{

NxShape* characterShape = getCharacterActor(0)->getShapes()[0];

NxVec3 aPos = getCharacterPos();
NxVec3 dir = NxVec3(0,-1,0);

NxRay worldRay;
worldRay.orig = aPos;
worldRay.dir = dir;

NxRaycastHit hit;
characterShape->setFlag(NX_SF_DISABLE_RAYCASTING, true);
NxShape* shape = mScene->raycastClosestShape(worldRay, NX_ALL_SHAPES, hit);
characterShape->setFlag(NX_SF_DISABLE_RAYCASTING, false);

if(!mPause)
mWorldRay = worldRay;

return shape ? hit.distance : 0; //NX_MAX_F32
}

void CCharacter::setDisplacement(Ogre::Vector3 dispVector) {
mNextMovement = dispVector;
}
void CCharacter::setDirection(Ogre::Quaternion orientation) {
mDirection = orientation;
}

void CCharacter::enableMotion(bool _motion) {
mMotion = _motion;
}
void CCharacter::enableRotation(bool _rotation) {
mRotating = _rotation;
}
bool CCharacter::isRotating() {
return mRotating;
}
bool CCharacter::isMoving() {
return mMotion;
}
void CCharacter::updateCharacter() {

float elapsedTime = mOgre->getTimeSinceLastFrame();
NxVec3 disp = NxVec3(0,0,0);
NxVec3 horizontalDisp = NxVec3(0,0,0);

if(!mStopWalk) {
mWalkTime += elapsedTime * mAcceleration;
} else {
mWalkTime -= elapsedTime * mAcceleration;
if(mWalkTime > 0.0f) {
}
}

if(mWalkTime >= 1) {
mWalkTime = 1;
}
if(mWalkTime <= 0) {
mWalkTime = 0;
mCurrentState = IDLE;
mCAnim->setAnimState(mCurrentState);
}

if(mWalkTime == 1) {
//mOgre->getDebugText()->addText("WALK_LOOP");
mCurrentState = LOOP_WALK;
mCAnim->setAnimState(mCurrentState);
}

Ogre::Vector3 tmpPos = (mDirection * mNextMovement);
horizontalDisp = NxTools::convert(tmpPos);
disp += horizontalDisp * (mSpeed * mWalkTime);

disp = disp * elapsedTime;

NxF32 heightDelta;

if(mJump) {
heightDelta = getJumpHeight(elapsedTime);
if(heightDelta!=0.0f)
disp.y+=heightDelta;

} else {
heightDelta = getFallHeight(elapsedTime);
if(heightDelta!=0.0f)
disp.y+=heightDelta;
}

//gravity checks

mNbPts = 0;
NxF32 sharpness = 1.0f;
NxU32 collisionFlags;
NxController* c = mManager->getController(0);

c->move(disp, 1, 0.000001f, collisionFlags, sharpness);

if(collisionFlags & NXCC_COLLISION_DOWN) {
stopJump();
stopFall();
}

if(!(collisionFlags & NXCC_COLLISION_DOWN)) {
if(!mJump)
startFall(0);
}

updateControllers();

////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//Vector3 dist = PlayerNode->getOrientation() * Vector3::NEGATIVE_UNIT_Z;
//Quaternion quat = dist.getRotationTo(MainNode->getOrientation() * Vector3::NEGATIVE_UNIT_Z);
//mDestYaw = quat.getYaw();
//mOgre->getDebugText()->addText("yaw =" + Ogre::StringConverter::toString(mDestYaw));
//mOgre->getDebugText()->addText("yaw =" + Ogre::StringConverter::toString(quat.getYaw()));


//mOgre->getDebugText()->addText("keyPress =" + Ogre::StringConverter::toString(mInput->forward));


}

moagames

10-11-2008 09:26:33

Thank you very much, i'll take a look at it later today :)