英雄远征Erlang源码分析(8)-怪物相关

与怪物相关的模块有三个:mod_mon_create.erl,mod_mon_active.erl,lib_mon.erl
mod_mon_create:创建负责创建怪物的进程,通过mod_mon_create:create_mon([MonId, Scene, X, Y, Type])创建怪物进程

怪物创建进程的state
-record(state, {auto_id}).
用于保存怪物的自增id,每一个怪物id都不同

mod_mon_active负责创建怪物进程,每个怪物进程是一个有限状态机(gen_fsm)

怪物进程state保存当前怪物所追踪的玩家Pid列表,当前怪物的#ets_mon信息

在mod_mon_active:start([Id,MonId,Scene,X,Y,Type])中创建怪物进程,根据配置表和传入的参数,初始化一个#ets_mon,插入到?ETS_MON表中,进程进入sleep状态。

怪物进程的有限状态机主要有以下几种状态:
sleep:休眠状态,怪物进程被创建后为该状态,当有玩家进入追踪范围后会去跟随(trace)
trace:跟随状态,如果玩家进入攻击范围则发起战斗,否则继续跟随,或者玩家离开追踪范围,则返回出生点(back)
back:返回出生点,进入sleep状态
rerive:复活,进入sleep状态

sleep,trace状态中如果怪物Hp为0,则进入rerive状态。
怪物进程接收last_red_hp消息,收到该消息后会减少hp,当hp为0时,无论何种状态都进入revive

有限状态机大致图示:

初始化 -> sleep

sleep - timeout - 未死亡 - 附近有玩家 -> trace
sleep - timeout - 未死亡 - 附近没有玩家 -> sleep
sleep - timeout - 已死亡 -> revive

trace - timeout - 在攻击范围内 - mod_battle:battle/2发起战斗 -> trace
trace - timeout - 不足攻击范围 -trace_line - move -> trace
trace - timeout - 在追踪范围外 -> back
trace - timeout - 怪物死亡 -> revive

trace - repeat -> trace

back - timeout - 返回(瞬移)出生点 -> sleep

revive - timeout - #ets_mon.retime大于0 -> sleep
revive - timeout - #ets_mon.retime小于0 -> 关闭怪物进程

任何状态下 - 掉血 - 怪物死亡 -> revive
任何状态下 - 掉血 - 怪物未死亡 -> 状态不变

怪物进程中两个handle_info方法:
handle_info(clear, _StateName, [Att, Minfo]) 清除怪物,停止进程
handle_info({last_red_hp, Hp, _Pid}, StateName, [Att, Minfo]) 掉血,修改后的#ets_mon回写?ETS_MON

距离相关方法:

is_attack(Status,X,Y):判断是否进入攻击距离,根据#ets_mon.att_area判断

trace_area(Status,X,Y):判断是否进入追踪距离,根据#ets_mon.trace_area判断

trace_line(X1,Y1,X2,Y2,AttArea):计算追踪玩家所需要走的路线,返回移动的下一个坐标点,每次移动2格

move(X,Y,[Pid,Minfo]):怪物移动,判断区域是否有障碍,将怪物新坐标写回?ETS_MON

auto_move(Minfo):随机移动,每次走两格