|
加载中! 我是流子吗?我不知道,或许是吧......或许又不是......我真的不知道. |
|
在用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函数, 剩下的事情应该交给脚本策划了……虽然很残忍, 但是很清晰, 下面我们来看看脚本策划应该实现的部分: 下面我们来看看脚本策划应该实现的部分: --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
第二步. 编写具体的条件以及条件满足后产生的事件 --条件 : 角色位于出生点 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
--条件 : 距离出生点太远 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
--条件 : 目标超出视野 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
--条件 : 发现目标 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] ai_event_find_target(c, t) SetChaTarget(c, t) ai_event_use_skill(c) end --事件 : 随机移动 ai_event_rand_move(c) birth_rand_move(c, 600) –在周围6米的范围内随机移动 end --事件 : 开始新一轮的巡逻 ai_event_patrol_begin(c) local px, py = GetChaPatrolPos(c) --取出巡逻点 ChaMove(c, px, py) SetChaPatrolState(c, 1) --修改巡逻标记, 设置为移动中 end --事件 : 回出生点 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 --事件 : 清除目标 ai_event_clear_target(c) clear_target(c) --清除目标 end --事件 : 目标更新(仇恨度相关检查) 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
--事件 : 对目标使用技能 ai_event_use_skill(c) local t = GetChaTarget(c) --取出当前角色的目标 local skill_id = select_skill(c) --怪物按照比率选择自己的技能 ChaUseSkill(c, t, skill_id) --向目标移动并使用技能 end
--事件 : 清除回家的状态 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的时候, 可以认为 状态 = 条件集合. 按照这种思路, 结合LUA独特的语法特点, 就可以把AI实现为如下的形式. |
|
http://blog.sina.com.cn/s/blog_4b7f61c90100075u.html Java 2D游戏图像引擎 梦幻西游 lua脚本 梦幻西游脚本 |