Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question 2D physics simulation to create trajectory prediction

Discussion in 'Physics' started by ahcollin, Apr 22, 2022.

  1. ahcollin

    ahcollin

    Joined:
    Jan 12, 2016
    Posts:
    7
    I have a 2D brick breaker style game in Unity where you get to choose the angle of your shot before each turn with the mouse. I'd like to show an accurate trajectory prediction of what a ball will do while the player is aiming, up to maybe 200 frames of ball movement. This involves potentially bouncing off the top, left, and right walls, and any bricks.

    I'm using a physics simulation and line renderer to accomplish this but can't get it to work correctly.

    It's supposed to copy the gun, walls, and bricks into a virtual Scene, launch a ball in the angle the player is aiming, simulate 200 frames of movement, and plot those in a line renderer.

    Here is an abridged version of the game code, reduced to just focus on the aiming and physics simulation for the 1st turn. When I run it, it simply plots the 200 points of the line renderer in the same coordinates as the gun.

    Any help is appreciated, thank you.
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.SceneManagement;
    4.  
    5. public class Aim3 : MonoBehaviour
    6. {
    7.  
    8.     private Vector3 gunPosScreenV3, aimPointScreenV3,
    9.         aimPointWorldV3, aimDirectionV3;
    10.  
    11.     private Vector2 ballDirection, ballVelocity;
    12.  
    13.     [SerializeField] private GameObject gun, walls, bricks;
    14.  
    15.     Camera cam;
    16.     LineRenderer lr;
    17.  
    18.     // For Physics Scene
    19.     private int maxPhysicsFrameIterations = 200;
    20.     private Scene simulationScene;
    21.     private PhysicsScene2D physicsScene;
    22.     [SerializeField] private GameObject ballPrefab;
    23.     private GameObject ghostObj;
    24.  
    25.     void Start()
    26.     {
    27.         lr = GetComponent<LineRenderer>();
    28.         lr.enabled = true;
    29.         cam = Camera.main;
    30.         CreatePhysicsScene();
    31.     }
    32.  
    33.     void Update()
    34.     {
    35.         DrawTrajectory();
    36.     }
    37.  
    38.     // This is run once to create a duplicate of the game board for the physics simulation
    39.     private void CreatePhysicsScene()
    40.     {
    41.         simulationScene = SceneManager.CreateScene("Simulation", new CreateSceneParameters(LocalPhysicsMode.Physics2D));
    42.         physicsScene = simulationScene.GetPhysicsScene2D();
    43.  
    44.         // Copy the gun to the simulated scene
    45.         ghostObj = Instantiate(gun.gameObject, gun.transform.position, gun.transform.rotation);
    46.         ghostObj.GetComponent<SpriteRenderer>().enabled = false;
    47.         SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);
    48.  
    49.         // Copy all the bricks to the simulated scene. These are stored under a parent Game Object that
    50.         // is attached in the editor
    51.         foreach (Transform obj in bricks.transform)
    52.         {
    53.             ghostObj = Instantiate(obj.gameObject, obj.position, obj.rotation);
    54.             ghostObj.GetComponent<SpriteRenderer>().enabled = false;
    55.             SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);
    56.         }
    57.  
    58.         // Copy the top, left, and right walls to the simulated scene. These are invisible and don't have sprites.
    59.         // These are stored under a parent Game Object that is attached in the editor
    60.         foreach (Transform obj in walls.transform)
    61.         {
    62.             ghostObj = Instantiate(obj.gameObject, obj.position, obj.rotation);
    63.             SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);
    64.         }
    65.     } // CreatePhysicsScene
    66.  
    67.     private void DrawTrajectory()
    68.     {
    69.         // Get the starting Screen position of the gun from the World position
    70.         gunPosScreenV3 = cam.WorldToScreenPoint(gun.transform.position);
    71.         gunPosScreenV3.z = 1;
    72.  
    73.         // Get position of mouse in screen units
    74.         aimPointScreenV3 = Input.mousePosition;
    75.  
    76.         // Get the position of the mouse in world units for aiming
    77.         aimPointWorldV3 = cam.ScreenToWorldPoint(aimPointScreenV3);
    78.         aimPointWorldV3.z = 1;
    79.  
    80.         // Calculate the normalized direction of the aim point compared to the gun
    81.         aimDirectionV3 = (aimPointScreenV3 - gunPosScreenV3).normalized;
    82.  
    83.         Physics2D.simulationMode = SimulationMode2D.Script;
    84.  
    85.         // Instantiate the ball prefab for the simulation
    86.         ghostObj = Instantiate(ballPrefab, gun.transform.position, Quaternion.identity);
    87.  
    88.         // Assign the ball's velocity
    89.         ballDirection = new Vector2(aimDirectionV3.x, aimDirectionV3.y);
    90.         ballVelocity = ballDirection * 20f;
    91.         ghostObj.GetComponent<Rigidbody2D>().velocity = ballVelocity;
    92.         SceneManager.MoveGameObjectToScene(ghostObj.gameObject, simulationScene);
    93.        
    94.         lr.positionCount = maxPhysicsFrameIterations;
    95.  
    96.         for (var i = 0; i < maxPhysicsFrameIterations; i++)
    97.         {
    98.             physicsScene.Simulate(Time.fixedDeltaTime);
    99.             //Physics2D.Simulate(Time.fixedDeltaTime);
    100.             lr.SetPosition(i, ghostObj.transform.position);
    101.         }
    102.        
    103.         Destroy(ghostObj);
    104.        
    105.         Physics2D.simulationMode = SimulationMode2D.Update;
    106.  
    107.     } // DrawTrajectory
    108.  
    109. }
     
  2. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    780
    How about making prediction shoots with some kind of objects with the sama physics properties as the "real" bullets, that leaves a trail plotting the trajectory? But that is maybe what you already are trying to do when "using a physics simulation and line render"?
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,101
    You said a lot of words and posted a lot of code but never actually said what was wrong! Apart from "it simply plots the 200 points of the line renderer in the same coordinates as the gun" but is that supposed to be the problem? I have no idea what that means. What are you expectations and what is it doing. For this, I believe an image would help because ... what is the "gun" and what should it look like?

    You should spend more time describing the problem and less so your solution. :)
     
  4. ahcollin

    ahcollin

    Joined:
    Jan 12, 2016
    Posts:
    7
    Oops :)

    I meant the physics simulation didn't work. It's supposed to launch the ball and simulate the physics of it. But it didn't launch, the ball simply stayed in the same place.

    Regardless, it's now fixed. The velocity needed to be added to the ball after moving it to the simulated scene, not before.
     
    MelvMay likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,101
    Yes, body velocity is a volatile property not part of the serialized state, same as angular velocity.

    Glad you got it working.