本期我们就接着来学习C#的分支与循环

目录

if语句

        (1)单独的 if:满足条件才执行

(2)if-else:二选一

(3)if - else if - else 链:多条件判断

(4)嵌套 if:条件内部再做判断

switch语句

        进阶:带模式匹配的 switch(Unity 2020+ 支持)

        更简洁的 switch 表达式(C# 8+)

三目运算符

        类型规则:两个分支的类型必须兼容

for循环

while循环

do-while循环

foreach循环


if语句

        (1)单独的 if:满足条件才执行

if (条件表达式) 
{
    // 条件为 true 时执行
}

Unity 实例:玩家按下空格键时跳跃。

if (Input.GetKeyDown(KeyCode.Space)) 
{
    rigidbody.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}

注意条件表达式必须是 bool 类型,C# 不允许将数值直接当作布尔值(比如 if(1) 会报错)。

(2)if-else:二选一

if (health > 0) 
{
    PlayAnimation("Idle");
} 
else 
{
    PlayAnimation("Death");
}

(3)if - else if - else 链:多条件判断

适用于多个互斥条件,顺序判断,命中一个后跳出整个结构。

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:条件内部再做判断

if (isAlive) 
{
    if (Input.GetKeyDown(KeyCode.Space)) 
    {
        Jump();
    }
}

可读性变差时,可以考虑用逻辑运算符 &&|| 合并条件,或把内层逻辑封装成独立方法。

switch语句

        当你要判断一个变量的多个可能值(比如枚举的游戏状态),用 switch 比一长串 if-else if 更简洁、更易读。

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 必须用 breakreturnthrow 或 goto 明确结束,不允许“贯穿”(fall through),除非两个 case 之间完全没有代码(可以空着直接连到下一个)。

  • default 分支是可选的,但建议写上,用来捕获意料之外的值。

  • switch 的类型支持:整数(intlongbyte等)、charstring、枚举、以及 C# 7+ 的模式匹配。

        进阶:带模式匹配的 switch(Unity 2020+ 支持)

        可以按类型或属性进行匹配,非常强大:

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 需要返回值时,可以用更紧凑的语法:

float speed = currentState switch 
{
    GameState.Playing => 10f,
    GameState.Paused  => 0f,
    GameState.MainMenu => 0f,
    _                  => 5f  // 下划线代表默认
};

这种写法省去了 case 和 break,适合简单的映射关系。

三目运算符

        三目运算符(也叫条件运算符)是 C# 中唯一需要三个操作数的运算符,语法为:

条件 ? 表达式1 : 表达式2
  • 如果 条件 为 true,计算并返回 表达式1 的值;

  • 如果 条件 为 false,计算并返回 表达式2 的值。

        比如如下这个情况

// if-else 写法
string stateText;
if (isDead)
    stateText = "阵亡";
else
    stateText = "存活";

// 三目运算符写法
string stateText = isDead ? "阵亡" : "存活";

        类型规则:两个分支的类型必须兼容

        三目运算符本身也有类型,它的类型由表达式1表达式2共同决定。规则如下:

  • 如果两个表达式类型相同,结果就是该类型。

  • 如果一个是 int,另一个是 float,会进行隐式提升,结果为 float

  • 如果一个是基类,另一个是派生类,结果为基类。

  • 如果两个类型无法隐式转换,编译器会报错。

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 时,也必须确保类型明确:

// 错误: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 是首选。

for (初始化; 条件; 迭代) 
{
    // 循环体
}

        遍历数组/列表的经典用法

GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
for (int i = 0; i < enemies.Length; i++) 
{
    enemies[i].GetComponent<Enemy>().TakeDamage(10);
}

        倒序循环(从末尾开始,常用于移除元素时避免索引错乱):

for (int i = list.Count - 1; i >= 0; i--) 
{
    if (list[i].IsDead) 
    {
        list.RemoveAt(i); // 倒序移除不会影响未处理元素的索引
    }
}

        注意:不要在 for 的循环体内增删正被遍历的集合,否则会导致异常或跳过元素,倒序是解决方案之一。

while循环

        当你事先不知道循环次数,只在满足某个条件时一直循环,用 while

while (条件) 
{
    // 循环体
}

Unity 协程中的动画等待

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循环

        循环体先执行一遍,然后再检查条件。用在“无论条件如何,至少要先做一次”的场景,比如游戏里“先扣血,再检查是否死亡”。

int hp = 100;
do 
{
    hp -= 15;
    Debug.Log("受到15点伤害,剩余:" + hp);
} while (hp > 0);
// 即使初始hp就≤0,也会先执行一次扣血再判断

在 Unity 游戏逻辑中用得相对少一些,但在输入验证、流程确保一次执行时有它的价值。

foreach循环

foreach 能极为简洁地遍历集合或数组。

List<Enemy> enemies = GetAllEnemies();
foreach (Enemy enemy in enemies) 
{
    enemy.TakeDamage(5);
}

        优点:没有索引变量,代码干净,不会越界。
        Unity 中的重大陷阱:在 Unity 中,普通的 foreach 遍历 ListDictionary 等会在堆上分配一个小的枚举器对象,如果放在每帧执行的 Update 里,会产生大量垃圾内存,导致 GC(垃圾回收)造成卡顿

        规避方案

  • 对 List 使用 for 代替:这是最简单、最高效的方法。

  • 对 Array 使用 foreach 是安全的:C# 编译器对数组的 foreach 做了优化,不会产生堆分配。

  • 使用非分配型的集合:如 C# 新增的 Span<T> 或第三方库的 FastList

  • 如果必须用 foreach 且不是数组,尽量避免在 UpdateFixedUpdate 等高频方法中使用。

        本期内容到这里就结束了,喜欢请点个赞谢谢

封面图自取:

更多推荐