Search Unity

Question Simulating grenade throwing trajectories using multi-scene physics.

Discussion in 'Physics' started by jkh13, Feb 14, 2021.

  1. jkh13

    jkh13

    Joined:
    Aug 6, 2013
    Posts:
    11
    I am working on a 3rd person shooter and wanted to have a way to display to the player how grenades will bounce around the scene when thrown when aiming these grenades, similar to how Gears of War does grenade aiming. I am attempting to use multi-scene physics like this example to simulate this but am running into a few problems:

    1) It doesn't appear that the physics are deterministic, this is especially obvious when bouncing off walls in the environment, the bounce jitters even though the starting position and force do not change between simulations.

    2) It doesn't exactly match the path of the actual thrown grenade. I am throwing the grenade from the same position, with the same orientation and using the same force but the arc seems to differ slightly.

    3) Performance appears to be terrible. Running enough simulates on the alternate physics scene for 3s of trajectory tanks the framerate from around 200fps to 20fps. I have tried to optimize as much as I can but it seems pretty unusable for a real-time scenario.

    This is the component which controls the simulation:

    Code (CSharp):
    1.     // Rendering the trajectory
    2.     LineRenderer lineRenderer;
    3.     List<Vector3> arcPositions = new List<Vector3>();
    4.     // How many line points to render.
    5.     public float steps;
    6.  
    7.     // Contains all the environment rigidbodies
    8.     public GameObject environment;
    9.  
    10.     private Scene mainScene;
    11.     private Scene physicsScene;
    12.  
    13.     GameObject grenadePrefab;
    14.     GameObject grenadeObject;
    15.  
    16.     // Force to be applied to grenade
    17.     public Vector3 force;
    18.  
    19.     void Start()
    20.     {
    21.         lineRenderer = GetComponent<LineRenderer>();
    22.         grenadePrefab = Resources.Load("Grenade") as GameObject;
    23.         mainScene = SceneManager.GetActiveScene();
    24.         physicsScene = SceneManager.CreateScene("Simulation", new CreateSceneParameters(LocalPhysicsMode.Physics3D));
    25.         PrepareScene();
    26.  
    27.         // Calculate how many simulation steps are needed to simulate 3s of the throw.
    28.         // (Appears to be 150 steps using default settings).
    29.         steps = 3f / Time.fixedDeltaTime;
    30.     }
    31.  
    32.     void PrepareScene()
    33.     {
    34.         SceneManager.SetActiveScene(physicsScene);
    35.  
    36.         // Clone environment gameobject structure into simulation scene.
    37.         Instantiate(environment);
    38.  
    39.         grenadeObject = GameObject.Instantiate(grenadePrefab);
    40.         // Destroy unecessary components from grenade prefab.
    41.         Destroy(grenadeObject.GetComponent<TrailRenderer>());
    42.         Destroy(grenadeObject.GetComponent<MeshRenderer>());
    43.         Destroy(grenadeObject.GetComponent<Grenade>());
    44.  
    45.         SceneManager.SetActiveScene(mainScene);
    46.     }
    47.  
    48.     void Update()
    49.     {
    50.         arcPositions.Clear();
    51.         // Reset velocity on simulation grenade and reset starting position.
    52.         grenadeObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
    53.         grenadeObject.transform.position = transform.position;
    54.         // Add the throw force to the grenade
    55.         grenadeObject.GetComponent<Rigidbody>().AddForce(force);
    56.  
    57.         // Simulate the throw for 3 seconds and draw the line.
    58.         for (int i = 0; i < steps; i++) {
    59.             arcPositions.Add(grenadeObject.transform.position);
    60.             physicsScene.GetPhysicsScene().Simulate(Time.fixedDeltaTime);
    61.         }
    62.         lineRenderer.positionCount = arcPositions.Count;
    63.         lineRenderer.SetPositions(arcPositions.ToArray());
    64.     }
    Does anyone have any ideas how I would be able to implement these trajectories in a more performant and accurate manner? This is how it looks like in Gears of War if you are not familiar:


    The simulated arc can bounce off the environment and this is all running in realtime as you aim.

    Note:
    I have also tried to increase the simulation step timing to allow me to run less simulates in order to get 3s of simulation but this entirely changes the trajectory and is unusable.

    Simulate step: 0.01f - purple line is the simulation, red is the actual.


    Simulate step 0.02f