Unreal 入門-Montage Root Motion 功能代碼說明。

Root Motion 移動功能。

void UCharacterMovementComponent::SimulatedTick(float DeltaSeconds)
{
    SCOPE_CYCLE_COUNTER(STAT_CharacterMovementSimulated);
    checkSlow(CharacterOwner != nullptr);
    if (NetworkSmoothingMode == ENetworkSmoothingMode::Replay)
    {
        const FVector OldLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
        const FVector OldVelocity = Velocity;
        // Interpolate between appropriate samples
        {
            SCOPE_CYCLE_COUNTER( STAT_CharacterMovementSmoothClientPosition );
            SmoothClientPosition( DeltaSeconds );
        }
        // Update replicated movement mode
        ApplyNetworkMovementMode( GetCharacterOwner()->GetReplicatedMovementMode() );
        UpdateComponentVelocity();
        bJustTeleported = false;
        CharacterOwner->RootMotionRepMoves.Empty();
        CurrentRootMotion.Clear();
        CharacterOwner->SavedRootMotion.Clear();
        // Note: we do not call the Super implementation, that runs prediction.
        // We do still need to call these though
        OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
        CallMovementUpdateDelegate(DeltaSeconds, OldLocation, OldVelocity);
        LastUpdateLocation = UpdatedComponent ? UpdatedComponent->GetComponentLocation() : FVector::ZeroVector;
        LastUpdateRotation = UpdatedComponent ? UpdatedComponent->GetComponentQuat() : FQuat::Identity;
        LastUpdateVelocity = Velocity;
        //TickCharacterPose( DeltaSeconds );
        return;
    }
    // If we are playing a RootMotion AnimMontage.
    if (CharacterOwner->IsPlayingNetworkedRootMotionMontage())
    {
        bWasSimulatingRootMotion = true;
        UE_LOG(LogRootMotion, Verbose, TEXT("UCharacterMovementComponent::SimulatedTick"));
        // Tick animations before physics.
        if( CharacterOwner->GetMesh() )
        {
            TickCharacterPose(DeltaSeconds);
            // Make sure animation didn't trigger an event that destroyed us
            if (!HasValidData())
            {
                return;
            }
        }
        if( RootMotionParams.bHasRootMotion )
        {
            const FQuat OldRotationQuat = UpdatedComponent->GetComponentQuat();
            const FVector OldLocation = UpdatedComponent->GetComponentLocation();
            SimulateRootMotion(DeltaSeconds, RootMotionParams.GetRootMotionTransform());
            #if !(UE_BUILD_SHIPPING)
            // debug
            if (false)
            {
                const FRotator OldRotation = OldRotationQuat.Rotator();
                const FRotator NewRotation = UpdatedComponent->GetComponentRotation();
                const FVector NewLocation = UpdatedComponent->GetComponentLocation();
                DrawDebugCoordinateSystem(GetWorld(), CharacterOwner->GetMesh()->GetComponentLocation() + FVector(0,0,1), NewRotation, 50.f, false);
                DrawDebugLine(GetWorld(), OldLocation, NewLocation, FColor::Red, true, 10.f);
                UE_LOG(LogRootMotion, Log,  TEXT("UCharacterMovementComponent::SimulatedTick DeltaMovement Translation: %s, Rotation: %s, MovementBase: %s"),
                *(NewLocation - OldLocation).ToCompactString(), *(NewRotation - OldRotation).GetNormalized().ToCompactString(), *GetNameSafe(CharacterOwner->GetMovementBase()) );
            }
            #endif // !(UE_BUILD_SHIPPING)
        }
        // then, once our position is up to date with our animation, 
        // handle position correction if we have any pending updates received from the server.
        if( CharacterOwner && (CharacterOwner->RootMotionRepMoves.Num() > 0) )
        {
            CharacterOwner->SimulatedRootMotionPositionFixup(DeltaSeconds);//這裏調整位置跟隨動作運動
        }
    }
    //...
}


這裏做了移動:

void ACharacter::SimulatedRootMotionPositionFixup(float DeltaSeconds)
{
    const FAnimMontageInstance* ClientMontageInstance = GetRootMotionAnimMontageInstance();//這裏獲取了自帶Mesh
    if( ClientMontageInstance && CharacterMovement && Mesh )
    {
        // Find most recent buffered move that we can use.
        const int32 MoveIndex = FindRootMotionRepMove(*ClientMontageInstance);
        if( MoveIndex != INDEX_NONE )
        {
            const FVector OldLocation = GetActorLocation();
            const FQuat OldRotation = GetActorQuat();
            // Move Actor back to position of that buffered move. (server replicated position).
            const FSimulatedRootMotionReplicatedMove& RootMotionRepMove = RootMotionRepMoves[MoveIndex];
            if( RestoreReplicatedMove(RootMotionRepMove) )
            {
                const float ServerPosition = RootMotionRepMove.RootMotion.Position;
                const float ClientPosition = ClientMontageInstance->GetPosition();
                const float DeltaPosition = (ClientPosition - ServerPosition);
                if( FMath::Abs(DeltaPosition) > KINDA_SMALL_NUMBER )
                {
                    // Find Root Motion delta move to get back to where we were on the client.
                    const FTransform LocalRootMotionTransform = ClientMontageInstance->Montage->ExtractRootMotionFromTrackRange(ServerPosition, ClientPosition);
                    // Simulate Root Motion for delta move.
                    if( CharacterMovement )
                    {
                        const float MontagePlayRate = ClientMontageInstance->GetPlayRate();
                        // Guess time it takes for this delta track position, so we can get falling physics accurate.
                        if (!FMath::IsNearlyZero(MontagePlayRate))
                        {
                            const float DeltaTime = DeltaPosition / MontagePlayRate;
                            // Even with negative playrate deltatime should be positive.
                            check(DeltaTime > 0.f);
                            CharacterMovement->SimulateRootMotion(DeltaTime, LocalRootMotionTransform);
                            // After movement correction, smooth out error in position if any.
                            CharacterMovement->bNetworkSmoothingComplete = false;
                            CharacterMovement->SmoothCorrection(OldLocation, OldRotation, GetActorLocation(), GetActorQuat());
                        }
                    }
                }
            }
            // Delete this move and any prior one, we don't need them anymore.
            UE_LOG(LogRootMotion, Log,  TEXT("\tClearing old moves (%d)"), MoveIndex+1);
            RootMotionRepMoves.RemoveAt(0, MoveIndex+1);
        }
    }
}

這裏獲取了Character自帶的Mesh,限制的Root Motion只能用在Character 自帶的Mesh。

/** Get FAnimMontageInstance playing RootMotion */
FAnimMontageInstance * ACharacter::GetRootMotionAnimMontageInstance() const
{
    return (Mesh && Mesh->GetAnimInstance()) ? Mesh->GetAnimInstance()->GetRootMotionMontageInstance() : NULL;
}

發佈了60 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章