updates
This commit is contained in:
17
Game.cpp
17
Game.cpp
@@ -244,7 +244,7 @@ public:
|
||||
float panel_width;
|
||||
void initGui();
|
||||
};
|
||||
#undef WATER
|
||||
#define WATER
|
||||
class App : public OgreBites::ApplicationContext {
|
||||
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
|
||||
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
|
||||
@@ -262,6 +262,7 @@ class App : public OgreBites::ApplicationContext {
|
||||
#ifdef WATER
|
||||
Water m_water;
|
||||
#endif
|
||||
bool mTerrainReady;
|
||||
class KeyboardListener : public OgreBites::InputListener,
|
||||
public Ogre::FrameListener {
|
||||
App *mApp;
|
||||
@@ -366,8 +367,10 @@ class App : public OgreBites::ApplicationContext {
|
||||
update(evt.timeSinceLastFrame);
|
||||
if (mApp->getCharacterController() && gui_active)
|
||||
mApp->getCharacterController()->disableUpdates();
|
||||
else if (mApp->getCharacterController() && !gui_active)
|
||||
else if (mApp->getCharacterController() && !gui_active && mApp->isTerrainReady()) {
|
||||
OgreAssert(mApp->isTerrainReady(), "terrain is not ready");
|
||||
mApp->getCharacterController()->enableUpdates();
|
||||
}
|
||||
if (!gui_active) {
|
||||
mApp->updateSun(evt.timeSinceLastFrame);
|
||||
mApp->updateTerrain(evt.timeSinceLastFrame);
|
||||
@@ -387,6 +390,7 @@ public:
|
||||
Ogre::Vector3(0, -9.8, 0)))
|
||||
, m_terrain(mDynWorld->getBtWorld())
|
||||
, mCharacterController(nullptr)
|
||||
, mTerrainReady(false)
|
||||
{
|
||||
}
|
||||
virtual ~App()
|
||||
@@ -550,6 +554,15 @@ public:
|
||||
Ogre::Timer mTerrainUpd;
|
||||
void updateTerrain(float delta)
|
||||
{
|
||||
Ogre::Vector3 pos = mCharacterController->getPosition();
|
||||
if (!mTerrainReady && m_terrain.isLoadedAt(pos) && mCharacterController->checkGround()) {
|
||||
std::cout << "terrain ready\n";
|
||||
mTerrainReady = true;
|
||||
}
|
||||
}
|
||||
bool isTerrainReady()
|
||||
{
|
||||
return mTerrainReady;
|
||||
}
|
||||
// TODO: implement rough water level calculation
|
||||
float getWaterLevel(const Ogre::Vector3 &position)
|
||||
|
||||
@@ -184,6 +184,7 @@ CharacterController::CharacterController(Ogre::SceneNode *camNode,
|
||||
, mWorld(world)
|
||||
, mCollisionShape(nullptr)
|
||||
, mGhostObject(nullptr)
|
||||
, gvelocity(0.0f, 0.0f, 0.0f)
|
||||
, mUpdate(false)
|
||||
{
|
||||
setupBody();
|
||||
@@ -231,12 +232,12 @@ void CharacterController::setupBody()
|
||||
mWorld->attachCollisionObject(mGhostObject, mBodyEnt,
|
||||
1,
|
||||
0x7FFFFFF);
|
||||
Ogre::Bullet::KinematicMotionSimple *controller =
|
||||
mController =
|
||||
new Ogre::Bullet::KinematicMotionSimple(mGhostObject,
|
||||
mBodyNode);
|
||||
OgreAssert(mGhostObject, "Need GhostObject");
|
||||
OgreAssert(controller, "Need controller");
|
||||
mWorld->getBtWorld()->addAction(controller);
|
||||
OgreAssert(mController, "Need controller");
|
||||
mWorld->getBtWorld()->addAction(mController);
|
||||
|
||||
OgreAssert(mCollisionShape, "No collision shape");
|
||||
#if 0
|
||||
@@ -555,105 +556,48 @@ struct EntityCollisionListener
|
||||
const Ogre::MovableObject* entity;
|
||||
Ogre::Bullet::CollisionListener* listener;
|
||||
};
|
||||
static bool is_on_floor = false;
|
||||
static bool penetration = false;
|
||||
static int is_on_floor_count = 0;
|
||||
void CharacterController::updateRootMotion(Ogre::Real delta)
|
||||
{
|
||||
int i, j, k;
|
||||
Ogre::Quaternion rot = mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = mRootBone->getPosition();
|
||||
Ogre::Vector3 velocity = rot * boneMotion / delta;
|
||||
OgreAssert(delta > 0.0f, "Zero delta");
|
||||
int maxPen = 0;
|
||||
Ogre::Vector3 colNormal;
|
||||
btVector3 currentPosition = mGhostObject->getWorldTransform().getOrigin();
|
||||
for (i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) {
|
||||
btManifoldArray manifoldArray;
|
||||
btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
if (collisionPair->m_algorithm)
|
||||
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
|
||||
for (j = 0; j < manifoldArray.size(); j++) {
|
||||
btPersistentManifold * manifold = manifoldArray[j];
|
||||
btScalar directionSign = manifold->getBody0() == mGhostObject ? btScalar(-1) : btScalar(1);
|
||||
for (k = 0; k < manifold->getNumContacts(); k++) {
|
||||
const btManifoldPoint &pt = manifold->getContactPoint(k);
|
||||
btScalar dist = pt.getDistance();
|
||||
if (dist < 0) {
|
||||
maxPen = dist;
|
||||
btVector3 touchingNormal = pt.m_normalWorldOnB;
|
||||
colNormal = Ogre::Bullet::convert(touchingNormal);
|
||||
if (touchingNormal.y() > 0 && (
|
||||
touchingNormal.y() > Ogre::Math::Abs(touchingNormal.x()) ||
|
||||
touchingNormal.y() > Ogre::Math::Abs(touchingNormal.z())))
|
||||
is_on_floor = true;
|
||||
penetration = true;
|
||||
}
|
||||
currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
|
||||
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
std::cout << "overlapping: " << i << " "
|
||||
<< manifoldArray.size()
|
||||
<< " is_on_floor = " << is_on_floor
|
||||
<< " position: " << Ogre::Bullet::convert(currentPosition)
|
||||
<< " colNormal: " << colNormal
|
||||
<< " penetration: " << penetration
|
||||
<< " dist: " << maxPen << "\n";
|
||||
#endif
|
||||
}
|
||||
btTransform newTrans = mGhostObject->getWorldTransform();
|
||||
newTrans.setOrigin(currentPosition);
|
||||
#if 0
|
||||
Ogre::Vector3 motion = boneMotion - rootMotion;
|
||||
if (motion.squaredLength() > 0.1f * 0.1f)
|
||||
motion = Ogre::Vector3();
|
||||
rootMotion = boneMotion;
|
||||
#endif
|
||||
#if 0
|
||||
float mass = mRigidBody->getMass();
|
||||
std::cout << "Root bone position: " << boneMotion << "\n";
|
||||
std::cout << "body mass: " << mass << "\n";
|
||||
#endif
|
||||
/* Kinematic motion */
|
||||
if (is_on_floor)
|
||||
is_on_floor_count++;
|
||||
else
|
||||
is_on_floor_count--;
|
||||
Ogre::Quaternion rot = mBodyNode->getOrientation();
|
||||
bool is_on_floor = false;
|
||||
bool penetration = false;
|
||||
Ogre::Vector3 gravity(0, -9.8, 0);
|
||||
Ogre::Vector3 velocity = rot * boneMotion / delta;
|
||||
if (is_on_floor_count < 0 && !penetration)
|
||||
velocity += gravity;
|
||||
if (is_on_floor_count < 0 && penetration)
|
||||
velocity += gravity * delta;
|
||||
if (is_on_floor_count < -1)
|
||||
is_on_floor_count = -1;
|
||||
if (is_on_floor_count > 1)
|
||||
is_on_floor_count = 1;
|
||||
gvelocity += gravity * delta;
|
||||
velocity += gvelocity;
|
||||
Ogre::Vector3 rotMotion = velocity * delta;
|
||||
btVector3 currentPosition = mGhostObject->getWorldTransform().getOrigin();
|
||||
is_on_floor = mController->isOnFloor();
|
||||
penetration = mController->isPenetrating();
|
||||
if (is_on_floor)
|
||||
gvelocity = Ogre::Vector3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
btTransform from(convert(mBodyNode->getOrientation()),
|
||||
convert(mBodyNode->getPosition()));
|
||||
mBodyNode->setPosition(mBodyNode->getPosition() + rotMotion);
|
||||
// WorldData::get_singleton()->getWorld()->testBodyMotion(mRigidBody, from, Ogre::Bullet::convert(rotMotion), true,
|
||||
// nullptr, false, std::set<btCollisionObject *>());
|
||||
#if 0
|
||||
if (mGhostObject->getNumOverlappingObjects() > 0) {
|
||||
int i;
|
||||
std::cout << "overlaps: " << mGhostObject->getNumOverlappingObjects() << "\n";
|
||||
for (i = 0; i < mGhostObject->getNumOverlappingObjects(); i++) {
|
||||
btCollisionObject *collided = nullptr;
|
||||
EntityCollisionListener *a = nullptr;
|
||||
collided = mGhostObject->getOverlappingObject(i);
|
||||
if (collided)
|
||||
a = static_cast<EntityCollisionListener*>(collided->getUserPointer());
|
||||
std::cout << i << " " << collided << " " << a << " ";
|
||||
if (a)
|
||||
std::cout << a->entity << " ";
|
||||
if (a->entity)
|
||||
std::cout << a->entity->getName();
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
std::cout << "rotMotion: " << rotMotion
|
||||
<< " isOnFloor: " << is_on_floor
|
||||
<< " pairs: " << mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs()
|
||||
<< " manifolds: " << mController->getManifolds()
|
||||
<< " penetration: " << penetration << "\n";
|
||||
std::cout << " position: " << mBodyNode->getPosition() << "\n";
|
||||
#endif
|
||||
#if 0
|
||||
std::cout
|
||||
<< " velocity: " << velocity
|
||||
<< " penetration: " << penetration
|
||||
<< " rotMotion: " << rotMotion
|
||||
<< "\n";
|
||||
std::cout << "old position: " << pos
|
||||
<< " new position: " << mBodyNode->getPosition()
|
||||
<< "\n";
|
||||
#endif
|
||||
}
|
||||
void CharacterController::fadeAnimations(Ogre::Real delta)
|
||||
|
||||
@@ -80,8 +80,10 @@ class CharacterController : public OgreBites::InputListener,
|
||||
// btRigidBody *mRigidBody;
|
||||
btCompoundShape *mCollisionShape;
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
Ogre::Vector3 gvelocity;
|
||||
|
||||
bool mUpdate;
|
||||
Ogre::Bullet::KinematicMotionSimple *mController;
|
||||
|
||||
public:
|
||||
CharacterController(Ogre::SceneNode *camNode, Ogre::Camera *cam,
|
||||
@@ -174,4 +176,42 @@ public:
|
||||
{
|
||||
return mUpdate;
|
||||
}
|
||||
Ogre::Vector3 getPosition() const
|
||||
{
|
||||
return mBodyNode->getPosition();
|
||||
}
|
||||
Ogre::Quaternion getRotation() const
|
||||
{
|
||||
return mBodyNode->getOrientation();
|
||||
}
|
||||
class ClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback {
|
||||
btCollisionObject *mMe;
|
||||
public:
|
||||
ClosestNotMeRayResultCallback(
|
||||
btCollisionObject *me,
|
||||
const btVector3 &from,
|
||||
const btVector3 &to):
|
||||
btCollisionWorld::ClosestRayResultCallback(from, to) {
|
||||
mMe = me;
|
||||
}
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace)
|
||||
{
|
||||
if (rayResult.m_collisionObject == mMe)
|
||||
return 1.0f;
|
||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||
}
|
||||
};
|
||||
bool checkGround()
|
||||
{
|
||||
btVector3 from = mGhostObject->getWorldTransform().getOrigin() + btVector3(0, 0.2f, 0);
|
||||
btVector3 to = from + btVector3(0, -3000.0f, 0);
|
||||
ClosestNotMeRayResultCallback
|
||||
resultCallback(mGhostObject, from, to);
|
||||
mGhostObject->rayTest(from, to, resultCallback);
|
||||
// std::cout << (resultCallback.hasHit() ? "hit" : "no hit");
|
||||
// if (resultCallback.hasHit())
|
||||
// std::cout << " " << Ogre::Bullet::convert(resultCallback.m_hitPointWorld);
|
||||
// std::cout << "\n";
|
||||
return resultCallback.hasHit();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -404,5 +404,12 @@ public:
|
||||
return body;
|
||||
}
|
||||
#endif
|
||||
bool isLoadedAt(const Ogre::Vector3 &position) const {
|
||||
long x, y;
|
||||
mTerrainGroup->convertWorldPositionToTerrainSlot(position, &x, &y);
|
||||
if (mTerrainGroup->getTerrain(x, y))
|
||||
return mTerrainGroup->getTerrain(x, y)->isLoaded();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user