1. Fsm 称为 有限状态机,举个例子,游戏中的怪物称为NPC,NPC通常有几种状态,好比:静止,移动,死亡,被攻击,攻击英雄等等几个有限的状态,那么咱们就能够有限状态机实现NPC的状态变动。函数
一个有限状态机能够用一个关系式来描述,State(静止状态S1) x Event(英雄进入视野范围事件E) -> Actions(开始移动动做A), State(移动状态S2)设计
解释以下:当一个NPC处于静止状态S1,有一个英雄进入NPC视野范围时E,会触发NPC开始移动动做A,而且NPC转变状态为移动状态S2。code
对于一个用 gen_fsm 行为实现的FSM来讲,状态转换规则被写为符合以下约定的一系列Erlang函数:orm
StateName( Event, StateData ) ->游戏
.. 这里放动做的代码 ...事件
{ next_state, StateName', StateData' }it
2. 接下来咱们来看个例子,游戏中NPC状态变化,固然我作了很大的简化,真正游戏中的逻辑比这复杂的多。这里我只是为了说明,erlang OTP设计原则中的gen_fsm如何使用,代码以下:io
-module(npc).event
-behaviour(gen_fsm).form
%% API
-export([start_link/0]).
%% gen_fsm callbacks
-export([init/1, static/2, moving/2, handle_event/3,
handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-export([hero_join/0, hero_leave/0]).
-define(SERVER, ?MODULE).
-record(npc, {state}).
start_link() ->
gen_fsm:start_link({local, ?SERVER}, ?MODULE, [], []).
%% 初始化NPC为静止状态
init([]) ->
io:format("init...~n"),
State = #npc{state = static},
io:format("init State: ~p~n", [State]),
{ok, static, State}.
%% 英雄进入视野
hero_join() ->
gen_fsm:send_event(?SERVER, hero_join).
%% 英雄离开视野
hero_leave() ->
gen_fsm:send_event(?SERVER, hero_leave).
%% 静止状态下,接受来自客户端的事件
static(Event, State) ->
case Event of
hero_join -> %% 英雄进入视野
do_moving(), %% 执行动做
NewState = State#npc{state = moving},
io:format("npc set state: ~p~n", [NewState]),
{next_state, moving, NewState}
end.
%% 移动状态下,接受来自客户端的事件
moving(Event, State) ->
case Event of
hero_leave -> %% 英雄离开视野
do_static(), %% 执行动做
NewState = State#npc{state = static},
io:format("npc set state: ~p~n", [NewState]),
{next_state, static, NewState}
end.
handle_event(_Event, StateName, State) ->
{next_state, StateName, State}.
handle_sync_event(_Event, _From, StateName, State) ->
Reply = ok,
{reply, Reply, StateName, State}.
handle_info(_Info, StateName, State) ->
{next_state, StateName, State}.
terminate(_Reason, _StateName, _State) ->
ok.
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.
%% NPC 开始移动,进入移动状态
do_moving() ->
io:format("npc beigin moving...~n").
%% NPC 中止移动,进入静止状态
do_static() ->
io:format("npc stop moving, join static...~n").
代码注释比较详细,接下来能够经过运行代码,来好好理解下这个例子,
1. 首先,调用 npc:start_link(). 来初始化NPC服务;这个时候NPC处于静止状态 static;
2. 当npc处于静止状态时,咱们经过调用 npc:hero_join().来表示有一个侠客进入NPC的视野,那么这个时候gen_fsm会默认调用当前gen_fsm处于的状态,也就是static的处理方法,也就是 static(Event, State) 这个函数,这边可能比较绕,我已经尽可能去用直白的语言来表达,能力有限,你们多思考下,呵呵;
3. 当处理 static 函数时,Event 这个变量,就是 gen_fsm:send_event(?SERVER, hero_join). hero_join,紧接着执行对应的动做,在这里也就是 do_moving(),开始移动;
4. 最后,咱们须要返回 {next_state, moving, NewState} 让gen_fsm进入下一个状态,也就是 moving 状态;
5. 当npc处于移动时,咱们经过调用 npc:hero_leave(). 来表示 该侠客移动NPC的视野,那么对应的 moving(Event, State) 函数就会被调用,其余的处理与 static 时的处理是相似的,这里就不重复表述了。