mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-19 20:53:52 +00:00
Use worldspace coords in AiWanderStorage
This commit is contained in:
parent
a9dbb023d7
commit
d40a9ec5bc
3 changed files with 46 additions and 43 deletions
|
@ -503,11 +503,9 @@ namespace MWMechanics
|
||||||
bool AiWander::isNearAllowedNode(const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const
|
bool AiWander::isNearAllowedNode(const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const
|
||||||
{
|
{
|
||||||
const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
||||||
auto cell = actor.getCell()->getCell();
|
|
||||||
for (const ESM::Pathgrid::Point& node : storage.mAllowedNodes)
|
for (const ESM::Pathgrid::Point& node : storage.mAllowedNodes)
|
||||||
{
|
{
|
||||||
osg::Vec3f point(node.mX, node.mY, node.mZ);
|
osg::Vec3f point(node.mX, node.mY, node.mZ);
|
||||||
Misc::CoordinateConverter(cell).toWorld(point);
|
|
||||||
if ((actorPos - point).length2() < distance * distance)
|
if ((actorPos - point).length2() < distance * distance)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -601,11 +599,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||||
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
|
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
|
||||||
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
const ESM::Pathgrid::Point& dest = storage.mAllowedNodes[randNode];
|
||||||
|
|
||||||
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
|
||||||
|
|
||||||
// actor position is already in world coordinates
|
|
||||||
const osg::Vec3f start = actorPos.asVec3();
|
const osg::Vec3f start = actorPos.asVec3();
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
|
@ -635,11 +630,6 @@ namespace MWMechanics
|
||||||
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode);
|
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell* cell)
|
|
||||||
{
|
|
||||||
Misc::CoordinateConverter(cell).toWorld(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder)
|
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder)
|
||||||
{
|
{
|
||||||
// TODO: how to add these back in once the door opens?
|
// TODO: how to add these back in once the door opens?
|
||||||
|
@ -739,9 +729,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||||
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
|
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
|
||||||
ESM::Pathgrid::Point dest = storage.mAllowedNodes[index];
|
ESM::Pathgrid::Point worldDest = storage.mAllowedNodes[index];
|
||||||
ESM::Pathgrid::Point worldDest = dest;
|
auto converter = Misc::CoordinateConverter(actor.getCell()->getCell());
|
||||||
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
|
ESM::Pathgrid::Point dest = converter.toLocalPoint(worldDest);
|
||||||
|
|
||||||
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
|
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
|
||||||
PathFinder::makeOsgVec3(worldDest), 60);
|
PathFinder::makeOsgVec3(worldDest), 60);
|
||||||
|
@ -756,13 +746,12 @@ namespace MWMechanics
|
||||||
if (points.empty())
|
if (points.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int initialSize = points.size();
|
|
||||||
bool isOccupied = false;
|
bool isOccupied = false;
|
||||||
// AI will try to move the NPC towards every neighboring node until suitable place will be found
|
// AI will try to move the NPC towards every neighboring node until suitable place will be found
|
||||||
for (int i = 0; i < initialSize; i++)
|
while (!points.empty())
|
||||||
{
|
{
|
||||||
int randomIndex = Misc::Rng::rollDice(points.size(), prng);
|
int randomIndex = Misc::Rng::rollDice(points.size(), prng);
|
||||||
ESM::Pathgrid::Point connDest = points[randomIndex];
|
const ESM::Pathgrid::Point& connDest = points[randomIndex];
|
||||||
|
|
||||||
// add an offset towards random neighboring node
|
// add an offset towards random neighboring node
|
||||||
osg::Vec3f dir = PathFinder::makeOsgVec3(connDest) - PathFinder::makeOsgVec3(dest);
|
osg::Vec3f dir = PathFinder::makeOsgVec3(connDest) - PathFinder::makeOsgVec3(dest);
|
||||||
|
@ -774,8 +763,7 @@ namespace MWMechanics
|
||||||
// move for 5-15% towards random neighboring node
|
// move for 5-15% towards random neighboring node
|
||||||
dest
|
dest
|
||||||
= PathFinder::makePathgridPoint(PathFinder::makeOsgVec3(dest) + dir * (j * 5 * length / 100.f));
|
= PathFinder::makePathgridPoint(PathFinder::makeOsgVec3(dest) + dir * (j * 5 * length / 100.f));
|
||||||
worldDest = dest;
|
worldDest = converter.toWorldPoint(dest);
|
||||||
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
|
|
||||||
|
|
||||||
isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
|
isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
|
||||||
PathFinder::makeOsgVec3(worldDest), 60);
|
PathFinder::makeOsgVec3(worldDest), 60);
|
||||||
|
@ -800,7 +788,7 @@ namespace MWMechanics
|
||||||
// underground. Adding 20 in adjustPosition() is not enough.
|
// underground. Adding 20 in adjustPosition() is not enough.
|
||||||
dest.mZ += 60;
|
dest.mZ += 60;
|
||||||
|
|
||||||
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
converter.toWorld(dest);
|
||||||
|
|
||||||
state.moveIn(std::make_unique<AiWanderStorage>());
|
state.moveIn(std::make_unique<AiWanderStorage>());
|
||||||
|
|
||||||
|
@ -847,15 +835,15 @@ namespace MWMechanics
|
||||||
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
|
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
|
||||||
{
|
{
|
||||||
// get NPC's position in local (i.e. cell) coordinates
|
// get NPC's position in local (i.e. cell) coordinates
|
||||||
osg::Vec3f npcPos(mInitialActorPosition);
|
auto converter = Misc::CoordinateConverter(cell);
|
||||||
Misc::CoordinateConverter(cell).toLocal(npcPos);
|
const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition);
|
||||||
|
|
||||||
// Find closest pathgrid point
|
// Find closest pathgrid point
|
||||||
int closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos);
|
int closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos);
|
||||||
|
|
||||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||||
// and if the point is connected to the closest current point
|
// and if the point is connected to the closest current point
|
||||||
// NOTE: mPoints and mAllowedNodes are in local coordinates
|
// NOTE: mPoints is in local coordinates
|
||||||
int pointIndex = 0;
|
int pointIndex = 0;
|
||||||
for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
|
@ -863,17 +851,18 @@ namespace MWMechanics
|
||||||
if ((npcPos - nodePos).length2() <= mDistance * mDistance
|
if ((npcPos - nodePos).length2() <= mDistance * mDistance
|
||||||
&& getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter))
|
&& getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter))
|
||||||
{
|
{
|
||||||
storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
storage.mAllowedNodes.push_back(converter.toWorldPoint(pathgrid->mPoints[counter]));
|
||||||
pointIndex = counter;
|
pointIndex = counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (storage.mAllowedNodes.size() == 1)
|
if (storage.mAllowedNodes.size() == 1)
|
||||||
{
|
{
|
||||||
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex, storage);
|
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(mInitialActorPosition));
|
||||||
|
addNonPathGridAllowedPoints(pathgrid, pointIndex, storage, converter);
|
||||||
}
|
}
|
||||||
if (!storage.mAllowedNodes.empty())
|
if (!storage.mAllowedNodes.empty())
|
||||||
{
|
{
|
||||||
SetCurrentNodeToClosestAllowedNode(npcPos, storage);
|
setCurrentNodeToClosestAllowedNode(storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,15 +873,15 @@ namespace MWMechanics
|
||||||
// additional points for NPC to wander to are:
|
// additional points for NPC to wander to are:
|
||||||
// 1. NPC's initial location
|
// 1. NPC's initial location
|
||||||
// 2. Partway along the path between the point and its connected points.
|
// 2. Partway along the path between the point and its connected points.
|
||||||
void AiWander::AddNonPathGridAllowedPoints(
|
void AiWander::addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage,
|
||||||
osg::Vec3f npcPos, const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage)
|
const Misc::CoordinateConverter& converter)
|
||||||
{
|
{
|
||||||
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(npcPos));
|
|
||||||
for (auto& edge : pathGrid->mEdges)
|
for (auto& edge : pathGrid->mEdges)
|
||||||
{
|
{
|
||||||
if (edge.mV0 == pointIndex)
|
if (edge.mV0 == pointIndex)
|
||||||
{
|
{
|
||||||
AddPointBetweenPathGridPoints(pathGrid->mPoints[edge.mV0], pathGrid->mPoints[edge.mV1], storage);
|
AddPointBetweenPathGridPoints(converter.toWorldPoint(pathGrid->mPoints[edge.mV0]),
|
||||||
|
converter.toWorldPoint(pathGrid->mPoints[edge.mV1]), storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -913,17 +902,17 @@ namespace MWMechanics
|
||||||
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(vectorStart + delta));
|
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(vectorStart + delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::SetCurrentNodeToClosestAllowedNode(const osg::Vec3f& npcPos, AiWanderStorage& storage)
|
void AiWander::setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
float distanceToClosestNode = std::numeric_limits<float>::max();
|
float distanceToClosestNode = std::numeric_limits<float>::max();
|
||||||
unsigned int index = 0;
|
size_t index = 0;
|
||||||
for (unsigned int counterThree = 0; counterThree < storage.mAllowedNodes.size(); counterThree++)
|
for (size_t i = 0; i < storage.mAllowedNodes.size(); ++i)
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::makeOsgVec3(storage.mAllowedNodes[counterThree]));
|
osg::Vec3f nodePos(PathFinder::makeOsgVec3(storage.mAllowedNodes[i]));
|
||||||
float tempDist = (npcPos - nodePos).length2();
|
float tempDist = (mInitialActorPosition - nodePos).length2();
|
||||||
if (tempDist < distanceToClosestNode)
|
if (tempDist < distanceToClosestNode)
|
||||||
{
|
{
|
||||||
index = counterThree;
|
index = i;
|
||||||
distanceToClosestNode = tempDist;
|
distanceToClosestNode = tempDist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ namespace ESM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Misc
|
||||||
|
{
|
||||||
|
class CoordinateConverter;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
||||||
|
@ -45,7 +50,6 @@ namespace MWMechanics
|
||||||
bool mPopulateAvailableNodes;
|
bool mPopulateAvailableNodes;
|
||||||
|
|
||||||
// allowed pathgrid nodes based on mDistance from the spawn point
|
// allowed pathgrid nodes based on mDistance from the spawn point
|
||||||
// in local coordinates of mCell
|
|
||||||
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
||||||
|
|
||||||
ESM::Pathgrid::Point mCurrentNode;
|
ESM::Pathgrid::Point mCurrentNode;
|
||||||
|
@ -154,13 +158,10 @@ namespace MWMechanics
|
||||||
GroupIndex_MaxIdle = 9
|
GroupIndex_MaxIdle = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
/// convert point from local (i.e. cell) to world coordinates
|
void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage);
|
||||||
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell* cell);
|
|
||||||
|
|
||||||
void SetCurrentNodeToClosestAllowedNode(const osg::Vec3f& npcPos, AiWanderStorage& storage);
|
void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage,
|
||||||
|
const Misc::CoordinateConverter& converter);
|
||||||
void AddNonPathGridAllowedPoints(
|
|
||||||
osg::Vec3f npcPos, const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage);
|
|
||||||
|
|
||||||
void AddPointBetweenPathGridPoints(
|
void AddPointBetweenPathGridPoints(
|
||||||
const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage);
|
const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage);
|
||||||
|
|
|
@ -29,12 +29,25 @@ namespace Misc
|
||||||
point.mY += mCellY;
|
point.mY += mCellY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// in-place conversion from world to local
|
||||||
|
void toLocal(ESM::Pathgrid::Point& point) const
|
||||||
|
{
|
||||||
|
point.mX -= mCellX;
|
||||||
|
point.mY -= mCellY;
|
||||||
|
}
|
||||||
|
|
||||||
ESM::Pathgrid::Point toWorldPoint(ESM::Pathgrid::Point point) const
|
ESM::Pathgrid::Point toWorldPoint(ESM::Pathgrid::Point point) const
|
||||||
{
|
{
|
||||||
toWorld(point);
|
toWorld(point);
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point toLocalPoint(ESM::Pathgrid::Point point) const
|
||||||
|
{
|
||||||
|
toLocal(point);
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
/// in-place conversion from local to world
|
/// in-place conversion from local to world
|
||||||
void toWorld(osg::Vec3f& point) const
|
void toWorld(osg::Vec3f& point) const
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue