my plesure,
Well I understand that won’t be feeling the right way and understand what you are trying to do better now..
Well there is multiple ways to solve it however since you are trying to do a physics simulation based movement, the event tick add force with accellaration checked should give you (not the best) but acceptable results. The proper way is to ofcourse have a fixed delta times so as you mentioned our calculations become frame independent and that one would be simply not available in blueprints.
as mentioned here, also in unreal engine 5 you can use similar approach made a substep delegate
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "FixedPhysicsDeltaTime.generated.h"
class UPrimitiveComponent;
struct FBodyInstance;
// Fires once per physics substep (delivered on GAME thread for BP safety).
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
FOnFixedSubstep, float, SubstepDelta, UPrimitiveComponent*, Target, int32, SubstepIndex);
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class YOUR GAME CHANGE_API UFixedPhysicsDeltaTime : public UActorComponent
{
GENERATED_BODY()
public:
UFixedPhysicsDeltaTime();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="FixedSubstep")
UPrimitiveComponent* Target = nullptr;
// Event: one call per physics substep game
UPROPERTY(BlueprintAssignable, Category="FixedSubstep")
FOnFixedSubstep OnFixedSubstep;
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
// Physics-thread callback for each substep
void CustomPhysics(float SubstepDelta, FBodyInstance* BodyInstance);
FBodyInstance* ResolveBody() const;
FCalculateCustomPhysics CalcDelegate;
int32 SubstepCounter = 0;
};
.cpp
#include "FixedPhysicsDeltaTime.h"
#include "Components/PrimitiveComponent.h"
#include "PhysicsEngine/BodyInstance.h"
#include "PhysicsPublic.h"
#include "Async/Async.h"
UFixedPhysicsDeltaTime::UFixedPhysicsDeltaTime()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = TG_PrePhysics;
// Bind our function pointer once
CalcDelegate.BindUObject(this, &UFixedPhysicsDeltaTime::CustomPhysics);
}
void UFixedPhysicsDeltaTime::BeginPlay()
{
Super::BeginPlay();
// Auto-pick a simulating primitive if none assigned
if (!Target)
{
if (AActor* Owner = GetOwner())
{
if (auto* RootPrim = Cast<UPrimitiveComponent>(Owner->GetRootComponent()))
{
if (RootPrim->IsSimulatingPhysics()) Target = RootPrim;
}
if (!Target)
{
TArray<UPrimitiveComponent*> Prims;
Owner->GetComponents(Prims);
for (UPrimitiveComponent* P : Prims)
{
if (P && P->IsSimulatingPhysics()) { Target = P; break; }
}
}
}
}
}
void UFixedPhysicsDeltaTime::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
FBodyInstance* UFixedPhysicsDeltaTime::ResolveBody() const
{
return Target ? Target->GetBodyInstance() : nullptr;
}
void UFixedPhysicsDeltaTime::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (FBodyInstance* BI = ResolveBody())
{
// Schedule our delegate
BI->AddCustomPhysics(CalcDelegate);
}
}
void UFixedPhysicsDeltaTime::CustomPhysics(float SubstepDelta, FBodyInstance* BodyInstance)
{
if (!BodyInstance || !Target) return;
const int32 Index = ++SubstepCounter;
UPrimitiveComponent* TargetComp = Target;
const float Dt = SubstepDelta;
// Bounce to the game thread so Blueprints can safely handle it.
AsyncTask(ENamedThreads::GameThread, [this, TargetComp, Dt, Index]()
{
if (OnFixedSubstep.IsBound())
{
OnFixedSubstep.Broadcast(Dt, TargetComp, Index);
}
});
}
so this basically on substep makes a delegate that you can make additional logic, if we don’t return to blueprints actually it would work better imo. This is not perfect however it would mimic a nice physics fixed delta time to compansate the movement on physics level.
I simply attachted to my actor with a phsyics sim enabled static mesh
here is the simple blueprint logic
results were like this, much more accurate in especially low framerates.

Let me know if that makes sense? I would like to hear additional thoughts on it. Ofcourse during fluctiations there is some changes but not dramatic.