From 304bc4eca4890633c47634faf7cd8aedcad4ecd7 Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Tue, 5 May 2015 10:04:41 +0300 Subject: AI - More conservative use of ResetPathFinding, fixed minor swimming / jumping bug --- src/Mobs/Monster.cpp | 57 ++++++++++++++++++++++++++++++++++------------------ src/Mobs/Monster.h | 16 +++++++++------ 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 01077bcdd..7ced89e45 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -77,6 +77,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A , m_Path(nullptr) , m_IsFollowingPath(false) , m_GiveUpCounter(0) + , m_TicksSinceLastPathReset(1000) , m_LastGroundHeight(POSY_TOINT) , m_JumpCoolDown(0) , m_IdleInterval(0) @@ -126,6 +127,11 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) { return false; } + if (m_TicksSinceLastPathReset < 1000) + { + // No need to count beyond 1000. 1000 is arbitary here. + ++m_TicksSinceLastPathReset; + } if (ReachedFinalDestination()) { @@ -133,16 +139,31 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) return false; } + if ((m_FinalDestination - m_PathFinderDestination).Length() > 0.25) // if the distance between where we're going and where we should go is too big. + { + /* If we reached the last path waypoint, + Or if we haven't re-calculated for too long. + Interval is proportional to distance squared. (Recalculate lots when close, calculate rarely when far) */ + if ( + ((GetPosition() - m_PathFinderDestination).Length() < 0.25) || + m_TicksSinceLastPathReset > (0.15 * (m_FinalDestination - GetPosition()).SqrLength()) + ) + { + ResetPathFinding(); + } + } + if (m_Path == nullptr) { - m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_FinalDestination.Floor(), 20); + m_PathFinderDestination = m_FinalDestination; + m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20); } switch (m_Path->Step(a_Chunk)) { case ePathFinderStatus::PATH_NOT_FOUND: { - StopMovingToPosition(); // Give up pathfinding to that destination + StopMovingToPosition(); // Give up pathfinding to that destination. break; } case ePathFinderStatus::CALCULATING: @@ -154,13 +175,13 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) { if (--m_GiveUpCounter == 0) { - ResetPathFinding(); // Try to calculate a path again + ResetPathFinding(); // Try to calculate a path again. return false; } - else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedDestination())) // Have we arrived at the next cell, as denoted by m_Destination? + else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedNextWaypoint())) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition? { - m_Destination = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint(); - m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_Destination. + m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint(); + m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. } return true; } @@ -177,8 +198,8 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) { if (m_JumpCoolDown == 0) { - // We're not moving and waypoint is above us, it means we are hitting something and we should jump. - if ((GetSpeedX() < 0.1) && (GetSpeedY() < 0.1) && DoesPosYRequireJump(FloorC(m_Destination.y))) + // We're not moving (or barely moving), and waypoint is above us, it means we are hitting something and we should jump. + if ((GetSpeedX() < 0.1) && (GetSpeedZ() < 0.1) && DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) { if (IsOnGround() || IsSwimming()) { @@ -186,8 +207,8 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) m_JumpCoolDown = 20; // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport AddPosY(1.6); // Jump!! - SetSpeedX(3.2 * (m_Destination.x - GetPosition().x)); // Move forward in a preset speed. - SetSpeedZ(3.2 * (m_Destination.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect. + SetSpeedX(3.2 * (m_NextWayPointPosition.x - GetPosition().x)); // Move forward in a preset speed. + SetSpeedZ(3.2 * (m_NextWayPointPosition.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect. } } } @@ -196,7 +217,7 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) --m_JumpCoolDown; } - Vector3d Distance = m_Destination - GetPosition(); + Vector3d Distance = m_NextWayPointPosition - GetPosition(); if ((Distance.x != 0) || (Distance.z != 0)) { Distance.y = 0; @@ -218,7 +239,7 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) // Apply walk speed: Distance *= m_RelativeWalkSpeed; /* Reduced default speed. - Close to Vanilla, easier for mobs to follow m_Destinations, hence + Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence better pathfinding. */ Distance *= 0.5; AddSpeedX(Distance.x); @@ -232,13 +253,8 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) void cMonster::MoveToPosition(const Vector3d & a_Position) { - if ((m_FinalDestination - a_Position).Length() > 0.25) - { - ResetPathFinding(); - m_FinalDestination = a_Position; m_IsFollowingPath = true; - } } @@ -248,7 +264,6 @@ void cMonster::MoveToPosition(const Vector3d & a_Position) void cMonster::StopMovingToPosition() { m_IsFollowingPath = false; - ResetPathFinding(); } @@ -257,6 +272,7 @@ void cMonster::StopMovingToPosition() void cMonster::ResetPathFinding(void) { + m_TicksSinceLastPathReset = 0; if (m_Path != nullptr) { delete m_Path; @@ -297,10 +313,11 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk)); if (TickPathFinding(*Chunk)) { - if (m_BurnsInDaylight && WouldBurnAt(m_Destination, *Chunk->GetNeighborChunk(FloorC(m_Destination.x), FloorC(m_Destination.z))) && !IsOnFire() && (m_TicksSinceLastDamaged == 100)) + if (m_BurnsInDaylight && WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && !IsOnFire() && (m_TicksSinceLastDamaged == 100)) { // If we burn in daylight, and we would burn at the next step, and we won't burn where we are right now, and we weren't provoked recently: StopMovingToPosition(); + m_GiveUpCounter = 40; // This doesn't count as giving up, keep the giveup timer as is. } else { @@ -365,7 +382,7 @@ void cMonster::SetPitchAndYawFromDestination() } { - Vector3d BodyDistance = m_Destination - GetPosition(); + Vector3d BodyDistance = m_NextWayPointPosition - GetPosition(); double Rotation, Pitch; BodyDistance.Normalize(); VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch); diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 329b9f399..c7f38c9f7 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -167,15 +167,19 @@ protected: /** Stores if mobile is currently moving towards the ultimate, final destination */ bool m_IsFollowingPath; - /* If 0, will give up reaching the next m_Destination and will re-compute path. */ + /* If 0, will give up reaching the next m_NextWayPointPosition and will re-compute path. */ int m_GiveUpCounter; + int m_TicksSinceLastPathReset; /** Coordinates of the next position that should be reached */ - Vector3d m_Destination; + Vector3d m_NextWayPointPosition; /** Coordinates for the ultimate, final destination. */ Vector3d m_FinalDestination; + /** Coordinates for the ultimate, final destination last given to the pathfinder. */ + Vector3d m_PathFinderDestination; + /** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does) If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1 If current Y is solid, goes up to find first nonsolid block, and returns that. @@ -185,8 +189,8 @@ protected: /** Returns if the ultimate, final destination has been reached */ bool ReachedFinalDestination(void) { return ((m_FinalDestination - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); } - /** Returns if the intermediate waypoint of m_Destination has been reached */ - bool ReachedDestination(void) { return ((m_Destination - GetPosition()).SqrLength() < 0.25); } + /** Returns if the intermediate waypoint of m_NextWayPointPosition has been reached */ + bool ReachedNextWaypoint(void) { return ((m_NextWayPointPosition - GetPosition()).SqrLength() < 0.25); } /** Returns if a monster can reach a given height by jumping */ inline bool DoesPosYRequireJump(int a_PosY) @@ -194,9 +198,9 @@ protected: return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1)); } - /** Finds the next place to go by calculating a path and setting the m_Destination variable for the next block to head to + /** Finds the next place to go by calculating a path and setting the m_NextWayPointPosition variable for the next block to head to This is based on the ultimate, final destination and the current position, as well as the A* algorithm, and any environmental hazards - Returns if a path is ready, and therefore if the mob should move to m_Destination + Returns if a path is ready, and therefore if the mob should move to m_NextWayPointPosition */ bool TickPathFinding(cChunk & a_Chunk); void MoveToWayPoint(cChunk & a_Chunk); -- cgit v1.2.3