瀏覽代碼

ft: 主模块重命令 依赖更换

master
SisMaker 4 年之前
父節點
當前提交
a4fb5e873a
共有 7 個檔案被更改,包括 212 行新增215 行删除
  1. +3
    -3
      README.md
  2. +1
    -1
      examples/action/action_skill_attack.erl
  3. +6
    -6
      examples/game_process.erl
  4. +2
    -2
      rebar.config
  5. +2
    -2
      src/core/base_node.erl
  6. +0
    -200
      src/core/behavior_tree.erl
  7. +198
    -1
      src/eBhv3.erl

+ 3
- 3
README.md 查看文件

@ -69,9 +69,9 @@ Build
Usage
----
{TitleMaps, TreeMaps, TreeNodeMaps} = behavior_tree:load_tree_file("example.json"),
{ok, RootID} = behavior_tree:init_btree_by_title(<<"example_ai"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{_BTStatus, _BTState1} = behavior_tree:execute(RootID, BTState = #{}).
{TitleMaps, TreeMaps, TreeNodeMaps} = eBhv3:load_tree_file("example.json"),
{ok, RootID} = eBhv3:init_btree_by_title(<<"example_ai"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{_BTStatus, _BTState1} = eBhv3:execute(RootID, BTState = #{}).
More
----

+ 1
- 1
examples/action/action_skill_attack.erl 查看文件

@ -18,7 +18,7 @@
tick(#{properties := Prop} = _BTree, #{uid := UID, rival_list := [RivalUID | _]} = State) ->
BTreeID = game_dict:get_passivity_btree_id(RivalUID),
RivalState = get_be_attacker_rival_state(Prop, UID, RivalUID),
{_, RivalState1} = behavior_tree:execute_sub_tree(BTreeID, RivalState),
{_, RivalState1} = eBhv3:execute_sub_tree(BTreeID, RivalState),
game_dict:put_role_state(RivalUID, RivalState1),
{?BT_SUCCESS, State}.

+ 6
- 6
examples/game_process.erl 查看文件

@ -24,7 +24,7 @@ start_link() ->
gen_server:start_link(?MODULE, [], []).
init([]) ->
{TitleMaps, TreeMaps, TreeNodeMaps} = behavior_tree:load_tree_file("examples/example.json"),
{TitleMaps, TreeMaps, TreeNodeMaps} = eBhv3:load_tree_file("examples/example.json"),
ZombieList = [
%% <<"HUNTER"/utf8>>,
@ -97,8 +97,8 @@ new_state(UID, Type, CurGrid) ->
State.
init_zombie([UID | T], TitleMaps, TreeMaps, TreeNodeMaps) ->
{ok, InitiativeBTreeID} = behavior_tree:init_btree_by_title(<<"丧尸主动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, PassivityBTreeID} = behavior_tree:init_btree_by_title(<<"丧尸被动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, InitiativeBTreeID} = eBhv3:init_btree_by_title(<<"丧尸主动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, PassivityBTreeID} = eBhv3:init_btree_by_title(<<"丧尸被动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
game_dict:put_initiative_btree_id(UID, InitiativeBTreeID),
game_dict:put_passivity_btree_id(UID, PassivityBTreeID),
Grid = {?RAND(0, ?MAX_X), ?RAND(0, ?MAX_Y)},
@ -108,8 +108,8 @@ init_zombie([], _TitleMaps, _TreeMaps, _TreeNodeMaps) ->
ok.
init_patrol(UID, TitleMaps, TreeMaps, TreeNodeMaps) ->
{ok, InitiativeBTreeID} = behavior_tree:init_btree_by_title(<<"巡逻兵主动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, PassivityBTreeID} = behavior_tree:init_btree_by_title(<<"巡逻兵被动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, InitiativeBTreeID} = eBhv3:init_btree_by_title(<<"巡逻兵主动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
{ok, PassivityBTreeID} = eBhv3:init_btree_by_title(<<"巡逻兵被动AI"/utf8>>, TitleMaps, TreeMaps, TreeNodeMaps),
game_dict:put_initiative_btree_id(UID, InitiativeBTreeID),
game_dict:put_passivity_btree_id(UID, PassivityBTreeID),
Grid = {?RAND(0, ?MAX_X), ?RAND(0, ?MAX_Y)},
@ -122,6 +122,6 @@ run(UID) ->
true ->
ok;
false ->
{_, State1} = behavior_tree:execute(BTreeID, State),
{_, State1} = eBhv3:execute(BTreeID, State),
game_dict:put_role_state(UID, State1)
end.

+ 2
- 2
rebar.config 查看文件

@ -1,9 +1,9 @@
{erl_opts, [debug_info, {i, "include"}
{erl_opts, [no_debug_info, {i, "include"}
%% {d, show_bt_log}, %% log_switch
]}.
{deps, [
{jsx, {git, "https://github.com/happyshiyu/jsx.git"}}
{jiffy, ".*", {git, "http://192.168.0.88:53000/SisMaker/jiffy.git", {branch, "master"}}}
]}.
{xref_checks, [

+ 2
- 2
src/core/base_node.erl 查看文件

@ -44,9 +44,9 @@ execute(NodeID, BTState) ->
%%
-spec do_init(bt_uid()|undefined, bt_node_id(), #{bt_node_id() => btree()}, tree_nodes()) -> {ok, bt_uid()}|{error, term()}.
do_init(ParentNodeID, BTNodeID, TreeMaps, TreeNodeMaps) ->
case behavior_tree:get_btree_node(BTNodeID, TreeNodeMaps) of
case eBhv3:get_btree_node(BTNodeID, TreeNodeMaps) of
#{name := Name, category := tree} ->
#{root := Root} = behavior_tree:get_btree(Name, TreeMaps),
#{root := Root} = eBhv3:get_btree(Name, TreeMaps),
do_init(ParentNodeID, Root, TreeMaps, TreeNodeMaps);
#{name := Name, children := Children} = BTNode ->
case code:ensure_loaded(Name) of

+ 0
- 200
src/core/behavior_tree.erl 查看文件

@ -1,200 +0,0 @@
-module(behavior_tree).
-include("eBhv3.hrl").
-export([
load_tree_file/1,
init_btree_by_title/4, init_btree/3,
execute/2, execute_child/2, close_btree_node/2, unload_btree/1
]).
-export([get_btree_id_by_title/2, get_btree/2, get_btree_node/2]).
%% @doc
%%
-spec load_tree_file(file:name_all()) -> {#{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()}|{error, term()}.
load_tree_file(JsonConfig) ->
case file:read_file(JsonConfig) of
{ok, Json} ->
JsonTerm = jsx:decode(Json, [return_maps]),
parse_btree(JsonTerm);
{error, Reason} ->
?BT_LOG("Error:~w Reason:~w JsonConfig:~w", [error, Reason, JsonConfig]),
{error, Reason}
end.
%% @doc
%% id
-spec get_btree_id_by_title(string(), #{string() => bt_node_id()}) -> bt_node_id()|undefined.
get_btree_id_by_title(Title, TitleMaps) ->
case TitleMaps of
#{Title := ID} ->
ID;
#{} ->
undefined
end.
%% @doc
%%
-spec get_btree(bt_node_id(), #{bt_node_id() => btree()}) -> btree()|undefined.
get_btree(BTNodeID, TreeMaps) ->
case TreeMaps of
#{BTNodeID := BTree} ->
BTree;
#{} ->
undefined
end.
%% @doc
%%
-spec get_btree_node(bt_node_id(), tree_nodes()) -> uninit_bt_node()|undefined.
get_btree_node(BTNodeID, TreeNodeMaps) ->
case TreeNodeMaps of
#{BTNodeID := BTNode} ->
BTNode;
#{} ->
undefined
end.
%% @doc
%%
-spec init_btree_by_title(string(), #{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()) -> {ok, bt_uid()}|{error, term()}.
init_btree_by_title(Title, TitleMaps, TreeMaps, TreeNodeMaps) ->
BTNodeID = get_btree_id_by_title(Title, TitleMaps),
init_btree(BTNodeID, TreeMaps, TreeNodeMaps).
%% @doc
%%
-spec init_btree(bt_node_id(), #{bt_node_id() => btree()}, tree_nodes()) -> {ok, bt_uid()}|{error, term()}.
init_btree(BTNodeID, TreeMaps, TreeNodeMaps) ->
#{root := Root} = behavior_tree:get_btree(BTNodeID, TreeMaps),
#{id := NodeID} = behavior_tree:get_btree_node(Root, TreeNodeMaps),
base_node:do_init(undefined, NodeID, TreeMaps, TreeNodeMaps).
%% @doc
%%
-spec execute(bt_uid(), bt_state()) -> {bt_status(), bt_state()}.
execute(NodeID, BTState) ->
BTState1 = blackboard:init_maps_keys(BTState),
case base_node:execute(NodeID, BTState1) of
{?BT_RUNNING, BTState2} ->
{?BT_RUNNING, BTState2};
{BTStatus, BTState2} ->
BTState3 = blackboard:erase_btree(BTState2),
{BTStatus, BTState3}
end.
%% @doc
%%
-spec execute_child(bt_uid(), bt_state()) -> {bt_status(), bt_state()}.
execute_child(NodeID, BTState) ->
base_node:execute(NodeID, BTState).
%% @doc
%%
-spec close_btree_node(bt_uid(), bt_state()) -> bt_state().
close_btree_node(NodeID, BTState) ->
BTState1 = do_close_btree_node(NodeID, BTState),
blackboard:erase_btree(BTState1).
%% @doc
%%
-spec unload_btree(bt_uid()) -> ok.
unload_btree(NodeID) ->
do_unload_btree_node(NodeID).
%%
-spec parse_btree(map()) -> {#{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()}.
parse_btree(#{<<"trees">> := Trees}) ->
parse_btree_1(Trees, #{}, #{}, #{}).
parse_btree_1([Node | T], TitleMaps, TreeMaps, TreeNodeMaps) ->
#{<<"id">> := ID, <<"title">> := Title, <<"root">> := Root, <<"nodes">> := Nodes} = Node,
Iterator = maps:iterator(Nodes),
{TreeNodes, TreeNodeMaps1} = parse_btree_node(maps:next(Iterator), #{}, TreeNodeMaps),
BTree = #{
id => ID,
root => Root,
properties => parse_properties(Node),
tree_nodes => TreeNodes
},
parse_btree_1(T, TitleMaps#{Title => ID}, TreeMaps#{ID => BTree}, TreeNodeMaps1);
parse_btree_1([], TitleMaps, TreeMaps, TreeNodeMaps) ->
{TitleMaps, TreeMaps, TreeNodeMaps}.
%%
-spec parse_btree_node({bt_node_id(), map(), maps:iterator()}|none, tree_nodes(), tree_nodes()) -> {tree_nodes(), tree_nodes()}.
parse_btree_node({ID, Node, NextIterator}, TreeNodes, TreeNodeMaps) ->
#{<<"name">> := Name, <<"category">> := Category} = Node,
case Category of
<<"tree">> ->
Name1 = Name;
_ ->
Name1 = name_convert(Name)
end,
TreeNode = #{
id => ID,
name => Name1,
category => binary_to_atom(Category, utf8),
properties => parse_properties(Node),
children => parse_children(Node)
},
parse_btree_node(maps:next(NextIterator), TreeNodes#{ID => TreeNode}, TreeNodeMaps#{ID => TreeNode});
parse_btree_node(none, TreeNodes, TreeNodeMaps) ->
{TreeNodes, TreeNodeMaps}.
%%
%% key会转为下划线分割小写atomvalue保持不变
-spec parse_properties(map()) -> properties().
parse_properties(#{<<"properties">> := Properties} = _Node) ->
Fun = fun(K, V, Map) -> Map#{name_convert(K) => V} end,
maps:fold(Fun, #{}, Properties).
%%
-spec parse_children(map()) -> [bt_node_id()].
parse_children(#{<<"child">> := Child} = _Node) ->
[Child];
parse_children(#{<<"children">> := Children} = _Node) ->
Children;
parse_children(_Node) ->
[].
%%
%% PlayerID -> player_id Name -> name
-spec name_convert(unicode:chardata()) -> atom().
name_convert(Name) ->
case name_convert_1(Name) of
<<"_"/utf8, NewName/binary>> ->
binary_to_atom(NewName, utf8);
NewName ->
binary_to_atom(NewName, utf8)
end.
name_convert_1(<<C/utf8, Other/binary>>) when $A =< C, C =< $Z ->
Other1 = name_convert_1(Other),
<<"_"/utf8, (C + 32)/utf8, Other1/binary>>;
name_convert_1(<<C/utf8, Other/binary>>) ->
Other1 = name_convert_1(Other),
<<C/utf8, Other1/binary>>;
name_convert_1(<<>>) ->
<<>>.
%%
-spec do_close_btree_node(bt_uid(), bt_state()) -> bt_state().
do_close_btree_node(NodeID, BTState) ->
BTNode = blackboard:get_btree_node(NodeID),
base_node:do_close(BTNode, BTState).
%%
-spec do_unload_btree_node(bt_uid()) -> ok.
do_unload_btree_node(NodeID) ->
#{children := Children} = blackboard:get_btree_node(NodeID),
do_unload_btree_node_1(Children),
blackboard:erase_btree_node(NodeID),
ok.
do_unload_btree_node_1([NodeID | T]) ->
do_unload_btree_node(NodeID),
do_unload_btree_node_1(T);
do_unload_btree_node_1([]) ->
ok.

+ 198
- 1
src/eBhv3.erl 查看文件

@ -1,3 +1,200 @@
-module(eBhv3).
-export([]).
-include("eBhv3.hrl").
-export([
load_tree_file/1,
init_btree_by_title/4, init_btree/3,
execute/2, execute_child/2, close_btree_node/2, unload_btree/1
]).
-export([get_btree_id_by_title/2, get_btree/2, get_btree_node/2]).
%% @doc
%%
-spec load_tree_file(file:name_all()) -> {#{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()}|{error, term()}.
load_tree_file(JsonConfig) ->
case file:read_file(JsonConfig) of
{ok, Json} ->
JsonTerm = jiffy:decode(Json, [return_maps]),
parse_btree(JsonTerm);
{error, Reason} ->
?BT_LOG("Error:~w Reason:~w JsonConfig:~w", [error, Reason, JsonConfig]),
{error, Reason}
end.
%% @doc
%% id
-spec get_btree_id_by_title(string(), #{string() => bt_node_id()}) -> bt_node_id()|undefined.
get_btree_id_by_title(Title, TitleMaps) ->
case TitleMaps of
#{Title := ID} ->
ID;
#{} ->
undefined
end.
%% @doc
%%
-spec get_btree(bt_node_id(), #{bt_node_id() => btree()}) -> btree()|undefined.
get_btree(BTNodeID, TreeMaps) ->
case TreeMaps of
#{BTNodeID := BTree} ->
BTree;
#{} ->
undefined
end.
%% @doc
%%
-spec get_btree_node(bt_node_id(), tree_nodes()) -> uninit_bt_node()|undefined.
get_btree_node(BTNodeID, TreeNodeMaps) ->
case TreeNodeMaps of
#{BTNodeID := BTNode} ->
BTNode;
#{} ->
undefined
end.
%% @doc
%%
-spec init_btree_by_title(string(), #{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()) -> {ok, bt_uid()}|{error, term()}.
init_btree_by_title(Title, TitleMaps, TreeMaps, TreeNodeMaps) ->
BTNodeID = get_btree_id_by_title(Title, TitleMaps),
init_btree(BTNodeID, TreeMaps, TreeNodeMaps).
%% @doc
%%
-spec init_btree(bt_node_id(), #{bt_node_id() => btree()}, tree_nodes()) -> {ok, bt_uid()}|{error, term()}.
init_btree(BTNodeID, TreeMaps, TreeNodeMaps) ->
#{root := Root} = eBhv3:get_btree(BTNodeID, TreeMaps),
#{id := NodeID} = eBhv3:get_btree_node(Root, TreeNodeMaps),
base_node:do_init(undefined, NodeID, TreeMaps, TreeNodeMaps).
%% @doc
%%
-spec execute(bt_uid(), bt_state()) -> {bt_status(), bt_state()}.
execute(NodeID, BTState) ->
BTState1 = blackboard:init_maps_keys(BTState),
case base_node:execute(NodeID, BTState1) of
{?BT_RUNNING, BTState2} ->
{?BT_RUNNING, BTState2};
{BTStatus, BTState2} ->
BTState3 = blackboard:erase_btree(BTState2),
{BTStatus, BTState3}
end.
%% @doc
%%
-spec execute_child(bt_uid(), bt_state()) -> {bt_status(), bt_state()}.
execute_child(NodeID, BTState) ->
base_node:execute(NodeID, BTState).
%% @doc
%%
-spec close_btree_node(bt_uid(), bt_state()) -> bt_state().
close_btree_node(NodeID, BTState) ->
BTState1 = do_close_btree_node(NodeID, BTState),
blackboard:erase_btree(BTState1).
%% @doc
%%
-spec unload_btree(bt_uid()) -> ok.
unload_btree(NodeID) ->
do_unload_btree_node(NodeID).
%%
-spec parse_btree(map()) -> {#{string() => bt_node_id()}, #{bt_node_id() => btree()}, tree_nodes()}.
parse_btree(#{<<"trees">> := Trees}) ->
parse_btree_1(Trees, #{}, #{}, #{}).
parse_btree_1([Node | T], TitleMaps, TreeMaps, TreeNodeMaps) ->
#{<<"id">> := ID, <<"title">> := Title, <<"root">> := Root, <<"nodes">> := Nodes} = Node,
Iterator = maps:iterator(Nodes),
{TreeNodes, TreeNodeMaps1} = parse_btree_node(maps:next(Iterator), #{}, TreeNodeMaps),
BTree = #{
id => ID,
root => Root,
properties => parse_properties(Node),
tree_nodes => TreeNodes
},
parse_btree_1(T, TitleMaps#{Title => ID}, TreeMaps#{ID => BTree}, TreeNodeMaps1);
parse_btree_1([], TitleMaps, TreeMaps, TreeNodeMaps) ->
{TitleMaps, TreeMaps, TreeNodeMaps}.
%%
-spec parse_btree_node({bt_node_id(), map(), maps:iterator()}|none, tree_nodes(), tree_nodes()) -> {tree_nodes(), tree_nodes()}.
parse_btree_node({ID, Node, NextIterator}, TreeNodes, TreeNodeMaps) ->
#{<<"name">> := Name, <<"category">> := Category} = Node,
case Category of
<<"tree">> ->
Name1 = Name;
_ ->
Name1 = name_convert(Name)
end,
TreeNode = #{
id => ID,
name => Name1,
category => binary_to_atom(Category, utf8),
properties => parse_properties(Node),
children => parse_children(Node)
},
parse_btree_node(maps:next(NextIterator), TreeNodes#{ID => TreeNode}, TreeNodeMaps#{ID => TreeNode});
parse_btree_node(none, TreeNodes, TreeNodeMaps) ->
{TreeNodes, TreeNodeMaps}.
%%
%% key会转为下划线分割小写atomvalue保持不变
-spec parse_properties(map()) -> properties().
parse_properties(#{<<"properties">> := Properties} = _Node) ->
Fun = fun(K, V, Map) -> Map#{name_convert(K) => V} end,
maps:fold(Fun, #{}, Properties).
%%
-spec parse_children(map()) -> [bt_node_id()].
parse_children(#{<<"child">> := Child} = _Node) ->
[Child];
parse_children(#{<<"children">> := Children} = _Node) ->
Children;
parse_children(_Node) ->
[].
%%
%% PlayerID -> player_id Name -> name
-spec name_convert(unicode:chardata()) -> atom().
name_convert(Name) ->
case name_convert_1(Name) of
<<"_"/utf8, NewName/binary>> ->
binary_to_atom(NewName, utf8);
NewName ->
binary_to_atom(NewName, utf8)
end.
name_convert_1(<<C/utf8, Other/binary>>) when $A =< C, C =< $Z ->
Other1 = name_convert_1(Other),
<<"_"/utf8, (C + 32)/utf8, Other1/binary>>;
name_convert_1(<<C/utf8, Other/binary>>) ->
Other1 = name_convert_1(Other),
<<C/utf8, Other1/binary>>;
name_convert_1(<<>>) ->
<<>>.
%%
-spec do_close_btree_node(bt_uid(), bt_state()) -> bt_state().
do_close_btree_node(NodeID, BTState) ->
BTNode = blackboard:get_btree_node(NodeID),
base_node:do_close(BTNode, BTState).
%%
-spec do_unload_btree_node(bt_uid()) -> ok.
do_unload_btree_node(NodeID) ->
#{children := Children} = blackboard:get_btree_node(NodeID),
do_unload_btree_node_1(Children),
blackboard:erase_btree_node(NodeID),
ok.
do_unload_btree_node_1([NodeID | T]) ->
do_unload_btree_node(NodeID),
do_unload_btree_node_1(T);
do_unload_btree_node_1([]) ->
ok.

Loading…
取消
儲存