这篇主要根据MeoHero项目简单介绍Lua函数、运算符的相关知识。
一、Lua函数
1. 函数的基本定义方式
-- 方式1: 最基本的函数定义
local function say_hello()
print("你好!")
end
-- 方式2: 把函数赋值给变量
local print_damage = function(damage)
print("造成伤害:" .. damage)
end
-- 方式3: 定义在表中的函数(方法)
local hero = {}
function hero.attack(target)
print("攻击目标")
end
2. 函数参数
-- 基本参数
local function add_buff(hero, buff_name, duration)
print(hero:get_name() .. "获得buff:" .. buff_name)
end
-- 可变参数
local function print_skills(hero_name, ...)
print(hero_name .. "的技能:")
for _, skill in ipairs({...}) do
print(skill)
end
end
-- 带默认值的参数(Lua没有直接语法,需要判断)
local function heal(hero, amount)
amount = amount or 100 -- 如果amount为nil,就使用100
hero:add_hp(amount)
end
3. 函数返回值
-- 单个返回值
local function get_hero_name()
return "小悟空"
end
-- 多个返回值
local function get_hero_info()
return "小悟空", 1000, 500 -- 返回名字、血量、魔法
end
-- 根据条件返回
local function check_damage(damage)
if damage <= 0 then
return false, "伤害无效"
end
return true, "造成伤害"
end
项目中的例子:
--判断单位是否存活
function mt:is_alive()
return self._is_alive
end
--获取单位的所有者
function mt:get_owner()
return self.owner
end
--获取单位的点
function mt:get_point()
return self.point or self:get_position()
end
4. 闭包(函数内部定义的函数)
function create_skill_system()
local skill_points = 0
-- 这是一个闭包,可以访问外部的skill_points
local function add_skill_point()
skill_points = skill_points + 1
print("当前技能点:", skill_points)
end
return add_skill_point
end
项目中的例子:
function mt:on_cast_channel()
local hero = self.owner
-- 这是一个闭包函数
local function update_explosion()
-- 可以访问外部的hero变量
if not hero:is_alive() then
return
end
-- 更新爆炸效果
end
-- 注册更新函数
ac.loop(30, update_explosion)
end
5. 函数作为参数(回调函数)
-- 注册事件的例子
hero:event('单位-死亡', function()
print("英雄死亡了!")
end)
-- 定时器的例子
ac.loop(1000, function()
print("每秒执行一次")
end)
项目中的例子:
--注册英雄
ac.game:event '玩家-注册英雄' (function(self, player, hero)
--英雄死亡后复活
hero:event '单位-死亡' (function()
local lv = hero:get_level()
local time = math.floor(5 + lv * lv * 0.077)
player:sendMsg(('你将在 |cffffff00%d|r 秒后复活'):format(time))
end)
end)
6. 一些实用建议:
函数命名要清晰易懂:
-- 好的命名 function hero:add_buff(buff_name) function hero:is_alive() function hero:get_owner() -- 不好的命名 function do_something() function abc()
一个函数最好只做一件事:
-- 好的做法 function hero:add_hp(amount) function hero:add_mp(amount) -- 不好的做法 function hero:add_hp_and_mp_and_do_other_things()
适当添加注释:
--[[ 添加buff到英雄身上 @param buff_name buff的名字 @param duration 持续时间 ]] function hero:add_buff(buff_name, duration)
处理错误情况:
function hero:cast_skill(skill_name) -- 检查参数 if not skill_name then return false, "技能名字不能为空" end -- 检查条件 if not self:is_alive() then return false, "英雄已死亡" end -- 执行操作 return self:do_cast_skill(skill_name) end
记住:
- 多使用local函数,避免污染全局环境
- 函数名要有意义,表达其功能
- 参数和返回值要清晰
- 适当使用注释说明功能
- 处理各种可能的错误情况
二、Lua的运算符
1. 算术运算符
-- 加法 +
local damage = base_damage + bonus_damage -- 100 + 50 = 150
-- 减法 -
local current_hp = max_hp - damage -- 1000 - 150 = 850
-- 乘法 *
local crit_damage = damage * 2 -- 150 * 2 = 300
-- 除法 /
local damage_reduce = damage / 2 -- 150 / 2 = 75
-- 取余 %
local gold = 125 % 100 -- 25(余数)
-- 负号 -
local direction = -180 -- 负数
从项目代码可以看到实际运用:
local player = hero:get_owner()
local time = math.floor(5 + lv * lv * 0.077)
2. 关系运算符
-- 等于 ==
if hero_level == 6 then
print("获得大招!")
end
-- 不等于 ~=
if target ~= nil then
hero:attack(target)
end
-- 大于 >
if damage > 100 then
print("高伤害!")
end
-- 小于 <
if hp < 100 then
print("血量危险!")
end
-- 大于等于 >=
if level >= 18 then
print("满级!")
end
-- 小于等于 <=
if mp <= 0 then
print("没蓝了!")
end
从项目代码看实际应用:
if block_chance > 100 then block_chance = 100 end
if block_rate > 100 then block_rate = 100 end
3. 逻辑运算符
-- 与 and
if hero:is_alive() and hero:has_mana() then
hero:cast_skill()
end
-- 或 or
local real_damage = damage or 0 -- 如果damage是nil就用0
-- 非 not
if not hero:is_dead() then
hero:move()
end
从项目代码看实际应用:
if hero.skill_points <= 0 then
return
end
self.sub_skill:upgrade(1, skill or self)
hero:addSkillPoint(-1)
if not self:is_ability_enable() and hero:get_owner() == ac.player.self then
jass.ForceUICancel()
end
if __on_cast_shot then
__on_cast_shot(self, skill or self)
end
4. 字符串连接运算符
-- 使用 .. 连接字符串
local name = "小悟空"
local level = 10
local text = name .. "达到" .. level .. "级" -- "小悟空达到10级"
5. 一些特殊的运算技巧
a) 数学运算:
local sin = math.sin
function math.sin(r)
return sin(r * rad)
end
--余弦
local cos = math.cos
function math.cos(r)
return cos(r * rad)
end
--正切
local tan = math.tan
function math.tan(r)
return tan(r * rad)
end
--反正弦
local asin = math.asin
function math.asin(v)
return asin(v) * deg
end
--反余弦
local acos = math.acos
function math.acos(v)
return acos(v) * deg
end
--反正切
local atan = math.atan
function math.atan(v1, v2)
return atan(v1, v2) * deg
end
这段代码展示了如何处理数学计算。
b) 伤害计算:
function mt:freshDamageInfo()
local atk = self:get '攻击'
local pene, pener = self:get '破甲', self:get '穿透'
local crit, critr = self:get '暴击', self:get '暴击伤害'
local crit_up = crit * (critr/100 - 1) / 100 + 1
local damage = atk * crit_up * (self:getDamageRate() / 100.0) * 60
self:setStr(damage)
return damage
end
这段代码展示了游戏中的复杂运算。
重要提示:
运算符优先级:
-- 优先级从高到低 -- ^ 乘方 -- not - # 一元运算符 -- * / % 乘除 -- + - 加减 -- .. 字符串连接 -- < > <= >= 比较 -- == ~= 相等 -- and 逻辑与 -- or 逻辑或 -- 使用括号可以改变优先级 local result = (1 + 2) * 3 -- 9 local result2 = 1 + 2 * 3 -- 7
- 注意事项:
- 除法运算会得到浮点数结果
- 字符串连接要注意效率问题
- 比较nil值要小心
- 逻辑运算要注意短路效果
这些运算符在游戏开发中经常用于:
- 伤害计算
- 等级判断
- 状态检查
- 文本拼接
- 坐标计算
- 时间控制