Almost moved character to flecs
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -8,6 +8,7 @@
|
||||
"files.associations": {
|
||||
"istream": "cpp",
|
||||
"variant": "cpp",
|
||||
"tuple": "cpp"
|
||||
"tuple": "cpp",
|
||||
"iostream": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -78,19 +78,21 @@ add_executable(0_Bootstrap Bootstrap.cpp)
|
||||
|
||||
# this also sets the includes and pulls third party dependencies
|
||||
target_link_libraries(0_Bootstrap OgreBites OgreBullet OgrePaging ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} ${ASSIMP_LIBRARIES}
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,--as-needed
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
target_link_options(0_Bootstrap PRIVATE -static-libstdc++ -static-libgcc)
|
||||
endif()
|
||||
add_dependencies(0_Bootstrap stage_files import_vrm)
|
||||
|
||||
add_executable(Editor Editor.cpp ${TERRAIN_SRC} ${WATER_SRC})
|
||||
target_link_libraries(Editor OgreBites OgreBullet OgrePaging OgreTerrain OgreMeshLodGenerator OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}
|
||||
controller
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,--as-needed
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
target_link_options(Editor PRIVATE -static-libstdc++ -static-libgcc)
|
||||
endif()
|
||||
add_dependencies(Editor stage_files import_buildings import_water_stuff import_vehicles import_vrm)
|
||||
add_executable(Game Game.cpp ${TERRAIN_SRC} ${WATER_SRC})
|
||||
target_include_directories(Game PRIVATE src/gamedata)
|
||||
@@ -112,10 +114,11 @@ add_executable(Procedural Procedural.cpp ${TERRAIN_SRC})
|
||||
target_link_libraries(Procedural OgreBites OgreBullet OgrePaging OgreTerrain
|
||||
OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY}
|
||||
${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,--as-needed
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
target_link_options(Procedural PRIVATE -static-libstdc++ -static-libgcc)
|
||||
endif()
|
||||
add_dependencies(Procedural stage_files import_buildings)
|
||||
file(GLOB BUILDINGS_SRC ${CMAKE_SOURCE_DIR}/assets/blender/buildings/*.blend)
|
||||
set(BUILDING_OUTPUT_FILES)
|
||||
@@ -167,13 +170,12 @@ add_custom_target(import_water_stuff ALL DEPENDS ${WATER_STUFF})
|
||||
|
||||
add_executable(TerrainTest terrain.cpp ${TERRAIN_SRC})
|
||||
target_link_libraries(TerrainTest OgreBites OgreBullet OgrePaging OgreTerrain lua ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,--as-needed
|
||||
)
|
||||
target_include_directories(TerrainTest PRIVATE . src/terrain src/lua src/lua/lua-5.4.8/src)
|
||||
if(OGRE_STATIC)
|
||||
target_link_libraries(TerrainTest fix::assimp pugixml)
|
||||
target_link_options(TerrainTest PRIVATE -static-libstdc++ -static-libgcc)
|
||||
target_link_libraries(Procedural fix::assimp pugixml)
|
||||
target_link_libraries(0_Bootstrap fix::assimp pugixml)
|
||||
target_link_libraries(Editor fix::assimp pugixml)
|
||||
|
||||
9
Game.cpp
9
Game.cpp
@@ -386,9 +386,6 @@ public:
|
||||
// getRenderWindow());
|
||||
mDbgDraw.reset(new Ogre::Bullet::DebugDrawer(
|
||||
mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld()));
|
||||
ECS::setup();
|
||||
Sound::setup();
|
||||
Sound::ding();
|
||||
}
|
||||
void locateResources() override
|
||||
{
|
||||
@@ -535,7 +532,8 @@ public:
|
||||
Ogre::Timer mTerrainUpd;
|
||||
void updateTerrain(float delta)
|
||||
{
|
||||
Ogre::Vector3 pos = mCharacterController->getPosition();
|
||||
// Ogre::Vector3 pos = mCharacterController->getPosition();
|
||||
Ogre::Vector3 pos(0, 0, 0);
|
||||
if (!mTerrainReady && m_terrain.isLoadedAt(pos) &&
|
||||
mCharacterController->checkGround()) {
|
||||
std::cout << "terrain ready\n";
|
||||
@@ -595,6 +593,9 @@ public:
|
||||
"Skybox/Dynamic", "General");
|
||||
OgreAssert(m, "Sky box material not found.");
|
||||
m->load();
|
||||
ECS::setup(mScnMgr, mDynWorld.get(), mCameraNode, mCamera);
|
||||
Sound::setup();
|
||||
Sound::ding();
|
||||
}
|
||||
void create_entity_node(const Ogre::String &name, int key)
|
||||
{
|
||||
|
||||
@@ -3,169 +3,6 @@
|
||||
#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
|
||||
@@ -179,265 +16,63 @@ CharacterController::CharacterController(Ogre::SceneNode *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);
|
||||
}
|
||||
static uint32_t control;
|
||||
static ECS::Vector2 mouse{ 0, 0 };
|
||||
static float wheel_y;
|
||||
static bool mouse_moved = false, wheel_moved = false;
|
||||
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;
|
||||
if (key == 'w')
|
||||
control |= 1;
|
||||
else if (key == 'a')
|
||||
mKeyDirection.x = -1;
|
||||
control |= 2;
|
||||
else if (key == 's')
|
||||
mKeyDirection.z = 1;
|
||||
control |= 4;
|
||||
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);
|
||||
control |= 8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control |= 16;
|
||||
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);
|
||||
|
||||
if (key == 'w')
|
||||
control &= ~1;
|
||||
else if (key == 'a')
|
||||
control &= ~2;
|
||||
else if (key == 's')
|
||||
control &= ~4;
|
||||
else if (key == 'd')
|
||||
control &= ~8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control &= ~16;
|
||||
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);
|
||||
mouse.x = evt.xrel;
|
||||
mouse.y = evt.yrel;
|
||||
mouse_moved = true;
|
||||
return true;
|
||||
}
|
||||
bool CharacterController::mouseWheelRolled(const OgreBites::MouseWheelEvent &evt)
|
||||
{
|
||||
// update camera goal based on mouse movement
|
||||
updateCameraGoal(0, 0, -0.15f * evt.y);
|
||||
wheel_y = evt.y;
|
||||
wheel_moved = true;
|
||||
return true;
|
||||
}
|
||||
bool CharacterController::mousePressed(const OgreBites::MouseButtonEvent &evt)
|
||||
@@ -449,208 +84,29 @@ 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);
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
#include <OgreInput.h>
|
||||
#include <OgreFrameListener.h>
|
||||
#if 0
|
||||
class Character;
|
||||
#include "GameData.h"
|
||||
class CharacterController : public OgreBites::InputListener,
|
||||
Ogre::FrameListener {
|
||||
Ogre::SceneNode *mCameraNode;
|
||||
@@ -12,78 +12,17 @@ class CharacterController : public OgreBites::InputListener,
|
||||
Ogre::SceneNode *mCameraPivot;
|
||||
Ogre::SceneNode *mCameraGoal;
|
||||
Ogre::Real mPivotPitch;
|
||||
Ogre::Real mVerticalVelocity;
|
||||
Ogre::Vector3
|
||||
mKeyDirection; // player's local intended direction based on WASD keys
|
||||
bool mRunning;
|
||||
Character *mCharacter;
|
||||
|
||||
public:
|
||||
CharacterController(Ogre::SceneNode *camNode, Ogre::Camera *cam,
|
||||
Ogre::SceneManager *scnMgr, Character *character);
|
||||
~CharacterController();
|
||||
|
||||
private:
|
||||
void setupCamera();
|
||||
|
||||
public:
|
||||
bool keyPressed(const OgreBites::KeyboardEvent &evt) override;
|
||||
bool keyReleased(const OgreBites::KeyboardEvent &evt) override;
|
||||
bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override;
|
||||
bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override;
|
||||
bool mousePressed(const OgreBites::MouseButtonEvent &evt) override;
|
||||
bool frameStarted(const Ogre::FrameEvent &evt) override;
|
||||
void frameRendered(const Ogre::FrameEvent &evt) override;
|
||||
|
||||
private:
|
||||
void updateCamera(Ogre::Real deltaTime);
|
||||
void updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch,
|
||||
Ogre::Real deltaZoom);
|
||||
};
|
||||
#endif
|
||||
class CharacterController : public OgreBites::InputListener,
|
||||
Ogre::FrameListener {
|
||||
enum AnimID {
|
||||
ANIM_IDLE = 0,
|
||||
ANIM_WALK,
|
||||
ANIM_RUN,
|
||||
NUM_ANIMS,
|
||||
ANIM_NONE = NUM_ANIMS
|
||||
};
|
||||
Ogre::Node *mRootBone;
|
||||
Ogre::SceneNode *mCameraNode;
|
||||
Ogre::Camera *mCamera;
|
||||
Ogre::SceneManager *mScnMgr;
|
||||
|
||||
Ogre::SceneNode *mCameraPivot;
|
||||
Ogre::SceneNode *mCameraGoal, *mBodyNode;
|
||||
Ogre::Entity *mBodyEnt;
|
||||
Ogre::Real mPivotPitch;
|
||||
Ogre::Real mVerticalVelocity;
|
||||
Ogre::Vector3
|
||||
mKeyDirection; // player's local intended direction based on WASD keys
|
||||
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
|
||||
Ogre::AnimationState *mAnims[NUM_ANIMS]; // master animation list
|
||||
Ogre::Animation *mSkelAnimations[NUM_ANIMS];
|
||||
Ogre::NodeAnimationTrack *mHipsTracks[NUM_ANIMS];
|
||||
Ogre::NodeAnimationTrack *mRootTracks[NUM_ANIMS];
|
||||
AnimID mAnimID;
|
||||
bool mFadingIn[NUM_ANIMS]; // which animations are fading in
|
||||
bool mFadingOut[NUM_ANIMS]; // which animations are fading out
|
||||
Ogre::Real
|
||||
mTimer; // general timer to see how long animations have been playing
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
bool mRunning;
|
||||
Ogre::Bullet::DynamicsWorld *mWorld;
|
||||
Ogre::Vector3 rootMotion;
|
||||
Ogre::Quaternion rootRotation;
|
||||
// btRigidBody *mRigidBody;
|
||||
btCompoundShape *mCollisionShape;
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
#if 0
|
||||
Ogre::Vector3 gvelocity;
|
||||
#endif
|
||||
|
||||
bool mUpdate;
|
||||
Ogre::Bullet::KinematicMotionSimple *mController;
|
||||
|
||||
public:
|
||||
CharacterController(Ogre::SceneNode *camNode, Ogre::Camera *cam,
|
||||
@@ -92,9 +31,7 @@ public:
|
||||
~CharacterController();
|
||||
|
||||
private:
|
||||
void setupBody();
|
||||
void setupCamera();
|
||||
void setupAnimations();
|
||||
|
||||
public:
|
||||
bool keyPressed(const OgreBites::KeyboardEvent &evt) override;
|
||||
@@ -107,33 +44,7 @@ public:
|
||||
|
||||
private:
|
||||
void updateBody(Ogre::Real deltaTime);
|
||||
void updateAnimations(Ogre::Real deltaTime);
|
||||
void updateRootMotion(Ogre::Real deltaTime);
|
||||
void fadeAnimations(Ogre::Real deltaTime);
|
||||
void updateCamera(Ogre::Real deltaTime);
|
||||
void updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch,
|
||||
Ogre::Real deltaZoom);
|
||||
void setAnimation(AnimID id, bool reset = false);
|
||||
#if 0
|
||||
struct testMotionResult {
|
||||
};
|
||||
struct recoverResult {
|
||||
};
|
||||
|
||||
bool bodyTestMotion(btRigidBody *body,
|
||||
const btTransform &from,
|
||||
const btVector3 &motion, bool infinite_inertia,
|
||||
textMotionResult *result,
|
||||
bool excludeRaycastShapes,
|
||||
const std::set<btCollisionObject *> &exclude);
|
||||
bool recoverFromPenetration(btRigidBody *body,
|
||||
const btTransform &body_position,
|
||||
btScalar recover_movement_scale,
|
||||
bool infinite_inertia,
|
||||
btVector3 &delta_recover_movement,
|
||||
recoverResult *recover_result,
|
||||
const std::set<btCollisionObject *> &exclude);
|
||||
#endif
|
||||
inline btQuaternion convert(const Ogre::Quaternion &q)
|
||||
{
|
||||
return btQuaternion(q.x, q.y, q.z, q.w);
|
||||
@@ -163,6 +74,7 @@ private:
|
||||
q = convert(from.getRotation());
|
||||
v = convert(from.getOrigin());
|
||||
}
|
||||
|
||||
public:
|
||||
void enableUpdates()
|
||||
{
|
||||
@@ -178,36 +90,53 @@ public:
|
||||
}
|
||||
Ogre::Vector3 getPosition() const
|
||||
{
|
||||
return mBodyNode->getPosition();
|
||||
flecs::entity player =
|
||||
ECS::get().lookup("ECS::CharacterModule::player");
|
||||
return player.get<ECS::CharacterBase>().mBodyNode->getPosition();
|
||||
}
|
||||
Ogre::Quaternion getRotation() const
|
||||
{
|
||||
return mBodyNode->getOrientation();
|
||||
flecs::entity player =
|
||||
ECS::get().lookup("ECS::CharacterModule::player");
|
||||
return player.get<ECS::CharacterBase>()
|
||||
.mBodyNode->getOrientation();
|
||||
}
|
||||
class ClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback {
|
||||
class ClosestNotMeRayResultCallback
|
||||
: public btCollisionWorld::ClosestRayResultCallback {
|
||||
btCollisionObject *mMe;
|
||||
|
||||
public:
|
||||
ClosestNotMeRayResultCallback(
|
||||
btCollisionObject *me,
|
||||
const btVector3 &from,
|
||||
const btVector3 &to):
|
||||
btCollisionWorld::ClosestRayResultCallback(from, to) {
|
||||
ClosestNotMeRayResultCallback(btCollisionObject *me,
|
||||
const btVector3 &from,
|
||||
const btVector3 &to)
|
||||
: btCollisionWorld::ClosestRayResultCallback(from, to)
|
||||
{
|
||||
mMe = me;
|
||||
}
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace)
|
||||
virtual btScalar
|
||||
addSingleResult(btCollisionWorld::LocalRayResult &rayResult,
|
||||
bool normalInWorldSpace)
|
||||
{
|
||||
if (rayResult.m_collisionObject == mMe)
|
||||
return 1.0f;
|
||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||
return ClosestRayResultCallback::addSingleResult(
|
||||
rayResult, normalInWorldSpace);
|
||||
}
|
||||
};
|
||||
bool checkGround()
|
||||
{
|
||||
btVector3 from = mGhostObject->getWorldTransform().getOrigin() + btVector3(0, 0.2f, 0);
|
||||
flecs::entity player =
|
||||
ECS::get().lookup("ECS::CharacterModule::player");
|
||||
btVector3 from = player.get<ECS::CharacterBody>()
|
||||
.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);
|
||||
ClosestNotMeRayResultCallback resultCallback(
|
||||
player.get<ECS::CharacterBody>().mGhostObject, from,
|
||||
to);
|
||||
player.get<ECS::CharacterBody>().mGhostObject->rayTest(
|
||||
from, to, resultCallback);
|
||||
// std::cout << (resultCallback.hasHit() ? "hit" : "no hit");
|
||||
// if (resultCallback.hasHit())
|
||||
// std::cout << " " << Ogre::Bullet::convert(resultCallback.m_hitPointWorld);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include <Ogre.h>
|
||||
#include "GameData.h"
|
||||
|
||||
@@ -6,24 +7,513 @@ namespace ECS
|
||||
static flecs::world ecs;
|
||||
CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.component<Input>();
|
||||
ecs.add<Input>();
|
||||
ecs.system("HandleInput").kind(flecs::OnUpdate).run([](flecs::iter &it) {
|
||||
/* handle input */
|
||||
});
|
||||
ecs.module<CharacterModule>();
|
||||
player = ecs.entity("player");
|
||||
player.set<AnimationControl>({ AnimationControl::ANIM_NONE,
|
||||
AnimationControl::ANIM_NONE, false,
|
||||
false });
|
||||
player.set<CharacterBase>(
|
||||
{ "normal-male.glb", nullptr, nullptr, nullptr });
|
||||
player.set<CharacterBody>({});
|
||||
player.add<Character>();
|
||||
player.add<Player>();
|
||||
ecs.system<Input, Camera>("HandleInput")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](Input &input, Camera &camera) {
|
||||
/* handle input */
|
||||
// if (input.control == input.control_prev)
|
||||
// return;
|
||||
uint32_t pressed = input.control & ~input.control_prev;
|
||||
uint32_t released = input.control_prev & ~input.control;
|
||||
uint32_t active = input.control;
|
||||
float zaxis = input.motion.z;
|
||||
zaxis *= 0.9f;
|
||||
if (pressed & 1)
|
||||
std::cout << "W pressed\n";
|
||||
if (released & 1)
|
||||
std::cout << "W released\n";
|
||||
if (active & 1)
|
||||
zaxis -= 1.0f;
|
||||
if (active & 4)
|
||||
zaxis += 1.0f;
|
||||
if (zaxis > -1.0f && zaxis < 1.0f)
|
||||
zaxis = 0.0f;
|
||||
else
|
||||
zaxis = Ogre::Math::Sign(zaxis);
|
||||
input.motion.z = zaxis;
|
||||
float xaxis = input.motion.x;
|
||||
xaxis *= 0.9f;
|
||||
if (active & 2)
|
||||
xaxis = -1.0f;
|
||||
if (active & 8)
|
||||
xaxis += 1.0f;
|
||||
if (xaxis > -1.0f && xaxis < 1.0f)
|
||||
xaxis = 0.0f;
|
||||
else
|
||||
xaxis = Ogre::Math::Sign(xaxis);
|
||||
input.motion.x = xaxis;
|
||||
if (active & 16)
|
||||
input.fast = true;
|
||||
else
|
||||
input.fast = false;
|
||||
input.control_prev = input.control;
|
||||
if (input.mouse_moved) {
|
||||
updateCameraGoal(camera, -0.18f * input.mouse.x,
|
||||
-0.12f * input.mouse.y, 0);
|
||||
input.mouse_moved = false;
|
||||
input.mouse.x = 0;
|
||||
input.mouse.y = 0;
|
||||
}
|
||||
if (input.wheel_moved) {
|
||||
updateCameraGoal(camera, 0, 0,
|
||||
-0.15f * input.wheel_y);
|
||||
input.wheel_moved = false;
|
||||
input.wheel_y = 0;
|
||||
}
|
||||
ECS::get().modified<ECS::Input>();
|
||||
});
|
||||
ecs.system<const CharacterBase, AnimationControl>("HandleAnimations")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured && ch.mSkeleton) {
|
||||
int i, j;
|
||||
ch.mSkeleton->setBlendMode(
|
||||
Ogre::ANIMBLEND_CUMULATIVE);
|
||||
Ogre::String
|
||||
animNames[AnimationControl::NUM_ANIMS] = {
|
||||
"idle", "walking", "running"
|
||||
};
|
||||
for (i = 0; i < AnimationControl::NUM_ANIMS;
|
||||
i++) {
|
||||
anim.mAnims[i] =
|
||||
ch.mBodyEnt->getAnimationState(
|
||||
animNames[i]);
|
||||
anim.mAnims[i]->setLoop(true);
|
||||
anim.mAnims[i]->setEnabled(true);
|
||||
anim.mAnims[i]->setWeight(0);
|
||||
anim.mFadingIn[i] = false;
|
||||
anim.mFadingOut[i] = false;
|
||||
anim.mSkelAnimations[i] =
|
||||
ch.mSkeleton->getAnimation(
|
||||
animNames[i]);
|
||||
for (const auto &it :
|
||||
anim.mSkelAnimations[i]
|
||||
->_getNodeTrackList()) {
|
||||
Ogre::NodeAnimationTrack *track =
|
||||
it.second;
|
||||
Ogre::String trackName =
|
||||
track->getAssociatedNode()
|
||||
->getName();
|
||||
if (trackName ==
|
||||
"mixamorig:Hips") {
|
||||
anim.mHipsTracks[i] =
|
||||
track;
|
||||
} else if (trackName ==
|
||||
"Root") {
|
||||
anim.mRootTracks[i] =
|
||||
track;
|
||||
// mRootTracks[i]->removeAllKeyFrames();
|
||||
}
|
||||
}
|
||||
Ogre::Vector3 delta =
|
||||
Ogre::Vector3::ZERO;
|
||||
Ogre::Vector3 motion =
|
||||
Ogre::Vector3::ZERO;
|
||||
for (j = 0;
|
||||
j < anim.mRootTracks[i]
|
||||
->getNumKeyFrames();
|
||||
j++) {
|
||||
Ogre::Vector3 trans =
|
||||
anim.mRootTracks[i]
|
||||
->getNodeKeyFrame(
|
||||
j)
|
||||
->getTranslate();
|
||||
if (j == 0)
|
||||
delta = trans;
|
||||
else
|
||||
delta = trans - motion;
|
||||
anim.mRootTracks[i]
|
||||
->getNodeKeyFrame(j)
|
||||
->setTranslate(delta);
|
||||
motion = trans;
|
||||
}
|
||||
}
|
||||
anim.nextAnim = AnimationControl::ANIM_IDLE;
|
||||
setAnimation(anim);
|
||||
anim.configured = true;
|
||||
}
|
||||
});
|
||||
ecs.system<AnimationControl>("HandleAnimations0")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, AnimationControl &anim) {
|
||||
if (anim.currentAnim != anim.nextAnim)
|
||||
setAnimation(anim);
|
||||
});
|
||||
ecs.system<CharacterBase, AnimationControl>("HandleAnimations1")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
float delta = e.world().delta_time();
|
||||
Ogre::Real animSpeed = 1;
|
||||
if (anim.currentAnim != AnimationControl::ANIM_NONE) {
|
||||
if (anim.currentAnim ==
|
||||
AnimationControl::ANIM_WALK)
|
||||
anim.mAnims[anim.currentAnim]->addTime(
|
||||
delta * 1.0f);
|
||||
else
|
||||
anim.mAnims[anim.currentAnim]->addTime(
|
||||
delta * animSpeed);
|
||||
}
|
||||
if (!ch.mRootBone)
|
||||
return;
|
||||
ch.mBoneMotion = ch.mRootBone->getPosition();
|
||||
});
|
||||
ecs.system<AnimationControl>("HandleAnimations2")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, AnimationControl &anim) {
|
||||
float delta = e.world().delta_time();
|
||||
fadeAnimations(anim, delta);
|
||||
});
|
||||
ecs.system<CharacterBase, CharacterBody, AnimationControl>(
|
||||
"HandleRootMotion")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, CharacterBase &ch,
|
||||
CharacterBody &body, AnimationControl &anim) {
|
||||
float delta = e.world().delta_time();
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
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);
|
||||
body.gvelocity += gravity * delta;
|
||||
velocity += body.gvelocity;
|
||||
Ogre::Vector3 rotMotion = velocity * delta;
|
||||
btVector3 currentPosition =
|
||||
body.mGhostObject->getWorldTransform()
|
||||
.getOrigin();
|
||||
is_on_floor = body.mController->isOnFloor();
|
||||
penetration = body.mController->isPenetrating();
|
||||
if (is_on_floor)
|
||||
body.gvelocity =
|
||||
Ogre::Vector3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
btTransform from(
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getOrientation()),
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition()));
|
||||
ch.mBodyNode->setPosition(ch.mBodyNode->getPosition() +
|
||||
rotMotion);
|
||||
ch.mBoneMotion = Ogre::Vector3(0, 0, 0);
|
||||
});
|
||||
ecs.system<const Input, AnimationControl>("HandlePlayerAnimations")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.with<Player>()
|
||||
.each([](const Input &input, AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
return;
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
bool anim_is_idle = anim.currentAnim ==
|
||||
AnimationControl::ANIM_IDLE;
|
||||
bool anim_is_walking = anim.currentAnim ==
|
||||
AnimationControl::ANIM_WALK;
|
||||
bool anim_is_running = anim.currentAnim ==
|
||||
AnimationControl::ANIM_RUN;
|
||||
bool anim_is_motion = anim_is_walking ||
|
||||
anim_is_running;
|
||||
if (!controls_idle && anim_is_idle) {
|
||||
anim.reset = true;
|
||||
if (input.fast)
|
||||
anim.nextAnim =
|
||||
AnimationControl::ANIM_RUN;
|
||||
else
|
||||
anim.nextAnim =
|
||||
AnimationControl::ANIM_WALK;
|
||||
} else
|
||||
anim.reset = false;
|
||||
if (controls_idle && anim_is_motion)
|
||||
anim.nextAnim = AnimationControl::ANIM_IDLE;
|
||||
else if (!controls_idle && anim_is_motion) {
|
||||
if (input.fast && anim_is_walking)
|
||||
anim.nextAnim =
|
||||
AnimationControl::ANIM_RUN;
|
||||
else if (!input.fast && anim_is_running)
|
||||
anim.nextAnim =
|
||||
AnimationControl::ANIM_WALK;
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterBody>(
|
||||
"UpdateCharacterBase")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.each([](const EngineData &eng, CharacterBase &ch,
|
||||
CharacterBody &body) {
|
||||
if (!ch.mBodyNode) {
|
||||
ch.mBodyEnt = eng.mScnMgr->createEntity(
|
||||
"normal-male.glb");
|
||||
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
|
||||
->createChildSceneNode();
|
||||
ch.mBodyNode->attachObject(ch.mBodyEnt);
|
||||
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
|
||||
body.mGhostObject =
|
||||
new btPairCachingGhostObject();
|
||||
body.mCollisionShape = new btCompoundShape;
|
||||
body.mGhostObject->setCollisionShape(
|
||||
body.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 *>(
|
||||
body.mCollisionShape)
|
||||
->addChildShape(transform,
|
||||
shape);
|
||||
btScalar masses[1] = { 0 };
|
||||
btTransform principal;
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mCollisionShape)
|
||||
->calculatePrincipalAxisTransform(
|
||||
masses, principal,
|
||||
inertia);
|
||||
}
|
||||
body.mGhostObject->setCollisionFlags(
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::
|
||||
CF_NO_CONTACT_RESPONSE);
|
||||
body.mGhostObject->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
eng.mWorld->attachCollisionObject(
|
||||
body.mGhostObject, ch.mBodyEnt, 1,
|
||||
0x7FFFFFF);
|
||||
body.mController =
|
||||
new Ogre::Bullet::KinematicMotionSimple(
|
||||
body.mGhostObject,
|
||||
ch.mBodyNode);
|
||||
OgreAssert(body.mGhostObject,
|
||||
"Need GhostObject");
|
||||
OgreAssert(body.mController, "Need controller");
|
||||
eng.mWorld->getBtWorld()->addAction(
|
||||
body.mController);
|
||||
|
||||
OgreAssert(body.mCollisionShape,
|
||||
"No collision shape");
|
||||
OgreAssert(ch.mSkeleton->hasBone("Root"),
|
||||
"No root bone");
|
||||
ch.mRootBone = ch.mSkeleton->getBone("Root");
|
||||
OgreAssert(ch.mRootBone, "No root bone");
|
||||
}
|
||||
});
|
||||
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
||||
ecs.system<const EngineData, Camera, const CharacterBase>(
|
||||
"UpdateCamera")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, const EngineData &eng, Camera &camera,
|
||||
const CharacterBase &ch) {
|
||||
float delta = e.world().delta_time();
|
||||
if (!camera.configured) {
|
||||
// create a pivot at roughly the character's shoulder
|
||||
camera.mCameraPivot =
|
||||
eng.mScnMgr->getRootSceneNode()
|
||||
->createChildSceneNode();
|
||||
camera.mCameraGoal =
|
||||
camera.mCameraPivot
|
||||
->createChildSceneNode(
|
||||
Ogre::Vector3(0, 2, 3));
|
||||
camera.mCameraNode->setPosition(
|
||||
camera.mCameraPivot->getPosition() +
|
||||
camera.mCameraGoal->getPosition());
|
||||
camera.mCameraPivot->setFixedYawAxis(true);
|
||||
camera.mCameraGoal->setFixedYawAxis(true);
|
||||
camera.mCameraNode->setFixedYawAxis(true);
|
||||
// our model is quite small, so reduce the clipping planes
|
||||
camera.mCamera->setNearClipDistance(0.1f);
|
||||
camera.mCamera->setFarClipDistance(700);
|
||||
|
||||
camera.mPivotPitch = 0;
|
||||
camera.configured = true;
|
||||
} else {
|
||||
// place the camera pivot roughly at the character's shoulder
|
||||
camera.mCameraPivot->setPosition(
|
||||
ch.mBodyNode->getPosition() +
|
||||
Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
|
||||
// move the camera smoothly to the goal
|
||||
Ogre::Vector3 goalOffset =
|
||||
camera.mCameraGoal
|
||||
->_getDerivedPosition() -
|
||||
camera.mCameraNode->getPosition();
|
||||
camera.mCameraNode->translate(goalOffset *
|
||||
delta * 9.0f);
|
||||
// always look at the pivot
|
||||
camera.mCameraNode->lookAt(
|
||||
camera.mCameraPivot
|
||||
->_getDerivedPosition(),
|
||||
Ogre::Node::TS_PARENT);
|
||||
}
|
||||
});
|
||||
#define TURN_SPEED 500.0f // character turning in degrees per second
|
||||
ecs.system<const Input, const Camera, CharacterBase>("UpdateBody")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const Camera &camera, CharacterBase &ch) {
|
||||
ch.mGoalDirection = Ogre::Vector3::ZERO;
|
||||
float delta = e.world().delta_time();
|
||||
if (!input.motion.zeroLength()) {
|
||||
// calculate actually goal direction in world based on player's key directions
|
||||
ch.mGoalDirection +=
|
||||
input.motion.z *
|
||||
camera.mCameraNode->getOrientation()
|
||||
.zAxis();
|
||||
ch.mGoalDirection +=
|
||||
input.motion.x *
|
||||
camera.mCameraNode->getOrientation()
|
||||
.xAxis();
|
||||
ch.mGoalDirection.y = 0;
|
||||
ch.mGoalDirection.normalise();
|
||||
|
||||
Ogre::Quaternion toGoal =
|
||||
ch.mBodyNode->getOrientation()
|
||||
.zAxis()
|
||||
.getRotationTo(
|
||||
ch.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);
|
||||
ch.mBodyNode->yaw(Ogre::Degree(yawToGoal));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setup()
|
||||
void CharacterModule::setAnimation(AnimationControl &anim)
|
||||
{
|
||||
OgreAssert(anim.nextAnim >= 0 &&
|
||||
anim.nextAnim < AnimationControl::NUM_ANIMS,
|
||||
"Bad animation");
|
||||
if (anim.currentAnim != AnimationControl::ANIM_NONE) {
|
||||
anim.mFadingIn[anim.currentAnim] = false;
|
||||
anim.mFadingOut[anim.currentAnim] = true;
|
||||
}
|
||||
if (anim.nextAnim != AnimationControl::ANIM_NONE) {
|
||||
anim.mAnims[anim.nextAnim]->setEnabled(true);
|
||||
anim.mAnims[anim.nextAnim]->setWeight(0);
|
||||
anim.mFadingOut[anim.nextAnim] = false;
|
||||
anim.mFadingIn[anim.nextAnim] = true;
|
||||
if (anim.reset)
|
||||
anim.mAnims[anim.nextAnim]->setTimePosition(0);
|
||||
}
|
||||
anim.currentAnim = anim.nextAnim;
|
||||
anim.reset = false;
|
||||
}
|
||||
#define ANIM_FADE_SPEED \
|
||||
7.5f // animation crossfade speed in % of full weight per second
|
||||
|
||||
void CharacterModule::fadeAnimations(AnimationControl &anim, Ogre::Real delta)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < AnimationControl::NUM_ANIMS; i++) {
|
||||
if (anim.mFadingIn[i]) {
|
||||
// slowly fade this animation in until it has full weight
|
||||
Ogre::Real newWeight = anim.mAnims[i]->getWeight() +
|
||||
delta * ANIM_FADE_SPEED;
|
||||
anim.mAnims[i]->setWeight(
|
||||
Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
|
||||
if (newWeight >= 1)
|
||||
anim.mFadingIn[i] = false;
|
||||
} else if (anim.mFadingOut[i]) {
|
||||
// slowly fade this animation out until it has no weight, and then disable it
|
||||
Ogre::Real newWeight = anim.mAnims[i]->getWeight() -
|
||||
delta * ANIM_FADE_SPEED;
|
||||
anim.mAnims[i]->setWeight(
|
||||
Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
|
||||
if (newWeight <= 0) {
|
||||
anim.mAnims[i]->setEnabled(false);
|
||||
anim.mFadingOut[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void CharacterModule::updateCameraGoal(Camera &camera, Ogre::Real deltaYaw,
|
||||
Ogre::Real deltaPitch,
|
||||
Ogre::Real deltaZoom)
|
||||
{
|
||||
camera.mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
|
||||
if (!(camera.mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
|
||||
!(camera.mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
|
||||
camera.mCameraPivot->pitch(Ogre::Degree(deltaPitch),
|
||||
Ogre::Node::TS_LOCAL);
|
||||
camera.mPivotPitch += deltaPitch;
|
||||
}
|
||||
Ogre::Real dist = camera.mCameraGoal->_getDerivedPosition().distance(
|
||||
camera.mCameraPivot->_getDerivedPosition());
|
||||
Ogre::Real distChange = deltaZoom * dist;
|
||||
|
||||
// bound the zoom
|
||||
if (!(dist + distChange < 8 && distChange < 0) &&
|
||||
!(dist + distChange > 25 && distChange > 0))
|
||||
camera.mCameraGoal->translate(0, 0, distChange,
|
||||
Ogre::Node::TS_LOCAL);
|
||||
}
|
||||
|
||||
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera)
|
||||
{
|
||||
ecs.component<EngineData>().add(flecs::Singleton);
|
||||
ecs.component<GameData>().add(flecs::Singleton);
|
||||
ecs.component<Input>().add(flecs::Singleton);
|
||||
ecs.component<Camera>().add(flecs::Singleton);
|
||||
ecs.set<EngineData>({ scnMgr, world });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
ecs.add<GameData>();
|
||||
ecs.add<Input>();
|
||||
ecs.import <CharacterModule>();
|
||||
}
|
||||
void update(float delta)
|
||||
{
|
||||
ecs.progress(delta);
|
||||
}
|
||||
flecs::world &get()
|
||||
flecs::world get()
|
||||
{
|
||||
return ecs;
|
||||
}
|
||||
bool Vector3::zeroLength() const
|
||||
{
|
||||
float l = x * x + y * y + z * z;
|
||||
return (l < 1e-06 * 1e-06);
|
||||
}
|
||||
}
|
||||
@@ -5,32 +5,94 @@
|
||||
namespace ECS
|
||||
{
|
||||
struct GameData {
|
||||
flecs::entity player;
|
||||
int tmp;
|
||||
};
|
||||
struct EngineData {
|
||||
Ogre::SceneManager *mScnMgr;
|
||||
Ogre::Bullet::DynamicsWorld *mWorld;
|
||||
};
|
||||
struct Vector3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
bool zeroLength() const;
|
||||
};
|
||||
struct Vector2 {
|
||||
float x, y;
|
||||
};
|
||||
struct Input {
|
||||
uint32_t control;
|
||||
uint32_t control_prev;
|
||||
Vector3 motion;
|
||||
Vector2 mouse;
|
||||
float wheel_y;
|
||||
bool mouse_moved;
|
||||
bool wheel_moved;
|
||||
bool fast;
|
||||
Input()
|
||||
: motion({ 0, 0, 0 })
|
||||
: control(0)
|
||||
, control_prev(0)
|
||||
, motion({ 0, 0, 0 })
|
||||
, fast(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
/* character */
|
||||
struct Character {}; /* tag */
|
||||
struct Player {}; /* tag */
|
||||
struct CharacterBase {
|
||||
Ogre::String type;
|
||||
Ogre::SceneNode *mBodyNode;
|
||||
Ogre::Entity *mBodyEnt;
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Ogre::Node *mRootBone;
|
||||
Ogre::Vector3 mBoneMotion;
|
||||
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
|
||||
};
|
||||
struct CharacterBody {
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
btCompoundShape *mCollisionShape;
|
||||
Ogre::Bullet::DynamicsWorld *mWorld;
|
||||
Ogre::Bullet::KinematicMotionSimple *mController;
|
||||
Ogre::Vector3 gvelocity;
|
||||
};
|
||||
struct Camera {
|
||||
Ogre::SceneNode *mCameraNode;
|
||||
Ogre::Camera *mCamera;
|
||||
bool configured;
|
||||
Ogre::SceneNode *mCameraPivot;
|
||||
Ogre::SceneNode *mCameraGoal;
|
||||
Ogre::Real mPivotPitch;
|
||||
};
|
||||
struct AnimationControl {
|
||||
enum AnimID {
|
||||
ANIM_IDLE = 0,
|
||||
ANIM_WALK,
|
||||
ANIM_RUN,
|
||||
NUM_ANIMS,
|
||||
ANIM_NONE = NUM_ANIMS
|
||||
};
|
||||
AnimID currentAnim;
|
||||
AnimID nextAnim;
|
||||
bool reset;
|
||||
bool configured;
|
||||
Ogre::AnimationState *mAnims[NUM_ANIMS]; // master animation list
|
||||
Ogre::Animation *mSkelAnimations[NUM_ANIMS];
|
||||
bool mFadingIn[NUM_ANIMS]; // which animations are fading in
|
||||
bool mFadingOut[NUM_ANIMS]; // which animations are fading out
|
||||
Ogre::NodeAnimationTrack *mHipsTracks[NUM_ANIMS];
|
||||
Ogre::NodeAnimationTrack *mRootTracks[NUM_ANIMS];
|
||||
};
|
||||
struct CharacterModule {
|
||||
flecs::entity player;
|
||||
CharacterModule(flecs::world &ecs);
|
||||
void setAnimation(AnimationControl &anim);
|
||||
void fadeAnimations(AnimationControl &anim, Ogre::Real deltaTime);
|
||||
void updateCameraGoal(Camera &camera, Ogre::Real deltaYaw,
|
||||
Ogre::Real deltaPitch, Ogre::Real deltaZoom);
|
||||
};
|
||||
void setup();
|
||||
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera);
|
||||
void update(float delta);
|
||||
flecs::world &get();
|
||||
flecs::world get();
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user