Ok since I'm seeing a lot of people in trouble to put PlayerController working with jump, I'm pasting here my code.
Function that detects ground collision:
bool cEntityCollisionHandler::groundCollision(OgreNewt::Body* body, Ogre::Real bodyHeight)
{
Ogre::Vector3 pos;
pos = Ogre::Vector3(cPhysicsInterface::getSingleton().getPosition(body).x,cPhysicsInterface::getSingleton().getPosition(body).y - (bodyHeight / 2),cPhysicsInterface::getSingleton().getPosition(body).z);
OgreNewt::BasicRaycast camRay(cPhysicsInterface::getSingleton().getNewtWorld(),Ogre::Vector3(pos.x,pos.y,pos.z),Ogre::Vector3(pos.x,pos.y - 1.0f,pos.z),false);
/* get collision distance it's comment because you don't realy need it for this propose but can be useful to do other things
Ogre::Vector3 direction = pos - (pos - Vector3(0,-1.0f,0));
Ogre::Real distance = direction.length();
distance = distance * camRay.getFirstHit().mDistance;
*/
if (camRay.getHitCount() > 0)
{
return true;
}
return false;
}
PlayerFrameListener code:
#include "cPlayerFrameListener.h"
#include "cPlayerCollisionHandler.h"
#include "Debugger.h"
#include "cPhysicsInterface.h"
cPlayerFrameListener::cPlayerFrameListener(OgreNewt::PlayerController* playerController, cPlayerCollisionHandler *entityCollision, cPlayer *player, bool bufferedKeys , bool bufferedMouse, bool bufferedJoy):cBasicFrameListener(true,true,false)
{
cameraPitchAngle = 0.0f;
// set the external view distance to 3 meters
m_cameraMode = 1;
m_cameraKeyState = false;
m_extenalViewDist = 5.0f;
mPlayerController = playerController;
mPlayer = player;
mEntityCollision = entityCollision;
// Set desired framerate and variables used for stepping the physics
desiredPhysicsFramerate = 120;
lastFPS = 0;
lastFrameDuration = 0;
physicsUpdateStep = 1.0f / static_cast<float>(desiredPhysicsFramerate);
physicsTimeAccumulator = 0.0f;
OgreNewt::Debugger &debug(cPhysicsInterface::getSingleton().getNewtWorld()->getDebugger());
debug.init(cGraphicalInterface::getSingleton().getSceneManager());
}
bool cPlayerFrameListener::mouseMoved( const OIS::MouseEvent &arg )
{
return true;
}
bool cPlayerFrameListener::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}
bool cPlayerFrameListener::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}
void cPlayerFrameListener::input(const FrameEvent& evt)
{
mKeyboard->capture();
mMouse->capture();
// Get frame rendertime in milliseconds
unsigned long currentFrameTime = cGraphicalInterface::getSingleton().getRoot()->getTimer()->getMilliseconds();
lastFrameDuration = currentFrameTime - lastFrameTime;
lastFrameTime = currentFrameTime;
bool isOnTheGround = false;
// Add last frame duration to accumulator that uses seconds
physicsTimeAccumulator += lastFrameDuration / 1000.0f;
// Check whether there is any reason to step the physics
if (physicsTimeAccumulator > physicsUpdateStep)
{
// Lets make maximum of 5 physics updates
if (physicsTimeAccumulator < physicsUpdateStep * 5)
{
while (physicsTimeAccumulator >= physicsUpdateStep)
{
// Update the physics world and substract from the accumulator
cPhysicsInterface::getSingleton().getNewtWorld()->update(physicsUpdateStep);
physicsTimeAccumulator -= physicsUpdateStep;
}
}
else
{
// Too many steps, just update once and clear accumulator to prevent total slowdown
cPhysicsInterface::getSingleton().getNewtWorld()->update(physicsTimeAccumulator);
physicsTimeAccumulator = 0.0f;
}
}
// player movement
Ogre::Real forwardSpeed, sideSpeed;
Ogre::Radian heading;
mPlayerController->getVelocity(forwardSpeed, sideSpeed, heading);
forwardSpeed = 0;
sideSpeed = 0;
OgreNewt::Body* playerBody = mPlayerController->getBody0();
//jumping
isOnTheGround = mEntityCollision->groundCollision(playerBody,mPlayerController->getPlayerHeight());
if(isOnTheGround)
mPlayer->setIsJumping(false);
else
mPlayer->setIsJumping(true);
//running
if(mPlayer->getIsRunning() == false) //Restores stamina
{
mPlayer->setStamina(mPlayer->getStamina()+ evt.timeSinceLastFrame);
if(mPlayer->getStamina() >= mPlayer->getStaminaLimit())
{
mPlayer->setStamina(mPlayer->getStaminaLimit());
}
}
// set player velocity from the user
if(mKeyboard->isKeyDown(OIS::KC_W))
{
if(mPlayer->getIsRunning() == false)
{
mPlayer->setRunVel(Ogre::Vector3(1,1,1));
}
forwardSpeed += (50.0f * mPlayer->getRunVel().x);
}
if(mKeyboard->isKeyDown(OIS::KC_S))
{
if(mPlayer->getIsRunning() == false)
{
mPlayer->setRunVel(Ogre::Vector3(1,1,1));
}
forwardSpeed -= (30.0f * mPlayer->getRunVel().x);
}
if(mKeyboard->isKeyDown(OIS::KC_A))
{
if(mPlayer->getIsRunning() == false)
{
mPlayer->setRunVel(Ogre::Vector3(1,1,1));
}
sideSpeed -= (30.0f * mPlayer->getRunVel().x);
}
if(mKeyboard->isKeyDown(OIS::KC_D))
{
if(mPlayer->getIsRunning() == false)
{
mPlayer->setRunVel(Ogre::Vector3(1,1,1));
}
sideSpeed += (30.0f * mPlayer->getRunVel().x);
}
if ((mKeyboard->isKeyDown(KC_LSHIFT)) && (mPlayer->getIsJumping() == false) && (mPlayer->getIsActive()))// jump
{
playerBody->addImpulse(playerBody->getOrientation() * Ogre::Vector3(0, 1, 0), playerBody->getPosition());
}
if ((mKeyboard->isKeyDown(KC_SPACE))&& (mPlayer->getIsJumping() == false) && (mPlayer->getStamina() > 1) && (mPlayer->getIsActive()))//run
{
mPlayer->setStamina(mPlayer->getStamina() - evt.timeSinceLastFrame);
mPlayer->setIsRunning(true);
if(mPlayer->getStamina() > 1)
{
mPlayer->setRunVel(Ogre::Vector3(2.5,2.5,2.5));
}
else
{
mPlayer->setRunVel(Ogre::Vector3(1,1,1));
}
}
if (mKeyboard->isKeyDown(OIS::KC_C))//crouch
{
if(cGraphicalInterface::getSingleton().getCameraHeight() > 3.0f)
cGraphicalInterface::getSingleton().setCameraHeight(cGraphicalInterface::getSingleton().getCameraHeight() - (evt.timeSinceLastFrame * 10));
}
//keys released
if (mKeyboard->isKeyDown(OIS::KC_C) == false)
{
if(cGraphicalInterface::getSingleton().getCameraHeight() < cGraphicalInterface::getSingleton().getInitialCameraHeight())
cGraphicalInterface::getSingleton().setCameraHeight(cGraphicalInterface::getSingleton().getCameraHeight() + (evt.timeSinceLastFrame * 10));
}
if(mKeyboard->isKeyDown(KC_SPACE) == false)
mPlayer->setIsRunning(false);
if (!m_cameraKeyState && mKeyboard->isKeyDown(OIS::KC_F3)) {
m_cameraMode = !m_cameraMode;
}
m_cameraKeyState = mKeyboard->isKeyDown(OIS::KC_F3);
Real timestep = evt.timeSinceLastFrame;
Real rate = (60.0f * 3.1416f/ 180.0f) * timestep;
// calculate the camera Pitch Angle
int pitchDir = -mMouse->getMouseState().Y.rel;
cameraPitchAngle += pitchDir * rate;
if (cameraPitchAngle > 80.0f * 3.1416f/ 180.0f) cameraPitchAngle = 80.0f * 3.1416f/ 180.0f;
if (cameraPitchAngle < -80.0f * 3.1416f/ 180.0f) cameraPitchAngle = -80.0f * 3.1416f/ 180.0f;
Ogre::Quaternion pitch (Ogre::Radian(cameraPitchAngle), Ogre::Vector3 (1, 0, 0));
int yawDir = -mMouse->getMouseState().X.rel;
heading += Ogre::Radian(yawDir * rate);
mPlayerController->setVelocity(forwardSpeed, sideSpeed, heading);
Ogre::Vector3 posit;
Ogre::Quaternion orient;
playerBody->getVisualPositionOrientation (posit, orient);
orient = orient * pitch;
if (m_cameraMode) {
// place the camera on external view
posit += orient * Ogre::Vector3 (0, 0, m_extenalViewDist);
}
// move eye point to be about the players head
posit.y += mPlayerController->getPlayerHeight() * cGraphicalInterface::getSingleton().getCameraHeight();
/*posit.y = 5;
posit.z = 100; //para debug
posit.x = 0;*/
cGraphicalInterface::getSingleton().getCamera()->setPosition(posit);
cGraphicalInterface::getSingleton().getCamera()->setOrientation(orient);
OgreNewt::Debugger& debug(cPhysicsInterface::getSingleton().getNewtWorld()->getDebugger());
if (mKeyboard->isKeyDown(OIS::KC_F3))
{
debug.startRaycastRecording();
debug.clearRaycastsRecorded();
debug.showDebugInformation();
}
else
{
debug.clearRaycastsRecorded();
debug.stopRaycastRecording();
debug.hideDebugInformation();
}
if (mKeyboard->isKeyDown(OIS::KC_T))
cPhysicsInterface::getSingleton().getNewtWorld()->setThreadCount( cPhysicsInterface::getSingleton().getNewtWorld()->getThreadCount() % 2 + 1);
}
bool cPlayerFrameListener::keyClicked(const OIS::KeyEvent &e)
{
return true;
}
bool cPlayerFrameListener::keyPressed(const OIS::KeyEvent &e)
{
return true;
}
bool cPlayerFrameListener::keyReleased(const OIS::KeyEvent &e)
{
return true;
}
bool cPlayerFrameListener::frameStarted(const FrameEvent& evt)
{
if(cGraphicalInterface::getSingleton().getWindow()->isClosed())
return false;
input(evt);
return true;
}
bool cPlayerFrameListener::frameEnded(const FrameEvent& evt)
{
if( mKeyboard->isKeyDown( KC_ESCAPE) )
{
return false;
}
return true;
}
cPlayerFrameListener::~cPlayerFrameListener()
{
//Remove ourself as a Window listener
WindowEventUtilities::removeWindowEventListener(cGraphicalInterface::getSingleton().getWindow(), this);
windowClosed(cGraphicalInterface::getSingleton().getWindow());
}
The important pieces of code for jump are:
This piece of code detects if the player is on the ground, if he is then he isn't jumping ( mPlayer->setIsJumping(false) ) otherwise...
//jumping
isOnTheGround = mEntityCollision->groundCollision(playerBody,mPlayerController->getPlayerHeight());
if(isOnTheGround)
mPlayer->setIsJumping(false);
else
mPlayer->setIsJumping(true);
This piece of code adds an impulse to the body only if the player is alive and if he isn't jumping:
if ((mKeyboard->isKeyDown(KC_LSHIFT)) && (mPlayer->getIsJumping() == false) && (mPlayer->getIsActive()))// jump
{
playerBody->addImpulse(playerBody->getOrientation() * Ogre::Vector3(0,1, 0), playerBody->getPosition());
}
I hope this help someone, I'm waiting for your feedback to know if was useful.
Houdini
15-10-2010 18:25:12
Sjinta,
I modified Newton/OgreNewt to allow jumping. To jump you simply call addImpulse() which I added to the OgreNewt_PlayerController class, and set the jump boolean to true. For example:
player_controller->addImpulse(0, 0, 10, true);
Below is the modified files that add this functionality:
CustomPlayerContoller.h
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/
#if !defined(AFX_CUSTOM_PLAYER_CONTROLLER_INCLUDED)
#define AFX_CUSTOM_PLAYER_CONTROLLER_INCLUDED
#include "NewtonCustomJoint.h"
class JOINTLIBRARY_API CustomPlayerController: public NewtonCustomJoint
{
public:
enum PlayerState
{
m_onLand,
m_onFreeFall,
m_onIlligalRamp,
//m_onJumping,
};
CustomPlayerController (const dMatrix& localFrame, const NewtonBody* child, dFloat maxStairStepFactor, dFloat cushion);
virtual ~CustomPlayerController();
dFloat GetMaxSlope () const;
void SetMaxSlope (dFloat maxSlopeAngleIndRadian);
void SetVelocity (dFloat forwardSpeed, dFloat sideSpeed, dFloat heading);
void GetVelocity (dFloat& forwardSpeed, dFloat& sideSpeed, dFloat& heading) const;
dMatrix CalculateVisualMatrix () const;
dFloat GetPlayerHeight() const;
dFloat GetPlayerStairHeight() const;
void SetPlayerStairHeight(dFloat stair_height);
void SetPlayerState(PlayerState state);
PlayerState GetPlayerState();
void AddImpulse(dFloat ximpulse, dFloat yimpulse, dFloat zimpulse, bool jump);
/*
virtual bool CanPushBody (const NewtonBody* hitBody) const {return true;}
const NewtonCollision* GetDynamicsSensorShape () const;
*/
const NewtonCollision* GetSensorShape () const;
const NewtonCollision* GetStairStepShape () const;
protected:
virtual void SubmitConstraints (dFloat timestep, int threadIndex);
private:
void PlayerOnLand (dFloat timestep, int threadIndex);
void PlayerOnRamp (dFloat timestep, int threadIndex);
void PlayerOnFreeFall (dFloat timestep, int threadIndex);
void KinematicMotion (dFloat timestep, int threadIndex);
int FindFloor (const dMatrix& origin, const dVector& dest, const dVector upDir, NewtonCollision* m_bodySensorShape, dFloat& hitParam, dVector& normal, int threadIndex) const;
int PreProcessContacts (NewtonWorldConvexCastReturnInfo* const contacts, int count, const dVector& updir) const;
dVector CalculateVelocity (const dVector& velocSrc, dFloat timestep, const dVector& upDir, dFloat elevation, int threadIndex) const;
static void KinematicMotion (const NewtonJoint* userJoint, dFloat timestep, int threadIndex);
static unsigned ConvexStaticCastPrefilter(const NewtonBody* body, const NewtonCollision* collision, void* userData);
static unsigned ConvexAllBodyCastPrefilter(const NewtonBody* body, const NewtonCollision* collision, void* userData);
protected:
struct CastFilterData
{
CastFilterData (const NewtonBody* me)
{
m_count = 1;
m_filter[0] = me;
}
int m_count;
const NewtonBody* m_filter[8];
};
/*
struct FindFloorData
{
FindFloorData (const NewtonBody* me)
:m_normal (0.0f, 1.0f, 0.0f, 0.0f)
{
m_me = me;
m_param = 2.0f;
m_hitBody = NULL;
}
dVector m_normal;
dFloat m_param;
const NewtonBody* m_me;
const NewtonBody* m_hitBody;
};
*/
dFloat m_heading;
dFloat m_loweCap;
dFloat m_maxSlope;
dFloat m_maxRadius;
dFloat m_sideSpeed;
dFloat m_restitution;
dFloat m_forwardSpeed;
dFloat m_playerHeight;
dFloat m_stairHeight;
dFloat m_kinematicCushion;
dVector m_gravity;
dMatrix m_localMatrix0;
dMatrix m_localMatrix1;
PlayerState m_playerState;
NewtonCollision* m_bodySensorShape;
NewtonCollision* m_stairSensorShape;
NewtonCollision* m_bodyFloorSensorShape;
bool m_jumping;
};
#endif
CustomPlayerController.cpp
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/
#include "CustomJointLibraryStdAfx.h"
#include "CustomPlayerController.h"
#define MAX_CONTACTS 16
#define SENSOR_SHAPE_SEGMENTS 32
#define MAX_COLLISIONS_ITERATION 8
#define DEAD_RESIDUAL_HORIZONTAL_VELOC 0.1f
CustomPlayerController::CustomPlayerController(
const dMatrix& playerFrameInGlobalSpace,
const NewtonBody* child,
dFloat maxStairStepFactor,
dFloat cushion)
:NewtonCustomJoint(6, child, NULL)
{
dVector com;
dMatrix matrix;
NewtonCollision* shape;
// the minimum cushion is 1.0/64.0f of a unit
if (cushion < 1.0f/64.0f) {
cushion = 1.0f/64.0f;
}
m_heading = 0.0f;
m_sideSpeed = 0.0f;
m_restitution = 0.0f;
m_forwardSpeed = 0.0f;
// m_playerState = m_onLand;
m_playerState = m_onFreeFall;
m_kinematicCushion = cushion;
SetMaxSlope (30.0f * 3.141592f / 180.0f);
NewtonBodyGetMatrix (child, &matrix[0][0]);
NewtonBodyGetCentreOfMass (child, &com[0]);
com.m_w = 1.0f;
dMatrix pinMatrix (playerFrameInGlobalSpace);
pinMatrix.m_posit = matrix.TransformVector(com);
pinMatrix.m_posit.m_w = 1.0f;
CalculateLocalMatrix (pinMatrix, m_localMatrix0, m_localMatrix1);
// register the callback for tire integration
NewtonUserJointSetFeedbackCollectorCallback (m_joint, KinematicMotion);
// calculate the dimensions of the Player internal auxiliary shapes
shape = NewtonBodyGetCollision (child);
// calculate top and bottom side
dVector top;
dVector bottom;
dVector upDir (m_localMatrix0.m_front);
NewtonCollisionSupportVertex (shape, &upDir[0], &top[0]);
// top += upDir.Scale (m_kinematicCushion);
dVector downDir (m_localMatrix0[0].Scale (-1.0f));
NewtonCollisionSupportVertex (shape, &downDir[0], &bottom[0]);
// bottom += downDir.Scale (m_kinematicCushion);
m_playerHeight = (top - bottom) % upDir;
// set stairs step high as a percent of the player high
m_stairHeight = m_playerHeight * maxStairStepFactor;
// calculate the radius
dFloat r1;
dFloat r2;
dFloat floorRadios;
dVector radiusVector1;
dVector radiusVector2;
NewtonCollisionSupportVertex (shape, &m_localMatrix0[1][0], &radiusVector1[0]);
NewtonCollisionSupportVertex (shape, &m_localMatrix0[2][0], &radiusVector2[0]);
r1 = dAbs (radiusVector1 % m_localMatrix0[1]);
r2 = dAbs (radiusVector2 % m_localMatrix0[2]);
floorRadios = (r1 > r2 ? r1 : r2);
m_maxRadius = floorRadios + m_kinematicCushion;
dVector stairSensorShape[SENSOR_SHAPE_SEGMENTS * 2];
dVector bodySensorPoints[SENSOR_SHAPE_SEGMENTS * 2];
dVector floorSensorShape[SENSOR_SHAPE_SEGMENTS * 2];
dFloat h0;
dFloat h1;
dFloat startHight;
h0 = bottom % pinMatrix[0];
h1 = top % pinMatrix[0] - m_stairHeight;
startHight = h0 + m_stairHeight;
m_loweCap = h0;
for (int i = 0; i < SENSOR_SHAPE_SEGMENTS; i ++) {
dFloat x;
dFloat z;
dFloat fx;
dFloat fz;
x = dCos (2.0f * 3.14159265f * dFloat(i) / dFloat(SENSOR_SHAPE_SEGMENTS));
z = dSin (2.0f * 3.14159265f * dFloat(i) / dFloat(SENSOR_SHAPE_SEGMENTS));
fx = floorRadios * x;
fz = floorRadios * z;
x = m_maxRadius * x;
z = m_maxRadius * z;
dVector point (h0, x, z);
point = m_localMatrix0.RotateVector (point);
bodySensorPoints[i].m_x = point.m_x;
bodySensorPoints[i].m_y = point.m_y;
bodySensorPoints[i].m_z = point.m_z;
point = dVector (h1, x, z);
point = m_localMatrix0.RotateVector (point);
bodySensorPoints[i + SENSOR_SHAPE_SEGMENTS].m_x = point.m_x;
bodySensorPoints[i + SENSOR_SHAPE_SEGMENTS].m_y = point.m_y;
bodySensorPoints[i + SENSOR_SHAPE_SEGMENTS].m_z = point.m_z;
point = dVector (h0, fx, fz);
point = m_localMatrix0.RotateVector (point);
floorSensorShape[i].m_x = point.m_x;
floorSensorShape[i].m_y = point.m_y;
floorSensorShape[i].m_z = point.m_z;
point = dVector (h1, fx, fz);
point = m_localMatrix0.RotateVector (point);
floorSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_x = point.m_x;
floorSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_y = point.m_y;
floorSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_z = point.m_z;
point = dVector (h0, x, z);
point = m_localMatrix0.RotateVector (point);
stairSensorShape[i].m_x = point.m_x;
stairSensorShape[i].m_y = point.m_y;
stairSensorShape[i].m_z = point.m_z;
point = dVector (startHight, x, z);
point = m_localMatrix0.RotateVector (point);
stairSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_x = point.m_x;
stairSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_y = point.m_y;
stairSensorShape[i + SENSOR_SHAPE_SEGMENTS].m_z = point.m_z;
}
m_stairSensorShape = NewtonCreateConvexHull (m_world, SENSOR_SHAPE_SEGMENTS * 2, &stairSensorShape[0].m_x, sizeof (dVector), 0.0f, 0, NULL);
m_bodySensorShape = NewtonCreateConvexHull (m_world, SENSOR_SHAPE_SEGMENTS * 2, &bodySensorPoints[0].m_x, sizeof (dVector), 0.0f, 0, NULL);
m_bodyFloorSensorShape = NewtonCreateConvexHull (m_world, SENSOR_SHAPE_SEGMENTS * 2, &floorSensorShape[0].m_x, sizeof (dVector), 0.0f, 0, NULL);
m_jumping = false;
}
CustomPlayerController::~CustomPlayerController()
{
NewtonReleaseCollision(m_world, m_bodySensorShape);
NewtonReleaseCollision(m_world, m_stairSensorShape);
NewtonReleaseCollision(m_world, m_bodyFloorSensorShape);
}
void CustomPlayerController::SetVelocity (dFloat forwardSpeed, dFloat sideSpeed, dFloat heading)
{
m_heading = heading;
m_sideSpeed = sideSpeed;
m_forwardSpeed = forwardSpeed;
}
void CustomPlayerController::GetVelocity (dFloat& forwardSpeed, dFloat& sideSpeed, dFloat& heading) const
{
heading = m_heading;
sideSpeed = m_sideSpeed;
forwardSpeed = m_forwardSpeed;
}
const NewtonCollision* CustomPlayerController::GetSensorShape () const
{
return m_bodySensorShape;
}
const NewtonCollision* CustomPlayerController::GetStairStepShape () const
{
return m_stairSensorShape;
}
void CustomPlayerController::SetMaxSlope (dFloat maxSlopeAngleIndRadian)
{
//
maxSlopeAngleIndRadian = dAbs(maxSlopeAngleIndRadian);
if (maxSlopeAngleIndRadian < 10.0f * 3.14159265f / 180.0f) {
maxSlopeAngleIndRadian = 10.0f * 3.14159265f / 180.0f;
}
if (maxSlopeAngleIndRadian > 60.0f * 3.14159265f / 180.0f) {
maxSlopeAngleIndRadian = 60.0f * 3.14159265f / 180.0f;
}
m_maxSlope = dCos (maxSlopeAngleIndRadian);
// m_maxSlope = 1.0f - dSin (dAbs(maxSlopeAngleIndRadian));
}
dFloat CustomPlayerController::GetMaxSlope () const
{
// return dSin (1.0f - m_maxSlope);
return dCos (m_maxSlope);
}
dFloat CustomPlayerController::GetPlayerHeight() const
{
return m_playerHeight;
}
dFloat CustomPlayerController::GetPlayerStairHeight() const
{
return m_stairHeight;
}
void CustomPlayerController::SetPlayerStairHeight(dFloat stair_height)
{
m_stairHeight = stair_height;
}
void CustomPlayerController::SetPlayerState(PlayerState state)
{
m_playerState = state;
}
CustomPlayerController::PlayerState CustomPlayerController::GetPlayerState()
{
return m_playerState;
}
/*
void CustomPlayerController::GetInfo (NewtonJointRecord* info) const
{
}
unsigned CustomPlayerController::ConvexDynamicCastPrefilter(const NewtonBody* body, const NewtonCollision* collision, void* userData)
{
// for now just collide with static bodies
dFloat mass;
dFloat Ixx;
dFloat Iyy;
dFloat Izz;
CastFilterData* CastFilterData;
CastFilterData = (CastFilterData*) userData;
for (int i =0; i < CastFilterData->m_count;i ++){
if (CastFilterData->m_filter[i] == body) {
return 0;
}
}
NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
return (mass > 0.0f);
}
dFloat CustomPlayerController::FindFloorCallback(const NewtonBody* body, const dFloat* hitNormal, int collisionID, void* userData, dFloat intersetParam)
{
dFloat param;
param = 1.0f;
FindFloorData& data = *((FindFloorData*)userData);
if (body != data.m_me) {
param = intersetParam;
if (param < data.m_param) {
data.m_param = param;
data.m_normal.m_x = hitNormal[0];
data.m_normal.m_y = hitNormal[1];
data.m_normal.m_z = hitNormal[2];
data.m_hitBody = body;
}
}
return param;
}
*/
unsigned CustomPlayerController::ConvexStaticCastPrefilter(const NewtonBody* body, const NewtonCollision* collision, void* userData)
{
// for now just collide with static bodies
// dFloat mass;
// dFloat Ixx;
// dFloat Iyy;
// dFloat Izz;
// CastFilterData* CastFilterData;
// CastFilterData = (CastFilterData*) userData;
// for (int i =0; i < CastFilterData->m_count;i ++){
// if (CastFilterData->m_filter[i] == body) {
// return 0;
// }
// }
// NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
// return (mass == 0.0f);
// return 1;
dFloat mass;
dFloat Ixx;
dFloat Iyy;
dFloat Izz;
NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
return (mass == 0.0f);
}
unsigned CustomPlayerController::ConvexAllBodyCastPrefilter(const NewtonBody* body, const NewtonCollision* collision, void* userData)
{
CastFilterData* filterData;
filterData = (CastFilterData*) userData;
for (int i =0; i < filterData->m_count;i ++){
if (filterData->m_filter[i] == body) {
return 0;
}
}
return 1;
}
void CustomPlayerController::KinematicMotion (const NewtonJoint* userJoint, dFloat timestep, int threadIndex)
{
CustomPlayerController* joint;
// get the pointer to the joint class
joint = (CustomPlayerController*) NewtonJointGetUserData (userJoint);
joint->KinematicMotion(timestep, threadIndex);
}
dMatrix CustomPlayerController::CalculateVisualMatrix () const
{
dMatrix bodyMatrix;
// Get the global matrices of each rigid body.
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
/*
if (!m_isInJumpState) {
// dFloat hitParam;
// CastFilterData staticCastFilterData (m_body0);
// NewtonWorldConvexCastReturnInfo info;
dVector upDir (bodyMatrix.RotateVector (m_localMatrix0.m_front));
// bodyMatrix.m_posit += upDir.Scale (m_stairHeight);
// dVector target (bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f));
FindFloorData floor (m_body0);
dVector p0 (bodyMatrix.m_posit + upDir.Scale (m_loweCap + m_stairHeight));
dVector p1 (p0 - upDir.Scale (2.0f * m_stairHeight));
NewtonWorldRayCast (m_world, &p0[0], &p1[0], FindFloorCallback, &floor, NULL);
if (floor.m_hitBody) {
bodyMatrix.m_posit -= upDir.Scale (m_stairHeight * (2.0f * floor.m_param - 1.0f));
}
}
*/
return bodyMatrix;
}
void CustomPlayerController::SubmitConstraints (dFloat timestep, int threadIndex)
{
dFloat mag;
dFloat angle;
dFloat invIxx;
dFloat invIyy;
dFloat invIzz;
dFloat invMass;
dMatrix matrix0;
dMatrix matrix1;
dVector velocity;
// save the gravity before collision force are applied
NewtonBodyGetForceAcc (m_body0, &m_gravity[0]);
NewtonBodyGetInvMass(m_body0, &invMass, &invIxx, &invIyy, &invIzz);
m_gravity = m_gravity.Scale (invMass);
// calculate the position of the pivot point and the Jacobian direction vectors, in global space.
CalculateGlobalMatrix (m_localMatrix0, m_localMatrix1, matrix0, matrix1);
// if the body ha rotated by some amount, the there will be a plane of rotation
dVector lateralDir (matrix0.m_front * matrix1.m_front);
mag = lateralDir % lateralDir;
if (mag > 1.0e-6f) {
// if the side vector is not zero, it means the body has rotated
mag = dSqrt (mag);
lateralDir = lateralDir.Scale (1.0f / mag);
angle = dAsin (mag);
// add an angular constraint to correct the error angle
NewtonUserJointAddAngularRow (m_joint, angle, &lateralDir[0]);
// in theory only one correction is needed, but this produces instability as the body may move sideway.
// a lateral correction prevent this from happening.
dVector frontDir (lateralDir * matrix1.m_front);
NewtonUserJointAddAngularRow (m_joint, 0.0f, &frontDir[0]);
} else {
// if the angle error is very small then two angular correction along the plane axis do the trick
NewtonUserJointAddAngularRow (m_joint, 0.0f, &matrix0.m_up[0]);
NewtonUserJointAddAngularRow (m_joint, 0.0f, &matrix0.m_right[0]);
}
// get linear velocity
if (m_playerState == m_onLand) {
// dFloat mag2;
NewtonBodyGetVelocity(m_body0, &velocity[0]);
// Get the global matrices of each rigid body.
const dVector& frontDir = matrix0.m_up;
const dVector& strafeDir = matrix0.m_right;
const dVector& upDir = matrix0.m_front;
dVector desiredVeloc (frontDir.Scale (m_forwardSpeed) + upDir.Scale (velocity % upDir) + strafeDir.Scale (-m_sideSpeed));
// dFloat maxSpeed = dAbs (m_forwardSpeed) > dAbs (m_sideSpeed) ? dAbs (m_forwardSpeed) : dAbs (m_sideSpeed);
// mag2 = desiredVeloc % desiredVeloc;
// if (mag2 > 1.0e-6f) {
// desiredVeloc = desiredVeloc.Scale (maxSpeed /dSqrt (mag2));
// }
NewtonBodySetVelocity(m_body0, &desiredVeloc[0]);
}
}
int CustomPlayerController::PreProcessContacts (NewtonWorldConvexCastReturnInfo* const contacts, int count, const dVector& upDir) const
{
// flatten contact prune contacts
for (int i = 0; i < count; i ++) {
dVector normal (contacts[i].m_normal);
// dVector point (contacts[i].m_point);
normal -= upDir.Scale (upDir % normal);
normal = normal.Scale (1.0f / dSqrt (normal % normal));
contacts[i].m_normal[0] = normal.m_x;
contacts[i].m_normal[1] = normal.m_y;
contacts[i].m_normal[2] = normal.m_z;
// contacts[i].m_normal[3] = - (normal % point);
}
// prune contact with the same normal
for (int i = 0; i < (count - 1); i ++) {
const dVector& normal0 = *((dVector*) (&contacts[i].m_normal[0]));
for (int j = i + 1; j < count; j ++) {
const dVector& normal1 = *((dVector*) (&contacts[j].m_normal[0]));
dFloat val = normal0 % normal1;
if (val > 0.9995f) {
count --;
contacts[j] = contacts[count];
j --;
}
}
}
return count;
}
dVector CustomPlayerController::CalculateVelocity (
const dVector& veloc,
dFloat timestep,
const dVector& upDir,
dFloat elevation,
int threadIndex) const
{
// see if it hit and obstacle
dFloat mag2;
dVector verticalVeloc (upDir.Scale (veloc % upDir)) ;
dVector velocity (veloc - verticalVeloc);
mag2 = velocity % velocity;
/*
static int xxx1;
xxx1 ++;
if (xxx1 >= 170){
xxx1 *=1;
dMatrix bodyMatrix;
//NewtonBodyGetVelocity(m_body0, &veloc[0]);
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
static dVector xxxx(bodyMatrix.m_posit);
dVector x (bodyMatrix.m_posit - xxxx);
//dTrace (("%d %f %f %f\n", xxx, bodyMatrix.m_posit.m_x, bodyMatrix.m_posit.m_y, bodyMatrix.m_posit.m_z));
dTrace (("step(%d %f %f %f) v(%f %f)\n", xxx1, x.m_x, x.m_y, x.m_z, veloc.m_x, veloc.m_z));
xxxx = bodyMatrix.m_posit;
}
*/
if (mag2 > 0.0f) {
int contactCount;
int prevContactCount;
int positionHasChanged;
dFloat hitParam;
dFloat paddingTimestep;
dMatrix bodyMatrix;
CastFilterData castFilterData (m_body0);
NewtonWorldConvexCastReturnInfo info[MAX_CONTACTS];
NewtonWorldConvexCastReturnInfo prevInfo[MAX_CONTACTS];
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
castFilterData.m_count = 1;
bodyMatrix.m_posit += upDir.Scale (elevation);
dVector translationStep (velocity.Scale (timestep));
dVector paddingStep (velocity.Scale (m_kinematicCushion / dSqrt (mag2)));
dVector destination (bodyMatrix.m_posit + translationStep + paddingStep);
paddingTimestep = (paddingStep % velocity) / (velocity % velocity);
prevContactCount = 0;
positionHasChanged = 0;
contactCount = NewtonWorldConvexCast (m_world, &bodyMatrix[0][0], &destination[0], m_bodySensorShape, &hitParam, &castFilterData, ConvexStaticCastPrefilter, info, sizeof (info) / sizeof (info[0]), threadIndex);
contactCount = PreProcessContacts (info, contactCount, upDir);
for (int iterations = 0; contactCount && (iterations < MAX_COLLISIONS_ITERATION); iterations ++) {
int flag;
int count;
dFloat time;
// calculate the travel time, and subtract from time remaining
time = hitParam * ((translationStep + paddingStep) % velocity) / (velocity % velocity) - paddingTimestep;
// teleport the body to the intersection point
positionHasChanged = 1;
bodyMatrix.m_posit += velocity.Scale (time);
dFloat speed[MAX_CONTACTS * 2];
dFloat bounceSpeed[MAX_CONTACTS * 2];
dVector bounceNormal[MAX_CONTACTS * 2];
dVector auxBounceVeloc (0.0f, 0.0f, 0.0f, 0.0f);
count = 0;
for (int i = 0; i < contactCount; i ++) {
dFloat reboundVeloc;
speed[count] = 0.0f;
bounceNormal[count] = info[i].m_normal;
reboundVeloc = -(velocity % bounceNormal[count]) * (1.0f + m_restitution);
bounceSpeed[count] = (reboundVeloc > 0.0f) ? reboundVeloc : 0.0f;
count ++;
}
for (int i = 0; i < prevContactCount; i ++) {
dFloat reboundVeloc;
speed[count] = 0.0f;
bounceNormal[count] = prevInfo[i].m_normal;
reboundVeloc = (velocity % bounceNormal[count]) * (1.0f + m_restitution);
bounceSpeed[count] = (reboundVeloc > 0.0f) ? reboundVeloc : 0.0f;
count ++;
}
dFloat residual;
residual = 10.0f;
for (int i = 0; (i < 16) && (residual > 1.0e-3f); i ++) {
residual = 0.0f;
for (int k = 0; k < count; k ++) {
dFloat v;
dFloat x;
v = bounceSpeed[k] - bounceNormal[k] % auxBounceVeloc;
x = speed[k] + v;
if (x < 0.0f) {
v = 0.0f;
x = 0.0f;
}
if (dAbs (v) > residual) {
residual = dAbs (v);
}
auxBounceVeloc += bounceNormal[k].Scale (x - speed[k]);
speed[k] = x;
}
}
flag = 0;
for (int i = 0; i < count; i ++) {
flag = (speed[i] > 0.0f);
velocity += bounceNormal[i].Scale (speed[i]);
}
prevContactCount = contactCount;
contactCount = 0;
if (flag) {
memcpy (prevInfo, info, prevContactCount * sizeof (NewtonWorldConvexCastReturnInfo));
mag2 = velocity % velocity;
if (mag2 > 1.0e-6f) {
translationStep = velocity.Scale (timestep);
paddingStep = velocity.Scale (m_kinematicCushion / dSqrt (mag2));
dVector destination (bodyMatrix.m_posit + translationStep + paddingStep);
castFilterData.m_count = 1;
contactCount = NewtonWorldConvexCast (m_world, &bodyMatrix[0][0], &destination[0], m_bodySensorShape, &hitParam, &castFilterData, ConvexStaticCastPrefilter, info, sizeof (info) / sizeof (info[0]), threadIndex);
contactCount = PreProcessContacts (info, contactCount, upDir);
}
}
}
if (positionHasChanged) {
bodyMatrix.m_posit -= upDir.Scale (elevation);
NewtonBodySetMatrix (m_body0, &bodyMatrix[0][0]);
}
// prevent the body form drifting form residual velocity when it is in a corner
mag2 = velocity % velocity;
if (mag2 < (DEAD_RESIDUAL_HORIZONTAL_VELOC * DEAD_RESIDUAL_HORIZONTAL_VELOC)) {
velocity = dVector (0.0f, 0.0f, 0.0f, 0.0f) ;
}
}
return (velocity + verticalVeloc);
}
int CustomPlayerController::FindFloor (const dMatrix& origin, const dVector& dest, const dVector upDir, NewtonCollision* shape, dFloat& hitParam, dVector& normal, int threadIndex) const
{
int contacts;
CastFilterData castFilterData (m_body0);
NewtonWorldConvexCastReturnInfo info[MAX_CONTACTS];
contacts = NewtonWorldConvexCast (m_world, &origin[0][0], &dest[0], shape, &hitParam, &castFilterData, ConvexAllBodyCastPrefilter, info, 8, threadIndex);
if (contacts) {
int bestContact = 0;
dFloat bestValue = upDir % info[0].m_normalOnHitPoint;
for (int i = 1; i < contacts; i ++) {
dFloat value = upDir % info[i].m_normalOnHitPoint;
if (value > bestValue) {
bestContact = i;
bestValue = value;
}
}
normal = info[bestContact].m_normalOnHitPoint;
contacts = 1;
}
return contacts;
}
void CustomPlayerController::PlayerOnFreeFall (dFloat timestep, int threadIndex)
{
dFloat dist;
dFloat hitParam;
dVector velocity;
dMatrix bodyMatrix;
// Get the global matrices of each rigid body.
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
dVector posit (bodyMatrix.m_posit);
dVector upDir (bodyMatrix.RotateVector (m_localMatrix0.m_front));
dVector frontDir (bodyMatrix.RotateVector (m_localMatrix0.m_up));
// make sure the body velocity will no penetrates other bodies
NewtonBodyGetVelocity (m_body0, &velocity[0]);
velocity = CalculateVelocity (velocity, timestep, upDir, m_stairHeight, threadIndex);
// player of in free fall look ahead for the land
dist = upDir % velocity.Scale (timestep);
bodyMatrix.m_posit -= upDir.Scale (m_kinematicCushion);
dVector floorNormal;
dVector target (bodyMatrix.m_posit + upDir.Scale (dist));
if (FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam, floorNormal, threadIndex)) {
// player is about to land, snap position to the ground
bodyMatrix.m_posit = posit + upDir.Scale (dist * hitParam);
NewtonBodySetMatrix (m_body0, &bodyMatrix[0][0]);
if ((floorNormal % upDir) < m_maxSlope) {
m_playerState = m_onIlligalRamp;
} else {
m_playerState = m_onLand;
velocity = velocity - upDir.Scale (upDir % velocity);
}
}
NewtonBodySetVelocity(m_body0, &velocity[0]);
m_jumping = false;
}
void CustomPlayerController::PlayerOnRamp (dFloat timestep, int threadIndex)
{
dFloat hitParam;
dVector velocity;
dMatrix bodyMatrix;
// CastFilterData castFilterData (m_body0);
// NewtonWorldConvexCastReturnInfo info[MAX_CONTACTS];
// Get the global matrices of each rigid body.
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
dVector posit (bodyMatrix.m_posit);
dVector upDir (bodyMatrix.RotateVector (m_localMatrix0.m_front));
dVector frontDir (bodyMatrix.RotateVector (m_localMatrix0.m_up));
// make sure the body velocity will no penetrates other bodies
NewtonBodyGetVelocity (m_body0, &velocity[0]);
// apply free fall gravity force to the body along the ramp
// castFilterData.m_count = 1;
bodyMatrix.m_posit = posit + upDir.Scale (m_stairHeight);
dVector target (bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f));
dVector floorNormal;
// if (NewtonWorldConvexCast (m_world, &bodyMatrix[0][0], &target[0], m_bodyFloorSensorShape, &hitParam, &castFilterData, ConvexStaticCastPrefilter, info, sizeof (info) / sizeof (info[0]), threadIndex)) {
if (FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam, floorNormal, threadIndex)) {
// velocity -= m_gravity.Scale (timestep);
velocity += m_gravity.Scale (timestep);
// dVector floorNormal (info[0].m_normalOnHitPoint[0], info[0].m_normalOnHitPoint[1], info[0].m_normalOnHitPoint[2], 0.0f);
// dVector gravityForce (m_gravity - floorNormal.Scale (floorNormal % m_gravity));
// velocity = velocity - floorNormal.Scale (floorNormal % velocity) + gravityForce.Scale (timestep);
velocity = velocity - floorNormal.Scale (floorNormal % velocity);
}
velocity = CalculateVelocity (velocity, timestep, upDir, m_stairHeight, threadIndex);
// if the player did not change state, then make sure it is still landed on a floor
dVector step (velocity.Scale (timestep));
bodyMatrix.m_posit = posit + step + upDir.Scale(m_stairHeight - m_kinematicCushion);
target = bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f);
// castFilterData.m_count = 1;
// if (NewtonWorldConvexCast (m_world, &bodyMatrix[0][0], &target[0], m_bodyFloorSensorShape, &hitParam, &castFilterData, ConvexAllBodyCastPrefilter, info, 1, threadIndex)) {
if (FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam, floorNormal, threadIndex)) {
if (hitParam > 1.0e-3f) {
int isFuturePosiInRamp;
bodyMatrix.m_posit = bodyMatrix.m_posit + (target - bodyMatrix.m_posit).Scale (hitParam) - step + upDir.Scale (m_kinematicCushion);
NewtonBodySetMatrix (m_body0, &bodyMatrix[0][0]);
// dVector floorNormal (info[0].m_normalOnHitPoint[0], info[0].m_normalOnHitPoint[1], info[0].m_normalOnHitPoint[2], 0.0f);
isFuturePosiInRamp = (floorNormal % upDir) < m_maxSlope;
if (!isFuturePosiInRamp) {
m_playerState = m_onLand;
// } else {
// // apply free fall gravity force to the body along the ramp
// dFloat hitParam1;
// NewtonWorldConvexCastReturnInfo info1;
// bodyMatrix.m_posit = posit + upDir.Scale (m_stairHeight - m_kinematicCushion);
// dVector target (bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f));
// NewtonWorldConvexCast (m_world, &bodyMatrix[0][0], &target[0], m_bodyFloorSensorShape, &hitParam1, &castFilterData, ConvexAllBodyCastPrefilter, &info1, 1, threadIndex);
// if (hitParam < hitParam1) {
// // the player hit the edge of a forbidden ramp
// //floorNormal -= upDir.Scale (floorNormal % upDir);
// //_ASSERTE ((floorNormal % floorNormal) > 1.0e-3f);
// //floorNormal = floorNormal.Scale (1.0f / dSqrt (floorNormal % floorNormal));
// velocity -= floorNormal.Scale (velocity % floorNormal);
// }
}
}
} else {
m_playerState = m_onFreeFall;
}
NewtonBodySetVelocity(m_body0, &velocity[0]);
}
void CustomPlayerController::PlayerOnLand (dFloat timestep, int threadIndex)
{
dFloat hitParam;
dVector velocity;
dMatrix bodyMatrix;
// Get the global matrices of each rigid body.
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
dVector posit (bodyMatrix.m_posit);
dVector upDir (bodyMatrix.RotateVector (m_localMatrix0.m_front));
dVector frontDir (bodyMatrix.RotateVector (m_localMatrix0.m_up));
// enlarge the time step to no overshot too much
// make sure the body velocity will no penetrates other bodies
NewtonBodyGetVelocity (m_body0, &velocity[0]);
// subtract the Gravity contribution
velocity -= m_gravity.Scale (timestep);
velocity = CalculateVelocity (velocity, timestep, upDir, m_stairHeight, threadIndex);
// if the player did not change state, then make sure it is still landed on a floor
dVector step (velocity.Scale (timestep));
dVector target;
if (!m_jumping)
{
bodyMatrix.m_posit = posit + step + upDir.Scale (m_stairHeight - m_kinematicCushion);
target = (bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f));
}
else
{
bodyMatrix.m_posit = posit + step + upDir.Scale (0.0f - m_kinematicCushion);
target = (bodyMatrix.m_posit - upDir.Scale(0.0f * 2.0f));
}
dVector floorNormal;
if (FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam, floorNormal, threadIndex)) {
if (hitParam > 1.0e-3f) {
int isFuturePosiInRamp;
isFuturePosiInRamp = (floorNormal % upDir) < m_maxSlope;
if (isFuturePosiInRamp) {
// apply free fall gravity force to the body along the ramp
dFloat hitParam1;
dVector floorNormal1;
bodyMatrix.m_posit = posit + upDir.Scale (m_stairHeight - m_kinematicCushion);
target = bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f);
FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam1, floorNormal1, threadIndex);
if (hitParam < hitParam1) {
int iterations;
int contactCount = 1;
// the player hit the edge of a forbidden ramp
dVector savedVeloc (velocity);
for (iterations = 0; contactCount && (iterations < MAX_COLLISIONS_ITERATION); iterations ++) {
dFloat projectVel;
floorNormal -= upDir.Scale (floorNormal % upDir);
_ASSERTE ((floorNormal % floorNormal) > 1.0e-3f);
floorNormal = floorNormal.Scale (1.0f / dSqrt (floorNormal % floorNormal));
projectVel = velocity % floorNormal;
velocity -= floorNormal.Scale (projectVel);
step = velocity.Scale (timestep);
bodyMatrix.m_posit = posit + step + upDir.Scale (m_stairHeight - m_kinematicCushion);
target = bodyMatrix.m_posit - upDir.Scale(m_stairHeight * 2.0f);
if (FindFloor (bodyMatrix, target, upDir, m_bodyFloorSensorShape, hitParam, floorNormal, threadIndex)) {
contactCount = (floorNormal % upDir) < m_maxSlope;
}
}
if (iterations >= MAX_COLLISIONS_ITERATION) {
dVector veloc1 (CalculateVelocity (savedVeloc, timestep, upDir, m_stairHeight, threadIndex));
dVector err (veloc1 - velocity);
if ((err % err) < 1.0e-6f) {
m_playerState = m_onIlligalRamp;
} else {
velocity = veloc1;
hitParam = 0.0f;
step = dVector (0.0f, 0.0f, 0.0f, 0.0f);
bodyMatrix.m_posit = posit - upDir.Scale (m_kinematicCushion);
}
}
} else {
m_playerState = m_onIlligalRamp;
}
}
bodyMatrix.m_posit = bodyMatrix.m_posit + (target - bodyMatrix.m_posit).Scale (hitParam) + upDir.Scale (m_kinematicCushion);
bodyMatrix.m_posit -= step;
NewtonBodySetMatrix (m_body0, &bodyMatrix[0][0]);
}
} else {
m_playerState = m_onFreeFall;
}
NewtonBodySetVelocity(m_body0, &velocity[0]);
}
void CustomPlayerController::KinematicMotion (dFloat timestep, int threadIndex)
{
dFloat turnOmega;
dFloat turnAngle;
dMatrix bodyMatrix;
// handle angular velocity and heading
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
dVector upDir (bodyMatrix.RotateVector (m_localMatrix0.m_front));
dVector frontDir (bodyMatrix.RotateVector (m_localMatrix0.m_up));
dVector heading (0.0f, dCos (m_heading), dSin (m_heading), 0.0f);
heading = m_localMatrix0.RotateVector(heading);
turnAngle = (frontDir * heading) % upDir;
turnAngle = dAsin (min (max (turnAngle, -1.0f), 1.0f));
turnOmega = turnAngle / timestep;
dVector omega (upDir.Scale (turnOmega));
NewtonBodySetOmega(m_body0, &omega.m_x);
switch (m_playerState)
{
case m_onFreeFall:
PlayerOnFreeFall (timestep, threadIndex);
break;
case m_onLand:
PlayerOnLand (timestep, threadIndex);
break;
case m_onIlligalRamp:
PlayerOnRamp (timestep, threadIndex);
break;
}
}
void CustomPlayerController::AddImpulse(dFloat ximpulse, dFloat yimpulse, dFloat zimpulse, bool jump)
{
dMatrix bodyMatrix;
// Get the global matrices of each rigid body.
NewtonBodyGetMatrix(m_body0, &bodyMatrix[0][0]);
dVector velocity(ximpulse, yimpulse, zimpulse);
dVector posit(bodyMatrix.m_posit);
NewtonBodyAddImpulse(m_body0, &velocity[0], &posit[0]);
m_jumping = jump;
}
OgreNewt_PlayerController.h
/*
OgreNewt Library
Ogre implementation of Newton Game Dynamics SDK
OgreNewt basically has no license, you may use any or all of the library however you desire... I hope it can help you in any way.
by melven
*/
#ifndef _INCLUDE_OGRENEWT_PLAYERCONTROLLER
#define _INCLUDE_OGRENEWT_PLAYERCONTROLLER
#include "OgreNewt_Prerequisites.h"
#include "OgreNewt_Joint.h"
#include "OgreNewt_RayCast.h"
#include "OgreNewt_Body.h"
namespace OgreNewt
{
//! PlayerController
/*!
this class implements a player-controller based on the code of the CustomPlayerController-class in the Newton-CustomJoints library
*/
class _OgreNewtExport PlayerController : public Joint
{
public:
//! constructor
/*!
* \param localFrame this is the player frame in global Space (x: side, y: up, -z forward)
*/
PlayerController(OgreNewt::Body* child, Ogre::Real stairHeight, Ogre::Real max_slope = 30.0f, Ogre::Real kinematicCushion = 1.0f/64.0f);
virtual ~PlayerController();
//! get currently set velocity
void getVelocity(Ogre::Real &forwardSpeed, Ogre::Real& sideSpeed, Ogre::Radian& heading) const;
//! set the characters velocity, the -Speed-values can be negative, sideSpeed positive means move to the right, heading is in absolute space
void setVelocity(Ogre::Real forwardSpeed, Ogre::Real sideSpeed, Ogre::Radian heading);
//! get the Player height
Ogre::Real getPlayerHeight() const;
void setStairHeight(Ogre::Real height);
void setPlayerState(Ogre::uint32 state);
Ogre::uint32 getPlayerState();
void addImpulse(Ogre::Real xdelta, Ogre::Real ydelta, Ogre::Real zdelta, bool jump);
protected:
//! show joint visual debugging data
/*!
implement its own version of visual debugging
*/
virtual void showDebugData(Ogre::SceneNode* debugRootNode);
struct DebugInfo
{
void* m_playershape;
Ogre::SceneNode* m_node;
Ogre::ManualObject* m_visualDebug;
};
std::vector<DebugInfo> m_debugInfo;
};
} // end NAMESPACE OgreNewt
#endif // _INCLUDE_OGRENEWT_PLAYERCONTROLLER
OgreNewt_PlayerController.cpp
#include "OgreNewt_stdafx.h"
#include "OgreNewt_Body.h"
#include "OgreNewt_World.h"
#include "OgreNewt_Tools.h"
#include "OgreNewt_CollisionPrimitives.h"
#include "OgreNewt_PlayerController.h"
#include "CustomPlayerController.h"
namespace OgreNewt
{
PlayerController::PlayerController(OgreNewt::Body * child, Ogre::Real stairHeight, Ogre::Real maxSlope, Ogre::Real kinematicCushion)
:Joint()
{
dMatrix globalFrame (GetIdentityMatrix());
globalFrame.m_front = dVector (0.0f, 1.0f, 0.0f, 0.0f); // up direction in global Space
globalFrame.m_up = dVector (0.0f, 0.0f, -1.0f, 0.0f); // ogre front dir is the -z direction
globalFrame.m_right = globalFrame.m_front * globalFrame.m_up; // strafing direction in global Space
// create a newton player controller
CustomPlayerController* controller;
controller = new CustomPlayerController (globalFrame, child->getNewtonBody(), stairHeight, kinematicCushion);
controller->SetMaxSlope(Ogre::Degree(maxSlope).valueRadians());
SetSupportJoint(controller);
}
PlayerController::~PlayerController()
{
for (std::vector<DebugInfo>::iterator it (m_debugInfo.begin()); it != m_debugInfo.end(); it++) {
DebugInfo& info = (*it);
if (info.m_node->getParent()) {
info.m_node->getParent()->removeChild(info.m_node);
}
info.m_node->detachAllObjects();
// delete info.m_node;
delete info.m_visualDebug;
info.m_node = NULL;
info.m_visualDebug = NULL;
}
m_debugInfo.clear();
}
void PlayerController::getVelocity(Ogre::Real& forwardSpeed, Ogre::Real& sideSpeed, Ogre::Radian& heading) const
{
dFloat dir;
dir = 0.0f;
sideSpeed = 0.0f;
forwardSpeed = 0.0f;
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
joint->GetVelocity (forwardSpeed, sideSpeed, dir);
}
heading = dir;
}
void PlayerController::setVelocity(Ogre::Real forwardSpeed, Ogre::Real sideSpeed, Ogre::Radian heading)
{
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
joint->SetVelocity (forwardSpeed, sideSpeed, heading.valueRadians());
}
}
//! get the Paley height
Ogre::Real PlayerController::getPlayerHeight() const
{
Ogre::Real height = 0.0f;
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
height = joint->GetPlayerHeight();
}
return height;
}
void PlayerController::setStairHeight(Ogre::Real height)
{
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
joint->SetPlayerStairHeight(height);
}
}
void PlayerController::setPlayerState(Ogre::uint32 state)
{
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
joint->SetPlayerState((CustomPlayerController::PlayerState)state);
}
}
Ogre::uint32 PlayerController::getPlayerState()
{
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
return (Ogre::uint32)joint->GetPlayerState();
}
return 0;
}
void PlayerController::addImpulse(Ogre::Real xdelta, Ogre::Real ydelta, Ogre::Real zdelta, bool jump)
{
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
if (joint) {
joint->AddImpulse(xdelta, ydelta, zdelta, jump);
}
}
void PlayerController::showDebugData(Ogre::SceneNode* debugRootNode)
{
Body* playerBody = getBody0();
CustomPlayerController* joint = (CustomPlayerController*) m_joint;
Ogre::Vector3 pos;
Ogre::Quaternion orient;
// playerBody->getPositionOrientation(pos, orient);
playerBody->getVisualPositionOrientation (pos, orient);
dMatrix matrix (dQuaternion (orient.w, orient.x, orient.y, orient.z), dVector (pos.x, pos.y, pos.z, 1.0f));
if (!m_debugInfo.size()) {
DebugInfo newInfo;
std::ostringstream oss;
Ogre::Vector3 pos;
Ogre::Quaternion orient;
OgreNewt::Debugger& debug(playerBody->getWorld()->getDebugger());
oss << "__OgreNewt__Debugger__Lines__" << joint->GetSensorShape() << "__";
newInfo.m_visualDebug = new Ogre::ManualObject(oss.str());
newInfo.m_node = debugRootNode->createChildSceneNode();
newInfo.m_playershape = (void*) joint->GetSensorShape();
OgreNewt::Collision sensorCollision (joint->GetSensorShape(), playerBody->getWorld());
debug.buildDebugObjectFromCollision(newInfo.m_visualDebug, Ogre::ColourValue(1, 0, 0, 1), sensorCollision);
newInfo.m_node->attachObject(newInfo.m_visualDebug);
// append this debug info to the array
m_debugInfo.push_back(newInfo);
oss << "__OgreNewt__Debugger__Lines__" << joint->GetStairStepShape() << "__";
newInfo.m_visualDebug = new Ogre::ManualObject(oss.str());
newInfo.m_node = debugRootNode->createChildSceneNode();
newInfo.m_playershape = (void*) joint->GetSensorShape();
OgreNewt::Collision stairCollision (joint->GetStairStepShape(), playerBody->getWorld());
debug.buildDebugObjectFromCollision(newInfo.m_visualDebug, Ogre::ColourValue(1, 1, 0, 1), stairCollision);
newInfo.m_node->attachObject(newInfo.m_visualDebug);
// append this debug info to the array
m_debugInfo.push_back(newInfo);
}
DebugInfo& shapeInfo = m_debugInfo[0];
shapeInfo.m_node->setPosition(pos);
shapeInfo.m_node->setOrientation (orient);
if (!shapeInfo.m_node->getParent()) {
debugRootNode->addChild(shapeInfo.m_node);
}
pos.y += joint->GetPlayerStairHeight();
DebugInfo& stairInfo = m_debugInfo[1];
stairInfo.m_node->setPosition(pos);
stairInfo.m_node->setOrientation (orient);
if (!stairInfo.m_node->getParent()) {
debugRootNode->addChild(stairInfo.m_node);
}
}
} // end NAMESPACE OgreNewt
Note that this does NOT fix the other issues with stair stepping, it just fixes the jumping.
- Houdini