﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Heath's Blog-随笔分类-Game Development</title><link>http://cppblog.com/heath/category/10986.html</link><description>There is no end, it is just the beginning! - A Game Developer's Notes</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2014 11:13:00 GMT</lastBuildDate><pubDate>Tue, 20 May 2014 11:13:00 GMT</pubDate><ttl>60</ttl><item><title>新的开始</title><link>http://www.cppblog.com/heath/archive/2014/05/20/207029.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 20 May 2014 05:06:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2014/05/20/207029.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/207029.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2014/05/20/207029.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/207029.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/207029.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; 博客很久没有更新了，一定程度上说明自己变懒了。回顾近一年，开发了5年的游戏上线，拿了工作室的5年服务奖，自己也就顺理成章的变成了老人。在那些清闲的日子里，做得最有意义的事情就是每天接送老婆上下班，等着宝宝的降生。年初，终于把换工作室的计划提上日程，流程一卡就是3个月，等到4月末的时候也就差不多该休陪产假了，也就是说换个项目组花了近6个月的时间，期间除了老项目的零星杂事外，还是有不少时间来学习手游开发知识的。进入了新项目，一切都是新的，自己就像当年毕业生的状态，除了养家糊口的担子。当然，最重要的还是新生命的诞生，焦虑和兴奋充斥这整个等待过程，5月2日带着双眼皮和小酒窝的女儿来到了人世，希望她快乐健康地成长。<img src ="http://www.cppblog.com/heath/aggbug/207029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2014-05-20 13:06 <a href="http://www.cppblog.com/heath/archive/2014/05/20/207029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Real-time Cutscene中的摄像机插值研究</title><link>http://www.cppblog.com/heath/archive/2013/10/26/203921.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 26 Oct 2013 01:07:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/10/26/203921.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/203921.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/10/26/203921.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/203921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/203921.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 很多DCC工具都提供了Curves Editor，通过控制点来构造插值曲线，这样可以精确地插值轨迹。在我们游戏的过场编辑器中，我们并没有开发这类工具，一方面由于时间人力有限，另一方面希望能够提供一种直观简便的方式达到想要的效果。因此我们支持两种摄像机路径创建方法：1）以摄像机视角直接将摄像机摆到想要位置，保存此时摄像机的位置与旋转；2）将3DS Max中的路径导出为游戏的过场格式。前者可以满足90%的过场编辑需求，后者满足了10%的复杂路径编辑需求。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 不管使用那种方式，都需要将离散点进行插值（interpolation）以便得到平滑路径。这里就牵涉到位置插值和朝向插值。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 从插值函数上可分为三类：1）线性；2）多项式；3）样条。顾名思义，线性插值采用线性函数，多项式插值采用多项式，而样条插值则采用了一组多项式组成的分段函数。由于摄像机的关键路径点通常都会大于2个，所以插值方法上就必须选取样条方法。 <p><font size="4" face="Arial"><strong>一、位置插值</strong></font></p> <p><font size="3"><strong>1.1 样条类型选择</strong></font> <p>&nbsp;&nbsp;&nbsp;&nbsp; 在这里我们仅考虑三次样条插值，因为它们可达到C2连续。三次样条中主要以Bezier、Catmull-Rom、均匀B样条为考查对象，它们都具有计算开销小的优点。可以通过下面公式来定义它们： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(18)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(18)" border="0" alt="Image(18)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(18)_thumb.png" width="500" height="117"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 简化为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(19)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(19)" border="0" alt="Image(19)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(19)_thumb.png" width="130" height="32"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 下面表格列出了三种插值曲线对应的G和M： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(20)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(20)" border="0" alt="Image(20)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(20)_thumb.png" width="483" height="339"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 如下图所示，对4个点进行Bezier插值得到的曲线只会有两个点被曲线穿过，而B-Spline插值得到的曲线不会经过控制点，只有Catmull-Rom Spline可以得到穿过除起点和终点之间的所有控制点。正因为Catmull-Rom具有这个特性，使得它被广泛地应用在关键帧平滑插值上，因此我们选择了Catmull-Rom样条作为摄像机位置点的插值算法。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(21)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(21)" border="0" alt="Image(21)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(21)_thumb.png" width="400" height="917"></a> <p><font size="3"><strong>1.2 实现</strong></font> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image" border="0" alt="Image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image_thumb.jpg" width="759" height="732"></a> <p><font size="3"><strong>参考：</strong></font> <p>[1] <a href="http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Edition/dp/1435458869/ref=sr_1_1?ie=UTF8&amp;qid=1378171987&amp;sr=8-1&amp;keywords=Mathematics+for+3D+Game+Programming+and+Computer+Graphics">Mathematics for 3D Game Programming and Computer Graphics 3e by Eric Lengyel</a> <p>[2] <a href="http://en.wikipedia.org/wiki/Catmull-Rom_spline#Catmull.E2.80.93Rom_spline">http://en.wikipedia.org/wiki/Catmull-Rom_spline#Catmull.E2.80.93Rom_spline</a> <p>[3] <a href="http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio">http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio</a> <p><font size="4"><strong>二、朝向（旋转）插值</strong></font>&nbsp;&nbsp; <p><font size="3"><strong>2.1 Euler Angles VS Quaternion</strong></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 三维空间中描述旋转的主要方法有Euler Angles和Quaternion。Euler Angles有三个明显的问题：1）三轴上的旋转顺序敏感；2）Gimbal Lock现象导致旋转自由度丢失；3）独立地对三个旋转分量进行插值，忽略了三轴之间的依赖关系，导致插值结果不理想。与Euler Angles不同的是，Quaternion没有将旋转分解到三个轴向上，而是用一个旋转轴和绕该轴的旋转角度来描述，所以从根本上消除了Euler Angles的三大问题。有关Quaternion的详细描述可参考[1]，在此不再累述。 <p><font size="3"><strong>2.2 LERP VS SLERP</strong></font> <p>&nbsp;&nbsp;&nbsp;&nbsp; 四元数线性插值（Linear Quaternion interpolation）的计算公式为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(1)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(1)" border="0" alt="Image(1)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(1)_thumb.jpg" width="510" height="306"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 四元数球面线性插值（Spherical Linear Quaternion interpolation）的计算公式为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(2)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(2)" border="0" alt="Image(2)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(2)_thumb.jpg" width="315" height="43"></a> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(3)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(3)" border="0" alt="Image(3)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(3)_thumb.jpg" width="221" height="138"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 其中，θ为两个四元数的夹角。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 为了方便展示，我们考虑在2D情况对角度V进行两次插值，两种算法在插值效果上存在的差异，如下图（b为LERP、c为SLERP）： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(4)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(4)" border="0" alt="Image(4)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(4)_thumb.jpg" width="640" height="128"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 从图中可以看出LERP其实是对两四元数在圆上的弦进行了等分，而SLERP则是对圆弧进行等分。由此得出的结论是，SLERP得到了比LERP更平滑的插值结果。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 为了保证插值曲线的C2连续性，需要使用球面四边形插值（Spherical Quadrangle interpolation）方法。例如，对q1和q2插值，首先要用q0、q1、q2、q3计算出两个控制点（Inner Quadrangle Point），公式如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(5)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(5)" border="0" alt="Image(5)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(5)_thumb.jpg" width="286" height="79"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 然后通过下式得到最终插值结果： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(6)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(6)" border="0" alt="Image(6)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(6)_thumb.jpg" width="760" height="41"></a> <p><font size="3"><strong>2.3 实现</strong></font> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(7)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(7)" border="0" alt="Image(7)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(7)_thumb.jpg" width="696" height="1022"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 上面代码没有考虑两个四元数之间夹角大于180°的情况。例如，考虑q1-&gt;q2的插值角度θ&gt;180°，我们可以让q1-&gt;q2反向旋转2π-θ，即旋转-(2π-θ)，根据四元数的定义[v*sin(θ/2) , cos(θ/2)]，那么对q2进行处理变为[-v*sin(θ/2) , -cos(θ/2)]。这个处理可以放在AddSplinePoint中来做： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(8)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(8)" border="0" alt="Image(8)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(8)_thumb.jpg" width="527" height="234"></a> <p><font size="3"><strong>参考：</strong></font> <p>[1] <a href="http://www.itu.dk/people/erikdam/DOWNLOAD/98-5.pdf%E2%80%8E">Quaternions, Interpolation and Animation by EB Dam - 1998</a> <p>[2] <a href="http://www.amazon.com/Game-Engine-Architecture-Jason-Gregory/dp/1568814135/ref=sr_1_1?ie=UTF8&amp;qid=1378136624&amp;sr=8-1&amp;keywords=Game+Engine+Architecture+by+Jason+Gregory">Game Engine Architecture by Jason Gregory - 2009</a> <p>[3] <a href="https://theory.org/software/qfa/writeup/node12.html">https://theory.org/software/qfa/writeup/node12.html</a><img src ="http://www.cppblog.com/heath/aggbug/203921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-10-26 09:07 <a href="http://www.cppblog.com/heath/archive/2013/10/26/203921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows平台下针对C/C++项目的内存泄漏检测方法</title><link>http://www.cppblog.com/heath/archive/2013/10/26/203920.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 26 Oct 2013 00:55:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/10/26/203920.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/203920.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/10/26/203920.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/203920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/203920.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 由于语言在自动内存管理上的欠缺，C/C++在内存管理上从来都是需要程序员小心处理的一个方面，当项目代码上了一定规模，内存消耗和泄漏就会成为程序稳定运行的第一大敌。如果不在项目之初就建立内存管理和泄漏检测机制，后面蛋疼的问题就会接踵而来。这篇文章着重讨论内存泄漏检测，而内存管理与具体项目类型关系密切，后面有时间我会着重游戏项目来讨论。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 内存泄漏检测的基本步骤是：1）包装（重载）内存分配/释放API；2）进行内存分配时记下相关信息：地址、大小、调用栈；3）释放时清除之前记录的对应信息；4）程序退出时（确保在所有内存释放操作完成之后），输出剩下的记录。其中，对进行分配操作是的调用栈回溯是个重点信息，它能够帮助我们找出内存泄漏代码。 <p>&nbsp;&nbsp;&nbsp;&nbsp; Windows中的Dbghelp库提供了丰富的调试API。StackWalk应该是进行栈回溯最直接的一种接口了，但是它不够快。如果能先记录下调用栈上的CALL指令地址，然后在输出日志时解析出符号，将会大大降低检测机制对程序本身性能的影响。Dbghelp库中提供了Sym*FromAddr系列API，可以通过指令地址获取函数符号，那么剩下的就是如何记录指令地址的问题了。从网上借了一张x86调用栈示意图，如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(12)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(12)" border="0" alt="Image(12)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(12)_thumb.png" width="263" height="458"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 从图中可以看出，Callee的EBP始终指向Caller的EBP，EBP下面是指向Caller下一条指令（注意x86体系下栈的增长方向是小地址），因此通过EBP就可以回溯整个调用栈了。通过下面代码可以实现此功能： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(13)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(13)" border="0" alt="Image(13)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(13)_thumb.png" width="512" height="335"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 宏参数frame是个void*指针数组，数组的大小取决于想要回溯的栈深度。内存分配和回收的包装代码如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(14)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(14)" border="0" alt="Image(14)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(14)_thumb.png" width="768" height="311"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我们看到，内存管理系统内部终究还是要使用语言提供的内存分配/释放API，只要配对实现了分配与释放管理，系统内部的无泄漏是很容易保证的。在这里着重讲解原理，就不重载new/delete operator了。最后看一下调用栈函数符号的回溯代码： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(15)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(15)" border="0" alt="Image(15)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(15)_thumb.png" width="1236" height="868"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我们用下面代码做测试用例： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(16)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(16)" border="0" alt="Image(16)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(16)_thumb.png" width="537" height="567"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 泄漏检测结果： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(17)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(17)" border="0" alt="Image(17)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(17)_thumb.png" width="800" height="322"></a> <p>参考： <p>[1] <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681412(v=vs.85).aspx">Using DbgHelp</a> <p>[2] <a href="http://www.unixwiz.net/techtips/win32-callconv-asm.html">Intel x86 Function-call Conventions - Assembly View</a><img src ="http://www.cppblog.com/heath/aggbug/203920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-10-26 08:55 <a href="http://www.cppblog.com/heath/archive/2013/10/26/203920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3DS Max坐标系与D3D左手系的简单转换方法</title><link>http://www.cppblog.com/heath/archive/2013/06/08/200890.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 08 Jun 2013 14:31:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/06/08/200890.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/200890.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/06/08/200890.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/200890.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/200890.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2013/06/08/200890.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/200890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-06-08 22:31 <a href="http://www.cppblog.com/heath/archive/2013/06/08/200890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决A*寻路中边缘行走问题</title><link>http://www.cppblog.com/heath/archive/2013/05/04/199973.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 04 May 2013 15:49:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/05/04/199973.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/199973.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/05/04/199973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/199973.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/199973.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 用碰撞体来约束世界范围已经用得很广泛了，玩家与世界边缘的交互问题也容易用碰撞面的法线和玩家朝向来解决。然而对于一个基于A* PathFinding的游戏，貌似还没有人去考虑和解决这个问题。最初考虑这个问题，是因为游戏中加入了AWSD的移动方式，当碰到阻挡就静止不动了，加上有时阻挡刷得与场景不太贴合，造成玩家在移动上的不爽快。考虑下图的情况，蓝色三角是角色，红色线段给出了前进方向和终点（游戏中配置为角色朝向上5m处）。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(9)%5B6%5D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(9)[6]" border="0" alt="Image(9)[6]" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(9)%5B6%5D_thumb.png" width="503" height="290"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我想了两种方案，最初的方案灵感来自光线反射，如下图所示。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(10)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(10)" border="0" alt="Image(10)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(10)_thumb.png" width="516" height="282"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 因为阻挡格子是轴对齐的，通过法向量n可以得到b点的反射向量e'-o，将|e'-o|限定在一个固定值，此时如果e'不在阻挡里面，就将它作为新的终点。该方案的实验结果不太令人满意，当角色离阻挡较近时断续感太明显，因为|e' - b|的长度较短。另外它不能处理e'在阻挡里的情况，被卡住不动的概率依然较大。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 第二种方案是根据移动趋向在一个轴向找一个可达试探点，然后用限制了搜索空间（搜索节点在50以内）的A*算法找到一条到试探点的路径，如下图。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(11)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(11)" border="0" alt="Image(11)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(11)_thumb.png" width="506" height="285"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 设diff_x = 终点x - 起点x，diff_y = 终点y - 起点y，当diff_x &gt; diff_y，认定为趋向x方向上移动，在这种情况下在终点y轴向上±10个格子内去找到一个最接近终点的无阻挡点（称它为可达试探点）。由于试探点与玩家当前点极有可能是直线不连通的，而且它们不可能太远，所以使用了一个将搜索节点个数限制在50以内A*来得到一条路径。该方案大部分情况都能在边缘找到合理点，但如果玩家垂直面朝阻挡内移动且不能在限制搜索范围内找到可达点，角色就会卡住不动，这种情况就只能让玩家自己调整一下朝向了。 <img src ="http://www.cppblog.com/heath/aggbug/199973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-05-04 23:49 <a href="http://www.cppblog.com/heath/archive/2013/05/04/199973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>toLua++的导出函数如何访问Lua Table</title><link>http://www.cppblog.com/heath/archive/2013/02/12/197808.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 12 Feb 2013 11:30:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/02/12/197808.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/197808.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/02/12/197808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/197808.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/197808.html</trackback:ping><description><![CDATA[<p>有些函数需要向lua返回多个结果，将这些结果存在table中是理所当然的。因为toLua++已经自动生成了函数的wrapper，所以没办法直接将栈顶table返回给Lua。好在toLua预留了lua_Object这个类型，可以代表lua中的任何类型，其实它只是int的typedef罢了，主要是在toLua解析程序时作为标记产生tolua_tovalue调用。在C/C++函数中，需要检查一下栈顶是否为table类型，进行table元素的插入操作，例子函数如下：<pre class="code"><span style="color: blue">void </span>ActorMgr::GetPlayerEntityIDs( lua_Object lua_table )
{
       TEntityListIt tIt ;
       std::list &lt;<span style="color: blue">int</span>&gt; result;

       <span style="color: blue">for</span>(<span style="color: blue">int </span>i = 0; i &lt; ACOTOR_BUCKET_LEN ; ++i)
      {
             <span style="color: blue">for</span>(tIt =mSceneEntities[i].mEntities.begin(); tIt != mSceneEntities[i].mEntities.end( ); ++tIt )
            {
                   TActorPtr tpActor  = tIt-&gt;second-&gt;mpActor ;
                   <span style="color: blue">if</span>(tpActor -&gt;GetActorType() == LOCAL_PLAYER)
                  {
                         result.push_front(tpActor-&gt;GetEntityID());
                  }
                   <span style="color: blue">else if </span>(tpActor-&gt; GetActorType() == REMOTE_PLAYER )
                  {
                         result.push_back(tpActor-&gt;GetEntityID());
                  }
            }
      }
       lua_State* L = LuaVM::GetInstPtr()-&gt;mLS ;
       assert(lua_istable (L , -1));
       std::list &lt;<span style="color: blue">int</span>&gt;:: iterator iter = result. begin();
       <span style="color: blue">for</span>(<span style="color: blue">int </span>i = 1; iter != result .end(); ++ iter , ++i )
      {
             lua_pushinteger(L , *iter);
             lua_rawseti(L , -2 , i);
      }
       lua_pop(L , 1);
}</pre>
<p>需要注意的是，如果是多个参数，Lua的压栈顺序是object pointer、参数从左到右，所以栈顶元素是函数签名最右边的参数。</p><img src ="http://www.cppblog.com/heath/aggbug/197808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-02-12 19:30 <a href="http://www.cppblog.com/heath/archive/2013/02/12/197808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单想了一下《泡泡龙》的实现</title><link>http://www.cppblog.com/heath/archive/2012/11/27/195752.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 27 Nov 2012 15:43:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/11/27/195752.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/195752.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/11/27/195752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/195752.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/195752.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 领导最近在玩泡泡龙，我也想不通为什么突然又对这么古老的游戏感兴趣了。昨晚在地铁上，她问我这种游戏能做吗？我不加思考回答道：当然，超简单。今天从深大地铁站出来，这个问题突然冒了出来，到公司的路上花了几分钟思考了下实现细节。从最简单的玩法开始：相同颜色的泡泡三个以上可以消除。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 核心数据结构我采用链表数组，将相同颜色且邻接的泡泡串成一个链表。采用这种数据结构，是基于下面考虑：1）通过颜色划分缩小搜索区域；2）没有排序，没有中间插入节点的需求；3）节省内存。当然，游戏界面中的泡泡还是把它对应到一个二维数组中，每个元素存储一个泡泡对象的指针，该对象中至少包含：颜色、坐标，分值。如下图所示： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/7a9d2cb25d28_14D24/Image(8)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(8)" border="0" alt="Image(8)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/7a9d2cb25d28_14D24/Image(8)_thumb.png" width="640" height="320"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剩下需要考虑的是发射泡泡颜色如何产生？如果从空关卡开始，前面可以用随机，后面就要使用统计信息了。在每个链表头可以统计该堆泡泡开闭性、数量等，利用这些信息可以决定发射泡泡的颜色。 <img src ="http://www.cppblog.com/heath/aggbug/195752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-11-27 23:43 <a href="http://www.cppblog.com/heath/archive/2012/11/27/195752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Window调试中的符号文件与源代码管理</title><link>http://www.cppblog.com/heath/archive/2012/03/26/169068.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 26 Mar 2012 15:10:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/03/26/169068.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/169068.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/03/26/169068.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/169068.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/169068.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 游戏开始进行第二次封闭测试，这次参与人数较多，随之而来的便是无数的崩溃dump。虽然在自动构建流程中已经对PDB和EXE按版本号进行了保存，但由于构建操作人员手动修改构建号，出现多个版本对应相同版本号的问题，以及BUG单填写人以基线版本号而非真实版本号提交的情况，经常浪费开发人员的时间和精力去找对应的PDB，降低了崩溃解决的响应速度。所以非常有必要建立一套自动化方案，得到dump文件后启动WinDbg进行分析时能够自动获取对应的PDB和源代码，WinDbg就提供了这样一套方便实用的工具。</p> <p><b><font size="3">1. 建立源代码索引</font></b>  <p><b></b>&nbsp;&nbsp;&nbsp;&nbsp; WinDbg提供了一套用于管理pdb对应的源代码的工具，位于其安装目录的srcsrv下，对VSS、SVN、CVS、Perforce提供了支持，分别对应vssindex.cmd、svnindex.cmd、cvsindex.cmd、p4index.cmd这四个perl脚本。其实，ssindex.cmd才是具体实现，它根据传入的版本控制系统标识，调用对应的perl module。  <p>&nbsp;&nbsp;&nbsp;&nbsp; svnindex.cmd通过/source和/symbols参数来指定源代码目录和PDB目录，/debug可输出处理的详细信息，/user和/pass提供svn账户和密码。PDB文件中有一节专门用于存放源代码文件列表及处理命令，可通过pdbstr -r -p:PdbFileName -s:srcsrv查看。  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; svnindex.cmd /debug /source="E:\CodeBase_SVN\Client\trunk\tools\CutSceneEditor" /symbols="E:\CodeBase_SVN\Client\trunk\bin\Release\CutSceneEditor" /user="user" /pass="pwd"  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 在执行上面命令前，确保Perl和Subversion已经被安装且设置了PATH环境变量。该命令将提取source code的服务器路径和当前Revision，然后写入PDB。下面是通过pdbstr获取的信息：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(9)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(9)" border="0" alt="Image(9)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(9)_thumb.png" width="569" height="278"></a>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 上面输出是经过格式化的，原始信息可以通过srctool -n查看：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(10)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(10)" border="0" alt="Image(10)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(10)_thumb.png" width="547" height="202"></a>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 可以看出，原始代码路径后面跟了一条svn cat指令，由于没有指定sourcepath，所以%targ%缺省为当前路径（"C:\Program Files\Debugging Tools for Windows (x64)\srcsrv"）。&nbsp; <p><b><font size="3">2. 创建符号服务器</font></b>  <p>&nbsp;&nbsp;&nbsp; 所谓符号服务器，最简单的形式就是文件共享服务器。我们使用<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681378%28v=vs.85%29.aspx" target="_blank">symstore命令</a>，将1中产生的pdb添加到一个文件共享服务器上，如：  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; symstore.exe add /f "E:\CodeBase_SVN\Client\trunk\bin\Release\CutSceneEditor\*.pdb" /s "\\server.com\pub\Symbols" /t "CutSceneEditor" /v "Build 4171" /c "fix memory leak"  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 该命令会根据PDB的signature和age产生一个GUID，并将PDB放置于以改GUID为名字的目录下：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image8" border="0" alt="Image8" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image8_thumb.png" width="304" height="505"></a>  <p>&nbsp;&nbsp;&nbsp; 当debug时，将UNC路径添加到_NT_SYMBOL_PATH中（如：_NT_SYMBOL_PATH=CACHE*F:\Symbols;SRV*http://msdl.microsoft.com/download/symbols;SRV*\\server.com\pub\Symbols），调试器会自动到指定的符号服务器上去搜索对应的pdb文件。  <p>&nbsp;&nbsp;&nbsp;&nbsp; symstore大大简化了符号的版本管理问题，关于它的详细介绍可参考<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681417%28v=vs.85%29.aspx" target="_blank">symstore介绍</a>。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 值得注意的是，symstore没有锁机制，并不支持多人同时操作。实际情况中，也只有自动构建时才会做此操作。 </p> <p> <p><b><font size="3">3. 使用WinDbg分析Dump文件</font></b>  <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>我们在代码中加入发生异常写MiniDump的功能，在程序崩溃时产生dump文件。在使用WinDbg分析dump文件时，需要设置Symbol File Path和Source File Path，也可以直接设置环境变量_NT_SYMBOL_PATH和_NT_SOURCE_PATH。在设置_NT_SOURCE_PATH时使用"SRV*CachePath"将表示启用代码提取功能，执行svn cat写入到CachePath指定的目录，否则将使用原始路径。此后，通过点击Call Stack中的函数调用便会触发从svn读取对应代码的操作（通常会有一个安全警告窗口弹出）。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 对于使用WinDbg进行调试在此就不多讲了，推荐一本不错的书《Advanced Windows Debugging》。  <p><font size="3"><strong></strong></font>&nbsp; <p><font size="3"><strong>参考资料</strong></font>  <p>[1] <a href="http://www.codeproject.com/Articles/115125/Source-Indexing-and-Symbol-Servers-A-Guide-to-Easi" target="_blank">Source Indexing and Symbol Servers: A Guide to Easier Debugging</a>  <p>[2] <a href="http://msdn.microsoft.com/en-us/magazine/cc163563.aspx" target="_blank">Source Server Helps You Kill Bugs Dead In Visual Studio 2005</a></p><img src ="http://www.cppblog.com/heath/aggbug/169068.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-03-26 23:10 <a href="http://www.cppblog.com/heath/archive/2012/03/26/169068.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hierarchical Path-Finding</title><link>http://www.cppblog.com/heath/archive/2011/11/12/159984.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 12 Nov 2011 04:50:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/11/12/159984.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/159984.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/11/12/159984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/159984.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/159984.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 《<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.7041&amp;rep=rep1&amp;type=pdf">Near Optimal Hierarchical Path-Finding</a>》中提出了一种层次A*算法，正好能够用于解决项目大地图寻路的问题。大致思路是：1）预处理。将地图划分为nxn大小的区块，找出每个区块与周围四个区块在边界上的互通点，在区块中使用局部A*对找出的点做连通性测试并将其保存下来；2）寻路时，使用预处理得到的数据（边界上的可通点与区块内部的互通点），先在区块层级上做一次A*，根据结果再在每个区块中使用局部A*找到区块与区块之间的路径，最终得到完整路径。  <p><font size="5">一、A* Path-Finding</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; A*算法就不多讲了，可参考：  <ul> <li><a href="http://theory.stanford.edu/~amitp/GameProgramming/">http://theory.stanford.edu/~amitp/GameProgramming/</a>  <li><a href="http://www.policyalmanac.org/games/aStarTutorial.htm">http://www.policyalmanac.org/games/aStarTutorial.htm</a></li></ul>&nbsp;&nbsp;&nbsp;&nbsp; A*算法的优化可从搜索节点储存和OpenList排序两方面入手。  <p><font size="5">二、预处理</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 每个相邻区块（C1和C2）都有一条由公共边，该边两侧小格组成L1和L2，则连通点集E满足下列条件：  <ul> <li>E ⊂ L1 ∪ L2  <li>∀t ∈ L1 ∪ L2 : t ∈ E ⇔ symm(t) ∈ E ，其中symm(t)为对称关系  <li>E不含不可行走格子</li></ul>&nbsp;&nbsp;&nbsp;&nbsp; 对在E中且同边的连续格子取其中点，如下图所示：  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(6)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(6)" border="0" alt="Image(6)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(6)_thumb.png" width="832" height="641"></a>  <p>&nbsp;&nbsp;&nbsp; 对上面得到的位于同一区块的点集合使用local A*做连通性测试，下图用直线连接来表示两点互通：  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(7)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(7)" border="0" alt="Image(7)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(7)_thumb.png" width="826" height="631"></a>  <p><font size="5">三、寻路</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 使用区块连通信息，进行区块级A*，得到区块之间的连接点，如果在预处理时保存了区块内互通点的路径，就不必再进行区块内的local A*了。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 实验结果表明，在未采用区块内预存路径的情况下，中长距离寻路使用层次A*后的平均效率是普通A*的5倍以上，距离越长效率对比越明显。  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb.png" width="903" height="469"></a>  <p align="left">&nbsp;&nbsp;&nbsp;&nbsp; A* 93ms  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb_1.png" width="888" height="516"></a></p> <p>HPA* 15ms  <p>&nbsp;&nbsp;&nbsp;&nbsp; 从上图中可以看出，HPA*得到的路径并不是最优的，它是在最优和效率上的折中，适合作为长距离寻路的一种优化方案。  <p><font size="5">四、优化点</font>  <ul> <li>可扩展为多层而不仅限于一层  <li>预存区块内连通点路径  <li>区块边界可通面积较大时，产生不自然路径，如下图所示：</li></ul> <blockquote> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb_2.png" width="460" height="112"></a></p></blockquote> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个改进的方法是对过长的边界再做划分：  <blockquote> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(5)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(5)" border="0" alt="Image(5)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(5)_thumb.png" width="244" height="234"></a></p></blockquote><img src ="http://www.cppblog.com/heath/aggbug/159984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-11-12 12:50 <a href="http://www.cppblog.com/heath/archive/2011/11/12/159984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>修正D3DXQuaternionSquad不能正确处理反向Quaternions的BUG</title><link>http://www.cppblog.com/heath/archive/2011/08/21/154037.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 21 Aug 2011 14:16:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/08/21/154037.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/154037.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/08/21/154037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/154037.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/154037.html</trackback:ping><description><![CDATA[<p>微软DX库里提供了对Quaternion进行球面四边形内插的接口，能够在多个Quaternion之间平滑插值。这里涉及到两个接口：</p><pre>void D3DXQuaternionSquadSetup(
  __out&nbsp; D3DXQUATERNION *pAOut,
  __out&nbsp; D3DXQUATERNION *pBOut,
  __out&nbsp; D3DXQUATERNION *pCOut,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ0,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ1,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ2,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ3
);</pre><pre>D3DXQUATERNION* D3DXQuaternionSquad(
  __inout&nbsp; D3DXQUATERNION *pOut,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pQ1,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pA,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pB,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pC,
  __in&nbsp;&nbsp;&nbsp;&nbsp; FLOAT t
);</pre><pre>其中，D3DXQuaternionSquadSetup用于返回内插的控制点。它们具体的实现公式和用法，有兴趣的同学可以参考MSDN。在此需要说明的是，</pre><pre>D3DXQuaternionSquad使用了Slerp作为内部实现，会导致在两个夹角为180°左右的Quaternion之间插值会出现断裂的问题。下面代码通过</pre><pre>实现一个考虑了上述情况的Slerp版本，在q1和q2夹角在0°或者180°时，使用线性内插而非球面，来解决该问题。</pre>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:1cd98649-9aef-4333-8ab4-db2524382469" class="wlWriterEditableSmartContent">
<div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="color:#010001">Quaternion</span> <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">q1</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">q2</span> , <span style="color:#0000ff">float</span> <span style="color:#010001">t</span>)</li>
<li style="background: #f3f3f3">{</li>
<li>    <span style="color:#0000ff">float</span> <span style="color:#010001">cosAngle</span> = <span style="color:#010001">DotProduct</span>(<span style="color:#010001">q1</span>, <span style="color:#010001">q2</span>);</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#0000ff">float</span> <span style="color:#010001">c1</span>, <span style="color:#010001">c2</span>;</li>
<li style="background: #f3f3f3">    <span style="color:#008000">// Linear interpolation for close orientations</span></li>
<li>    <span style="color:#0000ff">if</span> ((1.0f - <span style="color:#010001">fabs</span>(<span style="color:#010001">cosAngle</span>)) &lt; 1e-5f)</li>
<li style="background: #f3f3f3">    {</li>
<li>        <span style="color:#010001">c1</span> = 1.0f - <span style="color:#010001">t</span>;</li>
<li style="background: #f3f3f3">        <span style="color:#010001">c2</span> = <span style="color:#010001">t</span>;</li>
<li>    }</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">else</span></li>
<li>    {</li>
<li style="background: #f3f3f3">        <span style="color:#008000">// Spherical interpolation</span></li>
<li>        <span style="color:#0000ff">float</span> <span style="color:#010001">angle</span>    = <span style="color:#010001">acos</span>(<span style="color:#010001">fabs</span>(<span style="color:#010001">cosAngle</span>));</li>
<li style="background: #f3f3f3">        <span style="color:#0000ff">float</span> <span style="color:#010001">sinAngle</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span>);</li>
<li>        <span style="color:#010001">c1</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span> * (1.0f - <span style="color:#010001">t</span>)) / <span style="color:#010001">sinAngle</span>;</li>
<li style="background: #f3f3f3">        <span style="color:#010001">c2</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span> * <span style="color:#010001">t</span>) / <span style="color:#010001">sinAngle</span>;</li>
<li>    }</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#010001">Quaternion</span> <span style="color:#010001">q</span> = <span style="color:#010001">q1</span> * <span style="color:#010001">c1</span> + <span style="color:#010001">q2</span> * <span style="color:#010001">c2</span>;</li>
<li style="background: #f3f3f3">    <span style="color:#010001">q</span>.<span style="color:#010001">Normalize</span>();</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">q</span>;</li>
<li>}</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#010001">Quaternion</span> <span style="color:#010001">QuatSquad</span>(<span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p1</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p2</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p3</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p4</span> , <span style="color:#0000ff">float</span> <span style="color:#010001">t</span>)</li>
<li style="background: #f3f3f3">{</li>
<li>    <span style="color:#0000ff">static</span> <span style="color:#010001">Quaternion</span> <span style="color:#010001">a</span> , <span style="color:#010001">b</span> , <span style="color:#010001">c</span>;</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#010001">D3DXQuaternionSquadSetup</span>((<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">a</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">b</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">c</span> ,</li>
<li style="background: #f3f3f3">        (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p1</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p2</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p3</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p4</span>);</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">p2</span> , <span style="color:#010001">c</span> , <span style="color:#010001">t</span>) , <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">a</span> , <span style="color:#010001">b</span> , <span style="color:#010001">t</span>) , 2 * <span style="color:#010001">t</span> * (1-<span style="color:#010001">t</span>));</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>参考：</p>
<p>[1] <a href="http://msdn.microsoft.com/en-us/library/bb205419(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/bb205419(v=vs.85).aspx</a></p>
<p>[2] <a href="http://msdn.microsoft.com/en-us/library/bb205420(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/bb205420(v=vs.85).aspx</a></p><img src ="http://www.cppblog.com/heath/aggbug/154037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-08-21 22:16 <a href="http://www.cppblog.com/heath/archive/2011/08/21/154037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个QTE原型框架</title><link>http://www.cppblog.com/heath/archive/2011/08/13/153251.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 13 Aug 2011 02:25:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/08/13/153251.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/153251.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/08/13/153251.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/153251.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/153251.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: QTE为Quick Time Event的简写，多见于主机游戏中，通常以在规定时间内根据提示完成（一系列）按键操作的形式出现。就表现上看，其实是过场动画的一种分解触发机制，用于表现看似复杂实则固定的动作或者场景效果，一方面在消除了单纯过场乏味感的同时增强了游戏的互动性，另一方面还降低了表现复杂效果的开发难度。<br>本文主要根据自己在项目中开发的QTE系统，介绍一个相对比较简单的原型框架。&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2011/08/13/153251.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/153251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-08-13 10:25 <a href="http://www.cppblog.com/heath/archive/2011/08/13/153251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>算法优化&amp;mdash;&amp;mdash;递归到循环</title><link>http://www.cppblog.com/heath/archive/2011/03/05/141160.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 05 Mar 2011 05:42:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/03/05/141160.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/141160.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/03/05/141160.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/141160.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/141160.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 递归通常很直白地描述了一个求解过程，因此也是最容易被想到和实现的算法。循环其实和递归具有相同的特性（即：做重复任务），但有时，使用循环的算法并不会那么清晰地描述解决问题步骤。单从算法设计上看，递归和循环并无优劣之别。然而，在实际开发中，因为函数调用的开销，递归常常会带来性能问题，特别是在求解规模不确定的情况下。而循环因为没有函数调用开销，所以效率会比递归高。除少数编程语言对递归进行了优化外，大部分语言在实现递归算法时还是十分笨拙，由此带来了如何将递归算法转换为循环算法的问题。算法转换应当建立在对求解过程充分理解的基础上，有时甚至需要另辟蹊径。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 前段时间遇到过这样的问题：已知一2D地图格子的长宽（w、h）及每个格子的边长（a，格子为正方形），给定物体的2D坐标（pos[x , y]）及半径（r），求解物体在2D地图格子中所占的格子，仅考虑n*n的情况。大概的求解过程如下：  <p>1）根据半径，确定n*n中的n。假定计算公式为：n = Round(2*r / a)  <p>2）根据2D坐标得到物体的“中心格子”。根据n的奇偶，计算公式不同，如下图所示。  <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_10.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_4.png" width="239" height="244"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_12.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_5.png" width="240" height="244"></a></p> <p align="center">n为偶数[1]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n为奇数[2]</p> <p>[1]：grid(x , y) = Round(pos / a)  <p>[2]：grid(x , y) = Floor(pos / a)  <p>其中，格子坐标x &gt;= 0 , y &gt;= 0。  <p>3）以“中心格子”为基础，求出物体占据的其他格子。这样的描述，让人容易想到递归，就像用深度优先方法遍历树那样，伪代码算法如下：</p> <div style="padding-bottom: 0px; padding-left: 0px; width: 1032px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:866d37ab-87f1-4aea-9d49-b7235fcfb0e9" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">if</span><span style="color: #000000;"> n is even
{
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
    ExtendHeldGrid(row , col , n)
    ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , n)
    ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , n)
    ExtendHeldGrid(row , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , n)
}
</span><span style="color: #0000FF;">else</span><span style="color: #000000;">
{
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
    ExtendHeldGrid(row , col , n)
}

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> ExtendHeldGrid(row , col , level)
{
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(level </span><span style="color: #000000;">&lt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;">

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">((row </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> row </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridWidth) </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> (col </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> col </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridHeight))
    {
        mark the grid(row , col)
        ExtendHeldGrid(row , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;"> </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
        {
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        }
    }
}
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>虽然，该算法得到了正确的求解结果，但是由于每个格子都会标记周围的8个格子，所以存在大量的重复，再者如果上面的过程每帧都进行的话，函数调用开销也是相当可观。</p>
<p>循环自然是不可避免的，消除重复便成了优化的目标。分析格子图和n为2和3的情况，试图找出用循环代替递归的方法，我发现了下面一个有趣的规律：</p>
<p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_16.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_7.png" width="239" height="244"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_18.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_8.png" width="240" height="244"></a></p>
<p>从“中心格子”出发，顺时针（或逆时针）以上图方式可以走遍所求解的每个格子而不重复。在实现上，每个转角也是有规律的，可以通过一个2*2的转角矩阵来控制：</p>
<p align="center">[1 , 0][0 , -1]</p>
<p align="center">[0 , 1][-1 , 0]</p>
<p align="center">顺时针方式的转角阵</p>
<p align="left">&nbsp;</p>
<p>矩阵中的每个元素代表从当前格子走到下个格子在row和col上的变化。加之，在转角之间的路长（以格子个数计）有每转两次递增单位1的规律，算法就不难得到了，下面同样以伪代码示：</p>
<div style="padding-bottom: 0px; padding-left: 0px; width: 1032px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:c1053f9b-292c-4f91-b901-a530b31c17c3" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">conerMat </span><span style="color: #000000;">=</span><span style="color: #000000;"> 
{
    {</span><span style="color: #800080;">0</span><span style="color: #000000;"> , </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">} , 
    {</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;"> , </span><span style="color: #800080;">0</span><span style="color: #000000;">} ,
    {</span><span style="color: #800080;">0</span><span style="color: #000000;">  , </span><span style="color: #800080;">1</span><span style="color: #000000;">} ,
    {</span><span style="color: #800080;">1</span><span style="color: #000000;">  , </span><span style="color: #800080;">0</span><span style="color: #000000;">}
}

dir </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">     </span><span style="color: #000000;">///</span><span style="color: #000000;"> 转角控制，四个转角顺时针0~</span><span style="color: #800080;">3</span><span style="color: #000000;">
span </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">    </span><span style="color: #000000;">///</span><span style="color: #000000;"> 转角间的跨度
count </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">   </span><span style="color: #000000;">///</span><span style="color: #000000;"> 每两次增加一个跨度
rin </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">     </span><span style="color: #000000;">///</span><span style="color: #000000;"> 下一个转角的循环索引

</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> n is even
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
</span><span style="color: #0000FF;">else</span><span style="color: #000000;">
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)

</span><span style="color: #0000FF;">for</span><span style="color: #000000;">(i </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> n </span><span style="color: #000000;">*</span><span style="color: #000000;"> n; </span><span style="color: #000000;">++</span><span style="color: #000000;">i)
{
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">((row </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> row </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridWidth) </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> (col </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> col </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridHeight))
        mark the grid(row , col)

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(i </span><span style="color: #000000;">==</span><span style="color: #000000;"> rin)
    {
        dir </span><span style="color: #000000;">=</span><span style="color: #000000;"> (dir </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">) </span><span style="color: #000000;">%</span><span style="color: #000000;"> </span><span style="color: #800080;">4</span><span style="color: #000000;">

        </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(count </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        {
            </span><span style="color: #000000;">++</span><span style="color: #000000;">span
            count </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
        }
        </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
            </span><span style="color: #000000;">++</span><span style="color: #000000;">count

        rin </span><span style="color: #000000;">=</span><span style="color: #000000;"> i </span><span style="color: #000000;">+</span><span style="color: #000000;"> span
    }

    row </span><span style="color: #000000;">=</span><span style="color: #000000;"> row </span><span style="color: #000000;">+</span><span style="color: #000000;"> conerMat[dir][</span><span style="color: #800080;">0</span><span style="color: #000000;">]
    col </span><span style="color: #000000;">=</span><span style="color: #000000;"> col </span><span style="color: #000000;">+</span><span style="color: #000000;"> conerMat[dir][</span><span style="color: #800080;">1</span><span style="color: #000000;">]
}

</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>用MFC程序验证了一下算法的正确性，标号展示了循环的路线（注意GDI的坐标系中Y的正方向朝下）：</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_20.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_9.png" width="863" height="510"></a></p><img src ="http://www.cppblog.com/heath/aggbug/141160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-03-05 13:42 <a href="http://www.cppblog.com/heath/archive/2011/03/05/141160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows下Perforce Command Line处理中文参数的两种方法</title><link>http://www.cppblog.com/heath/archive/2010/11/15/133692.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 15 Nov 2010 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/11/15/133692.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/133692.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/11/15/133692.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/133692.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/133692.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; Windows下Command Line中的中文字符是采用ANSI编码来处理的，而Perforce command line要求传入的中文参数（文件（夹）名）为UTF-8编码，所以需要将中文参数转换为UTF-8后再做处理，下面介绍两种处理方法。</p> <p>一、系统调用</p> <p>&nbsp;&nbsp;&nbsp; 通过使用WinExec、ShellExecute或system，如：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:a202efe8-f955-49cf-8f11-16a2b3b1f36b" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #008080;">_snprintf</span><span style="color: #000000;">(cmdbuf , </span><span style="color: #800080;">1024</span><span style="color: #000000;"> , </span><span style="color: #800000;">"</span><span style="color: #800000;">p4 -c %s add \</span><span style="color: #800000;">"</span><span style="color: #000000;">%</span><span style="color: #000000;">s\</span><span style="color: #800000;">""</span><span style="color: #000000;"> , argv[</span><span style="color: #800080;">1</span><span style="color: #000000;">] , ANSIToUTF8(path.c_str()));
system(cmdbuf);</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 此方法的虽然简单，但存在效率问题，因为有创建进程的巨大开销。此外不同版本的Perforce也会出现不同的执行结果，针对特定的中文会出现操作失败的诡异问题。</p>
<p>二、Perforce SDK</p>
<p>&nbsp;&nbsp;&nbsp; Perforce提供有SDK用以扩展或集成到其他应用中，虽然没有详细的文档，但可以通过学习SDK中的sample文件来学习，此方法最稳定。</p>
<p>&nbsp;&nbsp;&nbsp; 下面代码展示了通过SDK中ClientAPI来递归添加指定文件夹下的所有文件：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:891e1b70-295a-4daf-9c0d-8f0ad2ef8b07" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">clientapi.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">i18napi.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">CharSetConvertUtil.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">vector</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">list</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">io.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">

using namespace std;

</span><span style="color: #000000;">//</span><span style="color: #000000;"> structure to hold a directory </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> all its filenames.
struct FILELIST
{
    string path;
    vector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> theList;
};


void TransverseDirectory(string path, list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&amp; theList)
{
    struct </span><span style="color: #008080;">_finddatai</span><span style="color: #000000;">64</span><span style="color: #008080;">_t</span><span style="color: #000000;"> data;
    string fname </span><span style="color: #000000;">=</span><span style="color: #000000;"> path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\*.*</span><span style="color: #800000;">"</span><span style="color: #000000;">;
    long h </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #008080;">_findfirsti</span><span style="color: #800080;">64</span><span style="color: #000000;">(fname.c_str(),&amp;data);
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(h </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
    {
        FILELIST thisList;
        theList.push_back(thisList);
        list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator it </span><span style="color: #000000;">=</span><span style="color: #000000;"> theList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">();
        it</span><span style="color: #008000;">--</span><span style="color: #008000;">;</span><span style="color: #008000;">
</span><span style="color: #000000;">
        (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).path </span><span style="color: #000000;">=</span><span style="color: #000000;"> path;
        </span><span style="color: #0000FF;">do</span><span style="color: #000000;"> {
            </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( (data.attrib &amp; </span><span style="color: #008080;">_A_SUBDIR</span><span style="color: #000000;">) )
            {
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> make sure we skip </span><span style="color: #800000;">"</span><span style="color: #800000;">.</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">..</span><span style="color: #800000;">"</span><span style="color: #000000;">.  Have to use strcmp here because
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> some file names can start with a dot, so just testing </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> the
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> first dot is </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> suffient.
                </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( strcmp(data.name,</span><span style="color: #800000;">"</span><span style="color: #800000;">.</span><span style="color: #800000;">"</span><span style="color: #000000;">) !</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> &amp;&amp;strcmp(data.name,</span><span style="color: #800000;">"</span><span style="color: #800000;">..</span><span style="color: #800000;">"</span><span style="color: #000000;">) !</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
                {
                    </span><span style="color: #000000;">//</span><span style="color: #000000;"> We found a sub</span><span style="color: #000000;">-</span><span style="color: #000000;">directory, so get the files </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> it too
                    fname </span><span style="color: #000000;">=</span><span style="color: #000000;"> path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> data.name;
                    </span><span style="color: #000000;">//</span><span style="color: #000000;"> recurrsion here!
                    TransverseDirectory(fname,theList);
                }

            }
            </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
            {
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> this is just a normal filename.  So just add it to our vector
                (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.push_back(data.name);

            }
        }</span><span style="color: #0000FF;">while</span><span style="color: #000000;">( </span><span style="color: #008080;">_findnexti</span><span style="color: #800080;">64</span><span style="color: #000000;">(h,&amp;data) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">);
        </span><span style="color: #008080;">_findclose</span><span style="color: #000000;">(h);

    }
}

int main( int argc, char </span><span style="color: #000000;">**</span><span style="color: #000000;">argv )
{
    list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> MyList;
    string path;
    ClientUser ui;
    ClientApi client;
    StrBuf msg;
    Error e;

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(argc </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> </span><span style="color: #800080;">4</span><span style="color: #000000;">)
    {
        fprintf( stderr , </span><span style="color: #800000;">"</span><span style="color: #800000;">P4 Transverse Add: Arguments Error!\n</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }

    client.SetPort(argv[</span><span style="color: #800080;">1</span><span style="color: #000000;">]);
    client.SetClient(argv[</span><span style="color: #800080;">2</span><span style="color: #000000;">]);
    client.SetTrans(CharSetApi::UTF_8 , CharSetApi::UTF_8 , 
        CharSetApi::UTF_8,
        CharSetApi::UTF_8);

    TransverseDirectory(argv[</span><span style="color: #800080;">3</span><span style="color: #000000;">],MyList);

    </span><span style="color: #000000;">//</span><span style="color: #000000;"> Connect to server
    client.Init( &amp;e );

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( e.Test() )
    {
        e.Fmt( &amp;msg );
        fprintf( stderr, </span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, msg.Text() );
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }

    list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator it;
    </span><span style="color: #0000FF;">for</span><span style="color: #000000;">(it </span><span style="color: #000000;">=</span><span style="color: #000000;"> MyList.begin(); it !</span><span style="color: #000000;">=</span><span style="color: #000000;"> MyList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">(); it</span><span style="color: #000000;">++</span><span style="color: #000000;">)
    {
        vector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator its;
        </span><span style="color: #0000FF;">for</span><span style="color: #000000;">(its </span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.begin(); its !</span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">(); its</span><span style="color: #000000;">++</span><span style="color: #000000;">)
        {
            path </span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">its);
            char</span><span style="color: #000000;">*</span><span style="color: #000000;"> pText </span><span style="color: #000000;">=</span><span style="color: #000000;"> ANSIToUTF8(path.c_str());
            client.SetArgv( </span><span style="color: #800080;">1</span><span style="color: #000000;"> , &amp;pText);
            client.Run( </span><span style="color: #800000;">"</span><span style="color: #800000;">add</span><span style="color: #800000;">"</span><span style="color: #000000;"> , &amp;ui );
        }
    }

    </span><span style="color: #000000;">//</span><span style="color: #000000;"> Close connection
    client.Final( &amp;e );

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( e.Test() )
    {
        e.Fmt( &amp;msg );
        fprintf( stderr, </span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, msg.Text() );
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }
    
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 此方法省去了创建p4进程的开销，任务执行效率会提高不少，而且也不会出现执行结果不稳定的问题。&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>附一：SDK下载地址</p>
<p><a title="ftp://ftp.perforce.com/perforce/" href="ftp://ftp.perforce.com/perforce/">ftp://ftp.perforce.com/perforce/</a></p>
<p>附二：附上ANSI转UTF-8代码</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:de1a1357-3f18-424a-bec7-b29768d70f5f" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">
wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> ANSIToUnicode( const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str )
{
    int    textlen ;
    wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> MultiByteToWideChar( CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL,</span><span style="color: #800080;">0</span><span style="color: #000000;"> );  
    result </span><span style="color: #000000;">=</span><span style="color: #000000;"> (wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    memset(result,</span><span style="color: #800080;">0</span><span style="color: #000000;">,(textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    MultiByteToWideChar(CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">,str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,(LPWSTR)result,textlen );  
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">    result;  
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> UnicodeToANSI( const wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">str )
{
    char </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    int textlen;
    </span><span style="color: #000000;">//</span><span style="color: #000000;"> wide char to multi char
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> WideCharToMultiByte( CP_ACP,    </span><span style="color: #800080;">0</span><span style="color: #000000;">,    str,    </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL, </span><span style="color: #800080;">0</span><span style="color: #000000;">, NULL, NULL );
    result </span><span style="color: #000000;">=</span><span style="color: #000000;">(char </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(char));
    memset( result, </span><span style="color: #800080;">0</span><span style="color: #000000;">, sizeof(char) </span><span style="color: #000000;">*</span><span style="color: #000000;"> ( textlen </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> ) );
    WideCharToMultiByte( CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str, </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, result, textlen, NULL, NULL );
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> result;
}

wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> UTF8ToUnicode( const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str )
{
    int    textlen ;
    wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> MultiByteToWideChar( CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL,</span><span style="color: #800080;">0</span><span style="color: #000000;"> );  
    result </span><span style="color: #000000;">=</span><span style="color: #000000;"> (wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    memset(result,</span><span style="color: #800080;">0</span><span style="color: #000000;">,(textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    MultiByteToWideChar(CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">,str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,(LPWSTR)result,textlen );  
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">    result;  
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> UnicodeToUTF8( const wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">str )
{
    char </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    int textlen;
    </span><span style="color: #000000;">//</span><span style="color: #000000;"> wide char to multi char
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> WideCharToMultiByte( CP_UTF8,    </span><span style="color: #800080;">0</span><span style="color: #000000;">,    str,    </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL, </span><span style="color: #800080;">0</span><span style="color: #000000;">, NULL, NULL );
    result </span><span style="color: #000000;">=</span><span style="color: #000000;">(char </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(char));
    memset(result, </span><span style="color: #800080;">0</span><span style="color: #000000;">, sizeof(char) </span><span style="color: #000000;">*</span><span style="color: #000000;"> ( textlen </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> ) );
    WideCharToMultiByte( CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str, </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, result, textlen, NULL, NULL );
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> result;
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> ANSIToUTF8(const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str)
{
    wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> pUnicodeBuff </span><span style="color: #000000;">=</span><span style="color: #000000;"> ANSIToUnicode(str);
    char</span><span style="color: #000000;">*</span><span style="color: #000000;"> pUtf8Buff </span><span style="color: #000000;">=</span><span style="color: #000000;"> UnicodeToUTF8(pUnicodeBuff);
    free(pUnicodeBuff);

    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> pUtf8Buff;
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div><img src ="http://www.cppblog.com/heath/aggbug/133692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-11-15 17:58 <a href="http://www.cppblog.com/heath/archive/2010/11/15/133692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CruiseControl.NET for CI in Game development</title><link>http://www.cppblog.com/heath/archive/2010/08/09/122834.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 09 Aug 2010 12:22:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/08/09/122834.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/122834.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/08/09/122834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/122834.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/122834.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 有个项目使用了CruiseControl.NET（以下简称CC.NET）作为持续集成工具，周末抽空研究了一下，发现这款由<b>ThoughtWorks</b>贡献的开源工具功能非常强大，主要体现在下面三个方面：</p> <p>1）灵活、高可配置性，如：多重组合条件触发、多任务队列策略；  <p>2）兼容目前几乎所有的流行SCM工具，使得多种异构系统能够由CruiseControl.NET统一监控和管理；  <p>3）完善的使用文档，使上手和维护变得容易；  <p>&nbsp;&nbsp;&nbsp; 而该项目引以自豪的代码check in触发构建的功能通过CC.NET也很容易实现。之前使用过Hudson，该系统采用主从式架构，使用者通过网页让Master控制Slave动作，由于Master由别的部门管理，出问题后需要联系相关人解决，会有一定的处理延迟，而且安装在构建机上的Slave服务经常崩溃。而CC.NET直接安装在构建机上，配置IIS后可通过网页直接访问，操作维护都较前者容易。由于之前的构建脚本是用VisualBuild实现的，所以不可能再花时间用CC.NET再写一遍。而通过实验得知，其实CC.NET能够以ExecutableTask的形式很好地与VisualBuild集成，目前每小时定时构建、NightBuild和构建成功后触发的自动测试都已经放到了CC.NET上了。  <p>&nbsp;&nbsp;&nbsp; ccnet.config Example: </p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:50b99a40-bc5a-4f79-b1ff-e2e4471bf333" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">cruisecontrol </span><span style="color: #FF0000;">xmlns:cb</span><span style="color: #0000FF;">="urn:ccnet.config.builder"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">queue </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="Q1"</span><span style="color: #FF0000;"> duplicates</span><span style="color: #0000FF;">="ApplyForceBuildsReAdd"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">queue </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> duplicates</span><span style="color: #0000FF;">="ApplyForceBuildsReAdd"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="AgileBuild"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q1"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="1"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoBuild</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">filterTrigger </span><span style="color: #FF0000;">startTime</span><span style="color: #0000FF;">="18:00"</span><span style="color: #FF0000;"> endTime</span><span style="color: #0000FF;">="10:00"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">trigger </span><span style="color: #FF0000;">type</span><span style="color: #0000FF;">="intervalTrigger"</span><span style="color: #FF0000;"> name</span><span style="color: #0000FF;">="Continuous"</span><span style="color: #FF0000;"> seconds</span><span style="color: #0000FF;">="1800"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Monday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Tuesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Wednesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Thursday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Friday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">filterTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">E:\GAMEDev\AgileBuilder.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">3000</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="NightBuild"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="1"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoBuild</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">scheduleTrigger </span><span style="color: #FF0000;">time</span><span style="color: #0000FF;">="23:00"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> name</span><span style="color: #0000FF;">="Scheduled"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Monday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Tuesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Wednesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Thursday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Friday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">scheduleTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">      
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">  
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">"BUILD_OPTION=clientworldeffect" "PACK_TYPE=RAR" E:\GAMEDev\NightBuilder.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">0</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="NightAutoTest"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="2"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoTest</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">projectTrigger </span><span style="color: #FF0000;">serverUri</span><span style="color: #0000FF;">="tcp://heath-builder:21234/CruiseManager.rem"</span><span style="color: #FF0000;"> project</span><span style="color: #0000FF;">="NightBuild"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggerStatus</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Success</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggerStatus</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">innerTrigger </span><span style="color: #FF0000;">type</span><span style="color: #0000FF;">="intervalTrigger"</span><span style="color: #FF0000;"> seconds</span><span style="color: #0000FF;">="60"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">projectTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">E:\GAMEDev\AutoTest.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">0</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">  
</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">cruisecontrol</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>References 
<p>[1] <a href="http://cruisecontrol.sourceforge.net/">http://cruisecontrol.sourceforge.net/</a> 
<p>[2] <a href="http://www.kinook.com/VisBuildPro/">http://www.kinook.com/VisBuildPro/</a></p><img src ="http://www.cppblog.com/heath/aggbug/122834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-08-09 20:22 <a href="http://www.cppblog.com/heath/archive/2010/08/09/122834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写着玩(2)&amp;mdash;&amp;mdash;WoW角色资源读取</title><link>http://www.cppblog.com/heath/archive/2010/04/24/113423.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 24 Apr 2010 04:31:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/04/24/113423.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/113423.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/04/24/113423.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/113423.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/113423.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/04/24/113423.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/113423.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-04-24 12:31 <a href="http://www.cppblog.com/heath/archive/2010/04/24/113423.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Slerp or Lerp</title><link>http://www.cppblog.com/heath/archive/2010/03/14/109689.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 14 Mar 2010 09:54:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/03/14/109689.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/109689.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/03/14/109689.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/109689.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/109689.html</trackback:ping><description><![CDATA[<p><a href="http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html" target="_blank">Understanding Slerp, Then Not Using It</a>对Slerp的起源及性能做了详细的讨论。Slerp并不局限于维数，因而不要认为只对Quaternion有效。作者认为Slerp会带来效率问题，即便经过优化也并不能达到理想的速度(与lerp做比较而言)，而且优化往往会降低代码的易读性。文章给出了一个结论：如果插值过程中的常量速度不是必须的，那么最好使用线性的lerp。</p> <p>Jason Gregory在他的引擎架构设计一书中也用“To SLERP or Not to SLERP (That’s Still the Question)”一小节介绍了开发者对Slerp的争论，并介绍他在Naughty Dog的同事针对PS3的优化方法，使Slerp可达到20周期/关节，相比Lerp的16.25周期/关节已经很不错了。</p> <p>之前确实没对Slerp的效率问题作过多的考虑，引擎的Slerp直接使用的是D3DXQuaternionSlerp，MS应该对其做了优化，效率怎么样要测一下才知道了。</p><img src ="http://www.cppblog.com/heath/aggbug/109689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-03-14 17:54 <a href="http://www.cppblog.com/heath/archive/2010/03/14/109689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Script in Game</title><link>http://www.cppblog.com/heath/archive/2010/01/29/106753.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Fri, 29 Jan 2010 11:34:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/01/29/106753.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/106753.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/01/29/106753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/106753.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/106753.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/01/29/106753.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/106753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-01-29 19:34 <a href="http://www.cppblog.com/heath/archive/2010/01/29/106753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FMOD Event System&amp;mdash;&amp;mdash;事件树策略、加载、内存分配</title><link>http://www.cppblog.com/heath/archive/2010/01/18/105976.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 18 Jan 2010 15:40:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/01/18/105976.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/105976.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/01/18/105976.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/105976.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/105976.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/01/18/105976.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/105976.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-01-18 23:40 <a href="http://www.cppblog.com/heath/archive/2010/01/18/105976.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何利用VS的Output快速定位UnitTest Failed代码</title><link>http://www.cppblog.com/heath/archive/2009/06/30/88889.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 30 Jun 2009 06:08:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2009/06/30/88889.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/88889.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2009/06/30/88889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/88889.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/88889.html</trackback:ping><description><![CDATA[<p>很简单，在Project的Property Page设置Build Events中的Post-Build Event，最简洁的写法就是将Command Line设置为：$(TargetPath)。由于UnitTest++的输出格式遵照了VS的格式，所以双击错误提示行便可跳转到测试失败的代码行。</p>
<img src ="http://www.cppblog.com/heath/aggbug/88889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2009-06-30 14:08 <a href="http://www.cppblog.com/heath/archive/2009/06/30/88889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>战斗数值模拟器</title><link>http://www.cppblog.com/heath/archive/2009/06/24/88451.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Wed, 24 Jun 2009 12:25:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2009/06/24/88451.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/88451.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2009/06/24/88451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/88451.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/88451.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 花了一周时间为策划做了个考察战斗数值平衡的工具。做工具有个好处就是不用受限于别人的工作，自我发挥程度最大，开发效率也就高很多啦。主要设计思想如下图：<br>
<div align=center src_cetemp="/images/cppblog_com/heath/NA.png"><img height=248 alt="" src="http://www.cppblog.com/images/cppblog_com/heath/NA.png" width=727 border=0></div>
&nbsp;&nbsp;&nbsp;玩家属性和怪物属性根据EXCEL自动产生，可动态修改数值。其核心是逻辑脚本的设计，逻辑脚本建立在Lua之上，支持Lua所有的语法特性和函数库，变量支持直接使用属性名字（呵呵，有点吹了哈，其实就是玩文字替换游戏，加入了自己的一些语法）。第一版只支持单一PK，这当然不能模拟真实场景下的战斗情况，只是个基础，后续功能继续开发。。。<br>&nbsp;&nbsp;&nbsp; 实现脚本语法着色的时候，在CodeGuru上找到了一位同学写的SyntaxColorize，经过改造之后成功支持Lua，然由于中文的存在且没有使用Unicode，导致Release版下Paste和Load出现着色异常，以前对_T("XXX")和TCHAR不以为然，现在恐怕要重视起来啦。&nbsp;<br>&nbsp;&nbsp;&nbsp; 做Timer的时候，突然想到一种不用if-else的更简单实现：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CCombatTimer::Forward()<br><img id=Codehighlighter1_29_234_Open_Image onclick="this.style.display='none'; Codehighlighter1_29_234_Open_Text.style.display='none'; Codehighlighter1_29_234_Closed_Image.style.display='inline'; Codehighlighter1_29_234_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_29_234_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_234_Closed_Text.style.display='none'; Codehighlighter1_29_234_Open_Image.style.display='inline'; Codehighlighter1_29_234_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_29_234_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_29_234_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uMSec&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;m_uStep;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uSec&nbsp;&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;m_uMSec&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uMSec&nbsp;&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_uMSec&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uMin&nbsp;&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;m_uSec&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">60</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uSec&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_uSec&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">60</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uHour&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;m_uMin&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">60</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uMin&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_uMin&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">60</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_uHour&nbsp;&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_uHour&nbsp;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">24</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<br>
<div align=center src_cetemp="/images/cppblog_com/heath/NAResult.png"><img height=342 alt="" src="http://www.cppblog.com/images/cppblog_com/heath/NAResult.png" width=473 border=0></div>
<img src ="http://www.cppblog.com/heath/aggbug/88451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2009-06-24 20:25 <a href="http://www.cppblog.com/heath/archive/2009/06/24/88451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写在入职一年</title><link>http://www.cppblog.com/heath/archive/2009/06/24/88434.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Wed, 24 Jun 2009 08:24:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2009/06/24/88434.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/88434.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2009/06/24/88434.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/88434.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/88434.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 入职一年，有些感慨，成文。&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2009/06/24/88434.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/88434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2009-06-24 16:24 <a href="http://www.cppblog.com/heath/archive/2009/06/24/88434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>