中国虚拟军事网(VME)- 专注于武装突袭系列虚拟军事游戏

 找回密码
 加入VME

QQ登录

只需一步,快速开始

搜索
楼主: FFUR2007SLX2_5

[教程] 《武装突袭3》脚本编写高级教程【255楼,武装突袭3——疯狂的戴夫和他的重量】

    [复制链接]
 楼主| 发表于 2013-10-11 22:46:53 | 显示全部楼层
本帖最后由 FFUR2007SLX2_5 于 2013-10-14 08:52 编辑

108楼 武装突袭3的代码结构——语块(花园,房子和卧室)



语块是句法最为基础的部分,好的脚本语块结构明晰,层次分明,方便阅读。语块就像是房型设计,拜访一个大家,里面有花园,花园里有水池,中间是别墅,进去是客厅,然后阁楼,厨房等等。而写得差的脚本找不到入口,得直接从厕所的窗户扒进去,一看不对里面是鱼缸,汤了一身水却直接来到了卧室,这不坑爹?
我们如何进一所房子呢?用调用——“call”
如下:

  1. scopeName "outside";  //  花园
  2. call {
  3.     scopeName "house";  //  房子
  4.     call {
  5.         scopeName "kitchen";  // 厨房
  6.     };
  7.     call {
  8.         scopeName "bedroom";  //  卧室
  9.     };
  10. };
复制代码


除了call我们还可以同其它方法进入房子,用跳的,用爬的用撞的随便。spawn {}; if () then {} else {}; while {} do {}; {} forEach等等。武装突袭3进入房子的过程是语块到语块的,这就意味着你不能从花园飞到卧室,你必须得到房子里去。(除非你是闪电侠)scopeName, breakOut和BreakTo我就不阐述了,不明白这两个代码的请看BiWiki http://community.bistudio.com/wiki/breakOut 不过当我们已近到厨房后就可以直接通过窗户翻到花园里去,请看:

  1. scopeName "outside";  //  花园
  2. call {
  3.     scopeName "house";//房子
  4.     call {
  5.         scopeName "kitchen";//厨房
  6.         breakTo "outside";
  7.     };
  8.     call {
  9.         scopeName "bedroom";//卧室
  10.     };
  11. };
复制代码


同样我们也可以从厨房返回到房子客厅,请看:

  1. scopeName "outside";//花园
  2. call {
  3.     scopeName "house";//房子
  4.     call {
  5.         scopeName "kitchen";//厨房
  6.         breakOut "kitchen";
  7.     };
  8.     call {
  9.         scopeName "bedroom";//卧室
  10.     };
  11. };
复制代码


对于exit with,它只能让你退出现已进去的语块。下面就是只从卧室回到客厅里,而不是直接就到花园。

  1. scopeName "outside";//花园
  2. call {
  3.     scopeName "house";//房子
  4.     call {
  5.         scopeName "kitchen";//厨房
  6.     };
  7.     call {
  8.         scopeName "bedroom";//卧室
  9.         if true exitWith {};
  10.     };
  11. };
复制代码


所以记住了,当你的脚本中有嵌套语块时,别傻傻的认为exit with可以退出所有语块,否则频繁的出错又要开始拳穿主板了……
还有一个我不得不提一下,上面的这些方法可以帮助我们正常的退出语块,但是有两个特殊的循环需要特殊的退出方式,普通的exit是无效的,就是OnEachFrame和WaitUntil,请看:

  1. onEachFrame {
  2.     if true exitWith {onEachFrame{}};
  3. };
  4. waitUntil {
  5.     if true exitWith {true};
  6. };
复制代码


下面我们看看房子里的人,我们假设将私用变量看成一个人,每个房子里都有一个人,外面马路上也有人,这和我们的社会是一样的,大家各不相关,各不认识,请看:

  1. _parentVar = 123;
  2. call {
  3.     hint str isNil "_parentVar"; //false
  4.     _childVar = 456;
  5. };
  6. if true then {
  7.     hint str isNil "_parentVar"; //false
  8.     _childVar = 456;
  9. };
  10. _null = [] spawn {
  11.     hint str isNil "_parentVar"; //true
  12.     _childVar = 456;
  13. };
  14. hint str isNil "_childVar"; //true
复制代码


好了,语块部分结束,希望大家现在对武装突袭3脚本编写已经明晰了吧。讲了那么多,我想我可以在代码部分做一下最后的小结,在武装突袭3 – 代码优化篇结束后我们就开始第二阶段的学习了。

请切换至120楼,武装突袭3——代码优化篇

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入VME

x
发表于 2013-10-11 23:10:09 | 显示全部楼层
好帖子,已收藏!
发表于 2013-10-12 01:29:53 | 显示全部楼层
感谢分享了
不知道能不能提供机场飞行载具起飞降弱路径引导教学
因为这部分设定好像特定规则
发表于 2013-10-12 06:19:51 | 显示全部楼层
一定要学习学习
发表于 2013-10-12 11:02:56 | 显示全部楼层
新手的福音{:soso__3409329614010722382_3:}
发表于 2013-10-12 11:58:31 | 显示全部楼层
卡纳可能...............
发表于 2013-10-12 13:47:50 | 显示全部楼层
搞不懂,学习学习..
发表于 2013-10-12 17:10:53 | 显示全部楼层
过来看看什么意思
发表于 2013-10-12 21:39:22 | 显示全部楼层
还好还好好好好
发表于 2013-10-12 23:50:11 | 显示全部楼层
WOW, FF大,支持支持
发表于 2013-10-13 08:50:01 | 显示全部楼层
好东西,谢谢
发表于 2013-10-13 09:56:59 | 显示全部楼层
不知道隐藏的是什么 我猜是目录  但是教程是个好东西  要支持下
发表于 2013-10-14 00:34:00 | 显示全部楼层
学习学习
 楼主| 发表于 2013-10-14 08:51:29 | 显示全部楼层
本帖最后由 FFUR2007SLX2_5 于 2013-10-14 09:11 编辑

120楼,武装突袭3 – 代码优化



好了,今天我就给前面的内容来个总结,希望大家不要前学后忘。在此篇中我将给大家列举一下代码优化的方法,哪些老代码改舍弃,那些新代码又有什么优势,闲言碎语不多说,上路!

进入到了代码优化的阶段,很荣幸的告诉大家现在你们已经从脚本编写者进化成程序员了,你们不仅能完成脚本编写者所有任务,而且从那些高度抽象的脚本中就可以看到这更像是一场秀,你们有极大的自信说出自己可以做得更好!现在请大家永远记住这几条,程序员与爱好者从字里行间中就可以看出区别!

1、      脚本中重复execVM同一个脚本是愚蠢的做法,必须把你的脚本写成函数汇编,这样能节省20倍的时间!

2、      如果你的函数或脚本超过了200行,那是一个愚蠢的做法,你必须重新考虑结构,否则你压根就没学会怎么去优化代码!

3、        在判断条件时如果条件很长必须使用惰性求值!

4、        你的代码必须整洁漂亮,就像你的人一样,谁喜欢邋遢的人?

5、        记住什么情况下再去用switch,如果你有一群判断却只需满足一个条件时,放弃switch转而调用if,因为这种情况下if调用的速度将更快!比如说:

private "_num2str";
_num = 0;
switch _num do {
    case 0: {_num2str = "0"};
    case 1: {_num2str = "1"};
    case 2: {_num2str = "2"};
    default {_num2str = "N/A"};
};

                 上面这个是愚蠢的做法,也许写了那么多年脚本你一直都这么做,但现在我告诉你这是错的。应该怎么做?看下面:

private "_num2str";
_num = 0;
call {
    if (_num == 0) exitWith {_num2str = "0"};
    if (_num == 1) exitWith {_num2str = "1"};
    if (_num == 2) exitWith {_num2str = "2"};
    _num2str = "N/A";
//Call if exitWith是这么用来提升速度的!
};

6、        脚本中涉及数字常量不会去定义而一贯的反复写入储存是愚蠢的做法,如果你喜欢这样:
a = _x + 1.053;
b = _y + 1.053;

                 或这样:
_buffer = 1.053;
a = _x + _buffer;
b = _y + _buffer;

                 为什么不这样?(记住,脚本开始前考虑好那些是你要用的常量!)
#define BUFFER 1.053

_a = _x + BUFFER;
_b = _y + BUFFER;
这样更快!




7、       还记得我在循环全解析(三)中排列出的速度排名吗?如果你想快点就用for和forEach,别用while, OnEachFrame和waitUntil。如果你想锁帧的话就别用for, while和forEach!

8、       你必须明白武装突袭3脚本运行速度上限是多少?0.3ms!什么意思?就是一个普通的sqf循环在游戏中的循环速度是每0.3ms一次!我在循环篇(三)中讲过解除引擎循环上限的做法,这里再总结一下:
所有触发器不受限!
所有预初始代码不受限!
FSM条件判断不受限!
Event handlers不受限!
从sqs中调取的sqf不受限!

9、       避免成方运算!
{
        { ...} foreach [0,0,0];
} foreach [0,0,0];
这样做会降低你的CPU运行速度!

10、     如果你给数组的尾部添加新值时依旧使用+是愚蠢的行为,set将更快,某些时候甚至resize,我在数组篇中已有详解。
_a = _a + [_v]  //  这是愚蠢的
ARRAYX = ARRAYX - [objnull];// 这是愚蠢的
ARRAYX set [0, objnull];// 这是明智的
_a set [count _a,_v]  //  这是明智的

11、     如果你在脚本中想要刷兵,还在使用:
_jeep = "Jeep" createVehicle (position player);
那真是愚蠢至极,这么做让你和菜鸟玩家没有区别,你必须用:
_veh = createVehicle ["ah1w", position player, [], 0, "FLY"]  
这么做比原来的句法快上500倍!

12、     如果你到现在还在用getpos?那你就想原始森林里古代人。getPosASL/getPosATL/Position的速度比getpos快上2倍!

13、     找附近的活人时还在用nearestObjects是愚蠢的,nearEntities更快!

14、     如果你不准备用特殊私用变量_forEachIndex!记住count永远比forEach快!
{diag_log _x} count [1,2,3,4,5,6,7,8,9];
//is faster than
{diag_log _x} forEach [1,2,3,4,5,6,7,8,9];
同样:
_someoneIsNear = {_x distance [0,0,0] < 1000} count allUnits > 0;
//is still faster than
_someoneIsNear = {
        if (_x distance [0,0,0] < 1000) exitWith {true};
        false
} forEach allUnits;

15、     如果同样的函数你有两套写法,勿必使用bis_fnc_codePerformance挑选出你认为速度更快的那个!

高级的脚本编写者必须牢记这15条,这也将成为中级到高级进阶的分水岭!记住,不要让你的脚本看起来很愚蠢!或许你认为高级教程到此结束了,恰恰相反,接下来的将会是一场饕餮盛宴!武装突袭3——fsm全教程!




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入VME

x
 楼主| 发表于 2013-10-14 09:06:59 | 显示全部楼层
本帖最后由 FFUR2007SLX2_5 于 2013-10-16 17:22 编辑

121楼,武装突袭3——FSM全教程(一)



相信绝大多数人看到FSM就头大,我连SQF还没搞清楚就跟我来FSM了?不过这点大家放心,只要按照流程将前面的SQF教程看完了并且消化吸收了,我想FSM只是1个小时的知识。我不想把FSM搞得同BIWIKI解释的那般复杂,什么像这篇:  http://community.bistudio.com/wiki/FSM 看了等于白看,我要你介绍FSM干吗用?还有AI FSM的 http://community.bistudio.com/wi ... n_Arrowhead:_AI_FSM  搞什么,都当我们是BI Dev吗?于是上google和bi forum苦苦搜索好不容易才找到了 http://www.sinewsofwar.com/Downl ... id/254/Default.aspx  FSM教程又不能下载? http://www.ofpec.com/sorry.php?reason=maintenance 也关门歇业了?bi wiki给出的链接都算什么? http://legacy.imatix.com/html/libero/  这又是什么? http://en.wikipedia.org/wiki/Finite_state_machine  这又是什么?wikipedia的学术报告?还有这个? http://www.nist.gov/dads/HTML/finiteStateMachine.html  都算什么?好容易找到像样点的一篇 http://rte.jonasscholz.de/blog/r ... sm-by-xenohtml.html  倒是给我点示范任务呀!什么都没有,于是便硬着头皮啃官方任务里的FSM,啃了老半天了轮到自己写FSM了各种问题又让我们有手撕显示屏的冲动了。既然官方不肯给一个像样点的FSM教程,那我们就自己干。

有些人问FSM究竟是什么东西?FSM是一种脚本。这个回答等于没回答,虽然我目前解释了可能略显抽象但是我想能干上这行的绝对是聪明人。

FSM是什么?这还得从源头sqs说起,在CWC(闪点行动:冷战危机)的年代,BI就已经拿sqs当作任务的框架,一些功能也通过sqs写(由于还没有引进sqf,所以暂且不称为其函数)。我可以肯定的是,虽然我们一直都习惯把它们叫做脚本,但是BI却从来都没有写过一个脚本!怎么理解?sqs是线性逻辑,可以非常方便的整理出任务的线性思路,它就像一棵大树,逻辑有了就有了枝干,接下来我们需要叶子才能看上去像完整的任务,关于叶子的定义我们可能有两种,社区玩家习惯于把它们叫做脚本(当然BI也这么称呼),还有一种是称呼为函数。由于当时的游戏只支持sqs,所以都可以统称为脚本,但是在BI Dev的心中它们可是有严格分工的!枝干与树叶!每个任务都有独一无二的枝干,但是许多叶子都是一样的,在BI看来我们不写脚本只写函数!那些脚本其实是社区玩家给搞出来的,当时比较有名的几个脚本如SLX,DAC。那个时候脚本与函数没有明确的界限直到抵抗力量更新到1.85之后,BI的概念已经彻底明晰了:使用fsm替代sqs,原本负责脚本的部分全部由sqf负责(既可以写脚本也可以写函数)。

现在的问题是那么脚本到底是什么?我们不用词条进行学术解释,只是从游戏的角度来解释,透过引擎所给的代码我们可以做出我们想要的一切,这就够了,脚本是宏观的,它包含了一切枝干与树叶,社区就有了无限的可能。但是为什么说BI从来就不写脚本而只写逻辑与函数呢?答案就是我通过更新引擎能做的事为什么还要花成本去写脚本?BI不写引擎只写脚本能进化游戏吗?那既然不写脚本还留着sqf作甚?但是任务却不是写在引擎里的,它们需要sqf和fsm的支持帮助开发人员更快更高效的写出任务。那么脚本的地位就明确了,这是留给社区玩家用的,至于开发人员,从来就不会浪费时间去写脚本。

回到课题,到了ARMA,BI明显开始使用fsm代替sqs来写任务的框架,sqf来写函数库通过框架反复调用,这样不是省时省力吗?那有些人说我看BI任务里的很多sqf都当作脚本来写的嘛,其实不是,这些sqf也全是任务框架的一部分,它们没有单独拿出来使用的价值,有价值的函数BI专门把它们集中写在一个文件夹里的。

到了ARMA2,BI依旧采取一贯的作风,不仅继承了8年发展的全部精华,更扩张了fsm的功能,配合bikb的使用玩家可以更好的控制对话。

到了ARMA3,BI更进一步,而且非常明显的两极分化,任务制作完全依赖函数与框架,我们甚至不见了bikb的踪影(其实其功能已经被新的函数所代替了)好了,说了那么多大家对fsm有一定了解了吧。

作为总结,我想说的是作为一名中级社区玩家,我们写的是脚本,或者是把它们做成插件造福千万AA玩家,社区正式因为有了这些脚本开发者而显得活力四射,比如说像VAS,MCC等等。(这里并不是说VAS,MCC的作者是中级玩家,其实他们都是高手,因为这些脚本里有大量需要调用它们预先写好的函数)。

那接下来再让我们看看真正的高手在哪里?他们几乎从来不会在ArmAholic上露面,也很少在BI Forum里露面,他们非常低调以至于我们只能从某个脚本某段话的注释里找到他们的名字,他们在干些什么?他们从来就不写脚本,他们只写函数!他们为ACE2 core写函数,他们为CBA A3写函数,他们为DayZ的服务器写函数,更有甚者写嵌入码黑服务器……

正如BI的开发者一样,为什么他们从来不写脚本,因为ACE离不开CBA,一大堆插件离不开CBA,服务器离不开函数调用,而写脚本的离不开调用函数(想象一下一个脚本不调用函数编写起来将会是多么的费时费力!)

所以,来到了高级篇,我就建议,sqs是脚本,必须放弃,用sqf写什么?脚本还是函数?这里我个人看法是放弃脚本改写函数。因为写脚本是给玩家用的,写函数是给写脚本用的,三者之间的阶梯等级我想大家都应该明确了吧。

那FSM做什么用?既然都建议大家放弃写脚本了,那fsm还有什么用?

FSM压根就不能当脚本来写!大家多逛逛Armaholic和Bi forum有多少人是写fsm脚本的?几乎就没有,就算有也是拿fsm当脚本练练手的。

为什么?首先,FSM不像sqf,它是不能汇编的,也就是说它不能当作函数来用,既然不能像函数一样调用就不能反复的去运行它(我在上一篇代码优化篇讲过反复运行不能汇编的脚本是一种愚蠢的行为)。

其次,虽然fsm能做sqf以及sqs的一切事情,但是它生来就是用来写任务框架的,把它写作脚本来运行然后发布到网上说我比你们写sqf的都高级,是种极其愚蠢的行为!

最后,还是一句话,别用fsm去写什么刷兵脚本咯,炮击支援脚本咯,AI行为增强脚本咯神马的,虽然在外行看来你很厉害,在内行看来更本就不屑一顾,连BI都不这么做,我们何苦呢?(至于为什么我会在后面的章节中详细示例)

反正,FSM就是给你来做任务的!简称辅助地图编辑器!(神马循环机的我不想听)

请切换至132楼继续教程,武装突袭3——FSM全教程(二)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入VME

x
您需要登录后才可以回帖 登录 | 加入VME

本版积分规则

小黑屋|中国虚拟军事网

GMT+8, 2024-4-29 11:03

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表