【Unity】Mathd系列(一)Double型Vector2

本文探讨了在Unity中使用float型Vector2时遇到的精度问题,并介绍了为解决这一问题自定义的Double型Vector2结构体,详细阐述了其实现和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    由于Unity中的向量用的都是float型去存储,而float型的精度只有五位小数,导致了前段时间做项目的时候出现了精度上的问题。当时重新写了一个简单的类去解决它,过后觉得以后还有可能还会遇到类似的问题,于是系统的写了一下Unity中的几个结构体。

首先是Vector2d:

/// Vector2d.cs
/// 
/// The double type version of the Unity struct Vector2.
/// It can solve the problem that the float type may not be accurate enough.
/// 
/// Unity Vector2结构体的double版实现,以解决float型精度可能不够的问题。
/// 
/// Created by D子宇 on 2018.3.17 
/// 
/// Email: darkziyu@126.com
using System;
using UnityEngine;

namespace Mathd
{
    public struct Vector2d
    {
        #region public members

        public double x;
        public double y;

        #endregion

        #region constructor

        public Vector2d(double p_x,double p_y) {
            x = p_x;
            y = p_y;
        }

        #endregion

        #region public properties

        public double this[int index]
        {
            get
            {
                switch (index)
                {
                    case 0:
                        return x;
                    case 1:
                        return y;
                    default:
                        throw new IndexOutOfRangeException("Invalid Vector2d index!");
                }
            }
            set
            {
                switch (index)
                {
                    case 0:
                        x = value;
                        break;
                    case 1:
                        y = value;
                        break;
                    default:
                        throw new IndexOutOfRangeException("Invalid Vector2d index!");
                }
            }
        }

        public static Vector2d down
        {
            get
            {
                return new Vector2d(0, -1);
            }
        }
        public static Vector2d left
        {
            get
            {
                return new Vector2d(-1, 0);
            }
        }
        public static Vector2d one
        {
            get
            {
                return new Vector2d(1, 1);
            }
        }
        public static Vector2d right
        {
            get
            {
                return new Vector2d(1, 0);
            }
        }
        public static Vector2d up
        {
            get
            {
                return new Vector2d(0, 1);
            }
        }
        public static Vector2d zero
        {
            get
            {
                return new Vector2d(0, 0);

            }
        }
        public double magnitude
        {
            get
            {
                return Math.Sqrt(sqrMagnitude);
            }
        }
        public Vect
好的,下面是个简单的卫星轨道控制的代码示例,使用 C# 语言在 Unity 引擎中实现,坐标系采用 J2000 坐标系。 首先,我们需要定义个表示卫星轨道的数据结构,包括半长轴、偏心率、倾角、近地点角度、升交点赤经和真近点角等参数。代码如下: ``` public class Orbit { public double semiMajorAxis; // 半长轴 public double eccentricity; // 偏心率 public double inclination; // 倾角 public double argOfPeriapsis; // 近地点角度 public double raan; // 升交点赤经 public double trueAnomaly; // 真近点角 } ``` 接下来,我们需要编写卫星轨道计算的函数,根据所给轨道参数计算卫星在 J2000 坐标系下的位置和速度。这里我们采用 Kepler 方程求解的方法。代码如下: ``` public static Vector3d CalculatePosition(Orbit orbit, double time) { double mu = 3.986004418e14; // 地球引力常数 double n = Math.Sqrt(mu / Math.Pow(orbit.semiMajorAxis, 3)); // 平均角速度 double E = EccentricAnomaly(orbit, time, n); // 求解偏近点角 double cosE = Math.Cos(E); double sinE = Math.Sin(E); double p = orbit.semiMajorAxis * (1 - Math.Pow(orbit.eccentricity, 2)); // 焦距 double r = p / (1 + orbit.eccentricity * cosE); // 距离 double cosv = (cosE - orbit.eccentricity) / (1 - orbit.eccentricity * cosE); double sinv = Math.Sqrt(1 - Math.Pow(orbit.eccentricity, 2)) * sinE / (1 - orbit.eccentricity * cosE); double x = r * (Math.Cos(orbit.raan) * Math.Cos(orbit.argOfPeriapsis + orbit.trueAnomaly) - Math.Sin(orbit.raan) * Math.Sin(orbit.argOfPeriapsis + orbit.trueAnomaly) * Math.Cos(orbit.inclination)); double y = r * (Math.Sin(orbit.raan) * Math.Cos(orbit.argOfPeriapsis + orbit.trueAnomaly) + Math.Cos(orbit.raan) * Math.Sin(orbit.argOfPeriapsis + orbit.trueAnomaly) * Math.Cos(orbit.inclination)); double z = r * Math.Sin(orbit.argOfPeriapsis + orbit.trueAnomaly) * Math.Sin(orbit.inclination); return new Vector3d(x, y, z); } // 求解偏近点角 public static double EccentricAnomaly(Orbit orbit, double time, double n) { double t0 = 0; // 初始时刻 double M = n * (time - t0); // 平均近点角 double E = M; // 初始偏近点角 double deltaE = 1; double tol = 1e-8; // 迭代精度 while (deltaE > tol) { double f = E - orbit.eccentricity * Math.Sin(E) - M; double fp = 1 - orbit.eccentricity * Math.Cos(E); deltaE = -f / fp; E += deltaE; } return E; } ``` 最后,我们需要实现控制器的控制策略,这里我们采用简单的 PID 控制器。代码如下: ``` public class SatelliteController : MonoBehaviour { public Orbit orbit; // 卫星轨道参数 public double thrust; // 推力 public double kp, ki, kd; // PID 控制器参数 private Vector3d targetPosition, targetVelocity; // 目标位置和速度 private Vector3d errorSum, lastError; // 误差累积和上次误差 void Start() { targetPosition = CalculatePosition(orbit, 0); // 初始目标位置 targetVelocity = Vector3d.zero; // 初始目标速度 errorSum = Vector3d.zero; // 初始误差累积和 lastError = Vector3d.zero; // 初始上次误差 } void Update() { Vector3d position = CalculatePosition(orbit, Time.time); // 当前位置 Vector3d velocity = (CalculatePosition(orbit, Time.time + 0.1) - CalculatePosition(orbit, Time.time - 0.1)) / 0.2; // 当前速度 Vector3d error = targetPosition - position; // 位置误差 Vector3d dError = (error - lastError) / Time.deltaTime; // 位置误差变化率 errorSum += error * Time.deltaTime; // 误差累积和 lastError = error; // 更新上次误差 Vector3d control = kp * error + ki * errorSum + kd * dError; // 控制量 Vector3d acceleration = control / GetComponent<Rigidbody>().mass; // 加速度 Vector3d thrustVector = acceleration.normalized * thrust; // 推力向量 GetComponent<Rigidbody>().AddForce(thrustVector); // 施加推力 } } ``` 以上是个简单的卫星轨道控制的代码示例,具体实现还需要根据具体情况进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值