|
楼主 |
发表于 2014-3-16 22:59:06
|
显示全部楼层
本帖最后由 FFUR2007SLX2_5 于 2014-3-21 19:17 编辑
242楼,《武装突袭3——刷军营与selectbestplaces》
还记得曾经我在ARMA2 F7模组教程中刷军营(FOB)的一篇帖子吗?也有不少玩家要求修复损坏的样板文件,坏消息是,很抱歉由于年久失修那个教程我已经彻底打算将其报废了,所以不再做更新了;好消息是,今天我把刷军营带到了A3,大家又可以重新燃起激情了!
何为造军营?就是自己在地图上一个一个创建帐篷,围栏,沙袋等等,随后不断调试,移位最后建成了自己满意的军营,就像这样:
随后就成这样了:
“额,老子花了一整天终于把这个破玩意儿给捣鼓出来了,累死爹了。”相信99%的朋友都有类似的经历并且在做任务时也是这么操作的。
剩下1%的玩家说:干嘛这么累,看我的脚本!于是花了一星期写了脚本可以“刷兵营”了,干得不错,上了一个层次并且可以在任务中随时调用生成。不过问题又来了,脚本刷建筑无非两种:预设位置与随机位置,预设位的缺点在于局限性,随机位在不确定性。一个精心设计的布局随机脚本无法达到该质量,而全部转换成脚本的对应坐标则费时费力,wiki上有专门的教程但看得人一头雾水:https://community.bistudio.com/w ... 789&oldid=69265 更糟的是还不支持A3。不过现在好了,在此篇教程中我将为大家介绍两位新朋友:BIS_fnc_ObjectsGrabber和BIS_fnc_ObjectsMapper。这两个函数的作者是Joris-Jan van 't Land(就是在希腊被兜进去的那个,出来后现在混到A3的项目负责人了)
先来看看它们派什么用:BIS_fnc_ObjectsGrabber用来复制你的的军营,就是说你得先自己在地图上搞个军营,虽然累点但是必须的,而且可以搞细致点,因为这次BIS_fnc_ObjectsGrabber可以把你的军营布局给永久的保存起来,以后就再也不用重新做了,MP任务可以直接丢进服务器脚本让脚本自己去刷。
BIS_fnc_ObjectsMapper就是刷军营的脚本,你可以将复制过来的军营以随意角度,任意地点,数量随意调用,非常方便。
现在看看怎么用,回到第一张图,我们先复制布局:
- [position player,100] call BIS_fnc_ObjectsGrabber
复制代码
具体参数解释可以在函数库中了解,在此不介绍。
回到记事本得到数组:
- /*
- Grab data:
- Mission: Unnamed
- World: Stratis
- Anchor position: [1626.65, 5273.64]
- Area size: 100
- Using orientation of objects: no
- */
- [
- ["Land_BagFence_Long_F",[-2.85596,1.99854,0],137,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-4.9906,2.22754,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[1.37378,6.21191,0],137,1,0,[],"","",true,false],
- ["Land_BarrelWater_F",[0.496948,7.20605,5.67436e-005],227.833,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-7.03015,4.48242,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[1.47778,8.23877,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-0.562744,10.4814,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagBunker_Small_F",[-10.7648,5.86182,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagBunker_Small_F",[-1.53735,14.3711,0],227.845,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-11.7985,9.74609,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-5.33801,15.7549,0],47.8449,1,0,[],"","",true,false],
- ["Land_WaterTank_F",[-10.0859,14.7197,-8.58307e-006],227.845,1,0,[],"","",true,false],
- ["Land_BarrelWater_F",[-11.7946,13.7856,5.72205e-005],227.834,1,0,[],"","",true,false],
- ["Land_WaterTank_F",[-8.97791,15.7915,-4.76837e-006],227.845,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-13.756,11.9941,0],47.8449,1,0,[],"","",true,false],
- ["Land_WaterTank_F",[-7.82532,16.9185,-4.76837e-006],227.845,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-7.29175,18.0049,0],47.8449,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-13.7778,13.9873,0],137,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-11.692,15.9463,0],137,1,0,[],"","",true,false],
- ["Land_BagFence_Long_F",[-9.44739,17.9038,0],137,1,0,[],"","",true,false],
- ["Snake_random_F",[33.8726,37.1655,0.00838757],269.029,1,0,[],"","",true,false]
- ]
复制代码
这就是我们的军营布局,A3总是会把蛇给一起复制进来,你可以把它删掉。
接下来我们在任意地点刷军营:
- [position player,88,[ ["Land_BagFence_Long_F",[-2.85596,1.99854,0],137,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-4.9906,2.22754,0],47.8449,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[1.37378,6.21191,0],137,1,0,[],"","",true,false], ["Land_BarrelWater_F",[0.496948,7.20605,5.67436e-005],227.833,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-7.03015,4.48242,0],47.8449,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[1.47778,8.23877,0],47.8449,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-0.562744,10.4814,0],47.8449,1,0,[],"","",true,false], ["Land_BagBunker_Small_F",[-10.7648,5.86182,0],47.8449,1,0,[],"","",true,false], ["Land_BagBunker_Small_F",[-1.53735,14.3711,0],227.845,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-11.7985,9.74609,0],47.8449,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-5.33801,15.7549,0],47.8449,1,0,[],"","",true,false], ["Land_WaterTank_F",[-10.0859,14.7197,-8.58307e-006],227.845,1,0,[],"","",true,false], ["Land_BarrelWater_F",[-11.7946,13.7856,5.72205e-005],227.834,1,0,[],"","",true,false], ["Land_WaterTank_F",[-8.97791,15.7915,-4.76837e-006],227.845,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-13.756,11.9941,0],47.8449,1,0,[],"","",true,false], ["Land_WaterTank_F",[-7.82532,16.9185,-4.76837e-006],227.845,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-7.29175,18.0049,0],47.8449,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-13.7778,13.9873,0],137,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-11.692,15.9463,0],137,1,0,[],"","",true,false], ["Land_BagFence_Long_F",[-9.44739,17.9038,0],137,1,0,[],"","",true,false], ["Snake_random_F",[33.8726,37.1655,0.00838757],269.029,1,0,[],"","",true,false] ] ] call BIS_fnc_ObjectsMapper
复制代码
随便你刷几个兵营都不在话下:
当然在实际使用中我们不会把那么一大串数组直接使用,我们可以将其汇编:
- [positionWhereYouWantToSpawnYourComposition, azimutOfYourComposition, call (compile (preprocessFileLineNumbers "yourComposition.sqf")),Propertion] call BIS_fnc_ObjectsMapper;
复制代码
现在我们来看看成果:
FOB已经搞定了,现在就来看看如何选择合适的地点来刷FOB,我们知道如果在非常陡峭的地方军营刷出来是无法判断法线角所以会斜插入地面,这样很不美观,所以我们需要找到合适的地方来生成FOB。
selectBestPlace https://community.bistudio.com/wiki/selectBestPlaces 是于2009年引入的一个代码,作为一个非常强劲的代码家族许多人却只知道其皮毛,在高级篇中我将着重介绍并且结合BIS_fnc_ObjectsMapper创造出极具动态效果的任务,selectbestplace拥有强大的参数组合 https://community.bistudio.com/wiki/Ambient_Parameters 譬如说寻找整张地图的最高点或最低点,将FOB生成在陆地上而非水里,将动物生成在草地里而非沙漠上,将人生成于城镇中而非荒野中等等。
Rube在这里有比较详细的介绍 http://forums.bistudio.com/showthread.php?93897-selectBestPlaces-(do-it-yourself-documentation)
我们来着重分析一下selectbestplace的计算表述:
1、 如何找到整张图的最高点?幸运的是BI的程序员们已经帮我们写好了,所以我们不必再用C++或sqf自己去写了:
- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 5000, "(1+hills)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码
2、 那么最低点呢?- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 5000, "(1-hills)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码 你直接进海沟里了。
3、 找到树林里的房子:- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 5000, "(1 + forest) * (1 + houses)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码
4、 找到有树林的,风大的地方:- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 5000, "(1 + forest) * (1 + windy)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码 等等,你可以进行任何搭配找到你所需要的位置,其基本原理就是组合使用乘法,全有为1+,全无为1-,那么一半一半呢?则可以是0.5*,当然你还可以使用更加复杂的算法12 - 8 * hills等等,各种配合可以通过简单的测试来观察效果。
Selectbestplace的最后两个参数,除数和返回数量。除数代表多点选取的间距,除数越小当然点数越多,返回数量则是从最佳到最差逐步筛选的坐标数组。因此我们可以通过selectbestplace轻松得到所需区域的关键点。
【新增A3DEV112】在升级到dev 1.12后selectbestplace共支持12种表述(感谢BI Dev DarkDruid与2014年3月13日做出的wiki更新):
rain [0-1] – 雨的稠密度
night [0-1] –夜间暗度
meadow [0-1] – 是否像草地
trees [0-1] – 有多少树木包围
hills [0-1] – 0 + hills为海拔高度大于160m; 1 + hills为海拔高度大于400m
houses [0-1] – 周围有多少房子
windy [0-1] – 区域风强度
forest [0-1] – 是否在树林中
deadBody [0-1] – 1 + deadBody离尸体很近,1 - deadBody离尸体很远
sea [0-1] – 1 + sea在海里,1 – sea在陆地上
waterDepth – 水深,1 + waterDepth最大水深
camDepth – 水中照相机深度,1 + camDepth最大水深
【新增A3DEV112】 (感谢BI Dev DarkDruid与2014年3月13日提供的强劲表述)
还记得A2时代的Ambient Animal吗?那些个动物是如何选取位置的?BI程序员不可能把羊群弄到森林里,到了A3,海龟,鱼这种东西不可能刷到陆地上来,而且即使在水中也有各自的生成点,至少要符合自然规律,所以在这里我新增了更复杂的表述:
https://community.bistudio.com/wiki/Simple_Expression 我们引入新概念“简易计算”
- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 5000, "((sea * (1 - night)) + (2 * houses * sea)) * (1 - night)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码
这个位置是海鸟的生成点,我们可以看到玩家直接来到了码头,来分析一下:((sea * (1 - night)) + (2 * houses * sea)) * (1 - night)就是(入海有亮光的地方)+(两倍入海靠房有亮光的地方)
- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 2000, "(20 * (0.1 - houses)) * (1 - sea)", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码 这个是兔子常去的地方,(离房子略远的陆地上)
- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 2000, "(4 * (WaterDepth interpolate [1,30,0,1]))", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码 这是深海动物常去的地方,这里的interpolate, factor和randomGen是A3的算法,想必我们知道加减乘除却不知道还有这3个,顺便科普一下。Interpolate是于2009年引入的算法,这里就相当于:
WaterDepth interpolate [p,q,r,s] =
WaterDepth <=p:r
WaterDepth >=q:s
p< WaterDepth <q: [(WaterDepth -p)/(q-p)]*(s-r) +r
这个就是一个加法运算,只不过再加上了因数和加数相成的结果,如果原始数超出范围则直接取r或s的值(上高数课时在睡觉?)。
A randomGen则直接取0~A的随机浮点数,强悍的算法,以后别忘了。
A factor [p,q] =
p< WaterDepth <q: [(WaterDepth -p)/(q-p)]
算出因数,以后做算术不用写长方程了。由于目前这三个只支持定义表达和selectbestplace,脚本中的算法并不支持,所以还有局限性,不过如果需要BI会将其纳入代码块。
- 0 = [] spawn {my_pos = ((selectBestPlaces [position player, 500, "(2 * (waterDepth interpolate [1,16,0,1]) * ((1-houses) * (1-houses)))", 1, 1]) select 0 select 0); player setPosATL [my_pos select 0,my_pos select 1,0];}
复制代码 这种应该算是沿岸海域,海龟活动的地方。现在开始发挥想象力了,重新认识selectbestplace后又可以开动你们的战争机器了!
【小贴士】:当然有些时候我们的随机定位脚本并不需要大量的selectbestplace运算以牺牲速度,所以surfaceType也是不错的选择用来筛选地表类型。
接着是 findEmptyPosition https://community.bistudio.com/wiki/findEmptyPosition 同时于2009年引进的代码,主要作用是搜索空地,当然包括法线角倾斜得厉害的地形,貌似比较鸡肋但至少我们还是能够找到适合停直升机的一块场地,先不看是否平整但必须足够大,我们的FOB也一样,必须得容得下我们的建筑:
- position player findEmptyPosition [0,150,"Land_City2_8mD_F"]
复制代码
这里一笔带过,最后来看isFlatEmpty https://community.bistudio.com/wiki/isFlatEmpty 2009年的代码,一串数组,配合其家族代码,负责判断地形是否是空地,为我们接下来的FOB选址做铺垫。
- oneachframe {hintsilent str (position player isFlatEmpty [10, 0, 0])};
复制代码
其实我们不需要那么多参数,三个就够了,isFlatEmpty仅仅判断是否空地!而并不判断是否平整,feedBack已经有人反映了,就看1.14能否解决了。
万事俱备只欠东风,又开始开动脑筋的时刻了,在这里我写了一个简单的函数来返还可用空地给我们来建FOB。
- /*
- fn_findflatpos
- author: ffur
- param: 0 - number range, 1 - string expression, 2 - number sourcecount, 3 - number mindistance
- */
- private ["_range","_expression","_count","_array","_Narray","_flat","_flatArray"];
- _Narray = [];
- _flatArray = [];
- _range = [_this,0,0,[0]] call bis_fnc_param;
- _expression = [_this,1,"",["",1]] call bis_fnc_param;
- _count = [_this,2,1,[1]] call bis_fnc_param;
- _flat = [_this,3,0,[0]] call bis_fnc_param;
- _array = selectbestplaces [position player,_range,_expression,1,_count];
- {
- _Narray set [_foreachindex,_x select 0];
- } foreach _array;
- {
- if ((count (_x isflatempty [_flat,0,0])) > 0) then {
- _flatArray set [count _flatArray, asltoatl (_x isflatempty [_flat,0,0])];
- };
- } foreach _Narray;
- _flatArray
复制代码
使用时[200,"1 + meadow",20,10] call fn_findflatpos即可直接找到可用的空点,随后我们随机选取一个地点来生成我们的FOB- [(([200,"1 + meadow",20,10] call fn_findflatpos) call bis_fnc_selectrandom),random 360, call (compile (preprocessFileLineNumbers "yourComposition.sqf"))] call bis_fnc_ ObjectsMapper;
复制代码 当然你还可以做更多异想天开的事,僵尸搜索尸体地点,平民随机生成系统等等。
245楼继续教程,《武装突袭3——HandleDamage与cfg函数》
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?加入VME
x
|