本期我们就接着来学习C#的分支与循环
目录
[(1)单独的 if:满足条件才执行](#(1)单独的 if:满足条件才执行)
[(3)if - else if - else 链:多条件判断](#(3)if - else if - else 链:多条件判断)
[(4)嵌套 if:条件内部再做判断](#(4)嵌套 if:条件内部再做判断)
[进阶:带模式匹配的 switch(Unity 2020+ 支持)](#进阶:带模式匹配的 switch(Unity 2020+ 支持))
[更简洁的 switch 表达式(C# 8+)](# 8+))
if语句
(1)单独的 if:满足条件才执行
cs
if (条件表达式)
{
// 条件为 true 时执行
}
Unity 实例:玩家按下空格键时跳跃。
cs
if (Input.GetKeyDown(KeyCode.Space))
{
rigidbody.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
注意条件表达式必须是 bool 类型,C# 不允许将数值直接当作布尔值(比如 if(1) 会报错)。
(2)if-else:二选一
cs
if (health > 0)
{
PlayAnimation("Idle");
}
else
{
PlayAnimation("Death");
}
(3)if - else if - else 链:多条件判断
适用于多个互斥条件,顺序判断,命中一个后跳出整个结构。
cs
if (distance < 5f)
{
state = EnemyState.Chase;
}
else if (distance < 20f)
{
state = EnemyState.Patrol;
}
else
{
state = EnemyState.Idle;
}
逻辑顺序非常重要 。如果你把 distance < 20f 写在 distance < 5f 前面,那么 distance = 3f 时就会错误地进入巡逻状态,而不是追击。
(4)嵌套 if:条件内部再做判断
cs
if (isAlive)
{
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
}
可读性变差时,可以考虑用逻辑运算符 &&、|| 合并条件,或把内层逻辑封装成独立方法。
switch语句
当你要判断一个变量的多个可能值(比如枚举的游戏状态),用 switch 比一长串 if-else if 更简洁、更易读。
cs
enum GameState { MainMenu, Playing, Paused, GameOver }
GameState currentState;
switch (currentState)
{
case GameState.MainMenu:
ShowMainMenu();
break;
case GameState.Playing:
ResumeGame();
break;
case GameState.Paused:
PauseGame();
break;
case GameState.GameOver:
ShowGameOverScreen();
break;
default:
Debug.LogWarning("未知状态");
break;
}
关键规则:
-
每个
case必须用break、return、throw或goto明确结束,不允许"贯穿"(fall through),除非两个case之间完全没有代码(可以空着直接连到下一个)。 -
default分支是可选的,但建议写上,用来捕获意料之外的值。 -
switch的类型支持:整数(int、long、byte等)、char、string、枚举、以及 C# 7+ 的模式匹配。
进阶:带模式匹配的 switch(Unity 2020+ 支持)
可以按类型或属性进行匹配,非常强大:
cs
object obj = GetComponent<Collider>();
switch (obj)
{
case BoxCollider box:
// 直接使用变量 box
Debug.Log($"盒子尺寸: {box.size}");
break;
case SphereCollider sphere:
Debug.Log($"球体半径: {sphere.radius}");
break;
case null:
Debug.Log("没有碰撞体");
break;
}
更简洁的 switch 表达式(C# 8+)
当 switch 需要返回值时,可以用更紧凑的语法:
cs
float speed = currentState switch
{
GameState.Playing => 10f,
GameState.Paused => 0f,
GameState.MainMenu => 0f,
_ => 5f // 下划线代表默认
};
这种写法省去了 case 和 break,适合简单的映射关系。
三目运算符
三目运算符(也叫条件运算符)是 C# 中唯一需要三个操作数的运算符,语法为:
bash
条件 ? 表达式1 : 表达式2
-
如果 条件 为
true,计算并返回 表达式1 的值; -
如果 条件 为
false,计算并返回 表达式2 的值。
比如如下这个情况
cs
// if-else 写法
string stateText;
if (isDead)
stateText = "阵亡";
else
stateText = "存活";
// 三目运算符写法
string stateText = isDead ? "阵亡" : "存活";
类型规则:两个分支的类型必须兼容
三目运算符本身也有类型,它的类型由表达式1 和表达式2共同决定。规则如下:
-
如果两个表达式类型相同,结果就是该类型。
-
如果一个是
int,另一个是float,会进行隐式提升 ,结果为float。 -
如果一个是基类,另一个是派生类,结果为基类。
-
如果两个类型无法隐式转换,编译器会报错。
cs
int a = 1;
float b = 2.5f;
// 正确:int + float → 结果类型为 float
float result = condition ? a : b; // a 会隐式转为 float
// 错误:string 和 int 之间无法转换,编译错误
// var error = condition ? "hello" : 100; // CS0173
当某分支需要 null 时,也必须确保类型明确:
cs
// 错误:null 和 int 之间无法推断类型
// var v = cond ? 5 : null; // 编译错误
// 正确:必须显式指定可空类型或 object
int? maybe = cond ? 5 : (int?)null;
object obj = cond ? 5 : (object)null;
for循环
在C#中,for循环与C/C++没有什么区别。当你明确知道需要执行多少次,或者需要一个索引变量时,for 是首选。
cs
for (初始化; 条件; 迭代)
{
// 循环体
}
遍历数组/列表的经典用法:
cs
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
for (int i = 0; i < enemies.Length; i++)
{
enemies[i].GetComponent<Enemy>().TakeDamage(10);
}
倒序循环(从末尾开始,常用于移除元素时避免索引错乱):
cs
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i].IsDead)
{
list.RemoveAt(i); // 倒序移除不会影响未处理元素的索引
}
}
注意 :不要在 for 的循环体内增删正被遍历的集合,否则会导致异常或跳过元素,倒序是解决方案之一。
while循环
当你事先不知道循环次数,只在满足某个条件时一直循环,用 while。
cs
while (条件)
{
// 循环体
}
Unity 协程中的动画等待:
cs
IEnumerator FadeOut(CanvasGroup group, float duration)
{
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
group.alpha = Mathf.Lerp(1f, 0f, elapsed / duration);
yield return null; // 每帧循环一次
}
}
注意 :务必确保循环条件最终会变为 false,否则死循环会让 Unity 编辑器直接卡死。你只能通过任务管理器强退。
do-while循环
循环体先执行一遍,然后再检查条件。用在"无论条件如何,至少要先做一次"的场景,比如游戏里"先扣血,再检查是否死亡"。
cs
int hp = 100;
do
{
hp -= 15;
Debug.Log("受到15点伤害,剩余:" + hp);
} while (hp > 0);
// 即使初始hp就≤0,也会先执行一次扣血再判断
在 Unity 游戏逻辑中用得相对少一些,但在输入验证、流程确保一次执行时有它的价值。
foreach循环
foreach 能极为简洁地遍历集合或数组。
cs
List<Enemy> enemies = GetAllEnemies();
foreach (Enemy enemy in enemies)
{
enemy.TakeDamage(5);
}
优点 :没有索引变量,代码干净,不会越界。
Unity 中的重大陷阱 :在 Unity 中,普通的 foreach 遍历 List、Dictionary 等会在堆上分配一个小的枚举器对象 ,如果放在每帧执行的 Update 里,会产生大量垃圾内存,导致 GC(垃圾回收)造成卡顿。
规避方案:
-
对
List使用for代替:这是最简单、最高效的方法。 -
对
Array使用foreach是安全的 :C# 编译器对数组的foreach做了优化,不会产生堆分配。 -
使用非分配型的集合 :如 C# 新增的
Span<T>或第三方库的FastList。 -
如果必须用
foreach且不是数组 ,尽量避免在Update、FixedUpdate等高频方法中使用。
本期内容到这里就结束了,喜欢请点个赞谢谢
封面图自取:
