unity学习2——基于物理模拟的太阳系模型

游戏对象运动的本质是什么?
游戏对象的运动,在本质上是在离散的时间点上,物体按照物理引擎说运算出的,呈现出不同的位置。

请用三种方法以上方法,实现物体的抛物线运动。(如,修改Transform属性,使用向量Vector3的方法…)
方法一:矢量叠加法
众所周知,一个抛物运动由水平方向的匀速和竖直方向的匀加速运动构成。
方法二:collider 的gravity 模拟
类似于上面,但云加速运动部分采用collider组件自带的gravity功能。
方法三:transform.position 描述表达式法

写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。


实现思路:利用transform的rotate、lookat、等方法,看上去像但并不真实的模拟出太阳系的运动。
另一种实现思路:使用万有引力定律和牛顿第二运动定律,列出物体动力学方程。

第二种方法的优点:可以模拟出水星的章动(椭圆周期运动上叠加小周期简谐振动)、各行星的椭圆轨道、冥王星和海王星的引力影响轨道。 unity学习2——基于物理模拟的太阳系模型_第1张图片

引力模拟代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GravitySimulate : MonoBehaviour {
    public List graviEffectWith;
    public Vector3 TotalGravitationalForce;
	// Use this for initialization
	void Start () {
    //    this.GetComponent().speed=startsetspeed();
	}
	public Vector3 startsetspeed()
    {
        this.GetComponent().speed.z = Mathf.Sqrt(graviEffectWith[0].GetComponent().mass /
    Vector3.Distance(this.transform.position, graviEffectWith[0].transform.position)
    );
        return new Vector3(0, 0, this.GetComponent().speed.z);
    }
    public void setSpeed(Vector3 input)
    {
        this.GetComponent().speed = input;
    }
	// Update is called once per frame
	void FixedUpdate () {
        TotalGravitationalForce.Set(0, 0, 0);
        foreach (GameObject i in graviEffectWith)
        {

            TotalGravitationalForce += -(i.GetComponent().mass) /
                (Vector3.Distance(this.transform.position, i.transform.position) * Vector3.Distance(this.transform.position, i.transform.position) * Vector3.Distance(this.transform.position, i.transform.position))
                * (this.transform.position - i.transform.position);
        }
        this.GetComponent().speed += TotalGravitationalForce*Time.deltaTime;
        this.transform.position+=(this.GetComponent().speed)*Time.deltaTime;
	}
}

我们可以看到,简单的使用牛顿第二定律就可以画出真实的椭圆轨道。
然后我们用一个PhysicalModel组件存储一些物理数据,此处略过
在gameController里,我们储存了九大行星的数据(重点是距离、黄道交角)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SolarController : MonoBehaviour {
    public GameObject SunPrefabs;
    public GameObject Sun;
    public GameObject[] SolarPlanetPrefabs;
    public GameObject[] SolarPlanet;

    public GameObject MoonPrefab;
    public GameObject Moon;
    Quaternion q;
    // Use this for initialization
    void Awake () {
        SolarPlanet = new GameObject[9];
        Sun = GameObject.Instantiate(SunPrefabs);
        for (int i=0; i < SolarPlanetPrefabs.Length; ++i)
        {
            SolarPlanet[i] = GameObject.Instantiate(SolarPlanetPrefabs[i]);
            SolarPlanet[i].GetComponent().graviEffectWith.Add(Sun);
        //    SolarPlanet[i].GetComponent().startsetspeed();
        }
        /*此处初始化行星*/
        SolarPlanet[0].GetComponent().SetPara(0.0553f,0.383f,3.87f);//质量半径距离
        SolarPlanet[1].GetComponent().SetPara(0.815f,0.950f,7.23f);
        SolarPlanet[2].GetComponent().SetPara(1,1,10);
        SolarPlanet[3].GetComponent().SetPara(0.107f, 0.532f, 15.24f);


     //   SolarPlanet[4].GetComponent().SetPara(95.159f,9.14f,52.03f);
       // SolarPlanet[5].GetComponent().SetPara(317.83f,10.97f,95.39f);
     //   SolarPlanet[6].GetComponent().SetPara(14.536f,3.98f,191.8f);
        //Sun.GetComponent().SetPara(332837f, 109.25f, 0);
        Sun.GetComponent().SetPara(33237f, 10.25f, 0);

        /*下面设定初始速度*/
        for (int i = 0; i < SolarPlanetPrefabs.Length; ++i)
        {
            SolarPlanet[i].GetComponent().setSpeed(planetspeed(i));
            SolarPlanet[i].GetComponent().setRotateAxis(selfrotateAxis(i));
        }


        /*下面设定月球相关*/
        Moon = Instantiate(MoonPrefab);
        Moon.GetComponent().graviEffectWith.Add(SolarPlanet[2]);
        Moon.GetComponent().graviEffectWith.Add(Sun);
        SolarPlanet[2].GetComponent().graviEffectWith.Add(Moon);
        Moon.GetComponent().GetComponent().SetPara(0.18f, 0.1f, 10 + 0.0256f);
        Moon.GetComponent().setSpeed(Moon.GetComponent().startsetspeed()+SolarPlanet[2].GetComponent().startsetspeed());




    }
	Vector3 planetspeed(int index)//这个函数用来存储各种行星的初始速度
    {
        Vector3 theplanetspeed=SolarPlanet[index].GetComponent().startsetspeed();

        switch (index)
        {
            case 0:
                q = Quaternion.AngleAxis(7.01f,new Vector3(1,0,0));
                break;
            case 1:
                q = Quaternion.AngleAxis(3.39f, new Vector3(1, 0, 0));
                break;
            case 2:
                q = Quaternion.AngleAxis(0.00f, new Vector3(1, 0, 0));
                break;
            case 3:
                q = Quaternion.AngleAxis(1.85f, new Vector3(1, 0, 0));
                break;
            case 4:
                q = Quaternion.AngleAxis(1.31f, new Vector3(1, 0, 0));
                break;
            case 5:
                q = Quaternion.AngleAxis(2.49f, new Vector3(1, 0, 0));
                break;
            case 6:
                q = Quaternion.AngleAxis(0.77f, new Vector3(1, 0, 0));
                break;
            case 7:
                q = Quaternion.AngleAxis(1.77f, new Vector3(1, 0, 0));
                break;
            case 8:
                q = Quaternion.AngleAxis(1.85f, new Vector3(1, 0, 0));
                break;
        }
        Debug.Log(q * theplanetspeed);
        return (q*theplanetspeed);
    }

    Vector3 selfrotateAxis(int index)//这个函数用来存储各种行星的初始自传角
    {
        

        switch (index)
        {
            case 0:
                q = Quaternion.AngleAxis(28f, new Vector3(1, 0, 0));
                break;
            case 1:
                q = Quaternion.AngleAxis(177f, new Vector3(1, 0, 0));
                break;
            case 2:
                q = Quaternion.AngleAxis(23.45f, new Vector3(1, 0, 0));
                break;
            case 3:
                q = Quaternion.AngleAxis(23.98f, new Vector3(1, 0, 0));
                break;
            case 4:
                q = Quaternion.AngleAxis(3.08f, new Vector3(1, 0, 0));
                break;
            case 5:
                q = Quaternion.AngleAxis(26.73f, new Vector3(1, 0, 0));
                break;
            case 6:
                q = Quaternion.AngleAxis(97.92f, new Vector3(1, 0, 0));
                break;
            case 7:
                q = Quaternion.AngleAxis(28.8f, new Vector3(1, 0, 0));
                break;
            case 8:
                q = Quaternion.AngleAxis(1.85f, new Vector3(1, 0, 0));
                break;
        }
        Debug.Log(q * new Vector3(0, 1, 0));
        return (q * new Vector3(0,1,0));
    }

    
}
在处理黄道交角时,我们用到了四元数与矩阵的积。高中物理知识告诉我们,调节物体的初速度就可以控制这个行星轨道的一切形状。比如,在黄道面上初速度不沿同心圆切线,那么这是个椭圆轨道。如果有垂直于黄道面的分速度,那么这个轨道将和黄道面异面!!!!

接下来还做了行星的自转,但有些bug,就先不放上来了

这个项目我会持续完善的,下一步时添加所有的行星、小行星带

项目地址:https://github.com/kotomineshiki/cosmos.git


你可能感兴趣的:(unity)