这篇主要根据MeoHero项目简单介绍Lua迭代器、table(表)的相关知识。

一、Lua迭代器

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。在Lua中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。
  1. 基本迭代器使用

a) pairs 和 ipairs:

-- pairs用于遍历表的所有键值对
for k, v in pairs(hero_data.attribute) do
    u:set(k, v)  -- 设置英雄属性
end

-- ipairs用于遍历数组(只遍历数字索引)
for i, skill_name in ipairs(skill_names) do
    hero:add_skill(skill_name)
end
  1. 自定义迭代器
    项目中有一个很好的例子是单位选择器:
local selector = {}
setmetatable(selector, selector)

function selector:in_range(point, radius)
    self.filter_in_range = {point = point, radius = radius}
    return self
end

function selector:is_enemy(unit)
    self.filter_is_enemy = unit
    return self
end

-- 迭代器方法
function selector:ipairs()
    local group = {}
    -- 根据条件筛选单位
    if self.filter_in_range then
        -- 在范围内的单位
        local units = point:get_point():get_all_units(self.filter_in_range.radius)
        for _, u in ipairs(units) do
            if self:check_unit(u) then
                table.insert(group, u)
            end
        end
    end
    return ipairs(group)
end

使用这个选择器的例子:

-- 选择范围内的敌人
for _, u in ac.selector()
    :in_range(point, radius)
    :is_enemy(hero)
    :ipairs()
do
    -- 对每个敌人造成伤害
    u:damage
    {
        source = hero,
        damage = damage,
        skill = self,
    }
end
  1. 泛型for的工作原理

    -- 迭代器函数的基本结构
    function iterator(t, index)
     index = index + 1
     local value = t[index]
     if value then
         return index, value
     end
    end
    
    -- 创建迭代器
    function my_ipairs(t)
     return iterator, t, 0
    end
    
    -- 使用自定义迭代器
    for i, v in my_ipairs(array) do
     print(i, v)
    end
  2. 项目中的高级迭代器示例

a) 技能遍历:

function mt:each_skill(callback)
    for i = 1, self.skill_count do
        local skill = self:get_skill(i)
        if skill then
            callback(skill)
        end
    end
end

使用方式:

hero:each_skill(function(skill)
    if skill:get_level() < skill:get_max_level() then
        skill:upgrade()
    end
end)

b) Buff遍历:

function mt:each_buff(name)
    local buffs = {}
    for buff in self:each_buff() do
        if buff:get_name() == name then
            table.insert(buffs, buff)
        end
    end
    return buffs
end
  1. 迭代器的实际应用场景

a) 区域伤害:

-- 遍历范围内的敌人
for _, enemy in ac.selector()
    :in_range(hero:get_point(), self.radius)
    :is_enemy(hero)
    :ipairs()
do
    -- 造成伤害
    enemy:damage{
        source = hero,
        damage = self.damage,
        skill = self
    }
end

b) 物品遍历:

-- 遍历背包物品
for i = 1, 6 do
    local item = hero:get_item(i)
    if item then
        -- 处理物品
    end
end

重要提示:

  1. 迭代器的选择:
  2. pairs用于遍历所有键值对
  3. ipairs用于遍历数组
  4. 自定义迭代器用于特定需求
  5. 性能考虑:
  6. 避免在迭代过程中修改表
  7. 大量数据考虑缓存迭代结果
  8. 合理使用过滤条件
  9. 使用建议:
  10. 选择合适的迭代方式
  11. 注意迭代顺序的重要性
  12. 考虑使用迭代器简化代码

迭代器在游戏开发中的常用场景:

  • 技能系统
  • 单位选择
  • Buff系统
  • 物品系统
  • 区域效果
  • 任务系统

二、Lua table(表)

1.表的基础概念

  1. 什么是表?

    -- 表是Lua中最重要的数据结构,可以把它理解为一个容器
    -- 创建一个空表
    local container = {}
    
    -- 表可以存储不同类型的数据
    local hero = {
     name = "小悟空",    -- 字符串
     hp = 1000,         -- 数字
     is_alive = true,   -- 布尔值
     skills = {"龟派气功", "如意棒"}  -- 数组
    }

让我们看看项目中的例子:

-- 这就是一个表,描述了英雄的属性
return ac.hero.create '小悟空'
{
    --物编中的id
    id = 'H00C',
    
    --英雄所属作品
    production = '龙珠',
    
    --属性数据
    attribute = {
        ['生命上限'] = 1000,
        ['魔法上限'] = 600,
        ['攻击'] = 33,
        ['护甲'] = 13,
    }
}

2.表的访问方式

  1. 使用点号访问

    local hero = {name = "小悟空"}
    print(hero.name)  -- 输出: 小悟空
    
    -- 项目示例
    hero.skill_points = 1
    hero.owner = player
  2. 使用方括号访问

    local hero = {["生命上限"] = 1000}
    print(hero["生命上限"])  -- 输出: 1000
    
    -- 当键包含特殊字符时必须用方括号
    hero["my-hp"] = 1000  -- 包含横线
    hero["1st_skill"] = "龟派气功"  -- 以数字开头

3.表的常用操作

  1. 添加和修改元素

    -- 在项目中添加玩家属性
    player.__index.kill_count = 0    -- 击杀数
    player.__index.dead_count = 0    -- 死亡数
    player.__index.assist_count = 0  -- 助攻数
    
    -- 修改属性
    function on_kill()
     player.kill_count = player.kill_count + 1
    end
  2. 删除元素

    local hero = {name = "小悟空", hp = 1000}
    hero.hp = nil  -- 删除hp字段
  3. 表的嵌套

    -- 项目中的多层嵌套表
    for i = 1, 16 do
     local p = ac.player(i)
     p.ability_list = {}  -- 创建表
     if i <= 10 then
         -- 表中存储表
         p.ability_list['英雄'] = {size = 4}
         p.ability_list['学习'] = {size = 4}
         p.ability_list['智能施法'] = {size = 4}
     end
    end

4.表的高级用法

  1. 表作为数组

    -- 技能列表
    local skills = {'龟派气功', '如意棒', '筋斗云', '狂暴'}
    
    -- 访问数组元素(Lua的索引从1开始!)
    print(skills[1])  -- 输出: 龟派气功
    
    -- 获取数组长度
    print(#skills)  -- 输出: 4
  2. 表作为字典

    -- 击杀奖励表
    self.gold = {
     300,  -- 1级击杀金钱
     325,  -- 2级击杀金钱
     350,  -- 3级击杀金钱
     375   -- 4级击杀金钱
    }
    
    -- 经验奖励表
    self.xp = {
     200,  -- 1级击杀经验
     210,  -- 2级击杀经验
     230   -- 3级击杀经验
    }
  3. 表作为类(面向对象)

    -- 创建伤害类
    local damage = {}
    setmetatable(damage, damage)
    
    -- 定义类的属性
    local mt = {}
    damage.__index = mt
    
    -- 类的属性
    mt.type = 'damage'
    mt.source = nil      -- 伤害来源
    mt.target = nil      -- 伤害目标
    mt.damage = 0        -- 伤害值
    mt.success = true    -- 是否成功

5.表的遍历方式

  1. 使用pairs遍历所有键值对

    local hero = {
     name = "小悟空",
     hp = 1000,
     mp = 500
    }
    
    for key, value in pairs(hero) do
     print(key, value)
    end
  2. 使用ipairs遍历数组部分

    local skills = {'龟派气功', '如意棒', '筋斗云'}
    
    for index, skill in ipairs(skills) do
     print(index, skill)
    end

项目中的实际应用:

-- 设置英雄属性
for k, v in pairs(hero_data.attribute) do
    hero:set(k, v)
end

6.实用技巧

  1. 表的合并

    -- 合并两个表
    local function merge_tables(t1, t2)
     local result = {}
     for k, v in pairs(t1) do
         result[k] = v
     end
     for k, v in pairs(t2) do
         result[k] = v
     end
     return result
    end
  2. 表的复制

    -- 浅拷贝
    local function copy_table(t)
     local new_t = {}
     for k, v in pairs(t) do
         new_t[k] = v
     end
     return new_t
    end

重要提示:

  1. 性能考虑:
  2. 重复访问表的某个值时,建议先保存到局部变量
  3. 频繁增删元素可能影响性能
  4. 大表考虑预分配空间
  5. 常见陷阱:
  6. 注意nil值会断开数组
  7. 记住索引从1开始
  8. 注意修改表时的副作用
  9. 最佳实践:
  10. 合理组织数据结构
  11. 使用描述性的键名
  12. 保持表结构的一致性

表在游戏开发中的应用:

  • 存储单位数据
  • 管理技能列表
  • 记录游戏状态
  • 实现物品系统
  • 存储配置信息

记住:表是Lua中最强大的特性之一,掌握好它对开发至关重要!