Skip to content

Commit

Permalink
find_path: consider walkable instead of CONTENT_AIR
Browse files Browse the repository at this point in the history
The path finding code works fairly well except that it considers
anythin not CONTENT_AIR to be "above the surface". This results in
paths that are unwalkable for entities since e.g. plants are not
walkable. The path would force them to jump on top of grass plants,
etc..

The obvious solution is not to use CONTENT_AIR as a criteria, but
instead distinguish between walkable and non-walkable nodes. This
results in paths that properly walk through grass nodes.

This was extensively tested by a flock of electric sheep.

Note that for underwater purposes this changes the behaviour from
"the surface is walkable" to "ignore water entirely" making the
path go across the water bottom, and pathing fail likely from the
water surface. This is intentional.
  • Loading branch information
sofar authored and est31 committed May 1, 2016
1 parent 9aec701 commit aa8c88c
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/pathfinder.cpp
Expand Up @@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "pathfinder.h"
#include "environment.h"
#include "gamedef.h"
#include "nodedef.h"
#include "map.h"
#include "log.h"
#include "irr_aabb3d.h"
Expand Down Expand Up @@ -518,6 +520,7 @@ void PathGridnode::setCost(v3s16 dir, PathCost cost)

void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node)
{
INodeDefManager *ndef = m_pathf->m_env->getGameDef()->ndef();
PathGridnode &elem = *p_node;

v3s16 realpos = m_pathf->getRealPos(ipos);
Expand All @@ -538,11 +541,10 @@ void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node)
}

//don't add anything if it isn't an air node
if ((current.param0 != CONTENT_AIR) ||
(below.param0 == CONTENT_AIR )) {
if (ndef->get(current).walkable || !ndef->get(below).walkable) {
DEBUG_OUT("Pathfinder: " << PPOS(realpos)
<< " not on surface" << std::endl);
if (current.param0 != CONTENT_AIR) {
if (ndef->get(current).walkable) {
elem.type = 's';
DEBUG_OUT(PPOS(ipos) << ": " << 's' << std::endl);
} else {
Expand Down Expand Up @@ -798,6 +800,7 @@ v3s16 Pathfinder::getRealPos(v3s16 ipos)
/******************************************************************************/
PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
{
INodeDefManager *ndef = m_env->getGameDef()->ndef();
PathCost retval;

retval.updated = true;
Expand All @@ -820,7 +823,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
return retval;
}

if (node_at_pos2.param0 == CONTENT_AIR) {
if (!ndef->get(node_at_pos2).walkable) {
MapNode node_below_pos2 =
m_env->getMap().getNodeNoEx(pos2 + v3s16(0, -1, 0));

Expand All @@ -831,7 +834,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
return retval;
}

if (node_below_pos2.param0 != CONTENT_AIR) {
if (ndef->get(node_below_pos2).walkable) {
retval.valid = true;
retval.value = 1;
retval.direction = 0;
Expand All @@ -843,7 +846,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
MapNode node_at_pos = m_env->getMap().getNodeNoEx(testpos);

while ((node_at_pos.param0 != CONTENT_IGNORE) &&
(node_at_pos.param0 == CONTENT_AIR) &&
(!ndef->get(node_at_pos).walkable) &&
(testpos.Y > m_limits.MinEdge.Y)) {
testpos += v3s16(0, -1, 0);
node_at_pos = m_env->getMap().getNodeNoEx(testpos);
Expand All @@ -852,7 +855,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
//did we find surface?
if ((testpos.Y >= m_limits.MinEdge.Y) &&
(node_at_pos.param0 != CONTENT_IGNORE) &&
(node_at_pos.param0 != CONTENT_AIR)) {
(ndef->get(node_at_pos).walkable)) {
if ((pos2.Y - testpos.Y - 1) <= m_maxdrop) {
retval.valid = true;
retval.value = 2;
Expand All @@ -877,15 +880,15 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
MapNode node_at_pos = m_env->getMap().getNodeNoEx(testpos);

while ((node_at_pos.param0 != CONTENT_IGNORE) &&
(node_at_pos.param0 != CONTENT_AIR) &&
(ndef->get(node_at_pos).walkable) &&
(testpos.Y < m_limits.MaxEdge.Y)) {
testpos += v3s16(0, 1, 0);
node_at_pos = m_env->getMap().getNodeNoEx(testpos);
}

//did we find surface?
if ((testpos.Y <= m_limits.MaxEdge.Y) &&
(node_at_pos.param0 == CONTENT_AIR)) {
(!ndef->get(node_at_pos).walkable)) {

if (testpos.Y - pos2.Y <= m_maxjump) {
retval.valid = true;
Expand Down

0 comments on commit aa8c88c

Please sign in to comment.