这篇主要根据MeoHero项目简单介绍Lua迭代器、table(表)的相关知识。
一、Lua迭代器
迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。在Lua中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。
- 基本迭代器使用
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
- 自定义迭代器
项目中有一个很好的例子是单位选择器:
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
泛型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
- 项目中的高级迭代器示例
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
- 迭代器的实际应用场景
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
重要提示:
- 迭代器的选择:
- pairs用于遍历所有键值对
- ipairs用于遍历数组
- 自定义迭代器用于特定需求
- 性能考虑:
- 避免在迭代过程中修改表
- 大量数据考虑缓存迭代结果
- 合理使用过滤条件
- 使用建议:
- 选择合适的迭代方式
- 注意迭代顺序的重要性
- 考虑使用迭代器简化代码
迭代器在游戏开发中的常用场景:
- 技能系统
- 单位选择
- Buff系统
- 物品系统
- 区域效果
- 任务系统
二、Lua table(表)
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.表的访问方式
使用点号访问
local hero = {name = "小悟空"} print(hero.name) -- 输出: 小悟空 -- 项目示例 hero.skill_points = 1 hero.owner = player
使用方括号访问
local hero = {["生命上限"] = 1000} print(hero["生命上限"]) -- 输出: 1000 -- 当键包含特殊字符时必须用方括号 hero["my-hp"] = 1000 -- 包含横线 hero["1st_skill"] = "龟派气功" -- 以数字开头
3.表的常用操作
添加和修改元素
-- 在项目中添加玩家属性 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
删除元素
local hero = {name = "小悟空", hp = 1000} hero.hp = nil -- 删除hp字段
表的嵌套
-- 项目中的多层嵌套表 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.表的高级用法
表作为数组
-- 技能列表 local skills = {'龟派气功', '如意棒', '筋斗云', '狂暴'} -- 访问数组元素(Lua的索引从1开始!) print(skills[1]) -- 输出: 龟派气功 -- 获取数组长度 print(#skills) -- 输出: 4
表作为字典
-- 击杀奖励表 self.gold = { 300, -- 1级击杀金钱 325, -- 2级击杀金钱 350, -- 3级击杀金钱 375 -- 4级击杀金钱 } -- 经验奖励表 self.xp = { 200, -- 1级击杀经验 210, -- 2级击杀经验 230 -- 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.表的遍历方式
使用pairs遍历所有键值对
local hero = { name = "小悟空", hp = 1000, mp = 500 } for key, value in pairs(hero) do print(key, value) end
使用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.实用技巧
表的合并
-- 合并两个表 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
表的复制
-- 浅拷贝 local function copy_table(t) local new_t = {} for k, v in pairs(t) do new_t[k] = v end return new_t end
重要提示:
- 性能考虑:
- 重复访问表的某个值时,建议先保存到局部变量
- 频繁增删元素可能影响性能
- 大表考虑预分配空间
- 常见陷阱:
- 注意nil值会断开数组
- 记住索引从1开始
- 注意修改表时的副作用
- 最佳实践:
- 合理组织数据结构
- 使用描述性的键名
- 保持表结构的一致性
表在游戏开发中的应用:
- 存储单位数据
- 管理技能列表
- 记录游戏状态
- 实现物品系统
- 存储配置信息
记住:表是Lua中最强大的特性之一,掌握好它对开发至关重要!