CoreT1AATank脚本分析 - from fonter456

//下面TA-EXCESS II alpha1e版的CORE的T1导弹车的脚本,估计每个版本的都一样,如果你的版本不一样也可以对照看看,这个脚本包含很多方面的内容
//解析这个脚本的目的是介绍:攻击后隐藏导弹,装完弹后显示,以及对空控制
#define TA
#include “sfxtype.h”
#include “exptype.h”
piece base, hull, ltrack, lshadow, rtrack, rshadow, radar, turret, pitchturret, launcher1, msl1, launcher2, msl2,
flare1, flare2, ltireturn, lhubcap, ltire, rtireturn, rhubcap, rtire;
static-var DamageNow, LastDamage, Launcher, Reloading, AntiAir, UnitHeading, UnitSpeed;
SmokeUnit(HealthPercent, SleepTime)
{
signal 8;
set-signal-mask 8;
while( get BUILD_PERCENT_LEFT )
{
sleep 500;
}
while( TRUE )
{
HealthPercent = get HEALTH;
if( HealthPercent < 60 )
{
emit-sfx 256 | 1 from rtireturn;
SleepTime = 300;
}
if( HealthPercent < 30 )
{
emit-sfx 256 | 2 from launcher1;
emit-sfx 256 | 2 from ltrack;
SleepTime = 200;
}
sleep SleepTime;
}
}
HitByWeapon(AngleX, AngleZ)
{
DamageNow = get HEALTH;
if( DamageNow <= LastDamage - 10 )
{
signal 128;
set-signal-mask 128;
LastDamage = DamageNow;
turn base to z-axis AngleZ speed <105.000000>;
turn base to x-axis AngleX speed <105.000000>;
wait-for-turn base around z-axis;
wait-for-turn base around x-axis;
turn base to z-axis <0.000000> speed <30.000000>;
turn base to x-axis <0.000000> speed <30.000000>;
return (0);
}
LastDamage = DamageNow;
}
Reload() //装弹控制脚本
{
Reloading = 1; //静态变量Reloading = 1
sleep 2000; //延迟 2秒
show msl1; //显示导弹1
show msl2; //显示导弹2
move msl1 to z-axis [0.00] speed [1.00]; //导弹1前移到初始位置,
move msl2 to z-axis [0.00] speed [1.00]; //导弹2前移到初始位置
sleep 1000; //延迟1秒
Reloading = 0; //静态变量Reloading = 0
return (0);
}
//实际上这里是冷却了3秒,中途2秒时插了一个显示导弹装填的动作,把因为下面会在攻击后后移导弹向前移到原位,这样搞只是为了使导弹好像是装上去一样。

Create()
{
DamageNow = 100;
LastDamage = 100;
Launcher = msl1; //初生状态下,导弹出发点是msl1
Reloading = 0; //初生状态下,不需要装弹
AntiAir = 0; //初生状态下,不是对空
UnitSpeed = 1; //初生状态下,速度1
dont-cache flare1;
dont-cache flare2;
hide flare1;
hide flare2;
spin flare1 around z-axis speed <200.00>;
spin flare2 around z-axis speed <2000.00>;

start-script SmokeUnit();

while( get BUILD_PERCENT_LEFT )
{
sleep 500;
}
spin radar around y-axis speed <210.00>;
}
RestoreAfterDelay()
{
sleep 4000;
AntiAir = 0;
show msl1;
show msl2;
move msl1 to z-axis [0.00] speed [1.00];
move msl2 to z-axis [0.00] speed [1.00];
turn turret to y-axis <0.000000> speed <120.000000>;
turn pitchturret to x-axis <0.000000> speed <30.000000>;
start-script SmokeUnit();//Smoke script seems to disappear sometimes. This should fix the issue.
}
SweetSpot(PieceNum)
{
PieceNum = turret;
}
StartMoving() //开始移动
{
set-signal-mask 4; //设置为信号4
dont-cache ltrack; //播放左边履带动画
dont-cache rtrack;
spin ltire around x-axis speed <360.000000> accelerate <100.000000>;//旋转左前轮
spin rtire around x-axis speed <360.000000> accelerate <100.000000>;
while( TRUE )
{
if( UnitSpeed == 1 ) //如果是速度1
{
UnitHeading = UnitHeading - get XZ_ATAN(7); //计算单位向那个方向运动,不懂的照抄
turn ltireturn to y-axis 5 * UnitHeading speed <200.00>; //左前轮向移动的方向转动
turn rtireturn to y-axis 5 * UnitHeading speed <200.00>;
UnitHeading = get XZ_ATAN(7);
}
if( UnitSpeed == 2 ) //如果是速度2
{
UnitHeading = UnitHeading - get XZ_ATAN(7);
turn ltireturn to y-axis 2.5 * UnitHeading speed <200.00>; //左前轮转动,但是幅度较上面小
turn rtireturn to y-axis 2.5 * UnitHeading speed <200.00>;
UnitHeading = get XZ_ATAN(7);
}
sleep 100;
}
}
StopMoving() //停止移动
{
signal 4; //杀掉信号4
cache ltrack; //停止播放左边履带动画
cache rtrack;
spin ltire around x-axis speed <0.000000> accelerate <-210.000000>; //左前轮减速旋转直到转速为0
spin rtire around x-axis speed <0.000000> accelerate <-210.000000>;
turn ltireturn to y-axis <0.00> speed <200.00>;
turn rtireturn to y-axis <0.00> speed <200.00>;
}
MoveRate1() //系统脚本,用来评估单位的当前速度,在fbi文件里设定参数大小,这个单位是MoveRate1=1.5
{
UnitSpeed = 1; //静态变量UnitSpeed=1
}
MoveRate2() //这个没有在fbi文件里指定大小,一般如果分2个MoveRate,就只指定1个,3个就指定2个,原因不明
{
UnitSpeed = 2;
}
AimFromPrimary(PieceNum)
{
PieceNum = pitchturret;
}
QueryPrimary(PieceNum)
{
PieceNum = Launcher;
}
AimPrimary(Heading, Pitch) //第一武器瞄准,这个是对地用
{
if( AntiAir == 1 )
{
return(0);
}
signal 2;
set-signal-mask 2;
turn turret to y-axis Heading speed <220.00>;
turn pitchturret to x-axis <0.00> - Pitch speed <60.00>;
while( Reloading == 1 )
{
sleep 100;
}
turn turret to y-axis Heading speed <220.00>;
turn pitchturret to x-axis <0.00> - Pitch speed <60.00>;
wait-for-turn turret around y-axis;
wait-for-turn pitchturret around x-axis;
start-script RestoreAfterDelay();
return (1);
}
FirePrimary()
{
if( Launcher == msl1 )
{
Launcher = msl2;
start-script Reload();

move flare1 to x-axis [2.65] now;
move flare2 to x-axis [2.65] now;

hide msl1; //发射后隐藏导弹1
move msl1 to z-axis [-1.00] now; //往后立刻移动1,这是为了装弹后可以向前移的动作
move launcher1 to z-axis [-1.00] speed [10.00];
emit-sfx 256 | 2 from flare1;
show flare1;
show flare2;
sleep 75;
emit-sfx 256 | 2 from flare1;
hide flare2;
sleep 75;
emit-sfx 256 | 1 from flare1;
hide flare1;
move launcher1 to z-axis [0.00] speed [1.00];
return (0);
}
Launcher = msl1;
start-script Reload();

move flare1 to x-axis [-2.65] now;
move flare2 to x-axis [-2.65] now;

hide msl2; //发射后隐藏导弹2
move msl2 to z-axis [-1.00] now; //往后移动导弹2
move launcher2 to z-axis [-1.00] speed [10.00];
emit-sfx 256 | 2 from flare1;
show flare1;
show flare2;
sleep 75;
emit-sfx 256 | 2 from flare1;
hide flare2;
sleep 75;
emit-sfx 256 | 1 from flare1;
move launcher2 to z-axis [0.00] speed [1.00];
hide flare1;
}
AimFromTertiary(PieceNum)
{
PieceNum = pitchturret;
}
QueryTertiary(PieceNum)
{
PieceNum = Launcher;
}
AimTertiary(Heading, Pitch) //第3武器瞄准,对空用
{
AntiAir = 1;
signal 2;
set-signal-mask 2;
turn turret to y-axis Heading speed <220.00>;
turn pitchturret to x-axis <0.00> - Pitch speed <60.00>;
while( Reloading == 1 )
{
sleep 100;
}
turn turret to y-axis Heading speed <220.00>;
turn pitchturret to x-axis <0.00> - Pitch speed <60.00>;
wait-for-turn turret around y-axis;
wait-for-turn pitchturret around x-axis;
AntiAir = 0;
start-script RestoreAfterDelay();
return (1);
}
FireTertiary()
{
if( Launcher == msl1 )
{
Launcher = msl2;
start-script Reload();

move flare1 to x-axis [2.65] now;
move flare2 to x-axis [2.65] now;

hide msl1;
move msl1 to z-axis [-1.00] now;
move launcher1 to z-axis [-1.00] speed [10.00];
emit-sfx 256 | 2 from flare1;
show flare1;
show flare2;
sleep 75;
emit-sfx 256 | 2 from flare1;
hide flare2;
sleep 75;
emit-sfx 256 | 1 from flare1;
hide flare1;
move launcher1 to z-axis [0.00] speed [1.00];
return (0);
}
Launcher = msl1;
start-script Reload();

move flare1 to x-axis [-2.65] now;
move flare2 to x-axis [-2.65] now;

hide msl2;
move msl2 to z-axis [-1.00] now;
move launcher2 to z-axis [-1.00] speed [10.00];
emit-sfx 256 | 2 from flare1;
show flare1;
show flare2;
sleep 75;
emit-sfx 256 | 2 from flare1;
hide flare2;
sleep 75;
emit-sfx 256 | 1 from flare1;
move launcher2 to z-axis [0.00] speed [1.00];
hide flare1;
}
Killed(Severity, CorpseType)
{
hide flare1;
hide flare2;
hide msl1;
hide msl2;
if( Severity <= 50 )
{
CorpseType = 1;
explode ltireturn type BITMAPONLY | BITMAP3;
explode rtireturn type BITMAPONLY | BITMAP3;
explode radar type BITMAPONLY | BITMAP1;
explode pitchturret type BITMAPONLY | BITMAP3;
explode ltrack type BITMAPONLY | BITMAP3;
explode rtrack type BITMAPONLY | BITMAP3;
explode lhubcap type SHATTER | BITMAP5;
explode rhubcap type SHATTER | BITMAP5;
return (0);
}
CorpseType = 2;
explode hull type SHATTER | BITMAP5;
explode ltireturn type BITMAPONLY | BITMAP3;
explode rtireturn type BITMAPONLY | BITMAP3;
explode radar type BITMAPONLY | BITMAP1;
explode turret type BITMAPONLY | BITMAP3;
explode ltrack type BITMAPONLY | BITMAP3;
explode rtrack type BITMAPONLY | BITMAP3;
explode launcher1 type FALL | SMOKE | EXPLODE_ON_HIT | BITMAP1;
explode launcher2 type FALL | SMOKE | EXPLODE_ON_HIT | BITMAP1;
explode ltire type FALL | SMOKE | EXPLODE_ON_HIT | BITMAP1;
explode rtire type FALL | SMOKE | EXPLODE_ON_HIT | BITMAP1;
}

//关于对空控制,这个单位有两个武器,武器1和武器3,武器3是对空武器。在下也没看懂在什么情况下用武器3,什么情况下用武器1攻击的原理,所以会C语言的自行研究,不会的照抄就好。
CoreT1AATank.jpg
CoreT1AATank.rar (4.52 KB)

尝试讲解:

StartMoving() //单位开始移动脚本
{
set-signal-mask 4; //设置脚本为信号4
dont-cache ltrack; //播放左边履带动画,该单位既有履带,又有轮胎
dont-cache rtrack;
spin ltire around x-axis speed <360.000000> accelerate <100.000000>; //旋转左前轮
spin rtire around x-axis speed <360.000000> accelerate <100.000000>;
while( TRUE )
{
if( UnitSpeed == 1 ) //其实这里设定了两个速度档,这个类似于我们平时开手动档的车,以便于理解,当速度为1档时 {
UnitHeading = UnitHeading - get XZ_ATAN(7); //用来判断车头将往哪个方向转弯
turn ltireturn to y-axis 5 * UnitHeading speed <200.00>; //根据判断结果,显示前轮的具体打轮效果,也就是前轮会略微转动,表示车辆在转弯
turn rtireturn to y-axis 5 * UnitHeading speed <200.00>;
UnitHeading = get XZ_ATAN(7); //车头调整回轮。。。
}
if( UnitSpeed == 2 ) //当挂到2档时。。。
{
UnitHeading = UnitHeading - get XZ_ATAN(7);
turn ltireturn to y-axis 2.5 * UnitHeading speed <200.00>; //前轮的打轮动作,但因为车速提升,所以打轮幅度小了。。
turn rtireturn to y-axis 2.5 * UnitHeading speed <200.00>;
UnitHeading = get XZ_ATAN(7);
}
sleep 100;
}
}

StopMoving() //停止移动,停车的脚本没什么好说的。。。
{
signal 4; //杀掉信号4
cache ltrack; //停止播放左边履带动画
cache rtrack;
spin ltire around x-axis speed <0.000000> accelerate <-210.000000>; //左前轮减速旋转直到转速为0
spin rtire around x-axis speed <0.000000> accelerate <-210.000000>;
turn ltireturn to y-axis <0.00> speed <200.00>;
turn rtireturn to y-axis <0.00> speed <200.00>;
}

MoveRate1() //这里给档位做了具体的规定,相当于驾车指南:soso_e129: 。。
{
UnitSpeed = 1; //当速度达到1时,就要挂1档了。。。
}

MoveRate2() //当速度达到2时,则要挂2档了。。。高速行驶请注意安全,祝您一路通畅。。。
{
UnitSpeed = 2;
}

重点脚本分析:
Excess II的物理系统模仿得非常逼真,关于驾车这一段,作者做了非常细致的描述,包括当车辆转弯时前轮的转动效果,以及在不同档速下轮胎的转动速度等,都做了细致的描述,只是,在游戏中,尤其是高解析度下,这么细腻的动作,是否可以被人察觉到。。。不管怎么说,这些思路都非常有趣:soso_e104:

重点脚本分析2:对空/对地切换
这里有一个关键变量 — AntiAir 。。。这个变量用于判断是否启用对空武器,这里需要先说明的是,每种单位都有三个武器位置,系统对三种武器做了不同的内部规定,第一武器为完全自动并且可以主动攻击,也就是说,无论你用攻击指令,还是直接鼠标右键点击可被攻击目标,这个武器都会发动;第二武器具有主动性以及“半自动”攻击效果,也就是说,你可以用攻击命令驱动其发射,但若用鼠标右键主动攻击目标时,可能不驱动(一般是对建筑物),除非是有威胁目标(比如敌方攻击单位或炮台)或可被识别目标(比如敌方工程单位),才会发射;第三武器最为奇怪,首先,攻击命令不会对其奏效(也正因如此,一般防空武器都在这个武器位置上),只在两种情况下才会发动,第一,有可被识别目标进入射程时会发动攻击(有时需要单位处在运动状态才会发射,具体情况还为搞清楚),因此属于完全被动,或者,在武器属性里有表明“手动发射”时,则变成完全主动,也就是“特殊”武器,比如40的D-GUN,这里就不多说了。

那么在了解了TA引擎对武器位置的规定后,我们可以利用这些规则给武器设置优先级,具体到这个单位,由于该单位的武器系统,对空和对地是共用相同发射架的,因此两套系统切换需要靠Anti-Air来切换,并设定优先级,但奇特的是,作为第一武器的对地武器的优先级却低于第三武器处于完全被动的防空系统,作者具体是怎么做的呢,我们可以做一个简单的逻辑分析,如果作为完全被动发射的第三武器,如果优先级低于第一武器,然而在共用发射架的情况下,第三武器根本没有机会发射,因此要提升其发射优先级,我们看到作者做了两个处理,第一是提升了第三武器脚本的信号等级,我们可以注意到第三武器的信号是2,而第一武器的信号是4(当然,这个是否实际管用,我还比较怀疑),另一个处理就是设定了Anti-Air这个参数,当处理第一武器脚本时,即使接受到了脚本信号,也会先判断是否同时在接受第三武器的脚本信号,同时,通过在第三武器中更改Anti-Air的参数值,达到对第一武器信号接收的控制,所以,当防空武器发射时,对地武器会停止工作,好达到对空优先的目的。。。

题外话
在TA:SoM新种族中,T2狙击机甲使用了类似于这个导弹车武器切换系统的脚本原理,但略微不同,T2狙击机甲的步枪具有两种发射模式,分别是“远程狙击”和“近战扫射”,那么T2机甲的脚本中仍然有一个用于切换发射模式的变量,并在处于第二武器位置的“近战扫射”脚本中增加了对第一武器“远程狙击”模式的控制,当目标进入了“近战扫射”武器模式的射程后(这个是因为远程武器的射程必然大于近战武器的射程),位于第二武器位置的“近战武器”必然会切换变量值,来控制“远程狙击”武器的发射,但同时也出现了一个问题,那就是切换后的近战武器不太可能切换回去,除非结束一轮攻击,进入RestoreAfterDelay()
语句恢复用于切换的变量的初始值,之所以这么做,是因为在实际测试时,如果“近战扫射”模式突然切换回“远程狙击”模式,会让攻击接连,当反复切换时,会导致大威力的“远程狙击”连续发动,从而成为导致单位威力不平衡的bug,目前也没有更好的解决方案。。。

TA中应不支持武器的发射速度超过在武器类型中的设置的,即便是在脚本中,也只有办法延缓武器的发射,而不能控制武器主动射击,这个切换成远程后,应不会出现那种问题的吗?

会有问题,武器射程是硬性指标,射程是死的,因此,射程低的武器一定会受限制,而射程高的武器,即使在近距离下,也不影响发射,因此需要提升近战武器的优先级,目前的脚本方案还是比较奏效的。。。

我转移了下帖子,到军备工厂。

我想着威力的问题不会那么明显,最后用过就知道,哈哈

其实威力是次要的,主要是看设计的理念何在,这部分应该是属于认为控制的,至于好不好,也只有用过才知道