在 Unity入门教程(上) 中咱们建立了一个游戏项目,而且建立了玩家角色和小球这些游戏对象,还经过添加游戏脚本实现了小方块的弹跳。虽然功能比较简单,可是完整地表现了使用Unity开发游戏的大致流程。html
为了让这个游戏变得更加有趣,下面咱们要进一步完善玩家角色和小球的动做。编程
目前小球是静止在空中的,下面咱们来尝试让它朝玩家角色飞去。ide
为了令小球可以模拟物理运动,须要添加Rigidbody组件。同时还须要建立一个Ball的脚本。此操做在Unity入门教程(上)中的步骤十和步骤十一。工具
添加了Ball脚本之后,咱们要对Start方法做以下修改学习
void Start () { this.GetComponent<Rigidbody>().velocity = new Vector3(-8.0f, 8.0f, 0.0f); //设置向左上方的速度 }
游戏开始后,小球将向画面左侧飞去this
为了可以随时建立出小球对象,首先须要对小球对象进行预设。spa
项目视图中将出现Ball项。同时,层级视图中的Ball项文本将会变为蓝色。3d
能够看到场景中会多出一个小球对象。code
预设了游戏对象后,咱们就可以很是容易地建立出多个一样的物体。htm
在项目视图左上角的菜单中点击Create→Folder后,项目视图中将生成一个文件夹,将名字改成Prefabs。
点击Prefabs文件夹,能够看到刚才移动的Ball预设。接着把Player预设和Floor预设也移动到Prefabs文件夹下。
注意在建立前务必先点击项目视图左侧的Assets图标以确保当前文件夹回到Assets。
因为该游戏对象被用做发射台,所以命名为Launcher
小结:如今咱们已经知道在检视面板中也能够添加组件,除此以外,还可使用窗口顶部菜单或者直接拖拽。
除了Update方法有变更以外,还增长了ballPrefab变量。
Instantiate是经过预设生成游戏对象实例的方法。不过脚本中并无对ballPrefab变量进行初始化的代码,因此在游戏运行前必须先在检视面板中对ballPrefab变量赋予预设对象值。
public class Launcher : MonoBehaviour { public GameObject ballPrefab; //小球预设 // Use this for initialization void Start () { } // Update is called once per frame void Update () { if (Input.GetMouseButtonDown(1)) //点击鼠标右键后触发 { Instantiate(this.ballPrefab); //建立ballPrefab的实例 } } }
从项目视图中选择Launcher预设。能够看到在检视面板中的Launcher(Script)标签下显示有Ball Prefab项。脚本代码中声明的全部public成员变量都将在这里列出。
往类中新添加的变量默认表示为None(GameObject),意味着该变量还未被赋值。请将项目视图中的Ball预设拖拽到这里(鼠标左键按着不要松手)。
每次单击鼠标右键时,都会射出一个小球。
这里,为了和预设对象分开,咱们把脚本中经过Instantiate方法生成的游戏对象称为实例,把产生实例的过程称为实例化。
咱们的游戏如今出现了一个Bug:发射出去的小球永远不会消失。
游戏运行时由脚本动态生成的游戏对象也会被显示在层级地图中。每点击一次鼠标,层级视图中都会增长一个Ball(Clone)游戏对象。所以即便小球已经跑出游戏画面以外,这些游戏对象也并未消失。
跑出画面以外的小球不会再回到画面中,因此彻底能够删除。
在脚本Ball.cs中添加OnBecameInvisible方法,该方法能够被添加到Ball类定义范围内的任意位置。
public class Ball : MonoBehaviour { //添加:游戏对象跑出画面外时被调用的方法 void OnBecameInvisible() { Destroy(this.gameObject); //删除游戏对象 } // Use this for initialization void Start () { this.GetComponent<Rigidbody>().velocity = new Vector3(-8.0f, 8.0f, 0.0f); //设置向左上方的速度 } // Update is called once per frame void Update () { } }
OnBecameInvisible方法是在游戏对象移动到画面以外再也不被绘制时被调用的方法。
Destroy(this.gameObject)则是删除游戏对象的方法。
注意:若是把参数设置成this的话,删除的就不是游戏对象,而是Ball脚本组件。
为了防止玩家角色在空中再次起跳,咱们来添加下列处理
修改Player脚本,代码以下:
public class Player : MonoBehaviour { protected float jump_speed = 8.0f; //设置起跳时的速度 public bool is_landing = false; //着陆标记 // Use this for initialization void Start () { this.is_landing = false; } // Update is called once per frame void Update () { if(this.is_landing){ //着陆后触发 if(Input.GetMouseButtonDown(0)){ this.is_landing = false; //将着陆标记设置为false(未着陆 = 在空中) this.GetComponent<Rigidbody>().velocity = Vector3.up * this.jump_speed; } } } //添加:和其余游戏对象发生碰撞时调用的方法 void OnCollisionEnter(Collision collision) { this.is_landing = true; //将着陆标记设置为true(着陆 = 在地面上) } }
当一个游戏对象同其余对象发生碰撞时,OnCollisionEnter方法将被调用。
这是为了检查玩家角色是否着陆而添加的。在该方法中把着陆标记的值设为true。这样玩家角色就不能在空中再次起跳了。
在某种程度上完成了玩家角色和小球的脚本编程后,让咱们来调整各相关参数,以使角色在起跳后能和小球发生碰撞。
这里咱们采用下列值:
其中Freeze Position对于将游戏对象的位置坐标固定在某些方向上,Freeze Rotation则用于固定其角度。
因为咱们但愿玩家角色只上下跳跃而不作左右和先后的移动,所以:
选择项目视图中的Ball预设,打开Rigidbody标签,将Mass项的值由1改成0.01。
Mass项用于设定游戏对象的重量。两个游戏对象发生碰撞时,Mass值较大的物体将保持原速度继续运动,相反Mass值较小的物体则容易因受到冲击而改变移动的方向。
从项目视图的Create菜单中选择Physic Material,建立一个新材质并将其名称改成Ball Physic Material
相对于用来指定颜色等能够看见的属性材质,物理材质则是用于设定弹性系数和摩擦系数等与物理运动相关的属性。
在项目视图中选择Ball Physic Material后,在检视面板中选择Bounciness,将其值由0改成1。这个值越大,游戏对象越容易被“弹开”。
从项目视图中选择Ball预设,接着把Ball Physic Material拖拽到检视面板中Sphere Collider标签下的Material
或者能够点击Ball Physic Material右侧的圆形图标。这时Select Physic Material窗口将被打开,在这个“物理材质选择窗口”中也能够进行选择设定
检视面板中将切换显示PhysicsManager
经过加强重力能够减弱物体在运动时的“漂浮感”,不过跳跃的高度和小球的轨道也显得比原来低了。这种状况下,咱们能够考虑调整为下列数值:
调整角度时需把移动工具切换为旋转工具。
用移动工具调整摄像机的位置
用旋转工具调整摄像机的角度
调整摄像机前:
调整摄像机后:
试玩游戏后,咱们注意到玩家角色和小球碰撞后还能够再次起跳。这多是由于防止空中跳跃的代码存在bug。
跳跃过程当中Is_landing为取消状态(值为false)
着陆后Is_landing为选中状态(值为true)
void Update () { if(this.is_landing){ //着陆后触发 if(Input.GetMouseButtonDown(0)){ this.is_landing = false; //将着陆标记设置为false(未着陆 = 在空中) this.GetComponent<Rigidbody>().velocity = Vector3.up * this.jump_speed; Debug.Break(); } } }
修改后仅添加了Debug.Break方法的调用。在玩家角色起跳时的瞬间暂停游戏的运行。
按下播放控制工具条最右边的按钮,在逐帧模式下能够看到玩家角色在一直上升。在玩家角色和小球碰撞的瞬间,Is_landing的值变成了true。(此处没法截图,见谅)
搞清楚了bug的缘由,接下来就考虑解决bug的对策。
此处咱们能够利用标签。须要对游戏对象的种类进行大体区分时,可使用标签来分组。
添加标签到项目中,在项目视图中选择Floor预设→点击Untagged→点击Add Tag→点击Tags左侧的三角形→点击“+”→输入Floor→再次在项目视图中选择Floor预设→点击Untagged→点击Floor
修改Player.OnCollisionEnter方法。在这里提醒下:记得删除了以前在Player.Update方法中添加的Debug.Break()。
void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Floor") { this.is_landing = true; //将着陆标记设置为true(着陆 = 在地面上) } }
使用了标签后就能够区分碰撞对象了。这样一来就只有在和地面碰撞时,也就是着陆时Is_landing的值才会变为true。
本次有关Unity入门的学习就暂时先告一段落。经过作一个小游戏项目的流程,让我切身体会到使用Unity开发游戏的大体流程,还有遇到Bug时的分析思路。
固然若是想经过一个小游戏的制做就学会Unity的所有技能是不可能的,后期在游戏开发的过程当中,遇到了问题再去查找相应的答案,见招拆招,才是最有效的。