You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中无法绘制火箭飞行轨迹的问题排查求助

问题:Unity太空模拟游戏轨迹绘制失效,Ghost火箭不移动

我正在开发一款太空模拟游戏,火箭需要借助引力在行星间航行。目前想要绘制火箭的飞行轨迹辅助玩家,用Unity的Simulate功能写了代码,但没法正常工作。游戏本身运行没问题,但用来绘制轨迹的ghost物体完全不动,一直停留在玩家火箭下方。

编辑补充:我发现哪怕执行ghostRocketRb.position = gameObject.GetComponent<Rigidbody2D>().position;,对ghostRocket的Rigidbody2D做的任何修改都不生效。


相关代码

TrajectoryVisualization.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManager;

public class TrajectoryVisualization : MonoBehaviour
{

    private static Scene TrajectoryScene;
    private static PhysicsScene TrajectoryPhysicsScene;
    private static LineRenderer lineRenderer;

    private static GameObject ghostRocketObj;
    private static List<GameObject> ghostPlanetsObj;
    private static List<GameObject> ghostBoundariesObj;

    [SerializeField] private static int simulationSteps = 50;

    void Start()
    {

        TrajectoryScene = SceneManager.CreateScene("TrajectorySimulation", new CreateSceneParameters(LocalPhysicsMode.Physics2D));
        TrajectoryPhysicsScene = TrajectoryScene.GetPhysicsScene();
        
        lineRenderer = GetComponent<LineRenderer>();

        addPlanetsToSimulation();
        addRocketToSimulation();
        addBoundariesToSimulation();
    }

    // Update is called once per frame
    void Update()
    {

        Physics.autoSimulation = false;

        Debug.Log("START SIMULATION");

        ghostRocketObj.transform.position = gameObject.transform.position;
        Rigidbody2D ghostVelocity = ghostRocketObj.GetComponent<Rigidbody2D>();
        ghostVelocity.velocity = gameObject.GetComponent<Rigidbody2D>().velocity;

        List<Vector3> pathPoints = new List<Vector3>();

        for (int i = 0; i < simulationSteps; i++)
        {
            Gravity.calculateGravity(ghostPlanetsObj, ghostRocketObj.GetComponent<Rigidbody2D>(), true);
            TrajectoryPhysicsScene.Simulate(Time.fixedDeltaTime);
            pathPoints.Add(ghostRocketObj.transform.position);
        }
        

        lineRenderer.positionCount = simulationSteps;
        lineRenderer.SetPositions(pathPoints.ToArray());

        Debug.Log("END SIMULATION");

        Physics.autoSimulation = true;

    }

    private void addPlanetsToSimulation()
    {

        ghostPlanetsObj = new List<GameObject>();

        //Add planets to simulation scene
        foreach (GameObject planet in ListPlanets.getPlanetsObject())
        {
            GameObject ghostplanetObj = Instantiate(planet, planet.transform.position, planet.transform.rotation);
            ghostplanetObj.GetComponent<Renderer>().enabled = false;
            SceneManager.MoveGameObjectToScene(ghostplanetObj, TrajectoryScene);
            ghostPlanetsObj.Add(ghostplanetObj);
        }

    }

    private void addRocketToSimulation()
    {
        //Add planets to simulation scene
        ghostRocketObj = Instantiate(gameObject, gameObject.transform.position, gameObject.transform.rotation);
        ghostRocketObj.tag = "RocketSimulation";
        ghostRocketObj.GetComponent<Renderer>().enabled = false;
        ghostRocketObj.GetComponent<Animator>().enabled = false;
        ghostRocketObj.GetComponent<Rotation>().enabled = false;
        ghostRocketObj.GetComponent<RocketThrust>().enabled = false;
        ghostRocketObj.GetComponent<PlayerInput>().enabled = false;
        ghostRocketObj.GetComponent<TrajectoryVisualization>().enabled = false;
        ghostRocketObj.GetComponent<AudioSource>().enabled = false;
        ghostRocketObj.GetComponent<Position>().enabled = false;
        SceneManager.MoveGameObjectToScene(ghostRocketObj, TrajectoryScene);
    }

    private void addBoundariesToSimulation()
    {

        ghostBoundariesObj = new List<GameObject>();

        foreach (GameObject boundary in GameObject.FindGameObjectsWithTag("Boundary"))
        {
            GameObject ghostBoundaryObj = Instantiate(boundary, boundary.transform.position, boundary.transform.rotation);
            ghostBoundaryObj.GetComponent<Renderer>().enabled = false;
            SceneManager.MoveGameObjectToScene(ghostBoundaryObj, TrajectoryScene);
            ghostBoundariesObj.Add(ghostBoundaryObj);
        }
    }


    public static void createNewPlanetSimulation(GameObject newPlanet)
    {
        GameObject ghostplanetObj = Instantiate(newPlanet, newPlanet.transform.position, newPlanet.transform.rotation);
        ghostplanetObj.GetComponent<Renderer>().enabled = false;
        SceneManager.MoveGameObjectToScene(ghostplanetObj, TrajectoryScene);
        ghostPlanetsObj.Add(ghostplanetObj);
    }

}

Gravity.cs

using System.Collections.Generic;
using UnityEngine;

public class Gravity : MonoBehaviour
{
    private static Rigidbody2D planetAttractor;

    [SerializeField] private static float G = 4.0f;
    [SerializeField] private Rigidbody2D rocketPlayer;
    [SerializeField] private Rigidbody2D planetOrigin;

    // Start is called before the first frame update
    void Start()
    {
        planetAttractor = planetOrigin;
        Scoring.reference = planetOrigin.name;
    }

    void FixedUpdate()
    {
        calculateGravity(ListPlanets.getPlanetsObject(), rocketPlayer, false);
    }

    public static void calculateGravity(List<GameObject> planets, Rigidbody2D rocket, bool isSimulation)
    {
        float smallestDistance = Vector2.Distance(planets[0].GetComponent<Rigidbody2D>().position, rocket.position);

        foreach (GameObject planet in planets)
        {
            Rigidbody2D tmpBody = planet.GetComponent<Rigidbody2D>();

            float distance = Vector2.Distance(tmpBody.position, rocket.position);
            if (distance <= smallestDistance)
            {

                planetAttractor = tmpBody;
                smallestDistance = distance;
            }
        }

        float massProduct = planetAttractor.mass*rocket.mass*G;

        Vector2 direction = planetAttractor.position - rocket.position;
        float distanceBetween = direction.magnitude;

        float unScaledforceMagnitude = massProduct/Mathf.Pow(distanceBetween,2);
        float forceMagnitude = G*unScaledforceMagnitude;

        Vector2 forceDirection = direction.normalized;
        Vector2 forceVector = forceDirection*forceMagnitude;

        Debug.Log("forceDirection: " + forceDirection);
        Debug.Log("forceMagnitude: " + forceMagnitude);
        Debug.Log("rocket.position: " + rocket.position);
        Debug.Log("rocket.velocity: " + rocket.velocity);

        rocket.AddForce(forceVector);
    }

}

问题排查与解决

1. 修正Rigidbody2D状态同步方式

直接修改transform.position无法正确同步独立物理场景中Rigidbody2D的状态,必须操作Rigidbody2D自身的属性:

// 替换原状态同步代码
Rigidbody2D ghostRb = ghostRocketObj.GetComponent<Rigidbody2D>();
ghostRb.position = gameObject.GetComponent<Rigidbody2D>().position;
ghostRb.velocity = gameObject.GetComponent<Rigidbody2D>().velocity;
ghostRb.angularVelocity = 0f;
ghostRb.ResetForces(); // 清除残留受力,避免模拟偏差

2. 修正物理模拟控制API

你创建的是2D物理场景,应该使用Physics2D.autoSimulation而非Physics.autoSimulation:

// 替换原代码中的Physics.autoSimulation
Physics2D.autoSimulation = false;

// ... 模拟逻辑 ...

Physics2D.autoSimulation = true;

3. 修复引力计算的公式错误

代码中重复乘以引力常数G,导致引力被平方放大,修正为标准万有引力公式:

// 替换Gravity.cs中的力计算部分
float forceMagnitude = (G * planetAttractor.mass * rocket.mass) / Mathf.Pow(distanceBetween, 2);
Vector2 forceDirection = direction.normalized;
Vector2 forceVector = forceDirection * forceMagnitude;

4. 移除静态变量的全局污染

TrajectoryVisualization中的静态变量(如ghostPlanetsObj)会导致多实例/场景切换时的状态冲突,建议改为非静态变量:

// 替换原静态变量定义
private Scene TrajectoryScene;
private PhysicsScene TrajectoryPhysicsScene;
private LineRenderer lineRenderer;

private GameObject ghostRocketObj;
private List<GameObject> ghostPlanetsObj;
private List<GameObject> ghostBoundariesObj;

[SerializeField] private int simulationSteps = 50;

内容的提问来源于stack exchange,提问作者CromSoldier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:12:08