我主要根据GitHub - actboy168/MoeHero: 我的英雄不可能那么萌
的项目代码,简单介绍一些重要的Lua语法概念。
如果你想对Lua语法有更深入的了解,可以访问菜鸟编程,或者编程狮等网站。直接跳过教程2。
好的,让我从快速简单的介绍MoeHero这个项目中使用的Lua语法特性。
1. 变量和基本数据类型
a. 局部变量(local)与全局变量
- 使用
local
声明局部变量 - 不使用
local
声明全局变量 - 变量命名规则
示例解释:
-- 局部变量(推荐使用)
local name = "小明"
local age = 18
-- 全局变量(不推荐随意使用)
global_value = 100
-- 多个变量同时声明
local a, b, c = 1, 2, 3
b. 基本数据类型
项目中使用的主要数据类型:
-- 数值型(number)
local damage = 100
local attack_speed = 1.5
-- 字符串(string)
local name = "英雄"
local desc = '这是一段描述'
-- 布尔值(boolean)
local is_alive = true
local can_move = false
-- nil值
local not_init = nil
-- 函数
local function add(a, b)
return a + b
end
-- table(Lua中的关联数组)
local hero = {
name = "圣骑士",
hp = 1000,
skills = {"圣光术", "神圣打击"}
}
c. 字符串操作
项目中的字符串处理示例:
-- 字符串连接
local full_name = first_name .. " " .. last_name
-- 字符串格式化
local msg = string.format("玩家%s的等级是%d", player_name, level)
-- 字符串查找和替换
local new_str = string.gsub(old_str, "旧内容", "新内容")
-- 字符串分割
local function split(str, delimiter)
local result = {}
string.gsub(str, '[^'..delimiter..']+', function(w)
table.insert(result, w)
end)
return result
end
这些是Lua最基础的语法特性。从项目代码中可以看到,这些基本语法被广泛应用于:
- 游戏数据的存储和处理
- 配置信息的管理
- 游戏逻辑的实现
- 调试信息的输出
2. 函数定义和调用
a. 基本函数定义
函数定义的几种方式:
-- 1. 全局函数
function globalFunction(param1, param2)
return param1 + param2
end
-- 2. 局部函数
local function localFunction(param)
print(param)
end
-- 3. 匿名函数
local callback = function(event)
print("事件触发:", event)
end
-- 4. 表方法
local obj = {}
function obj:method() -- 等同于 obj.method = function(self)
print(self.name)
end
b. 函数参数
参数特性:
-- 1. 可变参数
function sum(...)
local args = {...}
local total = 0
for _, v in ipairs(args) do
total = total + v
end
return total
end
-- 2. 默认参数(通过逻辑实现)
function createUnit(type, x, y, level)
level = level or 1 -- 默认等级为1
-- 创建单位逻辑
end
-- 3. 命名参数(通过表实现)
function createHero(params)
local name = params.name or "默认英雄"
local level = params.level or 1
local skills = params.skills or {}
end
c. 闭包
闭包示例:
-- 创建计数器
function createCounter()
local count = 0
return function()
count = count + 1
return count
end
end
-- 创建技能冷却管理器
function createCooldownManager()
local cooldowns = {}
return {
start = function(skillName, duration)
cooldowns[skillName] = os.clock() + duration
end,
check = function(skillName)
return not cooldowns[skillName] or
os.clock() >= cooldowns[skillName]
end
}
end
d. 函数重载
元方法使用:
local Unit = {}
Unit.__index = Unit
-- 构造函数
function Unit.new(name, level)
local self = setmetatable({}, Unit)
self.name = name
self.level = level
return self
end
-- 字符串转换
function Unit:__tostring()
return string.format("Unit[%s Lv%d]", self.name, self.level)
end
-- 加法运算符重载
function Unit:__add(other)
return self.level + other.level
end
这些函数相关的语法特性在项目中主要用于:
- 游戏逻辑的模块化
- 事件系统的实现
- 单位/技能系统的封装
- 异步操作的处理
3. 表(table)的高级用法
a. 表的基本操作
基本用法示例:
-- 表的创建和初始化
local hero = {
name = "圣骑士",
hp = 1000,
skills = {"圣光术", "神圣打击"}
}
-- 访问和修改
hero.name = "大法师" -- 点号访问
hero["hp"] = 1200 -- 方括号访问
-- 表的遍历
for key, value in pairs(hero) do
print(key, value)
end
-- 数组部分遍历
for index, skill in ipairs(hero.skills) do
print(index, skill)
end
b. 元表(Metatable)
元表使用示例:
-- 创建类
local Hero = {}
Hero.__index = Hero
-- 构造函数
function Hero.new(name)
local self = setmetatable({}, Hero)
self.name = name
self.level = 1
return self
end
-- 元方法
Hero.__add = function(hero1, hero2)
return hero1.level + hero2.level
end
Hero.__tostring = function(self)
return string.format("英雄[%s]等级%d", self.name, self.level)
end
c. 表作为命名空间
命名空间示例:
-- 创建游戏系统命名空间
local GameSystem = {
-- 子系统
Combat = {},
Inventory = {},
Quest = {},
-- 初始化函数
init = function(self)
self.Combat.init()
self.Inventory.init()
self.Quest.init()
end
}
-- 战斗系统
GameSystem.Combat = {
calculateDamage = function(attacker, defender)
-- 伤害计算逻辑
end,
applyEffect = function(target, effect)
-- 效果应用逻辑
end
}
d. 弱引用表
-- 创建弱引用表用于缓存
local cache = setmetatable({}, {__mode = "v"}) -- 值是弱引用
local refs = setmetatable({}, {__mode = "k"}) -- 键是弱引用
-- 用于对象池
local function createObjectPool()
local pool = setmetatable({}, {__mode = "v"})
return {
acquire = function()
return table.remove(pool) or {}
end,
release = function(obj)
table.insert(pool, obj)
end
}
end
e. 表的高级操作
高级操作示例:
-- 表的深拷贝
function deepcopy(orig)
local copy
if type(orig) == 'table' then
copy = {}
for k, v in pairs(orig) do
copy[deepcopy(k)] = deepcopy(v)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else
copy = orig
end
return copy
end
-- 表的合并
function merge(t1, t2)
for k, v in pairs(t2) do
if type(v) == 'table' and type(t1[k]) == 'table' then
merge(t1[k], v)
else
t1[k] = v
end
end
return t1
end
这些表的高级特性在项目中主要用于:
- 数据结构的实现
- 对象系统的构建
- 配置管理
- 缓存系统
4. 面向对象编程
a. 类的定义和继承
面向对象示例:
-- 基类定义
local Unit = {}
Unit.__index = Unit
function Unit.new(name)
local self = setmetatable({}, Unit)
self.name = name
self.hp = 100
return self
end
-- 子类继承
local Hero = setmetatable({}, {__index = Unit})
Hero.__index = Hero
function Hero.new(name, level)
local self = Unit.new(name) -- 调用父类构造函数
setmetatable(self, Hero) -- 设置为Hero类型
self.level = level
return self
end
*b. 方法定义
方法定义示例:
-- 实例方法(使用冒号语法)
function Hero:levelUp()
self.level = self.level + 1
self:updateStats() -- 自动传入self参数
end
-- 静态方法(使用点号语法)
function Hero.createTeam(heroes)
local team = {}
for _, hero in ipairs(heroes) do
if hero.type == "Hero" then
table.insert(team, hero)
end
end
return team
end
c. 私有成员模拟
私有成员示例:
-- 使用闭包实现私有成员
local function createClass()
-- 私有变量
local privateData = {}
-- 类定义
local Class = {}
Class.__index = Class
function Class.new(id)
local self = setmetatable({}, Class)
privateData[self] = {
id = id,
created = os.time()
}
return self
end
function Class:getId()
return privateData[self].id
end
return Class
end
d. 多态
多态示例:
-- 基础技能类
local Skill = {}
Skill.__index = Skill
function Skill:cast()
print("释放技能:", self.name)
end
-- 主动技能
local ActiveSkill = setmetatable({}, {__index = Skill})
ActiveSkill.__index = ActiveSkill
function ActiveSkill:cast()
print("释放主动技能:", self.name)
self:consumeMana()
end
-- 被动技能
local PassiveSkill = setmetatable({}, {__index = Skill})
PassiveSkill.__index = PassiveSkill
function PassiveSkill:cast()
print("触发被动技能:", self.name)
end
这些面向对象特性在项目中主要用于:
- 游戏对象系统的构建
- 技能系统的实现
- 事件系统的设计
- 各种游戏机制的模块化
5. 模块和包管理
a. 模块定义和导入
local std_print = print
require 'war3.id'
require 'war3.api'
require 'util.log'
require 'ac.init'
require 'util.error'
local runtime = require 'jass.runtime'
local japi = require 'jass.japi'
local slk = require 'jass.slk'
模块系统示例:
-- 定义模块 (damage.lua)
local damage = {}
function damage.calculate(attacker, defender)
-- 伤害计算逻辑
end
function damage.apply(source, target, amount)
-- 伤害应用逻辑
end
return damage
-- 使用模块
local damage = require 'systems.damage'
damage.apply(hero1, hero2, 100)
b. 包管理和目录结构
require 'maps.rule.设置'
require 'maps.rule.player'
require 'maps.rule.rects'
require 'maps.rule.units'
require 'maps.rule.misc'
require 'maps.rule.hero'
require 'maps.rule.attack'
require 'maps.rule.win'
包结构示例:
game/
├── init.lua -- 主入口
├── systems/ -- 游戏系统
│ ├── combat.lua
│ ├── inventory.lua
│ └── quest.lua
├── objects/ -- 游戏对象
│ ├── unit.lua
│ ├── hero.lua
│ └── item.lua
└── utils/ -- 工具函数
├── math.lua
└── string.lua
c. 模块加载机制
--测试版本和发布版本的脚本路径
if base.release then
package.path = package.path .. [[;Poi\]] .. base.version .. [[\?.lua;scripts\?.lua]]
end
if not base.release then
--调试器端口
runtime.debugger = 4279
end
模块加载示例:
-- 自定义加载器
local function customLoader(modname)
local filename = string.gsub(modname, '%.', '/') .. '.lua'
local file = io.open(filename, 'rb')
if file then
local content = file:read('*all')
file:close()
return load(content, '@'..filename)
end
end
-- 添加到加载器列表
table.insert(package.loaders, customLoader)
-- 设置模块搜索路径
package.path = package.path .. ';scripts/?.lua;modules/?.lua'
6. 协程和异步编程
a. 协程基础
--以线程模式运行函数
function thread.call(f, ...)
local co = coroutine.create(f)
local info = {coroutine.resume(co, ...)}
if info[1] then
return table.unpack(info, 2)
else
thread.error_handle(info[2], co)
end
end
--等待时间
function thread.sleep(time_out)
local co = coroutine.running()
ac.wait(time_out * 1000, function ()
local info = {coroutine.resume(co)}
if not info[1] then
thread.error_handle(info[2], co)
end
end)
coroutine.yield()
end
协程使用示例:
-- 创建和运行协程
local function async_task()
print("开始任务")
coroutine.yield() -- 暂停执行
print("继续任务")
coroutine.yield()
print("完成任务")
end
local co = coroutine.create(async_task)
coroutine.resume(co) -- 运行到第一个yield
coroutine.resume(co) -- 运行到第二个yield
coroutine.resume(co) -- 完成任务
b. 异步操作封装
function helper:move()
local data = self:get_owner():getCamera()
self:get_owner():sync(data, function(data)
self:blink(ac.point(data[1], data[2]), true)
end)
end
异步编程示例:
-- 异步操作封装
local function async_operation(callback)
local co = coroutine.create(function()
-- 模拟异步操作
thread.sleep(1.0)
return "操作完成"
end)
-- 启动协程
local function resume()
local ok, result = coroutine.resume(co)
if ok and coroutine.status(co) == "dead" then
callback(result)
end
end
resume()
end
-- 使用Promise风格封装
local function createPromise(fn)
local resolved = false
local callbacks = {}
local function resolve(value)
if resolved then return end
resolved = true
for _, callback in ipairs(callbacks) do
callback(value)
end
end
fn(resolve)
return {
then = function(self, callback)
table.insert(callbacks, callback)
end
}
end
这些特性在项目中主要用于:
- 游戏逻辑的模块化组织
- 异步操作的处理(如技能释放、动画播放)
- 复杂流程的控制
- 性能优化
7. 错误处理
a. 错误捕获和处理
local function error_handle(msg)
print("---------------------------------------")
print(tostring(msg) .. "\n")
print(debug.traceback())
print("---------------------------------------")
end
--错误汇报
function runtime.error_handle(msg)
base.error_handle(msg)
end
错误处理示例:
-- pcall使用
local function riskyFunction()
-- 可能出错的代码
error("发生错误")
end
local status, err = pcall(riskyFunction)
if not status then
print("捕获到错误:", err)
end
-- xpcall使用(带自定义错误处理)
local function errorHandler(err)
return {
message = err,
traceback = debug.traceback()
}
end
local status, err = xpcall(riskyFunction, errorHandler)
b. 调试信息
log = require 'jass.log'
local log = log
log.path = '我的英雄不可能那么萌\\日志\\' .. split(log.path, '\\')[2]
log.debug '日志系统装载完毕,向着星辰大海出击!'
function print(...)
log.info(...)
return std_print(...)
end
调试功能示例:
-- 调试信息输出
local function debugFunction()
local info = debug.getinfo(1)
print("当前函数:", info.name)
print("行号:", info.currentline)
print("源文件:", info.source)
-- 局部变量
local variables = {}
for i = 1, math.huge do
local name, value = debug.getlocal(1, i)
if not name then break end
variables[name] = value
end
end
-- 性能分析
local function profileFunction()
local start = os.clock()
-- 执行代码
local elapsed = os.clock() - start
print("执行时间:", elapsed)
end
8. 性能优化相关特性
a. 局部变量优化
local jass = require 'jass.common'
local japi = require 'jass.japi'
local slk = require 'jass.slk'
local dbg = require 'jass.debug'
local math = math
local table_insert = table.insert
local table_remove = table.remove
性能优化示例:
-- 局部化全局变量
local floor = math.floor
local insert = table.insert
local remove = table.remove
-- 避免重复table访问
local function processUnit(unit)
local x = unit.position.x -- 局部化table访问
local y = unit.position.y
-- 使用x,y而不是重复访问unit.position
end
-- 预分配table大小
local function createLargeTable(size)
local t = table.create(size) -- 预分配空间
for i = 1, size do
t[i] = 0
end
return t
end
b. 内存管理
ac.loop(30 * 1000, function()
local lua_memory = collectgarbage 'count'
log.debug('------------------------定期体检报告------------------------')
log.debug(('时间: %.f'):format(ac.clock() / 1000))
log.debug(('内存[%.3fk]'):format(lua_memory))
log.debug(('jass句柄数[%d],历史最大句柄[%d]'):format(dbg.handlecount(), dbg.handlemax()))
end)
内存管理示例:
-- 手动垃圾回收
local function performCleanup()
collectgarbage("collect")
collectgarbage("step")
end
-- 对象池
local ObjectPool = {}
function ObjectPool.new()
return {
free = {},
used = {},
acquire = function(self)
local obj = remove(self.free) or {}
self.used[obj] = true
return obj
end,
release = function(self, obj)
if self.used[obj] then
self.used[obj] = nil
insert(self.free, obj)
end
end
}
end
c. 缓存优化
--物品缓存表
local cache = {}
local function get_cached_item(name)
if not cache[name] then
cache[name] = create_new_item(name)
end
return cache[name]
end
缓存示例:
-- 函数结果缓存
local cache = {}
local function expensive_calculation(param)
if cache[param] then
return cache[param]
end
-- 进行复杂计算
local result = -- ...计算过程
cache[param] = result
return result
end
-- 带过期时间的缓存
local function createTimedCache(timeout)
local cache = {}
return {
get = function(key)
local entry = cache[key]
if entry and os.time() - entry.time < timeout then
return entry.value
end
return nil
end,
set = function(key, value)
cache[key] = {
value = value,
time = os.time()
}
end
}
end
这些优化特性在项目中主要用于:
- 提高代码执行效率
- 减少内存占用
- 优化游戏性能
- 提供更好的调试信息
好的,让我继续介绍项目中使用的Lua语法特性。
9. 文件操作和配置管理
a. 文件读写
local function encrypt_file(name)
local buf = w2l:file_load('resource', name)
if not buf then
return false
end
cache[name] = true
return true
end
local function encrypt_jass(path)
local jass = w2l:file_load('jass', path)
if not jass then
return
end
local new_jass = jass:gsub('([^\\]")([^%c"]*)(%.[mM][dD][lLxX]")', function(str1, name, str2)
if encrypt_model(name) then
return str1 .. encrypt_name(name) .. str2
end
end)
w2l:file_save('jass', path, new_jass)
end
文件操作示例:
-- 读取文件
local function readConfig(filename)
local file = io.open(filename, "r")
if not file then return nil end
local content = file:read("*all")
file:close()
return content
end
-- 写入文件
local function saveConfig(filename, data)
local file = io.open(filename, "w")
if not file then return false end
file:write(data)
file:close()
return true
end
-- 追加内容
local function appendLog(filename, message)
local file = io.open(filename, "a")
if file then
file:write(os.date("[%Y-%m-%d %H:%M:%S] ") .. message .. "\n")
file:close()
end
end
b. 配置管理
[AInv]
_parent = "AInv"
-- 可以取得物品
DataD = 0
[A000]
_parent = "ANcl"
-- 按钮位置 - 普通 (X)
Buttonpos_1 = 0
-- 按钮位置 - 普通 (Y)
Buttonpos_2 = 2
配置系统示例:
-- 配置管理器
local Config = {
data = {},
load = function(self, filename)
local content = readConfig(filename)
if content then
self.data = load("return " .. content)()
end
end,
get = function(self, key, default)
local value = self.data
for k in key:gmatch("[^%.]+") do
value = value[k]
if not value then
return default
end
end
return value
end,
set = function(self, key, value)
local t = self.data
local keys = {}
for k in key:gmatch("[^%.]+") do
table.insert(keys, k)
end
for i = 1, #keys-1 do
local k = keys[i]
t[k] = t[k] or {}
t = t[k]
end
t[keys[#keys]] = value
end
}
10. 字符串处理的高级特性
a. 模式匹配
local function get_key(player)
return string.char(('A'):byte() + (player:get() - 1))
end
function ac.game:record(n, name)
for i = 1, 12 do
japi.StoreString(ac.player(i):record(), '', 'Title@' .. string.char(('A'):byte() + n), name)
end
log.info(('设置积分标题[%d]为[%s]'):format(n, name))
end
字符串处理示例:
-- 模式匹配
local function parseCommand(str)
local cmd, args = str:match("^/(%w+)%s*(.*)$")
if cmd then
return cmd:lower(), args
end
end
-- 字符串分割
local function split(str, sep)
local parts = {}
for part in str:gmatch("[^" .. sep .. "]+") do
table.insert(parts, part)
end
return parts
end
-- 字符串替换
local function formatText(template, vars)
return template:gsub("%${(%w+)}", function(key)
return tostring(vars[key] or "")
end)
end
b. Unicode支持
-- Unicode字符串处理
local function utf8len(str)
local len = 0
for _ in str:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
len = len + 1
end
return len
end
-- UTF8字符串截取
local function utf8sub(str, i, j)
local pos = 1
local bytes = {str:byte(1, -1)}
local len = #bytes
local collect = {}
local count = 0
local continue = true
while continue do
if pos > len then break end
local c = bytes[pos]
local bc = nil
local cl = 0
if c > 0 and c <= 127 then
bc = c
cl = 1
elseif c >= 194 and c <= 223 then
bc = (c - 192) * 64
cl = 2
elseif c >= 224 and c <= 239 then
bc = (c - 224) * 4096
cl = 3
elseif c >= 240 and c <= 244 then
bc = (c - 240) * 262144
cl = 4
end
count = count + 1
if count >= i and count <= j then
for m = pos, pos + cl - 1 do
table.insert(collect, bytes[m])
end
end
pos = pos + cl
end
return string.char(unpack(collect))
end
这些特性在项目中主要用于:
- 配置文件的读写
- 游戏数据的序列化
- 多语言支持
- 文本处理和格式化
11. 数学运算和随机数
a. 基础数学运算
local damage = {}
function damage.init()
-- 伤害计算
function mt:get_damage()
local damage = self.damage
-- 暴击判定
if math.random(100) <= self.crit_chance then
damage = damage * (self.crit_rate / 100)
self.is_crit = true
end
-- 四舍五入
return math.floor(damage + 0.5)
end
end
数学运算示例:
-- 基础运算
local function calculateDamage(attack, defense)
local base_damage = attack * 100 / (100 + defense)
return math.floor(base_damage + 0.5)
end
-- 范围限制
local function clamp(value, min, max)
return math.min(math.max(value, min), max)
end
-- 距离计算
local function getDistance(x1, y1, x2, y2)
return math.sqrt((x2-x1)^2 + (y2-y1)^2)
end
b. 随机数生成
-- 随机偏移
local function randomOffset()
local angle = math.random() * math.pi * 2
local distance = math.random(10, 50)
return math.cos(angle) * distance, math.sin(angle) * distance
end
-- 随机选择
function getRandomSkill(skills)
local index = math.random(1, #skills)
return skills[index]
end
随机数示例:
-- 自定义随机数生成器
local RandomGenerator = {}
function RandomGenerator.new(seed)
return setmetatable({
seed = seed or os.time()
}, {
__index = RandomGenerator
})
end
function RandomGenerator:next()
self.seed = (self.seed * 1103515245 + 12345) & 0x7fffffff
return self.seed
end
function RandomGenerator:range(min, max)
return min + (self:next() % (max - min + 1))
end
-- 权重随机
function weightedRandom(weights)
local total = 0
for _, weight in pairs(weights) do
total = total + weight
end
local value = math.random() * total
local current = 0
for item, weight in pairs(weights) do
current = current + weight
if current >= value then
return item
end
end
end
12. 时间和定时器
a. 定时器系统
local timer = {}
setmetatable(timer, timer)
function timer:__call(timeout, count, on_timer)
if not on_timer then
on_timer = count
count = 1
end
local t = {
timeout = timeout,
count = count,
on_timer = on_timer,
running = true
}
function t:remove()
self.running = false
end
table.insert(timer, t)
return t
end
定时器示例:
-- 简单定时器
local function createTimer(interval, callback)
local timer = {
interval = interval,
callback = callback,
last_time = os.clock(),
update = function(self)
local current = os.clock()
if current - self.last_time >= self.interval then
self.callback()
self.last_time = current
end
end
}
return timer
end
-- 延迟执行
local function delay(seconds, callback)
local start_time = os.clock()
return createTimer(0.1, function()
if os.clock() - start_time >= seconds then
callback()
return true -- 停止定时器
end
end)
end
b. 时间管理
local jass = require 'jass.common'
local self = {}
function self.gt()
local time = 0
ac.loop(1000, function()
time = time + 1
local min = math.floor(time/60)
local sec = time % 60
ac.game:showText('time', ('游戏时间:%02d:%02d'):format(min, sec))
end)
end
return self
时间管理示例:
-- 时间格式化
local function formatTime(seconds)
local days = math.floor(seconds / 86400)
local hours = math.floor((seconds % 86400) / 3600)
local minutes = math.floor((seconds % 3600) / 60)
local secs = seconds % 60
if days > 0 then
return string.format("%d天%02d:%02d:%02d", days, hours, minutes, secs)
else
return string.format("%02d:%02d:%02d", hours, minutes, secs)
end
end
-- 计时器管理器
local TimerManager = {
timers = {},
update = function(self)
local current = os.clock()
for id, timer in pairs(self.timers) do
if timer.next_time <= current then
timer.callback()
if timer.repeat_count then
timer.repeat_count = timer.repeat_count - 1
if timer.repeat_count <= 0 then
self.timers[id] = nil
else
timer.next_time = current + timer.interval
end
else
timer.next_time = current + timer.interval
end
end
end
end,
addTimer = function(self, interval, callback, repeat_count)
local id = #self.timers + 1
self.timers[id] = {
interval = interval,
callback = callback,
repeat_count = repeat_count,
next_time = os.clock() + interval
}
return id
end,
removeTimer = function(self, id)
self.timers[id] = nil
end
}
这些特性在项目中主要用于:
- 游戏机制的随机性
- 技能效果的计算
- 游戏时间的管理
- 定时事件的处理