位置布局
一般来说,新建的有关场景位置等,都要先进行位置初始化操作,子对象的布局是相对于父对象的。
Main Camera
MainCamera有两种主要的Projection,分别是Perspective(透视的)和Othpgraphic(正交的)。透视形式会有适当的缩放,适合3D建模;正交形式是视角是平直的,适合2D建模(暂时这么认为,可能不太准确)。本次项目使用2D形式。
光线处理
删除默认的光源,根据实际的需求添加自己的光线。游戏的光线处理很重要。
背景
背景是PrimitiveType.Quad类型,该类型本质上是一个枚举类型。
Sphere A sphere primitive.
Capsule A capsule primitive.
Cylinder A cylinder primitive.
Cube A cube primitive.
Plane A plane primitive.
Quad A Quad primitive.
背景一般使用这种类型,它们构成环境的最基本的要素。。。。
MeshRender
用于构成物体的表面,是一个可视化物体必须有的Component(组件),像光线材料等都必须至于该组件上面。
MeshFilter
可以视为一个物体的基本结构,也是必须的,一个Object假设是Quad,那么它的MesFilter就是QUad。
本项目中使用quad
承载背景图片,直接拖拽材料到quad上,自动进行填充。
由于使用了Othographic类型的摄像机,因此背景向下移动10.
Player的处理和渲染
新建一个空的GameObject,然后拖拽预制的飞船组件,构成一个Player。
添加RigidBody,把该Object交给物理引擎处理,同时去掉Gravity和Is Kinematic,前者是去掉重力,后者运动选项如果选择了,就没法进行处理了。
添加MeshCollider,这是Collider的一个子类,用于碰撞检测。选择Convex,会自动包围物体表面。包围表面的处理会消耗计算资源,但是这是一个小型的游戏,忽略这一点。选择IsTrigger选项,否则不会触发事件。
添加一个EnginePlayer的空对象作为该Player的子对象,放在飞船的尾部,这是用于给尾喷火焰定位的用的;同样的,使用一个名为Shot Spawn 的空对象放在头部,用于给发射武器定位。 这种方式在游戏中经常用到。
Boundary游戏边界
该类型主要是后期处理飞出游戏边界的物体,让他们自动销毁用的。
Asteroid陨石的Prefabs(预制件)
由于要产生多个陨石,在这里需要使用Prefabs预制件的方式。直接拖入预制的Models即可。
Asteroid因为有动力学的属性,所以要添加RigidBody的组件。同样的,去掉Gravity和Is Kinematic属性。
因为需要进行碰撞处理,所以要添加一个Collider组件。在这里,没有使用Mesh Render,陨石太多,而且没有必要。使用Capsule Collider,自动调整到适合陨石的形状即可,打开IsTrigger属性。
Bolt激光的Prefabs(预制件)
和陨石的基本类似,添加一个己方的Models即可。注意,一点,我们的激光是放在一个方形上的,为了使得背景透明,需要在shader选项上改成Practles/additive类型。
RigidBody的与速度有关的属性
velocity
:这是一个Vector3
类型的属性,代表了当前物体的3维矢量。angularVelocity
:物体的角速度,一般不能主动更改,不过在需要物体随机旋转时,需要改动这个数值。该游戏中,陨石的随机旋转就使用了该属性
Instantiate类
Instantiate
类用于实例化一个具体的GameObject,这和直接在编辑框图中拖入一个对象的方法是一样的。主要的作用是在代码逻辑中添加实例化的游戏对象,也可以给定初始化的状态。
public static Object Instantiate(Object original);
public static Object Instantiate(Object original, Transform parent);
public static Object Instantiate(Object original, Transform parent, bool instantiateInWorldSpace);
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
Random随机数
public static Vector3 insideUnitSphere
:返回半径时1的球状物体内部的一个随机的点。本例中这个结合angularVelocity
共同产生随机旋转Random.rotation
:产生一个随机旋转
Mathf数学库
固定数值的函数Clamp
,用于固定value的范围,并返回value。如果value超过边界,那么就返回边界。
public static float Clamp(float value, float min, float max);
Quaternion 旋转组件
该类用于代表Unity的GameObject的旋转。我们一般把该组件用于现有的GameObject上,并产生想要的旋转。
几个常用的函数
public static Quaternion Euler(float x, float y, float z)
:围绕坐标轴产生旋转,并返回一个rotation的对象给一个GameObject。该游戏中,使用了该函数,使得飞船可以左右倾斜。public static float Angle(Quaternion a, Quaternion b)
:返回两个旋转之间的夹角。public static Quaternion Slerp(Quaternion a, Quaternion b, float t)
:a、b之间的球状插值, .public static Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up)
:LookRotation的含义就是,计算让Z轴对齐forward,让y轴对齐upward 所需要的旋转四元数。比如汽车爬坡时,需要使得汽车和坡度一致,因此需要使用该方法。public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection)
:创造一个从fromDirection到toDirection的旋转。public static Quaternion identity
:这是一个属性,用于校正方位,和现实世界一致或者和父对象一致。
MonoBehaviour启动协程
StartCoroutine
函数用于启动一个协程。这类似于Golang中的协程。一个协程视为一个更加轻量级的线程。一个协程可以在任何时候使用yeild
方式进行暂停,这类似于python中yeild
关键字。如果一个动作要在几帧之后完成,那么使用协程将会是比较好的方式。因为常规的暂停会暂停掉整个游戏,而协程可以仅仅暂停当前的某个游戏对象或者场景。如果有多个协程同时进行暂停和重启,那么它们的顺序是不确定的。
启动方式:
public Coroutine StartCoroutine(IEnumerator routine);
IEnumerator
是代表协程编号的一个特定数据类型,返回的是一个协程。
在这个项目中,使用协程的方式进行陨石批次的暂停控制。一般在游戏中,也是使用这种方式产生不同批次的游戏对象。
使用例子:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour {
public GameObject hazard;
public Vector3 spawnValues;
public int hazardCounts;
public float spawnWait;
public float spawnStart;
public float waveWait;
// Use this for initialization
void Start() {
StartCoroutine(SpawnWaves());
}
IEnumerator SpawnWaves() {
yield return new WaitForSeconds(spawnStart);
while (true) {
for (int i = 0 ; i < hazardCounts ; ++i) {
// 随机的顶部位置产生陨石
Vector3 spawnPositon = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity; // 与场景的位置旋转同步
Instantiate(hazard, spawnPositon, spawnRotation);
yield return new WaitForSeconds(spawnWait); // 单个陨石产生的时间间隔
}
yield return new WaitForSeconds(waveWait); // 一个批次陨石产生的时间间隔
}
}
}
游戏碰撞的使用方式
MonoBehaviour.OnTriggerEnter(Collider)
在游行中,如果飞船和陨石发生碰撞,那么就触发这个函数。同时销毁碰撞的对象,给陨石添加即可,不过注意忽略边界的tag,否则会立刻消失。
游戏边界的使用技巧
因为有很多陨石或者激光元素会飞出游戏边界,如果不进行释放,会占用过多的资源。在这里使用:
MonoBehaviour.OnTriggerExit(Collider)
函数进行销毁。该函数在两个Collider对象离开接触面后进行触发。在该项目中,添加一个Collider对象,作为边界框,当陨石或者激光离开边界后,自动进行销毁处理。