joaopccosta
10-12-2010 14:07:19
Hi there!
I've got a PhysX Character Controller and i'm trying to figure out this.
Imagine a staircase. Imagine that the Character is going up the staircase and then falls from it. The problem is that the capsule, once falling, collides with the ground almost instantly. :\ Apart from the newton's equations (:P) i think that probably this is related with the frameRenderingQueued.
mWorld->advance(evt.timeSinceLastFrame);
mLastTimeStep = mScene->getTimeStep().getModified();
//don't let the camera go underground
if (mCamera->getPosition().y< 0.5f)
{
Ogre::Vector3 pos = mCamera->getPosition();
pos.y = 0.5f;
mCamera->setPosition(pos);
}
//physx collisions for character controllers
updateCharacters(); //move controller
mScene->getScene()->simulate(mLastTimeStep);
mScene->getScene()->flushStream();
mScene->getScene()->fetchResults(NX_RIGID_BODY_FINISHED, true);
return BaseApplication::frameRenderingQueued(evt);
any tips? thanks!
betajaen
14-12-2010 11:04:10
Falls whilst trying to go up the staircase, or fails at the first step?
It may be your step offset or your gravitational vector. Some creation or updateCharacters code would be nice. Also; Have you seen the CC new code posted on Buggy Swires? It may be worth you having a look at it.
[Edit]
Your frame code seems to be fine, everything seems to be in the right order.
[Double Edit]
No you aren't. This is how you do it:
//physx collisions for character controllers
updateCharacters(); //move controller
mWorld->advance(evt.timeSinceLastFrame);
mLastTimeStep = mScene->getTimeStep().getModified();
//don't let the camera go underground
if (mCamera->getPosition().y< 0.5f)
{
Ogre::Vector3 pos = mCamera->getPosition();
pos.y = 0.5f;
mCamera->setPosition(pos);
}
If you need specific timing events (with the current guess at the deltaTime) then register your class as an NxOgre::TimeListener.
joaopccosta
16-12-2010 10:45:07
No, it climbs up perfectly, but if it goes straight after the staircase ends, the falling motion doesn't seem natural. As if it "teleports" instantly to the ground
haven't checked the new CC yet. Have some stuff to do before fixing this problem, but i'll check it as soon as i can
Here goes my MyController code:
/**
*
* This file is found in ../PhysX_SDK/TrainingPrograms/Programs/Shared_Source folder
*
*/
#include <stdio.h>
#include <vector>
#include <string>
#include <iostream>
#include "MyCharacterController.h"
//#define COLLIDABLE_MASK (1<<GROUP_COLLIDABLE_NON_PUSHABLE)
unsigned int COLLIDABLE_MASK = (GROUP_COLLIDABLE_NON_PUSHABLE << 1) | (GROUP_COLLIDABLE_PUSHABLE << 1);
MyCharacterController::MyCharacterController(NxControllerManager* manager, NxScene *scene, NxVec3 pos, NxVec3 dim)
{
mManager = manager;
NxBoxControllerDesc desc;
desc.position.x = pos.x;
desc.position.y = pos.y;
desc.position.z = pos.z;
desc.extents = dim;
desc.skinWidth = 0.1f;
desc.slopeLimit = cosf(NxMath::degToRad(45.0f));
desc.stepOffset = 0.5f;
desc.upDirection = NX_Y;
desc.callback = &mReport;
mController = mManager->createController(scene, desc);
body = NULL;
}
MyCharacterController::MyCharacterController(NxControllerManager* manager, NxScene *scene, NxVec3 pos, NxReal radius, NxReal height)
{
mManager = manager;
NxCapsuleControllerDesc desc;
desc.position.x = pos.x;
desc.position.y = pos.y;
desc.position.z = pos.z;
desc.height = height;
desc.radius = radius;
desc.skinWidth = 0.1f;
desc.slopeLimit = cosf(NxMath::degToRad(45.0f));
desc.stepOffset = 0.5f;
desc.upDirection = NX_Y;
desc.climbingMode = CLIMB_EASY;
desc.callback = &mReport;
mController = mManager->createController(scene, desc);
body = NULL;
}
MyCharacterController::~MyCharacterController()
{
if(mManager)
{
mManager->releaseController(*mController);
}
}
void MyCharacterController::Move(const NxVec3 &disp, NxU32 &flag)
{
NxExtendedVec3 vec = mController->getPosition();
body->getParentSceneNode()->setPosition(vec.x,vec.y-0.7,vec.z);
mController->move(disp, COLLIDABLE_MASK, 0.001, flag);
}
NxActor* MyCharacterController::GetCharacterActor()
{
return mController->getActor();
}
bool MyCharacterController::SetCharacterPos(NxVec3 pos)
{
body->getParentSceneNode()->setPosition(pos.x,pos.y,pos.z);
return mController->setPosition(NxExtendedVec3(pos.x, pos.y, pos.z));
}
void MyCharacterController::setBody(Ogre::Entity* tempBody)
{
body = tempBody;
}
void MyCharacterController::UpdateCharacterExtents(NxScene *scene, NxVec3 offset)
{
switch (mController->getType())
{
case NX_CONTROLLER_BOX:
{
NxBoxController* boxCtrl = ((NxBoxController*) mController);
NxExtendedVec3 pos = boxCtrl->getPosition();
NxVec3 dim = boxCtrl->getExtents() + offset; // expanded extent
if (dim.x <= 0.0f || dim.y <= 0.0f || dim.z <= 0.0f)
break;
NxBounds3 worldBounds;
worldBounds.setCenterExtents(NxVec3(pos.x, pos.y + offset.y, pos.z), dim); // expand upward
boxCtrl->setCollision(false); // avoid checking overlap with ourselves
if (scene->checkOverlapAABB(worldBounds))
printf("\n>> Can NOT change the size of the box controller!");
else
{
boxCtrl->setExtents(dim);
boxCtrl->setPosition(pos + NxExtendedVec3(0, offset.y, 0));
}
boxCtrl->setCollision(true);
break;
}
case NX_CONTROLLER_CAPSULE:
{
NxCapsuleController* capsuleCtrl = ((NxCapsuleController*) mController);
NxF32 height = capsuleCtrl->getHeight() + offset.y; // height offset = offset.y
NxF32 radius = capsuleCtrl->getRadius() + offset.y/2; // radius offset = offset.y/2
NxExtendedVec3 pos = capsuleCtrl->getPosition();
pos.y += offset.y; // radius offset + 1/2 * height offset
if (height <= 0.0f || radius <= 0.0f)
break;
NxCapsule worldCapsule;
worldCapsule.p0 = NxVec3(pos.x, pos.y-height/2, pos.z);
worldCapsule.p1 = NxVec3(pos.x, pos.y+height/2, pos.z);
worldCapsule.radius = radius;
capsuleCtrl->setCollision(false);
if (scene->checkOverlapCapsule(worldCapsule))
{
printf("\n>> Can NOT change the size of the capsule controller!");
}
else
{
capsuleCtrl->setHeight(height);
capsuleCtrl->setRadius(radius);
capsuleCtrl->setPosition(pos);
}
capsuleCtrl->setCollision(true);
break;
}
break;
}
}
header file:
/**
*
* This file is found in ../PhysX_SDK/TrainingPrograms/Programs/Shared_Source folder
*
*/
#ifndef MYCHARACTERCONTROLLER_H
#define MYCHARACTERCONTROLLER_H
#include "NxControllerManager.h"
#include "NxBoxController.h"
#include "NxCapsuleController.h"
#include "NxPhysics.h"
#include <vector>
#include <string>
#include <iostream>
#include <OgreEntity.h>
#include <OgreSceneManager.h>
using namespace std;
enum CollisionGroup
{
GROUP_NON_COLLIDABLE, // = 0
GROUP_COLLIDABLE_NON_PUSHABLE, // = 1
GROUP_COLLIDABLE_PUSHABLE, // = 2
};
class MyControllerHitReport : public NxUserControllerHitReport
{
public:
virtual NxControllerAction onShapeHit(const NxControllerShapeHit& hit)
{
if(hit.shape)
{
NxCollisionGroup group = hit.shape->getGroup();
if(group==GROUP_COLLIDABLE_PUSHABLE)
{
NxActor& actor = hit.shape->getActor();
if(actor.isDynamic())
{
// 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);
}
}
}
}
return NX_ACTION_NONE;
}
virtual NxControllerAction onControllerHit(const NxControllersHit& hit)
{
return NX_ACTION_NONE;
}
};
class MyCharacterController
{
public:
MyCharacterController(NxControllerManager* manager, NxScene *scene, NxVec3 pos, NxVec3 dim);
MyCharacterController(NxControllerManager* manager, NxScene *scene, NxVec3 pos, NxReal radius, NxReal height);
~MyCharacterController();
void Move(const NxVec3 &disp, NxU32 &flag);
NxActor* GetCharacterActor();
bool SetCharacterPos(NxVec3 pos);
void UpdateCharacterExtents(NxScene *scene, NxVec3 offset);
void setBody(Ogre::Entity* tempBody);
private:
NxControllerManager* mManager; // Singleton
NxController* mController;
MyControllerHitReport mReport;
Ogre::Entity* body;
};
#endif
thanks!
betajaen
16-12-2010 11:01:19
Where is the code calling MyCharacterController::Move(), because your using way to much velocity for gravity.
I know you've done all this work, but you may want to switch to Buggy Swires now and use the Background Character. It's very accurate, uses animations, and gravity and jumping are almost in sync with dynamic Rigid Bodies doing similar motions.
joaopccosta
16-12-2010 11:12:32
ahah no problem mate. this is only a minor problem... trying to be a perfectionist
void MyCharacterController::Move(const NxVec3 &disp, NxU32 &flag)
{
NxExtendedVec3 vec = mController->getPosition();
body->getParentSceneNode()->setPosition(vec.x,vec.y-0.98,vec.z);
mController->move(disp, COLLIDABLE_MASK, 0.001, flag);
}
betajaen
16-12-2010 11:19:36
No, I mean the code in your app that calls the function. I need to know what your displacement vector is.
The vertical motion your giving is way too high. You should know Gravity is an acceleration not a velocity (you increase in speed when falling), so you need to take that into account. Look at the
freefall section on this webpage to help you along (basically you need to account for the time whilst spent into the air and use that with the scene gravity, to accelerate the character downwards).
joaopccosta
16-12-2010 12:00:08
Ah sorry! my bad!
void argh::updateCharacters()
{
NxU32 collisionFlags;
NxVec3 disp = defaultGravity;
disp.x+=mX;
disp.y+=mY;
disp.z+=mZ;
mCharacterController->Move(disp,collisionFlags);
mManager->updateControllers();
}
figures i already forgot my physics lessons... x_x forgot to take the time spent into account... x_x
thanks mate
betajaen
16-12-2010 12:01:54
Yep. You need to multiply your displacement by the deltaTime before giving it to move. Your character will fall then, but not as accurately as it should be.