闪电战1脚本编写基础教程-[闪电战论坛].doc_第1页
闪电战1脚本编写基础教程-[闪电战论坛].doc_第2页
闪电战1脚本编写基础教程-[闪电战论坛].doc_第3页
闪电战1脚本编写基础教程-[闪电战论坛].doc_第4页
闪电战1脚本编写基础教程-[闪电战论坛].doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

闪电战1 脚本编写基础教程 序 言 闪电战1发行之时,地图编辑器与资源编辑器作为“赠品”与游戏一同打包。然而编辑器的帮助文件内容有限,而且完全没有介绍如何通过编码(脚本)控制自定义任务内的事件。全靠累积玩家们在各个论坛上分享的发现,我们才能找出如何发挥编辑器的最大效能。单从脚本语言LUA方面来看,同样是依靠准确解码、反复试错以及广泛开放的发现共享才得以完善。数量众多的个人玩家以“破解”Lua为己任来制作自定义地图,为跟随者开创了一条更为平坦的道路。直到这些先驱人物在“闪”界隐退,每一位玩过或尝试过制作自定义地图的玩家都应该感谢那些慷慨分享心得的编码破译者大量的辛勤劳作。 破译编码过程中产生的重要贡献之一是Calvin的Blitzkrieg Guideto Programming Lua Functions。它提供了一份闪电战1中使用脚本函数的列表以及如何运用这些函数的指导。它对于编写闪电战脚本的人是十分必要的。这个指南像是一本LUA词典,但它没有提供如何将这些术语组合成可用脚本的浅易说明。(Calvin提供了一个例子,但是这个例子不能被称为“简介”所以脚本编写的新手最好忽略它。)Calvin的Blitzkrieg Guideto Programming Lua Functions可以在Blitzkrieg Portal下载。 Wespex是第一位制作完整编辑地图指南的人,为此他编辑了地图,编写了脚本,并且打包了可以与其他玩家分享的自定义游戏。这个指南(再版很多次并最终与Calvin的指南合并)是任何希望制作自定义地图玩家的入门教程。在发布这个指南之后,Wespex在BKP论坛就脚本编写提供了非常广泛的问题答疑。这些指南和答疑最有价值的特征是在脚本范例中提供了全面的注释,不仅提供了制成的脚本,还解释了脚本运作的原理。如果说现在绝大多数脚本编写者是靠这个指南启蒙应该是不失公允的。 这个基础教程的编写是为了响应BKP论坛上的一些评论以及解决很多地图编辑者在开始尝试脚本编写时所面临的困难。本教程阐述Lua的基本原理并展示如何为自定义游戏的某个基本要点编写脚本。我将尝试揭开某些技术术语的神秘面纱。 考虑要点 像每一个刚开始编写Lua的人那样,我非常熟悉入门的巨大障碍以及脚本无效时的那份挫败感。无论如何,有些事情应该记在我们的脑子里: Lua是一种语言,你必须学会单个词句的意思以及如何运用他们来“涂鸦”。即使你聪明绝顶, 这也并不意味你可以不用认真学习词汇和语法就来编写Lua脚本。和人类语言不同,即使你在Lua语句中犯了一个微不足道的错误,它也将彻底无法被程序理解。开始编写Lua时的大多数挫败感是来源于那些“一点不起作用”的脚本,“这几乎不可避免的是你的错误!”自然的反应一般是说:“程序不在运转”或者“我的电脑出毛病了”。但有99.9%的可能是你犯下了一个拼写或语法错误。制作自己的地图并看到自编脚本运转是非常有趣的;但让脚本运转起来并不总是有趣的。即使BKP论坛上最优秀的脚本编写者也承认在调试自己的作品时仍然遇到大量挫折。并非每个人都有足够耐心只为了一个错位的字母、一个遗漏的括号或一个多余的分号来逐行检查脚本。如果想要编写脚本你必须接受这个事实,没有任何人能替你简化它。一旦你已经了解Lua的基础,最佳学习方法是打开一张你喜欢的地图并且逐行研究它的脚本(在手边准备一份Calvin的指南。译者注:或liukun1982翻译的script帮助文档)以弄清具体的原理。 如果你想测试一些新脚本或从其他编写者那里“借”来的脚本,不要在你乐于为傲的26X26地图上进行测试。制作一张4X4的测试地图,放上最少的单位,仅测试脚本中对你来说是新鲜内容的代码块。如果脚本不运行,你可以很快发现问题而不需要检查一大堆其他不相干的东西来判断是否存在冲突。这是本教程所采用的方针。如果你确实遇到了困难(在浏览了BKP写的抓虫须知(本书第33页)与这些教程以后),你可以在论坛中进行搜索,大多数问题已被讨论过了。如果你仍然无法找到答案,你可以在地图编辑问答专栏发布求助贴。如果你的问题明确具体(最好复制粘贴一些你的脚本),那些脚本编写的大侠们将会给我们这些小菜鸟提供迅速而有益的答复。 基础教程使用 以下每一节教程都配套一份与教程同名的地图(.bzm)与脚本(.lua)文件。所有.bzm文件和.lua文件应被复制粘贴到闪电战的DataMaps文件夹。这也是你用来保存自定义地图与脚本的路径。为了学习每一节教程,你可以用地图编辑器打开地图,用SciTE编辑器打开脚本。当你阅读完教程并看完地图和脚本内容以后,你可以按下地图编辑器工具栏右上角的RunBlitzkrieg按钮看看脚本在游戏中是如何执行的。 前五节课程的每张地图都是建立在前一张地图的基础之上,地图和脚本一步步升级。最后两节课程是独立的,涵盖了BKP论坛中经常提到的问题。本教程推荐你下载BlitzkriegSciTEEditor。它非常有效,是免费软件,体积不大,没什么理由不用。它不能替你编写脚本,当脚本无法运行时它也不能替你找出错误。但在编写与检查脚本时它对你很有帮助,所以还是下载吧!Blitzkrieg SciTE Editor (译者注:由于这个编辑器在处理中文时默认以半角格式处理,所以退格删除中文时只删除半个,从而出现乱码。建议中文的地图编写者最好加装汉化补丁,从而能完美支持在脚本中输入中文。) 注:使用SciTEEditor给文件命名时你必须使用一个.lua后缀否则它会被保存为.xml格式。 基本原理 脚本是一个lua文件。在地图编辑器上有一个“扳手加字母A”的按键,点击这个按键(译者注:设置脚本文件名)输入脚本名称,来把地图和相应的lua脚本文件联系起来。 脚本包含一系列的指令,叫做functions(函数),当地图运行时,这些函数使事件发生。函数可以很简单,可以只是(指令电脑)在特定时间完成一个事件, 或是更复杂的,测试某个条件,并根据结果做出不同的事情。 注意: 附录A给出了一个闪电战特有函数列表 为了使函数和地图配合,地图上的单位,步兵班,建筑等必须指定一个脚本代码(ScriptID),在地图编辑器中,在左边选择Objects界面,双击单位调出“单位属性窗口”,然后双击“ScriptID”文本框并输入一个代码(ID),然后关闭属性窗口。 提示:做一个笔记记录哪个代码是哪个单位。有的地图制作者常常在脚本的开头写下他们的编码方式。 提示:一个很有用的方法,是给予玩家单位和敌方单位以不同字头的代码(如100s和200s) 很多函数要用到脚本区域(ScriptAreas 也译作脚本范围)。用地图编辑器左边的MapTools按键来定义这些脚本区域: 选择“脚本范围工具”,并且拖动鼠标在在地图上定义一个(方形或圆形)区域,然后输入这个区域的名称。编写脚本时必须准确的使用这个“脚本区域名称”, 包括大小写和空格等都要一样。 提示:给你的脚本区域一个独特而有明确含义的名字,这样你不会在脚本中混淆。(Farm和Town, 而不要用Area1,Area2) Lua 语言 Lua的语法是简单而固定的,必须严格遵守。任何拼写,间隔(空格),或标点的错误,都会导致脚本不运行或不能正确执行函数的功能。多数的脚本问题都是拼写或语法错误。 下面的词语在Lua中有特殊的含义,被认为是保留字(keywords): and break do else elseif if end false for function in local nil not or repeat return then true until while 无论你认为这些词语在现实中是什么意思,在Lua语言中,他们有固定的用法,并且只能那样用。其中一些词语的用法在下面的教程中会详细解说。按照规则, 这些保留字要用小写。 这里也有一些闪电战的特定保留字,象“RunScript”,“LandReinforcement”,“Win” and“Loose” 等。这些必须正确书写-首字母大写和其它字母小写。Calvin的指南就像一部字典,可用来指导我们怎样正确书写这些词语。 提示:如果使用闪电战脚本编辑器(theBlitzkriegSciTEeditor),那么所有的保留字,如果你的拼写正确,会变成蓝色并且以浅蓝背景高亮显示。 脚本编写者所定义的事件(函数)的名称叫“names”。它们可以是任意数字和字母,但不能以数字开头。按照规则,我以大写字母开头为(函数)名称。举例来说, 在第一课我写的: function MoveCar() 在这里“function”是保留字,而“MoveCar”是名称 提示:如果使用闪电战脚本编辑器(theBlitzkriegSciTEeditor),那么(保留字是蓝色而)名称是黑色的。 当一个函数的名称确定以后,它就可以在后面被脚本调用。当它被再次使用时,必须放在双引号内作为字符串被调用。如我在第一课中写的:RunScript(“MoveCar”, 3000) 这里“RunScript”是闪电战专用保留字,“MoveCar”是字符串,代表我在脚本中定义的一个函数。一个绝对的要点是这个字符串要被正确的键入, 和之前的函数名完全一样,否则不会被脚本认可。由于这个原因,用复制粘贴函数名和字符串是最好的办法,可以防止键入错误。在使用双引号时,在引号和字符串的头以及引号和字符串的尾之间不许有任何空格。 提示:如果使用闪电战脚本编辑器(theBlitzkriegSciTEeditor),那么当引号的位置正确时,字符串显示为紫色文字。如果你看到紫色背景的高亮显示,说明双引号输入有错(少了一半)。注意,这个 脚本编辑器不会检查你键入的字符串正确与否函数和保留字是要用参数来限定的。要明白这个参数的作用,想象函数和保留字就像有人大声对你喊“做”,但这没有任何意义,直到你被告知做什么,什么时候做,做的频率多少,这些就是限定函数去做的参数。 在Lua中参数总是被放在一对括号内,如 RunScript(“MoveCar”, 3000) 保留字“RunScript”需要知道运行哪个函数,什么时候运行。这两个在括号内的参数, 被定义为运行字符串“MoveCar”以及值(value )为3000 (这个在后面的教程中解释). 提示:如果使用闪电战脚本编辑器(theBlitzkriegSciTEeditor),这个数值会显示为淡蓝色。当有超过一个的以逗号隔开的参数,来赋予这个字符串或值,很重要的一点, 如果这个逗号漏写了,脚本将不能运行。有些保留字或函数不用任何的参数定义,那就是说它们对于脚本是不解自明的,不需要用例如什么,哪里,何时,频率如何等来定义。没有参数的保留字或函数的括号是空的,但这对括号仍然必须保留。比如Suicide() 以及函数名后的括号。漏掉一个空括号是脚本不运行的一个常见原因。缩排是脚本编写者经常用到的(在编辑器中按Tab 键),但这不是必须的也不会对脚本有影响。当然它们非常有助于使语句有条理。我会在举例中用我自己的方法, 而脚本编写者有它们自己的方法。按照规则,脚本的每一行结尾要有一个分号“;”,(除了某些情形下如一个保留字将直接对下一行执行操作-这在下面的第三课会解说) 备注:有时候也会包括在脚本中,用于帮助脚本编写者明白或提示某些事情或者告诉其他人写的是什么。一条备注开始和结束于至少两条短横,如“-NOTE-”(译者注:只需要开头的两条短横;备注 可以是中文但短横等标点必须是英文标点)。备注不会被脚本读取,所以在行首和行尾(译者注:只需要在行首)键入两个短横可以使这一命令行丧失功能。这一点在测试脚本过程中非常有用。 提示:如果使用闪电战脚本编辑器(theBlitzkriegSciTEeditor),这个备注会显示为绿色。 第一节 编写一个函数并使它运行 这一课介绍怎样使一个单位从它的初始位置移动到定义的新位置 第一节的地图 打开地图,这里有一辆小轿车(ScriptID为 100)(双击单位可查看ID号) 和轿车将要到达的一栋建筑 Lesson1.luaScript 脚本 function MoveCar() Cmd(0, 100, 916, 1516); Suicide(); end; function Init() RunScript(MoveCar, 3000); end; 注意: 这个脚本以后缀为lua的文件保存,你可以复制粘贴这个脚本的语句到你自己写的脚本中。一定不要用微软的Word软件来编写脚本,因为Word允许插入不同内码的文字,而这会导致游戏运行过程中止(即忽然退出)。 解说 function MoveCar() 建立一个名叫“MoveCar”的函数,这个函数能被脚本调用。 Cmd(0, 100, 916, 1516); 命令单位(ID100)“移动(0)”到坐标为x,y(东916,北1516)的新位置。 Suicide(); (自毁)告诉脚本不要继续运行这个函数。(没有这一句,表示函数将无限次反复运行) end; (结束)关闭这个正在运行的函数(这是一个函数语句的结尾, 没有这个表示语句不完整,也会导致脚本中止(即游戏退出) function Init() 这是一个初始化函数,每个脚本必须有一个function Init ,否则脚本不会运行! RunScript(MoveCar, 3000); 就像这句话说的一样! 运行这个叫 “MoveCar”的函数(不要忘记双引号) 和何时运行(游戏开始后 3000 毫秒也就是3秒) end; 结束语句。 注意:可以在Calvin的指南或liukun1982翻译的script中找到Cmd命令列表 第二节 添加第二个有多项命令的函数 这一节 介绍使第二个单位在与第一个单位不同的时间点,做一系列移动。 第二节地图 这里有一辆小轿车(ScriptID100), 一辆卡车(ScriptID101), 一棵树和一个纪念碑。卡车将绕过纪念碑驶向建筑。 Lesson1.luaScript 脚本 function MoveCar() Cmd(0, 100, 916, 1516); Suicide(); end; function MoveTruck() Cmd(0, 101, 1583, 223); QCmd(0, 101, 1890, 1570); QCmd(0, 101, 1100, 1890); Suicide(); end; function Init() RunScript(MoveCar, 3000); RunScript(MoveTruck, 7000); end; 解说 function MoveCar() Cmd(0, 100, 916, 1516); Suicide(); end; function MoveTruck() 一个新函数,起名MoveTruck Cmd(0, 101, 1583, 223); 跟第一个函数一样的移动命令 QCmd(0, 101, 1890, 1570); QCmd 和 Cmd 一样,只是它产生于前一个命令之后。这个语句命令同一辆卡车在到达第一个点后继续驶向第二个设定的地点。 QCmd(0, 101, 1100, 1890); Suicide();end; function Init() RunScript(MoveCar, 3000); RunScript(MoveTruck, 7000); 这个指示运行第二个函数,但时间是游戏开始七秒后 end; 注意:第二个函数也可以象下面的脚本一样由第一个函数来调用。这是经常被用到的手法,适用于第二个函数肯定在第一个函数被执行之后被调用。这样做的好处是不用同一时间调用很多函数,而是只在需要时才调用特定的函数,从而可以减少CPU资源的占用。. 脚本 function MoveCar() Cmd(0, 100, 916, 1516); RunScript(MoveTruck, 4000); Suicide(); end; function MoveTruck() Cmd(0, 101, 1583, 223); QCmd(0, 101, 1890, 1570); QCmd(0, 101, 1100, 1890); Suicide(); end; function Init() RunScript(MoveCar, 3000); end; 解说 function MoveCar() Cmd(0, 100, 916, 1516); RunScript(MoveTruck, 4000); 第二个函数现在从这里被调用。为使卡车在游戏开始后7秒开始移动,我们要把时间改为4秒,因为在游戏开始后第一个函数“MoveCar”已经运行了3秒 Suicide(); end; function MoveTruck() Cmd(0, 101, 1583, 223); QCmd(0, 101, 1890, 1570); QCmd(0, 101, 1100, 1890); Suicide(); end; function Init() RunScript(MoveCar, 3000); 现在这个运行“MoveTruck”的命令可以从Initfunction 中去掉了。 end; 第三节 测试一个条件(是否具备) 这一节将介绍测试一个条件是否达到特定值从而触发一个新的应激行动。这是在闪电战地图中非常有用并且常用的程序设计。 第三节地图 这个地图上,在房子周围,有一个名为“Farm”的脚本区域,和两个脚本代码(ScriptID)为“103”,“104”的步兵班. 这两个步兵班隶属于援军组“103”( reinforcement group 103103b a 大于b a=b a 大于或等于b a=1 then SetIGlobalVar(Mission0, 1); Suicide(); end; end; function Objective0Complete() - NEW - if GetIGlobalVar(Mission0, 0) = 1 then ObjectiveChanged(0, 1); Suicide() end; end; function Init() RunScript(DebugView, 1000); RunScript(MoveCar, 3000); RunScript(FarmCheck, 2000); end; 解说 function ReavealObjective0() - NEW - ObjectiveChanged(0, 0); 这个参数表示哪一个目标(0)改变了,变成了什么,在这里显示(0) DisplayTrace(Off we go); 只是一个信息,可以忽略 RunScript(Objective0Check, 2000); - NEW 运行条件测试函数:达到什么条件才算目标完成 RunScript(Objective0Complete, 3000); - NEW 开始运行函数Objective0Complete,这个函数会显示目标完成的信息 Suicide() end; function Objective0Check() - NEW - if (130, Trench) =1 then 和GetNUnitsInArea语句不同,GetNScriptUnitsInArea计算的是代码为130的成员在脚本区域“Trench” 内的数量 SetIGlobalVar(Mission0, 1); 当条件符合,以指定的参数保存一个变量的名称和值。这里名称是“Mission0”,值是“1”,这个值可以是任意整数。(译者注:名称也可以是任意的,只要作者自己明白指的是什么) Suicide(); end; end; 两个end: 一个对应if,一个对应函数主体。 function Objective0Complete() - NEW - if GetIGlobalVar(Mission0, 0) = 1 then 这个保留字“if”调用前面由SetIGlobalVar保存的参数。第一个参数是保存的全局变量的名称,第二个参数一直都是“0”。总而言之,这个命令行调用了变量“Mission0”的值并且测试这个值是否等于“1”。如果答案为“真”, 那么执行下一行命令,如果是“假”, 那么什么也不做,函数继续运行。 ObjectiveChanged(0, 1); 参数(0,1)表示目标0是完成了(1) Suicide() end; end; 两个end: 一个对应if,一个对应函数主体。 注意:这里不是必须用全局变量去触发目标完成的信息,但这个变量经常被用来在脚本后部检查是否全部目标已经完成了。这是我们必须知道的。另一个完成目标的方法是象下面的函数: function Objective0Check() - NEW - if GetNScriptUnitsInArea(130, Trench) =1 then ObjectiveChanged(0, 1); Suicide(); end; end; 第五节 归纳 这一节我们将综合前面的教程内容:目标条件、不同种类的条件测试以及多样的援军呼叫。教程中将示范if else 以及if elseif 语句的用法,加入胜利和失败条件并且调用全局变量来测试这些条件是否已经符合。下面的例子换上不同的脚本区域和脚本代码以及不同的条件测试可以作为很多单人地图的基础。 第五节地图,基于第四节地图 Lesson5.lua 脚本 function DebugView() Password (Panzerklein); DisplayTrace(Lua really isnt scary any more!); ShowActiveScripts(); -God(0, 2); Suicide(); end; function MoveCar() Cmd(0, 100, 916, 1516); RunScript(MoveTruck, 4000); Suicide(); end; function MoveTruck() Cmd(0, 101, 1583, 223); QCmd(0, 101, 1890, 1570); QCmd(0, 101, 1100, 1890); RunScript(ReavealObjective0, 10000); Suicide(); end; function ReavealObjective0() ObjectiveChanged(0, 0); DisplayTrace(Off we go); RunScript(Objective0Check, 2000); RunScript(Objective0Complete, 3000); Suicide() end; function FarmCheck() if GetNUnitsInArea(0, Farm) = 2 then RunScript(SquadArrive, 1000); Suicide(); end; end; function SquadArrive() LandReinforcement(103); RunScript(SquadMove, 2000); Su

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论