2.1-变量与常量

2.1 变量与常量

想象你正在开发一个游戏,需要存储和管理各种数据:玩家的生命值会随着战斗而变化,游戏的基础伤害值保持固定,而一些配置在游戏启动时确定。C#提供了变量、常量和只读字段来满足这些不同的需求。

变量

变量就像游戏中的状态数据,它们的值可以随时改变。例如,玩家的生命值、经验值、位置等都需要使用变量来存储。

变量声明

// 基本语法:类型 变量名 = 初始值;

// 游戏相关的变量示例
int playerHealth = 100;            // 玩家生命值
float moveSpeed = 5.0f;           // 移动速度
string playerName = "勇者";       // 玩家名称
bool isGameOver = false;          // 游戏是否结束
Vector3 position = new Vector3(); // 玩家位置

变量命名规则

  1. 必须以字母、下划线或@开头
  2. 可以包含字母、数字和下划线
  3. 区分大小写
  4. 不能使用C#关键字(除非使用@前缀)
// 正确的命名
int health;
float _damage;
string @class;  // 使用@前缀可以使用关键字
int player1;

// 错误的命名
int 1player;    // 不能以数字开头
float my-speed; // 不能包含连字符
string void;    // 不能使用关键字

变量作用域

变量的作用域决定了它在代码中的可访问范围。

public class GameManager
{
    private int _score = 0;  // 类级别变量,整个类中都可访问

    public void UpdateScore()
    {
        int bonus = 100;    // 局部变量,只在方法内可访问
        _score += bonus;    // 可以访问类级别变量

        if (_score > 1000)
        {
            string message = "新高分!"; // 块级变量,只在if块内可访问
            ShowMessage(message);
        }
        // message 在这里不可访问
    }
}

变量监控与常见错误

// 错误1:变量名重复
int playerHealth = 100;
{
    int playerHealth = 80;  // 编译错误:变量名重复
}

// 错误2:使用未初始化的变量
int damage;
int totalDamage = damage * 2;  // 编译错误:使用未赋值的局部变量

// 错误3:类型不匹配
int health = "100";  // 编译错误:不能将字符串赋值给整数

// 错误4:超出范围
int maxHealth = int.MaxValue;
maxHealth += 1;  // 运行时错误:整数溢出

常量

常量就像游戏中的固定配置,一旦设定就不能改变。例如,最大等级、基础伤害值、经验值系数等。

常量声明

public class GameConstants
{
    // 游戏配置常量
    public const int MAX_LEVEL = 100;
    public const float BASE_DAMAGE = 10.0f;
    public const string GAME_VERSION = "1.0.0";
    public const float CRITICAL_MULTIPLIER = 2.0f;
}

只读字段

只读字段是一种特殊的变量,它的值只能在声明时或构造函数中设置,之后就不能改变。

public class GameSession
{
    // 只读字段示例
    public readonly string SessionId;
    public readonly DateTime StartTime;
    public readonly int Seed;

    public GameSession()
    {
        // 在构造函数中初始化只读字段
        SessionId = Guid.NewGuid().ToString();
        StartTime = DateTime.Now;
        Seed = new Random().Next();
    }
}

变量、常量与只读字段的对比

特性变量(var)常量(const)只读字段(readonly)
初始化时机随时声明时声明时或构造函数中
可修改性可修改不可修改仅构造函数中可修改
编译时确定
内存分配堆/栈编译时替换实例成员
适用场景游戏中变化的数据(血量、经验值)固定配置(最大等级、基础伤害)运行时确定的配置(随机种子、实例ID)

最佳实践

public class GameConfig
{
    // 1. 使用const定义编译时就能确定的常量
    public const int MAX_LEVEL = 100;
    public const float BASE_DAMAGE = 10.0f;
    public const string GAME_VERSION = "1.0.0";

    // 2. 使用readonly定义运行时才能确定的只读值
    public readonly Guid GameId;
    public readonly DateTime StartTime;
    public readonly int RandomSeed;

    // 3. 使用私有字段存储可变数据
    private int _currentLevel;
    private float _playerHealth;
    private Dictionary<string, float> _damageMultipliers;

    // 4. 使用属性提供受控的访问
    public int CurrentLevel 
    {
        get => _currentLevel;
        set => _currentLevel = Math.Min(value, MAX_LEVEL);
    }

    public GameConfig()
    {
        // 初始化只读字段
        GameId = Guid.NewGuid();
        StartTime = DateTime.Now;
        RandomSeed = new Random().Next();

        // 初始化变量
        _currentLevel = 1;
        _playerHealth = 100;
        _damageMultipliers = new Dictionary<string, float>();
    }
}

实战练习

练习1:角色属性系统

实现一个角色属性系统,包含以下功能:

  • 定义基础属性(生命值、攻击力、防御力等)
  • 实现属性的计算(考虑装备加成、buff效果等)
  • 实现等级提升机制
  • 保存和加载角色属性
public class Character
{
    // 常量定义
    private const int MAX_LEVEL = 100;
    private const float BASE_HEALTH = 100.0f;
    private const float BASE_ATTACK = 10.0f;
    private const float LEVEL_MULTIPLIER = 1.1f;

    // 只读字段
    public readonly string Id;
    public readonly DateTime CreateTime;

    // 基础属性
    private int _level;
    private float _health;
    private float _attack;
    private Dictionary<string, float> _equipmentBonuses;
    private List<Buff> _activeBuffs;

    // 属性访问器
    public int Level => _level;
    public float Health => CalculateFinalHealth();
    public float Attack => CalculateFinalAttack();

    public Character()
    {
        // 初始化只读字段
        Id = Guid.NewGuid().ToString();
        CreateTime = DateTime.Now;

        // 初始化基础属性
        _level = 1;
        _health = BASE_HEALTH;
        _attack = BASE_ATTACK;
        _equipmentBonuses = new Dictionary<string, float>();
        _activeBuffs = new List<Buff>();
    }

    // 等级提升
    public void LevelUp()
    {
        if (_level >= MAX_LEVEL) return;
        
        _level++;
        _health = BASE_HEALTH * (float)Math.Pow(LEVEL_MULTIPLIER, _level - 1);
        _attack = BASE_ATTACK * (float)Math.Pow(LEVEL_MULTIPLIER, _level - 1);
    }

    // 添加装备加成
    public void AddEquipmentBonus(string slot, float value)
    {
        _equipmentBonuses[slot] = value;
    }

    // 添加Buff效果
    public void AddBuff(Buff buff)
    {
        _activeBuffs.Add(buff);
    }

    // 计算最终属性
    private float CalculateFinalHealth()
    {
        float total = _health;
        
        // 计算装备加成
        total += _equipmentBonuses.Values.Sum();
        
        // 计算Buff效果
        foreach (var buff in _activeBuffs)
        {
            total *= buff.HealthMultiplier;
        }
        
        return total;
    }

    private float CalculateFinalAttack()
    {
        float total = _attack;
        
        // 计算装备加成
        total += _equipmentBonuses.Values.Sum();
        
        // 计算Buff效果
        foreach (var buff in _activeBuffs)
        {
            total *= buff.AttackMultiplier;
        }
        
        return total;
    }
}

// Buff类定义
public class Buff
{
    public string Name { get; }
    public float HealthMultiplier { get; }
    public float AttackMultiplier { get; }
    public DateTime ExpiryTime { get; }

    public Buff(string name, float healthMult, float attackMult, TimeSpan duration)
    {
        Name = name;
        HealthMultiplier = healthMult;
        AttackMultiplier = attackMult;
        ExpiryTime = DateTime.Now + duration;
    }

    public bool IsExpired => DateTime.Now > ExpiryTime;
}

练习2:游戏存档系统

实现一个游戏存档系统,要求:

  • 使用合适的变量类型存储游戏数据
  • 正确使用常量定义配置信息
  • 使用只读字段保护关键数据
  • 实现存档的保存和加载功能
public class GameSave
{
    // 常量定义
    private const string SAVE_FILE_EXTENSION = ".sav";
    private const int MAX_SAVE_SLOTS = 10;

    // 只读字段
    public readonly string SaveId;
    public readonly DateTime CreateTime;
    public readonly string GameVersion;

    // 游戏数据
    private Character _player;
    private List<Item> _inventory;
    private Dictionary<string, bool> _achievements;
    private GameSettings _settings;

    public GameSave()
    {
        SaveId = Guid.NewGuid().ToString();
        CreateTime = DateTime.Now;
        GameVersion = GameConstants.GAME_VERSION;

        _inventory = new List<Item>();
        _achievements = new Dictionary<string, bool>();
        _settings = new GameSettings();
    }

    // 保存游戏
    public void Save(string slot)
    {
        if (int.Parse(slot) > MAX_SAVE_SLOTS)
            throw new ArgumentException("无效的存档槽位");

        var saveData = new SaveData
        {
            SaveId = this.SaveId,
            CreateTime = this.CreateTime,
            GameVersion = this.GameVersion,
            Player = _player,
            Inventory = _inventory,
            Achievements = _achievements,
            Settings = _settings
        };

        string json = JsonSerializer.Serialize(saveData);
        string path = $"saves/save_{slot}{SAVE_FILE_EXTENSION}";
        File.WriteAllText(path, json);
    }

    // 加载游戏
    public static GameSave Load(string slot)
    {
        string path = $"saves/save_{slot}{SAVE_FILE_EXTENSION}";
        if (!File.Exists(path))
            throw new FileNotFoundException("存档文件不存在");

        string json = File.ReadAllText(path);
        var saveData = JsonSerializer.Deserialize<SaveData>(json);

        var save = new GameSave
        {
            _player = saveData.Player,
            _inventory = saveData.Inventory,
            _achievements = saveData.Achievements,
            _settings = saveData.Settings
        };

        return save;
    }
}

// 存档数据结构
public class SaveData
{
    public string SaveId { get; set; }
    public DateTime CreateTime { get; set; }
    public string GameVersion { get; set; }
    public Character Player { get; set; }
    public List<Item> Inventory { get; set; }
    public Dictionary<string, bool> Achievements { get; set; }
    public GameSettings Settings { get; set; }
}

总结

在本节中,我们学习了:

  1. 变量的声明、命名规则和作用域
  2. 常量的使用场景和特点
  3. 只读字段的应用
  4. 变量、常量和只读字段的对比
  5. 在游戏开发中的最佳实践

通过实战练习,我们实现了:

  1. 角色属性系统:展示了如何使用不同类型的变量管理游戏数据
  2. 游戏存档系统:展示了如何在实际项目中应用这些概念

在下一节中,我们将学习C#的基本数据类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值