<?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/tag/%E4%BA%8B%E4%BB%B6/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>Thu, 27 Apr 2017 03:35:36 +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>事件处理</title>
		<link>/tutorial11_event/</link>
					<comments>/tutorial11_event/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 13 May 2016 02:40:42 +0000</pubDate>
				<category><![CDATA[3.5]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[概念]]></category>
		<guid isPermaLink="false">/?p=302</guid>

					<description><![CDATA[事件处理 执行行为树的过程中，当状态、条件发生变化或发生事件（Event）时，如何响应或打断当前的执行是个重要的问题。 目前behaviac组件支持三种方式来处<a class="moretag" href="/tutorial11_event/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<h3><span class="ez-toc-section" id="i">事件处理</span></h3>
<p id="section">执行行为树的过程中，当状态、条件发生变化或发生事件（Event）时，如何响应或打断当前的执行是个重要的问题。</p>
<p>目前behaviac组件支持三种方式来处理状态变化或事件发生：并行节点、选择监测节点、事件附件等。</p>
<p>简而言之，并行和选择监测节点的工作方式是采用“轮询”的方式，每次执行时需要重新评估所有子节点，而不是像其他节点会保留上一次正在执行的子节点以便在下一次执行时继续执行。事件附件是在游戏逻辑发出事件时，才按需得到响应。</p>
<h3 id="section-1"><span class="ez-toc-section" id="i-2">并行节点</span></h3>
<p>依靠并行（Parallel）节点处理事件，需要把事件用条件的形式表达并且需要监控该条件，当该条件不满足的时候就退出。这种方式在概念上不太清晰，使用起来也比较繁琐，如下图所示：</p>
<p><img class="aligncenter" src="/img/overview/parallel.png" alt="" /></p>
<h3 id="section-2"><span class="ez-toc-section" id="i-3">选择监测节点</span></h3>
<p>选择监测（SelectorMonitor）和监测分支（WithPrecondition）节点作为对传统行为树的扩展，可以很自然的处理事件和状态的改变。选择监测和监测分支节点只能配对使用，即选择监测只能添加监测分支作为它的子节点，监测分支也只能作为选择监测的子节点被添加，如下图所示：</p>
<ul>
<li>选择监测节点是一个动态的选择节点，和选择（Selector）节点相同的是，它选择第一个返回成功的子节点，但不同的是，它不是只选择一次，而是每次执行时都对其子节点重新进行选择。</li>
<li>监测分支节点有条件分支子树和动作分支子树。只有条件分支子树返回成功的时候，动作分支子树才能够被执行。</li>
</ul>
<p><img class="aligncenter" src="/img/overview/selectormonitor.png" alt="" /></p>
<h3><span class="ez-toc-section" id="i-4">事件附件</span></h3>
<p>事件（Event）作为一种附件，是behaviac组件的一大特色。事件主要用于在游戏逻辑发出事件时，得到响应后打断当前正在执行的行为树，并切换到所设置的另一个行为树。</p>
<p>用一个具体例子来说明事件的原理和用法：</p>
<ul>
<li>首先，在编辑器中为AgentNodeTest类添加了event_test_int_bool(int val_int, bool val_bool)这个任务（Task）或者更形象的称之为“接口”（Interface），如下图所示：</li>
</ul>
<p><img class="aligncenter" src="/img/overview/task.png" alt="" /></p>
<ul>
<li>其次，为行为树event_subtree_2添加一个任务节点，并作为根节点的第一个子节点，为该任务节点选择一个任务，这里我们直接选择event_test_int_bool，如下图所示。类似于编程语言中的函数参数为函数体的代码提供了局部变量，任务节点中的接口参数为当前的行为树提供了局部变量，这些局部变量可以根据需要用于该行为树所有子节点。</li>
</ul>
<p><img class="aligncenter" src="/img/overview/settask.png" alt="" /></p>
<ul>
<li>再次，将上面的行为树event_subtree_2通过鼠标拖拽到行为树event_ut_1中的第一个序列节点上，这样该序列节点就有了一个事件的附件，如下图所示：</li>
</ul>
<p><img src="/img/overview/addevent.png" alt="" /></p>
<ul>
<li>然后，为该事件设置参数，如下图所示：<img src="/img/overview/eventparam.png" alt="" /><br />
其中，“触发一次”表示该事件是否只触发一次就不再起作用。“触发模式”控制该事件触发后对当前行为树的影响以及被触发的子树结束时应该如何恢复，有转移（Transfer）和返回（Return）两个选项：</p>
<ul>
<li>转移：当子树结束时，当前行为树被中断和重置，该子树将被设置为当前行为树。</li>
<li>返回：当子树结束时，返回控制到之前打断的地方继续执行。当前行为树直接“压”到执行堆栈上而不被中断和重置，该子树被设置为当前行为树，当该子树结束时，原本的那棵行为树从执行堆栈上“弹出”，并从当初的节点恢复执行。</li>
</ul>
</li>
<li>最后，在游戏代码端通过如下代码，将事件“event_test_int_bool”发出，并指定所需的参数（这里是15和true两个值）。</li>
</ul>
<figure class="highlight">
<pre><code class="language-cs" data-lang="cs"><span class="n">testAgent</span><span class="p">.</span><span class="nf">FireEvent</span><span class="p">(</span><span class="err">“</span><span class="n">event_test_int_bool</span><span class="err">”</span><span class="p">,</span> <span class="m">15</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span></code></pre>
</figure>
<p>这样，在执行行为树event_ut_1时，如果接收到事件“event_test_int_bool”，那么行为树中的事件附件将得到响应和处理，行为树的执行就会从当前的event_ut_1跳转到event_subtree_2。</p>
<p>调用FireEvent的时候，只有处于running状态的节点才响应事件。这样子是是为了事件的灵活性的考虑。这个设计是为了允许不同的分支不同的时机同样的事件可以触发不同的行为。比如同样是BeingHit，你受伤的时候，或者逃跑的时候可以对应不同的行为。如果不需要根据不同的节点相应不同的行为，只是需要响应事件，可以把事件配置在根节点上（根节点同样需要是running状态，非running状态的节点没有机会相应事件）。</p>
<p>另外需要补充说明的是，行为树event_subtree_2带有任务节点，我们也可以直接将该行为树拖拽到行为树event_ut_1中，如下图所示：</p>
<p><img class="aligncenter" src="/img/overview/eventsubtree.png" alt="" /></p>
<p>这样在行为树event_ut_1中，选中引用节点event_test_int_bool后，就可以直接配置该子树执行时所需的参数（这里是val_int和val_bool），如下图所示：</p>
<p><img class="aligncenter" src="/img/overview/subtreeparam.png" alt="" /></p>
<p>行为树的任务及其参数可以类比编程语言中的函数及其参数，因此event_test_int_bool这个“函数”有两个“形式参数”val_int和val_bool，而上图中所选择的5和true值就是event_test_int_bool函数执行时所用到的“实际参数”。</p>
<p>只有根节点是Task的子树才能被拖拽到另一个符合要求的树上生成事件。</p>
<p>可以查看 <a href="https://github.com/Tencent/behaviac/blob/master/test/btunittest/NodeTest/EventUnitTest.cpp">test/btunittest/NodeTest/EventUnitTest.cpp</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/tutorial11_event/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>附件</title>
		<link>/attachment/</link>
					<comments>/attachment/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 12 May 2016 10:10:18 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=226</guid>

					<description><![CDATA[附件（Attachments）类型可以附加到相应的节点上，在编辑器中有两类附件：显式附件和隐式附件。 1 显式附件 显式附件包括前置和后置，如下图所示： 可以在<a class="moretag" href="/attachment/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>附件（Attachments）类型可以附加到相应的节点上，在编辑器中有两类附件：显式附件和隐式附件。</p>
<h2 id="section">1 显式附件</h2>
<p>显式附件包括前置和后置，如下图所示：</p>
<p><img src="/img/references/attachment.png" alt="attachment" /></p>
<p>可以在任何一个节点通过鼠标拖拽来添加前置或后置附件，前置往往是作为前提条件（precondition）来使用，而后置往往是当节点结束的时候施加效果（effect）。</p>
<p>前置的属性主要有“联合”、“执行时机”、“左参数”、“操作符”和“右参数”等，如下图所示：</p>
<p><img src="/img/references/preaction_prop.png" alt="attachment" /></p>
<p>其中，“联合”是用于同一个节点的多个前置是“与（and）”还是“或（or）”的运算关系，执行时的逻辑顺序是从上往下依次执行，不管“与”还是“或”。如果“联合”是and<br />
&#8211; 如果有a，b两个前置，则最后的结果是（a and b）。<br />
&#8211; 如果有a，b，c三个前置，则最后的结果是（a and b and c），也即：（（a and b） and c）。如果a是false，b和c还是会计算，没有shortcut的优化。</p>
<p>如果“联合”是or<br />
&#8211; 如果有a，b两个前置，则最后的结果是（a or b）。<br />
&#8211; 如果有a，b，c三个前置，则最后的结果是（a or b or c），也即：（（a or b） or c）。如果a是true，b和c还是会计算，没有shortcut的优化。</p>
<p>“执行时机”分为Enter、Update和Both三种类型：</p>
<ul>
<li>Enter表示进入所在节点时，需要检查该前置。</li>
<li>Update表示所在节点每次更新时，都需要检查该前置。</li>
<li>Both表示不管所在节点是刚进入还是每次更新时，都需要检查该前置。</li>
</ul>
<p>后置的属性主要有“执行时机”、“左参数”、“操作符”和“右参数”等，如下图所示：</p>
<p><img src="/img/references/postaction_prop.png" alt="attachment" /></p>
<p>“执行时机”分为Success、Failure和Both三种类型：</p>
<ul>
<li>Success表示所在节点执行成功后，才需要继续执行该后置。</li>
<li>Failure表示所在节点执行失败后，才需要继续执行该后置。</li>
<li>Both表示不管所在节点执行成功还是失败后，都需要继续执行该后置。</li>
</ul>
<h2 id="section-1">2 隐式附件</h2>
<p>隐式附件主要是指事件这种附件，编辑器中没有单独的事件节点供拖拽来产生，需要通过拖拽另一棵行为树到目标行为树的节点来间接产生该事件附件。</p>
<p>只有根节点是Task的子树才能被拖拽到另一个符合要求的树上生成事件。</p>
<p>请详看文档《<a href="/docs/zh/tutorials/tutorial11_event/">事件处理</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>/attachment/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>任务节点</title>
		<link>/task/</link>
					<comments>/task/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 13 May 2016 02:12:05 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=260</guid>

					<description><![CDATA[任务节点（Task）用于描述一个接口，该接口的入口参数为当前的行为树提供了局部变量，这些局部变量可以根据需要用于该行为树所有子节点，如下图所示： 图1 任务节点<a class="moretag" href="/task/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>任务节点（Task）用于描述一个接口，该接口的入口参数为当前的行为树提供了局部变量，这些局部变量可以根据需要用于该行为树所有子节点，如下图所示：</p>
<p><img src="/img/references/task.png" alt="task" /></p>
<p>图1 任务节点</p>
<p>注意：任务节点只能作为行为树的第一个子节点存在，在任务节点上可以添加其他子节点。</p>
<p>在任务节点的任务属性中需要选择在类型信息浏览器中创建的事件，如下图所示：</p>
<p><img src="/img/references/task_prop.png" alt="task" /></p>
<p>图2 任务节点的属性</p>
<p>带有任务节点的行为树主要用于事件的处理，请详看文档《<a href="/docs/zh/tutorials/tutorial11_event/">事件处理</a>》。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/htn/task.cpp">htn/task.cpp</a></p>
]]></content:encoded>
					
					<wfw:commentRss>/task/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>选择监测节点</title>
		<link>/selectormonitor/</link>
					<comments>/selectormonitor/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 13 May 2016 02:11:13 +0000</pubDate>
				<category><![CDATA[手册]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[节点]]></category>
		<guid isPermaLink="false">/?p=258</guid>

					<description><![CDATA[选择监测节点（SelectorMonitor）和监测分支节点（WithPrecondition）作为对传统行为树的扩展，可以很自然的处理事件和状态的改变，类似于<a class="moretag" href="/selectormonitor/">Read More...</a>]]></description>
										<content:encoded><![CDATA[<p>选择监测节点（SelectorMonitor）和监测分支节点（WithPrecondition）作为对传统行为树的扩展，可以很自然的处理事件和状态的改变，类似于程序语言中的“switch&#8230;case”语句，如下图所示：</p>
<p id="xojrlZA"><img class="size-full wp-image-2000 aligncenter" src="/wp-content/uploads/2017/04/img_59015d5a54a9a.png" alt="" srcset="/wp-content/uploads/2017/04/img_59015d5a54a9a.png 887w, /wp-content/uploads/2017/04/img_59015d5a54a9a-300x126.png 300w, /wp-content/uploads/2017/04/img_59015d5a54a9a-768x323.png 768w" sizes="(max-width: 887px) 100vw, 887px" /></p>
<ul>
<li>选择监测和监测分支节点只能配对使用，即选择监测节点只能添加监测分支节点作为它的子节点，监测分支节点也只能作为选择监测节点的子节点被添加。</li>
<li>监测分支节点有条件分支子树和动作分支子树。只有条件分支子树返回成功的时候，动作分支子树才能够被执行。</li>
<li>选择监测节点是一个动态的选择节点，与选择节点（Selector）相同的是，它选择第一个返回成功的子节点，但不同的是，它不是只选择一次，而是每次执行时都对其子节点重新评估后再进行选择。</li>
</ul>
<p>默认情况下，上一次得到执行的动作分支，如果在下一次其条件分支也返回成功，那么这个动作分支会继续执行上次返回正在运行的节点。例如，假设上图中上一次执行行为树的时候，ID为13的条件节点返回成功，并且已经执行到ID为9的动作节点（这时ID为4的动作节点已返回成功，而ID为9的动作节点返回正在运行）。那么，当下一次执行该选择检测节点时，如果发现ID为13的条件节点还是返回成功，ID为9的动作节点就会直接得到执行，而不是先执行ID为4的动作节点。</p>
<p>但有的时候，可能需要在条件分支再次得到满足时，其动作分支需要重新执行，而不是默认情况下的从上次返回正在执行的节点继续执行。例如，对于上面的例子，当ID为13的条件节点再次返回成功时，需要重新执行其动作分支，即重新开始执行ID为4的动作节点。这时候，需要勾选上选择检测节点的属性“重置子节点”，如下图所示：</p>
<p id="TIymLqP"><img class="size-full wp-image-2001 aligncenter" src="/wp-content/uploads/2017/04/img_59016087886d5.png" alt="" srcset="/wp-content/uploads/2017/04/img_59016087886d5.png 476w, /wp-content/uploads/2017/04/img_59016087886d5-300x60.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<p>勾选该属性后，选择检测节点每次执行时，都会从头开始执行其动作分支。</p>
<p>选择检测节点的实现很像并行节点，每帧都要重新执行所有的子树，大量使用的时候请注意其性能。</p>
<p>具体的执行逻辑可以查看<a href="https://github.com/Tencent/behaviac/blob/master/src/behaviortree/nodes/composites/selectorloop.cpp">behaviortree/nodes/composites/selectorloop.cpp</a></p>
<p>另外，执行行为树的过程中，当状态、条件发生变化或发生事件（Event）时如何响应或打断当前的执行是个重要的问题。</p>
<p>目前behaviac组件支持三种方式来处理状态变化或事件发生：并行节点、选择监测节点、事件附件等。简而言之，并行和选择监测节点的工作方式是采用“轮询”的方式，每次执行时需要重新评估所有子节点，而不是像其他节点会保留上一次正在执行的子节点以便在下一次执行时继续执行。事件附件是在游戏逻辑（程序端）发出事件时，才按需得到响应。</p>
<p>请详看文档《<a href="/docs/zh/tutorials/tutorial11_event/">事件处理</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>/selectormonitor/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
