We encountered a problem where a ConstantForce is not applied in a separate PhysicsScene, but is working in our realtime scene. We use a separate scene to calculate the path of a bullet to preview it to the user.
I stripped the problem down to a very simple script that anyone can try. This script executes 10 steps of a physics simulation in two versions: One version with constant force, the second version without.
The resulting position of the test object should not be identical, but it is.
Reproduction should be easy:
- Create an empty scene
- Create an empty game object
- Attach the script below
- Press play
- Use the two check boxes in the inspector to run two versions of the simulation and check the debug log
Are we missing something or is this a Unity bug? We use 2020.3.15f2
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PhysicsSimulationTest : MonoBehaviour
{
[SerializeField] private bool runWithConstantForce;
[SerializeField] private bool runWithoutConstantForce;
void RunTest(bool withConstantForce)
{
// create a separate scene to simulate physics
var testScene = SceneManager.CreateScene("PhysicSimulation", new CreateSceneParameters(LocalPhysicsMode.Physics3D));
// set test scene active
var current = SceneManager.GetActiveScene();
SceneManager.SetActiveScene(testScene);
// create simple game object with a rigidbody and a mass of 1
var bulletPhysic = new GameObject();
var rb = bulletPhysic.AddComponent<Rigidbody>();
rb.mass = 1;
rb.position = Vector3.zero;
if (withConstantForce)
{
// apply a constant force to move the object upwards
var cf = bulletPhysic.AddComponent<ConstantForce>();
cf.force = new Vector3(0, 1000, 0);
}
// move object sideways during simulation
rb.AddForce(new Vector3(10,0,0), ForceMode.Impulse);
// execute 10 steps and log the position after each step
for (var i=0;i<10;++i)
{
var physicsScene = testScene.GetPhysicsScene();
physicsScene.Simulate(Time.fixedDeltaTime);
Debug.Log("Pos: " + rb.position);
}
// cleanup
Destroy(bulletPhysic);
SceneManager.SetActiveScene(current);
StartCoroutine(Unload(testScene));
}
private static IEnumerator Unload(Scene testScene)
{
yield return SceneManager.UnloadSceneAsync(testScene);
}
private void OnValidate()
{
if (runWithConstantForce)
{
runWithConstantForce = false;
RunTest(true);
}
else if (runWithoutConstantForce)
{
runWithoutConstantForce = false;
RunTest(false);
}
}
}