<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>教程 &#8211; behaviac</title>
	<atom:link href="/language/zh/category/docs/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>Tencent behaviac, Game AI, Behavior Tree, Finite State Machine, Hierarchical Task Network, BT FSM HTN, 腾讯开源, 游戏AI, 行为树,有限状态机,分层任务网络</description>
	<lastBuildDate>Tue, 04 Jul 2017 03:19:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.4.1</generator>
	<item>
		<title>教程1：Hello Behaviac</title>
		<link>/tutorial_1_hello_behaviac/</link>
					<comments>/tutorial_1_hello_behaviac/#comments</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Tue, 20 Dec 2016 02:36:53 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1315</guid>

					<description><![CDATA[还未查看过文档《原理和流程》的请首先阅读该文档，以便了解behaviac组件的基本原理和工作流程。 本文档有视频和文字说明。两者内容是一致的，以便按需查看。 本<a class="moretag" href="/tutorial_1_hello_behaviac/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre style="text-align: left;">还未查看过文档《<a href="/workflow/">原理和流程</a>》的请首先阅读该文档，以便了解behaviac组件的基本原理和工作流程。

本文档有视频和文字说明。两者内容是一致的，以便按需查看。
本文档描述的是3.6及以后版本。对于3.5及以前的老版本请参考分类“3.5”。</pre>
<h2><span class="ez-toc-section" id="i">编辑器的使用</span></h2>
<h3><span class="ez-toc-section" id="i-2">新建工作区</span></h3>
<p>工作区用于管理整个项目的配置，包括一些位置和语言等参数。</p>
<h4><span class="ez-toc-section" id="i-3">视频</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_1_0.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p>打开编辑器，点击菜单项“文件”-&gt;“新建工作区”，弹出新建工作区窗口，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1569" src="/wp-content/uploads/2016/12/tutorial_1_cpp_workspace.png" alt="" width="587" height="272" srcset="/wp-content/uploads/2016/12/tutorial_1_cpp_workspace.png 587w, /wp-content/uploads/2016/12/tutorial_1_cpp_workspace-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<ul>
<li><strong>工作区位置：</strong>保存工作区文件的目录，在该目录下会保存出*.workspace.xml的文件，该文件即是编辑器打开的工作区文件（或者称之为项目文件）。</li>
<li><strong>行为树源位置：</strong>对既有服务器，又有客户端的项目开发，可能需要共用行为树，这时候只要为服务器和客户端分别创建工作区，然后为它们设置相同的“行为树源位置”即可。这样，只需要编辑同一份行为树，就可以让服务器和客户端的AI逻辑保持一致。此外，源位置中还自动生成behaviac_meta文件夹，里面保存了跟工作区同名但后缀名为*.meta.xml的类型信息文件。</li>
<li><strong>行为树导出位置：</strong>在该目录下，导出编辑好的行为树，并且需要在程序端设置的加载位置，以便程序运行起来后，加载所需的行为树。</li>
<li><strong>代码生成位置：</strong>用于存放后面将要描述的类型信息浏览器中编辑好的类型代码文件，还包含了一些“胶水”代码文件，都需要整合到运行时（游戏端）一起编译构建。</li>
<li><strong>程序端开发语言：</strong>可选cpp（即C++）和cs（即C#）两种，表示程序端的代码语言。结合上面所说的情况，可以支持服务器和客户端采用不同的语言编写代码，但共用同一份行为树数据。</li>
</ul>
<pre>“胶水”代码：是指编辑器自动生成的代码文件，用于注册类型信息，并用于程序端执行时通过名字或ID调用类的成员属性或方法。</pre>
<p>点击确认后，就可以创建自己的工作区。创建完工作区之后，后续如果需要修改工作区中的参数，可以通过菜单项“文件”-&gt;“编辑工作区”，重新打开上图所示的窗口来修改相关的参数。</p>
<p>另外，还可以直接打开为本教程建好的工作区。点击菜单项“文件”-&gt;“打开工作区”，找到安装或源码包目录中的<a href="https://github.com/Tencent/behaviac/tree/master/tutorials/tutorial_1/workspace">tutorials/tutorial_1/workspace</a>文件夹，打开tutorial_1_cpp.workspace.xml文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1570" src="/wp-content/uploads/2016/12/tutorial_1_workspace.png" alt="" width="268" height="207" /></p>
<h3><span class="ez-toc-section" id="i-4">编辑类型信息</span></h3>
<p>为了让行为树可以描述某个Agent类型的行为，首先需要创建自己的Agent子类。</p>
<h4><span class="ez-toc-section" id="i-5">视频</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_1_1.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p>通过菜单项“视图”-&gt;“类型信息”（或快捷键Ctrl+M），打开类型信息浏览器，可以看到当前类型列表中只有一个默认生成的behaviac::Agent基类，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1338" src="/wp-content/uploads/2016/12/empty_types.png" alt="empty_types" width="612" height="735" srcset="/wp-content/uploads/2016/12/empty_types.png 612w, /wp-content/uploads/2016/12/empty_types-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>点击右上角的“新增”按钮，弹出“新增类型”窗口，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1339" src="/wp-content/uploads/2016/12/first_agent.png" alt="first_agent" width="370" height="270" srcset="/wp-content/uploads/2016/12/first_agent.png 370w, /wp-content/uploads/2016/12/first_agent-300x219.png 300w" sizes="(max-width: 370px) 100vw, 370px" /></p>
<ul>
<li>将“类型”选择为“Agent”</li>
<li>将“名称”设置为“FirstAgent”</li>
<li>右上方的“生成代码?”默认是勾选上的，表示编辑器要自动生成该类型的代码文件，否则该类型代码需要手工编写</li>
<li>“生成位置”是生成该类型文件所在的文件夹，默认不用设置，表示默认生成在工作区中配置的“代码生成位置”里面</li>
</ul>
<p>点击“确定”按钮后，可以看到类型列表中有了“FirstAgent”这个类，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1340" src="/wp-content/uploads/2016/12/first_agent_methods.png" alt="first_agent_methods" width="612" height="735" srcset="/wp-content/uploads/2016/12/first_agent_methods.png 612w, /wp-content/uploads/2016/12/first_agent_methods-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>选中该“FirstAgent”类，并设置中部的 “成员类型”为“Method”，可以看到目前该类有六个来自behaviac::Agent基类的成员方法，方法名前面的“~”表示该方法是从基类继承过来的，如上图所示。</p>
<p>点击右侧的“新增”按钮，弹出“新增方法”窗口，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1341" src="/wp-content/uploads/2016/12/create_SayHello.png" alt="create_sayhello" width="562" height="343" srcset="/wp-content/uploads/2016/12/create_SayHello.png 562w, /wp-content/uploads/2016/12/create_SayHello-300x183.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></p>
<p>将新方法的“名字”设为“SayHello”，其他参数暂不用设置。</p>
<p>直接点击“确定”按钮，回到类型信息浏览器，可以看到“FirstAgent”类有了第一个自己添加的成员方法“SayHello”，其他几个带“~”的方法表示是从基类继承过来的成员方法，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1342" src="/wp-content/uploads/2016/12/first_method-1.png" alt="first_method" width="612" height="735" srcset="/wp-content/uploads/2016/12/first_method-1.png 612w, /wp-content/uploads/2016/12/first_method-1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>现在，我们有了第一个Agent子类的“FirstAgent”，以及它的成员方法“SayHello”。</p>
<p>点击右下方的“应用”按钮，自动生成类型和其他相关的“胶水”代码文件等。</p>
<p>点击左下方的“打开代码生成位置”按钮，可以查看生成的代码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1318" src="/wp-content/uploads/2016/12/generated_types.png" alt="generated_types" width="234" height="168" /></p>
<p>其中，behaviac_types.h需要包含到自己的代码中，以便使用自动生成的类型和“胶水”代码，如下代码所示：</p>
<pre>#include "behaviac_generated/types/behaviac_types.h"</pre>
<p>“internal”文件夹中包含了前面提及的类型和“胶水”代码，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1343" src="/wp-content/uploads/2016/12/generated_internal-1.png" alt="generated_internal" width="269" height="267" srcset="/wp-content/uploads/2016/12/generated_internal-1.png 269w, /wp-content/uploads/2016/12/generated_internal-1-150x150.png 150w" sizes="(max-width: 269px) 100vw, 269px" /></p>
<p>其中，behaviac_agent_member_visitor.h文件生成了用于访问类的私有属性和方法的“胶水”代码，behaviac_agent_meta.h/cpp文件生成了用于注册类及其属性、方法、实例等信息的“胶水”代码，这些“胶水”代码主要是为了程序端可以通过名字自动取用到类及其成员属性、方法及其实例等。</p>
<p>这些生成的代码需要添加到自己的项目中一起编译构建，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1344" src="/wp-content/uploads/2016/12/include_project-1.png" alt="include_project" width="286" height="247" /></p>
<h3><span class="ez-toc-section" id="i-6">创建行为树</span></h3>
<p>有了上面创建的Agent子类“FirstAgent”后，就可以开始创建和编辑行为树了。</p>
<h4><span class="ez-toc-section" id="i-7">视频</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_1_2.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p>如果对编辑器的按键操作不熟悉，请通过菜单项“帮助”-&gt;“起始页”，查看按键说明，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1346" src="/wp-content/uploads/2016/12/controls.png" alt="controls" width="646" height="612" srcset="/wp-content/uploads/2016/12/controls.png 646w, /wp-content/uploads/2016/12/controls-300x284.png 300w" sizes="(max-width: 646px) 100vw, 646px" /></p>
<p>点击工具栏中的“新建行为树”按钮，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1347" src="/wp-content/uploads/2016/12/new_bt-1.png" alt="new_bt" width="285" height="116" /></p>
<p>新建行为树后，将该行为树名字改为“FirstBT”，现在有了第一棵行为树，该树只有一个根节点，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1348" src="/wp-content/uploads/2016/12/first_bt-1.png" alt="first_bt" width="599" height="290" srcset="/wp-content/uploads/2016/12/first_bt-1.png 599w, /wp-content/uploads/2016/12/first_bt-1-300x145.png 300w" sizes="(max-width: 599px) 100vw, 599px" /></p>
<p>鼠标左键单击选中该根节点，为该节点的“Agent类型”设置为前面创建的“FirstAgent”，表示这棵行为树用来描述FirstAgent类的行为，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1198" src="/wp-content/uploads/2016/12/agent_type.png" sizes="(max-width: 475px) 100vw, 475px" srcset="/wp-content/uploads/2016/12/agent_type.png 475w, /wp-content/uploads/2016/12/agent_type-300x85.png 300w" alt="agent_type" width="475" height="135" /></p>
<p>设置完后，可以发现根节点已经具有类型“FirstAgent”，如下图所示：</p>
<div><img class="aligncenter size-full wp-image-1349" src="/wp-content/uploads/2016/12/root_node.png" alt="root_node" width="602" height="297" srcset="/wp-content/uploads/2016/12/root_node.png 602w, /wp-content/uploads/2016/12/root_node-300x148.png 300w" sizes="(max-width: 602px) 100vw, 602px" /></div>
<div></div>
<p>在左侧的节点列表中（如下图所示），用鼠标左键选中“动作”节点（或其他需要的节点）后，按住鼠标左键并拖拽该节点到右侧的主视口中，并将动作节点落在根节点右侧的黑色三角箭头处。</p>
<p><img class="aligncenter size-full wp-image-1199" src="/wp-content/uploads/2016/12/node_tree.png" sizes="(max-width: 170px) 100vw, 170px" srcset="/wp-content/uploads/2016/12/node_tree.png 170w, /wp-content/uploads/2016/12/node_tree-134x300.png 134w" alt="node_tree" width="170" height="381" /></p>
<p>拖拽完毕，可以看到行为树有了叶子节点“动作”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1350" src="/wp-content/uploads/2016/12/action_node.png" alt="action_node" width="874" height="294" srcset="/wp-content/uploads/2016/12/action_node.png 874w, /wp-content/uploads/2016/12/action_node-300x101.png 300w, /wp-content/uploads/2016/12/action_node-768x258.png 768w" sizes="(max-width: 874px) 100vw, 874px" /></p>
<p>选中该动作节点，在右侧“动作的属性”窗口中，为其选择成员方法“SayHello”，并将另一参数“决定状态的选项”设置为“Success”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1322" src="/wp-content/uploads/2016/12/action_properties.png" alt="action_properties" width="476" height="102" srcset="/wp-content/uploads/2016/12/action_properties.png 476w, /wp-content/uploads/2016/12/action_properties-300x64.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<p>如果想了解动作节点的更多细节，请参考文档《<a href="/language/zh/action/">动作节点</a>》。或者选中某个节点后，按F1键或右键菜单直接打开该节点的文档。</p>
<p>至此，我们得到了一棵最简单但是完整的行为树，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1351" src="/wp-content/uploads/2016/12/first_bt_tree-1.png" alt="first_bt_tree" width="876" height="293" srcset="/wp-content/uploads/2016/12/first_bt_tree-1.png 876w, /wp-content/uploads/2016/12/first_bt_tree-1-300x100.png 300w, /wp-content/uploads/2016/12/first_bt_tree-1-768x257.png 768w" sizes="(max-width: 876px) 100vw, 876px" /></p>
<h3><span class="ez-toc-section" id="i-8">导出行为树</span></h3>
<p>编辑完行为树后，需要导出全部行为树，以便程序端加载使用。</p>
<h4><span class="ez-toc-section" id="i-9">视频</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_1_3.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p>点击工具栏中的“导出全部”按钮，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1359" src="/wp-content/uploads/2016/12/export_all-1.png" alt="export_all" width="285" height="113" /></p>
<p>弹出“导出”窗口，在导出格式中暂只用勾选“Xml”，点击右下方的“导出”按钮，如下图所示： <img class="aligncenter size-full wp-image-1323" src="/wp-content/uploads/2016/12/export_bt.png" alt="export_bt" width="395" height="595" srcset="/wp-content/uploads/2016/12/export_bt.png 395w, /wp-content/uploads/2016/12/export_bt-199x300.png 199w" sizes="(max-width: 395px) 100vw, 395px" /></p>
<p>导出后，打开工作区中指定的导出目录，可以看到成功导出了FirstBT.xml文件和meta文件夹中的tutorial_1_cpp.meta.xml文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1571" src="/wp-content/uploads/2016/12/tutorial_1_cpp_exported.png" alt="" width="284" height="165" /></p>
<p>导出的FirstBT.xml文件就是交给程序端加载使用的行为树，tutorial_1_cpp.meta.xml文件是交给程序端加载使用的含有类型和自定义成员属性信息的文件。</p>
<h2><span class="ez-toc-section" id="i-10">运行时的使用</span></h2>
<h3><span class="ez-toc-section" id="i-11">编写并运行程序</span></h3>
<p>需要整合behaviac运行时库到自己的项目中来一起编译构建和运行行为树。<strong>如何编译构建behaviac运行时库，请参考文档《<a href="/language/zh/how_to_build/">如何编译构建</a>》。</strong></p>
<h4><span class="ez-toc-section" id="C">C++版</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_2.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p style="text-align: left;" align="center">对于自己的C++项目，需要包含behaviac库的inc目录（该inc目录位于源码压缩包的最顶级）。例如，对于Visual Studio项目，inc目录配置如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1387" src="/wp-content/uploads/2016/12/include_headers.png" alt="include_headers" width="718" height="582" srcset="/wp-content/uploads/2016/12/include_headers.png 718w, /wp-content/uploads/2016/12/include_headers-300x243.png 300w" sizes="(max-width: 718px) 100vw, 718px" /></p>
<p>同时还需要包含编译behaviac生成的lib文件。例如，对于Visual Studio项目，behaviac lib文件配置如下图所示</p>
<p><img class="aligncenter size-full wp-image-1388" src="/wp-content/uploads/2016/12/include_lib-1.png" alt="include_lib" width="722" height="589" srcset="/wp-content/uploads/2016/12/include_lib-1.png 722w, /wp-content/uploads/2016/12/include_lib-1-300x245.png 300w" sizes="(max-width: 722px) 100vw, 722px" /></p>
<p>将编辑器生成的Agent子类的类型和相关的“胶水”代码都整合到自己的项目中，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1572" src="/wp-content/uploads/2016/12/tutorial_1_cpp_project.png" alt="" width="372" height="324" srcset="/wp-content/uploads/2016/12/tutorial_1_cpp_project.png 372w, /wp-content/uploads/2016/12/tutorial_1_cpp_project-300x261.png 300w" sizes="(max-width: 372px) 100vw, 372px" /></p>
<p>在tutorial_1.cpp文件中，通过使用behaviac组件提供的API来体现行为树是如何加载和执行起来的。</p>
<p><strong>首先，在InitBehaviac()方法中初始化behaviac的加载目录和文件格式等，如下代码所示：</strong></p>
<pre>bool InitBehavic()
{
    LOGI("InitBehavic\n");

    behaviac::Workspace::GetInstance()-&gt;SetFilePath("../tutorials/tutorial_1/cpp/exported");

    behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_xml);

    return true;
}</pre>
<p>上面的几个接口说明如下：</p>
<ul>
<li>Workspace::SetFilePath()用于设置加载编辑器导出的行为树所在的目录。</li>
<li>Workspace::SetFileFormat()用于设置加载的行为树格式，这里用的是xml格式。</li>
</ul>
<p><strong>接着，创建Agent子类“FirstAgent”的实例，并加载指定的行为树，这里的行为树名字为“FirstBT”，如下代码所示：</strong></p>
<pre>bool InitPlayer()
{
    LOGI("InitPlayer\n");

    g_FirstAgent = behaviac::Agent::Create&lt;FirstAgent&gt;();

    bool bRet = g_FirstAgent-&gt;btload("FirstBT");

    g_FirstAgent-&gt;btsetcurrent("FirstBT");

    return bRet;
}</pre>
<p>上面的几个接口说明如下：</p>
<ul>
<li>Agent::Create()用于创建Agent子类的实例。</li>
<li>Agent::btload()用于加载行为树，入口参数是行为树的名字，不要加后缀。</li>
<li>Agent::btsetcurrent()用于指定当前准备执行的行为树。</li>
</ul>
<p><strong>其次，开始执行行为树，如下代码所示：</strong></p>
<pre>void UpdateLoop()
{
    LOGI("UpdateLoop\n");

    int frames = 0;
    behaviac::EBTStatus status = behaviac::BT_RUNNING;

    while (status == behaviac::BT_RUNNING)
    {
        LOGI("frame %d\n", ++frames);
        status = g_FirstAgent-&gt;btexec();
    }
}</pre>
<p>Agent::btexec()用于执行一次前面通过Agent::btsetcurrent()指定的行为树。</p>
<p>另外，如果不通过Agent::btexec()来单独执行行为树，也可以调用Workspace::Update()的方式来统一执行所有Agent实例的行为树，详见文章《<a href="/tutorial13_updateloop/">运行时端的执行流程</a>》。</p>
<p><strong>然后，对创建的Agent实例进行销毁释放，并清理整个工作区，如下代码所示：</strong></p>
<pre>void CleanupPlayer()
{
    LOGI("CleanupPlayer\n");

    behaviac::Agent::Destroy(g_FirstAgent);
}

void CleanupBehaviac()
{
    LOGI("CleanupBehaviac\n");

    behaviac::Workspace::GetInstance()-&gt;Cleanup();
}</pre>
<p><strong>最后，打开FirstAgent.cpp文件，并修改FirstAgent::SayHello()方法如下：</strong></p>
<pre>///&lt;&lt;&lt; THE METHOD HEAD
void FirstAgent::SayHello()
{
    ///&lt;&lt;&lt; BEGIN WRITING YOUR CODE
    printf("\nHello Behaviac!\n\n");
    ///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>注意：自己的代码需要添加在“///&lt;&lt;&lt; BEGIN WRITING YOUR CODE”和“///&lt;&lt;&lt; END WRITING YOUR CODE”之间，以便编辑器下次生成代码的时候，可以自动合并手工添加的内容和生成的内容。</p>
<p>编译并运行整个程序，执行结果如下：</p>
<p><img class="aligncenter size-full wp-image-1326" src="/wp-content/uploads/2016/12/exec_result.png" alt="exec_result" width="128" height="182" /></p>
<p>可以看到，程序结果输出了“Hello Behaviac!”，也就是成功执行了我们创建的第一棵最简单的行为树，并成功执行了动作节点配置的成员方法“SayHello”。</p>
<p>下载源码包后，打开projects目录中的工程文件behaviac.sln（Windows平台）或make文件（Linux平台），编译并执行tutorial_1项目，就可以看到上图的结果。</p>
<h4><span class="ez-toc-section" id="C-2">纯C#版</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_3.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p style="text-align: left;" align="center">本教程纯C#版的工作区文件是安装包目录下的tutorials/tutorial_1/workspace/tutorial_1_cs.workspace.xml，相关参数配置如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1573" src="/wp-content/uploads/2016/12/tutorial_1_cs_workspace.png" alt="" width="587" height="272" srcset="/wp-content/uploads/2016/12/tutorial_1_cs_workspace.png 587w, /wp-content/uploads/2016/12/tutorial_1_cs_workspace-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<p>对于自己的C#项目，需要包含behaviac库的所有运行时源码（在源码包的<a href="https://github.com/Tencent/behaviac/tree/master/integration/unity/Assets/Scripts/behaviac/runtime">integration\unity\Assets\Scripts\behaviac\runtime</a>文件夹中）整合进来，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1574" src="/wp-content/uploads/2016/12/tutorial_1_cs_project.png" alt="" width="199" height="288" /></p>
<p>将编辑器生成的Agent子类的类型和相关的“胶水”代码都整合到自己的项目中，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1575" src="/wp-content/uploads/2016/12/tutorial_1_cs2_project.png" alt="" width="219" height="345" srcset="/wp-content/uploads/2016/12/tutorial_1_cs2_project.png 219w, /wp-content/uploads/2016/12/tutorial_1_cs2_project-190x300.png 190w" sizes="(max-width: 219px) 100vw, 219px" /></p>
<p>为项目添加条件编译宏BEHAVIAC_NOT_USE_UNITY，表示用的是纯C#模式，没有使用Unity相关的API，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1446" src="/wp-content/uploads/2016/12/cs_marco.png" alt="cs_marco" width="678" height="167" srcset="/wp-content/uploads/2016/12/cs_marco.png 678w, /wp-content/uploads/2016/12/cs_marco-300x74.png 300w" sizes="(max-width: 678px) 100vw, 678px" /></p>
<p>在tutorial_1.cs文件中，通过使用behaviac组件提供的API来体现行为树是如何加载和执行起来的。</p>
<p><strong>首先，在InitBehaviac()方法中初始化behaviac的加载目录和文件格式等，如下代码所示：</strong></p>
<pre>static bool InitBehavic()
{
    Console.WriteLine("InitBehavic");

    behaviac.Workspace.Instance.FilePath = "../../exported";
    behaviac.Workspace.Instance.FileFormat = behaviac.Workspace.EFileFormat.EFF_xml;

    return true;
}</pre>
<p>上面的几个接口说明如下：</p>
<ul>
<li>Workspace.FilePath用于设置加载编辑器导出的行为树所在的目录。</li>
<li>Workspace.FileFormat用于设置加载的行为树格式，这里用的是xml格式。</li>
</ul>
<p><strong>接着，创建Agent子类“FirstAgent”的实例，并加载指定的行为树，这里的行为树名字为“FirstBT”，如下代码所示：</strong></p>
<pre>static bool InitPlayer()
{
    Console.WriteLine("InitPlayer");

    g_FirstAgent = new FirstAgent();

    bool bRet = g_FirstAgent.btload("FirstBT");
    Debug.Assert(bRet);

    g_FirstAgent.btsetcurrent("FirstBT");

    return bRet;
}</pre>
<p>上面的几个接口说明如下：</p>
<ul>
<li>Agent.btload()用于加载行为树，入口参数是行为树的名字，不要加后缀。</li>
<li>Agent.btsetcurrent()用于指定当前准备执行的行为树。</li>
</ul>
<p><strong>其次，开始执行行为树，如下代码所示：</strong></p>
<pre>static void UpdateLoop()
{
    Console.WriteLine("UpdateLoop");

    int frames = 0;
    behaviac.EBTStatus status = behaviac.EBTStatus.BT_RUNNING;

    while (status == behaviac.EBTStatus.BT_RUNNING)
    {
        Console.WriteLine("frame {0}", ++frames);

        status = g_FirstAgent.btexec();
    }
}</pre>
<p>Agent.btexec()用于执行一次前面通过Agent.btsetcurrent()指定的行为树。</p>
<p><strong>然后，对创建的Agent实例进行销毁释放，并清理整个工作区，如下代码所示：</strong></p>
<pre>static void CleanupPlayer()
{
    Console.WriteLine("CleanupPlayer");

    g_FirstAgent = null;
}

static void CleanupBehaviac()
{
    Console.WriteLine("CleanupBehaviac");

    behaviac.Workspace.Instance.Cleanup();
}</pre>
<p><strong>最后，打开FirstAgent.cs文件，并修改SayHello()方法如下：</strong></p>
<pre>///&lt;&lt;&lt; THE METHOD HEAD
public void SayHello()
{
    ///&lt;&lt;&lt; BEGIN WRITING YOUR CODE
    Console.WriteLine();
    Console.WriteLine("Hello Behaviac!");
    Console.WriteLine();
    ///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>注意：自己的代码需要添加在“///&lt;&lt;&lt; BEGIN WRITING YOUR CODE”和“///&lt;&lt;&lt; END WRITING YOUR CODE”之间，以便编辑器下次生成代码的时候，可以自动合并手工添加的内容和生成的内容。</p>
<p>编译并运行整个程序，执行结果如下：</p>
<p><img class="aligncenter size-full wp-image-1326" src="/wp-content/uploads/2016/12/exec_result.png" alt="exec_result" width="128" height="182" /></p>
<p>可以看到，程序结果输出了“Hello Behaviac!”，也就是成功执行了我们创建的第一棵最简单的行为树，并成功执行了动作节点配置的成员方法“SayHello”。</p>
<p>下载源码包后，打开<a href="https://github.com/Tencent/behaviac/tree/master/tutorials/CsTutorials">tutorials/CsTutorials</a>目录中的工程文件<a id="12bd5ecb3f1c6dd4105af1cf9b665687-972df3316d1408803517f097a5db6f87b6f44981" class="js-navigation-open" title="CsTutorials.sln" href="https://github.com/Tencent/behaviac/blob/master/tutorials/CsTutorials/CsTutorials.sln">CsTutorials.sln</a>，编译并执行tutorial_1项目，就可以看到上图的结果。</p>
<h4><span class="ez-toc-section" id="Unity_C">Unity C#版</span></h4>
<p align="center"><video src="http://dlied5.qq.com/behaviac/tutorial_0_4.mp4" controls="controls" width="640" height="480"><br />
您的浏览器不支持 video 标签。<br />
</video></p>
<p style="text-align: left;" align="center">打开Unity编辑器创建一个空的Unity项目，保存该项目，或者直接打开安装目录下的tutorials/tutorial_1/unity目录中的项目。</p>
<p>通过behaviac编辑器创建一个工作区（或者直接打开安装包目录下的Unity工作区文件<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_1/workspace/tutorial_1_unity.workspace.xml">tutorials/tutorial_1/workspace/tutorial_1_unity.workspace.xml</a>），相关参数配置如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1576" src="/wp-content/uploads/2016/12/tutorial_1_unity_workspace.png" alt="" width="587" height="272" srcset="/wp-content/uploads/2016/12/tutorial_1_unity_workspace.png 587w, /wp-content/uploads/2016/12/tutorial_1_unity_workspace-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<p>添加FirstAgent类及其成员方法SayHello()、创建和导出行为树FirstBT等流程跟上文相同。</p>
<p>导出整个工作区后，可以看到在目录<a href="https://github.com/Tencent/behaviac/tree/master/tutorials/tutorial_1/unity/Assets/Scripts/behaviac/behaviac_generated/types">tutorials\tutorial_1\unity\Assets\Scripts\behaviac\behaviac_generated\types</a>有了自动生成的源码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1433" src="/wp-content/uploads/2016/12/unity_export.png" alt="unity_export" width="273" height="201" /></p>
<p>在Unity编辑器中导入安装包目录下的behaviac运行时包integration/behaviac***.unitypackage。</p>
<p>打开整个项目的源码工程，可以看到有了behaviac的运行时库runtime和编辑器生成的源码behaviac_generated，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1434" src="/wp-content/uploads/2016/12/unity_code.png" alt="unity_code" width="277" height="384" srcset="/wp-content/uploads/2016/12/unity_code.png 277w, /wp-content/uploads/2016/12/unity_code-216x300.png 216w" sizes="(max-width: 277px) 100vw, 277px" /></p>
<p>打开FirstAgent.cs文件，添加代码如下：</p>
<p><strong>首先，在InitBehaviac()方法中初始化behaviac的加载目录和文件格式等，如下代码所示：</strong></p>
<pre>private static string ExportedFilePath
{
    get
    {
        string relativePath = "/Resources/behaviac/exported";

        if (Application.platform == RuntimePlatform.WindowsEditor) {
            return Application.dataPath + relativePath;
        }
        else if (Application.platform == RuntimePlatform.WindowsPlayer) {
            return Application.dataPath + relativePath;
        }
        else {
            return "Assets" + relativePath;
        }
    }
}

private bool InitBehavic()
{
    behaviac.Debug.LogWarning("InitBehavic");

    <strong>behaviac.Workspace.Instance.FilePath</strong> = ExportedFilePath;
    <strong>behaviac.Workspace.Instance.FileFormat</strong> = behaviac.Workspace.EFileFormat.EFF_xml;

    return true;
}</pre>
<p><strong>接着，加载指定的行为树，这里的行为树名字为“FirstBT”，如下代码所示：</strong></p>
<pre>private bool InitPlayer()
{
    behaviac.Debug.LogWarning("InitPlayer");

    bool bRet = this.btload("FirstBT");
    if (bRet)
    {
        this.btsetcurrent("FirstBT");
    }

    return bRet;
}</pre>
<p>在Awake()方法中调用InitBehavic和InitPlayer方法，如下代码所示：</p>
<pre>void Awake()
{
    InitBehavic();

    InitPlayer();
}</pre>
<p><strong>其次，在Update()方法中执行行为树，如下代码所示：</strong></p>
<pre>behaviac.EBTStatus _status = behaviac.EBTStatus.BT_RUNNING;

void Update()
{
    if (_status == behaviac.EBTStatus.BT_RUNNING)
    {
        behaviac.Debug.LogWarning("Update");

        _status = this.btexec();
     }
}</pre>
<p><strong>然后，修改SayHello()方法如下：</strong></p>
<pre>public void SayHello()
{
    ///&lt;&lt;&lt; BEGIN WRITING YOUR CODE SayHello
    behaviac.Debug.LogWarning("Hello Behaviac!");
    ///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>注意：自己的代码需要添加在“///&lt;&lt;&lt; BEGIN WRITING YOUR CODE”和“///&lt;&lt;&lt; END WRITING YOUR CODE”之间，以便编辑器下次生成代码的时候，可以自动合并手工添加的内容和生成的内容。</p>
<p>最后，在Unity编辑器中添加一个GameObject，并且为其添加脚本组件FirstAgent，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1435" src="/wp-content/uploads/2016/12/unity_component.png" alt="unity_component" width="390" height="151" srcset="/wp-content/uploads/2016/12/unity_component.png 390w, /wp-content/uploads/2016/12/unity_component-300x116.png 300w" sizes="(max-width: 390px) 100vw, 390px" /></p>
<p>在Unity编辑器中运行这个简单的程序，执行结果如下：</p>
<p><img class="aligncenter size-full wp-image-1436" src="/wp-content/uploads/2016/12/unity_output.png" alt="unity_output" width="262" height="176" /></p>
<p>下载源码包后，通过Unity编辑器打开并运行<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_1/unity">tutorials/tutorial_1/unity</a>目录中的项目，就可以看到上图的结果。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_1">tutorials/tutorial_1</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_1_hello_behaviac/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>教程1.1：编辑器生成类型代码的工作流程</title>
		<link>/tutorial_1_1_generate_codes/</link>
					<comments>/tutorial_1_1_generate_codes/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Tue, 07 Mar 2017 04:04:05 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1733</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 如《教程1：Hello Behaviac》所述，程序端的类型代码可以通过编辑器自<a class="moretag" href="/tutorial_1_1_generate_codes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>如《<a href="/tutorial_1_hello_behaviac/">教程1：Hello Behaviac</a>》所述，程序端的类型代码可以通过编辑器自动生成基本原型，然后在生成的代码模板上继续添加自己的逻辑代码。</p>
<p>本教程将详细介绍相关的具体操作步骤，包括：从创建Agent类型到生成其代码文件，并利用该Agent类型创建行为树，最后执行该行为树的流程。</p>
<h2><span class="ez-toc-section" id="1_Agent">1. 新建Agent类型</span></h2>
<p>通过编辑器的菜单项“视图”-&gt;“类型信息”（或快捷键Ctrl+M），打开类型信息浏览器，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1338" src="/wp-content/uploads/2016/12/empty_types.png" sizes="(max-width: 612px) 100vw, 612px" srcset="/wp-content/uploads/2016/12/empty_types.png 612w, /wp-content/uploads/2016/12/empty_types-250x300.png 250w" alt="empty_types" width="612" height="735" /></p>
<p>点击右上角的“新增”按钮，弹出“新增类型”窗口，添加FirstAgent类，勾选“生成代码”选项，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1774" src="/wp-content/uploads/2017/03/ZMJHZIMHCVT2V7O_@Q.png" alt="" width="368" height="268" srcset="/wp-content/uploads/2017/03/ZMJHZIMHCVT2V7O_@Q.png 368w, /wp-content/uploads/2017/03/ZMJHZIMHCVT2V7O_@Q-300x218.png 300w" sizes="(max-width: 368px) 100vw, 368px" /></p>
<p>更详细的类型信息编辑过程以及相关操作面板的参数说明，请参考文章《<a href="/edit_types/">编辑类型信息</a>》。</p>
<h2><span class="ez-toc-section" id="2">2. 新增成员属性</span></h2>
<p>为FirstAgent类添加int类型的成员属性p1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1677" src="/wp-content/uploads/2017/03/second_agent_p1.png" alt="" width="489" height="293" srcset="/wp-content/uploads/2017/03/second_agent_p1.png 489w, /wp-content/uploads/2017/03/second_agent_p1-300x180.png 300w" sizes="(max-width: 489px) 100vw, 489px" /></p>
<h2><span class="ez-toc-section" id="3">3. 新增成员方法</span></h2>
<p>再为FirstAgent类添加成员方法m1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1679" src="/wp-content/uploads/2017/03/second_agent_m1-1.png" alt="" width="562" height="343" srcset="/wp-content/uploads/2017/03/second_agent_m1-1.png 562w, /wp-content/uploads/2017/03/second_agent_m1-1-300x183.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></p>
<p>添加完FirstAgent类型及其成员属性和方法之后，可以在类型信息浏览器中看到如下所示：</p>
<p><img class="aligncenter size-full wp-image-1729" src="/wp-content/uploads/2017/03/tutorial_1_1_m1.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/03/tutorial_1_1_m1.png 612w, /wp-content/uploads/2017/03/tutorial_1_1_m1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="4">4. 修改成员</span></h2>
<p>如果修改了成员属性和方法，例如改名、加参数等操作后，只需点击右下方的“应用”按钮即可。</p>
<p>例如，将成员属性p1改名为p2，如下图所示：</p>
<p id="vBPmkxS"><img class="size-full wp-image-1742 aligncenter" src="/wp-content/uploads/2017/03/img_58be330b3e5b1.png" alt="" srcset="/wp-content/uploads/2017/03/img_58be330b3e5b1.png 612w, /wp-content/uploads/2017/03/img_58be330b3e5b1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="5">5. 生成代码</span></h2>
<p>点击右下方的“应用”按钮，在工作区配置的“代码生成位置”生成了类型及其相关的“胶水”代码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1734" src="/wp-content/uploads/2017/03/generated_types.png" alt="" width="234" height="168" /></p>
<p>在上图中的internal文件夹中生成了Agent类型及其“胶水”代码，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1735" src="/wp-content/uploads/2017/03/generated_internal2.png" alt="" width="256" height="265" /></p>
<p>需要将types文件夹中的所有代码文件都加到自己的项目中一起编译构建，并只需在程序端代码中包含头文件types/behaviac_types.h即可，其他“胶水”代码头文件不用包含，如下代码所示：</p>
<pre>#include "behaviac_generated/types/behaviac_types.h"</pre>
<h2><span class="ez-toc-section" id="6">6. 添加逻辑代码</span></h2>
<p>打开上面生成的FirstAgent.cpp文件，为FirstAgent::m1方法添加自己的逻辑代码。注意所有自己添加的代码都需要添加在注释“///&lt;&lt;&lt; BEGIN WRITING YOUR CODE”和“///&lt;&lt;&lt; END WRITING YOUR CODE”之间，如下代码所示：</p>
<pre>#include "FirstAgent.h"

///&lt;&lt;&lt; BEGIN WRITING YOUR CODE FILE_INIT

///&lt;&lt;&lt; END WRITING YOUR CODE

FirstAgent::FirstAgent()
{
    p1 = 0;
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE CONSTRUCTOR

///&lt;&lt;&lt; END WRITING YOUR CODE
}

FirstAgent::~FirstAgent()
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE DESTRUCTOR

///&lt;&lt;&lt; END WRITING YOUR CODE
}

void FirstAgent::m1(behaviac::string&amp; value)
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE m1
    printf("\n%s\n\n", value.c_str());
///&lt;&lt;&lt; END WRITING YOUR CODE
}

///&lt;&lt;&lt; BEGIN WRITING YOUR CODE FILE_UNINIT

///&lt;&lt;&lt; END WRITING YOUR CODE</pre>
<p>如果在类型信息浏览器中将成员方法m1改名为m2，点击右下方的“应用”按钮，重新生成代码，上面代码中的m1会自动变为m2，在BEGIN和END之间的手写代码不会改变，会自动保留。</p>
<h2><span class="ez-toc-section" id="7">7. 添加行为树</span></h2>
<p>利用新加的FirstAgent类及其成员属性和方法，添加行为树“FirstBT”，如下图所示：</p>
<p id="nDoLHXC"><img class="size-full wp-image-1737 aligncenter" src="/wp-content/uploads/2017/03/img_58be2d939f783.png" alt="" srcset="/wp-content/uploads/2017/03/img_58be2d939f783.png 849w, /wp-content/uploads/2017/03/img_58be2d939f783-300x102.png 300w, /wp-content/uploads/2017/03/img_58be2d939f783-768x261.png 768w" sizes="(max-width: 849px) 100vw, 849px" /></p>
<h2><span class="ez-toc-section" id="8">8. 执行行为树</span></h2>
<p>加载并执行该行为树，可以看到输出结果如下图所示：</p>
<p id="iyDmJKn"><img class="size-full wp-image-1738 aligncenter" src="/wp-content/uploads/2017/03/img_58be2ff985e5c.png" alt="" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_1_1">tutorials/tutorial_1_1</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_1_1_generate_codes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程1.2：手工编写类型代码的工作流程</title>
		<link>/tutorial_1_2_write_codes/</link>
					<comments>/tutorial_1_2_write_codes/#comments</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Tue, 07 Mar 2017 09:02:50 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1745</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 在《教程1.1：编辑器生成类型代码的工作流程》中，介绍了通过编辑器自动生成类型代<a class="moretag" href="/tutorial_1_2_write_codes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>在《<a href="/language/zh/tutorial_1_1_generate_codes/">教程1.1：编辑器生成类型代码的工作流程</a>》中，介绍了通过编辑器自动生成类型代码的基本原型，然后在生成的代码模板上继续添加自己的逻辑代码。</p>
<p>而对于习惯手工编写代码，或已经有了大量手工编写的类型代码（如从老版本升级到3.6新版本），可以依然使用原来的代码，但需要在编辑器中创建对应的类型信息。</p>
<p>本教程详细介绍相关的具体步骤，包括：从创建Agent类型到手工编辑代码文件，并利用该Agent类型创建行为树，最后执行该行为树的结果。</p>
<h2><span class="ez-toc-section" id="1_Agent">1. 新建Agent类型</span></h2>
<p>首先需要在编辑器中创建跟程序端同名的Agent类型。</p>
<p>通过编辑器的菜单项“视图”-&gt;“类型信息”（或快捷键Ctrl+M），打开类型信息浏览器，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1338" src="/wp-content/uploads/2016/12/empty_types.png" sizes="(max-width: 612px) 100vw, 612px" srcset="/wp-content/uploads/2016/12/empty_types.png 612w, /wp-content/uploads/2016/12/empty_types-250x300.png 250w" alt="empty_types" width="612" height="735" /></p>
<p>点击右上角的“新增”按钮，弹出“新增类型”窗口，添加SecondAgent类，不要勾选“生成代码”选项，如下图所示：</p>
<p id="cXfcXis"><img class="aligncenter size-full wp-image-1776" src="/wp-content/uploads/2017/03/N_3QM45CYYZI2QB2R7.png" alt="" width="367" height="269" srcset="/wp-content/uploads/2017/03/N_3QM45CYYZI2QB2R7.png 367w, /wp-content/uploads/2017/03/N_3QM45CYYZI2QB2R7-300x220.png 300w" sizes="(max-width: 367px) 100vw, 367px" /></p>
<p>详细的类型信息编辑过程以及相关操作面板的参数说明，请参考文章《<a href="/edit_types/">编辑类型信息</a>》。</p>
<h2><span class="ez-toc-section" id="2">2. 新增成员属性</span></h2>
<p>为SecondAgent类添加int类型的成员属性p1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1677" src="/wp-content/uploads/2017/03/second_agent_p1.png" alt="" width="489" height="293" srcset="/wp-content/uploads/2017/03/second_agent_p1.png 489w, /wp-content/uploads/2017/03/second_agent_p1-300x180.png 300w" sizes="(max-width: 489px) 100vw, 489px" /></p>
<h2><span class="ez-toc-section" id="3">3. 新增成员方法</span></h2>
<p>再为SecondAgent类添加成员方法m1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1679" src="/wp-content/uploads/2017/03/second_agent_m1-1.png" alt="" width="562" height="343" srcset="/wp-content/uploads/2017/03/second_agent_m1-1.png 562w, /wp-content/uploads/2017/03/second_agent_m1-1-300x183.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></p>
<p>添加完SecondAgent类型及其成员属性和方法之后，可以在类型信息浏览器中看到如下所示：</p>
<p id="SRVWxpY"><img class="size-full wp-image-1750 aligncenter" src="/wp-content/uploads/2017/03/img_58be6912ed3c2.png" alt="" srcset="/wp-content/uploads/2017/03/img_58be6912ed3c2.png 612w, /wp-content/uploads/2017/03/img_58be6912ed3c2-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="4">4. 修改成员</span></h2>
<p>如果修改了成员属性和方法，例如改名、加参数等操作后，只需点击右下方的“应用”按钮即可。</p>
<p>例如，将成员属性p1改名为p2，如下图所示：</p>
<p id="bXEXlzm"><img class="size-full wp-image-1751 aligncenter" src="/wp-content/uploads/2017/03/img_58be693c70aec.png" alt="" srcset="/wp-content/uploads/2017/03/img_58be693c70aec.png 612w, /wp-content/uploads/2017/03/img_58be693c70aec-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="5">5. 生成“胶水”代码</span></h2>
<p>点击右下方的“应用”按钮，在工作区配置的“代码生成位置”生成了“胶水”代码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1734" src="/wp-content/uploads/2017/03/generated_types.png" alt="" width="234" height="168" /></p>
<p>在上图中的internal文件夹中生成了Agent类型的“胶水”代码，但并没有生成SecondAgent类型本身的代码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1753" src="/wp-content/uploads/2017/03/AH3V7_YC95HUDH_R_0.png" alt="" width="260" height="229" /></p>
<p>需要将types文件夹中的所有代码文件都加到自己的项目中一起编译构建，并只需在程序端代码中包含头文件types/behaviac_types.h即可，其他“胶水”代码头文件不用包含，如下代码所示：</p>
<pre>#include "behaviac_generated/types/behaviac_types.h"</pre>
<h2><span class="ez-toc-section" id="6">6. 添加类型代码</span></h2>
<p>在代码项目中手工添加SecondAgent.h/.cpp文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1755" src="/wp-content/uploads/2017/03/4Y4SEE1S06MG0AWNV50.png" alt="" width="201" height="254" /></p>
<p>为了提高手工编写代码的效率并<strong>保持与编辑器中定义的一致性</strong>，请点击类型信息浏览器中的“预览原型代码”按钮，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1756" src="/wp-content/uploads/2017/03/CF_L3HI43674KSL6LFFEG.png" alt="" width="609" height="236" srcset="/wp-content/uploads/2017/03/CF_L3HI43674KSL6LFFEG.png 609w, /wp-content/uploads/2017/03/CF_L3HI43674KSL6LFFEG-300x116.png 300w" sizes="(max-width: 609px) 100vw, 609px" /></p>
<p>可以看到SecondAgent类的原型代码如下所示，复制粘贴需要的类型、成员属性或方法的申明代码到自己的SecondAgent.h头文件中：</p>
<pre>#ifndef _BEHAVIAC_SECONDAGENT_H_
#define _BEHAVIAC_SECONDAGENT_H_

#include "behaviac_headers.h"

class SecondAgent : public behaviac::Agent
{
public:
    SecondAgent();

    virtual ~SecondAgent();

    BEHAVIAC_DECLARE_AGENTTYPE(SecondAgent, behaviac::Agent)

private: int p1;

private: void m1(behaviac::string&amp; value);

};

#endif</pre>
<p>在SecondAgent.cpp中实现该类的各个方法如下所示：</p>
<pre>#include "SecondAgent.h"

SecondAgent::SecondAgent()
    : p1(0)
{
}

SecondAgent::~SecondAgent()
{
}

void SecondAgent::m1(behaviac::string&amp; value)
{
    printf("\n%s\n\n", value.c_str());
}</pre>
<p>在类型信息浏览器中点击右上方的”设置头文件“，添加刚才手工新建的SecondAgent类的头文件路径，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1784" src="/wp-content/uploads/2017/03/VNTEOT06BV8_AAV6NCKAH.png" alt="" width="519" height="267" srcset="/wp-content/uploads/2017/03/VNTEOT06BV8_AAV6NCKAH.png 519w, /wp-content/uploads/2017/03/VNTEOT06BV8_AAV6NCKAH-300x154.png 300w" sizes="(max-width: 519px) 100vw, 519px" /></p>
<p>这样在生成的types/internal/behaviac_headers.h文件中，就自动包含了上面添加的SecondAgent.h头文件，如下代码所示：</p>
<pre>#ifndef _BEHAVIAC_HEADERS_H_
#define _BEHAVIAC_HEADERS_H_

#include "behaviac/behaviac.h"

// YOU SHOULD SET THE HEADER FILES OF YOUR GAME WHEN EXPORTING CPP FILES ON THE BEHAVIAC EDITOR:
#include "../../../SecondAgent.h"

#endif // _BEHAVIAC_HEADERS_H_</pre>
<p>注意上图中左下方的选项“生成代码时使用相对路径”，该选项用于生成上述包含头文件时，是否生成相对路径。</p>
<p>如果已经在自己的代码项目中设置了包含路径，可以不勾选该选项，生成的代码如下所示：</p>
<pre>#ifndef _BEHAVIAC_HEADERS_H_
#define _BEHAVIAC_HEADERS_H_

#include "behaviac/behaviac.h"

// YOU SHOULD SET THE HEADER FILES OF YOUR GAME WHEN EXPORTING CPP FILES ON THE BEHAVIAC EDITOR:
#include "SecondAgent.h"

#endif // _BEHAVIAC_HEADERS_H_</pre>
<h2><span class="ez-toc-section" id="7">7. 手工编辑类型信息</span></h2>
<p>有的程序员可能不喜欢使用类型信息浏览器来编辑类型信息，那么可以编写自己的导出工具或者直接手工编辑类型信息文件*.meta.xml。</p>
<p>该文件保存在工作区配置的“行为树源位置”中的behaviac_meta文件夹中，例如本教程对应的类型信息文件tutorial_1_2_cpp.meta.xml就在源码包tutorials/tutorial_1_2/workspace/behaviors/behaviac_meta目录下，该文件的内容如下：</p>
<p><img class="aligncenter size-full wp-image-1767" src="/wp-content/uploads/2017/03/8J8NL0R4A67G0CX3.png" alt="" width="980" height="496" srcset="/wp-content/uploads/2017/03/8J8NL0R4A67G0CX3.png 980w, /wp-content/uploads/2017/03/8J8NL0R4A67G0CX3-300x152.png 300w, /wp-content/uploads/2017/03/8J8NL0R4A67G0CX3-768x389.png 768w" sizes="(max-width: 980px) 100vw, 980px" /></p>
<p>可以手工编辑该文件，根据自己的需要添加或修改自己的类型信息，但需要确保内容格式跟上图保持一致，没有任何错误，否则会加载失败。</p>
<p>此外，编辑器还支持加载多个类型信息文件，支持混用编辑器编辑的类型信息和通过自己编写导出工具或手工编辑生成的类型信息这两种方式，那么可以将自己生成的*.meta.xml文件，也放在行为树源位置中的behaviac_meta目录里，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1768" src="/wp-content/uploads/2017/03/2TP6N2E2VD7A6SM2U.png" alt="" width="208" height="166" /></p>
<p>重新加载工作区后，会弹出如下提示窗口：</p>
<p id="DcUtgIe"><img class="size-full wp-image-1765 aligncenter" src="/wp-content/uploads/2017/03/img_58be862955972.png" alt="" srcset="/wp-content/uploads/2017/03/img_58be862955972.png 450w, /wp-content/uploads/2017/03/img_58be862955972-300x113.png 300w" sizes="(max-width: 450px) 100vw, 450px" /></p>
<p>如果没有弹出上述提示窗口，说明已经合并过多个类型信息文件，可以打开工作区文件tutorial_1_2_cpp.workspace.xml，并修改promptmergingmeta的值为&#8221;false&#8221;，如下图所示：</p>
<p id="TLuyFmk"><img class="aligncenter size-full wp-image-1769" src="/wp-content/uploads/2017/03/F4E714S7R_DDVXBXEAA4E.png" alt="" width="1159" height="266" srcset="/wp-content/uploads/2017/03/F4E714S7R_DDVXBXEAA4E.png 1159w, /wp-content/uploads/2017/03/F4E714S7R_DDVXBXEAA4E-300x69.png 300w, /wp-content/uploads/2017/03/F4E714S7R_DDVXBXEAA4E-768x176.png 768w, /wp-content/uploads/2017/03/F4E714S7R_DDVXBXEAA4E-1024x235.png 1024w" sizes="(max-width: 1159px) 100vw, 1159px" /></p>
<p>重新加载工作区，会再次弹出上述提示窗口。点击”是(Y)“，编辑器会自动合并多个类型信息文件。</p>
<p>这样，在类型信息浏览器中就可以查看手工编辑的所有类型信息，并在行为树中使用这些类型信息了。</p>
<h2><span class="ez-toc-section" id="8">8. 添加行为树</span></h2>
<p>利用新加的SecondAgent类及其成员属性和方法，添加行为树&#8221;SecondBT&#8221;，如下图所示：<img class="aligncenter size-full wp-image-1758" src="/wp-content/uploads/2017/03/RLZW3DYRV77JR4GKH_3B.png" alt="" width="905" height="283" srcset="/wp-content/uploads/2017/03/RLZW3DYRV77JR4GKH_3B.png 905w, /wp-content/uploads/2017/03/RLZW3DYRV77JR4GKH_3B-300x94.png 300w, /wp-content/uploads/2017/03/RLZW3DYRV77JR4GKH_3B-768x240.png 768w" sizes="(max-width: 905px) 100vw, 905px" /></p>
<h2><span class="ez-toc-section" id="9">9. 执行行为树</span></h2>
<p>加载并执行该行为树，可以看到输出结果如下图所示：</p>
<p id="TzfBzAW"><img class="size-full wp-image-1759 aligncenter" src="/wp-content/uploads/2017/03/img_58be770452f3d.png" alt="" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_1_2">tutorials/tutorial_1_2</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_1_2_write_codes/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>教程2：让行为树丰富起来</title>
		<link>/tutorial_2_more_nodes/</link>
					<comments>/tutorial_2_more_nodes/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Fri, 20 Jan 2017 04:08:48 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1492</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 类似于任何一种程序语言的基本语法，behaviac组件也提供了基本的赋值、条件、<a class="moretag" href="/tutorial_2_more_nodes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>类似于任何一种程序语言的基本语法，behaviac组件也提供了基本的赋值、条件、循环、序列、选择等基本节点。有了《<a href="/tutorial_1_hello_behaviac/">教程1：Hello Behaviac</a>》的基本介绍，本教程将引入这些常用的复合节点，以便将行为树编辑得更加丰富多彩。</p>
<p>用编辑器打开本教程C++版的工作区文件<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_2/workspace/tutorial_2_cpp.workspace.xml">tutorial_2_cpp.workspace.xml</a>（而C#版工作区文件是<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_2/workspace/tutorial_2_cs.workspace.xml">tutorial_2_cs.workspace.xml</a>），如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1578" src="/wp-content/uploads/2017/01/tutorial_2_cpp_workspace.png" alt="" width="587" height="272" srcset="/wp-content/uploads/2017/01/tutorial_2_cpp_workspace.png 587w, /wp-content/uploads/2017/01/tutorial_2_cpp_workspace-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<p>注意：本教程延用了《<a href="/tutorial_1_hello_behaviac/">教程一</a>》的FirstAgent子类及其成员方法SayHello等类型信息，可以参考《<a href="/tutorial_1_hello_behaviac/">教程一</a>》的做法，打开类型信息浏览器创建该子类。此外，还为FirstAgent子类添加了int类型的成员属性p1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1493" src="/wp-content/uploads/2017/01/p1.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/01/p1.png 612w, /wp-content/uploads/2017/01/p1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>参考《<a href="/tutorial_1_hello_behaviac/">教程一</a>》的做法，点击上图中右下方的“应用”按钮，生成“胶水”代码，并将这些代码整合到项目tutorial_2中，并添加tutorial_2.cpp文件用于使用behaviac的相关接口来加载和执行行为树，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1579" src="/wp-content/uploads/2017/01/tutorial_2_cpp_project.png" alt="" width="378" height="343" srcset="/wp-content/uploads/2017/01/tutorial_2_cpp_project.png 378w, /wp-content/uploads/2017/01/tutorial_2_cpp_project-300x272.png 300w" sizes="(max-width: 378px) 100vw, 378px" /></p>
<h2><span class="ez-toc-section" id="i">循环节点</span></h2>
<p>循环节点类似于程序语言中的for或while循环，用于重复执行某个操作。</p>
<p>新建行为树“LoopBT”，将根节点的Agent类型设置为“FirstAgent”，并为其添加循环和动作节点，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1495" src="/wp-content/uploads/2017/01/loop_node.png" alt="" width="130" height="370" srcset="/wp-content/uploads/2017/01/loop_node.png 130w, /wp-content/uploads/2017/01/loop_node-105x300.png 105w" sizes="(max-width: 130px) 100vw, 130px" /></p>
<p><img class="aligncenter size-full wp-image-1496" src="/wp-content/uploads/2017/01/loop_bt.png" alt="" width="828" height="137" srcset="/wp-content/uploads/2017/01/loop_bt.png 828w, /wp-content/uploads/2017/01/loop_bt-300x50.png 300w, /wp-content/uploads/2017/01/loop_bt-768x127.png 768w" sizes="(max-width: 828px) 100vw, 828px" /></p>
<p>选中循环节点，将其参数“次数”设置为3，其他参数暂不用设置，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1497" src="/wp-content/uploads/2017/01/loop_properties.png" alt="" width="474" height="213" srcset="/wp-content/uploads/2017/01/loop_properties.png 474w, /wp-content/uploads/2017/01/loop_properties-300x135.png 300w" sizes="(max-width: 474px) 100vw, 474px" /></p>
<p>选中动作节点，为其选择“SayHello”方法，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1322" src="/wp-content/uploads/2016/12/action_properties.png" alt="" width="476" height="102" srcset="/wp-content/uploads/2016/12/action_properties.png 476w, /wp-content/uploads/2016/12/action_properties-300x64.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<p>导出、加载并执行该行为树“LoopBT”，得到如下图所示的结果：</p>
<p><img class="aligncenter size-full wp-image-1498" src="/wp-content/uploads/2017/01/loop_bt_result.png" alt="" width="157" height="210" /></p>
<p>可以看到输出了3次“Hello Behaviac!”，这是我们预期的结果。</p>
<p>如果想了解循环节点其他参数的用法，请选中循环节点，并按F1键，会自动打开该节点的使用手册。</p>
<p>此外，循环直到节点类似于循环节点，两者的差别可以参考手册《<a href="/language/zh/decorator/#loopuntil">循环直到节点</a>》和《<a href="/language/zh/decorator/#loop">循环节点</a>》。</p>
<h2><span class="ez-toc-section" id="i-2">赋值节点</span></h2>
<p>新建行为树“SequenceBT”，将根节点的Agent类型设置为“FirstAgent”，并为其依次添加序列、赋值、条件和动作节点，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1500" src="/wp-content/uploads/2017/01/sequence_bt_nodes.png" alt="" width="121" height="371" srcset="/wp-content/uploads/2017/01/sequence_bt_nodes.png 121w, /wp-content/uploads/2017/01/sequence_bt_nodes-98x300.png 98w" sizes="(max-width: 121px) 100vw, 121px" /></p>
<p><img class="aligncenter size-full wp-image-1501" src="/wp-content/uploads/2017/01/sequence_bt.png" alt="" width="853" height="293" srcset="/wp-content/uploads/2017/01/sequence_bt.png 853w, /wp-content/uploads/2017/01/sequence_bt-300x103.png 300w, /wp-content/uploads/2017/01/sequence_bt-768x264.png 768w" sizes="(max-width: 853px) 100vw, 853px" /></p>
<p>类似于程序语言中的赋值语句，赋值节点可以将右值赋给左值。</p>
<p>选中上图中的赋值节点，将“左参数”选择为前面所添加的成员属性“p1”，“右参数”直接设置为6，表示程序端在执行该行为树时，会将右值6赋给左值p1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1502" src="/wp-content/uploads/2017/01/assignment_properties.png" alt="" width="477" height="212" srcset="/wp-content/uploads/2017/01/assignment_properties.png 477w, /wp-content/uploads/2017/01/assignment_properties-300x133.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>更多细节请参考手册《<a href="/language/zh/assignment/">赋值节点</a>》。</p>
<h2><span class="ez-toc-section" id="i-3">条件节点</span></h2>
<p>类似于程序语言中的条件判断语句，条件节点用于比较两个值的情况，用于跟后续节点组合使用，表示条件满足时，是否执行后续的节点。</p>
<p>选中上面行为树“SequenceBT”中的条件节点，将“左参数”选择为前面所添加的成员属性“p1”，“右参数”直接设置为3，“操作符”设置为“&gt;”，表示判断p1是否大于3，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1503" src="/wp-content/uploads/2017/01/condition_properties.png" alt="" width="477" height="214" srcset="/wp-content/uploads/2017/01/condition_properties.png 477w, /wp-content/uploads/2017/01/condition_properties-300x135.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>更多细节请参考手册《<a href="/language/zh/condition/">条件节点</a>》。</p>
<h2><span class="ez-toc-section" id="i-4">序列节点</span></h2>
<p>序列节点是行为树中传统的组合节点之一。该节点以给定的顺序依次执行其子节点，直到所有子节点成功返回，该节点也返回成功。只要其中某个子节点失败，那么该节点就直接返回失败，不再执行后续的子节点。</p>
<p>在上面行为树“SequenceBT”中，可以看到序列节点有3个子节点，分别是赋值、条件和动作节点。在依次执行该序列节点的子节点时，赋值节点（p1 = 6）永远返回成功，将继续执行条件节点（p1 &gt; 3），该条件节点也返回成功，因此继续执行动作节点（SayHello），最后期望输出“Hello Behaviac!”。</p>
<p>执行该行为树，得到如下结果：</p>
<p><img class="aligncenter size-full wp-image-1504" src="/wp-content/uploads/2017/01/sequence_bt_result.png" alt="" width="191" height="81" /></p>
<p>可以看到，执行结果跟期望保持一致。</p>
<p>如果将条件节点的右值3改为8，得到行为树如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1505" src="/wp-content/uploads/2017/01/sequence_bt_8.png" alt="" width="851" height="287" srcset="/wp-content/uploads/2017/01/sequence_bt_8.png 851w, /wp-content/uploads/2017/01/sequence_bt_8-300x101.png 300w, /wp-content/uploads/2017/01/sequence_bt_8-768x259.png 768w" sizes="(max-width: 851px) 100vw, 851px" /></p>
<p>重新导出并加载执行该行为树，执行结果如下所示：</p>
<p><img class="aligncenter size-full wp-image-1506" src="/wp-content/uploads/2017/01/sequence_bt_8_result.png" alt="" width="198" height="56" /></p>
<p>可以看到，并没有输出“Hello Behaviac!”，说明动作节点（SayHello）没有得到执行，因为条件节点（p1 &gt; 8）已经返回失败。</p>
<p>更多细节请参考手册《<a href="/language/zh/sequence/">序列节点</a>》。</p>
<h2><span class="ez-toc-section" id="i-5">选择节点</span></h2>
<p>选择节点也是行为树中传统的组合节点之一。该节点以给定的顺序依次调用其子节点，直到其中一个成功返回，那么该节点也直接返回成功，不再执行后续的子节点。如果所有的子节点都失败，那么该节点也返回失败。</p>
<p>新建行为树“SelectBT”，将根节点的Agent类型设置为“FirstAgent”，并为其依次添加序列、赋值、选择、条件和动作节点，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1507" src="/wp-content/uploads/2017/01/select_bt_nodes.png" alt="" width="124" height="372" srcset="/wp-content/uploads/2017/01/select_bt_nodes.png 124w, /wp-content/uploads/2017/01/select_bt_nodes-100x300.png 100w" sizes="(max-width: 124px) 100vw, 124px" /></p>
<p><img class="aligncenter size-full wp-image-1508" src="/wp-content/uploads/2017/01/select_bt.png" alt="" width="1095" height="282" srcset="/wp-content/uploads/2017/01/select_bt.png 1095w, /wp-content/uploads/2017/01/select_bt-300x77.png 300w, /wp-content/uploads/2017/01/select_bt-768x198.png 768w, /wp-content/uploads/2017/01/select_bt-1024x264.png 1024w" sizes="(max-width: 1095px) 100vw, 1095px" /></p>
<p>执行该行为树，得到结果如下：</p>
<p><img class="aligncenter size-full wp-image-1509" src="/wp-content/uploads/2017/01/select_bt_result.png" alt="" width="178" height="54" /></p>
<p>可以看到，并没有输出“Hello Behaviac!”，说明动作节点（SayHello）没有得到执行，因为条件节点（p1 &gt; 3）已经返回成功，那么选择节点直接返回成功，不再执行后续的子节点。</p>
<p>如果将条件节点的右值3改为8，得到如下的行为树：</p>
<p><img class="aligncenter size-full wp-image-1510" src="/wp-content/uploads/2017/01/select_bt_8.png" alt="" width="1101" height="287" srcset="/wp-content/uploads/2017/01/select_bt_8.png 1101w, /wp-content/uploads/2017/01/select_bt_8-300x78.png 300w, /wp-content/uploads/2017/01/select_bt_8-768x200.png 768w, /wp-content/uploads/2017/01/select_bt_8-1024x267.png 1024w" sizes="(max-width: 1101px) 100vw, 1101px" /></p>
<p>重新导出并加载执行该行为树，执行结果如下所示：</p>
<p><img class="aligncenter size-full wp-image-1511" src="/wp-content/uploads/2017/01/select_bt_8_result.png" alt="" width="174" height="87" /></p>
<p>可以看到，执行结果输出了“Hello Behaviac!”，说明动作节点（SayHello）得到了执行，因为条件节点（p1 &gt; 8）返回失败，选择节点会继续执行后续的子节点，也就是该动作节点。</p>
<p>更多细节请参考手册《<a href="/language/zh/selector/">选择节点</a>》。</p>
<h2><span class="ez-toc-section" id="i-6">导出格式</span></h2>
<p>除了支持《<a href="/tutorial_1_hello_behaviac/">教程一</a>》介绍的XML导出格式，behaviac组件还支持BSON、C++和C#格式的行为树导出。</p>
<p>勾选上所有的导出格式，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1518" src="/wp-content/uploads/2017/01/export_formats.png" alt="" width="395" height="595" srcset="/wp-content/uploads/2017/01/export_formats.png 395w, /wp-content/uploads/2017/01/export_formats-199x300.png 199w" sizes="(max-width: 395px) 100vw, 395px" /></p>
<h3><span class="ez-toc-section" id="XML">XML</span></h3>
<p>指定文件格式为XML，如下代码所示：</p>
<pre>behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_xml);</pre>
<h3><span class="ez-toc-section" id="BSON">BSON</span></h3>
<p>点击右下方的“导出”按钮后，可以看到在导出目录tutorials/tutorial_2/cpp/exported下，除了原有的*.xml文件之外，还有了*.bson.bytes文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1521" src="/wp-content/uploads/2017/01/export_bson.png" alt="" width="208" height="271" /></p>
<p>加载使用BSON文件，只需要把文件格式改为BSON即可，如下代码所示：</p>
<pre>behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_bson);</pre>
<p>加载某个行为树时，文件名并不需要指定后缀，只要指定相对于导出位置的路径和文件名，如下代码所示：</p>
<pre>g_FirstAgent-&gt;btload(“LoopBT”);</pre>
<p>这里，我们使用行为树“LoopBT”，执行后的结果如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1498" src="/wp-content/uploads/2017/01/loop_bt_result.png" alt="" width="157" height="210" /></p>
<p>可以看出，跟XML格式的执行结果保持一致。</p>
<h3><span class="ez-toc-section" id="C">C++</span></h3>
<p>在代码生成目录tutorials/tutorial_2/cpp/behaviac_generated/behaviors下，导出了行为树的C++源码文件，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1523" src="/wp-content/uploads/2017/01/export_cpp.png" alt="" width="268" height="165" /></p>
<p>需要把这些文件整合到自己的项目中一起编译，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1580" src="/wp-content/uploads/2017/01/tutorial_2_cpp_generated_project.png" alt="" width="385" height="381" srcset="/wp-content/uploads/2017/01/tutorial_2_cpp_generated_project.png 385w, /wp-content/uploads/2017/01/tutorial_2_cpp_generated_project-300x297.png 300w" sizes="(max-width: 385px) 100vw, 385px" /></p>
<p>所有C++版教程的项目都包含在源码包中projects/vs2013目录中的工程behaviac.sln，打开该工程文件后，可以看到里面有behaviac组件的源码和所有的教程项目，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1581" src="/wp-content/uploads/2017/01/tutorial_projects.png" alt="" width="144" height="178" /></p>
<p>找到tutorial_2项目，打开里面的tutorial_2.cpp文件，将文件格式改为C++，如下代码所示：</p>
<pre>behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_cpp);</pre>
<p>这里，我们使用行为树“LoopBT”，执行后的结果如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1498" src="/wp-content/uploads/2017/01/loop_bt_result.png" alt="" width="157" height="210" /></p>
<p>可以看出，跟XML格式的执行结果保持一致。</p>
<h3><span class="ez-toc-section" id="C-2">C#</span></h3>
<p>打开本教程C#版的工作区文件tutorials/tutorial_2/workspace/tutorial_2_cs.workspace.xml，该工作区的参数配置如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1582" src="/wp-content/uploads/2017/01/tutorial_2_cs_workspace.png" alt="" width="587" height="272" srcset="/wp-content/uploads/2017/01/tutorial_2_cs_workspace.png 587w, /wp-content/uploads/2017/01/tutorial_2_cs_workspace-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<p>类似于前面介绍的导出窗口配置，选中所有的格式并进行导出，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1528" src="/wp-content/uploads/2017/01/export_all_cs.png" alt="" width="395" height="595" srcset="/wp-content/uploads/2017/01/export_all_cs.png 395w, /wp-content/uploads/2017/01/export_all_cs-199x300.png 199w" sizes="(max-width: 395px) 100vw, 395px" /></p>
<p>打开位于源码包tutorials/tutorial_2/cs目录中的tutorial_2.sln工程，可以查看本教程的C#示例代码。</p>
<p>可以通过修改文件格式来加载不同类型的行为树文件，如下代码所示：</p>
<p>加载XML版的行为树：</p>
<pre>behaviac.Workspace.Instance.FileFormat = behaviac.Workspace.EFileFormat.EFF_xml;</pre>
<p>加载BSON版的行为树：</p>
<pre>behaviac.Workspace.Instance.FileFormat = behaviac.Workspace.EFileFormat.EFF_bson;</pre>
<p>加载C#版的行为树：</p>
<pre>behaviac.Workspace.Instance.FileFormat = behaviac.Workspace.EFileFormat.EFF_cs;</pre>
<p>编译并执行C#工程，可以查看加载和执行行为树后的结果。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_2">tutorials/tutorial_2</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_2_more_nodes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程3：Agent实例</title>
		<link>/tutorial_3_agent_instance/</link>
					<comments>/tutorial_3_agent_instance/#comments</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Mon, 23 Jan 2017 03:54:28 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1534</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 我们知道，面向对象程序编程的定义就是使用对象来做设计，对象即是类的实例。beha<a class="moretag" href="/tutorial_3_agent_instance/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>我们知道，面向对象程序编程的定义就是使用对象来做设计，对象即是类的实例。behaviac组件是基于Agent类及其实例来运转的，Agent类的实例加载和执行行为树，而在行为树的节点中又有可能用到了Agent实例的成员属性或方法。</p>
<p>在编辑器的节点属性窗口中，为了给该节点配置参数，首先需要选择一个实例，然后再选择该实例的成员属性或方法，如下图所示：</p>
<p><img class="aligncenter" src="/img/tutorials/tutorial17/instance_list.png" alt="" /></p>
<p>这些实例来自于如下三个方面：</p>
<ul>
<li><strong>Self：</strong>当前行为树根节点所配置的Agent类的实例，类似于程序语言中的this。</li>
<li><strong>成员实例：</strong>当前行为树根节点所配置的Agent类的成员属性，或是当前行为树的局部变量，需要是Agent或其子类类型。</li>
<li><strong>全局实例：</strong>在类型信息浏览器中编辑并生成注册代码的各种Agent或其子类的全局变量。</li>
</ul>
<h2><span class="ez-toc-section" id="i">成员实例</span></h2>
<p>对于成员实例，在上图所示的节点属性窗口中会根据当前行为树根节点所配置的Agent类型，自动列举出所有的成员实例以供选择。但在使用该成员实例之前，需要确保该实例已经赋过值，而不是空指针或引用。</p>
<p>在类型信息浏览器中添加新的Agent子类SecondAgent，并为其添加一个int类型的成员属性p2，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1540" src="/wp-content/uploads/2017/01/second_agent.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/01/second_agent.png 612w, /wp-content/uploads/2017/01/second_agent-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>然后，为FirstAgent类添加SecondAgent类型的成员属性pInstance，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1541" src="/wp-content/uploads/2017/01/member_agent_instance.png" alt="" width="607" height="732" srcset="/wp-content/uploads/2017/01/member_agent_instance.png 607w, /wp-content/uploads/2017/01/member_agent_instance-249x300.png 249w" sizes="(max-width: 607px) 100vw, 607px" /></p>
<p>点击上图中的“确认”按钮后，可以看到FirstAgent类多了一个成员属性pInstance，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1543" src="/wp-content/uploads/2017/01/member_agent_instance_added.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/01/member_agent_instance_added.png 612w, /wp-content/uploads/2017/01/member_agent_instance_added-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="i-2">全局实例</span></h2>
<p>对于全局实例，各种Agent或其子类实例的名字注册和绑定是为了支持单件（Singleton）或者类似确定的全局性实例（同一个类可能会有若干个实例而不是仅仅有一个实例），如player、camera、director等。</p>
<p>点击类型信息浏览器中部的“实例名称”右侧的“新增”按钮，添加SecondAgent类型的全局实例SecondAgentInstance，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1542" src="/wp-content/uploads/2017/01/second_agent_instance.png" alt="" width="612" height="733" srcset="/wp-content/uploads/2017/01/second_agent_instance.png 612w, /wp-content/uploads/2017/01/second_agent_instance-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>点击上图中的“确认”按钮后，可以看到SecondAgent类的“实例名称”下拉列表中有了新加的全局实例SecondAgentInstance，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1544" src="/wp-content/uploads/2017/01/second_agent_instance_added.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/01/second_agent_instance_added.png 612w, /wp-content/uploads/2017/01/second_agent_instance_added-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>点击上图中右下方的“应用”按钮，就可以在行为树中分别使用这2个新加的成员实例和全局实例了。</p>
<h2><span class="ez-toc-section" id="i-3">应用</span></h2>
<p>新建一棵行为树“InstanceBT”，依次添加序列、赋值、条件和动作节点，并为根节点选择FirstAgent类型，将动作节点配置为Self及其成员方法SayHello，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1556" src="/wp-content/uploads/2017/01/instance_bt_empty-2.png" alt="" width="839" height="376" srcset="/wp-content/uploads/2017/01/instance_bt_empty-2.png 839w, /wp-content/uploads/2017/01/instance_bt_empty-2-300x134.png 300w, /wp-content/uploads/2017/01/instance_bt_empty-2-768x344.png 768w, /wp-content/uploads/2017/01/instance_bt_empty-2-604x270.png 604w" sizes="(max-width: 839px) 100vw, 839px" /></p>
<p>选中ID为1的赋值节点，在其属性窗口“左参数”的实例名中，可以为其选择Self、SecondAgentInstance和pInstance 3个实例了，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1557" src="/wp-content/uploads/2017/01/instance_bt_assignment.png" alt="" width="481" height="217" srcset="/wp-content/uploads/2017/01/instance_bt_assignment.png 481w, /wp-content/uploads/2017/01/instance_bt_assignment-300x135.png 300w" sizes="(max-width: 481px) 100vw, 481px" /></p>
<p>为其选择SecondAgentInstance及其成员属性p2，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1558" src="/wp-content/uploads/2017/01/instance_bt_assignment_set.png" alt="" width="477" height="213" srcset="/wp-content/uploads/2017/01/instance_bt_assignment_set.png 477w, /wp-content/uploads/2017/01/instance_bt_assignment_set-300x134.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>类似的，选中ID为2的赋值节点，为其选择pInstance及其成员属性p2，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1559" src="/wp-content/uploads/2017/01/instance_bt_assignment2_set.png" alt="" width="477" height="215" srcset="/wp-content/uploads/2017/01/instance_bt_assignment2_set.png 477w, /wp-content/uploads/2017/01/instance_bt_assignment2_set-300x135.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>选中ID为3的条件节点，将“左参数”选择为SecondAgentInstance及其成员属性p2，将“右参数”选择为pInstance及其成员属性p2，将“操作符”选择为“&gt;”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1548" src="/wp-content/uploads/2017/01/instance_condition_set.png" alt="" width="453" height="213" srcset="/wp-content/uploads/2017/01/instance_condition_set.png 453w, /wp-content/uploads/2017/01/instance_condition_set-300x141.png 300w" sizes="(max-width: 453px) 100vw, 453px" /></p>
<p>配置完之后，得到行为树“InstanceBT”如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1560" src="/wp-content/uploads/2017/01/instance_bt_set-1.png" alt="" width="1024" height="372" srcset="/wp-content/uploads/2017/01/instance_bt_set-1.png 1024w, /wp-content/uploads/2017/01/instance_bt_set-1-300x109.png 300w, /wp-content/uploads/2017/01/instance_bt_set-1-768x279.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>导出行为树后，程序端就可以在加载和执行该行为树“InstanceBT”了。</p>
<h3><span class="ez-toc-section" id="C">C++版</span></h3>
<p>在源码包的tutorials/tutorial_3/cpp/tutorial_3.cpp文件中，定义了3个变量，如下代码所示：</p>
<pre>FirstAgent* g_FirstAgent = NULL;
SecondAgent* g_SecondAgent = NULL;
SecondAgent* g_ThirdAgent = NULL;</pre>
<p>其中，g_FirstAgent用于加载和执行行为树“InstanceBT”，g_SecondAgent用于赋值给g_FirstAgent的成员属性pInstance，g_ThirdAgent作为全局实例供行为树“InstanceBT”中的节点使用。这3个变量的初始化，如下代码所示：</p>
<pre>bool InitPlayer()
{
    LOGI("InitPlayer : %s\n", "InstanceBT");

    // 创建g_FirstAgent，并加载行为树“InstanceBT”
    g_FirstAgent = behaviac::Agent::Create&lt;FirstAgent&gt;();
    bool bRet = g_FirstAgent-&gt;btload("InstanceBT");
    g_FirstAgent-&gt;btsetcurrent("InstanceBT");

    // 创建g_SecondAgent，并将该实例赋给g_FirstAgent的成员pInstance
    g_SecondAgent = behaviac::Agent::Create&lt;SecondAgent&gt;();
    g_FirstAgent-&gt;SetSecondAgent(g_SecondAgent);

    // 创建g_ThirdAgent，并将"SecondAgentInstance"绑定给该实例
    g_ThirdAgent = behaviac::Agent::Create&lt;SecondAgent&gt;("SecondAgentInstance");

    return bRet;
}</pre>
<h3><span class="ez-toc-section" id="C-2">C#版</span></h3>
<p>在源码包的tutorials/tutorial_3/cs/tutorial_3.cs文件中，定义了3个变量，如下代码所示：</p>
<pre>static FirstAgent g_FirstAgent;
static SecondAgent g_SecondAgent;
static SecondAgent g_ThirdAgent;</pre>
<p>其中，g_FirstAgent用于加载和执行行为树“InstanceBT”，g_SecondAgent用于赋值给g_FirstAgent的成员属性pInstance，g_ThirdAgent作为全局实例供行为树“InstanceBT”中的节点使用。这3个变量的初始化，如下代码所示：</p>
<pre>static bool InitPlayer()
{
    Console.WriteLine("InitPlayer");

    // 创建g_FirstAgent，并加载行为树“InstanceBT”
    g_FirstAgent = new FirstAgent();
    bool bRet = g_FirstAgent.btload("InstanceBT");
    Debug.Assert(bRet);
    g_FirstAgent.btsetcurrent("InstanceBT");

    // 创建g_SecondAgent，并将该实例赋给g_FirstAgent的成员pInstance
    g_SecondAgent = new SecondAgent();
    g_FirstAgent._set_pInstance(g_SecondAgent);

    // 创建g_ThirdAgent，并将"SecondAgentInstance"绑定给该实例
    g_ThirdAgent = new SecondAgent();
    behaviac.Agent.BindInstance(g_ThirdAgent, "SecondAgentInstance");

    return bRet;
 }</pre>
<p>编译并执行，可以看到输出了“Hello Behaviac!”，说明行为树的执行结果符合我们的预期，Agent实例得到了正确的使用。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_3">tutorials/tutorial_3</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_3_agent_instance/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>教程4：预制的使用</title>
		<link>/tutorial_4_prefab/</link>
					<comments>/tutorial_4_prefab/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Thu, 16 Feb 2017 10:54:19 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1588</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 预制（Prefab）可以用来复用和实例化已有的行为树，如果只是直接复用行为树，预<a class="moretag" href="/tutorial_4_prefab/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>预制（Prefab）可以用来复用和实例化已有的行为树，如果只是直接复用行为树，预制跟引用子树的功能是一样的。</p>
<p>但是预制还可以用来定制个别节点的配置，称之为对预制的实例化。也即，如果一棵行为树用到了一棵预制行为树，那么可以局部修改某些节点，这些修改的节点不会跟着预制行为树的更新而同步更新。</p>
<p>首先新建一棵行为树“ParentBT”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1709" src="/wp-content/uploads/2017/02/parentbt.png" alt="" width="1093" height="466" srcset="/wp-content/uploads/2017/02/parentbt.png 1093w, /wp-content/uploads/2017/02/parentbt-300x128.png 300w, /wp-content/uploads/2017/02/parentbt-768x327.png 768w, /wp-content/uploads/2017/02/parentbt-1024x437.png 1024w" sizes="(max-width: 1093px) 100vw, 1093px" /></p>
<p>在ID为2的序列节点上右键鼠标，弹出菜单，选择“另存为预制行为树”，表示准备将该序列节点为根节点的子树保存为一棵预制行为树，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1710" src="/wp-content/uploads/2017/02/save_as_prefab.png" alt="" width="820" height="611" srcset="/wp-content/uploads/2017/02/save_as_prefab.png 820w, /wp-content/uploads/2017/02/save_as_prefab-300x224.png 300w, /wp-content/uploads/2017/02/save_as_prefab-768x572.png 768w" sizes="(max-width: 820px) 100vw, 820px" /></p>
<p>在弹出的“另存为预制”窗口中，可以为当前的预制改名，然后点击“确认”按钮，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1711" src="/wp-content/uploads/2017/02/save_as_prefab_confirm.png" alt="" width="390" height="160" srcset="/wp-content/uploads/2017/02/save_as_prefab_confirm.png 390w, /wp-content/uploads/2017/02/save_as_prefab_confirm-300x123.png 300w" sizes="(max-width: 390px) 100vw, 390px" /></p>
<p>在编辑器左侧的行为树列表中，可以看到多了“pf_Sequence”节点，这就是刚刚保存出来的预制行为树，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1712" src="/wp-content/uploads/2017/02/behaviors_list.png" alt="" width="214" height="127" /></p>
<p>在“Prefabs”下面的所有预制行为树都可以直接拖拽到主视口中打开的行为树中使用，不过需要保证预制行为树跟主视口中打开的行为树的Agent类型保持兼容，也即要么类型相同，要么预制行为树的Agent类型是主视口中打开的行为树的Agent类型的基类。</p>
<p>双击打开预制行为树“pf_Sequence”，可以看到该树自动添加了根节点及其Agent类型“FirstAgent”，其他节点跟原有的情况保持一致，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1713" src="/wp-content/uploads/2017/02/pf_prefab.png" alt="" width="848" height="284" srcset="/wp-content/uploads/2017/02/pf_prefab.png 848w, /wp-content/uploads/2017/02/pf_prefab-300x100.png 300w, /wp-content/uploads/2017/02/pf_prefab-768x257.png 768w" sizes="(max-width: 848px) 100vw, 848px" /></p>
<p>而在行为树“ParentBT”中，可以看到原有的ID为2的序列节点所在的子树已被上面的预制行为树“pf_Sequence”所替代，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1714" src="/wp-content/uploads/2017/02/parentbt_prefab.png" alt="" width="1094" height="471" srcset="/wp-content/uploads/2017/02/parentbt_prefab.png 1094w, /wp-content/uploads/2017/02/parentbt_prefab-300x129.png 300w, /wp-content/uploads/2017/02/parentbt_prefab-768x331.png 768w, /wp-content/uploads/2017/02/parentbt_prefab-1024x441.png 1024w" sizes="(max-width: 1094px) 100vw, 1094px" /></p>
<p>修改了预制行为树“pf_Sequence”中的节点，所有引用到该预制行为树的行为树都会保持相同的更新，除非在行为树中有对预制行为树的节点属性有自己的修改或定制。</p>
<p>再为行为树“ParentBT”拖拽添加一个预制“pf_Sequence”分支，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1719" src="/wp-content/uploads/2017/02/prefab2.png" alt="" width="1040" height="691" srcset="/wp-content/uploads/2017/02/prefab2.png 1040w, /wp-content/uploads/2017/02/prefab2-300x199.png 300w, /wp-content/uploads/2017/02/prefab2-768x510.png 768w, /wp-content/uploads/2017/02/prefab2-1024x680.png 1024w" sizes="(max-width: 1040px) 100vw, 1040px" /></p>
<p>修改上图中的第二个预制“pf_Sequence”中ID为9的赋值节点右值为3，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1721" src="/wp-content/uploads/2017/02/prefab3-1.png" alt="" width="1037" height="691" srcset="/wp-content/uploads/2017/02/prefab3-1.png 1037w, /wp-content/uploads/2017/02/prefab3-1-300x200.png 300w, /wp-content/uploads/2017/02/prefab3-1-768x512.png 768w, /wp-content/uploads/2017/02/prefab3-1-1024x682.png 1024w" sizes="(max-width: 1037px) 100vw, 1037px" /></p>
<p>可以看到上图ID为8和9的两个节点都变为了虚线框，表示这是预制实例化（定制）后的节点及其父节点。</p>
<p>如果在预制行为树“pf_Sequence”中，修改节点ID为5的赋值节点的右值为6，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1722" src="/wp-content/uploads/2017/02/prefab4.png" alt="" width="844" height="280" srcset="/wp-content/uploads/2017/02/prefab4.png 844w, /wp-content/uploads/2017/02/prefab4-300x100.png 300w, /wp-content/uploads/2017/02/prefab4-768x255.png 768w" sizes="(max-width: 844px) 100vw, 844px" /></p>
<p>那么行为树“ParentBT”中ID为5的赋值节点的右值会同步更新为6，但是ID为9的赋值节点的右值还是为3，并没有同步更新，因为该节点已经被定制过了，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1723" src="/wp-content/uploads/2017/02/prefab5.png" alt="" width="1037" height="693" srcset="/wp-content/uploads/2017/02/prefab5.png 1037w, /wp-content/uploads/2017/02/prefab5-300x200.png 300w, /wp-content/uploads/2017/02/prefab5-768x513.png 768w, /wp-content/uploads/2017/02/prefab5-1024x684.png 1024w" sizes="(max-width: 1037px) 100vw, 1037px" /></p>
<p>执行最终的行为树，输出结果如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1715" src="/wp-content/uploads/2017/02/prefab_result.png" alt="" width="243" height="162" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_4">tutorials/tutorial_4</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_4_prefab/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程5：子树的使用</title>
		<link>/tutorial_5_subtree/</link>
					<comments>/tutorial_5_subtree/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Fri, 17 Feb 2017 10:27:47 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1603</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 子树可以用来复用已有的行为树。通过子树节点，一个行为树可以作为另一个行为树的子树<a class="moretag" href="/tutorial_5_subtree/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>子树可以用来复用已有的行为树。通过<code class="highlighter-rouge">子树节点</code>，一个行为树可以作为另一个行为树的<code class="highlighter-rouge">子树，而</code>作为子树的那个行为树将被父树所“调用”。</p>
<p>子树还可以类似编程语言中的函数调用一样通过传递参数来使用。</p>
<p>类似动作节点，<code class="highlighter-rouge">子树</code>节点根据子树的执行结果也会返回一样的执行结果（即成功、失败或正在执行），其父节点按照自己的控制逻辑来控制接下来的运行。</p>
<h2><span class="ez-toc-section" id="1">1. 编辑类型信息</span></h2>
<p>首先，我们需要添加一个Agent类，后面会利用这个Agent类来创建行为树。</p>
<p>打开类型信息浏览器，分别为Agent类“FirstAgent”添加成员属性、方法和任务。</p>
<p>添加int类型的成员属性p1，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1608" src="/wp-content/uploads/2017/02/subtree_p1.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/02/subtree_p1.png 612w, /wp-content/uploads/2017/02/subtree_p1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>添加成员方法Say，该方法带有一个string&amp;类型的参数，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1624" src="/wp-content/uploads/2017/02/subtree_say-1.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/02/subtree_say-1.png 612w, /wp-content/uploads/2017/02/subtree_say-1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>添加任务t1，该任务带有一个int类型的参数，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1610" src="/wp-content/uploads/2017/02/subtree_t1.png" alt="" width="612" height="735" srcset="/wp-content/uploads/2017/02/subtree_t1.png 612w, /wp-content/uploads/2017/02/subtree_t1-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2 id="section-3"><span class="ez-toc-section" id="2">2. 不带参数的子树</span></h2>
<p>首先给出子树最直接的用法——不带参数的子树：</p>
<p>首先，创建行为树“subtree”，将动作节点的方法Say的参数设置为“Hello subtree!”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1612" src="/wp-content/uploads/2017/02/subtree-1.png" alt="" width="833" height="216" srcset="/wp-content/uploads/2017/02/subtree-1.png 833w, /wp-content/uploads/2017/02/subtree-1-300x78.png 300w, /wp-content/uploads/2017/02/subtree-1-768x199.png 768w" sizes="(max-width: 833px) 100vw, 833px" /></p>
<p>Say方法的功能是输出指定的字符串，如下代码所示：</p>
<pre>void FirstAgent::Say(behaviac::string&amp; param0)
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE Say
    printf("\n%s\n\n", param0.c_str());
///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>然后，创建行为树“maintree”，并将行为树列表中的节点“subtree”直接拖拽到该树中，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1607" src="/wp-content/uploads/2017/02/subtrees-1.png" alt="" width="181" height="137" /></p>
<p><img class="aligncenter size-full wp-image-1613" src="/wp-content/uploads/2017/02/maintree-1.png" alt="" width="819" height="293" srcset="/wp-content/uploads/2017/02/maintree-1.png 819w, /wp-content/uploads/2017/02/maintree-1-300x107.png 300w, /wp-content/uploads/2017/02/maintree-1-768x275.png 768w" sizes="(max-width: 819px) 100vw, 819px" /></p>
<p>这样，行为树“maintree”就可以“调用”子树“subtree”了。</p>
<p>加载并执行行为树“maintree”后，结果如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1619" src="/wp-content/uploads/2017/02/hello_maintree.png" alt="" width="180" height="119" /></p>
<p>可以看到，输出了“Hello subtree!”字符串，说明子树“subtree”得到了正确的调用和执行。</p>
<h2><span class="ez-toc-section" id="3">3. 带参数的子树</span></h2>
<p>有时候，我们可能需要给子树传递参数来使用，这样子树会更加模块化。</p>
<p>对于这种需要传参的子树，可以按照如下操作进行：</p>
<p>首先，创建行为树“subtree_task”，并为其添加的第一个子节点必须是任务节点，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1615" src="/wp-content/uploads/2017/02/task_node.png" alt="" width="161" height="372" srcset="/wp-content/uploads/2017/02/task_node.png 161w, /wp-content/uploads/2017/02/task_node-130x300.png 130w" sizes="(max-width: 161px) 100vw, 161px" /></p>
<p><img class="aligncenter size-full wp-image-1614" src="/wp-content/uploads/2017/02/subtree_task.png" alt="" width="1140" height="196" srcset="/wp-content/uploads/2017/02/subtree_task.png 1140w, /wp-content/uploads/2017/02/subtree_task-300x52.png 300w, /wp-content/uploads/2017/02/subtree_task-768x132.png 768w, /wp-content/uploads/2017/02/subtree_task-1024x176.png 1024w" sizes="(max-width: 1140px) 100vw, 1140px" /></p>
<p>为上图中的任务节点，在其属性窗口中配置其“任务”参数为“t1”，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1628" src="/wp-content/uploads/2017/02/subtree_task_t1.png" alt="" width="477" height="102" srcset="/wp-content/uploads/2017/02/subtree_task_t1.png 477w, /wp-content/uploads/2017/02/subtree_task_t1-300x64.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>由于任务“t1”带有参数“param0”，所以在上面行为树“subtree_task”的条件节点中可以使用该参数“param0”，如上图所示。可以借鉴程序语言的说法，该参数“param0”就类似于函数的形参。</p>
<p>然后，创建行为树“maintree_task”，并将行为树列表中的节点“subtree_task”直接拖拽到该树中，如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1607" src="/wp-content/uploads/2017/02/subtrees-1.png" alt="" width="181" height="137" /></p>
<p><img class="aligncenter size-full wp-image-1616" src="/wp-content/uploads/2017/02/maintree_task.png" alt="" width="867" height="296" srcset="/wp-content/uploads/2017/02/maintree_task.png 867w, /wp-content/uploads/2017/02/maintree_task-300x102.png 300w, /wp-content/uploads/2017/02/maintree_task-768x262.png 768w" sizes="(max-width: 867px) 100vw, 867px" /></p>
<p>选中上图中的子树节点，配置任务的参数值“param0”为2（这个参数类似于函数中的实参），如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1617" src="/wp-content/uploads/2017/02/task_set.png" alt="" width="475" height="163" srcset="/wp-content/uploads/2017/02/task_set.png 475w, /wp-content/uploads/2017/02/task_set-300x103.png 300w" sizes="(max-width: 475px) 100vw, 475px" /></p>
<p>这样，行为树“maintree_task”就可以“调用”子树“subtree_task”，并为该子树传递参数了。</p>
<p>加载并执行行为树“maintree_task”后，结果如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1621" src="/wp-content/uploads/2017/02/hello_maintree_task.png" alt="" width="218" height="121" /></p>
<p>可以看到，输出了“Hello subtree_task!”字符串，说明子树“subtree_task”得到了正确的调用和执行。</p>
<h2 id="section-3"><span class="ez-toc-section" id="4"><span id="i-4" class="ez-toc-section">4. 添加子树节点的补充说明</span></span></h2>
<ul>
<li>如上所述，可以从编辑器左侧的行为树节点列表中，通过鼠标选择并拖拽一棵行为树到另一棵行为树中来生成子树节点。被拖拽的行为树的路径被设置到<code class="highlighter-rouge">引用文件名</code>。需要指出的是，并非任意一个行为树都可以作为另外一个行为树的子树。3.6.32及之前版本，作为子树的Agent类型必须是父树的Agent类型的同类或父类。而3.6.33及之后版本，作为子树的Agent类型可以是父树的Agent类型的同类或父类或子类，但是需要保证执行该父树的Agent实例是父树和子树的Agent类型的子类或更低子类的实例（例如，假设父树的Agent类型是A，子树的Agent类型是B：如果A是B的子类，那么执行该父树的Agent实例必须是A或者A的子类的实例；如果B是A的子类，那么执行该父树的Agent实例必须是B或者B的子类的实例）。</li>
<li>另外，也可以像添加其他节点那样，在节点列表中选取子树，拖拽到相应的位置，然后点击该子树节点，在右侧的属性窗口中配置<code class="highlighter-rouge">引用文件名</code>或<code class="highlighter-rouge">任务</code>。<br />
<img src="/img/references/nodelist_subtree.png" alt="" /></li>
<li>如果手工配置的子树的路径是空的或无效的，在检查错误时会报错，表示该树不允许被导出。如果配置的是属性或方法，在编辑器中无法知其是否有效，只有运行的时候才会报运行时错误，如果运行过程中该值无效。</li>
</ul>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_5">tutorials/tutorial_5</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_5_subtree/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程6：事件的使用</title>
		<link>/tutorial_6_event_usage/</link>
					<comments>/tutorial_6_event_usage/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Thu, 16 Mar 2017 07:57:59 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1790</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 事件（Event）作为节点一种的附件，主要用于在程序端的游戏逻辑发出事件时，得到<a class="moretag" href="/tutorial_6_event_usage/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>事件（Event）作为节点一种的附件，主要用于在程序端的游戏逻辑发出事件时，得到响应后打断当前正在执行的行为树，并切换到所设置的另一个行为树。</p>
<h2><span class="ez-toc-section" id="1">1. 添加类型信息及任务</span></h2>
<p>在类型信息浏览器中为类“FirstAgent”添加了event_task(int param0)这个任务，或者更形象的称之为“接口”，该任务带有一个int类型的param0参数，如下图所示：</p>
<p id="mtRjkNr"><img class="size-full wp-image-1791 aligncenter" src="/wp-content/uploads/2017/03/img_58ca306fcc299.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca306fcc299.png 612w, /wp-content/uploads/2017/03/img_58ca306fcc299-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="2">2. 创建带任务节点的子树</span></h2>
<p>创建行为树subtree_task，该树根节点的第一个子节点务必是任务节点，并为其配置上面添加的任务event_task，如下三图所示：</p>
<p><img class="aligncenter size-full wp-image-1793" src="/wp-content/uploads/2017/03/8WWKVQO0LWHWXNOPEDT.png" alt="" width="143" height="349" srcset="/wp-content/uploads/2017/03/8WWKVQO0LWHWXNOPEDT.png 143w, /wp-content/uploads/2017/03/8WWKVQO0LWHWXNOPEDT-123x300.png 123w" sizes="(max-width: 143px) 100vw, 143px" /></p>
<p><img class="aligncenter size-full wp-image-1795" src="/wp-content/uploads/2017/03/MO1AP1TMFHI1QP0JO7.png" alt="" width="1077" height="180" srcset="/wp-content/uploads/2017/03/MO1AP1TMFHI1QP0JO7.png 1077w, /wp-content/uploads/2017/03/MO1AP1TMFHI1QP0JO7-300x50.png 300w, /wp-content/uploads/2017/03/MO1AP1TMFHI1QP0JO7-768x128.png 768w, /wp-content/uploads/2017/03/MO1AP1TMFHI1QP0JO7-1024x171.png 1024w" sizes="(max-width: 1077px) 100vw, 1077px" /></p>
<p><img class="size-full wp-image-1794 aligncenter" src="/wp-content/uploads/2017/03/img_58ca3309e0052.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca3309e0052.png 478w, /wp-content/uploads/2017/03/img_58ca3309e0052-300x103.png 300w" sizes="(max-width: 478px) 100vw, 478px" /></p>
<p>在上面的行为树subtree_task中，ID为1的条件节点使用了任务event_task的参数param0。这类似于编程语言中的函数参数为函数体的代码提供了局部变量，<strong>任务节点中的参数也为当前的行为树提供了同名的局部变量，这些“局部变量”可以根据需要用于该行为树所有子节点，也就在行为树节点中使用了任务的参数。</strong></p>
<h2><span class="ez-toc-section" id="3">3. 创建带有事件的主树</span></h2>
<p>创建另一个行为树maintree_task，并将ID为4的动作节点的参数“决定状态的选项”设置为Running，用于模拟行为树一直持续执行在该动作节点上，如下二图所示：</p>
<p id="rbrFofZ"><img class="size-full wp-image-1798 aligncenter" src="/wp-content/uploads/2017/03/img_58ca39b0c1e17.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca39b0c1e17.png 874w, /wp-content/uploads/2017/03/img_58ca39b0c1e17-300x130.png 300w, /wp-content/uploads/2017/03/img_58ca39b0c1e17-768x333.png 768w" sizes="(max-width: 874px) 100vw, 874px" /></p>
<p id="pVASTrI"><img class="size-full wp-image-1797 aligncenter" src="/wp-content/uploads/2017/03/img_58ca391f2fc13.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca391f2fc13.png 477w, /wp-content/uploads/2017/03/img_58ca391f2fc13-300x148.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>接着，在编辑器左侧的行为树节点列表中，将行为树节点subtree_task通过鼠标拖拽到行为树maintree_task中的第一个序列节点上（注意：一般默认把事件附件放在根节点的第一个子节点上），这样该序列节点就有了一个事件附件，如下图所示：</p>
<p><img class="size-full wp-image-1799 aligncenter" src="/wp-content/uploads/2017/03/img_58ca3e1e61419.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca3e1e61419.png 869w, /wp-content/uploads/2017/03/img_58ca3e1e61419-300x129.png 300w, /wp-content/uploads/2017/03/img_58ca3e1e61419-768x330.png 768w" sizes="(max-width: 869px) 100vw, 869px" /></p>
<p>然后，为该事件设置参数，如下图所示：</p>
<p id="iiOgZFc"><img class="size-full wp-image-1800 aligncenter" src="/wp-content/uploads/2017/03/img_58ca3f6ce5ae1.png" alt="" srcset="/wp-content/uploads/2017/03/img_58ca3f6ce5ae1.png 478w, /wp-content/uploads/2017/03/img_58ca3f6ce5ae1-300x118.png 300w" sizes="(max-width: 478px) 100vw, 478px" /></p>
<p>其中，“触发一次”表示该事件是否只触发一次就不再起作用。</p>
<p>“触发模式”控制该事件触发后对当前行为树的影响以及被触发的子树结束时应该如何恢复，有转移（Transfer）和返回（Return）两个选项：</p>
<ul>
<li>转移：当子树结束时，当前行为树被中断和重置，该子树将被设置为当前行为树。</li>
<li>返回：当子树结束时，返回控制到之前打断的地方继续执行。当前行为树直接“压”到执行堆栈上而不被中断和重置，该子树被设置为当前行为树，当该子树结束时，原本的那棵行为树从执行堆栈上“弹出”，并从当初的节点恢复执行。</li>
</ul>
<h2><span class="ez-toc-section" id="4">4. 程序端发送事件</span></h2>
<p>最后，在程序端通过如下代码，将事件“event_task”发出，并指定所需的参数，如下代码所示：</p>
<pre>g_FirstAgent-&gt;FireEvent("event_task", 2);</pre>
<p>这样，在执行行为树maintree_task过程中，如果接收到事件event_task，那么该行为树中的事件附件event_task将得到响应和处理，行为树的执行就会从当前的maintree_task跳转到subtree_task。</p>
<pre><strong>注意</strong>：调用FireEvent的时候，只有处于Running状态的节点才会响应事件。这是为了允许不同分支在不同时机下，同样的事件可以触发不同的行为。比如同样是BeingHit，受伤或逃跑的时候可以分别对应不同的行为。如果不需要根据不同的节点响应不同的行为，只是需要响应事件，一般只需把事件配置在根节点的第一个子节点上（根节点同样需要是Running状态，非Running状态的节点没有机会响应事件）。</pre>
<h2><span class="ez-toc-section" id="5">5. 执行行为树</span></h2>
<p>执行行为树maintree_task，可以得到如下结果：</p>
<p id="CShGPGh"><img class="size-full wp-image-1801 aligncenter" src="/wp-content/uploads/2017/03/img_58ca452400f73.png" alt="" /></p>
<p>本教程对应的工作区和代码工程，请查看源码包中的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_6">tutorials/tutorial_6</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_6_event_usage/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程7：行为树的连调</title>
		<link>/tutorial_7_debug/</link>
					<comments>/tutorial_7_debug/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Fri, 17 Mar 2017 09:30:36 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1811</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 对于行为树的调试，behaviac提供了连调和离线调试两大功能。 连调功能是在游<a class="moretag" href="/tutorial_7_debug/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>对于行为树的调试，behaviac提供了连调和离线调试两大功能。</p>
<p>连调功能是在游戏运行的时候，编辑器可以连上游戏，实时的查看树的运行情况、变量的当前值并可以设置断点等；而离线调试实际上是回放运行时所产生的log。</p>
<p>本教程主要介绍连调的过程和相关的功能说明，离线调试可以参考文章《<a href="/language/zh/debugging_desc/">调试功能的说明</a>》。</p>
<p>连调需要游戏是开发版本（即宏BEHAVIAC_RELEASE没有被定义），发布版本下没有连调的功能，可以参考文章《<a href="/language/zh/tutorial10_performence/">版本说明</a>》和《<a href="/language/zh/config/">开发功能开关</a>》。</p>
<p>打开目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_7/workspace">tutorials/tutorial_7/workspace</a>中的工作区，并打开类型信息浏览器，可以看到类FirstAgent有一个成员属性p1和两个成员方法Start和Wait，如下图所示：</p>
<p id="YtsrrmN"><img class="size-full wp-image-1813 aligncenter" src="/wp-content/uploads/2017/03/img_58cb9ab2eef0f.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cb9ab2eef0f.png 612w, /wp-content/uploads/2017/03/img_58cb9ab2eef0f-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>点击上图右下方的应用按钮，在生成的FirstAgent.cpp文件中，填写Start和Wait的方法内容如下代码所示：</p>
<pre>void FirstAgent::Start()
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE Start
    count = 0;
///&lt;&lt;&lt; END WRITING YOUR CODE
}

behaviac::EBTStatus FirstAgent::Wait()
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE Wait
    count++;

    printf("p1 = %i\n", p1);

    if (count == 10000)
    {
        return behaviac::BT_SUCCESS;
    }

    return behaviac::BT_RUNNING;
///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>打开行为树demo，可以看到该行为树如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1812" src="/wp-content/uploads/2017/03/XK7N9TW1KUQYX2HA9958.png" alt="" width="1100" height="376" srcset="/wp-content/uploads/2017/03/XK7N9TW1KUQYX2HA9958.png 1100w, /wp-content/uploads/2017/03/XK7N9TW1KUQYX2HA9958-300x103.png 300w, /wp-content/uploads/2017/03/XK7N9TW1KUQYX2HA9958-768x263.png 768w, /wp-content/uploads/2017/03/XK7N9TW1KUQYX2HA9958-1024x350.png 1024w" sizes="(max-width: 1100px) 100vw, 1100px" /></p>
<p>为了在程序启动时，等待编辑器连接上才往后继续执行，需要在tutorial_7.cpp文件中的InitBehaviac方法中，添加如下代码：</p>
<pre>behaviac::Config::SetSocketBlocking(true);</pre>
<p>如果需要修改端口号，需要添加如下代码：</p>
<pre>behaviac::Config::SetSocketPort(60636);</pre>
<p>为了在连调时，程序端能够发送消息到编辑器端，需要在游戏循环中执行Workspace::DebugUpdate()方法，如下代码所示：</p>
<pre>void UpdateLoop()
{
    LOGI("UpdateLoop\n");

    int frames = 0;
    behaviac::EBTStatus status = behaviac::BT_RUNNING;

    while (status == behaviac::BT_RUNNING)
    {
        LOGI("frame %d\n", ++frames);

        behaviac::Workspace::GetInstance()-&gt;DebugUpdate();

        status = g_FirstAgent-&gt;btexec();
    }
}</pre>
<p>另外，如果程序端是通过Workspace::Update()的方式来统一执行所有Agent实例的行为树，则不需要再额外调用Workspace::DebugUpdate()方法，详见文章《<a href="/tutorial13_updateloop/">运行时端的执行流程</a>》。</p>
<p>启动程序，可以看到如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1814" src="/wp-content/uploads/2017/03/7H9AZWJN@HDGQGJ65A5.png" alt="" width="492" height="95" srcset="/wp-content/uploads/2017/03/7H9AZWJN@HDGQGJ65A5.png 492w, /wp-content/uploads/2017/03/7H9AZWJN@HDGQGJ65A5-300x58.png 300w" sizes="(max-width: 492px) 100vw, 492px" /></p>
<p>上面表示，程序端已经在开始等待编辑器的连接了。</p>
<p>点击编辑器工具栏中的“连接”按钮，如下图所示：</p>
<p id="RQIdnGB"><img class="size-full wp-image-1815 aligncenter" src="/wp-content/uploads/2017/03/img_58cba67af1592.png" alt="" /></p>
<p>在弹出的“连接游戏”窗口中，设置相应的IP和端口号后，点击“确认”按钮开始连接游戏，如下图所示：</p>
<p id="hKRboME"><img class="size-full wp-image-1816 aligncenter" src="/wp-content/uploads/2017/03/img_58cba7c708eff.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cba7c708eff.png 322w, /wp-content/uploads/2017/03/img_58cba7c708eff-300x130.png 300w" sizes="(max-width: 322px) 100vw, 322px" /></p>
<p>编辑器成功连接后，在左侧的实例节点列表中，会列出当前的Agent实例，如下图所示：</p>
<p id="FwnCHwE"><img class="size-full wp-image-1817 aligncenter" src="/wp-content/uploads/2017/03/img_58cba86cda189.png" alt="" /></p>
<p>在“输出”窗口中，可以看到程序端发送过来的所有消息，编辑器也正是根据这些消息来相应的刷新当前的高亮执行路径和处理断点、刷新成员属性的当前值等，如下图所示：</p>
<p id="uENnzEu"><img class="size-full wp-image-1822 aligncenter" src="/wp-content/uploads/2017/03/img_58cbab8f124bd.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cbab8f124bd.png 586w, /wp-content/uploads/2017/03/img_58cbab8f124bd-300x103.png 300w" sizes="(max-width: 586px) 100vw, 586px" /></p>
<p>鼠标双击实例节点列表中的节点FirstAgent_0_0，开始跟踪该实例的当前行为树的执行情况，可以看到行为树有了高亮的执行路径效果，表示当前返回Running的所有节点序列，如下图所示：</p>
<p id="LyMVOUW"><img class="size-full wp-image-1818 aligncenter" src="/wp-content/uploads/2017/03/img_58cba8ed9aff4.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cba8ed9aff4.png 1107w, /wp-content/uploads/2017/03/img_58cba8ed9aff4-300x101.png 300w, /wp-content/uploads/2017/03/img_58cba8ed9aff4-768x258.png 768w, /wp-content/uploads/2017/03/img_58cba8ed9aff4-1024x344.png 1024w" sizes="(max-width: 1107px) 100vw, 1107px" /></p>
<p>双击某个节点的左侧可以为该节点添加“进入”断点，双击某个节点的右侧可以为该节点添加“退出”断点，如下图所示：</p>
<p id="xaOSRWe"><img class="size-full wp-image-1820 aligncenter" src="/wp-content/uploads/2017/03/img_58cbaac86b0af.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cbaac86b0af.png 1102w, /wp-content/uploads/2017/03/img_58cbaac86b0af-300x103.png 300w, /wp-content/uploads/2017/03/img_58cbaac86b0af-768x263.png 768w, /wp-content/uploads/2017/03/img_58cbaac86b0af-1024x351.png 1024w" sizes="(max-width: 1102px) 100vw, 1102px" /></p>
<p>上图中高亮的断点，表示当前行为树的执行已经停在该处。点击Timeline工具栏中的“继续”按钮或直接按F5快捷键，可以继续执行行为树，如下图所示：</p>
<div>
<p id="dMOSqHw"><img class="size-full wp-image-1821 aligncenter" src="/wp-content/uploads/2017/03/img_58cbab355eaa5.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cbab355eaa5.png 608w, /wp-content/uploads/2017/03/img_58cbab355eaa5-300x31.png 300w, /wp-content/uploads/2017/03/img_58cbab355eaa5-604x63.png 604w" sizes="(max-width: 608px) 100vw, 608px" /></p>
</div>
<p>在属性窗口中，可以查看当前实例的所有成员属性及其当前值，如下图所示：</p>
<p id="NgzRIhh"><img class="size-full wp-image-1823 aligncenter" src="/wp-content/uploads/2017/03/img_58cbac32b3d92.png" alt="" srcset="/wp-content/uploads/2017/03/img_58cbac32b3d92.png 829w, /wp-content/uploads/2017/03/img_58cbac32b3d92-300x30.png 300w, /wp-content/uploads/2017/03/img_58cbac32b3d92-768x77.png 768w" sizes="(max-width: 829px) 100vw, 829px" /></p>
<p>为了方便调试，可以在上图中手工修改属性的值，该值会被发送到程序端，影响行为树的执行。</p>
<p>有关连调的使用还可以参考<a href="http://bbs.behaviac.com/index.php/tag/%E8%BF%9E%E8%B0%83">连调相关常见问题</a>。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_7">tutorials/tutorial_7</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_7_debug/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程8：结构体的添加和使用</title>
		<link>/tutorial_8_extend_structs/</link>
					<comments>/tutorial_8_extend_structs/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Wed, 05 Apr 2017 10:16:42 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1861</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 对于结构体类型的使用，包括新增全新的结构体和扩展使用已有的结构体。对于新增的结构<a class="moretag" href="/tutorial_8_extend_structs/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>对于结构体类型的使用，包括新增全新的结构体和扩展使用已有的结构体。对于新增的结构体，又包括编辑器是否自动生成该结构体的代码。</p>
<p>实际上，我们将新增结构体，又不自动生成该结构体代码的情况，认为跟扩展使用已有的结构体是一致的，即都是在程序端已经有了该结构体的定义代码（要么手工编写，要么第三方代码已经包含了该结构体的定义），不用再让编辑器自动生成。</p>
<p>进而，后文将只通过<strong>“生成代码”</strong>和<strong>“不生成代码”</strong>来区分上面所说的各种使用情况，但这里需要注意的是，生成或不生成代码，只是针对结构体本身的定义而言，而结构体相关的“胶水”代码都是会自动生成的，并且必须要整合到自己的项目中一起编译构建。</p>
<p>1. 如果是“生成代码”的情况，则忽略这一步说明。否则，如果是“不生成代码”的情况，这里假定程序端已经有了结构体类型文件FirstStruct.h，该文件中包含了结构体“FirstStruct”的定义，如下代码所示：</p>
<pre>struct FirstStruct
{
    int s1;
    float s2;
};</pre>
<p>2. 在类型信息浏览器中新增跟程序端同名的结构体类型“FirstStruct”，并且根据自己的需要，来决定是否勾选“生成代码”选项（如果只是扩展使用已有的结构体，则不需要勾选），如下图所示：</p>
<p><img class="size-full wp-image-1863 aligncenter" src="/wp-content/uploads/2017/04/img_58e4aa4ded2fa.png" alt="" srcset="/wp-content/uploads/2017/04/img_58e4aa4ded2fa.png 368w, /wp-content/uploads/2017/04/img_58e4aa4ded2fa-300x219.png 300w" sizes="(max-width: 368px) 100vw, 368px" /></p>
<p>3. 上图中的“引用类型”选项，一般不用勾选，表示在行为树编辑器中可以为该结构体配置其成员属性，并且在该结构体的两个实例做比较运算时，会比较所有的成员属性。否则，如果勾选了“引用类型”选项，则表示该结构体在行为树中使用时是作为引用类型来使用，在该结构体的两个实例做比较运算时，只会比较两个实例的引用（指针），而不比较其内容（成员属性）。</p>
<p>4. 为结构体“FirstStruct”添加成员属性s1和s2，这跟程序端的定义保持一致，如下图所示：</p>
<p id="pxEYVoj"><img class="size-full wp-image-1864 aligncenter" src="/wp-content/uploads/2017/04/img_58e4afe7d87ff.png" alt="" srcset="/wp-content/uploads/2017/04/img_58e4afe7d87ff.png 612w, /wp-content/uploads/2017/04/img_58e4afe7d87ff-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>5. 对于C++版的运行时库，如果是“生成代码”的情况，则忽略这一步操作。否则，如果是“不生成代码”的情况，则说明程序端已经有了包含该结构体类型的头文件。点击上图右上方的“设置头文件”按钮，弹出“C++导出设置”窗口，并添加已有的结构体头文件FirstStruct.h，如下图所示：</p>
<p id="FOhtzdA"><img class="size-full wp-image-1866 aligncenter" src="/wp-content/uploads/2017/04/img_58e4b98a80a3b.png" alt="" srcset="/wp-content/uploads/2017/04/img_58e4b98a80a3b.png 524w, /wp-content/uploads/2017/04/img_58e4b98a80a3b-300x155.png 300w" sizes="(max-width: 524px) 100vw, 524px" /></p>
<p>6. 点击类型信息浏览器右下方的“应用”按钮，这样会在“代码生成位置”中生成该结构体的定义（如果上面勾选了“生成代码”选项）及相关的“胶水”代码<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_8/cpp/behaviac_generated/types/internal/behaviac_customized_types.h">behaviac_customized_types.h</a>等文件，如下代码所示：</p>
<pre>BEHAVIAC_EXTEND_EXISTING_TYPE_EX(FirstStruct, false);
BEHAVIAC_DECLARE_TYPE_VECTOR_HANDLER(FirstStruct);

// 如下结构体的定义代码，会根据是否勾选了上面所说的“生成代码”选项来决定是否生成
 
struct FirstStruct
{
    int s1;
    float s2;
};

// 如下代码，不管是否勾选了“生成代码”选项，都会自动生成

BEHAVIAC_EXTEND_EXISTING_TYPE_EX(FirstStruct, false);
BEHAVIAC_DECLARE_TYPE_VECTOR_HANDLER(FirstStruct);

template&lt; typename SWAPPER &gt;
inline void SwapByteImplement(FirstStruct&amp; v)
{
    SwapByteImplement&lt; SWAPPER &gt;(v.s1);
    SwapByteImplement&lt; SWAPPER &gt;(v.s2);
}

namespace behaviac
{
    namespace PrivateDetails
    {
        template&lt;&gt;
        inline bool Equal(const FirstStruct&amp; lhs, const FirstStruct&amp; rhs)
        {
            return Equal(lhs.s1, rhs.s1)
                &amp;&amp; Equal(lhs.s2, rhs.s2);
         }
     }
}</pre>
<p>7. 为FirstAgent类新增成员属性p1，其类型是结构体FirstStruct，如下图所示：</p>
<p id="jMyHgCv"><img class="size-full wp-image-1871 aligncenter" src="/wp-content/uploads/2017/04/img_58e4cdeba978e.png" alt="" srcset="/wp-content/uploads/2017/04/img_58e4cdeba978e.png 612w, /wp-content/uploads/2017/04/img_58e4cdeba978e-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>8. 点击类型信息浏览器右下方的“应用”按钮，将“代码生成位置”中<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_8/cpp/behaviac_generated/types/">behaviac_generated/types</a>目录下所有生成的代码文件，添加到自己的项目中一起编译构建。</p>
<p>9. 新增行为树“StrcutBT”，并使用成员属性p1来赋值和做比较运算，如下图所示：</p>
<p id="LrmqVUt"><img class="size-full wp-image-1867 aligncenter" src="/wp-content/uploads/2017/04/img_58e4bce69495e.png" alt="" srcset="/wp-content/uploads/2017/04/img_58e4bce69495e.png 823w, /wp-content/uploads/2017/04/img_58e4bce69495e-300x112.png 300w, /wp-content/uploads/2017/04/img_58e4bce69495e-768x286.png 768w" sizes="(max-width: 823px) 100vw, 823px" /></p>
<p>10. 执行该行为树，得到如下执行结果：<br />
<img class="aligncenter size-full wp-image-1868" src="/wp-content/uploads/2017/04/HGQ3LJ5J22UE48BNU.png" alt="" width="179" height="145" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_8">tutorials/tutorial_8</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_8_extend_structs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程9：枚举的添加和使用</title>
		<link>/tutorial_9_extend_enum/</link>
					<comments>/tutorial_9_extend_enum/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Mon, 10 Apr 2017 03:22:33 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1878</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 对于枚举类型的使用，包括新增全新的枚举和扩展使用已有的枚举。对于新增的枚举，又包<a class="moretag" href="/tutorial_9_extend_enum/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>对于枚举类型的使用，包括新增全新的枚举和扩展使用已有的枚举。对于新增的枚举，又包括编辑器是否自动生成该枚举的代码。</p>
<p>实际上，我们将新增枚举，又不自动生成该枚举代码的情况，认为跟扩展使用已有的枚举是一致的，即都是在程序端已经有了该枚举的定义代码（要么手工编写，要么第三方代码已经包含了该枚举的定义），不用再让编辑器自动生成。</p>
<p>进而，后文将只通过<strong>“生成代码”</strong>和<strong>“不生成代码”</strong>来区分上面所说的各种使用情况，但这里需要注意的是，生成或不生成代码，只是针对枚举本身的定义而言，而枚举相关的“胶水”代码都是会自动生成的，并且必须要整合到自己的项目中一起编译构建。</p>
<p>1. 如果是“生成代码”的情况，则忽略这一步说明。否则，如果是“不生成代码”的情况，这里假定程序端已经有了枚举类型文件FirstEnum.h，该文件中包含了枚举“FirstEnum”的定义，如下代码所示：</p>
<pre>enum FirstEnum
{
    e1,
    e2,
    e3
};</pre>
<p>2. 在类型信息浏览器中新增跟程序端同名的枚举类型“FirstEnum”，并且根据自己的需要，来决定是否勾选“生成代码”选项（如果只是扩展使用已有的枚举，则不需要勾选），如下图所示：</p>
<p><img class="aligncenter size-full wp-image-1880" src="/wp-content/uploads/2017/04/UNTAFB25PBQRD_DMN.png" alt="" width="365" height="263" srcset="/wp-content/uploads/2017/04/UNTAFB25PBQRD_DMN.png 365w, /wp-content/uploads/2017/04/UNTAFB25PBQRD_DMN-300x216.png 300w" sizes="(max-width: 365px) 100vw, 365px" /></p>
<p>3. 为枚举“FirstEnum”添加成员e1、e2和e3，这跟程序端的定义保持一致，如下图所示：</p>
<p id="llHMYON"><img class="size-full wp-image-1889 aligncenter" src="/wp-content/uploads/2017/04/img_58eafbec92aca.png" alt="" srcset="/wp-content/uploads/2017/04/img_58eafbec92aca.png 612w, /wp-content/uploads/2017/04/img_58eafbec92aca-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>4. 对于C++版的运行时库，如果是“生成代码”的情况，则忽略这一步操作。否则，如果是“不生成代码”的情况，则说明程序端已经有了包含该枚举类型的头文件。点击上图右上方的“设置头文件”按钮，弹出“C++导出设置”窗口，并添加已有的枚举类型头文件FirstEnum.h，如下图所示：</p>
<p id="EAOktLA"><img class="size-full wp-image-1882 aligncenter" src="/wp-content/uploads/2017/04/img_58eaf86e332c8.png" alt="" srcset="/wp-content/uploads/2017/04/img_58eaf86e332c8.png 524w, /wp-content/uploads/2017/04/img_58eaf86e332c8-300x155.png 300w" sizes="(max-width: 524px) 100vw, 524px" /></p>
<p>5. 点击类型信息浏览器右下方的“应用”按钮，这样会在“代码生成位置”中生成该枚举的定义（如果上面勾选了“生成代码”选项）及相关的“胶水”代码<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_9/cpp/behaviac_generated/types/internal/behaviac_customized_types.h">behaviac_customized_types.h</a>和<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_9/cpp/behaviac_generated/types/internal/behaviac_customized_types.cpp">behaviac_customized_types.cpp</a>等文件，如下代码所示：</p>
<pre>// behaviac_customized_types.h

// 如下枚举的定义代码，会根据是否勾选了上面所说的“生成代码”选项来决定是否生成

enum FirstEnum
{
    e1,
    e2,
    e3,
};

// 如下代码，不管是否勾选了“生成代码”选项，都会自动生成
 
DECLARE_BEHAVIAC_ENUM_EX(FirstEnum, FirstEnum);
BEHAVIAC_DECLARE_TYPE_VECTOR_HANDLER(FirstEnum);


// behaviac_customized_types.cpp

BEHAVIAC_BEGIN_ENUM_EX(FirstEnum, FirstEnum)
{
    BEHAVIAC_ENUMCLASS_DISPLAY_INFO_EX(L"FirstEnum", L"");

    BEHAVIAC_ENUM_ITEM_EX(e1, "e1");
    BEHAVIAC_ENUM_ITEM_EX(e2, "e2");
    BEHAVIAC_ENUM_ITEM_EX(e3, "e3");
}
BEHAVIAC_END_ENUM_EX()</pre>
<p id="CpEirBJ">6. 为FirstAgent类新增成员属性p1，其类型是枚举“FirstEnum”，如下图所示：</p>
<p id="CmrqJLa"><img class="size-full wp-image-1883 aligncenter" src="/wp-content/uploads/2017/04/img_58eaf9f4a4b79.png" alt="" srcset="/wp-content/uploads/2017/04/img_58eaf9f4a4b79.png 612w, /wp-content/uploads/2017/04/img_58eaf9f4a4b79-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>7. 点击类型信息浏览器右下方的“应用”按钮，将“代码生成位置”中<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_9/cpp/behaviac_generated/types/">behaviac_generated/types</a>目录下所有生成的代码文件，添加到自己的项目中一起编译构建。</p>
<p>8. 新增行为树“EnumBT”，并使用成员属性p1来赋值和做比较运算，如下图所示：</p>
<p id="LrmqVUt"><img class="aligncenter size-full wp-image-1884" src="/wp-content/uploads/2017/04/MSNFMW7Q6EURC2KZS_9B.png" alt="" width="823" height="292" srcset="/wp-content/uploads/2017/04/MSNFMW7Q6EURC2KZS_9B.png 823w, /wp-content/uploads/2017/04/MSNFMW7Q6EURC2KZS_9B-300x106.png 300w, /wp-content/uploads/2017/04/MSNFMW7Q6EURC2KZS_9B-768x272.png 768w" sizes="(max-width: 823px) 100vw, 823px" /></p>
<p>9. 执行该行为树，得到如下执行结果：<br />
<img class="aligncenter size-full wp-image-1887" src="/wp-content/uploads/2017/04/AJHJULEHE0FKBDAI7F.png" alt="" width="166" height="145" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_9">tutorials/tutorial_9</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_9_extend_enum/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程10：定制自己的读取方式来加载行为树</title>
		<link>/tutorial_10_extent_filemanager/</link>
					<comments>/tutorial_10_extent_filemanager/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Thu, 13 Apr 2017 06:16:45 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1905</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 有的时候，由于自身项目的需要，例如对行为树文件进行加密、打包等处理，behavi<a class="moretag" href="/tutorial_10_extent_filemanager/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>有的时候，由于自身项目的需要，例如对行为树文件进行加密、打包等处理，behaviac组件默认提供的文件加载机制不再满足需要，因此程序端需要定制自己的读取方式来加载行为树文件。</p>
<h2>C++版</h2>
<p>1. 需要从behaviac::CFileManager派生出自己的子类，并根据需要重载相关的方法，如下代码所示：</p>
<pre>#include "behaviac/common/file/filemanager.h"

<strong>class BEHAVIAC_API MyFileManager : public behaviac::CFileManager</strong>
{
public:
    <strong>BEHAVIAC_DECLARE_MEMORY_OPERATORS(MyFileManager);</strong>

    MyFileManager();
    virtual ~MyFileManager();

    virtual behaviac::IFile* FileOpen(const char* fileName, behaviac::CFileSystem::EOpenMode iOpenAccess = behaviac::CFileSystem::EOpenMode_Read);

    virtual void FileClose(behaviac::IFile* file);
    virtual bool FileExists(const char* fileName);
    virtual bool FileExists(const behaviac::string&amp; filePath, const behaviac::string&amp; ext);

    virtual uint64_t FileGetSize(const char* fileName);
    virtual behaviac::wstring GetCurrentWorkingDirectory();
};</pre>
<p>2. 根据自己的开发平台需要，实现相应的方法，这里只是简单的调用了基类的同名方法，仅用于演示流程，如下代码所示：</p>
<pre>#include "myfilemanager.h"

MyFileManager::MyFileManager()
{
}

MyFileManager::~MyFileManager()
{
}

behaviac::IFile* MyFileManager::FileOpen(const char* fileName, behaviac::CFileSystem::EOpenMode iOpenAccess)
{
    // 需要实现自己的代码，这里直接调用基类的方法仅供演示
    return CFileManager::FileOpen(fileName, iOpenAccess);
}

void MyFileManager::FileClose(behaviac::IFile* file)
{
    CFileManager::FileClose(file);
}

bool MyFileManager::FileExists(const behaviac::string&amp; filePath, const behaviac::string&amp; ext)
{
    return CFileManager::FileExists(filePath, ext);
}

bool MyFileManager::FileExists(const char* fileName)
{
    return CFileManager::FileExists(fileName);
}

uint64_t MyFileManager::FileGetSize(const char* fileName)
{
    return CFileManager::FileGetSize(fileName);
}

behaviac::wstring MyFileManager::GetCurrentWorkingDirectory()
{
    return CFileManager::GetCurrentWorkingDirectory();
}</pre>
<p>3. 在程序端初始化的地方，创建MyFileManager实例，如下代码所示：</p>
<pre>bool InitBehavic()
{
    LOGI("InitBehavic\n");

    <strong>g_MyFileManager = BEHAVIAC_NEW MyFileManager();</strong>

    behaviac::Workspace::GetInstance()-&gt;SetFilePath("../tutorials/tutorial_10/cpp/exported");

    behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_xml);

    return true;
}</pre>
<p>4. 调用Agent::btload()方法，就可以通过上面实现的MyFileManager来加载行为树文件了（Agent::btload()方法内部会执行到MyFileManager::FileOpen()方法），如下代码所示：</p>
<pre>bool InitPlayer()
{
    LOGI("InitPlayer\n");

    g_FirstAgent = behaviac::Agent::Create&lt;FirstAgent&gt;();

    <strong>bool bRet = g_FirstAgent-&gt;btload("FirstBT");</strong>

    g_FirstAgent-&gt;btsetcurrent("FirstBT");

    return bRet;
}</pre>
<p>5. 在程序端结束清理的地方，销毁上面创建的MyFileManager实例，如下代码所示：</p>
<pre>void CleanupBehaviac()
{
    LOGI("CleanupBehaviac\n");

    behaviac::Workspace::GetInstance()-&gt;Cleanup();

    if (g_MyFileManager)
    {
        <strong>BEHAVIAC_DELETE(g_MyFileManager);</strong>
        g_MyFileManager = NULL;
    }
}</pre>
<h2>C#版</h2>
<p>1. 需要从behaviac.FileManager派生出自己的子类，并根据需要重载相关的方法，这里只是简单的调用了基类的同名方法，仅用于演示流程，如下代码所示：</p>
<pre><strong>public class MyFileManager : behaviac.FileManager</strong>
{
    public MyFileManager()
    {
    }

    public override byte[] FileOpen(string filePath, string ext)
    {
        // 需要实现自己的代码，这里直接调用基类的方法仅供演示
        return base.FileOpen(filePath, ext);
    }

    public override void FileClose(string filePath, string ext, byte[] fileHandle)
    {
        base.FileClose(filePath, ext, fileHandle);
    }
}</pre>
<p>2. 在程序端初始化的地方，创建MyFileManager实例，如下代码所示：</p>
<pre>static bool InitBehavic()
{
    Console.WriteLine("InitBehavic");

    <strong>g_MyFileManager = new MyFileManager();</strong>

    behaviac.Workspace.Instance.FilePath = "../../exported";
    behaviac.Workspace.Instance.FileFormat = behaviac.Workspace.EFileFormat.EFF_xml;

    return true;
}</pre>
<p>3. 调用Agent.btload()方法，就可以通过上面实现的MyFileManager来加载行为树文件了（Agent.btload()方法内部会执行到MyFileManager.FileOpen()方法），如下代码所示：</p>
<pre>static bool InitPlayer()
{
    Console.WriteLine("InitPlayer");

    g_FirstAgent = new FirstAgent();

    <strong>bool bRet = g_FirstAgent.btload("FirstBT");</strong>
    Debug.Assert(bRet);

    g_FirstAgent.btsetcurrent("FirstBT");

    return bRet;
}</pre>
<p>4. 在程序端结束清理的地方，释放上面创建的MyFileManager实例引用，如下代码所示：</p>
<pre>static void CleanupBehaviac()
{
    Console.WriteLine("CleanupBehaviac");

    behaviac.Workspace.Instance.Cleanup();

    <strong>g_MyFileManager = null;</strong>
}</pre>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_10">tutorials/tutorial_10</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_10_extent_filemanager/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程11：使用Android Studio编译构建behaviac</title>
		<link>/tutorial_11_android_studio/</link>
					<comments>/tutorial_11_android_studio/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Wed, 26 Apr 2017 03:47:20 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1982</guid>

					<description><![CDATA[Android Studio是一个为Android平台开发程序的集成开发环境，可供开发者免费使用。需要在官网下载并安装最新版的Android Studio，然后<a class="moretag" href="/tutorial_11_android_studio/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>Android Studio是一个为Android平台开发程序的集成开发环境，可供开发者免费使用。需要在<a href="https://developer.android.com/studio/index.html">官网</a>下载并安装最新版的Android Studio，然后继续后文的编译构建。</p>
<p>可以参考源码包中<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_11">tutorials/tutorial_11</a>的做法类似构建自己的项目，具体步骤如下：</p>
<p>1. 新建自己的项目。这里我们直接打开已有的<a href="https://github.com/Tencent/behaviac/blob/master/build/android_studio/behaviac_android">behaviac_android</a>项目，如下图所示：</p>
<p id="kdYtPSD"><img class="size-full wp-image-1990 aligncenter" src="/wp-content/uploads/2017/04/img_59001c9c9fb84.png" alt="" srcset="/wp-content/uploads/2017/04/img_59001c9c9fb84.png 495w, /wp-content/uploads/2017/04/img_59001c9c9fb84-300x292.png 300w" sizes="(max-width: 495px) 100vw, 495px" /></p>
<p>2. 双击打开<a href="https://github.com/Tencent/behaviac/blob/master/build/android_studio/behaviac_android/app/build.gradle">build.gradle</a>文件，如下图所示：</p>
<p><!--StartFragment --></p>
<p><img class="aligncenter size-full wp-image-1985" src="/wp-content/uploads/2017/04/U9ADKNKBJ1EPAX5WR11EM.png" alt="" width="583" height="390" srcset="/wp-content/uploads/2017/04/U9ADKNKBJ1EPAX5WR11EM.png 583w, /wp-content/uploads/2017/04/U9ADKNKBJ1EPAX5WR11EM-300x201.png 300w" sizes="(max-width: 583px) 100vw, 583px" /></p>
<p>3. 在打开的文件中，修改cmake文件的相对路径，如下代码所示：</p>
<div>
<pre>externalNativeBuild {
    cmake {
        path "../../../../CMakeLists.txt"
    }
}</pre>
</div>
<div>
<p>这是由于<a href="https://github.com/Tencent/behaviac/blob/master/CMakeLists.txt">CMakeLists.txt</a>所在的路径在源码包的最顶级，如下图所示：</p>
<p id="mvVbtJP"><img class="size-full wp-image-1986 aligncenter" src="/wp-content/uploads/2017/04/img_59000a14869f8.png" alt="" srcset="/wp-content/uploads/2017/04/img_59000a14869f8.png 228w, /wp-content/uploads/2017/04/img_59000a14869f8-153x300.png 153w" sizes="(max-width: 228px) 100vw, 228px" /></p>
<p>需要参考上面的CMakeLists.txt，用于编译构建behaviac组件。在这个CMakeLists.txt文件中，还需要添加自己的项目，这里是tutorial_11来做示范，如下代码所示：</p>
<pre>add_subdirectory ("${PROJECT_SOURCE_DIR}/tutorials/tutorial_11/cpp")</pre>
</div>
<div>
<p>4. 在tutorial_11项目中，也有自己的<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_11/cpp/CMakeLists.txt">CMakeLists.txt</a>，这个文件用于示范如何编译构建自己的项目，如下图所示：</p>
<p id="iWFpGqe"><img class="size-full wp-image-1987 aligncenter" src="/wp-content/uploads/2017/04/img_59000b40d531b.png" alt="" srcset="/wp-content/uploads/2017/04/img_59000b40d531b.png 330w, /wp-content/uploads/2017/04/img_59000b40d531b-300x192.png 300w" sizes="(max-width: 330px) 100vw, 330px" /></p>
</div>
<p>打开该文件，可以看到我们将tutorial_11作为一个lib来编译构建，如下代码所示：</p>
<pre>if (BEHAVIAC_ANDROID_STUDIO)
   add_library(tutorial_11 SHARED ${BTUNITTEST_INC} ${BTUNITTEST_SRC})
else()
   # add the executable
   add_executable(tutorial_11 ${BTUNITTEST_INC} ${BTUNITTEST_SRC})
endif()

target_link_libraries (tutorial_11 libbehaviac ${CMAKE_THREAD_LIBS_INIT})</pre>
<p>5. 新建Android所需的assets目录，将behaviac编辑器导出的行为树和类型信息文件全部放在该目录中，如下图所示：</p>
<p id="wnufpRg"><img class="size-full wp-image-2007 aligncenter" src="/wp-content/uploads/2017/04/img_5902c241c3fa0.png" alt="" /></p>
<p>6. 在<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_11/cpp/tutorial_11.cpp">tutorial_11.cpp</a>文件的InitBehavic()方法中，调用了Workspace::SetFilePath()接口，设置行为树加载路径，<strong>必须要以“assets:/”字符串开头</strong>，如下代码所示：</p>
<pre>const char* InitBehavic()
{
    LOGI("InitBehavic\n");

#if !BEHAVIAC_CCDEFINE_ANDROID
    behaviac::Workspace::GetInstance()-&gt;SetFilePath("../tutorials/tutorial_11/cpp/exported");
#else
<strong>    behaviac::Workspace::GetInstance()-&gt;SetFilePath("assets:/behaviac/exported");</strong>
#endif

    behaviac::Workspace::GetInstance()-&gt;SetFileFormat(behaviac::Workspace::EFF_xml);

    return "InitBehavic\n";
}</pre>
<p>7. 在项目的<a href="https://github.com/Tencent/behaviac/blob/master/build/android_studio/behaviac_android/app/src/main/java/com/tencent/behaviac/behaviac_android/MainActivity.java">MainActivity.java</a>文件中，加载behaviac_gcc_debug和tutorial_11_gcc_debug库，如下代码所示：</p>
<pre>static {
    System.loadLibrary("behaviac_gcc_debug");
    System.loadLibrary("tutorial_11_gcc_debug");
}</pre>
<p>8. 在onCreate()方法中调用C++的方法（这样处理仅供示范），并将AssetManager实例传递给C++端，如下代码所示：</p>
<pre>protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Example of a call to a native method
    TextView tv = (TextView) findViewById(R.id.sample_text);
    tv.setText(<strong>TestMain(getApplication().getAssets())</strong>);
}

public native String TestMain(android.content.res.AssetManager assetManager);</pre>
<p>9. 在<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_11/cpp/tutorial_11.cpp">tutorial_11.cpp</a>文件中，实现了上一步中的TestMain()方法，调用接口Workspace::SetAssetManager()设置AssetManager实例，如下代码所示：</p>
<pre>extern "C"
JNIEXPORT jstring JNICALL
Java_com_tencent_behaviac_behaviac_1android_MainActivity_TestMain(JNIEnv* env, jclass cls, jobject assetManager)
{
    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
    BEHAVIAC_ASSERT(mgr);

    <strong>behaviac::CFileManager::GetInstance()-&gt;SetAssetManager(mgr);</strong>

    std::string str = <strong>TestBehaviac();</strong>

    return env-&gt;NewStringUTF(str.c_str());
}</pre>
<p>&nbsp;</p>
<p>10. 编译构建APK包，并安装运行，结果如下图所示：</p>
<p id="oWrYuZH"><img class="size-full wp-image-1992 aligncenter" src="/wp-content/uploads/2017/04/img_59001ddad05df.png" alt="" /></p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_11">tutorials/tutorial_11</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_11_android_studio/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程12：并行节点的使用</title>
		<link>/tutorial_12_parallel/</link>
					<comments>/tutorial_12_parallel/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Tue, 25 Apr 2017 04:04:20 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1939</guid>

					<description><![CDATA[本文档描述的是3.6.34及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 并行节点用于一般意义上并行的执行所有子节点，相关的功能和属性说明详见手册《<a class="moretag" href="/tutorial_12_parallel/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6.34及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>并行节点用于一般意义上并行的执行所有子节点，相关的功能和属性说明详见手册《<a href="/language/zh/parallel/">并行节点</a>》。</p>
<p>并行节点容易在其属性配置上产生误用，本文将结合行为树中对并行节点的实际使用来加以说明。</p>
<p>1. 首先创建Agent子类“FirstAgent”及其成员属性p1和成员方法Say(behaviac::string&amp; value, bool isLatent)，Say()方法用于打印指定的参数，如下图所示：</p>
<p id="AhQHURQ"><img class="size-full wp-image-2031 aligncenter" src="/wp-content/uploads/2017/05/img_5909a93aaff59.png" alt="" srcset="/wp-content/uploads/2017/05/img_5909a93aaff59.png 612w, /wp-content/uploads/2017/05/img_5909a93aaff59-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<p>Say()方法表示对于isLatent为真的情况，在第三帧后返回成功，前两帧返回正在执行；而对于isLatent为假的情况，在第一帧就直接返回成功，其实现代码如下所示：</p>
<pre>behaviac::EBTStatus FirstAgent::Say(behaviac::string&amp; value, bool isLatent)
{
///&lt;&lt;&lt; BEGIN WRITING YOUR CODE Say
    if (isLatent &amp;&amp; behaviac::Workspace::GetInstance()-&gt;GetFrameSinceStartup() &lt; 3)
    {
        printf("\n%s [Running]\n\n", value.c_str());

        return behaviac::BT_RUNNING;
    }

    printf("\n%s [Success]\n\n", value.c_str());

    return behaviac::BT_SUCCESS;
///&lt;&lt;&lt; END WRITING YOUR CODE
}</pre>
<p>其中，当前帧数在主循环代码中每帧进行累加，如下代码所示：</p>
<pre>void UpdateLoop()
{
    LOGI("UpdateLoop\n");

    behaviac::Workspace::GetInstance()-&gt;SetFrameSinceStartup(0);

    behaviac::EBTStatus status = behaviac::BT_RUNNING;

    while (status == behaviac::BT_RUNNING)
    {
        behaviac::Workspace::GetInstance()-&gt;SetFrameSinceStartup(behaviac::Workspace::GetInstance()-&gt;GetFrameSinceStartup() + 1);

        LOGI("frame %d\n", behaviac::Workspace::GetInstance()-&gt;GetFrameSinceStartup());

        status = g_FirstAgent-&gt;btexec();
    }
}</pre>
<p>2. 创建行为树“ParallelBT”，其中并行节点有3个子节点，第一个是条件节点，第二和三个都是动作节点，如下图所示：</p>
<p id="NJvyZLO"><img class="size-full wp-image-2045 aligncenter" src="/wp-content/uploads/2017/05/img_59194b03da0fb.png" alt="" srcset="/wp-content/uploads/2017/05/img_59194b03da0fb.png 1098w, /wp-content/uploads/2017/05/img_59194b03da0fb-300x95.png 300w, /wp-content/uploads/2017/05/img_59194b03da0fb-768x242.png 768w, /wp-content/uploads/2017/05/img_59194b03da0fb-1024x323.png 1024w" sizes="(max-width: 1098px) 100vw, 1098px" /></p>
<p>3. 该并行节点的的属性默认配置如下图所示：</p>
<p><img class="size-full wp-image-1943 aligncenter" src="/wp-content/uploads/2017/04/img_58feb9cd3d315.png" alt="" srcset="/wp-content/uploads/2017/04/img_58feb9cd3d315.png 475w, /wp-content/uploads/2017/04/img_58feb9cd3d315-300x105.png 300w" sizes="(max-width: 475px) 100vw, 475px" /></p>
<ul>
<li><strong>失败条件：</strong>FAIL_ON_ONE表示一个子节点返回失败，那么并行节点就返回失败。</li>
<li><strong>成功条件：</strong>SUCCEED_ON_ALL表示所有子节点都返回成功，并行节点才返回成功。这里需要注意，失败条件优先于成功条件。</li>
<li><strong>子节点结束继续条件：</strong>CHILDFINISH_LOOP表示子节点结束后会重新再循环执行。</li>
<li><strong>退出行为：</strong>EXIT_ABORT_RUNNINGSIBLINGS表示当并行节点的成功或失败条件满足并返回成功或失败后，会终止掉其他还在运行的子节点。</li>
</ul>
<p>4. 执行该行为树，结果如下图所示：</p>
<p id="WKjlFhz"><img class="size-full wp-image-2035 aligncenter" src="/wp-content/uploads/2017/05/img_5909ab958726a.png" alt="" srcset="/wp-content/uploads/2017/05/img_5909ab958726a.png 214w, /wp-content/uploads/2017/05/img_5909ab958726a-137x300.png 137w" sizes="(max-width: 214px) 100vw, 214px" /></p>
<p>5. 将并行节点的属性“子节点结束继续条件”改为CHILDFINISH_ONCE，表示子节点结束后不再执行（除非重入该并行节点），如下图所示：</p>
<p id="ksHGkoe"><img class="size-full wp-image-1948 aligncenter" src="/wp-content/uploads/2017/04/img_58fec8784ee36.png" alt="" srcset="/wp-content/uploads/2017/04/img_58fec8784ee36.png 477w, /wp-content/uploads/2017/04/img_58fec8784ee36-300x103.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>6. 再执行该行为树，结果如下图所示：</p>
<p id="yzOtmuW"><img class="size-full wp-image-2036 aligncenter" src="/wp-content/uploads/2017/05/img_5909ac085f1a6.png" alt="" srcset="/wp-content/uploads/2017/05/img_5909ac085f1a6.png 217w, /wp-content/uploads/2017/05/img_5909ac085f1a6-175x300.png 175w" sizes="(max-width: 217px) 100vw, 217px" /></p>
<p>从上图可以看到，虽然一共循环了3次，但ID为7的动作节点只执行了一次，而ID为0的动作节点由于前两帧执行时返回Running，得到持续执行，直到第三帧返回Success或Failure。</p>
<p>7. 将并行节点的属性“失败条件”改为FAIL_ON_ALL，并将“成功条件”改为SUCCEED_ON_ONE，如下图所示：</p>
<p id="ecycJfE"><img class="size-full wp-image-1949 aligncenter" src="/wp-content/uploads/2017/04/img_58fec9ec1afdb.png" alt="" srcset="/wp-content/uploads/2017/04/img_58fec9ec1afdb.png 477w, /wp-content/uploads/2017/04/img_58fec9ec1afdb-300x104.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>8. 再执行该行为树，结果如下图所示：</p>
<p id="ZDFiGAF"><img class="size-full wp-image-2046 aligncenter" src="/wp-content/uploads/2017/05/img_59194b7c8c160.png" alt="" /></p>
<p>从上图可以看到，一共循环了1次，并行节点的所有子节点也都执行了1次。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_12">tutorials/tutorial_12</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_12_parallel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>教程13：随机与概率相关节点的使用</title>
		<link>/tutorial_13_random_nodes/</link>
					<comments>/tutorial_13_random_nodes/#respond</comments>
		
		<dc:creator><![CDATA[cainhuang]]></dc:creator>
		<pubDate>Tue, 25 Apr 2017 11:19:30 +0000</pubDate>
				<category><![CDATA[教程]]></category>
		<guid isPermaLink="false">/?p=1967</guid>

					<description><![CDATA[本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。 为了方便使用，behaviac组件除了提供传统的序列、选择等组合节点之外，还提供<a class="moretag" href="/tutorial_13_random_nodes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<pre>本文档描述的是3.6及以后版本，对于3.5及以前的老版本请参考分类“3.5”。</pre>
<p>为了方便使用，behaviac组件除了提供传统的序列、选择等组合节点之外，还提供了随机与概率相关的节点类型，主要包括<a href="/language/zh/sequencestochastic/">随机序列（SequenceStochastic）</a>、<a href="/language/zh/selectorstochastic/">随机选择（SelectorStochastic）</a>和<a href="/language/zh/selectorprobability/">概率选择（SelectorProbability）</a>等节点。</p>
<p>这3个节点对于初学者容易混淆，本文将结合行为树中对这3个节点的使用来分别加以说明。</p>
<h2><span class="ez-toc-section" id="1">1. 创建类型信息</span></h2>
<p>首先创建Agent子类“FirstAgent”及其成员方法Say(behaviac::string&amp; value)，Say()方法用于打印指定的参数，如下图所示：</p>
<p id="cLqSFmy"><img class="size-full wp-image-1945 aligncenter" src="/wp-content/uploads/2017/04/img_58febc064178c.png" alt="" srcset="/wp-content/uploads/2017/04/img_58febc064178c.png 612w, /wp-content/uploads/2017/04/img_58febc064178c-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></p>
<h2><span class="ez-toc-section" id="2">2. 随机序列节点</span></h2>
<p>如果对随机序列节点不熟悉，请首先查看其手册《<a href="/language/zh/sequencestochastic/">随机序列节点</a>》。</p>
<p>1. 创建行为树“sequencestochasticBT”，其中随机序列节点有3个动作子节点，分别输出“A”、“B”、“C”，如下图所示：</p>
<p id="RdIyQom"><img class="size-full wp-image-1968 aligncenter" src="/wp-content/uploads/2017/04/img_58ff13286fbe7.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff13286fbe7.png 947w, /wp-content/uploads/2017/04/img_58ff13286fbe7-300x93.png 300w, /wp-content/uploads/2017/04/img_58ff13286fbe7-768x237.png 768w" sizes="(max-width: 947px) 100vw, 947px" /></p>
<p>2. 随机序列节点的的属性“随机数”默认为空，表示使用系统默认的随机数产生器，当然也可以配置自己实现的随机数方法，这里我们保持为空即可，如下图所示：</p>
<p id="hEtkPWQ"><img class="size-full wp-image-1969 aligncenter" src="/wp-content/uploads/2017/04/img_58ff13b8973e4.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff13b8973e4.png 478w, /wp-content/uploads/2017/04/img_58ff13b8973e4-300x63.png 300w" sizes="(max-width: 478px) 100vw, 478px" /></p>
<p>3. 执行该行为树，结果如下图所示：</p>
<p id="YbFitvC"><img class="size-full wp-image-1970 aligncenter" src="/wp-content/uploads/2017/04/img_58ff14c07f01c.png" alt="" /></p>
<p>可以看到随机输出了“B”、“C”、“A”，但多次执行程序，发现都是输出这个顺序，并没有随机输出。这是由于没有调用随机种子方法，需要在代码中调用如下接口即可：</p>
<pre>#if BEHAVIAC_CCDEFINE_MSVC
    time_t timer;
    time(&amp;timer);

    behaviac::RandomGenerator::GetInstance()-&gt;setSeed((unsigned int)timer);
#endif</pre>
<h2><span class="ez-toc-section" id="3">3. 随机选择节点</span></h2>
<p>如果对随机选择节点不熟悉，请首先查看其手册《<a href="/language/zh/selectorstochastic/">随机选择节点</a>》。</p>
<p>1. 创建行为树“selectorstochasticBT”，其中随机选择节点有3个动作子节点，分别输出“A”、“B”、“C”，如下图所示：</p>
<p id="lAjLUVo"><img class="size-full wp-image-1971 aligncenter" src="/wp-content/uploads/2017/04/img_58ff2f4c29fee.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff2f4c29fee.png 925w, /wp-content/uploads/2017/04/img_58ff2f4c29fee-300x91.png 300w, /wp-content/uploads/2017/04/img_58ff2f4c29fee-768x233.png 768w" sizes="(max-width: 925px) 100vw, 925px" /></p>
<p>2. 随机选择节点的的属性“随机数”默认为空，表示使用系统默认的随机数产生器，当然也可以配置自己实现的随机数方法，这里我们保持为空即可，如下图所示：</p>
<p id="wyjDAMd"><img class="size-full wp-image-1972 aligncenter" src="/wp-content/uploads/2017/04/img_58ff2f7896b99.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff2f7896b99.png 478w, /wp-content/uploads/2017/04/img_58ff2f7896b99-300x63.png 300w" sizes="(max-width: 478px) 100vw, 478px" /></p>
<p>3. 执行该行为树，结果如下图所示：</p>
<p id="pbDGEOZ"><img class="size-full wp-image-1973 aligncenter" src="/wp-content/uploads/2017/04/img_58ff2f9fbf1cc.png" alt="" /></p>
<p>可以看到随机输出了“C”，多次执行程序，可以看到还会随机输出“A”或“B”。</p>
<h2><span class="ez-toc-section" id="4">4. 概率选择节点</span></h2>
<p>如果对概率选择节点不熟悉，请首先查看其手册《<a href="/language/zh/selectorprobability/">概率选择节点</a>》。</p>
<p>1. 创建行为树“selectorprobabilityBT”，其中概率选择节点有3个动作子节点，权值分别为20、30、50，表示分别会已20%、30%、50%的概率输出“A”、“B”、“C”，如下图所示：</p>
<p id="zQrSEOb"><img class="size-full wp-image-1974 aligncenter" src="/wp-content/uploads/2017/04/img_58ff3033c6eaa.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff3033c6eaa.png 1096w, /wp-content/uploads/2017/04/img_58ff3033c6eaa-300x71.png 300w, /wp-content/uploads/2017/04/img_58ff3033c6eaa-768x183.png 768w, /wp-content/uploads/2017/04/img_58ff3033c6eaa-1024x244.png 1024w" sizes="(max-width: 1096px) 100vw, 1096px" /></p>
<p>2. 概率选择节点节点的的属性“随机数”默认为空，表示使用系统默认的随机数产生器，当然也可以配置自己实现的随机数方法，这里我们保持为空即可，如下图所示：</p>
<p id="UTBKQlv"><img class="size-full wp-image-1975 aligncenter" src="/wp-content/uploads/2017/04/img_58ff3059aac62.png" alt="" srcset="/wp-content/uploads/2017/04/img_58ff3059aac62.png 477w, /wp-content/uploads/2017/04/img_58ff3059aac62-300x59.png 300w" sizes="(max-width: 477px) 100vw, 477px" /></p>
<p>3. 执行该行为树，结果如下图所示：</p>
<p id="TUIXabU"><img class="size-full wp-image-1976 aligncenter" src="/wp-content/uploads/2017/04/img_58ff30a48dadb.png" alt="" /></p>
<p>可以看到随机输出了“B”，多次执行程序，可以看到还会随机输出“A”或“C”。</p>
<p>本教程相关的工作区和代码工程详见源码包的目录<a href="https://github.com/Tencent/behaviac/blob/master/tutorials/tutorial_13">tutorials/tutorial_13</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial_13_random_nodes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
