Предсказатель Orbital Motion является точным только тогда, когда спутник начинается с определенной стороны планетыC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Предсказатель Orbital Motion является точным только тогда, когда спутник начинается с определенной стороны планеты

Сообщение Anonymous »

Я создал сценарий, который имитирует гравитацию между спутниками и планетой и предсказывает орбиту спутника на основе орбитальных элементов, рассчитанных по скорости и положению спутника. Все работает на удивление, совершенно хорошо, но проблема в том, что предиктор орбиты является правильным только тогда, когда спутник начинает свою орбиту с определенной стороны планеты. Когда я запускаю его с какой -либо другой стороны, орбита либо обратно, совершенно неправильно, либо возникает некоторая ошибка, что приводит к тому, что путь вообще не нарисован. < /P>
Код, который вычисляет все Физика и предиктор орбитального движения. Это единственный активный сценарий в сцене. Он прикреплен к игровому объекту сферы. G (гравитация) составляет 0,005, масса планеты (масса) составляет 1e+09: < /p>
using NUnit.Framework;
using UnityEngine;
using System.Collections.Generic;
using System;
using Unity.VisualScripting;
using UnityEngine.UIElements;
using JetBrains.Annotations;
//using static UnityEditor.PlayerSettings;
using System.Collections;
using Unity.Mathematics.Geometry;
//using UnityEditor.Experimental.GraphView;

public class Physics : MonoBehaviour
{
public Material shipTexture;
public Material trailTexture;
public Vector3 shipCoords;
public Vector3 shipThrust;
GameObject central;
Rigidbody planetMass;
float size;
public float gravity;
public float mass;

// What the player will control. Each ship has its own properties that are decided by the physics
public class Ship
{
public string name;
public float xPos;
public float yPos;
public float zPos;
public float xVel;
public float yVel;
public float zVel;
public Vector3 spam;
public Vector3 novec;
public float std;
public Vector3 ecvec;
public float semaj;
public float smen;
public float inclination;
public float rAscensionNode;
public float argumentOfPeriapsis;
public float trueAnomaly;
public float gnd;
public float dist;
public Vector3 point;
public GameObject body;
public Rigidbody mass;
public Transform pos;
public MeshFilter mFilter;
public Material mats;

public Ship(string shipName, Vector3 coords)
{
name = shipName;
xPos = coords.x;
yPos = coords.y;
zPos = coords.z;
dist = MathF.Sqrt(MathF.Pow(xPos, 2) + MathF.Pow(yPos, 2) + MathF.Pow(zPos, 2));
body = new GameObject(name);
mass = body.AddComponent();
mass.mass = 10;
mass.useGravity = false;
mass.angularDamping = 0;
mass.AddRelativeTorque(new Vector3(-0.3f, 1, 0.5f), ForceMode.Impulse);
pos = body.GetComponent();
pos.localScale = new Vector3(10, 10, 10);
mFilter = body.AddComponent();
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
mFilter.mesh = go.GetComponent().mesh;
mFilter.gameObject.AddComponent();
Destroy(go);
pos.position = new Vector3(xPos, yPos, zPos);

}

}

// Every equation I will need to map out orbits
public class Equations
{
public static float Gravity(Transform m2Loc, Rigidbody m1Mass, Rigidbody m2Mass, float gravityConstant)
{

return (m1Mass.mass * m2Mass.mass) * gravityConstant / MathF.Pow(m2Loc.position.magnitude, 3);
}

public static Vector3 SpecificAngularMomentum(Vector3 r, Vector3 v) // h
{
return Vector3.Cross(r, v);
}

public static Vector3 NodeVector(Vector3 SAM) // n
{
return Vector3.Cross(new Vector3(0, -1, 0), SAM);
}

public static float StandardGravParam(float gConst, float earthMass, float shipMass)
{

return gConst * (earthMass + shipMass);
}

public static Vector3 EccentricityVector(Vector3 r, Vector3 v, Vector3 h, float u) // e
{
return ((MathF.Pow(v.magnitude, 2) - u / r.magnitude) * r - (Vector3.Dot(r, v) * v)) / u;
}

public static float SpecialMechanicalEnergy(Vector3 v, Vector3 r, float u) // E
{
return (MathF.Pow(v.magnitude, 2) / 2) - (u / r.magnitude);
}

public static float Momentum(float a, Vector3 e) // p
{
return a * (1 - MathF.Pow(e.magnitude, 2));
}

//////////////////////////////////////////////////////////////////
// Five of the Six Orbital Elements (minus time since Periapsis)
public static float Inclination(Vector3 h) // i
{
return MathF.Acos(-1 * h.y / h.magnitude);
}

public static float RightAscendingNode(Vector3 n) // O
{
return MathF.Acos(n.x / n.magnitude);
}

public static float ArgumentOfPeriapsis(Vector3 n, Vector3 e) // w
{
float equation = MathF.Acos(Vector3.Dot(n, e) / (n.magnitude * e.magnitude));

if (e.z < 0)
{
return 2 * MathF.PI - equation;
}
else
{
return equation;
}
}

public static float SemiMajorAxis(float u, float SME) // a
{
return -1 * (u / (2 * SME));
}

public static float TrueAnomaly(Vector3 e, Vector3 r) // v
{
return Mathf.Acos(Vector3.Dot(e, r) / (e.magnitude * r.magnitude));
}

}
public List ships = new List();
public List paths = new List();

// Gets the orbital elements 1 second after game starts
IEnumerator GetElements()
{
yield return new WaitForSeconds(1.005f);

Predictor();

}

// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{

central = GameObject.Find("M1");
planetMass = central.AddComponent();
planetMass.mass = mass;
planetMass.angularDamping = 0;
size = central.GetComponent().localScale.magnitude;
planetMass.angularVelocity = new Vector3(0, 0.1f, 0);
Ship mil = new Ship("Player", shipCoords);
ships.Add(mil);

mil.mass.AddForce(shipThrust, ForceMode.Impulse);
foreach (Ship i in ships)
{
i.body.GetComponent().material = shipTexture;
}
//InvokeRepeating("Trail", 0, 0.1f);

StartCoroutine(GetElements());

}

// Drawn behind the ship for a motion trail effect
void Trail()
{
foreach(Ship i in ships)
{
Vector3 tailPos = i.pos.position;
GameObject tail = new GameObject("Tail");
tail.GetComponent().position = tailPos;
tail.GetComponent().localScale = i.pos.localScale * 0.5f;
MeshFilter mFilter = tail.AddComponent();
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
mFilter.mesh = go.GetComponent().mesh;
mFilter.gameObject.AddComponent();
tail.GetComponent().material = shipTexture;
Destroy(go);

}

}

//Uses the orbital elements (and their consituent equations) to determine the orbit of a ship by calculating its position based on a changing True Anomaly
void Predictor()
{
foreach(GameObject o in paths)
{
Destroy(o);
}
paths.Clear();
foreach (Ship i in ships)
{
for(int x = 0; x < 360; x++)
{
// Gets the r value using the equation, but plugs in x for the True Anomaly, so a complete orbit is drawn no matter what the ship's current TA
float r = (i.semaj * (1 - MathF.Pow(i.ecvec.magnitude, 2))) / (1 + i.ecvec.magnitude * MathF.Cos(x * Mathf.Deg2Rad));
Vector3 flatPos = new Vector3(r * MathF.Cos(x * Mathf.Deg2Rad), r * MathF.Sin(x * Mathf.Deg2Rad), 0);

// These rotate the X and Y coordinates so that they fit in 3D space
Quaternion rotationPeriapsis = Quaternion.Euler(0, 0, i.argumentOfPeriapsis * Mathf.Rad2Deg);
Quaternion rotationInclination = Quaternion.Euler(i.inclination * Mathf.Rad2Deg, 0, 0);
Quaternion rotationAscendingNode = Quaternion.Euler(0, 0, i.rAscensionNode * Mathf.Rad2Deg);

// Combine the rotations. The order of multiplication matters.
Quaternion totalRotation = rotationAscendingNode * rotationInclination * rotationPeriapsis * Quaternion.Euler(90, 0, 0);

// Apply the rotation to the orbital position
Vector3 nodePos = totalRotation * flatPos;

// Just creates a cube in each calculated position to make a trajectory.
GameObject orbit = new GameObject("Orbit");
orbit.GetComponent().position = nodePos;
orbit.GetComponent().localScale = i.pos.localScale * 0.5f;
MeshFilter mFilter = orbit.AddComponent();
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
mFilter.mesh = go.GetComponent().mesh;
mFilter.gameObject.AddComponent();
orbit.GetComponent().material = shipTexture;
Destroy(go);
paths.Add(orbit);
}

}
}

// Update is called once per frame
void FixedUpdate()
{
foreach(Ship i in ships)
{
// Calculates every value needed to then create all six orbital elements to determine orbital position
i.gnd = MathF.Abs(i.pos.position.magnitude) - (size / 2);
i.spam = Equations.SpecificAngularMomentum(i.pos.position, i.mass.linearVelocity);
i.novec = Equations.NodeVector(i.spam);
i.std = Equations.StandardGravParam(gravity, central.GetComponent().mass, i.mass.mass);
i.ecvec = Equations.EccentricityVector(i.pos.position, i.mass.linearVelocity, i.spam, i.std);
i.smen = Equations.SpecialMechanicalEnergy(i.mass.linearVelocity, i.pos.position, i.std);
i.semaj = Equations.SemiMajorAxis(i.std, i.smen);
i.inclination = Equations.Inclination(i.spam);
i.rAscensionNode = Equations.RightAscendingNode(i.novec);
i.argumentOfPeriapsis = Equations.ArgumentOfPeriapsis(i.novec, i.ecvec);
i.trueAnomaly = Equations.TrueAnomaly(i.ecvec, i.pos.position);
i.mass.AddForce(i.pos.position * -1 * Equations.Gravity(i.pos, planetMass, i.mass, gravity), ForceMode.Force);
i.pos.eulerAngles = i.mass.linearVelocity;

// Used to change the orbit while game is running. Found other problems when doing this
if (Input.GetKeyDown("space"))
{
i.mass.AddForce(0, -50, 0, ForceMode.Impulse);
}

}
}
}
< /code>
Если я запускаю орбиту только с правой стороны планеты (1200, 0, 0), любая орбита работает (за исключением орбиты, которая идеально соответствует экватору, для какая -то причина). < /p>
(почти) экваториальная орбита:

45 градусов орбита:

Полярные орбиты:

Ретроградные орбиты:

etc.
Но когда я Запустите корабль с любой другой позиции (что угодно, что угодно, что угодно), предсказанная орбита совершенно неверна. < /p>
Начиная с любой координаты z:


Начиная с любой координаты y:


Нажатие места в режиме игры раскрывает те же проблемы.
Я наблюдаю за орбитами Оставаясь в режиме редактора, когда начинается игра. < /p>
Я действительно просто не понимаю, как продолжить. Я уже не орбитальный физик. Я просто не могу обернуть голову вокруг того, что вызывает эту проблему.

Подробнее здесь: https://stackoverflow.com/questions/794 ... pecific-si
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»