3.2 C#的基本语法和使用
本节将通过一系列示例介绍C#语言的基本语法及其使用方法。
3.2.1 变量和数据类型
在编程语言的世界,变量由变量名称和数据类型构成。变量的数据类型决定了我们可以在其中存储哪种类型的数据。我们可以把变量看作存储某个数据的临时储物箱。正如储物箱有各种类型和尺寸一样,数据也五花八门。
你不能把东西扔到储物箱里面后就撒手不管了,因为储物箱经常会放入一些新的东西。当你的应用需要记住一些变化时,就需要把旧的数据拿出来,然后把新的数据放进去。
这就是变量(Variable)的本质—变(Vary)。变量就像小孩的玩具积木一样,如图3-1所示。
图3-1 变量的例子
我们需要把正确的形状放到正确的储物箱里。储物箱就是变量,而它的数据类型(Datatype)决定了里面能放什么形状的东西。形状就是你可以放入变量的可能数值。
我们可以更换每个箱子里面的东西,比如可以拿出蓝色的方形积木,然后放进红色的方形积木,但前提是它们都是方形。我们不能把方形积木放到一个圆孔里面,因为数值的数据类型和变量的数据类型必须是匹配的。
常见的数据类型有如下几种。
1. 数字型的变量
在C#中,数字型的变量主要包括整数(int)、单精度浮点数(float)和双精度浮点数(double)。float和double类型变量的区别是:float是单精度类型,有效位数是6位,占用4字节的存储空间;而double是双精度类型,有效位数是15位,占用8字节的存储空间。默认情况下,小数使用double来表示。如果需要使用float,需要在末尾加上f。比如:
float myNumber = 1.23f;
在上面这行代码中,我们定义了一个名为myNumber的变量,其类型是float(单精度浮点数),初始值是1.23。
除了以上3种常用的数字变量类型外,在C#中还有其他类型的数字型变量,如表3-1所示。
表3-1 基本变量及其取值范围
表3-1中所示变量使用方法大同小异,这里就不再一一赘述了。
2. 文本型的变量
文本型的变量主要是char和string,其中char类型变量用于保存单个字符的值,而string类型变量则用于保存字符串的值。
比如:
string playerName = "Steve Jobs";
在上面这行代码中,我们定义了一个名为playerName的变量,其类型是string(字符串),初始值是Steve Jobs。
也可以用string类型保存数字:
string myString = "1";
不过此时,myString中保存的数据是字符串“1”,并不是数字1。
3. 布尔型的变量
在C#中,布尔型的变量是bool,用于保存逻辑状态的变量,包含两个值—true和false。比如:
bool isPlayerDead = true;
在上面这行代码中,我们定义了一个名为isPlayerDead的变量,其类型是bool(布尔),初始值是true。需要注意的是,C#是大小写敏感的,不能将大小写混淆。比如:
Bool bool1 = true;
该语句会报错,因为C#中并没有Bool类型的变量,只有bool类型。
关于变量命名需要提醒大家的是,在C#中允许字母、数字、下划线“_”出现在变量名中,但不能以数字开头,也不允许以int、bool这些系统保留字作为变量名。
除了以上3种基本类型的变量外,在C#中还支持引用类型、枚举类型等数据类型,在后续的实战学习中我们会逐渐接触到。
此外,C#还支持一种特殊的变量—常量。所谓的“常量”,是指在程序运行过程中值不会发生变化的量。在声明变量时,在变量的前面加上关键字const或readonly即可把该变量指定为一个常量。比如:
const int constNum = 2; readonly int readonlyNum = 3;
常量必须在声明时赋值,且赋值后通常不允许再改变其值。如果将其他值赋给常量,编译器就会报错。
3.2.2 表达式与运算符
表达式与运算符的作用是对数据或信息进行各种形式的运算处理,这构成了程序代码的主体。
表达式由运算符和操作数组成。其中,运算符比较好理解,用于设置对操作数的运算,例如+、-、*和/分别代表加、减、乘、除4种运算。而操作数是运算符作用的实体,指出指令执行的操作所需要的数据来源。操作数的概念最早来源于汇编语言,其代表参与运算的数据及其单元地址。在C#中,操作数可以简单地理解为参与运算的各类变量和表达式等。
在C#中,我们需要了解以下几种主要的运算符。
1. 算术运算符
算术运算符是我们都很熟悉的基本数学运算,主要是加、减、乘、除、求余。
【示例3-1】基本数学运算
打开Unity,新建一个项目,将其命名为BasicMath。使用快捷键Ctrl+N新建一个场景,然后使用Ctrl+S保存场景,将其命名为MainScene。在Project视图中右击空白处,在弹出的快捷菜单中依次选择Create→Folder命令,将项目命名为Scripts。
双击进入项目文件夹并右击,在快捷菜单中依次选择Create→C# Script命令,如图3-2所示。
将上述创建的脚本命名为BasicCalculator,双击该脚本在Visual Studio中打开,并更改其中的代码,如代码清单3-1所示。
代码清单3-1 基础数学运算
using System.Collections; using System.Collections.Generic; using UnityEngine; public class BasicCalculator : MonoBehaviour { // 初始化方法 void Start() { //1.这是一行注释,解释了下面代码的作用,即定义两个整型变量 int firstNumber = 1; //第1个数 int secondNumber = 5; //第2个数 //2.求二者的和 int sumOfNumbers = firstNumber + secondNumber; //3.求二者的积 int mulOfNumbers = firstNumber * secondNumber; //4.求二者的差 int difOfNumbers = firstNumber - secondNumber; //5.求二者的商并进行强制类型转换 double divOfNumbers = (double)firstNumber / secondNumber; //6.求二者的余数 int remOfNumbers = firstNumber % secondNumber; //7.输出以上计算结果到Console中 Debug.Log("两个数字的和是: " + sumOfNumbers); Debug.Log("两个数字的乘积是: " + mulOfNumbers); Debug.Log("两个数字之间的差是: " + difOfNumbers); Debug.Log("两个数字相除的商是: " + divOfNumbers); Debug.Log("两个数字相除的余数是: " + remOfNumbers); } }
图3-2 创建新脚本
下面我们按照数字编号简单解释上述代码的作用。
首先要说明的是,在C#中//(双斜杠)的作用代表注释。那么,什么是注释呢?在开发产品的时候,我们需要借助注释提高代码的可读性,从而让接手项目的其他人,或者自己在若干天、若干周、若干月之后能看得懂当初的创作。单行注释用双斜杠“//”即可,如果是多行注释,就需要用/* */的形式,所有的注释内容都在星号中间。
下面对上述代码进行简单分析。
第1处:分别定义了两个整数变量firstNumber和secondNumber。
第2处:定义了一个名为sumOfNumbers的整数变量,用来保存两个整数的和。
第3处:定义了一个名为mulOfNumbers的整数变量,用来保存两个整数的乘积。
第4处:定义了一个名为difOfNumbers的整数变量,用来保存两个整数的差值。
第5处:定义了一个名为divOfNumbers的浮点型变量,用来保存两个整数相除的商,并将运算结果强制转换成浮点数。
第6处:定义了一个名为remOfNumbers的整数变量,用来保存两个整数相除的余数。
第7处:分别输出上述5种计算结果。
通过Ctrl+S组合键保存代码修改,回到Unity编辑器主界面。
在层级视图中勾选Main Camera复选框,然后在检视视图中点击Add Component按钮,在下拉列表中搜索刚才添加的Basic Calculator脚本,最后单击回车键以确定,如图3-3所示。
图3-3 添加Basic Calculator脚本
需要特别说明的是,Script脚本的文件名和Visual Studio中的类名必须完全一致,否则在这里是找不到对应的脚本的。如果因为误操作使脚本文件名和类名不一致,就需要手动在代码中更改类名,以保持一致。
单击工具栏上的“播放”控制按钮,即可在Console里面看到输出的结果,如图3-4所示。
图3-4 Console视图中输出的运算结果
2. 赋值运算符
在C#中,赋值运算符用于将一个数据赋予一个变量、属性或者引用。数据本身是常量、变量或者表达式。赋值运算符本身又分为简单赋值和复合赋值。其作用如表3-2所示。
表3-2 赋值运算符
【示例3-2】使用赋值运算符进行计算
回到BasicMath项目,打开MainScene场景,在Project视图中的Scripts子目录下创建一个新的C# script,将其命名为AssignmentCal。双击在编辑器中打开该脚本文件,并输入代码清单3-2所示的代码。
代码清单3-2 使用赋值运算符
using System.Collections; using System.Collections.Generic; using UnityEngine; public class AssignmentCal : MonoBehaviour { // 初始化方法 void Start() { //1.定义一个常数变量 const int basicNumber = 10; //2.定义一个普通的整型变量 int x = basicNumber; //3.输出不同赋值计算的结果 Debug.Log("x=" + x); Debug.Log("x+=2的运算结果为:" + (x += 2)); x = basicNumber; Debug.Log("x-=2的运算结果为:" + (x -= 2)); x = basicNumber; Debug.Log("x*=2的运算结果为:" + (x *= 2)); x = basicNumber; Debug.Log("x/=2的运算结果为:" + (x /= 2)); x = basicNumber; Debug.Log("x%=2的运算结果为:" + (x %= 2)); x = basicNumber; Debug.Log(“x >>= 2的运算结果为:" + (x >>= 2)); x = basicNumber; Debug.Log("x<<=2的运算结果为:" + (x <<= 2)); x = basicNumber; Debug.Log("x&=2的运算结果为:" + (x &= 2)); x = basicNumber; Debug.Log("x|=2的运算结果为:" + (x |= 2)); x = basicNumber; Debug.Log("x^=2的运算结果为:" + (x ^= 2)); } }
需要注意的是,我们仅仅修改了void Start(){}方法里花括号中的代码,其他地方的代码并没有做任何调整。
另外,需要特别注意的是,对于初学者来说,以上代码中所用到的双引号和分号必须采用半角输入,如果使用全角输入,则没办法得到想要的结果。
小练习
给以上代码添加完整的注释。从Hierarchy视图中选中Main Camera对象,取消对Numbers Operation组件的勾选,然后关联AssignmentCal组件,并点击Play按钮,在Console中查看计算结果。
注意
为了不影响查看计算结果,我们需要在测试运行之前手动切换到Console视图,点击Clear按钮以清除之前的显示内容。
3. 关系运算符
关系运算符用于比较两个值之间的关系,并在比较之后返回一个布尔类型的运算结果。常用的关系运算符如表3-3所示。
表3-3 关系运算符
【示例3-3】使用关系运算符
回到BasicMath项目,打开MainScene场景,在Project视图中的Scripts子目录下创建一个新的C# script,将其命名为RelationCal。双击在编辑器中打开该脚本文件,并输入代码清单3-3所示的代码。
代码清单3-3 使用关系运算符
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RelationCal : MonoBehaviour { // 初始化方法 void Start () { int firstNumber = 3; int secondNumber = 5; if (firstNumber == secondNumber) { Debug.Log ("The First number is equal to the second number."); } if (firstNumber < secondNumber) { Debug.Log ("The First number is smaller than the second number."); } if (firstNumber <= secondNumber) { Debug.Log ("The First number is smaller or equal to the second number."); } if (firstNumber > secondNumber) { Debug.Log ("The First number is bigger than the second number."); } if (firstNumber >= secondNumber) { Debug.Log ("The First number is bigger or equal to the second number."); } if (firstNumber != secondNumber) { Debug.Log ("The First number is not equal to the second number."); } } }
以上代码比较简单,我们使用了逻辑判断,比较firstNumber和secondNumber的大小,并根据比较的结果输出不同的内容。
小练习
给以上代码添加完整的注释,解释各行代码的作用。从Hierarchy视图中选中Main Camera对象,取消对Numbers Operation组件和AssignmentCal的勾选,然后关联RelationCal组件,并点击Play按钮,在Console视图中查看计算结果。
4. 条件运算符
条件运算符用于进行逻辑判断,并返回一个布尔类型的运算结果。常用的条件运算符如表3-4所示。
表3-4 条件运算符
【示例3-4】使用条件运算符
回到BasicMath项目,打开MainScene场景,在Project视图中的Scripts子目录下创建一个新的C# script,将其命名为ConditionalCal。双击在编辑器中打开该脚本文件,并输入代码清单3-4所示的代码。
代码清单3-4 使用条件运算符
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ConditionalCal : MonoBehaviour { // 初始化方法 void Start () { //定义了两个布尔类型变量 bool isPlayer1Dead = true; bool isPlayer2Dead = false; //定义了3个整型变量 int player1KilledLives = 1; int player1InitialLives = 5; int player1CurrentLives; //如果两个玩家角色都已死亡 if (isPlayer1Dead && isPlayer2Dead) { Debug.Log ("所有玩家角色均已死亡"); } //如果至少有一个玩家角色已经死亡 if (isPlayer1Dead || isPlayer2Dead) { Debug.Log ("至少有一个玩家角色已死亡"); } //如果第一个玩家角色还没有死亡 if(!isPlayer1Dead == true){ Debug.Log ("第一个玩家角色还没有死亡"); } /*如果第一个玩家角色已经死亡,那么他当前的生命值等于初始生命值减1,如果玩家角色还没有 死亡,那么他当前的生命值等于初始生命值*/ player1CurrentLives = isPlayer1Dead ? (player1InitialLives - player1KilledLives) : player1InitialLives; Debug.Log ("第一个玩家还剩下的重生机会是:" + player1CurrentLives); } }
小练习
从Hierarchy视图中选中Main Camera对象,取消对Numbers Operation、AssignmentCal和RelationCal组件的勾选,然后关联ConditionalCal组件,并点击Play按钮,在Console中查看计算结果。
3.2.3 流程控制
C#中的流程控制方法和其他语言基本相同,支持if…else、while、do…while、for、foreach、switch这些流程控制语句。
所谓的流程控制,就是对某个条件进行判断,如果判断通过,就执行对应的语句。
1. if…else
if…else是最基本也是最常用的流程控制语句,表示在满足某种特定条件的情况下,执行某种操作,否则执行else后面的操作。例如:
int num1 = 3; if(num1 == 3){ Console.WriteLine("你好呀"); }
在以上的代码中,我们首先定义了一个int类型的变量,值为3。随后判断num1的值是否等于3,如果判断成立,则执行花括号中的语句。执行num1 == 3得到的结果会是一个布尔类型的值。
在这里,num1 ==3结果成立,所以得到的值为true。如果我们想让判断更清晰,执行逻辑可以进一步优化,比如如果条件成立,就去做第一件事,否则就去做第二件事:
int num1 = 3; if(num1 == 4){ //如果判断成立,会执行该语句 Console.WriteLine("你好呀"); } else { //如果判断不成立,会执行该语句 Console.WriteLine("我不好"); }
此时,num1 == 4的判断并不成立,所以会执行else之后花括号中的语句,也就是输出“我不好”。
2. while
while和if…else语句相似,表示当满足某个条件的情况下将执行某些操作。注意,while没有else部分。例如:
int num1 = 3; while(num1 <= 4){ Console.WriteLine("你好呀"); }
在以上代码中,我们首先定义了一个整型变量,然后将其和4进行比较,最后根据比较的结果来决定是否执行花括号中的代码。
通过if进行的判断,语句只会执行一次。而使用while后,如果结果为true,那么该语句会一直重复执行,直到判断不成立。所以这里的“你好呀”会执行无数次。
3. do…while
do…while和while的区别在于,do...while语句并不会先进行判定,而是会先执行一次括号中的语句,再进行判定,如果判定成立,再继续执行括号中的语句。例如:
int num1 = 3; do{ Console.WriteLine("你好呀"); }while(num1 > 5);
在以上代码中,首先输出一次“你好呀”,然后再判断num1 > 5是否成立,如果成立,重复输出“你好呀”。
4. for
for循环的语法示例如下:
for(int i = 0; i <= 10 ; i++){ Console.WriteLine("你好呀"): }
该示例的执行顺序为:首先执行int i = 0,然后判断i≤10是否成立,如果成立则执行花括号中的语句,执行完花括号中的语句后,执行i++,然后再判断i≤10是否成立,如果不成立则跳出循环。
for(初始值; 判断语句; 值变化语句){}
也就是说,初始值语句只会执行一次,随后进行判断,如果判定成立,执行花括号中的语句,再执行值变化语句,然后执行判断,如果判断不成立,跳出循环。
5. foreach
foreach并不算严格意义上的流程控制语句,它的作用是依次遍历集合中的数据。例如:
//定义数组 int[] numbers = new int[10]; //遍历数组中的每一个元素 foreach(var num in numbers){ Console.WriteLine(num); }
该示例中,首先创建一个int数组,然后通过foreach遍历数组中的每一个元素。foreach会按顺序依次取出数组中的每一个元素。
foreach(类型 变量名 in 集合){}
上述示例中,var是变量类型,num为变量名,numbers为集合名。foreach支持对任何类型的集合进行遍历,不限于数组。foreach的性能开销很大,在Unity开发中应尽量避免使用。
3.2.4 函数
在数学领域,函数的作用是让输入值根据特定的规则计算出某个结果并输出。在编程领域,函数的作用与之类似,不过不局限于计算数值,而是可以实现任何所需要的功能。简单来说,函数就是可以完成特定功能且可以重复执行的代码块。
为了说明函数的作用,我们把3.2.2节中的所有代码重构,使用函数的方式来实现所需要的功能。
【示例3-5】使用函数重构3.2.2节中的所有运算
回到BasicMath项目,打开MainScene场景,在Project视图中的Scripts子目录下创建一个新的C# script,将其命名为FunctionCal。双击在编辑器中打开该脚本文件,并输入代码清单3-5所示的代码。
代码清单3-5 使用函数重构运算
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FunctionCal : MonoBehaviour { //初始化方法 void Start () { //分别调用每个函数 AssignmentCal(); MathCal (); ConditionalCal (); RelationCal (); } void AssignmentCal(){ const int basicNumber = 10; int x = basicNumber; Debug.Log("x=" + x); Debug.Log("x+=2的运算结果为:" + (x += 2)); x = basicNumber; Debug.Log("x-=2的运算结果为:" + (x -= 2)); x = basicNumber; Debug.Log("x*=2的运算结果为:" + (x *= 2)); x = basicNumber; Debug.Log("x/=2的运算结果为:" + (x /= 2)); x = basicNumber; Debug.Log("x%=2的运算结果为:" + (x %= 2)); x = basicNumber; Debug.Log("x>>=2的运算结果为:" + (x >>= 2)); x = basicNumber; Debug.Log("x<<=2的运算结果为:" + (x <<= 2)); x = basicNumber; Debug.Log("x&=2的运算结果为:" + (x &= 2)); x = basicNumber; Debug.Log("x|=2的运算结果为:" + (x |= 2)); x = basicNumber; Debug.Log("x^=2的运算结果为:" + (x ^= 2)); } void ConditionalCal(){ bool isPlayer1Dead = true; bool isPlayer2Dead = false; int player1KilledLives = 1; int player1InitialLives = 5; int player1CurrentLives; //如果两个玩家都已死亡 if (isPlayer1Dead && isPlayer2Dead) { Debug.Log ("所有玩家均已死亡"); } //如果至少有一个玩家已经死亡 if (isPlayer1Dead || isPlayer2Dead) { Debug.Log ("至少有一个玩家已死亡"); } //如果第一个玩家还没有死亡 if(!isPlayer1Dead == true){ Debug.Log ("第一个玩家还没有死亡"); } /*如果第一个玩家已经死亡,那么他当前的生命值等于初始生命值减1,如果还没有死亡,那么他当前的 生命值等于初始生命值*/ player1CurrentLives = isPlayer1Dead ? (player1InitialLives - player1KilledLives) : player1InitialLives; Debug.Log ("第一个玩家还剩下的重生机会是:" + player1CurrentLives); } void MathCal(){ int firstNumber = 1; int secondNumber = 5; //求二者的和 int sumOfNumbers = firstNumber + secondNumber; //求二者的积 int mulOfNumbers = firstNumber * secondNumber; //求二者的差 int difOfNumbers = firstNumber - secondNumber; //求二者的商 double divOfNumbers = (double)firstNumber / secondNumber; //求二者的余数 int remOfNumbers = firstNumber % secondNumber; //输出以上计算结果到Console中 Debug.Log ("The sum of two numbers is: " + sumOfNumbers); Debug.Log ("The multiply of two numbers is: " + mulOfNumbers); Debug.Log ("The difference of two numbers is: " + difOfNumbers); Debug.Log ("The division of two numbers is: " + divOfNumbers); Debug.Log ("The remainder of two numbers is: " + remOfNumbers); } void RelationCal(){ int firstNumber = 3; int secondNumber = 5; if (firstNumber == secondNumber) { Debug.Log ("The First number is equal to the second number."); } if (firstNumber < secondNumber) { Debug.Log ("The First number is smaller than the second number."); } if (firstNumber <= secondNumber) { Debug.Log ("The First number is smaller or equal to the second number."); } if (firstNumber > secondNumber) { Debug.Log ("The First number is bigger than the second number."); } if (firstNumber >= secondNumber) { Debug.Log ("The First number is bigger or equal to the second number."); } if (firstNumber != secondNumber) { Debug.Log ("The First number is not equal to the second number."); } } }
在以上代码中,我们分别用4个不同的函数来替代之前想要实现的数学运算,然后调用每个函数,并输出结果。当然,严格来说这里的函数其实属于方法。关于函数和方法的区别,我们将在下一节进一步说明。
小练习
给以上代码添加完整的注释,然后将FunctionCal脚本关联到Main Camera对象,并取消之前对几个脚本组件的勾选,点击工具栏上的Play按钮,在Console视图中查看函数运行结果。
3.2.5 类、对象和方法
C#是一门面向对象的编程语言,类、对象和方法则是面向对象的语言中重要的概念。具有相同属性和功能的一组对象的集合就是一个类,比如人是一个类,猫是一个类。类的一个实体就是对象。类和对象的示意如图3-5所示。
图3-5 类和对象
至于方法,其形式和函数类似,也是为了实现某些特定功能的代码块。但是方法和函数的区别在于,方法通常是某个对象所特有的。换言之,函数是代码世界里独立的生命体,它不依赖于某个对象而存在。但方法不同,任何一个方法都是某个对象的附属生命,同时只有它的宿主对象才能调用这个方法。
这么说有点抽象,我们以实际的例子来说明。比如某个幻想类RPG游戏中有多种角色,如刺客、战士、法师、术士、弓箭手等。以弓箭手为例,他有一些基本的属性,比如昵称、生命值、法术值、法术攻击力、耐力、敏捷等。这些属性值通常是以变量的形式来保存的。与此同时,弓箭手具备很多技能,比如后羿射日、元气弹、时空穿梭等。而这些技能通常体现在特定的方法中。通过将这些变量和方法放在一起,我们就创造了一个弓箭手的类,这个过程称为封装。而该弓箭手的类代表了一个抽象的弓箭手。
在Unity中,每个脚本文件都对应一个对象。如果想要在游戏中初始化某个对象,需要将其添加到GameObject中。正如我们之前所看到的,Unity中的类以组件的形式附着在游戏对象上。每个组件都是一个对象,而多个组件共同组成了一个GameObject。关于这一点,下一节将进一步说明。
【示例3-6】创建并引用一个弓箭手类
回到刚才的BasicMath项目,在Project视图中的Scripts子目录下创建一个新的C# script,将其命名为ArcherClass。双击在代码编辑器中将其打开,并输入代码清单3-6所示代码。
代码清单3-6 创建弓箭手类
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArcherClass { //定义弓箭手的各种属性 public string playerName; private int lifeLeft = 5; public int attackForce = 15; public int magicForce = 20; public float playerSpeed = 5.0f; public bool isPlayerDead = false; //定义弓箭手的各种技能 //范围攻击 public void AttackRange(){ Debug.Log ("开始范围攻击"); } //单体攻击 public void AttackSingle(){ Debug.Log ("开始单体攻击"); } //打招呼 public void SayHello(){ Debug.Log ("我是弓箭手"); } //显示弓箭手的状态 public void ShowStatus(){ Debug.Log ("弓箭手的生命值是: " + lifeLeft); Debug.Log ("弓箭手的移动速度是: " + playerSpeed); } }
在Project视图中的Scripts子目录下创建一个新的C# script,并将其命名为Archer-Command。双击在代码编辑器中将其打开,并更改代码。更改后的代码如代码清单3-7所示。
代码清单3-7 调用弓箭手类
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArcherCommand : MonoBehaviour { // 初始化方法 void Start () { ArcherClass myArcher = new ArcherClass(); myArcher.SayHello (); myArcher.ShowStatus (); myArcher.playerSpeed = 10.0f; myArcher.ShowStatus (); } }
在Hierarchy视图中选中Main Camera选项,然后在Inspector视图中单击Add Component按钮,最后从下拉列表框中依次选择Script→ArcherCommand选项,将ArcherCommand.cs脚本添加为Main Camera对象的组件,同时取消对其他代码组件的勾选。
点击工具栏上的“播放”按钮,就可以在Console面板中看到对应的输出结果了。
在以上代码中,ArcherClass.cs脚本文件中定义了弓箭手类,而在ArcherCommand.cs脚本文件中创建了一个新的弓箭手,并调用其SayHello()方法和ShowStatus()方法,然后访问了public类型的属性变量playerSpeed,更改其数值为10.0f,最后再次调用ShowStatus()方法。
需要注意的是,在C#中,类名需要和文件名保持一致,如果文件名为Archer.cs,那么类名应该为Archer。根据代码规范可知,类名和方法名的首字母都应该大写。此外,在Archer类的定义中,我们看到变量前面有一个修饰符public。实际上,C#中共有5种修饰符:public、private、protected、internal、protected internal。
如果不给属性指定访问修饰符,默认使用private。private类型的变量只有在类的内部才能够被访问。如果希望在外部能够直接对属性进行修改,那么需要指定变量为public类型。
比如在示例3-6中,我们在ArcherCommand类中对Archer对象的playerSpeed属性成功进行了修改。而使用private修饰符定义的变量lifeLeft则无法在ArcherCommand中被访问并修改。
Unity中有一些非常重要的类,其中最为重要的就是MonoBehaviour。它是所有Unity脚本的基类。关于Unity中这些重要类的详细信息,请参考Unity3D的官方文档[1]。
通过对本节的学习,我们掌握了C#的基本语法和使用方法。在下一节中,我们将继续学习如何在Unity中进行C#脚本的开发。
[1] 参见https://docs.unity3d.com/Manual/ScriptingImportantClasses.html。