空间与物体运动——实现一个太阳系

 

了解游戏对象运动的本质

首先通过初步学习,可以了解到我们在Unity中创建的物体,都会带有Transfrom的部件,其中包含了PositionRotationScale三个主要部分。而实际上物体的运动就是改变这三个状态,使其能够平移、旋转、缩放,以及这三种运动的组合。构成游戏对象所有运动的基础。还有一种理解,就是通过矩阵变换,使得物体空间属性发生变化,这就是对象运动的本质。

实现物体简单运动

用三种不同方法,实现物体的抛物线运动

  1. 使用改变position方法,直接将position加上一个三维向量,得到的就是一个新的position。其中模拟的是抛物线运动,在y轴有一个加速度,所以用了s = v 0 t + 1 2 a t 2 s=v_0t + \frac{1}{2}at^2s=v0​t+21​at2的公式计算每一步长移动的距离,由于是向下运动,所以要加上负号。由于我们计算的是每一小段时间内的物体位移的增量,所以要记录每一个时段开始(也就是上一个时段结束时)物体的初速度v 2 v_2v2​。
public class Parabolic : MonoBehaviour
{
    // Start is called before the first frame update
    public float v = 0.5f;
    public float v2 = 0;
    const float a = 9.8f;
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.position += new Vector3(v*Time.deltaTime, (float)(-v2*Time.deltaTime-0.5*g*(Time.deltaTime)*(Time.deltaTime)), 0);
        v2 += g * Time.deltaTime;
    }
}
  •  
  1. 使用transform的Translate方法(由于代码大体相同,所以只写出关键部分,即使用函数不同)
void Update()
{
	this.transform.Translate(new Vector3(v*Time.deltaTime, (float)(-v2*Time.deltaTime-0.5*g*(Time.deltaTime)*(Time.deltaTime)), 0));
	v2 += g * Time.deltaTime;
}
  •  

3.使用 SetPositionAndRotation函数
使用此函数就需要计算得到物体最后时刻的位置,而不能简单的相加。由于我们设置物体y方向上初速度为0,所以运动的总距离就是y 0 − 1 2 a t 2 y_0-\frac{1}{2}at^2y0​−21​at2
先保存原来的y坐标为y 0 y_0y0​,在这个基础上,在y方向作匀加速运动,再计算出坐标。而总时间的话要累积加上每次Update的时间。

void Update()
    {   
        this.transform.SetPositionAndRotation(new Vector3(v*t, origin_y - (float)(0.5*g*t*t), 10), this.transform.rotation);
        t += Time.deltaTime;
    }
  •  

简单太阳系制作

首先创建一堆球体,按照一定的比例改变他们的大小,并且给它们重命名。(这里没有使用真实比例,只是粗略的体现哪个行星比较大,因为按照真实比例的话,有的行星可能在场景中小得看不见了),然后将它们拖到太阳对象中,作为子物体:
在这里插入图片描述
调整它们的相对位置,使其距离太阳的轨道距离不同。
然后到网上寻找各个行星的贴图,并且把他们拖到对应的球体上,形成材料。
在这里插入图片描述
在这里插入图片描述
成品如下:
在这里插入图片描述
然后每个球体都可以绕太阳旋转,所以编写一个简单脚本,让其绕太阳运动。
这里用到的是老师上课讲到的Quaternion以及欧拉角的应用,根据旋转角度以及旋转轴来改变物体的位置。

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

public class Rotate : MonoBehaviour
{
    public int speed = 10;
    public Vector3 e;
    float ry, rx;
    // Start is called before the first frame update
    void Start()
    {
        // 随机生成法向量,使x尽可能小于y,即旋转轴基于y轴偏一点点
        rx = Random.Range(1,5);
        ry = Random.Range(10, 30);
        e = new Vector3(rx, ry, 0);
    }
    // Update is called once per frame
    void Update()
    {
        // 按照一定速度,生成旋转变换的四元组(类似矩阵变换)
        Quaternion q = Quaternion.AngleAxis(speed * Time.deltaTime, e);
        // 由于是太阳的子物体,所以可以指改变相对位置即可,防止太阳不在原点
        // 也可以通过相对坐标和绝对坐标的转换,不过比较麻烦
        this.transform.localPosition = q * this.transform.localPosition;
    }
}
  •  

将脚本拖到每个球体的部件中,更改相应的速度参数:
在这里插入图片描述
这样就基本实现了旋转运动。(对于月亮与地球关系也是一样,由于月亮也是地球的子物体,所以不需要特别更改)

一点美化

将摄像头(Camera)的Clear Flag改成solid color,然后把背景颜色改为黑色或者比较深的颜色(当然也可以使用Skybox,只要有合适的素材),这样游戏场景看上去就比较像星空的黑色(尽管只有几个球)。
在这里插入图片描述
除了场景中的平行光之外,还可以增加太阳本身的光源,在太阳的Inseptor里增加,Light部件,调整为点光源,并且设置颜色以及强度(Intensity):
在这里插入图片描述
这样得到的效果就是行星面向太阳的一面为比较亮,但是由于场景中有平行光的存在,另一面又不至于全暗,看起来比较适合。效果如下:
在这里插入图片描述
然后为了证明行星转动轨迹不在同一个法平面上,我们可以添加轨迹来观察,给每个行星Inseptor中添加Trail Renderer,调整宽度不要太大,还能改变轨道颜色,不过好像不能通过Color来改变,只能通过material来改变颜色。还有轨道记录时间(Time)尽可能调大,让行星轨迹能够绕一周。设置如下:
在这里插入图片描述

完成之后就可以开始测试,效果如下:
在这里插入图片描述
动态如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40552127/article/details/112784790