mirror of
https://github.com/TES3MP/TES3MP.git
synced 2025-09-27 06:55:54 -04:00
Improvements to smooth NPC steering
This commit is contained in:
parent
2b15b8b484
commit
39d86a9468
@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics
|
|||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||||
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat
|
disease pickpocket levelledlist combat steering
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
@ -574,8 +574,6 @@ namespace MWInput
|
|||||||
|
|
||||||
double x = arg.xrel * mCameraSensitivity * (1.0f/256.f);
|
double x = arg.xrel * mCameraSensitivity * (1.0f/256.f);
|
||||||
double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier;
|
double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier;
|
||||||
float scale = MWBase::Environment::get().getFrameDuration();
|
|
||||||
if(scale <= 0.0f) scale = 1.0f;
|
|
||||||
|
|
||||||
float rot[3];
|
float rot[3];
|
||||||
rot[0] = -y;
|
rot[0] = -y;
|
||||||
@ -585,8 +583,8 @@ namespace MWInput
|
|||||||
// Only actually turn player when we're not in vanity mode
|
// Only actually turn player when we're not in vanity mode
|
||||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||||
{
|
{
|
||||||
mPlayer->yaw(x/scale);
|
mPlayer->yaw(x);
|
||||||
mPlayer->pitch(-y/scale);
|
mPlayer->pitch(-y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
#include "aicombat.hpp"
|
#include "aicombat.hpp"
|
||||||
#include "aifollow.hpp"
|
|
||||||
|
|
||||||
#include "movement.hpp"
|
#include <OgreMath.h>
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/timestamp.hpp"
|
#include "../mwworld/timestamp.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
|
|
||||||
#include "character.hpp"
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
#include "steering.hpp"
|
||||||
#include <OgreMath.h>
|
#include "movement.hpp"
|
||||||
#include <OgreVector3.h>
|
#include "character.hpp" // fixme: for getActiveWeapon
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -43,7 +42,9 @@ namespace MWMechanics
|
|||||||
mReadyToAttack(false),
|
mReadyToAttack(false),
|
||||||
mStrike(false),
|
mStrike(false),
|
||||||
mCombatMove(false),
|
mCombatMove(false),
|
||||||
mMovement()
|
mRotate(false),
|
||||||
|
mMovement(),
|
||||||
|
mTargetAngle(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +69,16 @@ namespace MWMechanics
|
|||||||
mCombatMove = false;
|
mCombatMove = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor.getClass().getMovementSettings(actor) = mMovement;
|
actor.getClass().getMovementSettings(actor) = mMovement;
|
||||||
|
|
||||||
|
if (mRotate)
|
||||||
|
{
|
||||||
|
if (zTurn(actor, Ogre::Degree(mTargetAngle)))
|
||||||
|
mRotate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mReadyToAttack);
|
|
||||||
mTimerAttack -= duration;
|
mTimerAttack -= duration;
|
||||||
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike);
|
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike);
|
||||||
|
|
||||||
@ -156,12 +163,7 @@ namespace MWMechanics
|
|||||||
weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit)
|
weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit)
|
||||||
}
|
}
|
||||||
|
|
||||||
//MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false);
|
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
|
||||||
float zAngle;
|
|
||||||
|
|
||||||
|
|
||||||
float rangeMelee;
|
float rangeMelee;
|
||||||
float rangeCloseUp;
|
float rangeCloseUp;
|
||||||
@ -189,12 +191,8 @@ namespace MWMechanics
|
|||||||
//Melee and Close-up combat
|
//Melee and Close-up combat
|
||||||
vDir.z = 0;
|
vDir.z = 0;
|
||||||
float dirLen = vDir.length();
|
float dirLen = vDir.length();
|
||||||
zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees();
|
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees();
|
||||||
|
mRotate = true;
|
||||||
// TODO: use movement settings instead of rotating directly
|
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
|
||||||
|
|
||||||
//MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
|
|
||||||
//bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
|
//bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
|
||||||
if (mFollowTarget && distBetween > rangeMelee)
|
if (mFollowTarget && distBetween > rangeMelee)
|
||||||
@ -237,12 +235,6 @@ namespace MWMechanics
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
||||||
|
|
||||||
/*
|
|
||||||
//apply when AIFOLLOW package implementation will be existent
|
|
||||||
if(mFollowTarget)
|
|
||||||
actor.getClass().getCreatureStats(actor).getAiSequence().stack(AiFollow(mTarget));*/
|
|
||||||
|
|
||||||
mFollowTarget = false;
|
mFollowTarget = false;
|
||||||
|
|
||||||
buildNewPath(actor);
|
buildNewPath(actor);
|
||||||
@ -252,13 +244,10 @@ namespace MWMechanics
|
|||||||
|
|
||||||
//try shortcut
|
//try shortcut
|
||||||
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
||||||
zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||||
else
|
else
|
||||||
zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||||
|
mRotate = true;
|
||||||
// TODO: use movement settings instead of rotating directly
|
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
|
||||||
//mMovement.mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
|
||||||
|
|
||||||
mMovement.mPosition[1] = 1;
|
mMovement.mPosition[1] = 1;
|
||||||
mReadyToAttack = false;
|
mReadyToAttack = false;
|
||||||
@ -294,6 +283,8 @@ namespace MWMechanics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actor.getClass().getMovementSettings(actor) = mMovement;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,16 +29,21 @@ namespace MWMechanics
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
//controls duration of the actual strike
|
// controls duration of the actual strike
|
||||||
float mTimerAttack;
|
float mTimerAttack;
|
||||||
float mTimerReact;
|
float mTimerReact;
|
||||||
//controls duration of the sideway & forward moves
|
// controls duration of the sideway & forward moves
|
||||||
//when mCombatMove is true
|
// when mCombatMove is true
|
||||||
float mTimerCombatMove;
|
float mTimerCombatMove;
|
||||||
|
|
||||||
|
// the z rotation angle (degrees) we want to reach
|
||||||
|
// used every frame when mRotate is true
|
||||||
|
float mTargetAngle;
|
||||||
|
|
||||||
bool mReadyToAttack, mStrike;
|
bool mReadyToAttack, mStrike;
|
||||||
bool mFollowTarget;
|
bool mFollowTarget;
|
||||||
bool mCombatMove;
|
bool mCombatMove;
|
||||||
|
bool mRotate;
|
||||||
|
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
MWWorld::Ptr mTarget;
|
MWWorld::Ptr mTarget;
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
float sgn(float a)
|
float sgn(float a)
|
||||||
@ -33,7 +35,7 @@ namespace MWMechanics
|
|||||||
{
|
{
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
|
|
||||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
// The CS Help File states that if a duration is given, the AI package will run for that long
|
||||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||||
if(mX != 0 || mY != 0 || mZ != 0)
|
if(mX != 0 || mY != 0 || mZ != 0)
|
||||||
mDuration = 0;
|
mDuration = 0;
|
||||||
@ -52,7 +54,7 @@ namespace MWMechanics
|
|||||||
{
|
{
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
|
|
||||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
// The CS Help File states that if a duration is given, the AI package will run for that long
|
||||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||||
if(mX != 0 || mY != 0 || mZ != 0)
|
if(mX != 0 || mY != 0 || mZ != 0)
|
||||||
mDuration = 0;
|
mDuration = 0;
|
||||||
@ -89,25 +91,23 @@ namespace MWMechanics
|
|||||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||||
{
|
{
|
||||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
|
||||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||||
2.0 - 200))
|
2.0 - 200))
|
||||||
{
|
{
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||||
{
|
{
|
||||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
|
||||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||||
2.0 - 200))
|
2.0 - 200))
|
||||||
{
|
{
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +151,7 @@ namespace MWMechanics
|
|||||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||||
{
|
{
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||||
// TODO: use movement settings instead of rotating directly
|
zTurn(actor, Ogre::Degree(zAngle));
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,17 @@
|
|||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
#include <OgreMath.h>
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
@ -45,14 +47,14 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
ESM::Pathgrid::Point dest;
|
||||||
dest.mX = target.getRefData().getPosition().pos[0];
|
dest.mX = target.getRefData().getPosition().pos[0];
|
||||||
dest.mY = target.getRefData().getPosition().pos[1];
|
dest.mY = target.getRefData().getPosition().pos[1];
|
||||||
dest.mZ = target.getRefData().getPosition().pos[2];
|
dest.mZ = target.getRefData().getPosition().pos[2];
|
||||||
|
|
||||||
ESM::Pathgrid::Point start;
|
ESM::Pathgrid::Point start;
|
||||||
start.mX = pos.pos[0];
|
start.mX = pos.pos[0];
|
||||||
start.mY = pos.pos[1];
|
start.mY = pos.pos[1];
|
||||||
start.mZ = pos.pos[2];
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
if(mPathFinder.getPath().empty())
|
if(mPathFinder.getPath().empty())
|
||||||
@ -88,18 +90,14 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||||||
|
|
||||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||||
{
|
{
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
//MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
}
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
|
||||||
//std::cout << Ogre::Degree(zAngle).valueDegrees()-Ogre::Radian(actor.getRefData().getPosition().rot[2]).valueDegrees() << " "<< pos.rot[2] << " " << zAngle << "\n";
|
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
||||||
//MWWorld::Class::get(actor).get
|
< 100*100)
|
||||||
}
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
|
||||||
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
|
||||||
< 100*100)
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
else
|
else
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -109,12 +107,12 @@ std::string MWMechanics::AiFollow::getFollowedActor()
|
|||||||
return mActorId;
|
return mActorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||||
{
|
{
|
||||||
return new AiFollow(*this);
|
return new AiFollow(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiFollow::getTypeId() const
|
int MWMechanics::AiFollow::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdFollow;
|
return TypeIdFollow;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#include "aitravel.hpp"
|
#include "aitravel.hpp"
|
||||||
|
|
||||||
#include "movement.hpp"
|
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
#include "movement.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
float sgn(float a)
|
float sgn(float a)
|
||||||
@ -86,9 +87,7 @@ namespace MWMechanics
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
// TODO: use movement settings instead of rotating directly
|
|
||||||
world->rotateObject(actor, 0, 0, zAngle, false);
|
|
||||||
movement.mPosition[1] = 1;
|
movement.mPosition[1] = 1;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include <OgreVector3.h>
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
float sgn(float a)
|
float sgn(float a)
|
||||||
@ -282,11 +284,6 @@ namespace MWMechanics
|
|||||||
|
|
||||||
if(mWalking)
|
if(mWalking)
|
||||||
{
|
{
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
|
||||||
// TODO: use movement settings instead of rotating directly
|
|
||||||
world->rotateObject(actor, 0, 0, zAngle, false);
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||||
{
|
{
|
||||||
stopWalking(actor);
|
stopWalking(actor);
|
||||||
@ -294,6 +291,12 @@ namespace MWMechanics
|
|||||||
mWalking = false;
|
mWalking = false;
|
||||||
mChooseAction = true;
|
mChooseAction = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
|
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1111,9 +1111,9 @@ void CharacterController::update(float duration)
|
|||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
{
|
{
|
||||||
|
rot *= Ogre::Math::RadiansToDegrees(1.0f);
|
||||||
if(mHitState != CharState_KnockDown)
|
if(mHitState != CharState_KnockDown)
|
||||||
{
|
{
|
||||||
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
|
|
||||||
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
|
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
|
||||||
}
|
}
|
||||||
else //avoid z-rotating for knockdown
|
else //avoid z-rotating for knockdown
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <components/esm/loadpgrd.hpp>
|
#include <components/esm/loadpgrd.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
@ -26,8 +25,10 @@ namespace MWMechanics
|
|||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float z);
|
bool checkPathCompleted(float x, float y, float z);
|
||||||
///< \Returns true if the last point of the path has been reached.
|
///< \Returns true if the last point of the path has been reached.
|
||||||
|
|
||||||
bool checkWaypoint(float x, float y, float z);
|
bool checkWaypoint(float x, float y, float z);
|
||||||
///< \Returns true if a way point was reached
|
///< \Returns true if a way point was reached
|
||||||
|
|
||||||
float getZAngleToNext(float x, float y) const;
|
float getZAngleToNext(float x, float y) const;
|
||||||
|
|
||||||
float getDistToNext(float x, float y, float z);
|
float getDistToNext(float x, float y, float z);
|
||||||
|
43
apps/openmw/mwmechanics/steering.cpp
Normal file
43
apps/openmw/mwmechanics/steering.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle)
|
||||||
|
{
|
||||||
|
Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[2]);
|
||||||
|
Ogre::Radian diff (targetAngle - currentAngle);
|
||||||
|
if (diff >= Ogre::Degree(180))
|
||||||
|
{
|
||||||
|
// Turning the other way would be a better idea
|
||||||
|
diff = diff-Ogre::Degree(360);
|
||||||
|
}
|
||||||
|
else if (diff <= Ogre::Degree(-180))
|
||||||
|
{
|
||||||
|
diff = Ogre::Degree(360)-diff;
|
||||||
|
}
|
||||||
|
Ogre::Radian absDiff = Ogre::Math::Abs(diff);
|
||||||
|
|
||||||
|
// The turning animation actually moves you slightly, so the angle will be wrong again.
|
||||||
|
// Use epsilon to prevent jerkiness.
|
||||||
|
const Ogre::Degree epsilon (0.5);
|
||||||
|
if (absDiff < epsilon)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Max. speed of 10 radian per sec
|
||||||
|
Ogre::Radian limit = Ogre::Radian(10) * MWBase::Environment::get().getFrameDuration();
|
||||||
|
if (absDiff > limit)
|
||||||
|
diff = Ogre::Math::Sign(diff) * limit;
|
||||||
|
|
||||||
|
actor.getClass().getMovementSettings(actor).mRotation[2] = diff.valueRadians();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
apps/openmw/mwmechanics/steering.hpp
Normal file
19
apps/openmw/mwmechanics/steering.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef OPENMW_MECHANICS_STEERING_H
|
||||||
|
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
/// configure rotation settings for an actor to reach this target angle (eventually)
|
||||||
|
/// @return have we reached the target angle?
|
||||||
|
bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user