<?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>jonygli &#8211; behaviac</title>
	<atom:link href="/language/zh/author/jonygli/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, 08 Aug 2017 03:19:05 +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>最新版3.6.36发布了！</title>
		<link>/version3_6_36/</link>
					<comments>/version3_6_36/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Thu, 03 Aug 2017 08:03:57 +0000</pubDate>
				<category><![CDATA[公告]]></category>
		<guid isPermaLink="false">/?p=2068</guid>

					<description><![CDATA[下载该版本点这里 修复Task参数访问时有子树时的bug 有任何问题可以去问答社区寻求帮助，或者去QQ群（433547396）寻求技术支持！]]></description>
										<content:encoded><![CDATA[<h6><span id="i" class="ez-toc-section"><a href="/language/zh/downloads/#3636_2017-08-03">下载该版本点这里</a></span></h6>
<ul>
<li>修复Task参数访问时有子树时的bug</li>
</ul>
<p>有任何问题可以去<a href="http://bbs.behaviac.com/">问答社区</a>寻求帮助，或者去QQ群（433547396）寻求技术支持！</p>
]]></content:encoded>
					
					<wfw:commentRss>/version3_6_36/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>behaviac到底是什么</title>
		<link>/what_is_behaviac/</link>
					<comments>/what_is_behaviac/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 10:02:27 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[概念]]></category>
		<guid isPermaLink="false">/?p=170</guid>

					<description><![CDATA[简述 behaviac是游戏AI的开发框架组件，也是游戏原型的快速设计工具。支持全平台，适用于客户端和服务器，助力游戏快速迭代开发 。 编辑器可以运行在PC上，<a class="moretag" href="/what_is_behaviac/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h2 id="section"><span class="ez-toc-section" id="i">简述</span></h2>
<p>behaviac是游戏AI的开发框架组件，也是游戏原型的快速设计工具。支持全平台，适用于客户端和服务器，助力游戏快速迭代开发 。</p>
<p>编辑器可以运行在PC上，操作方便直观可靠，支持实时和离线调试；编辑器可以导出xml，bson等多种格式，更可以导出C++、C#源码，提供最高效率。</p>
<p>运行时支持全平台，有C++和C#两个版本，原生支持Unity。</p>
<p>已被多款知名游戏及更多其他预研项目使用。</p>
<p>所有代码，包括编辑器和运行时<a href="https://github.com/Tencent/behaviac">全部开源https://github.com/Tencent/behaviac</a></p>
<h2 id="section-1"><span class="ez-toc-section" id="i-2">编辑器和运行时</span></h2>
<p>behaviac作为游戏AI的开发框架组件，有编辑器和运行时两个部分，这两个部分通过类型信息（描述AI实例属性和能力方法的信息）交换信息。<br />
<img class="aligncenter size-full wp-image-1406" src="/wp-content/uploads/2016/12/architecture-2.png" alt="" width="687" height="603" srcset="/wp-content/uploads/2016/12/architecture-2.png 687w, /wp-content/uploads/2016/12/architecture-2-300x263.png 300w" sizes="(max-width: 687px) 100vw, 687px" /></p>
<h3 id="section-2"><span class="ez-toc-section" id="i-3">类型信息</span></h3>
<p>类型信息用来描述类型的属性和方法。在3.5及之前的旧版本通过运行时端导出类型信息，3.6及之后的新版本通过编辑器创建类型信息，如下所示。编辑器中，该类型信息作为基本的语法单位用来创建行为树。</p>
<pre class="brush: cpp; title: ; notranslate">&lt;agent classfullname=&quot;framework::GameObject&quot; base=&quot;behaviac::Agent&quot; inherited=&quot;true&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; IsRefType=&quot;true&quot;&gt;
&lt;Member Name=&quot;HP&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Type=&quot;uint&quot; Class=&quot;framework::GameObject&quot; /&gt;
&lt;Member Name=&quot;age&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Type=&quot;long&quot; Class=&quot;framework::GameObject&quot; /&gt;
&lt;Method Name=&quot;GoStraight&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;void&quot;&gt;
&lt;Param DisplayName=&quot;speed&quot; Desc=&quot;speed&quot; Type=&quot;int&quot; /&gt;
&lt;/Method&gt;
&lt;Method Name=&quot;TurnTowardsTarget&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;int&quot;&gt;
&lt;Param DisplayName=&quot;turnSpeed&quot; Desc=&quot;turnSpeed&quot; Type=&quot;float&quot; /&gt;
&lt;/Method&gt;
&lt;Method Name=&quot;alignedWithPlayer&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;bool&quot; /&gt;
&lt;Method Name=&quot;playerIsAligned&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;bool&quot; /&gt;
&lt;Method Name=&quot;projectileNearby&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;bool&quot;&gt;
&lt;Param DisplayName=&quot;radius&quot; Desc=&quot;radius&quot; Type=&quot;float&quot; /&gt;
&lt;/Method&gt;
&lt;Method Name=&quot;distanceToPlayer&quot; DisplayName=&quot;&quot; Desc=&quot;&quot; Class=&quot;framework::GameObject&quot; ReturnType=&quot;float&quot; /&gt;
&lt;/agent&gt;</pre>
<p>在3.x版本之前的版本中，类型信息必须通过运行时来导出，策划需要新的属性或方法时，必须等待程序员更新代码重现导出类型信息后才能使用。而在3.x版本中，可以直接在编辑器中创建一个类型，并且创建它的属性和方法，而且可以导出类型的c++或c#源码，这极大的加速了迭代的过程，从而把编辑器作为一个原型设计工具。</p>
<h3 id="section-3"><span class="ez-toc-section" id="i-4">编辑器</span></h3>
<p>编辑器是一个可以运行在Windows平台上的编辑工具。<br />
<img src="/img/whatisbehaviac/designer.png" alt="designer" /><br />
在编辑器内，使用鼠标或快捷键，可以添加、编辑、配置、修改行为树（包括FSM，或HTN），也可以实时或离线调试游戏的行为，既可以设断点，也可以查看或修改变量的值。</p>
<h3 id="section-4"><span class="ez-toc-section" id="i-5">运行时</span></h3>
<p>运行时有C++和C#两个版本，Unity使用C#的实现，像是cocos等使用C++的引擎或平台使用C++的实现。其具体逻辑是一致的，即加载编辑器中导出的行为树，解释运行之。</p>
<pre class="brush: cpp; title: ; notranslate">

g_player = behaviac::Agent::Create&lt;CBTPlayer&gt;();

bool bRet = false;
bRet = g_player-&gt;btload(pszTreeName);
assert(bRet);

g_player-&gt;btsetcurrent(pszTreeName);

behaviac::EBTStatus status = behaviac::BT_RUNNING;

while (status == behaviac::BT_RUNNING)
{
status = g_player-&gt;btexec();
}</pre>
<div class="highlighter-rouge"></div>
<h3 id="section-5"><span class="ez-toc-section" id="i-6">导出和调试</span></h3>
<p>在编辑器内创建好行为后，需要导出，然后运行时才可以加载运行。编辑器支持导出多种格式：</p>
<ol>
<li>xml</li>
<li>bson</li>
<li>cpp</li>
<li>c#</li>
</ol>
<p>其中xml和bson作为数据，可以被加载，而cpp或c#作为源码直接编辑链接进程序，用户可以根据需要选择使用最合适的格式。</p>
<h2 id="behaviac"><span class="ez-toc-section" id="behaviac">behaviac能解决什么问题</span></h2>
<ul>
<li>behaviac作为游戏AI的开发框架组件，主要是用来开发游戏AI。</li>
<li>behaviac的编辑器使用图形化的界面（Visual scripting）和操作，操作直观方便。</li>
<li>游戏中的NPC，小怪，老怪等等的游戏逻辑都可以通过behaviac来创建和开发。</li>
<li>behaviac并不限于开发游戏AI的游戏逻辑，也可以用来开发组队逻辑（Squad Logic），策略AI（Strategy AI），玩家Avatar，甚至关卡设计等各种游戏场景。</li>
<li>behaviac还可以用作原型设计工具，策划只是使用behaviac编辑器来设计类型安全的，表达严谨的游戏逻辑。</li>
<li>C#版本的运行时原生支持unity，behaviac可以在unity内开发游戏AI</li>
<li>在iOS平台，作为热更新的一种手段</li>
<li>C++版本支持全平台，不仅可以用在客户端，也可以用在服务器端。一套逻辑，可以根据情况分别在客户端，服务器运行，避免重复开发。</li>
</ul>
<h2 id="behaviac-1"><span class="ez-toc-section" id="behaviac-2">behaviac有哪些主要特性</span></h2>
<ul>
<li>behaviac是游戏AI的开发框架组件，也是游戏原型的快速设计工具</li>
<li>支持持行为树（BT），状态机（FSM），层次任务网络（HTN）等多种范式</li>
<li>编辑器可以运行在PC上，操作方便直观可靠</li>
<li>编辑器可以导出xml，bson等多种格式，更可以导出C++，C#源码，提供最高效率</li>
<li>支持实时和离线调试，可以设断点，查看或修改变量</li>
<li>编辑器通过socket和游戏连接实现实时调试，支持远程实时调试</li>
<li>运行时支持全平台（Windows/Linux/iOS/Android等），有C++和C#两个版本，原生支持Unity。适用于客户端和服务器，助力游戏快速迭代开发</li>
<li>支持热加载，可以不用重启游戏就更新行为树</li>
<li>中英文界面可选，类型信息可以提供中英文显示信息</li>
<li>支持预制件（Prefab）、子树，方便重用共享</li>
<li>支持自定义数据类型，支持已有第3方库中的自定义类型</li>
<li>支持扩展节点类型</li>
</ul>
<hr />
<p><a href="/docs/zh/articles/overview/">可以继续阅读behaviac概述 →</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/what_is_behaviac/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>目录结构</title>
		<link>/directory/</link>
					<comments>/directory/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 09:58:37 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[上手]]></category>
		<category><![CDATA[概述]]></category>
		<guid isPermaLink="false">/?p=162</guid>

					<description><![CDATA[首先说明的是从下载链接获取的BehaviacSetup*.exe是安装包，内含可执行的编辑器及示例。 如果编辑器不能正常启动，需要下载安装Microsoft V<a class="moretag" href="/directory/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>首先说明的是从<a href="/language/zh/downloads/">下载链接</a>获取的BehaviacSetup*.exe是安装包，内含可执行的编辑器及示例。</p>
<p>如果编辑器不能正常启动，需要下载安装<a href="https://support.microsoft.com/en-us/kb/2977003">Microsoft Visual C++ 运行库</a>及<a href="https://www.microsoft.com/en-US/download/details.aspx?id=21">.net框架</a>。</p>
<p>可以从<a href="/language/zh/downloads/">下载链接</a>下载或从<a href="https://github.com/Tencent/behaviac">github</a>克隆源码，这里介绍的是源码的目录结构。</p>
<h3 id="section">目录结构图示</h3>
<p><img class="aligncenter size-full wp-image-1411" src="/wp-content/uploads/2016/04/directory.png" alt="directory" width="177" height="346" srcset="/wp-content/uploads/2016/04/directory.png 177w, /wp-content/uploads/2016/04/directory-153x300.png 153w" sizes="(max-width: 177px) 100vw, 177px" /></p>
<h3 id="section-1">目录结构说明</h3>
<ul>
<li>build：构建脚本，使用CMake构建。可以参考文档<a href="/language/zh/how_to_build/">《如何编译构建》</a>。</li>
<li>docs：文档，目前只有behaviac.chm，以后访问文档需要访问<a href="/">API</a></li>
<li>inc：运行时库的C++头文件</li>
<li>integration：Unity平台的实现及示例
<ul>
<li>demo_running：一个简单demo</li>
<li>unity：unity的实现及unittest</li>
</ul>
</li>
<li>projects：C++项目文件，用于打开unit test和tutorials等项目。这里的项目文件是预提供的，仅支持vs及make。如果需要其他平台，可以参考build目录下的构建脚本。</li>
<li>src：运行时库的C++源码</li>
<li>test：测试，C++
<ul>
<li>btperformance：简单的性能测试</li>
<li>btremotetest,：简单的连调测试</li>
<li>btunittest：C++ unit test</li>
<li>demo_running：简单的测试，适合少量修改，体会<a href="/docs/zh/articles/concepts/">行为树的概念</a></li>
<li>usertest：简单的测试，适合少量修改，做出自己的测试</li>
</ul>
</li>
<li>tools：编辑器的C#源码
<ul>
<li>designer</li>
</ul>
</li>
<li>tutorials：教程相关的源码，配合<a href="/language/zh/category/docs/tutorial/">教程相关文档</a>使用，方便上手</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>/directory/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>行为树的基本概念及进阶</title>
		<link>/concepts/</link>
					<comments>/concepts/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 09:56:50 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[概念]]></category>
		<guid isPermaLink="false">/?p=158</guid>

					<description><![CDATA[前言 开发游戏AI的目标之一就是要找到一个简单，可扩展的编辑逻辑的方案，从而加速游戏开发的迭代速度。在“行为系统图”中，行为系统（Behavior System<a class="moretag" href="/concepts/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h2><span class="ez-toc-section" id="i">前言</span></h2>
<p>开发游戏AI的目标之一就是要找到一个简单，可扩展的编辑逻辑的方案，从而加速游戏开发的迭代速度。在“行为系统图”中，行为系统（Behavior System）响应游戏中的各种信息，进行决策以挑选接下来将要执行的行动并且监控该行动的执行。<br />
<img src="/img/concepts/architecture.png" alt="行为系统图" /></p>
<p>知识模型（Knowledge Model）是对游戏世界中各种信息的抽象。</p>
<p>在行为系统中，有限状态机（FSM，Finite State Machine）最为经典，FSM模型的优势之一是简单。但是FSMs需要用转换（Transition）连接状态（State），因此，状态（State）失去了模块性（Modularity）。</p>
<p><img src="/img/concepts/fsm.png" alt="FSM" /></p>
<h2 id="section"><span class="ez-toc-section" id="i-2">什么是行为树</span></h2>
<p>行为树，英文是Behavior Tree，简称BT，是由行为节点组成的树状结构：<br />
<img src="/img/concepts/whatisbt.png" alt="什么是行为树" /></p>
<p>对于FSM，每个节点表示一个状态，而对于BT，每个节点表示一个行为。同样是由节点连接而成，BT有什么优势呢？</p>
<p>在BT中，节点是有层次（Hierarchical）的，子节点由其父节点来控制。每个节点的执行都有一个结果（成功Success，失败Failure或运行Running），该节点的执行结果都由其父节点来管理，从而决定接下来做什么，父节点的类型决定了不同的控制类型。节点不需要维护向其他节点的转换，节点的模块性（Modularity）被大大增强了。实际上，在BT里，由于节点不再有转换，它们不再是状态（State），而是行为（Behavior）。</p>
<p>由此可见，BT的主要优势之一就是其更好的封装性和模块性，让游戏逻辑更直观，开发者不会被那些复杂的连线绕晕。</p>
<h2 id="section-1"><span class="ez-toc-section" id="i-3">一个例子</span></h2>
<p><img src="/img/concepts/example1.png" alt="例子1" /><br />
上图中，3号Sequence节点有3个子节点，分别是：<br />
&#8211; 4号Condition节点<br />
&#8211; 5号Action节点<br />
&#8211; 6号Wait节点</p>
<p>而3号节点的父节点是2号的Loop节点。</p>
<p>先补充下各节点类型的执行逻辑（详见<a href="/intro/">节点说明</a>）：</p>
<ul>
<li>序列（Sequence）节点：顺序执行所有子节点返回成功，如果某个子节点失败返回失败。</li>
<li>循环（Loop）节点：循环执行子节点到指定次数后返回成功，如果循环次数为-1，则无限循环。</li>
<li>条件（Condition）节点：根据条件的比较结果，返回成功或失败。</li>
<li>动作（Action）节点：根据动作结果返回成功，失败，或运行。</li>
<li>等待（Wait）节点：当指定的时间过去后返回成功。</li>
</ul>
<h3 id="section-2"><span class="ez-toc-section" id="i-4">执行说明</span></h3>
<ul>
<li>如果4号条件节点的执行结果是成功，其父节点3号节点则继续执行5号节点，如果5号动作节点返回成功，则执行6号等待节点，如果6号节点返回成功，则3号节点全部执行完毕且会返回成功，那么2号节点继续下个迭代。</li>
<li>如果4号条件节点的执行结果是失败，其父节点3号节点则返回失败不再继续执行子节点，并且2号节点继续下个迭代。</li>
</ul>
<h2 id="section-3"><span class="ez-toc-section" id="i-5">进阶</span></h2>
<p>聪明的读者可能会问，上面的例子中只讲了成功或失败的情况，但如果动作要持续一段时间呢？如果5号节点，Fire需要持续一段时间呢？</p>
<ul>
<li>节点的执行结果可以是“成功”，“失败”，或“运行”。</li>
<li>对于持续运行一段时间的Fire动作，其执行结果持续返回“运行”，结束的时候返回“成功”。</li>
<li>对于持续运行一段时间的Wait动作，其执行结果持续返回“运行”，当等待时间到达的时候返回“成功”。</li>
</ul>
<p>当节点持续返回“运行”的时候，BT树的内部“知道”该节点是在持续“运行”的，从而在后续的执行过程中“直接”继续执行该节点，而不需要从头开始执行，直到该运行状态的节点返回“成功”或“失败”，从而继续后续的节点。从外面看，就像“阻塞”在了那个“运行”的节点上，其父节点就像不再管理，要一直等运行的子节点结束的时候，其父节点才再次接管</p>
<p>（请注意，这一段说明只是从概念上这样讲，概念上可以这样理解，实际上即使运行状态的节点每次执行也是要返回的，只是其返回值是运行，其父节点对于返回值是运行状态的节点，将使其继续，所以看上去好像父节点不再管理。）。</p>
<h2 id="a-nameanotherexample-a"><span class="ez-toc-section" id="i-6">另一个例子</span></h2>
<p><img src="/img/concepts/example2.png" alt="例子2" /><br />
如上图，为了清晰说明运行状态，来看另一个例子。在这个例子中，Condition，Action1，Action3是3个函数。</p>
<ul>
<li>0号节点是个Loop节点，循环3次。</li>
<li>1号节点是个Sequence节点</li>
<li>2号节点模拟一个条件，直接返回成功。</li>
<li>3号节点Action1是一个动作，直接返回成功。</li>
<li>4号节点Action3同样是一个动作，返回3次运行，然后返回成功。</li>
</ul>
<p>其代码如下：</p>
<div class="highlighter-rouge">
<pre class="highlight"><code><span class="n">bool</span> <span class="n">CBTPlayer</span><span class="o">::</span><span class="n">Condition</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">m_Frames</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\t</span><span class="s">Condition</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">behaviac</span><span class="o">::</span><span class="n">EBTStatus</span> <span class="n">CBTPlayer</span><span class="o">::</span><span class="n">Action1</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\t</span><span class="s">Action1</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">behaviac</span><span class="o">::</span><span class="n">BT_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">behaviac</span><span class="o">::</span><span class="n">EBTStatus</span> <span class="n">CBTPlayer</span><span class="o">::</span><span class="n">Action3</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\t</span><span class="s">Action3</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">m_Frames</span><span class="o">++</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_Frames</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">behaviac</span><span class="o">::</span><span class="n">BT_SUCCESS</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">behaviac</span><span class="o">::</span><span class="n">BT_RUNNING</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<p>而执行该BT树的C++代码如下：</p>
<div class="highlighter-rouge">
<pre class="highlight"><code>    <span class="kt">int</span> <span class="n">frames</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">behaviac</span><span class="o">::</span><span class="n">EBTStatus</span> <span class="n">status</span> <span class="o">=</span> <span class="n">behaviac</span><span class="o">::</span><span class="n">BT_RUNNING</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">status</span> <span class="o">==</span> <span class="n">behaviac</span><span class="o">::</span><span class="n">BT_RUNNING</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="err">\</span><span class="s">" frame "</span> <span class="o">&lt;&lt;</span> <span class="o">++</span><span class="n">frames</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
        <span class="n">status</span> <span class="o">=</span> <span class="n">g_player</span><span class="o">-&gt;</span><span class="n">btexec</span><span class="p">();</span>

        <span class="c1">//other codes
</span>    <span class="p">}</span>
</code></pre>
</div>
<p>上面的执行行为树的代码就如同游戏更新部分。<code class="highlighter-rouge">status = g_player-&gt;btexec()</code>是在游戏的更新函数（update或tick）里，需要每帧调用。<br />
特别的，对于运行状态，即使运行状态概念上讲是“阻塞”在节点，但是依然是每帧需要调用<code class="highlighter-rouge">btexec</code>，也就是说，其节点依然是每帧都在运行，只是下一帧是继续上一帧，从而表现的是运行状态，在其结束之前，其父节点不会把控制转移给其他后续节点。这里的“阻塞”并非真的被阻塞，并非后续的代码(上面的<code class="highlighter-rouge">other codes</code>部分)不会被执行。<code class="highlighter-rouge">status = g_player-&gt;btexec()</code>后面如果有代码，依然被执行。</p>
<p>执行结果会是个什么样的输出呢？</p>
<p><img src="/img/concepts/result.png" alt="结果" /></p>
<p>第1帧：<br />
2号节点Condition返回“成功”，继续执行3号Action1节点，同样返回“成功”，接续执行4号Action3，返回“运行”。</p>
<p><img src="/img/concepts/frame1.png" alt="frame1" /></p>
<p>第2帧：<br />
由于上一帧4号Action3返回“运行”，直接继续执行4号Action3节点。</p>
<p><img src="/img/concepts/frame2.png" alt="frame2" /></p>
<p>第3帧：<br />
由于上一帧4号Action3返回“运行”，直接继续执行4号Action3节点。</p>
<p><img src="/img/concepts/frame3.png" alt="frame3" /></p>
<p>同样需要注意的是，2号Condition节点不再被执行。</p>
<p>而且，本次Action3返回“成功”，1号Sequence节点返回成功。0号Loop节点结束第1次迭代。<br />
第4帧：<br />
Loop的第2次迭代开始，就像第1帧的执行。</p>
<p><img src="/img/concepts/frame4.png" alt="frame4" /></p>
<h2 id="section-4"><span class="ez-toc-section" id="i-7">再进阶</span></h2>
<p>又有聪明的读者要问了，持续返回“运行”状态的节点固然优化了执行，但其结果就像“阻塞”了BT的执行一样，如果发生了其他“重要”的事情需要处理怎么办？</p>
<p>在behaviac里至少有多种办法。</p>
<h3 id="httpwwwbehaviaccomdocszhreferencesattachment"><span class="ez-toc-section" id="i-8">使用<a href="/docs/zh/references/attachment/">前置</a></span></h3>
<p><img src="/img/references/preaction.png" alt="" /></p>
<p>每个节点都可以添加<a href="/docs/zh/references/attachment/">前置</a>附件或<a href="/docs/zh/references/attachment/">后置</a>附件。<br />
上图的action节点添加了一个前置，两个后置。</p>
<p>可以添加<a href="/docs/zh/references/attachment/">前置</a>附件，并且“执行时机”设为Update或Both，则在每次执行之前都会先执行前置里配置的条件。</p>
<h3 id="parallelhttpwwwbehaviaccomdocszhreferencesparallel"><span class="ez-toc-section" id="Parallel">使用<a href="/docs/zh/references/parallel/">Parallel</a>节点</span></h3>
<p><img src="/img/concepts/parallel.png" alt="parallel" /></p>
<p>如上图，可以使用Parallel节点来“一边检查条件，一边执行动作”，该条件作为该动作的“Guard”条件。当该条件失败的时候来结束该处于持续运行状态的动作节点。</p>
<h3 id="selectormonitorhttpwwwbehaviaccomdocszhreferencesselectormonitor"><span class="ez-toc-section" id="SelectorMonitor">使用<a href="/docs/zh/references/selectormonitor/">SelectorMonitor</a>节点</span></h3>
<p><img src="/img/concepts/selectormonitor.png" alt="selectormonitor" /></p>
<ul>
<li>SelectorMonitor是一个动态的选择节点，和Selector相同的是，它选择第一个success的节点，但不同的是，它不是只选择一次，而是每次执行的时候都对其子节点进行选择。如上图所示，假若它选择了下面有True条件的那个节点（节点7）并且下面的1号Sequence节点在运行状态，下一次它执行的时候，它依然会去检查上面的那个8号条件的子树，如果该条件为真，则终止下面的运行节点而执行9号节点。</li>
<li>WithPrecondition有precondition子树和action子树。只有precondition子树返回success的时候，action子树才能够被执行。</li>
</ul>
<h3 id="event"><span class="ez-toc-section" id="Event">使用Event子树</span></h3>
<p>任何一个BT都可以作为事件子树，作为event附加到任何的一个节点上(用鼠标拖动BT到节点)。当运行该BT的时候，如果发生了某个事件，可以通过Agent::FireEvent来触发该事件，则处于running状态的节点，<strong>从下到上</strong>都有机会检查是否需要响应该事件，如果有该事件配置，则相应的事件子树就会被触发。请参考behaviac的相关文档获取详细信息。</p>
<h2 id="section-5"><span class="ez-toc-section" id="i-9">总结</span></h2>
<p>行为树的基本概念：</p>
<ul>
<li>执行每个节点都会有一个结果（成功，失败或运行）</li>
<li>子节点的执行结果由其父节点控制和管理</li>
<li>返回运行结果的节点被视作处于运行状态，处于运行状态的节点将被持续执行一直到其返回结束（成功或失败）。在其结束前，其父节点不会把控制转移到后续节点。</li>
</ul>
<p>其中理解运行状态是理解行为树的关键，也是使用好行为树的关键。</p>
<h2 id="section-6"><span class="ez-toc-section" id="i-10">其他</span></h2>
<p>上文<a href="/docs/zh/articles/concepts/#anotherexample">另一个例子</a>中“demo_running”的例子在安装包及源码里都有提供。最好查看源码，编译运行，自行尝试体会。<br />
可以查看<a href="/docs/zh/articles/directory/">目录说明</a></p>
<p><img src="/img/concepts/demo_running_project.png" alt="demo_running_project" /></p>
<p>请指定demo_running作为参数或不指定任何参数运行demo_running：</p>
<p><img src="/img/concepts/demo_running_exec.jpg" alt="demo_running_exec" /></p>
<p><a href="https://github.com/Tencent/behaviac">源码及示例下载地址</a></p>
<div class="section-nav"></div>
]]></content:encoded>
					
					<wfw:commentRss>/concepts/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>等待节点</title>
		<link>/wait/</link>
					<comments>/wait/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 06 Jun 2016 10:11:17 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=460</guid>

					<description><![CDATA[等待（Wait）节点在指定的数值内（单位根据自己的使用场景来定）持续保持为运行（Running）状态，数值到达之后则返回成功，如下图所示： 需要配置“持续时间”<a class="moretag" href="/wait/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>等待（Wait）节点在指定的数值内（单位根据自己的使用场景来定）持续保持为运行（Running）状态，数值到达之后则返回成功，如下图所示：</p>
<p><img class="aligncenter" src="/img/references/wait.png" alt="wait" /></p>
<p>需要配置“持续时间”，可以是常数、属性或方法的返回值（支持double和int类型），如下图所示：</p>
<p><img class="aligncenter" src="/img/references/wait_prop.png" alt="wait" /></p>
<p>在工作区配置窗口中，可以勾选左下角的“使用整数值”来表示是否使用整数值，如下图所示：</p>
<p><img class="size-full wp-image-1163 aligncenter" src="/wp-content/uploads/2016/06/edit_workspace-1.png" alt="edit_workspace" width="587" height="272" srcset="/wp-content/uploads/2016/06/edit_workspace-1.png 587w, /wp-content/uploads/2016/06/edit_workspace-1-300x139.png 300w" sizes="(max-width: 587px) 100vw, 587px" /></p>
<p>如果勾选了“使用整数值”选项，那么在导出代码文件behaviac_agent_meta.cpp中，会自动生成Workspace::GetInstance()-&gt;SetUseIntValue(true)。</p>
<p>等待节点的更新逻辑是：</p>
<div class="highlighter-rouge">
<pre class="highlight"><code>bool bUseIntValue = Workspace::GetInstance()-&gt;GetUseIntValue();

if (bUseIntValue)
{
    long long time = Workspace::GetInstance()-&gt;GetIntValueSinceStartup();

    if (time - this-&gt;m_intStart &gt;= this-&gt;m_intTime)
    {
        return BT_SUCCESS;
    }
}
else
{
    double time = Workspace::GetInstance()-&gt;GetDoubleValueSinceStartup();

    if (time - this-&gt;m_start &gt;= this-&gt;m_time)
    {
        return BT_SUCCESS;
    }
}
</code></pre>
</div>
<p>因此，只有保证Workspace::GetInstance()-&gt;GetIntValueSinceStartup()或Workspace::GetInstance()-&gt;GetDoubleValueSinceStartup()正确的返回从游戏启动到现在的总时间，等待节点才能正确工作。</p>
<p>如果勾选了“使用整数值”选项，那么Workspace::GetInstance()-&gt;GetUseIntValue()将返回true，并且该总数值需要通过Workspace::GetInstance()-&gt;SetIntValueSinceStartup(long long value)设置，可以在自己的游戏更新函数中调用该函数。</p>
<p>如果没有勾选“使用整数值”选项，那么Workspace::GetInstance()-&gt;GetUseIntValue()将返回false。该总时间需要通过Workspace::GetInstance()-&gt;SetDoubleValueSinceStartup(double value)设置，可以在自己的游戏更新函数中调用该函数。</p>
<p>注意：在C#代码中相应的接口需改为Workspace.Instance.IntValueSinceStartup或Workspace.Instance.DoubleValueSinceStartup，默认实现方式是返回Unity的系统时间Time.realtimeSinceStartup，一般情况无需自己重新实现，直接使用即可，不用类似C++的接口每帧更新时调用Workspace.Instance.IntValueSinceStartup或Workspace.Instance.DoubleValueSinceStartup为其赋值。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/behaviortree/nodes/actions/wait.cpp">behaviortree/nodes/actions/wait.cpp</a></p>
<div class="section-nav"></div>
]]></content:encoded>
					
					<wfw:commentRss>/wait/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>等待帧数节点</title>
		<link>/waitframes/</link>
					<comments>/waitframes/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 06 Jun 2016 10:14:25 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=463</guid>

					<description><![CDATA[//www 图1 等待帧数节点 需要配置“帧数”，可以是常数、属性或方法的返回值（必须是int类型），如下图所示： 图2 等待帧数节点的属性 等待帧数节点的更新<a class="moretag" href="/waitframes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>//www</p>
<p><img src="/img/references/waitframes.png" alt="waitframes" /></p>
<p>图1 等待帧数节点</p>
<p>需要配置“帧数”，可以是常数、属性或方法的返回值（必须是int类型），如下图所示：</p>
<p><img src="/img/references/waitframes_prop.png" alt="waitframes" /></p>
<p>图2 等待帧数节点的属性</p>
<p>等待帧数节点的更新逻辑是:</p>
<div class="highlighter-rouge">
<pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">Workspace</span><span class="o">::</span><span class="n">GetInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">GetFrameSinceStartup</span><span class="p">()</span> <span class="o">-</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">m_start</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&gt;=</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">m_frames</span><span class="p">)</span>
<span class="p">{</span>
	<span class="k">return</span> <span class="n">BT_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<p>因此，只有保证Workspace::GetInstance()-&gt;GetFrameSinceStartup()正确的返回从游戏启动到当前的总帧数，等待帧数节点才能正确工作。</p>
<p>该总帧数需要通过Workspace::GetInstance()-&gt;SetFrameSinceStartup()设置，可以在自己的游戏更新函数中调用该函数。</p>
<p>注意：在C#代码中相应的接口需改为Workspace.Instance.FrameSinceStartup，默认实现方式是返回Unity的当前系统帧数Time.frameCount，一般情况无需自己重新实现，直接使用即可，不用类似以上C++的接口方式每帧更新时再额外调用Workspace.Instance.FrameSinceStartup为其赋值。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/behaviortree/nodes/actions/waitframes.cpp">behaviortree/nodes/actions/waitframes.cpp</a></p>
<div class="section-nav"></div>
]]></content:encoded>
					
					<wfw:commentRss>/waitframes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>状态机</title>
		<link>/fsm/</link>
					<comments>/fsm/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Fri, 13 May 2016 02:12:55 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=262</guid>

					<description><![CDATA[简介 behaviac组件不仅支持行为树，也支持有限状态机（FSM），并且支持行为树跟状态机的相互嵌套调用。 behaviac组件中的状态机主要用到了状态（St<a class="moretag" href="/fsm/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h2><span class="ez-toc-section" id="i">简介</span></h2>
<p>behaviac组件不仅支持行为树，也支持有限状态机（FSM），并且支持行为树跟状态机的相互嵌套调用。</p>
<p>behaviac组件中的状态机主要用到了状态（State）、等待状态（WaitState）和等待帧数状态（WaitFramesState）三种节点，以及条件转换（Transition）和总是转换（AlwaysTransition）两种附件，如下图所示：</p>
<p><img src="/img/references/fsm_nodes.png" alt="fsm_nodes" /></p>
<p>图1 状态机相关节点和附件</p>
<h2 id="section"><span class="ez-toc-section" id="i-2">状态节点</span></h2>
<p>状态节点（State）是状态机中的基本组成部分之一，可以在状态节点上添加前置、后置以及转换等附件，如下图所示：</p>
<p><img src="/img/references/state.png" alt="state" /></p>
<p>图2 状态节点</p>
<ul>
<li>在状态节点上添加的前置：表明进入该状态节点时，需要执行的操作。</li>
<li>在状态节点上添加的后置：表明退出该状态节点时，需要执行的操作。</li>
<li>在状态节点上添加的转换：表明满足该转换所表示的条件时，由当前状态切换到转换所指向的下一个状态。</li>
</ul>
<p>如下图所示，可以编辑状态节点的相关属性：</p>
<p><img src="/img/references/state_prop.png" alt="state" /></p>
<p>图3 状态节点的属性</p>
<ul>
<li>名字：为状态节点指定一个有意义的名字，以便区分其他状态节点。</li>
<li>方法：表示该状态节点需要执行的操作。</li>
<li>结束状态：如果勾选，表示该状态作为结束状态，即在执行完该状态节点之后，整个状态机也直接结束。该节点形状也将显示为RoundRectangle，以示区别。</li>
</ul>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/fsm/fsmstate.cpp">fsm/fsmstate.cpp</a></p>
<h2 id="section-1"><span class="ez-toc-section" id="i-3">等待状态节点</span></h2>
<p>等待状态节点（WaitState）是一种特殊的状态节点，可以在状态节点上添加前置、后置以及等待转换等附件，如下图所示：</p>
<p><img src="/img/references/waitstate.png" alt="waitstate" /></p>
<p>图4 等待状态节点</p>
<p>添加等待状态节点时，会自动的生成唯一的等待转换附件，不接受添加其他类型的转换附件。</p>
<p>如下图所示，可以编辑等待状态节点的相关属性：</p>
<p><img src="/img/references/waitstate_prop.png" alt="waitstate" /></p>
<p>图5 等待状态节点的属性</p>
<p>相比状态节点的属性，等待状态节点少了“方法”属性，但多出了一个“持续时间”属性，用来指定需要等待多长时间，可以是常数、属性或方法的返回值。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/fsm/waitstate.cpp">fsm/waitstate.cpp</a></p>
<h2 id="section-2"><span class="ez-toc-section" id="i-4">等待帧数状态节点</span></h2>
<p>等待帧数状态节点（WaitFramesState）也是一种特殊的状态节点，可以在状态节点上添加前置、后置以及等待转换等附件，如下图所示：</p>
<p><img src="/img/references/waitframesstate.png" alt="waitframesstate" /></p>
<p>图6 等待帧数状态节点</p>
<p>添加等待帧数状态节点时，会自动的生成唯一的等待转换附件，不接受添加其他类型的转换附件。</p>
<p>如下图所示，可以编辑等待帧数状态节点的相关属性：</p>
<p><img src="/img/references/waitframesstate_prop.png" alt="waitframesstate" /></p>
<p>图7 等待帧数状态节点的属性</p>
<p>相比状态节点的属性，等待帧数状态节点少了“方法”属性，但多出了一个“帧数”属性，用来指定需要等待多少帧数，可以是常数、属性或方法的返回值。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/fsm/waitframesstate.cpp">fsm/waitframesstate.cpp</a></p>
<h2 id="section-3"><span class="ez-toc-section" id="i-5">条件转换附件</span></h2>
<p>转换附件（Transition）是状态机中的基本组成部分之一，它表示一个条件，当这个条件满足时，由所在的状态切换到另一个状态，如下图所示：</p>
<p><img src="/img/references/transition.png" alt="transition" /></p>
<p>图8 转换附件</p>
<p>如下图所示，类似条件节点来编辑转换附件的相关属性：</p>
<p><img src="/img/references/transition_prop.png" alt="transition" /></p>
<p>图9 转换附件的属性</p>
<p>此外，在上图中有个“效果”的属性，是转换附件执行完之后需要执行的额外操作。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/fsm/startcondition.cpp">fsm/startcondition.cpp</a></p>
<h2 id="section-4"><span class="ez-toc-section" id="i-6">状态转换附件</span></h2>
<p>状态转换附件（StatusTransition）是一种特殊的转换附件，根据它的配置，转换时机会有不同：</p>
<ol>
<li>总跳转，表示无条件从所在的状态切换到另一个状态，如下图所示</li>
<li>成功时，表示当所在节点是子树并且成功的时候转换</li>
<li>失败时，表示当所在节点是子树并且失败的时候转换</li>
<li>结束时，表示当所在节点是子树并且结束（成功或失败）的时候转换</li>
</ol>
<p><img src="/img/references/alwaystransition.png" alt="alwaystransition" /></p>
<p>图10 状态转换附件</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/fsm/alwaystransition.cpp">fsm/alwaystransition.cpp</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/fsm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>C++生成代码大小的说明</title>
		<link>/code_size/</link>
					<comments>/code_size/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 09 May 2016 03:15:17 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[编译构建]]></category>
		<guid isPermaLink="false">/?p=204</guid>

					<description><![CDATA[C++版本广泛的用到了template。 Code bloat occurs because compilers generate code for all t<a class="moretag" href="/code_size/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>C++版本广泛的用到了template。</p>
<blockquote><p>Code bloat occurs because compilers generate code for all templated functions in each translation unit that use them. Back in the day the duplicate code was not consolidated resulting in “code bloat”. These days the duplicate code can be removed at link time.</p></blockquote>
<p>所以，在看到产生的代码的大小后不要过于惊慌。（另外，编译速度也会比较慢。）</p>
<p>在3.4.0后的版本里，behaviac已经支持了Link Time Optimization（LTO）。LTO可以极大的减少产生代码的大小以及优化产生代码的效率。</p>
<h3 id="gcc">gcc</h3>
<ul>
<li>如下所示，通过参数指定<code class="highlighter-rouge">Release</code>以及<code class="highlighter-rouge">ForeUseRelease</code>可以打开LTO（如果你的gcc支持的话）<br />
<code class="highlighter-rouge">cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBEHAVIAC_VERSION_MODE=ForeUseRelease --build ../../../..</code></li>
<li>或者通过cmake gui设置<code class="highlighter-rouge">CMAKE_BUILD_TYPE</code>为<code class="highlighter-rouge">Release</code>和<code class="highlighter-rouge">BEHAVIAC_VERSION_MODE</code>为<code class="highlighter-rouge">ForeUseRelease</code></li>
<li>gcc版本需要是4.9以上，低版本不支持LTO</li>
<li>其他版本的gcc请参考相应文档设置LTO</li>
</ul>
<h3 id="msvc">msvc</h3>
<ul>
<li>在visual studio中可以参考打开编译选项/Gy, /GL及/OPT:ICF /OPT:REF /LTCG链接选项</li>
<li>指定<code class="highlighter-rouge">ForeUseRelease</code>的时候，cmake生成的项目文件，在Release下缺省的已经打开上述优化开关。</li>
<li>也可以考虑调整O1,O2或Ox编译选项</li>
</ul>
<p>请参考<a href="http://Tencent.github.io/behaviac/docs/zh/articles/build">构建说明</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/code_size/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>关于性能优化的说明</title>
		<link>/opt_practice/</link>
					<comments>/opt_practice/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Thu, 23 Jun 2016 03:25:55 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[优化]]></category>
		<guid isPermaLink="false">/?p=717</guid>

					<description><![CDATA[概述 behaviac作为图形化的脚本，设计上是用来调用代码（c++，c#）提供的方法，在调用这些方法的时候会有些额外消耗，该消耗已经被充分优化，可以参考消耗。<a class="moretag" href="/opt_practice/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h2><span class="ez-toc-section" id="i">概述</span></h2>
<p>behaviac作为图形化的脚本，设计上是用来调用代码（c++，c#）提供的方法，在调用这些方法的时候会有些额外消耗，该消耗已经被充分优化，可以参考<a href="/language/zh/tutorial10_performence/">消耗</a>。</p>
<p>实践中，要尽量把需要计算的操作由代码实现，通过方法提供给behaviac，behaviac只是去<strong>选择</strong>这些方法，behaviac作为<strong>选择者</strong>，发挥behaviac灵活直观的优势。</p>
<h2><span class="ez-toc-section" id="i-2">设计</span></h2>
<p>要想高效的使用behaviac，首先要有好的设计，需要什么Agent，Agent需要有什么属性，什么方法，有一个好的接口。所谓好，是指不能太底层，也不能太高层。</p>
<ul>
<li>太底层，意味着需要进行很多小的计算</li>
<li>太高层，意外着失去了灵活性</li>
</ul>
<p>底层的计算要尽量在代码（c++或c#）实现。behaviac用来做策略选择。</p>
<p>behaviac虽然提供了Assignment，Compute，Compare，IfElse等节点，允许做一些“小的”计算，允许就像写代码一样进行if else的基本选择，但不鼓励这样做。鼓励使用Selector，Sequence，前置，后置等节点及附件。</p>
<h2><span class="ez-toc-section" id="i-3">持续运行的动作</span></h2>
<p>Agent提供的方法，最好是能够持续运行的方法，比如，播放动画，移动一段距离，都是持续很多帧的动作；而不是只是返回某个值，然后再需要在行为树里根据该值做比较，进行计算，再执行其他小的一帧触发的方法。</p>
<p>持续运行的节点在下一帧会被持续继续执行，behaviac不会愚蠢的每一帧都从根节点重新执行。但是，不好的行为树（只是简单的成功或失败，没有返回运行的节点）就会迫使behaviac每一帧都不得不从根节点重新选择。可以参考行为树的<a href="/language/zh/concepts/">基本概念及进阶</a>。</p>
<p>持续运行的动作往往需要大量计算，由代码（c++或c#）实现，behaviac只是在高层去选择使用它，避免大量的计算。这样子，利用behaviac的灵活直观的优势而不会有性能的损失。</p>
<h2><span class="ez-toc-section" id="i-4">并行及选择检测节点</span></h2>
<p><a href="/language/zh/selectormonitor/">选择监测节点</a>以及<a href="/language/zh/parallel/">并行</a>节点用起来很方便，但是需要提醒的是，相比其他节点，这两个节点比较费。</p>
<p><a href="/language/zh/parallel/">并行</a>节点每次更新都会更新它所有的子节点（子树），<a href="/language/zh/selectormonitor/">选择监测节点</a>也是如此。不仅如此，这两个节点还会导致接管所在树对处于运行状态节点的控制，形成多一级的控制。（不理解没关系，总之，比其他节点更费。）</p>
<p>不是说这两个节点不能用，但是使用起来请注意其性能，特别的不能滥用，最好不要嵌套这两个节点。</p>
<h2><span class="ez-toc-section" id="i-5">发布版</span></h2>
<p>当发布版本或测量性能的时候，可以定义宏BEHAVIAC_RELEASE关闭开发功能，这样子性能是最优的。或者可以保留开发功能但使用<a href="/language/zh/config/">功能开关</a>有选择的关闭或打开开发功能。</p>
<p>关于BEHAVIAC_RELEASE可以参考<a href="/language/zh/tutorial10_performence/">优化及性能</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/opt_practice/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>调试功能的说明</title>
		<link>/debugging_desc/</link>
					<comments>/debugging_desc/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Fri, 17 Jun 2016 07:50:54 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[连调]]></category>
		<guid isPermaLink="false">/?p=622</guid>

					<description><![CDATA[behaviac提供了离线调试以及连调功能。 离线调试 离线调试功能是指在编辑器里加载运行时产生的_behaviac_$_.log文件，如下图，可以加载_beh<a class="moretag" href="/debugging_desc/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>behaviac提供了离线调试以及连调功能。</p>
<h2>离线调试</h2>
<p>离线调试功能是指在编辑器里加载运行时产生的_behaviac_$_.log文件，如下图，可以加载_behaviac_$_.log文件：</p>
<p><img class="alignnone size-medium wp-image-625" src="/wp-content/uploads/2016/06/offline-300x194.png" alt="offline" width="300" height="194" srcset="/wp-content/uploads/2016/06/offline-300x194.png 300w, /wp-content/uploads/2016/06/offline.png 328w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>_behaviac_$_.log是运行游戏时产生的log文件。一般都是产生在exe所在的目录，对于Unity，是产生在Assets的同级目录。</p>
<p><img class="alignnone size-medium wp-image-626" src="/wp-content/uploads/2016/06/off-300x225.png" alt="off" width="300" height="225" srcset="/wp-content/uploads/2016/06/off-300x225.png 300w, /wp-content/uploads/2016/06/off-768x576.png 768w, /wp-content/uploads/2016/06/off.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>在离线调试里，可以模拟游戏的运行，甚至可以设断点，然后查看变量的当前值，可以查看树的执行情况。</p>
<p>文件_behaviac_$_.log只在开发版本下产生，或者是Config::IsLogging为true时产生。</p>
<p>可以参考：<a href="/language/zh/tutorial10_performence/">优化与性能</a>和<a href="/language/zh/config/">开发功能开关</a>。</p>
<h2>连调</h2>
<p>连调功能是指在游戏运行的时候，编辑器可以连上游戏，实时的查看树的运行情况，变量的当前值，可以设断点等。而离线调试实际上是回放运行时产生的log。</p>
<p>和上面离线调试时需要在开发版本下一样，连调同样需要游戏是开发版本，发布版本下没有连调的功能。可以参考：<a href="/language/zh/tutorial10_performence/">版本说明</a>和<a href="/language/zh/config/">开发功能开关</a>。</p>
<p>除此之外，还需要下面的事项：</p>
<ol>
<li>请检查Agent::SetIdMask 和 Agent::SetIdFlag的调用是否合适。IdFlag和IdMask都是int，IdMask是个公用的Mask，而IdFlag是设置给某个Agent实例的，当(IdFlag &amp; IdMask)!= 0的时候，该Agent才被调试。</li>
<li>请确保游戏确实在更新，具体可以参考<a href="/docs/zh/tutorials/tutorial13_updateloop/" target="_blank" rel="nofollow">更新流程</a>。Workspace::DebugUpdate需要被调用，如果只是调用Agent::btexec来更新，则连调功能不能正常工作。</li>
</ol>
<p>有问题可以参考<a href="http://bbs.behaviac.com/index.php/tag/%E8%BF%9E%E8%B0%83">连调相关常见问题</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/debugging_desc/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>版本号说明</title>
		<link>/version/</link>
					<comments>/version/#respond</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 09 May 2016 03:16:57 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[概述]]></category>
		<guid isPermaLink="false">/?p=206</guid>

					<description><![CDATA[在源码和安装包的根目录都提供了version.txt，unity的源码里也提供了version.txt。 version.txt中的版本号和安装包（如Behav<a class="moretag" href="/version/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>在源码和安装包的根目录都提供了<a href="https://github.com/Tencent/behaviac/blob/master/version.txt">version.txt</a>，unity的源码里也提供了<a href="https://github.com/Tencent/behaviac/blob/master/integration/unity/Assets/Scripts/behaviac/runtime/version.txt">version.txt</a>。</p>
<ol>
<li>version.txt中的版本号和安装包（如BehaviacSetup_3.3.16.exe）的版本号以及编辑器的版本号是一致的。请使用相同版本号的编辑器和运行时。</li>
<li>version.txt的存在是用来表明该版本的版本号之用，出现了问题请提供该版本号。</li>
<li>version.txt只是从3.3.16版本后才提供，之前的版本中没有该文件。</li>
<li>Cpp版本中提供了函数<code class="highlighter-rouge">behaviac::GetVersionString()</code>来返回版本号，该版本号和version.txt中的版本号是一致的。</li>
<li>Cpp版本运行的时候，有下图所示的信息。<br />
<img class="aligncenter size-full wp-image-1275" src="/wp-content/uploads/2016/05/version.png" alt="version" width="583" height="138" srcset="/wp-content/uploads/2016/05/version.png 583w, /wp-content/uploads/2016/05/version-300x71.png 300w" sizes="(max-width: 583px) 100vw, 583px" /></p>
<ul>
<li>第一行就包含了版本信息。其中的debug，NRELEASE等信息是用来表明是否定义了宏<code class="highlighter-rouge">_DEBUG</code>或<code class="highlighter-rouge">DEBUG</code>,<code class="highlighter-rouge">BEHAVIAC_RELEASE</code></li>
<li>该信息在vs的输出窗口中有输出，在<code class="highlighter-rouge">_behaviac_$_$_.log</code>文件里也有输出</li>
</ul>
</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>/version/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>开发功能开关</title>
		<link>/config/</link>
					<comments>/config/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 09:57:37 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[连调]]></category>
		<category><![CDATA[概述]]></category>
		<category><![CDATA[编译构建]]></category>
		<guid isPermaLink="false">/?p=160</guid>

					<description><![CDATA[behaviac的运行时提供有核心的更新行为树的功能，在其之上，还有logging，热加载，连调等调试功能。这些调试功能只是‘开发’功能，在游戏发布后实际上是不<a class="moretag" href="/config/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>behaviac的运行时提供有核心的更新行为树的功能，在其之上，还有logging，热加载，连调等调试功能。这些调试功能只是‘开发’功能，在游戏发布后实际上是不需要的。</p>
<p>除了可以在<code>config.h</code>中定义<code>BEHAVIAC_RELEASE</code>宏为1来完全使‘开发功能’不被编译外。也可以保留这些‘开发’功能但只是使用下面所列的‘开关’来关闭或者打开某些功能。</p>
<p>具体可以参考<a href="/language/zh/tutorial10_performence/">优化及性能</a></p>
<h2>Cpp</h2>
<pre class="brush: cpp; title: ; notranslate">namespace behaviac
{
class BEHAVIAC_API Config
{
public:
static bool IsProfiling();
static void SetProfiling(bool bEnabled);

//logging是否打开
static bool IsLogging();
static void SetLogging(bool bLogging);

//logging打开的情况下，是否每次logging的时候都Flush
static bool IsLoggingFlush();
static void SetLoggingFlush(bool bFlush);

//socket连接是否打开，只有打开socket连接，连调功能才会支持
static bool IsSocketing();
static void SetSocketing(bool bSocketing);

//是否是阻塞模式，当时阻塞模式的时候，游戏会阻塞，等待编辑器的连接，
//只有成功建立连接后，游戏才继续运行
static bool IsSocketBlocking();
static void SetSocketBlocking(bool bBlocking);

//游戏和编辑器建立连接的时候使用的端口
static void SetSocketPort(unsigned short port);
static unsigned short GetSocketPort();

//热加载是否打开
static bool IsHotReload();
static void SetHotReload(bool bHotReload);
};</pre>
<p>具体的代码可以查看<a href="{{site.repository}}/blob/master/inc/behaviac/base/workspace.h">behaviac/base/workspace.h</a></p>
<h2>Unity</h2>
<p>C#下同名函数的意义和Cpp一样，此外，<code>IsSuppressingNonPublicWarning</code>是个用来控制是否输出非public成员的警告。</p>
<p>当<code>IsSuppressingNonPublicWarning</code>为true的时候，Agent的成员（field，method，property）如果不是public的，则输出警告信息，从而可以修改其为public，这样的话，当使用导出格式为c#时其效率就是最高的，而且没有GC Alloc。</p>
<p>具体的代码请查看<a href="{{site.repository}}/blob/master/integration/unity/Assets/Scripts/behaviac/runtime/Workspace.cs">behaviac/runtime/workspace.cs</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/config/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>使用cmake构建C++版运行时库</title>
		<link>/build/</link>
					<comments>/build/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 09:55:36 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[上手]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[编译构建]]></category>
		<guid isPermaLink="false">/?p=156</guid>

					<description><![CDATA[请首先到/language/zh/downloads/下载或克隆源码。 缺省的，我们使用cmake来生成对应平台的<a class="moretag" href="/build/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>请首先到<a href="/language/zh/downloads/#https://github.com/Tencent/behaviac">/language/zh/downloads/</a>下载或克隆源码。</p>
<p id="cpp">缺省的，我们使用<a href="https://cmake.org/download/">cmake</a>来生成对应平台的项目文件（sln或make文件等）。</p>
<p>但cmake不是必须的，也可以选择自己喜欢的方式创建自己的项目文件。比如，使用premake等来生成项目文件，或者手工创建。</p>
<h3></h3>
<h3 id="windows"><span class="ez-toc-section" id="Windows">Windows平台</span></h3>
<ul>
<li>下载并安装<a href="https://cmake.org/download/">cmake</a>，请使用3.3以上版本</li>
<li>cmake的路径需要添加到环境变量PATH</li>
<li>运行build目录下的cmake_generate_projects.bat生成项目文件</li>
<li>如果需要build android版本
<ul>
<li>需要安装vs2015</li>
<li>使用android_vs2015子目录下的项目文件</li>
<li>或者使用cmake生成项目文件
<ul>
<li>下载并安装<a href="https://github.com/Microsoft/CMake/releases">cmake android</a>, 直接覆盖上面步骤安装的cmake就好。</li>
<li>运行build目录下的cmake_generate_projects_android.bat生成项目文件</li>
<li>如果想使用mk，可以修改生成的linux下的make文件</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="section"><span class="ez-toc-section" id="i">其他平台</span></h3>
<ul>
<li>下载并安装<a href="https://cmake.org/">cmake</a>，请使用3.3以上版本</li>
<li>如果可能，请保证4.4.6以上版本的gcc
<ul>
<li>使用版本为4.4.6的gcc可以顺利编译，但4.1.2的gcc有错误（未测试低于4.4.6的版本）</li>
</ul>
</li>
<li>运行build目录下的cmake_generate_projects.sh生成项目文件
<ul>
<li>mac上，运行build目录下的cmake_generate_projects_mac.sh生成项目文件</li>
</ul>
</li>
</ul>
<h3 id="section-1"><span class="ez-toc-section" id="i-2">注意</span></h3>
<ol>
<li>cmake_generate*.bat里使用的是vs2013和vs2015，用户可以根据自己的需要选择相应的编译器，比如vs2008、vs2010等，或者通过cmakegui进行选择。</li>
<li>CMakeLists.txt里提供的是缺省设置，可以根据自己的需要直接修改或通过cmakegui来选择配置。特别的，CMakeLists.txt里有若干个选项可以配置。<br />
<img src="/img/concepts/cmake_config.png" alt="cmake_config" /></p>
<ul>
<li>BEHAVIAC_VERSION_MODE用来控制BEHAVIAC_RELEASE是否定义。BEHAVIAC_RELEASE的用途请参考文章《<a href="/docs/zh/articles/tutorial10_performence">优化及性能</a>》。
<ul>
<li>Default：缺省模式是Debug下BEHAVIAC_RELEASE没有定义，而Release下BEHAVIAC_RELEASE有定义</li>
<li>ForceUseDev：强制不定义BEHAVIAC_RELEASE</li>
<li>ForceUseRelease：强制定义BEHAVIAC_RELEASE
<ul>
<li>在ForceUseRelease的时候，Release下，生成的项目文件会试图打开LTO开关，请参考文档《<a href="/docs/zh/articles/code_size">Cpp生成代码大小的说明</a>》</li>
</ul>
</li>
</ul>
</li>
<li>CMAKE_BUILD_TYPE用来控制生成Debug还是Release（Visual Studio的时候不需要指定CMAKE_BUILD_TYPE）</li>
<li>BUILD_SHARED_LIBS用来控制libbehaviac是stati lib/a还是dynamid dll/so</li>
<li>BUILD_USE_64BITS用来控制是否生成64位 （使用Visual Studio时，需要指定带Win64的generator，请参考cmake的文档）</li>
<li>根据上面的配置，CMake生成下面的_config.h文件，用来自动定义宏BEHAVIAC_RELEASE，如下图所示：<img class="aligncenter size-full wp-image-1650" src="/wp-content/uploads/2016/04/config.png" alt="" width="874" height="286" srcset="/wp-content/uploads/2016/04/config.png 874w, /wp-content/uploads/2016/04/config-300x98.png 300w, /wp-content/uploads/2016/04/config-768x251.png 768w" sizes="(max-width: 874px) 100vw, 874px" /></li>
<li>在另一个文件config.h中，会根据_DEBUG或DEBUG宏来尝试重新定义宏BEHAVIAC_RELEASE，如果在_config.h中宏BEHAVIAC_RELEASE并没有定义，如下图所示：<img class="aligncenter size-full wp-image-1651" src="/wp-content/uploads/2016/04/config-1.png" alt="" width="855" height="372" srcset="/wp-content/uploads/2016/04/config-1.png 855w, /wp-content/uploads/2016/04/config-1-300x131.png 300w, /wp-content/uploads/2016/04/config-1-768x334.png 768w" sizes="(max-width: 855px) 100vw, 855px" /></li>
</ul>
</li>
<li>cmake不是必须的
<ul>
<li>你可以选择自己喜欢的其他类似工具，比如premake等来生成项目文件。</li>
<li>或者，你可以手工创建项目文件。</li>
<li>又或者，可以直接把src和inc加到你已有的项目文件。</li>
<li>当你自行修改或创建项目文件的时候，可能需要参考CMakeLists.txt查看需要的设置：
<ul>
<li>include_directories包含目录，你需要设置正确的包含目录</li>
<li>add_definitions编译宏，比如_DEBUG</li>
<li>add_target_definitions编译宏，比如BEHAVIACDLL_EXPORTS，BEHAVIAC_DLL</li>
<li>CMAKE_CXX_FLAGS编译开关</li>
<li>BUILD_SHARED_LIBS是否动态库还是静态库</li>
</ul>
</li>
</ul>
</li>
<li>build\android_vs2015是提供的缺省的使用Visual Studio 2015来生成android项目的项目工程，支持64位。</li>
<li>可以使用cmakegui选择设置，或者在cmake的命令行里指定设置（ -DCMAKE_BUILD_TYPE=Debug -DBUILD_USE_64BITS=ON等）。请参考<a href="https://github.com/Tencent/behaviac/blob/master/build/cmake_generate_projects.bat">build/cmake_generate_projects.bat</a>或者cmake文档。</li>
</ol>
<h3 id="section-2"><span class="ez-toc-section" id="i-3">构建</span></h3>
<ul>
<li>无论Windows平台还是其他平台，项目文件都生成到目录cmake_binary</li>
<li>项目文件生成到目录cmake_binary，根据选用的编译工具（vs2013、make等）打开相应目录的项目文件或运行make等进行构建</li>
<li>.a、.lib、.dll、.exe等被生成到根目录的lib目录和bin目录</li>
<li>生成的项目配置(mvsc, linxu, xcode)包含了Debug和Release，请根据需要构建Debug或Release版本</li>
</ul>
<h2 id="unity"></h2>
]]></content:encoded>
					
					<wfw:commentRss>/build/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>共享资源和实例数据</title>
		<link>/memory_shared/</link>
					<comments>/memory_shared/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 09:59:42 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[概念]]></category>
		<guid isPermaLink="false">/?p=164</guid>

					<description><![CDATA[每个行为树都只有一份单独的数据作为资源被加载。 每个使用行为树的对象（Agent）依据这个共享的资源创建独立的实例数据，例如对于Sequence节点，实例数据中<a class="moretag" href="/memory_shared/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>每个行为树都只有一份单独的数据作为资源被加载。</p>
<p>每个使用行为树的对象（Agent）依据这个共享的资源创建独立的实例数据，例如对于Sequence节点，实例数据中只是存储更新到哪个子树，至于Sequence节点的配置信息等则被共享。</p>
<p><img src="/img/faq/memory_shared.png" alt="memory_shared" /></p>
<hr />
<ul>
<li>加载行为树请使用<code>Workspace::Load</code>或<code>Agent::btload</code></li>
<li>卸载行为树请使用<code>Workspace::UnLoad</code>或<code>Agent::btunload</code></li>
<li><code>Workspace::CreateBehaviorTreeTask</code>用来根据加载的行为树资源创建实例数据，而它配套的是<code>Workspace::DestroyBehaviorTreeTask</code></li>
<li>一般情况下，不需要<strong>显式</strong>调用<code>Workspace::CreateBehaviorTreeTask</code>和<code>Workspace::DestroyBehaviorTreeTask</code>
<ul>
<li>初始化的时候调用<code>Workspace::Load</code>或<code>Agent::btload</code>加载可能会用到的行为树</li>
<li>游戏循环的时候，根据需要，调用<code>Agent::btsetcurrent</code>指定该Agent当前的行为树，后续<code>Agent::btexec</code>更新的就是当前行为树，除非再次调用<code>Agent::btsetcurrent</code>修改当前行为树</li>
<li>退出的时候，调用<code>Workspace::UnLoad</code>或<code>Agent::btunload</code>，或<code>Workspace::UnLoadAll</code>卸载行为树资源。而行为树实例是在<code>Agent::btsetcurrent</code>的时候被创建的，释放Agent的时候被Agent负责释放</li>
</ul>
</li>
<li>C#代码是同名类型里的同名函数，如<code>Workspace.Load</code>和<code>Agent.btload</code></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>/memory_shared/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>behaviac升级的步骤及注意事项</title>
		<link>/updatenotes/</link>
					<comments>/updatenotes/#comments</comments>
		
		<dc:creator><![CDATA[jonygli]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 10:01:19 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<category><![CDATA[版本升级]]></category>
		<guid isPermaLink="false">/?p=168</guid>

					<description><![CDATA[ 相比之前版本，3.6.x版本有若干重大改动 3.6版本的概述，请参考文章《关于新旧版本的说明》。 3.6.x版本的编辑器将导出类型信息代码文件，运行时不需要注<a class="moretag" href="/updatenotes/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h2><span class="ez-toc-section" id="36x"> 相比之前版本，3.6.x版本有若干重大改动</span></h2>
<ol>
<li>3.6版本的概述，请参考文章《<a href="/language/zh/3-6-overview/">关于新旧版本的说明</a>》。</li>
<li>3.6.x版本的编辑器将导出类型信息<strong>代码文件</strong>，运行时<strong>不需要</strong>注册和导出xml类型信息文件。</li>
<li>如果3.6.x版本的编辑器打开之前版本的workspace文件，将读取xml类型信息文件并且转存其中的内容，之后的版本就不再需要xml类型信息文件了</li>
<li>下列宏及函数已删除，升级后使用该宏或代码的相应代码注释掉或删掉即可（升级的时候，只需要修改编译出现错误的部分，其他的不是必须修改的，因为为了尽可能向后兼容，已经把相关宏重新定义为了空）
<ol>
<li><del>BEHAVIAC_REGISTER_METHOD/BEHAVIAC_REGISTER_PROPERTY</del></li>
<li><del>BEHAVIAC_BEGIN_PROPERTIES/BEHAVIAC_END_PROPERTIES</del></li>
<li><del>BEGIN_PROPERTIES_DESCRIPTION/END_PROPERTIES_DESCRIPTION</del></li>
<li><del>behaviac::Agent::Register/behaviac::Agent::UnRegister</del></li>
<li><del>behaviac::TypeRegister::Register/behaviac::TypeRegister::UnRegister</del></li>
<li><del>behaviac::Agent::ExportMetas</del></li>
</ol>
</li>
<li><span style="color: #ff0000;"><strong>升级步骤</strong></span>
<ol>
<li>备份程序代码及workspace项目</li>
<li><strong>删掉</strong>老版本中behaviac的所有代码（src及inc等），使用新版本中behaviac的代码（src及inc等）。（因为很多文件被删除，不要只是覆盖！）</li>
<li>使用新版本的编辑器打开workspace.xml文件，重新导出（可能需要配置“代码生成位置”）
<ol>
<li>仔细阅读该说明，点击确定后，你的workspace文件将被更新（不能恢复，除非你预先有备份！）。<img class="alignnone size-full wp-image-1151" src="/wp-content/uploads/2016/04/QQ截图20161129165728.png" alt="qq%e6%88%aa%e5%9b%be20161129165728" width="496" height="357" srcset="/wp-content/uploads/2016/04/QQ截图20161129165728.png 496w, /wp-content/uploads/2016/04/QQ截图20161129165728-300x216.png 300w" sizes="(max-width: 496px) 100vw, 496px" /></li>
<li>在弹出来的类型信息浏览器中，点击下方的“应用”按钮，生成类型代码文件，点击左下方的“打开代码生成位置”，将生成的类型代码文件添加到程序make文件或项目文件中，并编译构建成为程序的一部分：<img class="alignnone size-medium wp-image-1138" src="/wp-content/uploads/2016/04/QQ截图20161125171027-1-250x300.png" alt="qq%e6%88%aa%e5%9b%be20161125171027" width="250" height="300" srcset="/wp-content/uploads/2016/04/QQ截图20161125171027-1-250x300.png 250w, /wp-content/uploads/2016/04/QQ截图20161125171027-1.png 612w" sizes="(max-width: 250px) 100vw, 250px" /></li>
<li>你可能需要通过菜单项“文件-&gt;编辑工作区”来配置“代码生成位置”，如下图： <img class="alignnone wp-image-1089" src="/wp-content/uploads/2016/04/QQ截图20161118193315-300x139.png" alt="qq%e6%88%aa%e5%9b%be20161118193315" width="365" height="169" srcset="/wp-content/uploads/2016/04/QQ截图20161118193315-300x139.png 300w, /wp-content/uploads/2016/04/QQ截图20161118193315.png 587w" sizes="(max-width: 365px) 100vw, 365px" /></li>
<li>通过菜单项“文件-&gt;导出全部&#8230;”，重新导出所有的行为树及生成所有的类型文件，如下图：<img class="alignnone size-medium wp-image-1144" src="/wp-content/uploads/2016/04/QQ截图20161125170748-1-199x300.png" alt="qq%e6%88%aa%e5%9b%be20161125170748" width="199" height="300" srcset="/wp-content/uploads/2016/04/QQ截图20161125170748-1-199x300.png 199w, /wp-content/uploads/2016/04/QQ截图20161125170748-1.png 395w" sizes="(max-width: 199px) 100vw, 199px" /></li>
</ol>
</li>
<li>把上一步中导出的源码加入工程中开始编译构建，并修改出现的编译错误，把出错的代码都删掉即可（如上述4中所说，那些宏和函数已删除。<strong>只需要修改编译出现错误的部分，其他的不是必须修改的，因为为了尽可能向后兼容，已经把相关宏重新定义为了空</strong>）</li>
<li>如果是C#版本，步骤基本一致。</li>
</ol>
</li>
<li>等待节点和等待帧数节点的使用，请分别参考文档：<a href="/language/zh/wait/">/language/zh/wait/</a>和<a href="/language/zh/waitframes/">/language/zh/waitframes/</a></li>
<li>按照上述步骤就可以正常运行了。对于“已有实现”的类型，如果需要修改，请参考下面的说明。</li>
</ol>
<p>&nbsp;</p>
<h3><span class="ez-toc-section" id="i">对于‘已有实现’的类型</span></h3>
<p>如果需要修改的话，有两个流程可以选择。可以选择生成代码，也可以选择不生成代码，请参考下面的步骤，选择自己适合的方式。</p>
<h4><span class="ez-toc-section" id="i-2">生成代码</span></h4>
<ol>
<li>打开类型信息浏览器，如下图，“生成代码?”没有勾选上的类型就是在程序里已经实现的类型，程序里已经有了相应的类型声明以及函数定义的代码。如下图中的ChildNodeTest在代码里已经有’class ChildNodeTest’了。<img class="alignnone size-full wp-image-1153" src="/wp-content/uploads/2016/04/QQ截图20161130142048.png" alt="qq%e6%88%aa%e5%9b%be20161130142048" width="612" height="735" srcset="/wp-content/uploads/2016/04/QQ截图20161130142048.png 612w, /wp-content/uploads/2016/04/QQ截图20161130142048-250x300.png 250w" sizes="(max-width: 612px) 100vw, 612px" /></li>
<li>勾选上该Checkbox，然后点击“应用”，会生成类型文件。</li>
<li>点击“打开代码生成位置”，可以看到ChildNodeTest.cs被生成了。在上图类型信息浏览器中，每个类的“生成位置”可以用来配置该类的生成位置，如果不配置，则使用工作区统一配置的代码生成位置。<img class="alignnone size-full wp-image-1129" src="/wp-content/uploads/2016/04/QQ截图20161124183705.png" alt="qq%e6%88%aa%e5%9b%be20161124183705" width="712" height="266" srcset="/wp-content/uploads/2016/04/QQ截图20161124183705.png 712w, /wp-content/uploads/2016/04/QQ截图20161124183705-300x112.png 300w" sizes="(max-width: 712px) 100vw, 712px" /></li>
<li>打开ChildNodeTest.cs，可以看到如下，<span style="color: #0000ff;"><strong>只能在红色框内添加自己的代码。红色框外面的修改将会在重新生成代码的时候被丢弃</strong></span>！需要手工的把原来类型中的代码复制到新生成的类里，而把原来的文件<span style="color: #ff0000;">删掉</span>！否则会有重复定义的错误产生。<img class="alignnone size-full wp-image-1149" src="/wp-content/uploads/2016/04/QQ截图20161128195834-1.png" alt="qq%e6%88%aa%e5%9b%be20161128195834" width="910" height="737" srcset="/wp-content/uploads/2016/04/QQ截图20161128195834-1.png 910w, /wp-content/uploads/2016/04/QQ截图20161128195834-1-300x243.png 300w, /wp-content/uploads/2016/04/QQ截图20161128195834-1-768x622.png 768w" sizes="(max-width: 910px) 100vw, 910px" /></li>
<li>从上可知，如果要修改类型名、成员名，请在“类型信息浏览器”中修改，然后“应用”就可以生成更新的代码。而其他相关代码只能添加在‘///&lt;&lt;&lt; BEGIN WRITING YOUR CODE’和‘///&lt;&lt;&lt; END WRITING YOUR CODE’中间，添加在这个块外面的代码在重新生成代码的时候将会丢失！C++代码也是同样的处理。<span style="color: #ff0000;">不要手工修改</span>‘///&lt;&lt;&lt; BEGIN WRITING YOUR CODE’后面的内容（例如FILE_INIT，FILE_UNINIT，CLASS_PART等），该内容在重新生成代码的时候将被使用到。</li>
<li>对于enum和struct，如果需要修改，也需要勾选上其&#8221;生成代码?&#8221;的Checkbox。</li>
</ol>
<h4><span class="ez-toc-section" id="i-3">不生成代码</span></h4>
<p>上述生成代码的流程，需要手工的把原来的代码copy/paste到生成的代码文件中有“///&lt;&lt;&lt; BEGIN WRITING YOUR CODE’和‘///&lt;&lt;&lt; END WRITING YOUR CODE”这样的注释块中间，比较麻烦！而且有人可能并不喜欢这样的形式，那么可以采取下面的流程：</p>
<ol>
<li>不要勾选“生成代码?”，任何修改依然在原来自己维护的代码中进行。</li>
<li>任何需要在行为树中暴露的属性或方法需要在类型信息浏览器中同样的添加，否则编辑器中将看不到该属性或方法，即不能被使用。但原来已有的不需要重复加入，添加后需要点击“应用”重新生成胶水代码。</li>
<li>另一方面，如果只是在编辑器中添加了属性或方法（添加后需要点击“应用”重新生成胶水代码），而在你的代码中没有相应的修改，编译程序的时候，会有编译错误。</li>
<li>如果运行没有重新编译的程序，有可能会有报错发生：
<ol>
<li>当只是添加了属性的时候，如果没有使用“应用”后重新生成的代码编译构建程序，而使用老的程序的时候，可以正常运行，只是新添加的属性作为自定义属性使用而已（编译构建后，新添加的属性就将作为Agent的真正成员，效率最高）。</li>
<li>当修改了方法（添加或改名），如果没有使用“应用”后重新生成的代码编译构建程序，而使用老的程序的时候，会有错误发生，在_behaviac_$_$.log中会有详细的错误输出。</li>
</ol>
</li>
</ol>
<h4><span class="ez-toc-section" id="i-4">总结比较</span></h4>
<p>从上面可以知道，对于从老版本升级到3.6.*的情况下，对于已经有了大量代码的类来说，可以选择依然使用原来的代码，或者可以选择生成代码。</p>
<p>使用原来的代码的好处是不需要copy/paste大量代码到新生成的类型文件中了，并且所有的代码都可以保持原来的风格，缺点是之后任何关于属性、方法的修改（改名、添加、删除等）都需要在类型信息浏览器中重复的做一遍。</p>
<p>选择生成代码的缺点是需要手工copy/paste大量的代码到新生成的类型文件里，并且需要忍受begin/end注释块的束缚。但好处是后续的修改都只需要在类型信息浏览器中改一次，重新生成就好了。</p>
<p>实际上即使对于选择了生成代码的情况，后续也可以再选择不生成代码，反之亦然。选择生成代码，则编辑器负责在你指定的位置生成代码；而选择不生成代码，编辑器将不为你生成代码，所有的代码由你自己来维护。二选一，如果选择生成代码，而自己原来维护的代码没用删掉，则会有编译错误！</p>
<p>另外，需要说明的是，这里的生成代码是指生成class的声明代码（.h和.cpp，或者.cs）。而不管这里是否选择生成代码，在点击“应用”的时候，都会生成所有类型的胶水代码，可以在配置的代码生成位置查看生成的behaviac_agent_meta.cpp文件或AgentProperties.cs，里面的代码就是所谓的“胶水”代码。</p>
<p>此外，我们知道，行为树的导出格式可以是xml或bson，也可以导出cpp或c#代码。即使采用xml或bson格式的时候，这里的“胶水”代码或者类型代码都会被生成，而且需要被添加到工程项目中参与编译构建！</p>
<p><span id="more-168"></span></p>
<h2><span class="ez-toc-section" id="34x35x">相比3.4.x版本，3.5.x版本有若干重大改动</span></h2>
<ol>
<li>用最新的代码把你们的游戏能够编译运行（如果可能首先删除旧的的代码及导出数据，用新代码替换。）</li>
<li>导出最新的meta的xml文件</li>
<li>用最新版本的编辑器打开老的workspace，重新导出</li>
<li>用3中导出的新的文件，重新编译构建，运行游戏</li>
</ol>
<p>大版本升级，导出文件的版本号都会有改变，不严格按照上述步骤的话，在运行游戏或编辑器的时候都会有报错。而小版本的升级的时候，导出文件的版本号没有改变，可以不严格按照上述步骤。</p>
<p>对于unity，3.5.3及以后的版本，在上述步骤3中导出文件的时候，会生成c#文件（AgentProperties.cs和customizedtypes.cs），需要添加都项目中，否则运行时会发生错误。</p>
<p>为了支持C# GC Free，生成的代码有大的变化，需要按照上述升级步骤升级版本，否则运行游戏或者编辑器都会有报错。</p>
<h2><span class="ez-toc-section" id="2x3x">相比2.x版本，3.x版本有若干重大改动</span></h2>
<ol>
<li>meta browser， 变量的使用更加统一和方便</li>
<li>preaction/postaction，任何一个节点都可以添加前置和后置，统一了用法和体验</li>
<li>支持了FSM</li>
</ol>
<h2><span class="ez-toc-section" id="2xAPItestunittesttestusertest">相比2.x版本，API的改动（请参考test/unittest或test/usertest中的代码）：</span></h2>
<ul>
<li>删掉了behaviac::Start, behaviac::Stop</li>
<li>LogManager::SetEnable -&gt; Config::SetLogging</li>
<li>删掉了World</li>
<li>删掉了SetWorkspaceSettings</li>
<li>删掉了REGISTER_EVENT</li>
<li>bttick rename to btexec</li>
<li>DECLARE_BEHAVIAC_OBJECT_NOVIRTUAL rename to DECLARE_BEHAVIAC_OBJECT_STRUCT</li>
<li>删掉了REGISTER_METHOD_CHECKRESULT</li>
<li>RegisterName -&gt; RegisterIntanceName, UnRegisterName -&gt; UnRegisterIntanceName</li>
<li>behaviac::Property::Registger, behaviac::Condition::Register -&gt; behaviac::TypeRegister::Register, UnRegister类似</li>
<li>在所有加载BT之前，调用behaviac::Workspace::GetInstance()-&gt;SetFilePath和behaviac:: Workspace::GetInstance()-&gt;SetFileFormat来设置路径和格式</li>
<li>behaviac::Workspace::ExportMetas修改为behaviac::Workspace::GetInstance()-&gt;ExportMetas，其他相应的对Workspace的函数的调用也要类似的修改</li>
<li>删掉了Workspace::LogFrames和Workspace::HandleRequests, 添加了Workspace::DebugUpdate</li>
<li>behaviac::World::GetInstance()-&gt;btexec()修改为behaviac::Workspace::GetInstance()-&gt;Update()</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>/updatenotes/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
