New movement system for leashed entities (#4147)
* New movement system for leashed entities Entities are accelerated towards the leashed to entity as if by a spring. * Mobs now pathfind close to but not directly to the leashing entity. * Also minor comment changes
This commit is contained in:
parent
ec9e0eecf6
commit
e88b3fa2fe
|
@ -22,10 +22,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Ticks to wait to do leash calculations
|
|
||||||
#define LEASH_ACTIONS_TICK_STEP 10
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Map for eType <-> string
|
/** Map for eType <-> string
|
||||||
Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType()
|
Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType()
|
||||||
|
@ -239,28 +235,12 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk)
|
||||||
AddSpeedX(Distance.x);
|
AddSpeedX(Distance.x);
|
||||||
AddSpeedZ(Distance.z);
|
AddSpeedZ(Distance.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speed up leashed mobs getting far from player
|
|
||||||
if (IsLeashed() && GetLeashedTo()->IsPlayer())
|
|
||||||
{
|
|
||||||
Distance = GetLeashedTo()->GetPosition() - GetPosition();
|
|
||||||
Distance.Normalize();
|
|
||||||
AddSpeedX(Distance.x);
|
|
||||||
AddSpeedZ(Distance.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMonster::MoveToPosition(const Vector3d & a_Position)
|
void cMonster::MoveToPosition(const Vector3d & a_Position)
|
||||||
{
|
{
|
||||||
m_FinalDestination = a_Position;
|
m_FinalDestination = a_Position;
|
||||||
|
@ -400,10 +380,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
} // switch (m_EMState)
|
} // switch (m_EMState)
|
||||||
|
|
||||||
// Leash calculations
|
// Leash calculations
|
||||||
if ((m_TicksAlive % LEASH_ACTIONS_TICK_STEP) == 0)
|
CalcLeashActions(a_Dt);
|
||||||
{
|
|
||||||
CalcLeashActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
|
|
||||||
|
@ -422,7 +399,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMonster::CalcLeashActions()
|
void cMonster::CalcLeashActions(std::chrono::milliseconds a_Dt)
|
||||||
{
|
{
|
||||||
// This mob just spotted in the world and [m_LeashToPos not null] shows that should be leashed to a leash knot at m_LeashToPos.
|
// This mob just spotted in the world and [m_LeashToPos not null] shows that should be leashed to a leash knot at m_LeashToPos.
|
||||||
// This keeps trying until knot is found. Leash knot may be in a different chunk that needn't or can't be loaded yet.
|
// This keeps trying until knot is found. Leash knot may be in a different chunk that needn't or can't be loaded yet.
|
||||||
|
@ -435,19 +412,54 @@ void cMonster::CalcLeashActions()
|
||||||
SetLeashToPos(nullptr);
|
SetLeashToPos(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsLeashed()) // Mob is already leashed to an entity: follow it.
|
|
||||||
{
|
|
||||||
// TODO: leashed mobs in vanilla can move around up to 5 blocks distance from leash origin
|
|
||||||
MoveToPosition(m_LeashedTo->GetPosition());
|
|
||||||
|
|
||||||
// If distance to target > 10 break leash
|
if (!IsLeashed())
|
||||||
Vector3f a_Distance(m_LeashedTo->GetPosition() - GetPosition());
|
{
|
||||||
double Distance(a_Distance.Length());
|
return;
|
||||||
if (Distance > 10.0)
|
}
|
||||||
|
|
||||||
|
static const double CloseFollowDistance = 1.8; // The closest the mob will path towards the leashed to entity
|
||||||
|
static const double LeashNaturalLength = 5.0; // The closest the mob is actively pulled towards the entity
|
||||||
|
static const double LeashMaximumLength = 10.0; // Length where the leash breaks
|
||||||
|
static const double LeashSpringConstant = 20.0; // How stiff the leash is
|
||||||
|
|
||||||
|
const auto LeashedToPos = m_LeashedTo->GetPosition();
|
||||||
|
const auto Displacement = LeashedToPos - GetPosition();
|
||||||
|
const auto Distance = Displacement.Length();
|
||||||
|
const auto Direction = Displacement.NormalizeCopy();
|
||||||
|
|
||||||
|
// If the leash is over-extended, break the leash:
|
||||||
|
if (Distance > LeashMaximumLength)
|
||||||
|
{
|
||||||
|
LOGD("Leash broken (distance)");
|
||||||
|
Unleash(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the mob isn't following close enough, pull the mob towards the leashed to entity:
|
||||||
|
if (Distance > LeashNaturalLength)
|
||||||
|
{
|
||||||
|
// Accelerate monster towards the leashed to entity:
|
||||||
|
const auto Extension = Distance - LeashNaturalLength;
|
||||||
|
auto Acceleration = Direction * (Extension * LeashSpringConstant);
|
||||||
|
|
||||||
|
// Stop mobs from floating up when on the ground
|
||||||
|
if (IsOnGround() && (Acceleration.y < std::abs(GetGravity())))
|
||||||
{
|
{
|
||||||
LOGD("Leash broken (distance)");
|
Acceleration.y = 0.0;
|
||||||
Unleash(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the acceleration
|
||||||
|
using namespace std::chrono;
|
||||||
|
AddSpeed(Acceleration * duration_cast<duration<double>>(a_Dt).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passively follow the leashed to entity:
|
||||||
|
if (Distance > CloseFollowDistance)
|
||||||
|
{
|
||||||
|
const Vector3d TargetBlock((LeashedToPos - Direction * CloseFollowDistance).Floor());
|
||||||
|
// Move to centre of target block face
|
||||||
|
MoveToPosition(TargetBlock + Vector3d{ 0.5, 0.0, 0.5 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -326,6 +326,6 @@ private:
|
||||||
cPawn * m_Target;
|
cPawn * m_Target;
|
||||||
|
|
||||||
/** Leash calculations inside Tick function */
|
/** Leash calculations inside Tick function */
|
||||||
void CalcLeashActions();
|
void CalcLeashActions(std::chrono::milliseconds a_Dt);
|
||||||
|
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
|
Loading…
Reference in New Issue
Block a user