2.3-运算符与表达式

2.3 运算符与表达式

在游戏开发中,我们经常需要进行各种计算:伤害计算、经验值增长、状态判断等。C#提供了丰富的运算符来帮助我们完成这些操作。

目录

算术运算符

想象你正在开发一个角色战斗系统:

public class CombatSystem
{
    // 基础伤害计算
    public float CalculateDamage(float baseDamage, float multiplier, float defense)
    {
        // 加法:基础伤害 + 附加伤害
        float totalDamage = baseDamage + 25;
        
        // 减法:伤害减去防御力
        totalDamage = totalDamage - defense;
        
        // 乘法:应用伤害倍率
        totalDamage = totalDamage * multiplier;
        
        // 除法:计算实际伤害(考虑护甲减免)
        float finalDamage = totalDamage / (1 + defense * 0.1f);
        
        // 取余:计算溢出伤害
        int overkillDamage = (int)finalDamage % 100;
        
        // 使用复合赋值运算符
        totalDamage += 10;    // 增加额外伤害
        totalDamage *= 1.5f;  // 暴击伤害
        
        return finalDamage;
    }
    
    // 经验值计算
    public void CalculateExperience(ref int currentExp, int gainedExp)
    {
        // 自增和自减
        currentExp++;  // 完成任务的基础经验
        gainedExp--;   // 经验衰减
        
        // 前缀和后缀
        int bonusExp = 100;
        int totalExp = ++bonusExp;  // 先增加再使用
        int extraExp = bonusExp--;  // 先使用再减少
    }
}

赋值运算符

赋值运算符用于将值赋给变量。

运算符描述示例等价于
=简单赋值a = ba = b
+=加法赋值a += ba = a + b
-=减法赋值a -= ba = a - b
*=乘法赋值a *= ba = a * b
/=除法赋值a /= ba = a / b
%=取余赋值a %= ba = a % b
&=按位与赋值a &= ba = a & b
|=按位或赋值a |= ba = a | b
^=按位异或赋值a ^= ba = a ^ b
<<=左移赋值a <<= ba = a << b
>>=右移赋值a >>= ba = a >> b

示例代码

int a = 10;

a += 5;     // 等价于 a = a + 5
Console.WriteLine($"a += 5: {a}");    // 输出: a += 5: 15

a -= 3;     // 等价于 a = a - 3
Console.WriteLine($"a -= 3: {a}");    // 输出: a -= 3: 12

a *= 2;     // 等价于 a = a * 2
Console.WriteLine($"a *= 2: {a}");    // 输出: a *= 2: 24

a /= 4;     // 等价于 a = a / 4
Console.WriteLine($"a /= 4: {a}");    // 输出: a /= 4: 6

a %= 4;     // 等价于 a = a % 4
Console.WriteLine($"a %= 4: {a}");    // 输出: a %= 4: 2

比较运算符

在游戏中,我们经常需要进行各种条件判断:

public class PlayerStatus
{
    private float health;
    private int level;
    private bool isAlive;
    
    public void CheckStatus()
    {
        // 等于和不等于
        if (health == 0)
        {
            isAlive = false;
        }
        
        if (level != 99)
        {
            // 还可以升级
        }
        
        // 大于和小于
        if (health > 0)
        {
            isAlive = true;
        }
        
        if (level < 10)
        {
            // 新手玩家
        }
        
        // 大于等于和小于等于
        if (health >= 100)
        {
            // 满血状态
        }
        
        if (level <= 20)
        {
            // 低等级玩家
        }
    }
}

逻辑运算符

在处理游戏逻辑时,我们需要组合多个条件:

public class GameLogic
{
    public bool CanAttack(Player player, Enemy enemy)
    {
        // 逻辑与:玩家存活且有足够的法力值
        if (player.IsAlive && player.ManaPoints >= 10)
        {
            return true;
        }
        
        // 逻辑或:敌人被眩晕或被冰冻
        if (enemy.IsStunned || enemy.IsFrozen)
        {
            return true;
        }
        
        // 逻辑非:敌人不是无敌状态
        if (!enemy.IsInvincible)
        {
            return true;
        }
        
        return false;
    }
    
    public void ProcessCombat(Player player, Enemy enemy)
    {
        // 短路逻辑:如果玩家死亡,不会检查后面的条件
        if (!player.IsAlive || !CanAttack(player, enemy))
        {
            return;
        }
        
        // 复杂条件组合
        if ((player.Health > 50 || player.HasShield) && !enemy.IsInvincible)
        {
            // 可以进行攻击
        }
    }
}

位运算符

位运算符在处理游戏状态和权限时非常有用:

public class StatusSystem
{
    [Flags]
    public enum PlayerStatus
    {
        None     = 0,      // 0000 0000
        Poisoned = 1 << 0, // 0000 0001
        Burning  = 1 << 1, // 0000 0010
        Frozen   = 1 << 2, // 0000 0100
        Stunned  = 1 << 3  // 0000 1000
    }
    
    private PlayerStatus currentStatus;
    
    public void UpdateStatus()
    {
        // 位与:检查状态
        bool isPoisoned = (currentStatus & PlayerStatus.Poisoned) != 0;
        
        // 位或:添加状态
        currentStatus |= PlayerStatus.Burning;
        
        // 位异或:切换状态
        currentStatus ^= PlayerStatus.Frozen;
        
        // 位取反:清除所有状态
        currentStatus = ~PlayerStatus.None;
        
        // 左移:增加伤害等级
        int damageLevel = 1;
        int damageMask = 1 << damageLevel;  // 1变成2,2变成4
        
        // 右移:降低伤害等级
        damageMask = damageMask >> 1;  // 2变成1,4变成2
    }
}

特殊运算符

C#还提供了一些特殊的运算符,用于特定的操作。

运算符描述示例
?:条件运算符(三元运算符)condition ? expr1 : expr2
??空合并运算符a ?? b
??=空合并赋值运算符a ??= b
is类型检查obj is Type
as类型转换obj as Type
typeof获取类型typeof(Type)
sizeof获取值类型的大小sizeof(Type)
new创建对象new Type()
.成员访问obj.member
[]数组索引array[index]
()方法调用method()

条件运算符(三元运算符)

条件运算符?:是C#中唯一的三元运算符,它根据条件表达式的结果返回两个表达式之一。

int a = 10;
int b = 20;

// 如果a大于b,返回a,否则返回b
int max = (a > b) ? a : b;
Console.WriteLine($"较大的数是: {max}");  // 输出: 较大的数是: 20

// 三元运算符可以嵌套使用
int c = 15;
int median = (a > b) ? ((a > c) ? ((b > c) ? b : c) : a) : ((b > c) ? ((a > c) ? a : c) : b);
Console.WriteLine($"中间的数是: {median}");  // 输出: 中间的数是: 15

空合并运算符

空合并运算符??在左操作数为null时返回右操作数,否则返回左操作数。

string name = null;
string displayName = name ?? "未知用户";
Console.WriteLine($"欢迎, {displayName}");  // 输出: 欢迎, 未知用户

name = "张三";
displayName = name ?? "未知用户";
Console.WriteLine($"欢迎, {displayName}");  // 输出: 欢迎, 张三

空合并赋值运算符

空合并赋值运算符??=在左操作数为null时将右操作数赋值给左操作数。

string username = null;
username ??= "游客";
Console.WriteLine($"用户名: {username}");  // 输出: 用户名: 游客

username = "admin";
username ??= "游客";
Console.WriteLine($"用户名: {username}");  // 输出: 用户名: admin

类型检查和转换运算符

isas运算符用于类型检查和安全类型转换。

object obj = "Hello, World!";

// 使用is运算符检查类型
if (obj is string)
{
    Console.WriteLine("obj是一个字符串");
    
    // C# 7.0模式匹配
    if (obj is string message)
    {
        Console.WriteLine($"字符串内容: {message}");
    }
}

// 使用as运算符进行安全类型转换
string str = obj as string;
if (str != null)
{
    Console.WriteLine($"转换后的字符串: {str}");
}

// 尝试将整数转换为字符串(会失败)
object number = 123;
string numStr = number as string;  // numStr将为null
Console.WriteLine($"numStr是否为null: {numStr == null}");  // 输出: numStr是否为null: True

运算符优先级

C#中的运算符按照优先级从高到低的顺序执行。下表列出了主要运算符的优先级(从高到低):

类别运算符
主要x.y, f(x), a[i], x++, x–, new, typeof, checked, unchecked
一元+, -, !, ~, ++x, --x, (T)x
乘法*, /, %
加法+, -
移位<<, >>
关系<, >, <=, >=, is, as
相等==, !=
按位与&
按位异或^
按位或|
逻辑与&&
逻辑或||
条件?:
赋值=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

当表达式中包含多个具有相同优先级的运算符时,大多数运算符从左到右计算(左结合性)。例外的是赋值运算符和条件运算符,它们从右到左计算(右结合性)。

示例代码

int a = 5 + 3 * 2;      // 乘法优先级高于加法: 5 + (3 * 2) = 11
Console.WriteLine($"5 + 3 * 2 = {a}");

int b = (5 + 3) * 2;    // 括号改变了优先级: (5 + 3) * 2 = 16
Console.WriteLine($"(5 + 3) * 2 = {b}");

int c = 10 - 2 - 3;     // 左结合性: (10 - 2) - 3 = 5
Console.WriteLine($"10 - 2 - 3 = {c}");

int d = 1;
d = d + d++ + ++d;      // 复杂表达式,需要理解运算符优先级和求值顺序
Console.WriteLine($"d = d + d++ + ++d 的结果: {d}");

表达式类型

在C#中,表达式可以分为多种类型:

  1. 算术表达式:使用算术运算符的表达式,如a + b * c
  2. 逻辑表达式:使用逻辑运算符的表达式,如a && b || c
  3. 关系表达式:使用比较运算符的表达式,如a > b
  4. 位表达式:使用位运算符的表达式,如a & b | c
  5. 赋值表达式:使用赋值运算符的表达式,如a = b + c
  6. 条件表达式:使用条件运算符的表达式,如a > b ? a : b
  7. 方法调用表达式:调用方法的表达式,如Math.Max(a, b)
  8. 对象创建表达式:使用new关键字创建对象的表达式,如new Person()
  9. Lambda表达式:使用Lambda语法的表达式,如x => x * x

复合表达式

复合表达式是由多个简单表达式组合而成的表达式。在评估复合表达式时,会根据运算符优先级和结合性确定操作的执行顺序。

// 复合表达式示例
int a = 5, b = 3, c = 2;
int result = a * b + c * (a + b) / (a - c);
Console.WriteLine($"表达式结果: {result}");

// 表达式求值过程:
// 1. (a + b) = 5 + 3 = 8
// 2. (a - c) = 5 - 2 = 3
// 3. a * b = 5 * 3 = 15
// 4. c * (a + b) = 2 * 8 = 16
// 5. c * (a + b) / (a - c) = 16 / 3 = 5 (整数除法)
// 6. a * b + c * (a + b) / (a - c) = 15 + 5 = 20

练习与实践

练习1:伤害计算系统

实现一个复杂的伤害计算系统:

public class AdvancedCombatSystem
{
    public float CalculateDamage(
        float baseDamage,
        float criticalMultiplier,
        float penetration,
        float defense,
        bool isCritical,
        bool isWeakPoint,
        PlayerStatus status)
    {
        // 基础伤害计算
        float finalDamage = baseDamage;
        
        // 应用暴击
        if (isCritical)
        {
            finalDamage *= criticalMultiplier;
        }
        
        // 应用弱点攻击
        finalDamage *= isWeakPoint ? 1.5f : 1.0f;
        
        // 计算护甲穿透
        float effectiveDefense = defense * (1 - penetration);
        
        // 应用防御减免
        finalDamage = finalDamage * (100 / (100 + effectiveDefense));
        
        // 检查状态效果
        if ((status & PlayerStatus.Burning) != 0)
        {
            finalDamage *= 1.2f;  // 燃烧状态增加伤害
        }
        
        if ((status & PlayerStatus.Frozen) != 0)
        {
            finalDamage *= 0.8f;  // 冰冻状态减少伤害
        }
        
        // 确保伤害不为负
        return Math.Max(0, finalDamage);
    }
}

练习2:技能系统

实现一个技能检查和释放系统:

public class SkillSystem
{
    public bool CanCastSkill(
        Player player,
        Skill skill,
        Target target)
    {
        // 检查玩家状态
        bool playerReady = player.IsAlive 
            && !player.IsStunned 
            && !player.IsSilenced;
            
        // 检查技能条件
        bool skillReady = skill.Cooldown <= 0 
            && player.ManaPoints >= skill.ManaCost
            && player.Level >= skill.RequiredLevel;
            
        // 检查目标
        bool targetValid = target != null 
            && target.IsAlive 
            && !target.IsInvulnerable
            && IsInRange(player, target, skill.Range);
            
        // 组合所有条件
        return playerReady && skillReady && targetValid;
    }
    
    public void CastSkill(
        Player player,
        Skill skill,
        Target target)
    {
        // 前置检查
        if (!CanCastSkill(player, skill, target))
        {
            return;
        }
        
        // 消耗资源
        player.ManaPoints -= skill.ManaCost;
        
        // 计算技能效果
        float effectValue = skill.BaseValue;
        
        // 应用增益效果
        effectValue *= player.HasBuff("Empowered") ? 1.5f : 1.0f;
        
        // 应用天赋加成
        effectValue += player.TalentPoints * 0.1f;
        
        // 处理技能效果
        switch (skill.Type)
        {
            case SkillType.Damage:
                ApplyDamage(target, effectValue);
                break;
                
            case SkillType.Heal:
                ApplyHealing(target, effectValue);
                break;
                
            case SkillType.Buff:
                ApplyBuff(target, skill.BuffType, effectValue);
                break;
        }
        
        // 设置冷却
        skill.Cooldown = skill.BaseCooldown;
    }
}

常见问题与解决方案

  1. 整数除法问题

    // 错误示例
    int result = 5 / 2;  // 结果为2,小数部分被截断
    
    // 正确示例
    double result = 5.0 / 2;  // 结果为2.5
    // 或者
    int result = 5 / 2;
    double remainder = 5 % 2;  // 获取余数
    
  2. 浮点数精度问题

   // 错误示例
   float a = 0.1f;
   float b = 0.2f;
   bool equal = (a + b) == 0.3f;  // 可能为false
   
   // 正确示例
   float a = 0.1f;
   float b = 0.2f;
   bool equal = Math.Abs((a + b) - 0.3f) < float.Epsilon;
  1. 逻辑运算符短路
    // 错误示例
    if (player != null && player.Health > 0)  // 可能抛出异常
    
    // 正确示例
    if (player?.Health > 0)  // 使用空条件运算符
    

## 总结

在本节中,我们学习了:
1. 算术运算符在游戏数值计算中的应用
2. 比较运算符在游戏逻辑判断中的使用
3. 逻辑运算符在复杂条件判断中的作用
4. 位运算符在状态管理中的高效应用
5. 条件运算符让代码更简洁的方法

通过实战练习,我们实现了:
1. 一个复杂的伤害计算系统
2. 一个完整的技能系统

这些运算符和表达式的灵活运用,可以帮助我们实现更复杂的游戏功能。在下一节中,我们将学习数组与集合的使用。

## 下一步学习

- 数组与集合基础
- 流程控制语句
- 字符串处理 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值