// ICalcProbeLengths ------------------- // ----------------- void plAvBrainClimb::ICalcProbeLengths() { // we assume that the up and down climbs go the same distance; // same for the left and right climbs plAGAnim *up = fAvMod->FindCustomAnim("ClimbUp"); plAGAnim *left = fAvMod->FindCustomAnim("ClimbLeft"); hsMatrix44 upMove, leftMove; hsAssert(up, "Couldn't find ClimbUp animation."); if(up) { GetStartToEndTransform(up, &upMove, nil, "Handle"); fVerticalProbeLength = upMove.GetTranslate().fZ; } else fVerticalProbeLength = 4.0f; // guess hsAssert(left, "Couldn't find ClimbLeft animation."); if(left) { GetStartToEndTransform(left, &leftMove, nil, "Handle"); fHorizontalProbeLength = leftMove.GetTranslate().fX; } else fHorizontalProbeLength = 3.0f; // guess }
// IIsClosestAnim ------------------------------------------------------------------- // --------------- bool IIsClosestAnim(const char *animName, hsMatrix44 &sitGoal, float &closestDist, hsPoint3 curPosition, const plArmatureMod *avatar) { plAGAnim *anim = avatar->FindCustomAnim(animName); if(anim) { hsMatrix44 animEndToStart; // The sit target is the position we want to be at the END of the sit animation. // We have several animations to choose from, each starting from a different // position. // This will look at one of those animations and figure out how far we are from // its starting position. // The first step is to get the transform from the end to the beginning of the // animation. That's what this next line is doing. It's a bit unintuitive // until you look at the parameter definitions. GetStartToEndTransform(anim, nil, &animEndToStart, "Handle"); hsMatrix44 candidateGoal = sitGoal * animEndToStart; hsPoint3 distP = candidateGoal.GetTranslate() - curPosition; hsVector3 distV(distP.fX, distP.fY, distP.fZ); float dist = distP.Magnitude(); if(closestDist == 0.0 || dist < closestDist) { closestDist = dist; return true; } } else { hsAssert(false, ST::format("Missing sit animation: {}", animName).c_str()); } return false; }
// START // Adjust our goal time based on our duration and the current time bool plAvSeekTask::Start(plArmatureMod *avatar, plArmatureBrain *brain, double time, float elapsed) { fTargetTime = time + fDuration; // clock starts now.... fPhysicalAtStart = avatar->IsPhysicsEnabled(); avatar->EnablePhysics(false); // always turn physics off for seek plAvBrainHuman *huBrain = plAvBrainHuman::ConvertNoRef(brain); if(huBrain) huBrain->IdleOnly(); ILimitPlayersInput(avatar); if (!fTarget || !fTarget->ObjectIsLoaded()) { fCleanup = true; return true; } plSceneObject* seekTarget = plSceneObject::ConvertNoRef(fTarget->ObjectIsLoaded()); hsMatrix44 targetL2W = seekTarget->GetLocalToWorld(); const plCoordinateInterface* subworldCI = nil; if (avatar->GetController()) subworldCI = avatar->GetController()->GetSubworldCI(); if (subworldCI) targetL2W = subworldCI->GetWorldToLocal() * targetL2W; switch(fAlign) { // just match our handle to the target matrix case kAlignHandle: // targetL2Sim is already correct break; // match our handle to the target matrix at the end of the given animation case kAlignHandleAnimEnd: { hsMatrix44 adjustment; plAGAnim *anim = avatar->FindCustomAnim(fAnimName); GetStartToEndTransform(anim, nil, &adjustment, "Handle"); // actually getting end-to-start targetL2W = targetL2W * adjustment; } break; default: break; }; GetPositionAndRotation(targetL2W, &fTargetPosition, &fTargetRotation); Process(avatar, brain, time, elapsed); return true; }
// IUpdateObjective ---------------------------------------- // ----------------- hsBool plAvTaskSeek::IUpdateObjective(plArmatureMod *avatar) { // This is an entirely valid case. It just means our goal is fixed. if (fSeekObject == nil) return true; // goal here is to express the target matrix in the avatar's PHYSICAL space hsMatrix44 targL2W = fSeekObject->GetLocalToWorld(); const plCoordinateInterface* subworldCI = nil; if (avatar->GetController()) subworldCI = avatar->GetController()->GetSubworldCI(); if (subworldCI) targL2W = subworldCI->GetWorldToLocal() * targL2W; MakeMatrixUpright(targL2W); switch(fAlign) { // match our handle to the target matrix at the end of the given animation // This case isn't currently used but will be important someday. The idea // is that you have a target point and an animation, and you want to seek // the avatar to a point where he can start playing the animation and wind // up, after the animation completes, at the target location. // Hence "AlignHandleAnimEnd" = "align the avatar so the animation will // end on the target." case kAlignHandleAnimEnd: { hsMatrix44 adjustment; plAGAnim *anim = avatar->FindCustomAnim(fAnimName); // don't need to do this every frame; the animation doesn't change. // *** cache the adjustment; GetStartToEndTransform(anim, nil, &adjustment, _TEMP_CONVERT_FROM_LITERAL("Handle")); // actually getting end-to-start // ... but we do still need to multiply by the (potentially changed) target targL2W = targL2W * adjustment; } break; case kAlignHandle: // targetMat is already correct default: break; }; GetPositionAndRotation(targL2W, &fSeekPos, &fSeekRot); return true; }