CScriptSpiderBallWaypoint progress (#26)

This commit is contained in:
Phillip Stephens 2025-09-28 14:16:38 -07:00 committed by GitHub
parent 00c1024f98
commit ab1f33c245
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 254 additions and 8 deletions

View File

@ -5,18 +5,36 @@
class CScriptSpiderBallWaypoint : public CActor { class CScriptSpiderBallWaypoint : public CActor {
public: public:
CScriptSpiderBallWaypoint(TUniqueId, const rstl::string&, const CEntityInfo&,
const CTransform4f& xf, const bool active, uint w1);
void ClearWaypoints();
void BuildWaypointListAndBounds(CStateManager& mgr);
private:
enum ECheckActiveWaypoint { enum ECheckActiveWaypoint {
kCAW_Check, kCAW_Check,
kCAW_SkipCheck, kCAW_SkipCheck,
}; };
CScriptSpiderBallWaypoint(TUniqueId, const rstl::string&, const CEntityInfo&,
const CTransform4f& xf, const bool active, uint w1);
~CScriptSpiderBallWaypoint();
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override;
void ClearWaypoints();
void BuildWaypointListAndBounds(CStateManager& mgr);
void AddPreviousWaypoint(TUniqueId uid);
void AddPointToTouchBounds(const CVector3f& point);
TUniqueId NextWaypoint(const CStateManager& mgr, ECheckActiveWaypoint check) const;
TUniqueId PreviousWaypoint(const CStateManager& mgr, ECheckActiveWaypoint check) const;
void GetClosestPointAlongWaypoints(CStateManager& mgr, const CVector3f& ballPos,
float maxPointToBallDist,
const CScriptSpiderBallWaypoint** closestWaypoint,
CVector3f& closestPoint, CVector3f& deltaBetweenPoints,
float deltaBetweenInterpPoints,
CVector3f& interpDeltaBetweenPoints) const;
void AddToRenderer(const CFrustumPlanes& frustum, const CStateManager& mgr) const override;
void Accept(IVisitor& visitor) override;
void Render(const CStateManager& mgr) const override;
rstl::optional_object< CAABox > GetTouchBounds() const override;
private:
uint xe8_; uint xe8_;
rstl::vector< TUniqueId > xec_waypoints; rstl::vector< TUniqueId > xec_waypoints;
rstl::optional_object< CAABox > xfc_aabox; rstl::optional_object< CAABox > xfc_aabox;

View File

@ -1,9 +1,237 @@
#include "MetroidPrime/ScriptObjects/CScriptSpiderBallWaypoint.hpp" #include "MetroidPrime/ScriptObjects/CScriptSpiderBallWaypoint.hpp"
#include "MetroidPrime/CActorParameters.hpp" #include "MetroidPrime/CActorParameters.hpp"
#include "MetroidPrime/CEntityInfo.hpp"
#include "MetroidPrime/TCastTo.hpp"
#include "MetroidPrime/TGameTypes.hpp"
CScriptSpiderBallWaypoint::CScriptSpiderBallWaypoint(TUniqueId uid, const rstl::string& name, CScriptSpiderBallWaypoint::CScriptSpiderBallWaypoint(TUniqueId uid, const rstl::string& name,
const CEntityInfo& info, const CEntityInfo& info,
const CTransform4f& xf, const bool active, const CTransform4f& xf, const bool active,
uint w1) uint w1)
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(kMT_NoStepLogic), : CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(kMT_NoStepLogic),
CActorParameters::None(), kInvalidUniqueId) {} CActorParameters::None(), kInvalidUniqueId)
, xe8_(w1) {}
CScriptSpiderBallWaypoint::~CScriptSpiderBallWaypoint() {}
void CScriptSpiderBallWaypoint::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid,
CStateManager& mgr) {
CActor::AcceptScriptMsg(msg, uid, mgr);
switch (msg) {
case kSM_InitializedInArea:
BuildWaypointListAndBounds(mgr);
break;
case kSM_Arrived: {
if (GetActive()) {
SendScriptMsgs(kSS_Arrived, mgr, kSM_None);
}
break;
}
default:
break;
}
}
void CScriptSpiderBallWaypoint::ClearWaypoints() {
xfc_aabox.clear();
xec_waypoints.clear();
}
void CScriptSpiderBallWaypoint::BuildWaypointListAndBounds(CStateManager& mgr) {
rstl::vector< SConnection >::const_iterator it = GetConnectionList().begin();
int validConnections = 0;
for (; it != GetConnectionList().end(); ++it) {
if (it->x0_state == kSS_Arrived && it->x4_msg == kSM_Next) {
TUniqueId uid = mgr.GetIdForScript(it->x8_objId);
if (uid != kInvalidUniqueId) {
CScriptSpiderBallWaypoint* wp =
static_cast< CScriptSpiderBallWaypoint* >(mgr.ObjectById(uid));
wp->AddPreviousWaypoint(GetUniqueId());
++validConnections;
}
}
}
if (validConnections == 0) {
AddPointToTouchBounds(GetTranslation());
return;
}
CScriptSpiderBallWaypoint* curWaypoint = this;
while (curWaypoint->NextWaypoint(mgr, kCAW_SkipCheck) != kInvalidUniqueId) {
curWaypoint = static_cast< CScriptSpiderBallWaypoint* >(
mgr.ObjectById(curWaypoint->NextWaypoint(mgr, kCAW_SkipCheck)));
}
curWaypoint->AddPointToTouchBounds(GetTranslation());
}
void CScriptSpiderBallWaypoint::AddPointToTouchBounds(const CVector3f& point) {
if (!xfc_aabox) {
xfc_aabox = CAABox(point, point);
} else {
xfc_aabox->AccumulateBounds(point);
}
}
TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr,
ECheckActiveWaypoint check) const {
rstl::vector< SConnection >::const_iterator it = GetConnectionList().begin();
for (; it != GetConnectionList().end(); ++it) {
if (it->x0_state == kSS_Arrived && it->x4_msg == kSM_Next) {
TUniqueId uid = mgr.GetIdForScript(it->x8_objId);
if (const CScriptSpiderBallWaypoint* wp =
static_cast< const CScriptSpiderBallWaypoint* >(mgr.GetObjectById(uid))) {
if (check == kCAW_SkipCheck) {
return uid;
} else if (wp->GetActive()) {
return uid;
}
}
}
}
return kInvalidUniqueId;
}
TUniqueId CScriptSpiderBallWaypoint::PreviousWaypoint(const CStateManager& mgr,
ECheckActiveWaypoint check) const {
for (int i = 0; i < xec_waypoints.size(); ++i) {
if (const CScriptSpiderBallWaypoint* wp =
static_cast< const CScriptSpiderBallWaypoint* >(mgr.GetObjectById(xec_waypoints[i]))) {
if (check == kCAW_SkipCheck) {
return xec_waypoints[i];
} else if (wp->GetActive()) {
return xec_waypoints[i];
}
}
}
return kInvalidUniqueId;
}
void CScriptSpiderBallWaypoint::AddPreviousWaypoint(TUniqueId uid) {
if (xec_waypoints.size() == xec_waypoints.capacity()) {
xec_waypoints.reserve(xec_waypoints.capacity() == 0 ? 4 : xec_waypoints.capacity() * 2);
}
xec_waypoints.push_back(uid);
}
void CScriptSpiderBallWaypoint::GetClosestPointAlongWaypoints(
CStateManager& mgr, const CVector3f& ballPos, float maxPointToBallDist,
const CScriptSpiderBallWaypoint** closestWaypoint, CVector3f& closestPoint,
CVector3f& deltaBetweenPoints, float deltaBetweenInterpPoints,
CVector3f& interpDeltaBetweenPoints) const {
const CScriptSpiderBallWaypoint* wp = this;
while (wp->PreviousWaypoint(mgr, kCAW_SkipCheck) != kInvalidUniqueId) {
wp = static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->PreviousWaypoint(mgr, kCAW_SkipCheck)));
}
float minPointToBallDistSq = maxPointToBallDist * maxPointToBallDist;
const float deltaBetweenInterpDistSq = deltaBetweenInterpPoints * deltaBetweenInterpDistSq;
CVector3f lastPoint = wp->GetTranslation();
CVector3f lastDelta = CVector3f::Zero();
bool computeDelta = wp->GetActive();
while (true) {
if (wp->NextWaypoint(mgr, kCAW_Check) != kInvalidUniqueId) {
if (computeDelta) {
const CScriptSpiderBallWaypoint* prevWp = wp;
wp = static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->NextWaypoint(mgr, kCAW_Check)));
const CVector3f thisDelta = wp->GetTranslation() - lastPoint;
const CVector3f lastPointToBall = ballPos - lastPoint;
if (prevWp->PreviousWaypoint(mgr, kCAW_Check) == kInvalidUniqueId) {
lastDelta = thisDelta;
}
const float pointToBallDistSq = lastPointToBall.MagSquared();
if (pointToBallDistSq < minPointToBallDistSq) {
minPointToBallDistSq = pointToBallDistSq;
closestPoint = lastPoint;
deltaBetweenPoints = thisDelta;
interpDeltaBetweenPoints = (thisDelta.AsNormalized() + lastDelta.AsNormalized()) * 0.5f;
*closestWaypoint = wp;
}
const float projectedT = CVector3f::Dot(lastPointToBall, thisDelta);
if (projectedT >= 0.f) {
const float normT = projectedT / thisDelta.MagSquared();
if (normT < 1.f) {
const CVector3f projectedPoint =
CVector3f::Lerp(lastPoint, wp->GetTranslation(), normT);
const float projToBallDistSq = (ballPos - projectedPoint).MagSquared();
if (projToBallDistSq < minPointToBallDistSq) {
minPointToBallDistSq = projToBallDistSq;
closestPoint = projectedPoint;
interpDeltaBetweenPoints = deltaBetweenPoints = thisDelta;
*closestWaypoint = wp;
float lastToProjDist = (lastPoint - projectedPoint).Magnitude();
if (lastToProjDist < deltaBetweenInterpDistSq) {
interpDeltaBetweenPoints = CVector3f::Lerp(
0.5f * (thisDelta.AsNormalized() + lastDelta.AsNormalized()),
thisDelta.AsNormalized(), lastToProjDist / deltaBetweenInterpDistSq);
} else if (wp->NextWaypoint(mgr, kCAW_Check) != kInvalidUniqueId) {
lastToProjDist = (projectedPoint - wp->GetTranslation()).Magnitude();
if (lastToProjDist < deltaBetweenInterpPoints) {
const float t = lastToProjDist / deltaBetweenInterpPoints;
const CScriptSpiderBallWaypoint* tmpWp =
static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->NextWaypoint(mgr, kCAW_Check)));
interpDeltaBetweenPoints = CVector3f::Lerp(
((tmpWp->GetTranslation() - wp->GetTranslation()).AsNormalized() +
(wp->GetTranslation().AsNormalized() + thisDelta.AsNormalized())) *
0.5f,
thisDelta.AsNormalized(), t);
}
}
}
}
}
lastDelta = thisDelta;
lastPoint = wp->GetTranslation();
computeDelta = true;
} else {
wp = static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->NextWaypoint(mgr, kCAW_Check)));
lastPoint = wp->GetTranslation();
computeDelta = true;
}
} else if (wp->NextWaypoint(mgr, kCAW_SkipCheck) != kInvalidUniqueId) {
wp = static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->NextWaypoint(mgr, kCAW_Check)));
computeDelta = false;
} else {
break;
}
}
if ((ballPos - lastPoint).MagSquared() >= minPointToBallDistSq) {
return;
}
closestPoint = lastPoint;
if (wp->PreviousWaypoint(mgr, kCAW_Check)) {
wp = static_cast< const CScriptSpiderBallWaypoint* >(
mgr.GetObjectById(wp->PreviousWaypoint(mgr, kCAW_Check)));
deltaBetweenPoints = lastPoint - wp->GetTranslation();
interpDeltaBetweenPoints = deltaBetweenPoints;
}
*closestWaypoint = wp;
}
void CScriptSpiderBallWaypoint::AddToRenderer(const CFrustumPlanes& frustum,
const CStateManager& mgr) const {}
void CScriptSpiderBallWaypoint::Render(const CStateManager& mgr) const { CActor::Render(mgr); }
void CScriptSpiderBallWaypoint::Accept(IVisitor& visitor) { visitor.Visit(*this); }
rstl::optional_object< CAABox > CScriptSpiderBallWaypoint::GetTouchBounds() const {
return xfc_aabox;
}