C#开发Unity游戏教程之游戏对象的行为逻辑方法

C#开发Unity游戏教程之游戏对象的行为逻辑方法

C#游戏开发快速入门

C#游戏开发快速入门

游戏对象的行为逻辑——方法

方法(method),读者在第1章新建脚本时就见过了,而且在第2章对脚本做整体上的介绍时也介绍过,那么上一章呢,尽管主要内容是变量,但是在章节的最后为了展示游戏效果,也用到了它。现在看来方法真的是无处不在,并且不可或缺。它甚至都可以影响游戏对象的行为逻辑!因此本章终于到了不得不介绍它的时候了。

Unity游戏对象的行为逻辑

游戏场景中,有些游戏对象是静止的,例如,树木、山峰、石头等等。而另外一些游戏对象则是运动的,它们都有自己的行为逻辑。例如,由电脑控制的游戏对象可能会按照预定的线路行进,如果行进的途中遇到了玩家控制的游戏对象,还会发起进攻。如图4-1所示,行为逻辑在游戏《合金弹头》中的体现。不管是行进还是进攻,这都属于游戏对象的行为逻辑,而决定这一行为逻辑的就是脚本中的方法。


图4-1  《合金弹头》中各游戏对象的行为逻辑

Unity脚本中的方法

前两章做过两个游戏示例,第一个示例中的立方体对象会边前行边转动,第二个示例中的立方体则会在玩家单击指定的按钮后,进行移动、旋转和缩放。在这两个游戏中,立方体都表现出了特定的行为逻辑,而决定这些行为逻辑的就是方法。如图4-2所示的是第一个游戏示例中的脚本方法。


图4-2  脚本中决定游戏对象行为逻辑的方法

上一章的末尾向读者介绍过语句,那么再来看脚本中的方法,它的外在表现形式就是由一条或多条语句组成的。通常情况下,脚本中声明的变量是用来存储数据的,而脚本中的方法则会对这些数据做一些处理,然后将这些数据应用到游戏对象行为逻辑的控制中。例如,上一章演示的示例,通过在Inspector视图里调节属性的值,进而影响到立方体对象的缩放大小,如图4-3所示。


图4-3  脚本中的方法,将属性中的数据应用到对游戏对象行为逻辑的控制中

Unity中使用脚本方法

通过本章前面的介绍,读者也许已经认识到了方法是有多重要,以至于前面两章介绍的游戏示例,都必须在方法的协助下,才实现了最终的效果。方法这么神奇,读者现在一定有兴趣来了解,那么本节就来逐步揭开方法的神秘面纱。

Unity中的方法与变量

方法与变量有很多相似的地方。例如,变量与变量名不等价,方法与方法名同样如此。具体的说明如下:

  • q  方法也是一块儿特定的存储空间,只不过方法里存储的不是数据,而是代码语句;
  • q  方法名也需要遵守C#的命名规则,即名称必须由字母、数字和下划线组成,且数字不能作为名称的首字母,否则就是犯了语法错误;
  • q  为了区别方法名与变量名,读者可以考虑遵守这样一个约定,即变量名的首字母小写,方法名的首字母大写。既然说这是一个约定,读者当然可以不遵守,也不会犯语法错误;
  • q  就像是变量名一样,方法名也应该取的有意义些。例如,既然方法可以控制游戏对象的逻辑行为,那么就可以考虑给控制立方体移动的方法定一个类似于CubeWalking的方法名;
  • q  同样可以使用public和private修饰,只不过方法使用什么修饰,结果都不会体现在Inspector视图中,只是会反应在对方法的使用上。即使用public修饰的方法,可以被其它脚本使用,而使用private修饰,则正好相反。如果省略了对方法的修饰,Unity会认为方式是被private修饰的。

Unity中定义方法

就像是在使用变量前需要声明变量一样,使用方法前,需要定义方法。这就像是在告诉Unity:存在这样一个方法,此方法可以控制游戏对象做出特定的行为。方法的定义形式如下:

  • 返回值类型  方法名()
  • {
  •          //方法中的语句
  • }
  • q  方法名后的一对括号“( )”是必不可少的;
  • q  被大括号“{ }”括住的语句,就可以看作是存储于方法中的数据;
  • q  声明变量时,有些读者注意到,它的末尾是以分号“;”结尾的,但是对于方法的定义,大括号中的“}”就是结束标识,读者无需“画蛇添足”;
  • q  方法可以“返回特定类型的数据”;

例如,前面章节编写游戏时,用到的脚本中的一个方法如下:

  • void Update()
  • {
  •          transform.Translate(new Vector3(xPosition,0,0),Space.World);
  •          transform.Rotate(Vector3.up*yRotation,Space.World);
  • }

对于此方法,Unity会这样理解:

  • q  这个方法名为Update();
  • q  方法中一共有两条语句;
  • q  方法返回的数据类型是void。此类型表示方法不会返回任何值。因此,与其说void表示一种类型,还不如说它是一种标志,即不返回任何类型数据的标志;
  • q  省略了对方法的修饰,因此Unity会认为它是被private修饰的,因此其它脚本无法使用这个方法;

Unity中调用方法

方法定义好以后,就可以直接使用了。使用方法在脚本中有个专门术语,就是“调用方法”。在脚本中调用方法的方式很简单,直接使用方法名就可以了,但是千万不要忘了带上后面的一对括号“( )”。如下:

  • //方法的定义部分
  • …                                           //省略
  • //调用方法
  • AddTwoNumber();

Unity中方法使用示例

理论部分已经写了很多,读者应该对方法的概念有印象了才对。那现在就趁热打铁,以一个示例来说明方法的定义和调用。实现示例的操作步骤如下:

(1)在Project视图里,新建一个脚本文件,命名为MyScript,打开此脚本文件并添加下面的代码:

  • 01     using UnityEngine;
  • 02     using System.Collections;
  • 03
  • 04     public class MyScript : MonoBehaviour
  • 05     {
  • 06              private int number1 = 15;
  • 07              private int number2 = 59;
  • 08              void OnGUI()
  • 09              {
  • 10                       GUILayout.Label (“number1 = ” + number1);
  • 11                       GUILayout.Label (“number2 = ” + number2);
  • 12                       GUILayout.Label (“number1 + number2 = ” + AddTwoNumber ());   //使用方法
  • 13              }
  • 14              int AddTwoNumber()                                                      //定于方法
  • 15              {
  • 16                       return number1 + number2;
  • 17              }
  • 18     }

对于此脚本的06、07行代码,读者一定不陌生。这里的代码完成了变量的声明和初始化。变量是上一章重点介绍的内容,而本章主要关心14~17行方法的定义部分,以及12行方法的调用部分。

  • q  从方法的定义上来看,方法名为AddTwoNumber(),会返回int类型的数据,方法里只有一行语句,语句的含义是计算两个整数的和。
  • q  从方法的调用上来看,使用方法的方式很简单,直接书写AddTwoNumber()就可以了。

(2)将脚本MyScript添加到Main Camera对象上,除此以外游戏场景中不需要任何其它游戏对象。直接运行游戏,在游戏视图的左上角会出现3行文本信息,如图4-4所示。


图4-4  游戏视图左上角的文本信息

(3)这只是一个示例,是让读者熟悉方法定义和调用的示例。所以没有让方法控制游戏对象的行为逻辑,至于方法的游戏示例,会在本章后续内容讲解结束以后给出。

Unity内置的方法

在Unity中新建的脚本文件,里面会自动添加一些代码,如图4-5所示。读者在学习完方法以后,有没有觉得自动添加的代码中,Start()和Update()的书写形式很像方法。没错,它们就是方法。只不过它们是Unity内置的方法,他们会被游戏程序调用。


图4-5  脚本中Unity自动添加的代码

因为这两个方法在脚本中很常用,所以Unity直接在新建的脚本中添加了它们。那么,读者可能要问了,这两个方法会如何作用于游戏对象呢?代码中使用了注释(双斜杠“//”以及后面的部分就是注释)对这两个方法进行了简单的说明:前者在初始化时被调用,后者在游戏运行过程的每一帧被调用。如果读者并不满足于注释上的解释,可以考虑查阅Unity的帮助文档。在第1章中,作者介绍过帮助文档的打开和检索方式,忘了的话可以去复习以下。

现以查找Start()方法的使用说明为例。在帮助文档的检索框中输入MonoBehaviour.start,开始查找。一般情况下会查找出很多结果,选择需要的结果,打开它就可以了。整个过程如图4-6所示。

在帮助文档中,会首先对这个方法的功能和使用步骤做简要说明,并在最后给出这个方法的使用示例。

提示:Unity 的脚本可以使用三种语言编写,它们是C#、JavaScript和Boo,因此帮助文档会给出分别使用这3种语言的使用示例。因为本书讲解时使用的语言是C#,所以建议读者看C#语言编写的示例。


图4-6  使用Unity提供的帮助文档,查看Start()方法的使用说明

下面使用一个示例来说明,Unity内置方法Start()和Update()的使用。示例的操作步骤如下:

(1打开脚本MyScript,为其添加下面的代码:

  • 01     using UnityEngine;
  • 02     using System.Collections;
  • 03
  • 04     public class MyScript : MonoBehaviour
  • 05     {
  • 06              private int frameCount = 0;
  • 07              void Start()
  • 08              {
  • 09                        Debug.Log (“这是Start()里输出的信息”);
  • 10              }
  • 11              void Update()
  • 12              {
  • 13                        frameCount++;
  • 14                       if(frameCount == 100)
  • 15                       {
  • 16                                 Debug.Log (“这是Update()里输出的信息”);
  • 17                                 frameCount = 0;
  • 18                       }
  • 19              }
  • 20     }

新添加的代码,分别为Start()和Update()添加了一条语句(09行)和多条语句(13~18行),实现的功能均是在Unity的Console视图里输出一行文本信息。读者可以从输出的信息中了解到,Start()和Update()的调用情况。

(2运行游戏,这次观察的焦点不是Game视图,而是Console视图,输出的文本信息,如图4-7所示。


图4-7  Console视图的文本信息输出结果

通过Unity提供的帮助文档,读者应该了解到,方法Start()是在游戏对象初始化的时候调用,且是在Update()前被调用。因此,Console视图中首先输出的是Start()方法里的文本信息,而后Update()方法才被调用,因此随后就输出了Update()方法里的文本信息。并且,由于Update()方法在每帧都会被调用,因此Update()方法里的文本信息会在游戏运行的过程中,持续输出。

提示:如果让Update()方法每帧都输出信息的话,Console视图很快就会被“刷屏”了。为了阻止这种现象的发生,脚本代码只是让Update()方法每100帧输出一次文本信息,但是Update()方法依然在每帧被调用。

Unity中的方法的参数

出现在脚本中的方法,无论是在定义的时候,还是使用的时候,后面都跟着一对括号“( )”,有意义吗?看起来最多也就是起个快速识别方法的作用吧。既然C#的语法规定方法就应该这么写,肯定是有一定道理的。如果是上升到战略意义的道理,连作者也不是很明白,但是作者知道这对括号里可以添加“参数”。

Unity中参数的作用

要说明参数的作用,就必须从方法说起。方法可以处理变量中的数据,进而影响游戏对象的行为逻辑,这是本章前面一直在强调的。但是就前面脚本中一直在使用的,方法的括号里没有参数的情况而言,方法总是在处理特定变量里的数据。例如,下面是前面一个示例中定义的方法:

  • int AddTwoNumber()
  • {
  •          return number1 + number2;
  • }

这个方法的括号里没有参数,它处理的数据总是变量number1和number2里的数据。既然这只是一个用于求和的方法,没有必要指定它只计算变量number1和number2里的数据和。如果有其它变量的数据也要求和的话,就只能再定义一个方法了。为方法引入参数就可以很好的解决这类的问题。

对于游戏的实际意义

开发者定义了一个方法,可以控制一个游戏对象的逻辑行为。如果其它对象也需要做出与之类似的行为,就没有必要再定义一个方法了。例如下面的游戏示例所做的那样。

(1)为游戏场景添加Cube、Cylinder和Directional light,这3个游戏对象。前两者将作为脚本方法控制行为逻辑的游戏对象,最后一个游戏对象负责游戏场景的照明。合理设置它们各自的位置,得到的Scene和Game视图,如图4-8所示。


图4-8  在Scene和Game视图里,查看各对象的相对位置,以及游戏视图的效果

(2)在Project视图里,新建脚本文件,命名为MyScript,打开此脚本并添加下面的代码:

  • 01     using UnityEngine;
  • 02     using System.Collections;
  • 03
  • 04     public class MyScript : MonoBehaviour
  • 05     {
  • 06              public GameObject myCube;
  • 07              public GameObject myCylinder;
  • 08              void OnGUI()
  • 09              {
  • 10                        //当鼠标左键按下的时候
  • 11                       if(Input.GetMouseButton(0))
  • 12                                 RotateObject (myCube);
  • 13                        //当鼠标右键按下的时候
  • 14                       if(Input.GetMouseButton(1))
  • 15                                 RotateObject (myCylinder);
  • 16              }
  • 17              //改变游戏对象朝向的方法
  • 18              void RotateObject(GameObject myObject)
  • 19              {
  • 20                       myObject.transform.Rotate(Vector3.right*100,Space.World);
  • 21              }
  • 22     }
  • q  脚本代码的18~21行,是有参数方法的定义部分。从代码来看,传入的参数是一个游戏对象,而方法中的语句,就是通过修改游戏对象Transform组件下的Rotation属性,实现改变游戏对象朝向的目地的;
  • q  脚本代码的12、15行,调用了两次方法RotateObject(),先后传入的参数也是不一样的;

(3)将脚本MyScript赋予Main Camera对象,并在后者的Inspector视图里,设置My Script组件里的My Cube和My Cylinder属性为游戏场景中的Cube和Cylinder对象,属性的设置方法是,直接拖动Hierarchy视图里的Cube和Cylinder对象到对应的属性框中即可,如图4-9所示。


图4-9  设置My Script组件下的属性

(4)运行游戏,在Game视图里,一直按下鼠标左键,读者会看到立方体对象在原地滚动。如果一直按下鼠标右键,那么原地滚动的就成了圆柱体。如果同时按住鼠标左键和右键,立方体和圆柱体就会同时滚动了,如图4-10所示。


图4-10  游戏效果展示图

(5)游戏中,控制游戏对象滚动的方法是RotateObject(),它是一个需要传入参数的方法。正是因为需要传入参数,所以它才能被用于游戏场景中,所有游戏对象滚动的行为逻辑控制中。而不只是单独的控制一个对象的行为逻辑。

本文选自:C#游戏开发快速入门大学霸内部资料,转载请注明出处,尊重技术尊重IT人!

Comments are closed.