在用Lua写AI脚本这一块,这是我从网上找到的唯一一篇文章,而且写的非常好,读后受宜菲浅!让我少走很多弯路。但文章源出处找不到了,在这里对这篇文章的作者表示非常的感谢!
LUA实现角色AI的新方法
怪物AI只需要提供3种条件集:
1. 无目标的条件集
2. 有目标的条件集
3. 无论是有目标还是无目标, 都必须检测的条件集. 或者叫做定时器条件集.
假设目前我们为游戏提供如下类型的怪物表现: [来自ai_define.lua]
--ai类型 : 废材型 表现为被打也不还手, 继续随机走动
ai_useless = { no_target = as_idle, has_target = as_forget, tick = as_tick}
--ai类型 : 标准型 表现为被打了就还手并追击, 自己不会主动搜敌
ai_standard = { no_target = as_idle, has_target = as_chase , tick = as_tick}
--ai类型 : 进攻型 表现为保持警戒搜敌,有目标就追击
ai_attacker = { no_target = as_guard, has_target = as_chase , tick = as_tick}
--ai类型 : 胆小型 表现为被打了就反方向逃跑了
ai_flee = { no_target = as_idle, has_target = as_flee , tick = as_tick}
--ai类型 : 机智型 表现为保持警戒搜敌, 如果目标靠近, 就躲远点继续攻击,
用于高级远程攻击怪
ai_smart = { no_target = as_guard,has_target = as_around, tick = as_tick}
--ai类型 : 巡逻型 表现为两点间巡逻, 并保持警戒搜敌, 有目标就追击
ai_patrol = { no_target = as_patrol, has_target = as_chase, tick = as_tick}
然后写出如下两个AI运行的核心函数
function handle_state(c, state) --处理条件集(state), 参数c表示角色对象
if state==nil then return end
for con, event in state do --遍历条件集中的所有条件
if con==1 then
event(c) --永为真的条件, 必然执行事件
else
local r = con(c)
if r~=0 then event(c, r) end –条件满足, 执行事件
end
end
end
function ai_loop(c) --每个角色都会循环执行的ai函数
local ai_t = GetAIType(c) --取出角色的ai类型定义, 例如废材,标准
local t = GetChaTarget(c) --取出当前角色的目标
if t~=nil then
handle_state(c, ai_t.has_target) --有目标的处理
else
handle_state(c, ai_t.no_target) --无目标的处理
end
handle_state(c, ai_t.tick) –无论有目标还是无目标, 都要进行的处理
end
打完收功, AI就实现完毕了. 除了这两个总计21行的lua函数, 剩下的事情应该交给脚本策划了……虽然很残忍, 但是很清晰, 下面我们来看看脚本策划应该实现的部分:
1. 组合条件集
2. 编写具体的条件以及条件产生的事件
下面我们来看看脚本策划应该实现的部分:
1. 组合条件集
2. 编写具体的条件以及条件产生的事件
第一步 : 组合条件集
--AI状态条件集 : 各种AI通用的tick
--无论有无目标, 角色都会进入这些条件检查
--只要角色回到了出生点附近, 则清除'回家'的标志, 当角色被置上此标志时, 是不搜敌的
as_tick = {}
as_tick[aic_near_spawnpos] = ai_event_clear_gohome
--AI状态条件集 : 忘记目标
as_forget = {}
as_forget[1] = ai_event_clear_target --( 条件为1表示必然执行 )
--AI状态条件集 : 警戒
as_guard = {}
as_guard[aic_seek_target] = ai_event_find_target
--AI状态条件集 : 休息(随机移动)
as_idle = {}
as_idle[aic_rand_8_1] = ai_event_rand_move
--AI状态条件集 : 巡逻
--如果回到巡逻起点, 则开始在起点休息
--如果休息结束, 应该开始巡逻了, 则开始巡逻
--如果抵达巡逻目标点, 则在目标点开始休息
--巡逻的同时, 保持警戒
--巡逻内部子状态的说明:
--patrol_state = 0 表示可以开始前往巡逻目标点
--patrol_state = 1 正在前往目标点的路上
--patrol_state = 2 表示可以回到起始点
--patrol_state = 3 表示正在从回到起始点的路上
as_patrol = {}
as_patrol[aic_patrol_begin] = ai_event_patrol_begin
as_patrol[aic_patrol_arrive] = ai_event_patrol_end_idle
as_patrol[aic_patrol_return] = ai_event_patrol_return
as_patrol[aic_patrol_back_ok] = ai_event_patrol_start_idle
as_patrol[aic_seek_target] = ai_event_find_target
--AI状态条件集 : 追击
--如果距离出生点太远, 则往回走
--如果目标已经超出视野, 则清除目标
as_chase = {}
as_chase[aic_at_spawn_toofar]= ai_event_go_home
as_chase[aic_target_outofsight] = ai_event_clear_target
as_chase[aic_update_target] = ai_event_update_target
as_chase[1] = ai_event_use_skill
第二步. 编写具体的条件以及条件满足后产生的事件
这里的代码较多, 列举几个例子说明问题就好了, 总的原则是来自c/c++的接口函数我们称之为sdk, 脚本策划自己实现的函数我们称之为2次封装, 这些条件函数有的是各种AI都可以使用的, 有的是某种AI专用的. 来自[ai_condition.lua]
-------------------------------------通用条件列表-----------------------------------
--条件 : 角色位于出生点
function aic_at_spawnpos(c)
local x, y = GetChaSpawnPos(c)
if is_near_pos(c, x, y, 100)==1 then
return 1
end
return 0
end
--条件 : 距离出生点太远
function aic_at_spawn_toofar(c)
local chase_r = GetChaChaseRange(c)
local x, y = GetChaSpawnPos(c)
local now_x, now_y = GetChaPos(c)
local dis = (now_x - x) * (now_x - x) + (now_y - y) * (now_y - y)
if dis > chase_r * chase_r then
return 1
end
return 0
end
--条件 : 目标超出视野
function aic_target_outofsight(c)
local t = GetChaTarget(c) --取出当前角色的目标
local vision = GetChaVision(c) --取出角色的视野
if is_near(c, t, vision)==0 then --目标距离已经太远
return 1
end
return 0
end
--条件 : 发现目标
function aic_seek_target(c)
if is_moving_back(c)==1 then return 0 end
local t = find_target(c, 0) --没有目标, 则寻找一个, 没有找到则t为空
if t~=nil then
return t
end
return 0
end
……
下面代码来自[ai_event.lua]
--事件 : 发现目标
function ai_event_find_target(c, t)
SetChaTarget(c, t)
ai_event_use_skill(c)
end
--事件 : 随机移动
function ai_event_rand_move(c)
birth_rand_move(c, 600) –在周围6米的范围内随机移动
end
--事件 : 开始新一轮的巡逻
function ai_event_patrol_begin(c)
local px, py = GetChaPatrolPos(c) --取出巡逻点
ChaMove(c, px, py)
SetChaPatrolState(c, 1) --修改巡逻标记, 设置为移动中
end
--事件 : 回出生点
function ai_event_go_home(c)
clear_target(c) --清除目标
local x, y = GetChaSpawnPos(c)
ChaMoveToSleep(c, x, y)
set_moving_back(c, 1)
LG("ai_debug", "event go home", GetChaPatrolState(c))
end
--事件 : 清除目标
function ai_event_clear_target(c)
clear_target(c) --清除目标
end
--事件 : 目标更新(仇恨度相关检查)
function ai_event_update_target(c)
local t = GetChaTarget(c) --取出当前角色的目标
local tNew = GetChaFirstTarget(c) --通过伤害判断取得优先目标
if tNew~=nil and tNew~=t then
clear_target(c) --清除原目标
SetChaTarget(c, tNew) --设置新目标
return 1
end
return 0
end
--事件 : 对目标使用技能
function ai_event_use_skill(c)
local t = GetChaTarget(c) --取出当前角色的目标
local skill_id = select_skill(c) --怪物按照比率选择自己的技能
ChaUseSkill(c, t, skill_id) --向目标移动并使用技能
end
--事件 : 清除回家的状态
function ai_event_clear_gohome(c)
set_moving_back(c, 0)
if GetChaTypeID(c)==41 then
LG("ai_debug", "event clear gohome", GetChaPatrolState(c))
end
end
……
当需要扩充新的ai类型, 就重复以上的步骤:
1. 组合条件集
2. 编写具体的条件以及条件产生的事件
结束!
对于游戏中怪物的运行逻辑而言, 主要是检测出怪物此时的状态, 然后确定该状态下需要检测哪些行为条件, 每当符合一个行为条件, 就执行一个事件, 所以在实现AI的时候, 可以认为 状态 = 条件集合. 按照这种思路, 结合LUA独特的语法特点, 就可以把AI实现为如下的形式.
分享到:
相关推荐
"游戏脚本设计与实现" ...从提供的游戏脚本实例中,我们可以了解到游戏脚本设计的基本结构、游戏任务的设计、游戏机制的实现、游戏逻辑的编写、lua语言在游戏脚本中的应用、游戏脚本的优化和游戏脚本的测试等知识点。
SpringBoot+Redis 执行 Lua 脚本的方法步骤 以下是 SpringBoot+Redis 执行 Lua 脚本的方法步骤的知识点总结: 1. 背景:在开发中,我们需要一次性操作多个 Redis 命令,但是这些操作不具备原子性,而 Redis 的事务...
lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问文件哈哈哈lua脚本问...
json转lua脚本,全自动转换 快速读取
LUA脚本支持库|LUA脚本支持库
"基于Lua脚本语言的嵌入式UART通信的实现" 本文提出了一种基于Lua脚本语言的解决方案,旨在提高IED装置对各种类型串口数据报文帧格式的适应性。该方案将具体串口报文规约的组建和解析交给Lua脚本进行处理,使设计者...
Lua脚本支持库
Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用...
高并发场景:在高并发场景下,使用 Lua 脚本可以实现原子性操作,避免并发问题。 复杂业务逻辑:对于复杂的业务逻辑,使用 Lua 脚本可以简化代码,提高可读性和可维护性。 事务处理:使用 Lua 脚本可以实现事务处理...
《终极网络服务端编程》的lua server 实现了lua脚本处理服务端逻辑+数据库 lua服务端 c++版服务端客户端(netserver,netclient) lua服务端 就是 c++ netserver项目的lua脚本化版 运行效果 ![image]...
freeswitch LUA 脚本reference lua 脚本reference lua 开发脚本指南
delph调用lua脚本,在delphixe3下通过
用CEGUI结合lua脚本写的一个小的游戏界面 这个压缩包里面后缀名为lua是脚本信息 layout是界面,cpp和.h里面是具体怎么在window窗口上显示 登录界面和功能 CEGUI在编译前要把工作目录什么的都赔好!!
运行Lua脚本语句 运行Lua脚本文件 调用 Android API
项目实现的Lua脚本代码,有需要的朋友可以参考
本资源是一个关于LUA脚本语言的入门教程,旨在帮助读者快速掌握LUA语言的基础知识和语法。该教程由Roberto Ierusalimschy编写,www.luachina.net翻译。 一、LUA语言概述 LUA是一种轻量级的脚本语言,广泛应用于...
FCEUX Lua 脚本的模拟退火实现自动搜索 NES 输入序列。 用法 准备 FCEUX。 打开一个ROM。 打开 Lua 脚本。 停止 Lua 脚本。 打开 TAS 编辑器。 运行 Lua 脚本。 请注意,脚本不会按下 START 按钮。请手动按下开始...
LUa脚本编辑器
适用于lua脚本的解密