657 lines
21 KiB
C++
657 lines
21 KiB
C++
#include <iostream>
|
|
#include <OgreMath.h>
|
|
#include "GameData.h"
|
|
#include "character.h"
|
|
#include "controller.h"
|
|
#if 0
|
|
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
|
CharacterController::CharacterController(Ogre::SceneNode *camNode,
|
|
Ogre::Camera *cam,
|
|
Ogre::SceneManager *scnMgr,
|
|
Character *character)
|
|
: mCameraNode(camNode)
|
|
, mCamera(cam)
|
|
, mScnMgr(scnMgr)
|
|
, mPivotPitch(0)
|
|
, mVerticalVelocity(0)
|
|
, mRunning(false)
|
|
, mCharacter(character)
|
|
, mCameraPivot(nullptr)
|
|
{
|
|
setupCamera();
|
|
}
|
|
CharacterController::~CharacterController()
|
|
{
|
|
}
|
|
void CharacterController::setupCamera()
|
|
{
|
|
// create a pivot at roughly the character's shoulder
|
|
mCameraPivot = mScnMgr->getRootSceneNode()->createChildSceneNode();
|
|
mCameraGoal =
|
|
mCameraPivot->createChildSceneNode(Ogre::Vector3(0, 2, 3));
|
|
mCameraNode->setPosition(mCameraPivot->getPosition() +
|
|
mCameraGoal->getPosition());
|
|
mCameraPivot->setFixedYawAxis(true);
|
|
mCameraGoal->setFixedYawAxis(true);
|
|
mCameraNode->setFixedYawAxis(true);
|
|
// our model is quite small, so reduce the clipping planes
|
|
mCamera->setNearClipDistance(0.1f);
|
|
mCamera->setFarClipDistance(700);
|
|
|
|
mPivotPitch = 0;
|
|
mKeyDirection = Ogre::Vector3::ZERO;
|
|
mVerticalVelocity = 0;
|
|
std::cout << "ORIGINAL: " << mCameraNode->getPosition() << "\n";
|
|
}
|
|
bool CharacterController::keyPressed(const OgreBites::KeyboardEvent &evt)
|
|
{
|
|
OgreBites::Keycode key = evt.keysym.sym;
|
|
if (key == 'q') {
|
|
/* ... */
|
|
} else if (key == 'e') {
|
|
} else if (key == 'w')
|
|
mKeyDirection.z = -1;
|
|
else if (key == 'a')
|
|
mKeyDirection.x = -1;
|
|
else if (key == 's')
|
|
mKeyDirection.z = 1;
|
|
else if (key == 'd')
|
|
mKeyDirection.x = 1;
|
|
if (key == OgreBites::SDLK_LSHIFT)
|
|
mRunning = true;
|
|
if (!mKeyDirection.isZeroLength() && mCharacter->isIdle()) {
|
|
if (mRunning)
|
|
mCharacter->act_run();
|
|
else
|
|
mCharacter->act_walk();
|
|
// std::cout << "Walking\n";
|
|
} else if (!mKeyDirection.isZeroLength() && mCharacter->isWalking() &&
|
|
mRunning)
|
|
mCharacter->act_run();
|
|
return true;
|
|
}
|
|
bool CharacterController::keyReleased(const OgreBites::KeyboardEvent &evt)
|
|
{
|
|
OgreBites::Keycode key = evt.keysym.sym;
|
|
if (key == 'w' && mKeyDirection.z == -1)
|
|
mKeyDirection.z = 0;
|
|
else if (key == 'a' && mKeyDirection.x == -1)
|
|
mKeyDirection.x = 0;
|
|
else if (key == 's' && mKeyDirection.z == 1)
|
|
mKeyDirection.z = 0;
|
|
else if (key == 'd' && mKeyDirection.x == 1)
|
|
mKeyDirection.x = 0;
|
|
if (key == OgreBites::SDLK_LSHIFT)
|
|
mRunning = false;
|
|
|
|
if (mKeyDirection.isZeroLength() && mCharacter->isMoving())
|
|
mCharacter->act_idle();
|
|
else if (!mKeyDirection.isZeroLength() && mCharacter->isRunning() &&
|
|
!mRunning)
|
|
mCharacter->act_walk();
|
|
|
|
return true;
|
|
}
|
|
bool CharacterController::mouseMoved(const OgreBites::MouseMotionEvent &evt)
|
|
{
|
|
// update camera goal based on mouse movement
|
|
updateCameraGoal(-0.18f * evt.xrel, -0.12f * evt.yrel, 0);
|
|
return true;
|
|
}
|
|
bool CharacterController::mouseWheelRolled(const OgreBites::MouseWheelEvent &evt)
|
|
{
|
|
// update camera goal based on mouse movement
|
|
updateCameraGoal(0, 0, -0.15f * evt.y);
|
|
return true;
|
|
}
|
|
bool CharacterController::mousePressed(const OgreBites::MouseButtonEvent &evt)
|
|
{
|
|
std::cout << "Mouse press\n";
|
|
return false;
|
|
}
|
|
void CharacterController::frameRendered(const Ogre::FrameEvent &evt)
|
|
{
|
|
Ogre::Vector3 goalDirection = Ogre::Vector3::ZERO;
|
|
updateCamera(evt.timeSinceLastFrame);
|
|
if (mKeyDirection != Ogre::Vector3::ZERO) {
|
|
// calculate actually goal direction in world based on player's key directions
|
|
goalDirection +=
|
|
mKeyDirection.z * mCameraNode->getOrientation().zAxis();
|
|
goalDirection +=
|
|
mKeyDirection.x * mCameraNode->getOrientation().xAxis();
|
|
goalDirection.y = 0;
|
|
goalDirection.normalise();
|
|
mCharacter->setGoalDirection(goalDirection);
|
|
}
|
|
}
|
|
bool CharacterController::frameStarted(const Ogre::FrameEvent &evt)
|
|
{
|
|
return true;
|
|
}
|
|
void CharacterController::updateCameraGoal(Ogre::Real deltaYaw,
|
|
Ogre::Real deltaPitch,
|
|
Ogre::Real deltaZoom)
|
|
{
|
|
mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
|
|
if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
|
|
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
|
|
mCameraPivot->pitch(Ogre::Degree(deltaPitch),
|
|
Ogre::Node::TS_LOCAL);
|
|
mPivotPitch += deltaPitch;
|
|
}
|
|
Ogre::Real dist = mCameraGoal->_getDerivedPosition().distance(
|
|
mCameraPivot->_getDerivedPosition());
|
|
Ogre::Real distChange = deltaZoom * dist;
|
|
|
|
// bound the zoom
|
|
if (!(dist + distChange < 8 && distChange < 0) &&
|
|
!(dist + distChange > 25 && distChange > 0))
|
|
mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL);
|
|
}
|
|
void CharacterController::updateCamera(Ogre::Real delta)
|
|
{
|
|
// static int count = 0;
|
|
// place the camera pivot roughly at the character's shoulder
|
|
Ogre::Vector3 pivotOffset =
|
|
mCharacter->getPosition() - mCameraPivot->_getDerivedPosition();
|
|
Ogre::Vector3 pivotPos = mCameraPivot->_getDerivedPosition();
|
|
mCameraPivot->setPosition(pivotPos + pivotOffset * 0.1f * delta +
|
|
Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
|
|
// move the camera smoothly to the goal
|
|
Ogre::Vector3 goalOffset =
|
|
mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
|
|
mCameraNode->translate(goalOffset * delta * 9.0f);
|
|
// always look at the pivot
|
|
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(),
|
|
Ogre::Node::TS_PARENT);
|
|
}
|
|
#endif
|
|
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
|
#define RUN_SPEED 17 // character running speed in units per second
|
|
#define TURN_SPEED 500.0f // character turning in degrees per second
|
|
#define ANIM_FADE_SPEED \
|
|
7.5f // animation crossfade speed in % of full weight per second
|
|
CharacterController::CharacterController(Ogre::SceneNode *camNode,
|
|
Ogre::Camera *cam,
|
|
Ogre::SceneManager *scnMgr,
|
|
Ogre::Bullet::DynamicsWorld *world)
|
|
: mCameraNode(camNode)
|
|
, mCamera(cam)
|
|
, mScnMgr(scnMgr)
|
|
, mPivotPitch(0)
|
|
, mVerticalVelocity(0)
|
|
, mAnimID(ANIM_NONE)
|
|
, mRunning(false)
|
|
, mWorld(world)
|
|
, mCollisionShape(nullptr)
|
|
, mGhostObject(nullptr)
|
|
, gvelocity(0.0f, 0.0f, 0.0f)
|
|
, mUpdate(false)
|
|
{
|
|
setupBody();
|
|
setupCamera();
|
|
setupAnimations();
|
|
Ogre::Root::getSingleton().addFrameListener(this);
|
|
}
|
|
CharacterController::~CharacterController()
|
|
{
|
|
}
|
|
void CharacterController::setupBody()
|
|
{
|
|
mBodyEnt = mScnMgr->createEntity("normal-male.glb");
|
|
mBodyNode = mScnMgr->getRootSceneNode()->createChildSceneNode();
|
|
mBodyNode->attachObject(mBodyEnt);
|
|
mSkeleton = mBodyEnt->getSkeleton();
|
|
// mRigidBody = world->addCharacter(mBodyEnt, 0);
|
|
// mCollisionShape = static_cast<btCompoundShape *>(mRigidBody->getCollisionShape());
|
|
mGhostObject = new btPairCachingGhostObject();
|
|
mCollisionShape = new btCompoundShape;
|
|
mGhostObject->setCollisionShape(mCollisionShape);
|
|
|
|
{
|
|
btVector3 inertia(0, 0, 0);
|
|
// mCollisionShape = new btCompoundShape();
|
|
btScalar height = 1.0f;
|
|
btScalar radius = 0.3f;
|
|
btCapsuleShape *shape =
|
|
new btCapsuleShape(radius, 2 * height - 2 * radius);
|
|
btTransform transform;
|
|
transform.setIdentity();
|
|
transform.setOrigin(btVector3(0, 1, 0));
|
|
static_cast<btCompoundShape *>(mCollisionShape)
|
|
->addChildShape(transform, shape);
|
|
btScalar masses[1] = { 0 };
|
|
btTransform principal;
|
|
static_cast<btCompoundShape *>(mCollisionShape)
|
|
->calculatePrincipalAxisTransform(masses, principal,
|
|
inertia);
|
|
}
|
|
mGhostObject->setCollisionFlags(
|
|
btCollisionObject::CF_KINEMATIC_OBJECT |
|
|
btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
|
mGhostObject->setActivationState(DISABLE_DEACTIVATION);
|
|
mWorld->attachCollisionObject(mGhostObject, mBodyEnt, 1, 0x7FFFFFF);
|
|
mController = new Ogre::Bullet::KinematicMotionSimple(mGhostObject,
|
|
mBodyNode);
|
|
OgreAssert(mGhostObject, "Need GhostObject");
|
|
OgreAssert(mController, "Need controller");
|
|
mWorld->getBtWorld()->addAction(mController);
|
|
|
|
OgreAssert(mCollisionShape, "No collision shape");
|
|
#if 0
|
|
if (mRigidBody->getMass() == 0) {
|
|
#if 0
|
|
mRigidBody->setCollisionFlags(mRigidBody->getCollisionFlags()
|
|
| btCollisionObject::CF_KINEMATIC_OBJECT
|
|
| btCollisionObject::CF_NO_CONTACT_RESPONSE
|
|
);
|
|
#endif
|
|
#if 0
|
|
mGhostObject->setWorldTransform(mRigidBody->getWorldTransform());
|
|
WorldData::get_singleton()->getBtWorld()
|
|
->getBroadphase()->getOverlappingPairCache()
|
|
->setInternalGhostPairCallback(new btGhostPairCallback());
|
|
#endif
|
|
}
|
|
#endif
|
|
#if 0
|
|
mRigidBody->setActivationState(DISABLE_DEACTIVATION);
|
|
#endif
|
|
#if 0
|
|
{
|
|
Ogre::Entity *e2 = mScnMgr->createEntity("normal-male.glb");
|
|
Ogre::SceneNode *e2node = mScnMgr->getRootSceneNode()->createChildSceneNode();
|
|
e2node->attachObject(e2);
|
|
mGhostObject = WorldData::get_singleton()->addGhostObject(e2, mCollisionShape);
|
|
mController = new btKinematicCharacterController(mGhostObject, mCollisionShape, 0.5f);
|
|
WorldData::get_singleton()->getBtWorld()->addAction(mController);
|
|
}
|
|
#endif
|
|
OgreAssert(mSkeleton->hasBone("Root"), "No root bone");
|
|
mRootBone = mSkeleton->getBone("Root");
|
|
OgreAssert(mRootBone, "No root bone");
|
|
}
|
|
void CharacterController::setupCamera()
|
|
{
|
|
// create a pivot at roughly the character's shoulder
|
|
mCameraPivot = mScnMgr->getRootSceneNode()->createChildSceneNode();
|
|
mCameraGoal =
|
|
mCameraPivot->createChildSceneNode(Ogre::Vector3(0, 2, 3));
|
|
mCameraNode->setPosition(mCameraPivot->getPosition() +
|
|
mCameraGoal->getPosition());
|
|
mCameraPivot->setFixedYawAxis(true);
|
|
mCameraGoal->setFixedYawAxis(true);
|
|
mCameraNode->setFixedYawAxis(true);
|
|
// our model is quite small, so reduce the clipping planes
|
|
mCamera->setNearClipDistance(0.1f);
|
|
mCamera->setFarClipDistance(700);
|
|
|
|
mPivotPitch = 0;
|
|
mKeyDirection = Ogre::Vector3::ZERO;
|
|
mVerticalVelocity = 0;
|
|
}
|
|
void CharacterController::setupAnimations()
|
|
{
|
|
int i, j;
|
|
mSkeleton->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
|
|
Ogre::String animNames[NUM_ANIMS] = { "idle", "walking", "running" };
|
|
for (i = 0; i < NUM_ANIMS; i++) {
|
|
mAnims[i] = mBodyEnt->getAnimationState(animNames[i]);
|
|
mAnims[i]->setLoop(true);
|
|
mAnims[i]->setEnabled(true);
|
|
mAnims[i]->setWeight(0);
|
|
mFadingIn[i] = false;
|
|
mFadingOut[i] = false;
|
|
mSkelAnimations[i] = mSkeleton->getAnimation(animNames[i]);
|
|
for (const auto &it : mSkelAnimations[i]->_getNodeTrackList()) {
|
|
Ogre::NodeAnimationTrack *track = it.second;
|
|
Ogre::String trackName =
|
|
track->getAssociatedNode()->getName();
|
|
if (trackName == "mixamorig:Hips") {
|
|
mHipsTracks[i] = track;
|
|
} else if (trackName == "Root") {
|
|
mRootTracks[i] = track;
|
|
// mRootTracks[i]->removeAllKeyFrames();
|
|
}
|
|
}
|
|
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
|
|
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
|
|
for (j = 0; j < mRootTracks[i]->getNumKeyFrames(); j++) {
|
|
Ogre::Vector3 trans = mRootTracks[i]
|
|
->getNodeKeyFrame(j)
|
|
->getTranslate();
|
|
if (j == 0)
|
|
delta = trans;
|
|
else
|
|
delta = trans - motion;
|
|
mRootTracks[i]->getNodeKeyFrame(j)->setTranslate(delta);
|
|
motion = trans;
|
|
}
|
|
}
|
|
#if 0
|
|
for(i = 0; i < NUM_ANIMS - 1; i++) {
|
|
// need to cache
|
|
int j;
|
|
Ogre::String animName = mAnims[i]->getAnimationName();
|
|
Ogre::Animation *anim = mSkeleton->getAnimation(animName);
|
|
Ogre::NodeAnimationTrack *hips_track = nullptr, *root_track = nullptr;
|
|
Ogre::Node *root_node = nullptr;
|
|
for (const auto& it : anim->_getNodeTrackList()) {
|
|
Ogre::NodeAnimationTrack* track = it.second;
|
|
Ogre::String trackName = track->getAssociatedNode()->getName();
|
|
std::cout << animName << " track: " << trackName << "\n";
|
|
if (trackName == "mixamorig:Hips")
|
|
hips_track = track;
|
|
else if (trackName == "Root") {
|
|
root_track = track;
|
|
root_node = track->getAssociatedNode();
|
|
}
|
|
}
|
|
assert(false);
|
|
root_track->removeAllKeyFrames();
|
|
std::cout << hips_track << " " << root_track << "\n";
|
|
std::cout << hips_track->getNumKeyFrames() << " " << root_track->getNumKeyFrames() << "\n";
|
|
assert(hips_track && root_track);
|
|
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
|
|
for(j = 0; j < hips_track->getNumKeyFrames(); j++) {
|
|
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
|
|
Ogre::Vector3 trans = hips_track->getNodeKeyFrame(j)->getTranslate();
|
|
Ogre::Vector3 hips_trans(0, 0, 0);
|
|
Ogre::Vector3 root_trans(0, 0, 0);
|
|
hips_track->getNodeKeyFrame(j)->setTranslate(hips_trans);
|
|
Ogre::TransformKeyFrame *nk = root_track->createNodeKeyFrame(timePos);
|
|
nk->setTranslate(root_trans - delta);
|
|
nk->setScale(Ogre::Vector3(1, 1, 1));
|
|
nk->setRotation(Ogre::Quaternion());
|
|
std::cout << animName << " delta: " << j << " " << timePos << " " << root_trans - delta << "\n";
|
|
delta = root_trans;
|
|
}
|
|
for(j = 0; j < root_track->getNumKeyFrames(); j++) {
|
|
float timePos = hips_track->getNodeKeyFrame(j)->getTime();
|
|
Ogre::Vector3 root_trans = hips_track->getNodeKeyFrame(j)->getTranslate();
|
|
std::cout << animName << " delta: root: " << j << " " << timePos << " " << root_trans << "\n";
|
|
}
|
|
}
|
|
// assert(false);
|
|
#endif
|
|
setAnimation(ANIM_IDLE);
|
|
}
|
|
bool CharacterController::keyPressed(const OgreBites::KeyboardEvent &evt)
|
|
{
|
|
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
|
OgreBites::Keycode key = evt.keysym.sym;
|
|
if (key == 'q' && (mAnimID == ANIM_IDLE)) {
|
|
/* ... */
|
|
mTimer = 0;
|
|
} else if (key == 'e') {
|
|
} else if (key == 'w')
|
|
mKeyDirection.z = -1;
|
|
else if (key == 'a')
|
|
mKeyDirection.x = -1;
|
|
else if (key == 's')
|
|
mKeyDirection.z = 1;
|
|
else if (key == 'd')
|
|
mKeyDirection.x = 1;
|
|
if (key == OgreBites::SDLK_LSHIFT)
|
|
mRunning = true;
|
|
if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_IDLE) {
|
|
if (mRunning)
|
|
setAnimation(ANIM_RUN, true);
|
|
else
|
|
setAnimation(ANIM_WALK, true);
|
|
// std::cout << "Walking\n";
|
|
} else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_WALK &&
|
|
mRunning)
|
|
setAnimation(ANIM_RUN);
|
|
return true;
|
|
}
|
|
bool CharacterController::keyReleased(const OgreBites::KeyboardEvent &evt)
|
|
{
|
|
OgreBites::Keycode key = evt.keysym.sym;
|
|
if (key == 'w' && mKeyDirection.z == -1)
|
|
mKeyDirection.z = 0;
|
|
else if (key == 'a' && mKeyDirection.x == -1)
|
|
mKeyDirection.x = 0;
|
|
else if (key == 's' && mKeyDirection.z == 1)
|
|
mKeyDirection.z = 0;
|
|
else if (key == 'd' && mKeyDirection.x == 1)
|
|
mKeyDirection.x = 0;
|
|
if (key == OgreBites::SDLK_LSHIFT)
|
|
mRunning = false;
|
|
|
|
if (mKeyDirection.isZeroLength() &&
|
|
(mAnimID == ANIM_WALK || mAnimID == ANIM_RUN))
|
|
setAnimation(ANIM_IDLE);
|
|
else if (!mKeyDirection.isZeroLength() && mAnimID == ANIM_RUN &&
|
|
!mRunning)
|
|
setAnimation(ANIM_WALK);
|
|
|
|
return true;
|
|
}
|
|
bool CharacterController::mouseMoved(const OgreBites::MouseMotionEvent &evt)
|
|
{
|
|
// update camera goal based on mouse movement
|
|
updateCameraGoal(-0.18f * evt.xrel, -0.12f * evt.yrel, 0);
|
|
return true;
|
|
}
|
|
bool CharacterController::mouseWheelRolled(const OgreBites::MouseWheelEvent &evt)
|
|
{
|
|
// update camera goal based on mouse movement
|
|
updateCameraGoal(0, 0, -0.15f * evt.y);
|
|
return true;
|
|
}
|
|
bool CharacterController::mousePressed(const OgreBites::MouseButtonEvent &evt)
|
|
{
|
|
std::cout << "Mouse press\n";
|
|
return false;
|
|
}
|
|
void CharacterController::frameRendered(const Ogre::FrameEvent &evt)
|
|
{
|
|
if (mUpdate) {
|
|
updateBody(evt.timeSinceLastFrame);
|
|
updateAnimations(evt.timeSinceLastFrame);
|
|
updateCamera(evt.timeSinceLastFrame);
|
|
if (evt.timeSinceLastFrame > 0)
|
|
updateRootMotion(evt.timeSinceLastFrame);
|
|
}
|
|
}
|
|
bool CharacterController::frameStarted(const Ogre::FrameEvent &evt)
|
|
{
|
|
return true;
|
|
}
|
|
void CharacterController::updateCameraGoal(Ogre::Real deltaYaw,
|
|
Ogre::Real deltaPitch,
|
|
Ogre::Real deltaZoom)
|
|
{
|
|
mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
|
|
if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
|
|
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
|
|
mCameraPivot->pitch(Ogre::Degree(deltaPitch),
|
|
Ogre::Node::TS_LOCAL);
|
|
mPivotPitch += deltaPitch;
|
|
}
|
|
Ogre::Real dist = mCameraGoal->_getDerivedPosition().distance(
|
|
mCameraPivot->_getDerivedPosition());
|
|
Ogre::Real distChange = deltaZoom * dist;
|
|
|
|
// bound the zoom
|
|
if (!(dist + distChange < 8 && distChange < 0) &&
|
|
!(dist + distChange > 25 && distChange > 0))
|
|
mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL);
|
|
}
|
|
void CharacterController::updateBody(Ogre::Real delta)
|
|
{
|
|
mGoalDirection = Ogre::Vector3::ZERO;
|
|
if (mKeyDirection != Ogre::Vector3::ZERO) {
|
|
// calculate actually goal direction in world based on player's key directions
|
|
mGoalDirection +=
|
|
mKeyDirection.z * mCameraNode->getOrientation().zAxis();
|
|
mGoalDirection +=
|
|
mKeyDirection.x * mCameraNode->getOrientation().xAxis();
|
|
mGoalDirection.y = 0;
|
|
mGoalDirection.normalise();
|
|
|
|
Ogre::Quaternion toGoal =
|
|
mBodyNode->getOrientation().zAxis().getRotationTo(
|
|
mGoalDirection);
|
|
// calculate how much the character has to turn to face goal direction
|
|
Ogre::Real yawToGoal = toGoal.getYaw().valueDegrees();
|
|
// this is how much the character CAN turn this frame
|
|
Ogre::Real yawAtSpeed = yawToGoal / Ogre::Math::Abs(yawToGoal) *
|
|
delta * TURN_SPEED;
|
|
// reduce "turnability" if we're in midair
|
|
// if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;
|
|
if (yawToGoal < 0)
|
|
yawToGoal = std::min<Ogre::Real>(
|
|
0,
|
|
std::max<Ogre::Real>(
|
|
yawToGoal,
|
|
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
|
|
else if (yawToGoal > 0)
|
|
yawToGoal = std::max<Ogre::Real>(
|
|
0,
|
|
std::min<Ogre::Real>(
|
|
yawToGoal,
|
|
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);
|
|
mBodyNode->yaw(Ogre::Degree(yawToGoal));
|
|
// move in current body direction (not the goal direction)
|
|
// mBodyNode->translate(0, 0, delta * RUN_SPEED * mAnims[mAnimID]->getWeight(),
|
|
// Ogre::Node::TS_LOCAL);
|
|
#if 0
|
|
if (mBaseAnimID == ANIM_JUMP_LOOP)
|
|
{
|
|
// if we're jumping, add a vertical offset too, and apply gravity
|
|
mBodyNode->translate(0, mVerticalVelocity * deltaTime, 0, Node::TS_LOCAL);
|
|
mVerticalVelocity -= GRAVITY * deltaTime;
|
|
|
|
Vector3 pos = mBodyNode->getPosition();
|
|
if (pos.y <= CHAR_HEIGHT)
|
|
{
|
|
// if we've hit the ground, change to landing state
|
|
pos.y = CHAR_HEIGHT;
|
|
mBodyNode->setPosition(pos);
|
|
setBaseAnimation(ANIM_JUMP_END, true);
|
|
mTimer = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
void CharacterController::updateAnimations(Ogre::Real delta)
|
|
{
|
|
int i, j, k;
|
|
Ogre::Real animSpeed = 1;
|
|
mTimer += delta;
|
|
if (mAnimID != ANIM_NONE) {
|
|
if (mAnimID == ANIM_WALK)
|
|
mAnims[mAnimID]->addTime(delta * 1.0f);
|
|
else
|
|
mAnims[mAnimID]->addTime(delta * animSpeed);
|
|
}
|
|
fadeAnimations(delta);
|
|
}
|
|
struct EntityCollisionListener {
|
|
const Ogre::MovableObject *entity;
|
|
Ogre::Bullet::CollisionListener *listener;
|
|
};
|
|
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;
|
|
bool is_on_floor = false;
|
|
bool penetration = false;
|
|
Ogre::Vector3 gravity(0, -9.8, 0);
|
|
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);
|
|
#if 0
|
|
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)
|
|
{
|
|
int i;
|
|
for (i = 0; i < NUM_ANIMS; i++) {
|
|
if (mFadingIn[i]) {
|
|
// slowly fade this animation in until it has full weight
|
|
Ogre::Real newWeight = mAnims[i]->getWeight() +
|
|
delta * ANIM_FADE_SPEED;
|
|
mAnims[i]->setWeight(
|
|
Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
|
|
if (newWeight >= 1)
|
|
mFadingIn[i] = false;
|
|
} else if (mFadingOut[i]) {
|
|
// slowly fade this animation out until it has no weight, and then disable it
|
|
Ogre::Real newWeight = mAnims[i]->getWeight() -
|
|
delta * ANIM_FADE_SPEED;
|
|
mAnims[i]->setWeight(
|
|
Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
|
|
if (newWeight <= 0) {
|
|
mAnims[i]->setEnabled(false);
|
|
mFadingOut[i] = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void CharacterController::updateCamera(Ogre::Real delta)
|
|
{
|
|
// place the camera pivot roughly at the character's shoulder
|
|
mCameraPivot->setPosition(mBodyNode->getPosition() +
|
|
Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
|
|
// move the camera smoothly to the goal
|
|
Ogre::Vector3 goalOffset =
|
|
mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
|
|
mCameraNode->translate(goalOffset * delta * 9.0f);
|
|
// always look at the pivot
|
|
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(),
|
|
Ogre::Node::TS_PARENT);
|
|
}
|
|
void CharacterController::setAnimation(AnimID id, bool reset)
|
|
{
|
|
assert(id >= 0 && id < NUM_ANIMS);
|
|
if (mAnimID != ANIM_NONE) {
|
|
mFadingIn[mAnimID] = false;
|
|
mFadingOut[mAnimID] = true;
|
|
}
|
|
mAnimID = id;
|
|
if (id != ANIM_NONE) {
|
|
mAnims[id]->setEnabled(true);
|
|
mAnims[id]->setWeight(0);
|
|
mFadingOut[id] = false;
|
|
mFadingIn[id] = true;
|
|
if (reset)
|
|
mAnims[id]->setTimePosition(0);
|
|
}
|
|
}
|