了解游戏对象运动的本质
首先通过初步学习,可以了解到我们在Unity中创建的物体,都会带有Transfrom的部件,其中包含了Position,Rotation,Scale三个主要部分。而实际上物体的运动就是改变这三个状态,使其能够平移、旋转、缩放,以及这三种运动的组合。构成游戏对象所有运动的基础。还有一种理解,就是通过矩阵变换,使得物体空间属性发生变化,这就是对象运动的本质。
实现物体简单运动
用三种不同方法,实现物体的抛物线运动
- 使用改变position方法,直接将position加上一个三维向量,得到的就是一个新的position。其中模拟的是抛物线运动,在y轴有一个加速度,所以用了s = v 0 t + 1 2 a t 2 s=v_0t + \frac{1}{2}at^2s=v0t+21at2的公式计算每一步长移动的距离,由于是向下运动,所以要加上负号。由于我们计算的是每一小段时间内的物体位移的增量,所以要记录每一个时段开始(也就是上一个时段结束时)物体的初速度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;
}
}
- 使用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−21at2
先保存原来的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)尽可能调大,让行星轨迹能够绕一周。设置如下:
完成之后就可以开始测试,效果如下:
动态如下: