列表
列表与数组密切相关,列表能将相同类型的多个值收集到单个变量中。但是,在添加、删除和更新元素时,列表要灵活得多,这使列表在大多数情况下成为首选。
1.基本语法
列表类型的变量需要具备以下条件:
- List 关键字,元素类型定义在后面的一对尖括号中,此外还要有唯一的名称。
- new 关键字,用于初始化内存中的列表以及 List 关键字后面的一对尖括号中的元素类型。
- 以分号结尾的一对括号。
以蓝图的形式看起来语法如下:
List<elementType> name = new List<elementType>();
注意:列表的长度总是可以修改的。因此,不需要在创建时就指定列表最终存储的元素数量
与数组一样,可以在变量的声明中通过在花括号内添加元素值来初始化列表:
List<elementType> name = new List<elementType>() {valuel, value2 };
元素从索引0开始按照添加的顺序进行存储,并且可以使用下标运算符进行访问。
实践一派对成员
下面通过在虚构的角色扮演游戏中创建派对成员列表来进行热身练习。
(1)创建一个名为 questPartyMembers 的字符串类型的列表,并使用三个角色名称进行初始化。
(2)添加一条调试日志,使用 Count 方法打印出列表中的派对成员数量
(3)保存脚本并在Unity 中单击 Play 按钮,
刚刚发生了什么
我们初始化了一个名为questPartyMembers 的列表,其中存储了三个字符串,然后使用Count方法打印了列表中的元素数量
2.常用方法
只要索引在列表范围内,就可以像数组那样使用下标运算符和索引访问并修改列表元素。但是,List 类提供了多个用来扩展列表功能的方法,从而添加、插入和删除元素.
继续使用questPartyMembers列表。下面将一个新的成员添加到这个列表中:
questPartyMembers.Add("I am 4");
Add 方法可以将新元素追加到列表的末尾,这将使 questPartyMembers 列表的长度变为4,并使元素的顺序变为如下形式:
"I am 1","I am 2","I am 3","I am 4"
要在列表中的特定位置添加元素,可以向 Insert 方法传递想要添加的索引和值:
questPartyMembers.Insert(1,"I am 5");
删除元素非常简单,只需要提供索引或字面值,List 类即可完成工作:
1. questPartyMembers.RemoveAt(0); 2. questPartyMembers.Remove("I am 1");
字典
与数组和列表相比,字典在每个元素中存储值对而不是单个值。字典中的元素又称为键值对:键充当对应的值的索引。与数组和列表不同,字典是无序的。但是,典可以在创建后以各种配置进行排序。
1.基本语法
声明字典和声明列表几乎一样,但是许多细节(比如键和值的类型)需要在尖括号中进行指定:
Dictionary<keyType, valueType> name = new Dictionary<keytypevalueType>();
要使用键值对初始化字典,请执行以下操作:
- 在声明的最后使用一对花括号。
- 将每个元素添加到各自的一对花括号中,用逗号分隔键和值
- 用逗号分隔元素,最后一个元素的逗号是可选的。
Dictionary<keyType, valueType> name = new Dictionary<keyType,valueType>() { {keyl,valuel}, {key2,valve2} };
选择键值时,每个键必须唯一,并且不能更改。如果需要更新键,请在变量声明中更改对应的值,或者删除后重新添加。
提示:
就像使用数组和列表一样,可以在一行中初始化字典,这在 Visual Studio中没有问题。但是,与前面的示例一样,在每一行中写出完整的键值对是一种良好习惯,这有利于提高代码的可读性。
实践一建立库存
下面创建字典来存储角色可能携带的物品
(I)声明一个名为itemInventory 的字典,键的类型为string,值的类型为int
(2)将创建的字典初始化为 new Dictionary
(3)添加调试日志以打印itemInventory.Count 属性,以便查看存储的物品的数量
(4)保存脚本并在Unity 单击 Play 按钮
void Start() { Dictionary<string, int> itemInventory = new Dictionary<string, int>() { {"potion",5}, {"Antidote",7}, {"Aspirin,1} }; Debug.LogFormat("Items:{0}",itemInventory.Count}; }
刚刚发生了什么
我们创建了一个名为itemInventory 的字典,并使用三个键值对进行初始化。我们指定键为字符串类型、对应的值为整型,然后打印 itemInventory 字典中元素的数量
2使用字典对
可以使用下标和类方法在字典中添加、删除和访问键值对。要检索元素的值,请使用带元素键的下标运算符。如以下代码所示,numberOfPotions将被赋值为5:
int mumberofPotions = itemInventory["Potion"];
元素值可以使用同样的方法进行更改。与"Potion"关联的值现在是 10:
itemInventory["Potion"] = 10;
元素可以通过两种方式添加到字典中:使用Add 方法或下标运算符。Add 方法接收键和值,并使用它们创建新的键值对元素,只要类型与字典声明中的一致即可:
itemInventory.Add("Throwing Knife",3);
如果使用下标运算符为字典中不存在的键赋值,编译器将自动把它们添加为新的键值对。
如果想添加新的元素”Bandages”,可以使用以下代码
itemInventory{“WBandage"} = 5;
这就引出如下关于引用键值对的关键问题:最好在尝试访问一个元素之前确定这个元素是否存在,以免错误地添加新的键值对。将ContainsKey 方法与i语句配对是种简单的解决方案,因为ContainsKey 方法会根据键是否存在返回一个布尔值。在以下代码中,我们在确保"Aspirin"键存在后才更改对应的值:
if(itemInventory.ContainsKey("Aspirin")) { itemInventory{"Aspirin"} = 3; }
最后,可以使用 Remove 方法从字典中删除键值对,只需要传入键作为参数即可:
迭代
我们已经通过下标运算符和集合类型中的方法访问了各个集合元素,但是当需要逐个元素地遍历整个集合时,该怎么办呢?在编程中,这被称为迭代(iteration)。C#提供了几种语句类型,让我们可以遍历集合元素。迭代语句就像方法一样,它们可以存储将要执行的代码块;但与方法不同的是,只要满足条件,它们就可以重复执行代码块。
for循环
for 循环最常见的应用场景是:在程序继续之前需要执行某个代码块一定的次数for 循环语句本身包含三个表达式,每个表达式在执行循环之前都要执行特定的任务因为for 循环能够追踪正在进行的迭代,所以十分适用于数组和列表。
for 循环语句的蓝图如下:
1. for (initializer; condition; iterator) 2. { 3. code block; 4. }
下面稍作分析:
- 整个结构从 for 关键字开始,后面跟着一对括号
- 括号内是三个表达式一一初始化表达式、条件表达式和迭代表达式
- 循环从初始化表达式开始,可创建局部变量来追踪循环执行的次数通常设置为0,因为集合类型是从0开始索引的。
- 接下来检查条件表达式,如果为 true,就进行选代。
- 迭代表达式用于初始化变量的增减,这意味着下一次循环计算条件表达式时初始化变量会有所不同。
内容看起来好像很多,所以下面我们看看之前创建的questPartyMembers 列表示例:
下面看看其中的 for 循环是如何工作的
- 初始化表达式将名为i的局部变量设置为0。
- 确保只有当i小于questPartyMembers 中元素的数量时,for 循环才会执行
- for 循环每执行一次就使用++运算符将i加1。
- 在 for 循环内部,我们使用i打印出索引和索引处的列表元素。请注意,i 与集合元素的索引将保持一致,因为它们都是从0 开始的.
实践一查找元素
当遍历questPartyMembers 时,我们可以看看是否能迭代到某个确定的元素,并为这种情况添加特殊的调试日志。
(1)在for 循环的调试志的下面添加if语句。
(2)在if语句中检查当前的questPartyMembers 元素是否与”Merli the Wise"匹配
(3)如果匹配,就添加一条调试日志.\
控制台输出应该看起来几乎相同,只不过现在有一条额外的调试日志,并且这条日志仅在遍历到"I am 1"时才打印一次。具体而言,当i等于1,进入第二次循环,因为满足 if 语句中的条件,所以会打印两条调试日志而不是一条
foreach循环
foreach 循环能够获取集合中的每个元素并将其存储到局部变量中,从而可以在语句中访问它们。局部变量的类型必须与集合元素的类型匹配才能正常工作。foreach循环可以与数组和列表一起使用,但是它们对于字典来说尤为有用,因为它们不是基于数字索引的。
以蓝图的形式看起来语法如下:
1. foreach(elementType localName in collectionVariable) 2. { 3. code block; 4. }
下面继续使用questPartyMembers列表示例,对其中的每个派对成员进行点名:
下面稍作分析:
元素类型被声明为字符串,从而能够与questPartyMembers 列表中的值匹配
创建一个名为 partyMember 的局部变量,用于在每次循环中保存元素。
i关键字的后面是想要遍历的集合,在本例中是questPartyMember 列表。我们得到的控制台输出
这比 for 循环要简单得多,但是在处理字典时,我们需要指出如下重要的区别:
如何将键值对作为局部变量处理.
遍历键值对
为了在局部变量中捕获键值对,需要使用 KeyValuePair 类型,同时分配键和值的类型以匹配字典中相应的类型。KeyValuePair 由于能够作为自身的类型,因此可与其他任何元素类型一样充当局部变量。
我们已经指定了命名为kvp 的 KeyValuePair 局部变量,这个变量的作用类似于 for循环的初始化表达式中的 i,用于将键和值的类型设置为字符串和整数以匹配itemlnventory
while循环
while 循环与 if 语句的相似之处在于,只要单个表达式或条件为 true,它们就可以运行。值的比较结果和布尔变量可以用作 while 条件,你也可以使用逻辑非运算符修改条件。
while 循环的语法如下:当条件为 true 时,就会一直运行代码块
在 while 循环中,通常需要声明一个初始化变量,就像在 for 循环中一样,然后在代码块的末尾手动对这个初始变量进行增减。根据自身的情况,初始化表达式通常是循环条件的一部分。
实践一追踪玩家是否还活着
在游戏中,假设我们需要在玩家活着时执行代码,并在玩家死亡时输出一些提示信息。
(1)创建一个int类型的名为 playerLives 的初始化变量,赋值为3。
(2)声明一个 while 循环,条件是检查 playerLives 是否大于0(判断玩家是否还活着)
(3)在 while 循环中,输出一些信息,从而让我们知道玩家还活着,然后使用--运算符将 playerLives 减1。
(4)在while循环的后面添加调试日志,从而在玩家死亡时打印一些内容,
刚刚发生了什么
playerLives从3 开始,因而 while 循环执行了3次。循环期间会打印"Stillalive!"”并从 playerLives 中减去生命值。当第4 次运行 while 循环时,因为 playerLives为0所以循环条件不满足,于是代码块被跳过,打印 while 循环后面的调试日志
超越无限
在结束本章之前,我们需要理解关于迭代语句的一个极其重要的概念:无限循环顾名思义,无限循环指的就是循环无法停止,因而将在程序中一直运行。
在 for和 while 循环中,当迭代变量不增加或减少时,通常会发生无限循环。例如.在之前的 while 循环示例中,如果去掉 playerLives 代码行,Unity 就会崩溃,因光playerLives 始终为3,循环会永远执行下去。
另外,在 for 循环中,永远不会通过或计算为 false 的设置条件,也可能导致无限循环。在遍历键值对时,如果将 for 循环条件设置为 i>0 而不是iquestPartyMembers.Count,那么i永远不会小于0,for 循环会一直运行下去直到Unity崩溃。
总结
至此,我们应该反思自己已经完成了多少工作以及利用这些知识可以创建什么。我们已经知道如何使用简单的 felse 语句和复杂的switch 语句在代码中做出决策。我们可以使用数组、列表或带键值对的字典来创建存储各种值的集合变量,甚至可以为每种集合类型选择正确的循环语句,同时谨慎地避免无限循环。如果感到任务过重,没有关系一-逻辑和顺序思考是锻炼编程能力的有效方式。下面将通过研究类、结构体和面向对象编程(通常称为 OOP)来结束对 C#编程基础知识的讨论。我们将把到目前为止所学的一切都放到对这些主题的讨论之中,从而为第一次真正地深入了解和控制Unity引擎中的对象做好准备。