努力通过 2D 物理模拟在 Unity 中创建轨迹预测

Struggling to create a trajectory prediction in Unity with 2D physics simulation

我在 Unity 中有一个 2D 打砖块风格的游戏,您可以在每次转动前用鼠标选择射击角度。我想展示玩家瞄准时球会做什么的准确轨迹预测,最多可能有 200 帧球运动(目前)。这涉及到可能从顶部、左侧和右侧的墙壁以及任何砖块弹回。

我正在使用物理模拟和线条渲染器来完成此操作,但无法使其正常工作。

它应该将枪支、墙壁和砖块复制到一个虚拟场景中,以玩家瞄准的角度发射一个球,模拟 200 帧的运动,并将它们绘制在线性渲染器中。

这是游戏代码的精简版,简化为只关注第一回合的瞄准和物理模拟。当我 运行 它时,它只是在与枪相同的坐标中绘制线渲染器的 200 个点。

我做错了什么?谢谢!

using UnityEngine;
using UnityEngine.SceneManagement;

public class Aim3 : MonoBehaviour
{

    private Vector3 gunPosScreenV3, aimPointScreenV3,
        aimPointWorldV3, aimDirectionV3;

    private Vector2 ballDirection, ballVelocity;

    [SerializeField] private GameObject gun, walls, bricks;

    Camera cam;
    LineRenderer lr;

    // For Physics Scene
    private int maxPhysicsFrameIterations = 200;
    private Scene simulationScene;
    private PhysicsScene2D physicsScene;
    [SerializeField] private GameObject ballPrefab;
    private GameObject ghostObj;

    void Start()
    {
        lr = GetComponent<LineRenderer>();
        lr.enabled = true;
        cam = Camera.main;
        CreatePhysicsScene();
    }

    void Update()
    {
        DrawTrajectory();
    }

    // This is run once to create a duplicate of the game board for the physics simulation
    private void CreatePhysicsScene()
    {
        simulationScene = SceneManager.CreateScene("Simulation", new CreateSceneParameters(LocalPhysicsMode.Physics2D));
        physicsScene = simulationScene.GetPhysicsScene2D();

        // Copy the gun to the simulated scene
        ghostObj = Instantiate(gun.gameObject, gun.transform.position, gun.transform.rotation);
        ghostObj.GetComponent<SpriteRenderer>().enabled = false;
        SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);

        // Copy all the bricks to the simulated scene. These are stored under a parent Game Object that
        // is attached in the editor
        foreach (Transform obj in bricks.transform)
        {
            ghostObj = Instantiate(obj.gameObject, obj.position, obj.rotation);
            ghostObj.GetComponent<SpriteRenderer>().enabled = false;
            SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);
        }

        // Copy the top, left, and right walls to the simulated scene. These are invisible and don't have sprites.
        // These are stored under a parent Game Object that is attached in the editor
        foreach (Transform obj in walls.transform)
        {
            ghostObj = Instantiate(obj.gameObject, obj.position, obj.rotation);
            SceneManager.MoveGameObjectToScene(ghostObj, simulationScene);
        }
    } // CreatePhysicsScene

    private void DrawTrajectory()
    {
        // Get the starting Screen position of the gun from the World position
        gunPosScreenV3 = cam.WorldToScreenPoint(gun.transform.position);
        gunPosScreenV3.z = 1;

        // Get position of mouse in screen units
        aimPointScreenV3 = Input.mousePosition;

        // Get the position of the mouse in world units for aiming
        aimPointWorldV3 = cam.ScreenToWorldPoint(aimPointScreenV3);
        aimPointWorldV3.z = 1;

        // Calculate the normalized direction of the aim point compared to the gun
        aimDirectionV3 = (aimPointScreenV3 - gunPosScreenV3).normalized;

        Physics2D.simulationMode = SimulationMode2D.Script;

        // Instantiate the ball prefab for the simulation
        ghostObj = Instantiate(ballPrefab, gun.transform.position, Quaternion.identity);

        // Assign the ball's velocity
        ballDirection = new Vector2(aimDirectionV3.x, aimDirectionV3.y);
        ballVelocity = ballDirection * 20f;
        ghostObj.GetComponent<Rigidbody2D>().velocity = ballVelocity;
        SceneManager.MoveGameObjectToScene(ghostObj.gameObject, simulationScene);
        
        lr.positionCount = maxPhysicsFrameIterations;

        for (var i = 0; i < maxPhysicsFrameIterations; i++)
        {
            physicsScene.Simulate(Time.fixedDeltaTime);
            //Physics2D.Simulate(Time.fixedDeltaTime);
            lr.SetPosition(i, ghostObj.transform.position);
        }
        
        Destroy(ghostObj);
        
        Physics2D.simulationMode = SimulationMode2D.Update;

    } // DrawTrajectory

}

您使用了 aimPointScreenV3,但它似乎从来没有 initialized/calculated。

找到答案了。只需要在 将球移动到模拟场景后 添加速度。

SceneManager.MoveGameObjectToScene(ghostObj.gameObject, simulationScene);
ghostObj.GetComponent<Rigidbody2D>().velocity = ballVelocity;