The issue is that you're applying the force in
FixedUpdate, and using ObiFixedUpdater too.
The order in which Unity calls events (Update(), FixedUpdate(),etc) for multiple scripts is
arbitrary. This means that the ObiFixedUpdater might be called
before your script's FixedUpdate(), so you apply the force after the rope simulation is done. This introduces a 1-frame delay, causing the rope to always work with out of date physics data. See:
https://docs.unity3d.com/Manual/ExecutionOrder.html
Using ObiLateFixedUpdater fixes the issue as you discovered, because it ensures the rope simulation is done
after you've applied the force (hence the "
Late"). However, since it cannot substep Unity physics (as they have already happened right before it had a chance to update the solver), both engines work with different timestep lengths and get out fo sync, causing a new issue if the amount of substeps > 1.
So the solution is to ensure your force is applied before rope simulation takes place. You could write your own Updater component that performs simulation exactly when you need, but there's an easier way: simply subscribe to the solver's OnBeginStep event, which is always called right before the solver advances a timestep. This way you can keep using ObiFixedUpdater and substepping:
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
public class FixedUpdateForce : MonoBehaviour
{
public float Thrust;
public ObiSolver solver;
private void OnEnable()
{
if (solver != null)
solver.OnBeginStep += Solver_OnBeginStep;
}
private void OnDisable()
{
if (solver != null)
solver.OnBeginStep -= Solver_OnBeginStep;
}
private void Solver_OnBeginStep(ObiSolver solver, float stepTime)
{
GetComponent<Rigidbody>().AddForce(Vector3.down * Thrust);
}
}