C#编程中的协程、属性与位运算深入解析
协程处理与属性应用
在编程里,当使用LINQ语句筛选并选定标记方法后,会为每个方法创建一个新的协程。具体而言,在
foreach
循环中会出现
updater()
内联函数,这意味着对于类中的每个
updateMethod
实例,都会创建一个新的
IEnumerator
函数。这些函数的数据会被存储在
List<IEnumerator>
中。
要获取延迟值,可以使用
method.GetCustomAttribute()
函数来获取函数标记属性中的延迟值,然后将该值添加到
updater()
函数
while
循环里的
yield return WaitForSeconds
函数中。完成设置后,将
Updater()
添加到
routineList
。当
updateMethods
的
foreach
循环结束后,会遍历
routineList
中的所有项并启动协程,最终会在Unity控制台窗口中显示“Got Updated”和“Also Got Updated”,“Got Updated”每秒显示两次,“Also Got Updated”每三秒显示一次。
通过存储
routineList
,还能停止协程,这让系统更加健壮。保留协程的好处是,在需要时可以重新启动它们,这在切换场景或暂停游戏等情况下非常实用。
属性可以应用于类、函数和变量。在声明新的属性类时,有多种选项可供选择。可以使用按位运算符
|
添加额外的
AttributeTargets
来设置多个标志。
自定义属性能简化许多任务。例如,带有时间延迟的
Update
属性
[UpdateAttribute (3.0f)]
可让函数按自身节奏更新,并非所有函数都需要在每一帧开始时更新。每个怪物的行为部分可以在不同的时间值进行更新,聪明、快速的怪物更新频率可高于迟钝、缓慢的怪物。若要复活角色,可能需要将各种属性重置为默认值,使用
[DefaultAttribute(int restoredAmount)]
属性可自动完成这项工作,只需获取所有需要恢复的字段并将其恢复到指定的恢复量。自定义属性为函数或变量附加重要信息提供了一个易于阅读的系统。
位运算数学基础
位运算与常规数学运算有所不同。在计算机的二进制世界中,将10变为 -10不能简单地用10乘以 -1。以4位二进制数的半字节为例,无符号半字节的最大值是1111(即15),而有符号半字节的范围是 -8到7(即1000到0111)。
二进制数的范围是从0到一个上限,通常以十六进制形式呈现,在网页颜色设置中经常会遇到。在十进制中,从0数到9后,需要增加一位来表示10;而计算机计数时使用16(即一个半字节),用字母来表示额外的数字,计数顺序为0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f。计算机从0数到255需要8位二进制数,若使用两个半字节则可用两位十六进制数表示。
在C#中,使用前缀
0x
表示十六进制数,例如
0x01
表示十进制的1,
ff
表示十进制的255。有符号字节(
sbyte
)可以表示负数,如
-0x80
表示十进制的 -128。若给
sbyte
赋值超出范围,会出现错误提示。
int
类型有更大的范围,长度为8个半字节(即8位十六进制数),最大值是
0x7fffffff
,也可通过
int.MaxValue
访问。较小的值(如
0xff
)可以赋值给
int
。
按位取反运算符
~
用于处理
int
值。若使用
byte b = 0x01;
,
~b
操作时C#会自动将
byte
类型提升为
int
类型。该运算符会对二进制位进行取反操作,例如对
0001
应用
~
运算符会得到
1110
。使用按位运算将
int
从10变为 -10的方法是取反加1,这种方法比乘法运算更快,在一些优化的C++代码中经常使用。
计算机CPU内部没有直接的
+
和
-
电路,加法和减法都是通过位运算符实现的。以7 + 3为例,在半字节中,7表示为1110,3表示为1100,相加结果为1010(即10)。按位加法的过程如下:
1. 首先,使用`a & b`找出两个数中都为1的位,即需要进位的位,如`0111 & 0011 = 0011`。
2. 然后,使用`a ^ b`找出两个数中不同的位,如`0111 ^ 0011 = 0100`。
3. 接着,将进位的位左移一位`int s = c << 1;`。
4. 重复上述步骤,直到进位为0。
减法可通过将减数取反加1后与被减数相加来实现,即使用之前的按位取反方法得到负数,再使用按位加法函数。
位左移运算符
<<
可用于乘以2,如
4 << 1 = 8
。乘法可以通过多次左移和加法实现,例如7 * 3可表示为
(7 * 2) + 7
。除法可简化为从被除数中多次减去除数。
位运算还有一些实用技巧。例如,使用
n & 1 == 1
判断一个
int
是否为奇数比使用
n % 2 == 0
更快;通过
(someNumber & (1<<31)) != 0
可以判断一个数是否为负数。不过,并非所有位运算技巧都比常规数学函数更快,但了解位运算的工作原理很有趣。
项目架构与组织策略
在构建游戏项目时,将C#文件按任务分开非常重要。这样做的好处是,任务的添加或合并会更加容易,在团队协作中也能减少文件合并的次数。如果每个类的功能范围较窄,只处理少数相关任务,那么查找和修复错误会更方便,调试也会更高效。
当独自工作时,对代码库的掌控相对容易,但在团队协作中,每个人应专注于代码库中较小、更专业的部分。将每个任务放在单独的文件中,可减少多人同时修改文件的情况,降低使用版本控制系统(如Git)时的合并冲突。
在规划项目结构时,在
Assets
根目录下应为游戏公司或游戏标题创建一个目录,该目录可作为项目中最通用的函数和类的容器。
以下是一个简单的流程图,展示了按位加法的过程:
graph TD;
A[开始] --> B[计算a & b得到进位c];
B --> C[计算a ^ b得到结果r];
C --> D[c是否为0];
D -- 否 --> E[c左移一位];
E --> F[a = r, b = c];
F --> B;
D -- 是 --> G[结束];
以下是按位加法和减法的操作步骤总结:
| 操作 | 步骤 |
| ---- | ---- |
| 按位加法 | 1. 计算
a & b
得到进位
c
;2. 计算
a ^ b
得到结果
r
;3. 若
c
不为0,将
c
左移一位,更新
a = r
,
b = c
,重复步骤1和2;4. 若
c
为0,结束。 |
| 按位减法 | 1. 将减数
b
按位取反加1得到负数;2. 使用按位加法函数将被减数
a
和负数相加。 |
总之,这些编程概念虽然较为底层,但为理解C#提供了重要基础。掌握它们有助于创建更复杂、有趣的游戏玩法场景,同时在数据处理等方面也有广泛应用。
C#编程中的协程、属性与位运算深入解析(续)
位运算在实际编程中的应用拓展
位运算在实际编程中有着广泛的应用,除了前面提到的基本数学运算,还能用于解决一些特定的问题。例如,在判断两个数的正负性时,可以使用位运算来提高效率。
若要判断两个数a和b是否同号,可以使用 (a ^ b) >= 0 来实现。如果结果为真,则a和b同号;否则,a和b异号。
这种方法利用了异或运算的特性,当两个数同号时,它们的符号位相同,异或结果的符号位为0;当两个数异号时,它们的符号位不同,异或结果的符号位为1。
另外,位运算还可以用于权限管理。假设我们有多个权限,每个权限用一个二进制位表示,那么可以通过位运算来组合和检查权限。
例如,有三个权限:读权限(用二进制位 001 表示)、写权限(用二进制位 010 表示)和执行权限(用二进制位 100 表示)。
若要检查一个用户是否具有读和写权限,可以将用户的权限值与 001 | 010 进行按位与运算,如果结果等于 001 | 010,则表示用户具有这两个权限。
以下是一个简单的权限管理示例代码:
// 定义权限常量
const int READ_PERMISSION = 0x01;
const int WRITE_PERMISSION = 0x02;
const int EXECUTE_PERMISSION = 0x04;
// 用户权限值
int userPermissions = READ_PERMISSION | WRITE_PERMISSION;
// 检查用户是否具有读和写权限
bool hasReadAndWrite = (userPermissions & (READ_PERMISSION | WRITE_PERMISSION)) == (READ_PERMISSION | WRITE_PERMISSION);
项目架构的进一步优化
在项目架构方面,除了将C#文件按任务分开,还可以使用命名空间来进一步组织代码。命名空间可以将相关的类和函数分组,避免命名冲突,提高代码的可读性和可维护性。
在
Assets
根目录下的游戏公司或游戏标题目录中,可以创建不同的子目录来存放不同功能模块的代码。例如,可以创建一个
Scripts
目录来存放所有的脚本文件,再在
Scripts
目录下创建
Gameplay
、
UI
、
Network
等子目录,分别存放游戏玩法、用户界面和网络相关的代码。
同时,使用接口和抽象类可以提高代码的灵活性和可扩展性。接口定义了一组方法的签名,实现该接口的类必须实现这些方法。抽象类则可以包含抽象方法和具体方法,继承抽象类的子类必须实现抽象方法。
以下是一个简单的接口和抽象类的示例:
// 定义一个接口
interface IAttackable
{
void Attack();
}
// 定义一个抽象类
abstract class Character
{
public string Name { get; set; }
public abstract void Move();
public void Speak()
{
Console.WriteLine($"{Name} is speaking.");
}
}
// 实现接口和继承抽象类的具体类
class Warrior : Character, IAttackable
{
public override void Move()
{
Console.WriteLine($"{Name} is running.");
}
public void Attack()
{
Console.WriteLine($"{Name} is attacking with a sword.");
}
}
总结与展望
通过对协程、属性、位运算和项目架构的学习,我们了解到这些知识在C#编程中的重要性。协程可以实现异步操作,让程序在等待某些操作完成时继续执行其他任务;属性可以为类、函数和变量附加额外的信息,简化编程任务;位运算则提供了一种高效的计算方式,在底层编程和性能优化方面有着重要的应用;合理的项目架构可以提高代码的可维护性和可扩展性,便于团队协作开发。
在未来的编程实践中,我们可以进一步探索这些知识的应用场景,结合实际需求,灵活运用这些技术来解决问题。例如,在开发游戏时,可以使用协程来实现怪物的行为逻辑,使用属性来管理角色的属性和技能,使用位运算来优化游戏的性能,使用合理的项目架构来组织游戏的代码。
以下是一个总结表格,展示了本文介绍的主要知识点及其应用场景:
| 知识点 | 应用场景 |
| ---- | ---- |
| 协程 | 异步操作,如怪物行为逻辑、资源加载等 |
| 属性 | 函数定时更新、角色属性管理等 |
| 位运算 | 数学计算、权限管理、性能优化等 |
| 项目架构 | 团队协作开发、代码维护和扩展等 |
同时,为了更好地理解这些知识点之间的关系,我们可以用一个流程图来展示:
graph LR;
A[协程] --> B[游戏开发];
C[属性] --> B;
D[位运算] --> B;
E[项目架构] --> B;
B --> F[提高游戏性能和可维护性];
希望本文能为读者在C#编程方面提供一些有用的参考和启示,帮助读者更好地掌握这些技术,开发出更加优秀的项目。
超级会员免费看
1002

被折叠的 条评论
为什么被折叠?



