Unity学习笔记(3)-----制作一个仿真星系(复杂版)【Step1】

来源:互联网 发布:淘宝怎么设置延长收货 编辑:程序博客网 时间:2024/06/05 04:45

继续学习Unity3D  这周任务之一是要做一个太阳系,如下图:


而这次笔记的重点不在作业上~.~, 而是在于如何建立一个, 真正意义上的  “星系”。

上过课都知道, 作业简单用以下两条语句即可搞定:

Planet.gameObject.transform.RotateAround();Planet.gameObject.transform.Rotate();

 然而这样做并没有实现真的仿真, 因为:

1. 轨道只能是圆的..... 而大部分星球轨道不可能完全是圆, 只是有些轨道离心率略低看起来像是圆罢了。。。

2. 凭感觉(因为高中物理忘得差不多了), 这样弄出来的各个星球的转速放在同一个中心天体的星系中可能会违反物理规律.....

3. 用的物理模型本身就不符 ~。~  Rotate只有旋转而已, 不能体现各个星球之间对各自轨道的影响


------------------------------------装逼与正文分割线-----------------------------------------


所以第一个问题, 就是如何建立一个引力场。

我们知道每个星球都有引力, 而且引力范围是无限的。各个天体之间的引力由万有引力公式给出

那么, 首先我们新建一个 Sphere 物体, Reset其位置, 当做中心天体。

然后, 给这个物体添加Rigidbody属性, 这是为了给此对象添加物理事件, 比如我们需要的引力, 碰撞等......

将其做成一个预设, 放在Resources/Prefabs 中。(文件夹名字一定要是Resources里啊, 不然之后没法加载...)

当然保存Scene也是习惯了, 还有一些琐碎操作, 什么调摄像机镜头到合适角度啊,设定物体Scale和Mass啊之类的, 合理就行。

放一个我设置的图:(Rotation那里忽略, 设置为0就好! 这图是我在仿真过程中随手截的, 等下会解释这个)



然后就是添加一个Script脚本, 实现引力效果。

要实现引力, 大致可以分为以下几个步骤:

  1. 设置一个引力范围。
  2. 选定在引力范围内的所有天体。
  3. 给每个天体都加一个来自此对象的力(即指向此对象), 力的大小由万有引力公式决定。
对应代码如下:
void KeepUniversalG() {var Center = this.transform.position;Collider[] colliders = Physics.OverlapSphere (Center, GalaxyRange);foreach (Collider obj in colliders) {Rigidbody rb = obj.GetComponent<Rigidbody> ();if (rb != null)rb.AddExplosionForce (-1 * UniversalG(this.gameObject, obj.gameObject) * Time.deltaTime, Center, GalaxyRange);}}
没高亮?.... 好伤啊。
API就不多解释了, 大概从名字和参数都看得懂是干啥。 就说一句:
AddExplosionForce(...);
这个从名字看是实现从某物体发出的产生爆炸力的作用效果, 但是注意在参数设定Force那里*-1, 改变力的方向不就是引力了么(~。~)
PS: 开始没注意说明: GalaxyRange是类的一个private float, 自己设定参数值就好, 表示的是星系引力作用范围。  UniversalG是计算力的大小的函数。 等下具体解释, 先直接建一个函数在里面写return 某个值就好(先看效果嘛)。
然后把这函数放进FixedUpdate里就行了。
现在你在地图上中心天梯附近随便建几个Sphere, 能看到明显的引力效果。(建议用中心天体的Prefab, 不用自己一个个加Rigidbody和挂载这个脚本)

接下来要考虑的就是怎么让它们绕着中心天体转而不是直接黏上去了。
----------------------------------高中物理势力登场----------------------------
物体 之所以会绕着天体旋转, 一是有一个合适初始速度, 二是受到一个始终与速度方向垂直(或近似垂直)的力。
引力为我们解决了第二点, 现在只要解决第一点即可。 而之后我们会看到, 这第一点其实并不容易。 它对于建立一个能够维持稳定的星系具有很重要的影响。
然而我们先从最简单的开始。 由于要做较多的简化, 所以这次直接先贴代码了...

void Start () {var Center = this.transform.position;InitialForce = ProperForce (this.gameObject);this.gameObject.GetComponent<Rigidbody> ().AddForce (InitialForce * ProperDirect(Center));}

复杂就复杂在ProperForce和ProperDirect两函数得写出来。 这个之后再管什么“proper”, 首先我们要的是效果, 效果! 所以。。。Force值随便自己建一个函数设一个return值就好,  ProperDirect只要保证两点就可以:
1. 当传入参数为(0,0,0)时(即中心天体位置), 返回的也是Vecter3.zero。
2. 对于其他传入参数, 保证返回的向量与传入的向量方向垂直。即 存在关系:

Center * ProperDirect(Center) == 0 //这里指向量点乘。

以上工作做完, 保存脚本, 看看效果。 

这时候的效果应该不是太好, 原因如下:

1.参数乱设的。 2. 天体不美观。 3.轨道很难观察  4. 可能还有Bug、、、(这是最气的)

鉴于写到这里我发现还有很多没写,, 我还是另写一篇做下文吧, 不然太长了。

先发下成品效果图。。

懒得发动图了, 角度也懒得换了。。。 反正自己看着还挺不错。




0 0
原创粉丝点击