﻿<?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>BlogJava-风依归林鹤 云憩隐山居-随笔分类-脚本语言</title><link>http://www.blogjava.net/tianlinux/category/22963.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 01 Jun 2007 19:00:44 GMT</lastBuildDate><pubDate>Fri, 01 Jun 2007 19:00:44 GMT</pubDate><ttl>60</ttl><item><title>游戏引擎脚本系统（二）</title><link>http://www.blogjava.net/tianlinux/archive/2007/06/01/121434.html</link><dc:creator>tianlinux</dc:creator><author>tianlinux</author><pubDate>Fri, 01 Jun 2007 14:35:00 GMT</pubDate><guid>http://www.blogjava.net/tianlinux/archive/2007/06/01/121434.html</guid><wfw:comment>http://www.blogjava.net/tianlinux/comments/121434.html</wfw:comment><comments>http://www.blogjava.net/tianlinux/archive/2007/06/01/121434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tianlinux/comments/commentRss/121434.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tianlinux/services/trackbacks/121434.html</trackback:ping><description><![CDATA[<p goog_ds_charIndex="1">这两天，有关游戏引擎脚本系统的预研还在继续。在google上找了一些资料来学习，目前网络上这部分的资料是比较少的，主要还是在gamedev上有一些相关的主题。泡了两天的鸟文论坛，做了一打的摘录。现在整理一下思绪，感觉脚本系统的轮廓已经比较清晰了，但还有很多细节需要去了解，后续会对这些细节再慢慢研究道来。</p>
<p goog_ds_charIndex="155">&nbsp;</p>
<p goog_ds_charIndex="156">脚本的基本特性</p>
<p goog_ds_charIndex="165">1、从语法的角度来说需要支持到顺序、条件、循环，并且最好语法接近某种成熟语言（比如C），这样有利于学习＆使用；</p>
<p goog_ds_charIndex="222">2、性能，性能，性能。要在实时的游戏里面发挥作用，性能无异是贯穿始终的话题。</p>
<p goog_ds_charIndex="262">&nbsp;</p>
<p goog_ds_charIndex="263">语法功能解决方案</p>
<p goog_ds_charIndex="273">1、可以选择一门成熟语言作为借鉴；</p>
<p goog_ds_charIndex="292">2、删掉不需要的Keyword，裁剪语言元素。特别对于C语言，完全去掉有关函数声明等部分可以大大降低parse&amp;excute的复杂性。</p>
<p goog_ds_charIndex="361">&nbsp;</p>
<p goog_ds_charIndex="362">脚本库</p>
<p goog_ds_charIndex="367">1、脚本语言的函数库比脚本语言的语法更加重要，这个说法的出发点仍然是性能。在上一篇文章中，我有提到&#8220;冗余&#8221;的概念，就是这句话很好的体现。尽量将复杂的函数功能封装在游戏引擎本身，而不要在脚本中编写这些函数，甚至可以在脚本中不提供用户自定义函数的功能。</p>
<p goog_ds_charIndex="493">2、提供给用户（脚本编写者）完善的库函数集，从环境配置命令到信息查询等等。用户用这些函数来控制游戏环境，脚本语法只是提供分支＆循环控制。&nbsp;</p>
<p goog_ds_charIndex="564">&nbsp;</p>
<p goog_ds_charIndex="565">事件响应</p>
<p goog_ds_charIndex="571">1、上篇提到&#8220;事件&#8221;(event)指的是所有外设输入的统称，这种说法是不全面的。除了外设输入，事件还可以由游戏引擎内部来触发，比如timer事件，这里做一个小小的更正。</p>
<p goog_ds_charIndex="657">2、事件包含一些参数，参数的内容是&#8220;哪些Object要响应&#8221;＆&#8220;事件类型&#8221;。</p>
<p goog_ds_charIndex="697">3、一个脚本可以调用其他脚本，实现脚本之间的通信。</p>
<p goog_ds_charIndex="724">4、事件，可作为脚本系统＆游戏引擎的连接，也就是说，游戏引擎只有在处理事件的时候才会调用脚本系统，而脚本系统的唯一任务，就是响应事件。</p>
<p goog_ds_charIndex="793">5、再次强调一下，事件不是只能有游戏引擎内部的object来触发，还有timer、startUp、sceneEnd等等。</p>
<p goog_ds_charIndex="855">&nbsp;</p>
<p goog_ds_charIndex="856">脚本运行模型</p>
<p goog_ds_charIndex="864">1、每个脚本都可以&#8220;挂&#8221;到任何数量的object上去；</p>
<p goog_ds_charIndex="893">2、每个脚本都可以看作是独立的虚拟机，拥有自己独立的变量、堆栈＆运行点(execution pointer)，这一点我自己有保留的想法，出于性能原因，可能独立虚拟机的概念难以实施，需要进一步寻找变通的方法。</p>
<p goog_ds_charIndex="998">&nbsp;</p>
<p goog_ds_charIndex="999">访问控制</p>
<p goog_ds_charIndex="1005">1、上篇提到脚本需要能读取＆改变游戏引擎内部object的属性，这里需要注意一个问题：让脚本直接访问object的属性是很危险的事情，出于defensive coding的考虑，个人认为不应该让脚本直接地来访问内部数据，而应该提供库函数，通过库函数来对内部数据进行访问，这样做的好处是：将边界检查等等安全性工作加入了进来，并且让脚本编写者在编写脚本的时候不用对安全性进行考虑；坏处是：肯定效率是有所降低的。（或者还有更好的办法？想想。。。）</p>
<p goog_ds_charIndex="1227">&nbsp;</p>
<p goog_ds_charIndex="1228">库函数</p>
<p goog_ds_charIndex="1233">1、库函数的实质是C/C++（引擎编写语言）的函数指针，对于脚本系统来说它们是可见的全局symbols。这里引入两个小话题：一是在引擎初始化的时候，需要注意建立这些函数的入口地址表，让引擎在需要调用的时候有表可查；二是，java呢？有没有类似函数指针的东西？（这里属于实现阶段的问题，我只是提出，没有去研究）</p>
<p goog_ds_charIndex="1389">2、脚本运行的时候，如果遇到调用库函数，则跳转到native C/C++代码去。这里存在运行环境切换的问题，从脚本语言的堆栈里弹出参数，传给native C/C++函数来执行，执行结束以后，返回结果压入脚本语言的堆栈中。如果把游戏引擎看做虚拟机，那么脚本系统就是嵌套在这个虚拟机里面的虚拟机，^_^，拗口哦，不知道您明白了没有？</p>
<p goog_ds_charIndex="1555">====================================================================================================&nbsp;</p>
<p goog_ds_charIndex="1658">以上讨论的，是运行与游戏引擎部分的脚本系统。以下的，是有关脚本本身的一些讨论，这个应该归属于游戏制作工具的一部分。</p>
<p goog_ds_charIndex="1717">====================================================================================================</p>
<p goog_ds_charIndex="1819">编译</p>
<p goog_ds_charIndex="1823">1、当然，这个步骤叫&#8220;解释&#8221;，与C语言一类编译式语言有所区分的话更加准确。但由于在做法上跟C是类似的，所以也可以叫&#8220;编译&#8221;。</p>
<p goog_ds_charIndex="1887">2、两个阶段：一是把脚本源代码拆成语言元素，token，不知道这个用哪个中文表达好，编译原理学了都忘了；二是把所有token组织起来，组成基本命令序列。</p>
<p goog_ds_charIndex="1965">3、什么&#8220;基本命令序列&#8221;？刚才不是说把脚本看过虚拟机吗？这个&#8220;基本命令&#8221;就相当于这个虚拟机CPU的机器指令或汇编指令。也就是对于这个虚拟机来说的可执行代码。</p>
<p goog_ds_charIndex="2045">&nbsp;</p>
<p goog_ds_charIndex="2046">&#8220;汇编指令&#8221;</p>
<p goog_ds_charIndex="2054">1、为了简单，就把脚本这个虚拟机设计成单堆栈的吧。</p>
<p goog_ds_charIndex="2081">2、基本的命令包括：push，pop，go，stop，callfunc，add，asign等等。</p>
<p goog_ds_charIndex="2131">&nbsp;</p>
<p goog_ds_charIndex="2132">举个小例子吧：比如写了如下的脚本（语法上近C）</p>
<p goog_ds_charIndex="2157">a = 1 + 2;</p>
<p goog_ds_charIndex="2169">通过编译，变化成如下的&#8220;可执行序列&#8221;：</p>
<p goog_ds_charIndex="2190">push 1</p>
<p goog_ds_charIndex="2198">push 2</p>
<p goog_ds_charIndex="2206">pop&nbsp;&nbsp;&nbsp;// store 1 </p>
<p goog_ds_charIndex="2225">pop&nbsp;&nbsp;&nbsp;// store 2</p>
<p goog_ds_charIndex="2243">add&nbsp;&nbsp;&nbsp;// store result</p>
<p goog_ds_charIndex="2266">push 3&nbsp;&nbsp;&nbsp;// push result</p>
<p goog_ds_charIndex="2291">pop&nbsp;&nbsp;&nbsp;// store 3</p>
<p goog_ds_charIndex="2309">pop&nbsp;&nbsp;&nbsp;// var name a</p>
<p goog_ds_charIndex="2330">asign&nbsp;&nbsp;&nbsp;// a = 3</p>
<p goog_ds_charIndex="2348">这里只是示意，可能与实际实现有出入。</p>
<p goog_ds_charIndex="2368">&nbsp;</p>
<p goog_ds_charIndex="2369">这篇略显枯燥了，聊点轻松的。一直在强调脚本语言的性能问题，来看看 <a title=各种语言性能比较 href="http://shootout.alioth.debian.org/gp4/index.php" target=_blank goog_ds_charIndex="2403"><u><font color=#0000ff>各种语言性能比较</font></u></a> 吧。LUA好像在脚本语言里面排名靠前呵，我正好也下载了它的源码，并在VC上编译好了。在Python＆LUA之间犹豫了一下，还是选择LUA吧，比较小，简单，Python目前已经做得很复杂了。再说偶的脚本系统里面目前不需要提供自定义函数机制，也不需要OO滴，看看几个月后能不能作出自己的脚本语言来？到时候再跟Python等等一较高低！:)<br><br>好戏在后头哦，下期开始实际以LUA为例子研究脚本系统了。。</p>
<img src ="http://www.blogjava.net/tianlinux/aggbug/121434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tianlinux/" target="_blank">tianlinux</a> 2007-06-01 22:35 <a href="http://www.blogjava.net/tianlinux/archive/2007/06/01/121434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎脚本系统（一）</title><link>http://www.blogjava.net/tianlinux/archive/2007/05/30/121006.html</link><dc:creator>tianlinux</dc:creator><author>tianlinux</author><pubDate>Wed, 30 May 2007 14:07:00 GMT</pubDate><guid>http://www.blogjava.net/tianlinux/archive/2007/05/30/121006.html</guid><wfw:comment>http://www.blogjava.net/tianlinux/comments/121006.html</wfw:comment><comments>http://www.blogjava.net/tianlinux/archive/2007/05/30/121006.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/tianlinux/comments/commentRss/121006.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tianlinux/services/trackbacks/121006.html</trackback:ping><description><![CDATA[<p>今天开始进行新项目的预研，有关游戏引擎的脚本系统。之前自己对Python有所了解，但也仅仅限于应用层，如今要把一个脚本系统加入到游戏引擎里面，一时还有点不知道如何下手。赶紧上网查资料，逛了大半天的gamedev，现在总算有点眉目了。<br>首先要明确的是脚本系统在游戏引擎中扮演什么样的角色。 </p>
<p><strong>脚本系统的必要性</strong></p>
<p>游戏作为上层应用程序，是在游戏引擎的基础上运行的，现在游戏的发展趋势来看，游戏者（gamer）对游戏的可自我配置性有非常高的需求，特别是在游戏运行时的自我配置，已经不能通过简单的传参数来完成这种配置。所以，整个游戏的架构有分成两大块的发展趋势。一块是kernel，另一块是configuration。Kernel是游戏的基础类＆Object的集合，而configuration是针对特定的上层应用程序（游戏本身），对kernel的元素进行组织＆配置。脚本系统无疑将是configuration的重要组成部分。</p>
<p><strong>游戏引擎需要为脚本系统提供的接口</strong></p>
<p>我们把游戏中的物体（实例）称为object，把可以作用于object的函数叫action<br>1、保存全局变量＆局部变量<br>2、得到object(s)的引用<br>3、得到object(s)的属性，并调用object的action<br>4、提供timer进行周期性触发action&nbsp;<br>以上4点并不全面，但是却是最最基本需要支持的部分。如果需要更深入，应该还要提供对静态场景的配置、设置场景结束条件以及完善的Debug机制等等。&nbsp;</p>
<p><strong>游戏引擎不应该为脚本系统提供的接口</strong></p>
<p>1、画图&amp;播放声音等算法<br>2、内存管理<br>以上2点也并不全面，因为目前的项目没有网络方面的需求，所以没有考虑安全等因素进来。<br><strong>杂七杂八</strong></p>
<p>外设响应</p>
<p>我们把所有的gamer的输入都归纳为外设输入。那么在游戏引擎里面，对外设的响应应该是游戏实时反应能力的直接体现，在去年从事的游戏引擎项目中，采用了类似于windows消息队列的方式，对某种特定外设输入（比如：游戏手柄左键按下），挂上一个写死的函数。在脚本系统引入以后，应该不再挂上一个编译式语言编写的响应函数，而是调用脚本解释器来运行挂在这个外设上的脚本。<strong>所有外设都采用脚本来响应</strong>，这一思想是保证游戏可用户自我配置的关键之一。</p>
<p>冗余</p>
<p>脚本的性能总是令人头疼的。所以在引擎提供给脚本的接口当中（全面所述4点当然在内），不要害怕冗余的情况出现，而是要针对游戏开发者的需求，适当的增加引擎输出的功能，让游戏开发者在使用脚本的时候，能用将脚本写得尽量的简单。举例来讲：比如需要在某个时刻获得离主角最近的怪兽，如果只使用前面所提的4种接口，需要在脚本里面枚举出所有的怪兽，然后一一与主角的坐标进行距离计算，然后才能得到最近的一个怪兽。这是十分低效的。如果这一动作需要频繁发生，那么势必影响游戏的整体运行效率。解决办法就是在游戏引擎里面提供一个类似功能的API，由游戏引擎本身的开发语言（一般是编译式语言）来完成这项功能，而游戏开发者只需要在脚本里面调用这个API即可完成这项运算。如此做法在效率上应该比前面的做法要高出许多。</p>
<img src ="http://www.blogjava.net/tianlinux/aggbug/121006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tianlinux/" target="_blank">tianlinux</a> 2007-05-30 22:07 <a href="http://www.blogjava.net/tianlinux/archive/2007/05/30/121006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>