王者荣耀是怎样炼成的(三)unity组件与脚本
2017-09-21 23:58
330 查看
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/73177e7febec6b94cd60e126fdf55f60.png)
转载请注明出处:http://www.cnblogs.com/yuxiuyan/p/7565345.html
上回书说到了unity的基本操作。这回我们来侃侃unity中的组件与脚本。
目录结构
一.组件与脚本简介
二.鼠标与键盘输入
三.使用变换组件移动游戏物体
四.物理组件之刚体
五.物理组件之碰撞体
六.刚体常用方法介绍
七.刚体碰撞事件监测与处理
八.刚体触发事件监测与处理
九.游戏打包与发布
十.入门总结
一.组件与脚本简介
1.组件
组件(Component),顾名思义,就是游戏物体的组成部件。这和我们对现实生活的认识是一致的。就比如说一台主机,是有CPU,显卡,主板,内存条等等组成的。这些部件就是主机的“组件”。这些组件一旦有不满意的,随时可以增删改查。
Unity3D就是一个“组件式”的游戏引擎,它使用各种各样的的组件“拼装”了游戏物体,最终再把游戏物体拼装成游戏。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/dd0825d0f826ebc44d6ed041c9a84122.png)
上图是一个Plane的自带组件。
Unity3D为我们提供了许多种类的组件。后期其实就是各种组件的使用和特性,以及它们能实现的功能和效果。
按照我们老祖宗的理论,五行是组成世界的最基本元素。那么在Unity3D中,组件就是组成游戏世界的最基本元素。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/ea6222ccf648b97bc3c152e2e4fbcec2.png)
我总结出了上面一幅图,这幅图相当重要,大家需要认真看看。因为这涉及到了游戏物体与脚本中类和对象的联系。
2.Transform组件
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/dbb9fc1f4bd2ecc7332b7586581c004e.png)
在这里提一个最最基本的组件之一——Transform组件。
Transform,中文为“变换”,这个组件有三大基本属性,Position(世界位置坐标),Rotation(相对自身坐标系的旋转角度),Scale(相对于初始的缩放比例)。
这个组件是每一个游戏物体都有的属性,并且不能删除。其实想想也是,在现实生活中,只要是一个物体必定有方位、旋转、缩放的属性。
通过修改这三大属性的X\Y\Z值,我们就可以控制物体的“变换”信息了。这里有一个小技巧,当把鼠标放到X\Y\Z上时,鼠标变成了可以左右拖动的标志,可以直接左右拖动改变值,当然直接修改值也是ok的。
3.脚本
脚本(Script),也就是给游戏物体写的代码,用来控制游戏的逻辑。在Unity3D 5.x版本后,只支持C#脚本和JavaScript脚本。在国内开发的主流的C#。4.创建与管理脚本
我们说过,Assets文件夹是总管,所以我们在Assets中新建一个Scripts文件夹,用来管理脚本资源。在Scripts文件夹中右键-->Create-->C# Script。C#脚本文件的后缀是“.cs”。双击脚本文件,可以调用代码编辑器进行编辑。
5.原始脚本代码组成
在上一步我们新建了一个脚本,这次打开它看看究竟是什么东东。![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/0f3061289521b1654e16ea799ec394ff.png)
ok,我们看到这次unity帮我们新建立了一个类,类名就是我们的脚本文件名。然后它继承自MonoBehaviour类,这个类呢,在unity的地位和作用,类似于在java中的Object类,所以重要性不言而喻。有兴趣的童鞋可以去看看这个类的实现。可以看一下这篇文章:http://blog.csdn.net/yuyueliuliu/article/details/43795333。还能看到,这个脚本using了UnityEngine的引擎。然后unity还帮我们写了两个方法Start()和Update()。
Start():当游戏运行起来,这个方法就会马上执行且只执行一次。由此看来,这个方法非常适合做初始化的工作。事实上也是这样的,我们常常在这个方法中做一些GetComponent()的操作。
Update():循环调用,每一帧就调用一次。我大致测了一下,一般的场景大概是每秒60次的样子。
这里还要介绍一个方法:Debug.Log()。这个用来输出调试。如果你的目标是“helloworld”,ok,这个方法正好就是这样。
顺便提一句,Start()和Update()都是unity内部的“事件方法”,不需要我们人工调用,系统会自动调用和管理这些方法的。
6.使用脚本
直接将脚本拖拽到Hiearchy面板的物体上直接将脚本拖拽到物体的Inspector面板上
运行游戏,脚本自动执行。
这是一个first.cs脚本:
using UnityEngine; using System.Collections; public class first : MonoBehaviour { void Start () { Debug.Log("这是Start方法"); } void Update () { Debug.Log("这是Update方法"); } }
把它添加到灯光上,运行游戏,控制台效果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/944bfa1cb77bd8e873ff347b7b76dcee.png)
二.鼠标与键盘输入
上面我们已经知道了C#脚本的大致套路。说到写代码就是各位童鞋的长处了。这次我们实现一下让游戏读出我们的输入。
unity很友好地为我们都写好了方法,我们只需要调用这些接口就ok了。
1.获取键盘输入
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/2e6b09d5199a8ebe62317d8352783dba.png)
案例如下:
using UnityEngine; using System.Collections; public class InputTest : MonoBehaviour { void Update () { if (Input.GetKey(KeyCode.A)) { Debug.Log("按下了A键"); } if (Input.GetKeyDown(KeyCode.A)) { Debug.Log("GetKeyDown"); } if (Input.GetKeyUp(KeyCode.A)) { Debug.Log("GetKeyUp"); } } }
2.获取鼠标输入
直接上方法。![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/5624a660a01642933e507becea97e9d4.png)
用法和监听键盘输入类似,在这里就不再写代码举例了(笑~)。
三.使用变换组件移动游戏物体
上面提到了鼠标键盘监听控制,也提到了Transform组件,我们利用脚本,可以把两者组合起来,实现通过键盘让游戏物体动起来!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/1e1cbe7f9b457068f33ea8509b16b505.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/f20d1a6d4ff65563c89e26e1541e7f16.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/c9d7ee2f7f57cf3a9abfe816a0bcb85c.png)
备注:脚本也可以看成组件,一般是要控制哪个游戏物体就把脚本挂载到哪个物体上。
下面就是一个例子:
using UnityEngine; using System.Collections; public class StudentMove : MonoBehaviour { private Transform trans; // Use this for initialization void Start() { trans = gameObject.GetComponent<Transform>(); } // Update is called once per frame void Update() { if (Input.GetKey(KeyCode.W)) { trans.Translate(Vector3.forward * 0.1f, Space.World); } if (Input.GetKey(KeyCode.A)) { trans.Translate(Vector3.left * 0.1f, Space.World); } if (Input.GetKey(KeyCode.S)) { trans.Translate(Vector3.back * 0.1f, Space.World); } if (Input.GetKey(KeyCode.D)) { trans.Translate(Vector3.right * 0.1f, Space.World); } } }
把这个脚本,拖到游戏物体的Inspector面板上,然后点击游戏的“运行”按钮,可以发现我们已经可以通过键盘的W\A\S\D键控制物体的前左后右的移动了!amazing!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/e69e067e3414c241f8ef4ba2071b9302.png)
[b]四.物理组件之刚体[/b]
在上面我们通过Transform组件实现了物体位置的移动,但是仔细研究一下发现了以下几个特点:
移动的物体会“穿透”场景中其他的物体模型
移动的物体不会受到重力影响(即使到达场景之外,也不会下落)
这样看起来物体动是动了,但是不太真实,和我们现实生活中有很大差别。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/4bbdf164a34aaeece9ab6995f33fa80a.png)
大家应该都听过或者玩过《愤怒的小鸟》,小鸟的抛物线运动,石头的坍塌,都是符合物理规律的。
我们说过,组件是构成游戏物体的基础。所以,我们需要其他组件来使物体符合物理规律。
1.刚体
刚体(Rigidbody),属于物理类组件。添加了刚体组件的游戏物体,就有了重力,就会做自由落体运动,也就实现了现实物体的物理运动。选择游戏物体-->菜单栏点击Componment-->Physics-->Rigidbody,给物体添加刚体组件成功!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/b2b4d928e0dff8e6c0f3ec6be3ea4aae.png)
2.常用属性
看着上图,我们了解一下它的几个常用属性。Mass[质量],可以设置物体的质量,你可以认为单位是KG。
Drag[阻力],一般是指空气阻力,0表示没有空气阻力,空气阻力越大,物体自由落体越慢。当值很大时,物体甚至会停止运动,漂浮在空中。
Angular Drag[角阻力],收到扭曲力时候的空气阻力,0表示没有阻力,当值很大时,物体甚至会停止运动。
Use Gravity[使用重力]。当勾选之后,如果物体掉入场景之外,会落入“深渊”。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/cb658852abdd1c77bdb46208caf13b1d.png)
3.在脚本中使用刚体组件移动游戏物体
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/9ac551693d68899ca9c1e7861afe8c69.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/9707d8bf587994d1ca2523c50b2b43da.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/6027ba36e8e3d674c445e7c8d256040d.png)
直接上脚本:
using UnityEngine; using System.Collections; public class RigidbodyMove : MonoBehaviour { private Transform trans; private Rigidbody rigid; // Use this for initialization void Start() { trans = gameObject.GetComponent<Transform>(); rigid = gameObject.GetComponent<Rigidbody>(); } // Update is called once per frame void Update() { if (Input.GetKey(KeyCode.W)) { rigid.MovePosition(trans.position + Vector3.forward * 0.1f); } if (Input.GetKey(KeyCode.A)) { rigid.MovePosition(trans.position + Vector3.left * 0.1f); } if (Input.GetKey(KeyCode.S)) { rigid.MovePosition(trans.position + Vector3.back * 0.1f); } if (Input.GetKey(KeyCode.D)) { rigid.MovePosition(trans.position + Vector3.right * 0.1f); } } }
代码很简略,但是却实现了像现实物体一样的物理运动,很神奇。
[b]五.物理组件之碰撞体[/b]
1.碰撞体
上面使用刚体组件的物体,在场景中其他物体可以产生碰撞的效果。其实碰撞目标物体的,是专门有一个组件来负责的,就是碰撞体组件(Collider)。换个说法,我们控制的物体A与物体B的碰撞,实质上是物体A与物体B的碰撞体组件发生了作用关系。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/1d27b110b343d3dcef6b52e0e22f5702.png)
碰撞体可以理解成我们模型的“外骨骼”。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/100b1ae9df1066d739ea82495373a4ab.png)
这是一个什么也没有动的原来的Cube。
把物体的渲染器(上面的Renderer的勾选去掉)屏蔽,可以发现物体的碰撞体长得什么样子:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/5a61b1e6d7e0e2d28c6303cbf1e43bb8.png)
显示的就是Cube外层的碰撞体组件。
只要我们创建了物体,unity就默认为我们加上了碰撞体组件,没有碰撞体的刚体是没有意义的,就失去了刚体本该有的物理特性。
换句话说,物理特性是刚体组件和碰撞体组件一起表现出来的。
其实这一对“好基友”有很多很多的故事,大致总结了一下。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/e0393bd28a285725b6c310a243c9763c.png)
碰撞体组件按照它们的形状,大致可以分为以下几类。
2.Box Collider
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/fd4b70d849b5fb5eaeaef92bd7abf0ec.png)
盒子碰撞体,形状是立方体,用来包裹盒子状的模型,比如箱子、门、房子,等等。有几个常用属性:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/863718414bf300f57a336de49115ff6b.png)
Is Trigger:设置是否为触发器。这个属性非常重要,在后面讲触发器会经常使用。
Material:物理材质。
Center:碰撞体也可以设置中心点。一般来说碰撞体中心点就是物体的几何中心点。
Size:设置物体的“外骨骼”的尺寸。
3.Sphere Collider
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/3aec162f0b76a5d23b9b3aff2e357dd1.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/ae69ffeecec2fd830362e57fc6e04585.png)
球形碰撞体,和上面的盒子碰撞体基本类似,Radius是半径。
4.Capsule Collider
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/8a65083c68a4c2b18aa5879ae4050c42.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/720763bcad1d1494826f64180cabde33.png)
胶囊碰撞体,属性和球形碰撞体类似,Direction是指设置它的高度的方向。
5.Mesh Collider
网格碰撞体,用来包裹复杂结构的模型Mesh:根据指定的网格,生成碰撞体。
[b]六.刚体常用方法介绍[/b]
有了组件,必然有新带来的方法。
1.AddForce()
作用:给刚体一个力,使刚体按照“世界坐标系”进行运动。![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/089dfd4906a7ff291914f0e2367a8a8d.png)
其中的ForceMode是力的模式,是一个枚举类型,决定以什么样的方式添加力给刚体。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/3874cc05a58ccd489921e969619e79be.png)
using UnityEngine; using System.Collections; public class ForceTest : MonoBehaviour { private Rigidbody rigid; void Start() { //获取物体的刚体组件 rigid = gameObject.GetComponent<Rigidbody>(); } void Update() { //给刚体施加一个相对世界坐标系向前的力 rigid.AddForce(Vector3.forward, ForceMode.Force); } }
2.AddRelativeForce()
作用:给刚体添加一个力,让刚体按照“自身坐标系”进行运动。![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/5a1e45c0b38fb9a4dd1655ceae4d3d22.png)
由此可以知道,AddForce()和AddRelativeForce()是非常像的,这俩其实就是双胞胎,只不过一个是相对世界坐标系,另一个是相对自身坐标系罢了。
3.FixedUpdate()
这个是固定的更新方法。这个方法值得说道说道。一查网上资料还真不少,那就不献丑了~Update()方法是每一帧刷新一次,但是时间间隔是不确定的。而FixedUpdate()方法是固定时间间隔(默认0.02秒)刷新一次。
这个值是可以自己设定的。Edit-->Project Settings-->Time-->Fixed Timestep。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/66d3267be50b9b9c0227bfd7374a68cf.png)
基本上和物理相关的操作,代码都是写在FixedUpdate()方法里面。如果你写在了Update()里,会出现卡顿的现象。
[b]七.刚体碰撞事件监测与处理[/b]
1.碰撞事件简介
啥叫“碰撞事件”呢?当一个用刚体控制的物体与另外一个物体碰撞时,就会触发碰撞事件。注:目标物体必须带有Collider组件。
碰撞 Collision
比如,一个射击类游戏,我们发射了子弹,子弹是一个由刚体控制运动的物体。子弹射中了敌人,我们怎么监测这个碰撞呢?
2.碰撞事件监测方法
OnCollisionEnter(Collision) //当碰撞开始时调用,只会调用该方法一次OnCollisionExit(Collision) //当碰撞结束时调用,只会调用该方法一次
OnCollisionStay(Collision) //当碰撞进行中时,会持续调用该方法
这个Collision参数是什么呢?
这个是“碰撞”的一个类,用来传递碰撞信息。
Collision.gameObject属性,与当前物体碰撞的物体的引用。
gameObject.name属性,当前物体的名字。
上代码示例:
using UnityEngine; using System.Collections; public class CollisionCube : MonoBehaviour { void OnCollisionEnter(Collision coll) { if(coll.gameObject.name != "Ground") Debug.Log ("Enter " + coll.gameObject.name); } void OnCollisionExit(Collision coll) { if(coll.gameObject.name != "Ground") Debug.Log ("Exit " + coll.gameObject.name); } void OnCollisionStay(Collision coll) { if(coll.gameObject.name != "Ground") Debug.Log ("Stay " + coll.gameObject.name); } }
八.刚体触发事件监测与处理
1.触发事件简介
将碰撞体组件上的Is Trigger选项选中,当前的游戏物体的碰撞体组件就变成了触发器。我想大家应该都理解“触发器”的概念。
注:移动的刚体物体都会穿透碰撞体勾选了“Is Trigger”选项的物体。
当一个用刚体控制的物体进入到另一个物体的触发器范围内,就产生了触发事件。
这个不与目标物体发生直接的碰撞(接触),而是只要进入目标物体的“触发范围”就能执行某些操作。
那怎么设定“触发范围”呢?其实和我们上面设置碰撞体范围的方法是一致的。
2.触发事件监测方法
OnTriggerEnter(Collider) //当进入触发范围开始时调用,只会调用该方法一次OnTriggerExit(Collider) //当退出触发范围开始时调用,只会调用该方法一次
OnTriggerStay(Collider) //在触发范围内,会持续调用该方法
这个Collider参数是什么呢?
这个是“碰撞体”的一个类,用来传递触发信息。
Collision.gameObject属性,进入触发范围内的目标物体的引用。
gameObject.name属性,当前物体的名字。
using UnityEngine; using System.Collections; public class TriggerCube : MonoBehaviour { void OnTriggerEnter(Collider coll) { Debug.Log (coll.gameObject.name+"on trigger enter"); } void OnTriggerStay(Collider coll) { Debug.Log (coll.gameObject.name+"on trigger stay"); } void OnTriggerExit(Collider coll) { Debug.Log (coll.gameObject.name+"on trigger exit"); } }
[b]九.游戏打包与发布[/b]
好了,当我们制作好了一个游戏,怎么把它发布到各个平台呢?
其实很简单。untiy已经帮我们做好了绝大部分事情。
我们要做的事情:
1.Build Settings[生成设置]
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/986a8774ab5b02cb6892a9f1fb8825e4.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/17e146e8e7425f1d28980a21e9687e47.png)
2.Player Settings[详细设置]
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/89bcbb18a00be97e1f029add6be246bd.png)
3.成品介绍
一个exe文件,一个data数据文件夹,两者缺一不可。![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/a6f1aa7e5bca13d80c74a64009617796.png)
十.入门总结
这个阶段我们从最简单的组件与脚本学起,介绍了鼠标键盘的交互,怎么移动物体,了解了刚体、碰撞体以及常用的几个方法,还学习了怎么打包发布。那么unity的基本操作差不多告一段落。虽然还有很多没有介绍到,那我们在做demo的过程中再学再用吧。我还把上面介绍到的所有的方法和属性写了一个思维导图文件,缩略图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/27/d0c76592a1da0d221d09522d62c4268e.png)
详细的地址:链接:http://pan.baidu.com/s/1dFMXvpf 密码:8xq0
ok,今天告一段落。
------------------------------------9.26更新---------------------------------------------------------------------------------------------------------------
最近规划了一下,发现看似简单的一个demo做起来需要用到许多unity的其他知识,什么动画系统,粒子系统,物理引擎,所以准备开一个新的案例,如《贪吃蛇大作战》等,补充自己的知识后,再来更好地做这个农药的demo。再加上本人还是某不知名双一流大学的学生,课程比较紧,期间会穿插其他知识,所以这个专栏更新会比较慢。
相关文章推荐
- 面向组件编程之Unity 7.怎样脚本控制物体旋转和移动 关键字:画圆&&Translate/transform.Translate,transform.Rotate
- 面向组件编程之Unity 3.怎样获取脚本所在物体的各种组件 例如:GetComponentInChildren<T>()/GetComponentsInChildren<U>()
- 面向组件编程之Unity 1.怎样获取脚本所在物体的各种组件,例如:transform/BoxCollider
- 蓝鸥Unity入门脚本组件学习笔记
- unity 4.6新UI系统学习笔记 如何通过脚本访问并修改Text组件
- unity 的游戏脚本组件的生命周期
- Android 框架炼成 教你怎样写组件间通信框架EventBus
- 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生
- 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生
- Unity 通过代码获取从面板传入的mono脚本,并添加为GameObject的脚本组件
- 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生
- 初试Unity 3D——理解U3D的组件和脚本
- 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生
- 面向组件编程之Unity 6.怎样复制游戏物体 关键字:time/<GameObject>/Instantiate/Debug
- Unity常用类之脚本、对象与组件
- 对面向组件和Unity中脚本与gameobject关系的个人理解
- 在unity通过组件名称(string)添加脚本
- 蓝鸥Unity开发教程之课时5 Unity组件开发之脚本组件
- unity 动态控制 组件或脚本的激活与关闭 对象的显示与隐藏
- unity 脚本(自定义组件)的事件触发关系