Fixing script
This commit is contained in:
1 parent
3fe21230cc
commit
423d8b8f52
1 file changed
+50
-13
+50
-13
@@ -890,14 +890,16 @@ namespace FRG
|
||||
}
|
||||
|
||||
Character* Location::raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance) {
|
||||
// Every NPC is treated as a vertical cylinder: radius 1.0m, height 1.85m,
|
||||
// Every NPC is treated as a vertical cylinder: radius 0.25m, height 1.6m,
|
||||
// base at npc->position (the model's foot). Intersection = circle hit in the
|
||||
// XZ plane, then clip the entry/exit t against the [yFoot, yFoot+height] slab.
|
||||
static constexpr float NPC_CLICK_RADIUS = 1.0f;
|
||||
static constexpr float NPC_CLICK_HEIGHT = 1.85f;
|
||||
static constexpr float NPC_CLICK_RADIUS = 0.25f;
|
||||
static constexpr float NPC_CLICK_HEIGHT = 1.6f;
|
||||
static constexpr float NPC_PICK_EPSILON = 1e-6f;
|
||||
|
||||
Character* closestNpc = nullptr;
|
||||
float closestDist = maxDistance;
|
||||
float closestAngularDistanceSq = (std::numeric_limits<float>::max)();
|
||||
float closestEntryDistance = maxDistance;
|
||||
|
||||
//logger() << "[RAYCAST_NPC] Starting raycast with " << npcs.size() << " npcs" << std::endl;
|
||||
|
||||
@@ -908,8 +910,11 @@ namespace FRG
|
||||
continue;
|
||||
}
|
||||
if (!npcState->enabled) continue;
|
||||
const float dx = rayOrigin.x() - npcState->position.x();
|
||||
const float dz = rayOrigin.z() - npcState->position.z();
|
||||
// Use the presentation position so the clickable volume follows the
|
||||
// rendered character while it is being interpolated between ticks.
|
||||
const Eigen::Vector3f npcPosition = npc->renderPosition();
|
||||
const float dx = rayOrigin.x() - npcPosition.x();
|
||||
const float dz = rayOrigin.z() - npcPosition.z();
|
||||
const float a = rayDir.x() * rayDir.x() + rayDir.z() * rayDir.z();
|
||||
if (a < 1e-6f) continue; // purely-vertical ray; not a real click case
|
||||
|
||||
@@ -922,28 +927,60 @@ namespace FRG
|
||||
const float tNear = (-b - sqrtDisc) / (2.0f * a);
|
||||
const float tFar = (-b + sqrtDisc) / (2.0f * a);
|
||||
|
||||
float entryT = max(tNear, 0.1f);
|
||||
float entryT = (std::max)(tNear, 0.1f);
|
||||
float exitT = tFar;
|
||||
|
||||
// Clip against the cylinder's vertical extent.
|
||||
const float yMin = npcState->position.y();
|
||||
const float yMin = npcPosition.y();
|
||||
const float yMax = yMin + NPC_CLICK_HEIGHT;
|
||||
if (std::abs(rayDir.y()) > 1e-6f) {
|
||||
const float tYa = (yMin - rayOrigin.y()) / rayDir.y();
|
||||
const float tYb = (yMax - rayOrigin.y()) / rayDir.y();
|
||||
entryT = max(entryT, min(tYa, tYb));
|
||||
exitT = min(exitT, max(tYa, tYb));
|
||||
entryT = (std::max)(entryT, (std::min)(tYa, tYb));
|
||||
exitT = (std::min)(exitT, (std::max)(tYa, tYb));
|
||||
}
|
||||
else if (rayOrigin.y() < yMin || rayOrigin.y() > yMax) {
|
||||
continue; // horizontal ray passing above or below the cylinder
|
||||
}
|
||||
|
||||
if (entryT > exitT) continue;
|
||||
if (entryT > maxDistance) continue;
|
||||
|
||||
//logger() << "[RAYCAST_NPC] " << npc->entityId() << " hit at t=" << entryT << std::endl;
|
||||
// All candidates above are under the cursor. Resolve overlaps by
|
||||
// projected cursor proximity rather than by whichever cylinder is
|
||||
// entered first along the ray. The normalized perpendicular distance
|
||||
// is an angular/screen-space approximation that remains comparable
|
||||
// for NPCs at different depths.
|
||||
const Eigen::Vector3f bodyCenter =
|
||||
npcPosition + Eigen::Vector3f(0.0f, NPC_CLICK_HEIGHT * 0.5f, 0.0f);
|
||||
const Eigen::Vector3f toBody = bodyCenter - rayOrigin;
|
||||
const float bodyDepth = toBody.dot(rayDir);
|
||||
if (bodyDepth <= NPC_PICK_EPSILON) continue;
|
||||
const float perpendicularDistanceSq =
|
||||
(toBody - rayDir * bodyDepth).squaredNorm();
|
||||
const float angularDistanceSq =
|
||||
perpendicularDistanceSq /
|
||||
(std::max)(bodyDepth * bodyDepth, NPC_PICK_EPSILON);
|
||||
|
||||
if (entryT < closestDist) {
|
||||
closestDist = entryT;
|
||||
const bool betterAngularMatch =
|
||||
angularDistanceSq <
|
||||
closestAngularDistanceSq - NPC_PICK_EPSILON;
|
||||
const bool equalAngularMatch =
|
||||
std::abs(angularDistanceSq - closestAngularDistanceSq) <=
|
||||
NPC_PICK_EPSILON;
|
||||
const bool betterDepthTieBreak =
|
||||
equalAngularMatch &&
|
||||
(entryT < closestEntryDistance - NPC_PICK_EPSILON);
|
||||
const bool equalDepthTieBreak =
|
||||
equalAngularMatch &&
|
||||
std::abs(entryT - closestEntryDistance) <= NPC_PICK_EPSILON;
|
||||
const bool betterStableTieBreak =
|
||||
equalDepthTieBreak &&
|
||||
(!closestNpc || npc->entityId() < closestNpc->entityId());
|
||||
|
||||
if (betterAngularMatch || betterDepthTieBreak || betterStableTieBreak) {
|
||||
closestEntryDistance = entryT;
|
||||
closestAngularDistanceSq = angularDistanceSq;
|
||||
closestNpc = npc.get();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user