A problem with Add Force & Set Physics Linear Velocity related to independent framerate!!

Hello! I’m struggling to set these nodes (Add Force and Set Physics Linear Velocity) to be framerate independent..
I don’t know what to do at this point.
I just want the launch to be consistent, regardless of the framerate

The timeline has the length 0.1

Timeline + Add Force


Timeline + Add Force

Timeline + Set Physics Linear Velocity


Timeline + Set Physics Linear Velocity

Event Tick + Add Force


Event Tick + Add Force

Event Tick + Set Physics Linear Velocity


Event Tick + Set Physics Linear Velocity

Event Tick + Delta Seconds + Add Force


Event Tick + Delta Seconds + Add Force

Event Tick + Delta Seconds + Set Physics Linear Velocity


Event Tick + Delta Seconds + Set Physics Linear Velocity

What am I doing wrong??

So the question is I am assuming why they are all different? and they all result in different heights?

Let’s break down the question into its basics

distance = time x velocity

for distance to be constant time and velocity simply inverse relations ship. one increases other should decrease to be consistent.

Forces are integrated over time AddForce once per frame, but frames vary so applying different forces each slice unless physics is substepped properly or your frames are super consistent. Still if you have that target machines would have different results, so that bugs.

In order to easy solve your problem I would suggest using “Add Impulse”. Add impulse in on tick and its one shot go with and impulse force resulting in consistent interpolation. Don’t apply on tick, just a high impulse and engine will take care of the rest. I am especially telling this since there is no much external forces on object rather than the gravity itself.

Additionally you can keep Fixed Velocity and interpolate between point A to B simply kinematic set actor location external forces. That would be again quite accurate but as said its more kinematic feel than actual physics simulation.

Also Project setting → physics substepping on would increase accuracy, give a shot to add impulse and let us know.

1 Like

Thanks for the answer!
What I want is to have a force addition time of 0.1 seconds, if I simply use Add Impulse with a single hit it will seem fast, like a snap.
I will also want to move the cube while it is in the air forward/backward and left/right by adding force to it using the input axis. What should I do in this case? I want to use physics and not the kinematics way!

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.
ezgif-4c35e515b82b6a

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.

Wow, that’s a lot and thank you very much for your involvement!
I’ll definitely try them all. I have a little problem with the code, I know to work only with blueprints, so I don’t know where or how to put the code. Do you know of a short tutorial specifically for this code?

If you project is C++ you can simply put those files under your project
image

D:\Project\Source\ProjectName

Build compile and it should be available in unreal.

Unfortunately, I’ve never done this before, I really don’t know where and how. I work exclusively with blueprints, I never touch the files or anything in C++.
The two files I need to create myself, like create a text document with .h and .cpp format and put them in D:\Project\Source\ProjectName with the code?
I don’t know about the build and compile part, do I just open the project or do I have to go into Visual Studio somewhere to build it?