---------------------------------------------------------------------------
继续讲状态控制器(state controller或sctrl)和触发器(trigger)的知识。
如果把Mugen代码比喻成一本书的话,
那么Sctrl和trigger就可以比喻为文字。
书的内容其实是一个一个字组合而成,Mugen代码亦然,是由Sctrl与trigger拼凑而成。
Sctrl是状态变化的类型,也可以理解为想要触发的事件,例如说切换动作、改变速度之类。
trigger是触发器,满足条件就触发,用来判断该事件是否符合条件被触发,例如判断对方的名字是否叫KFM之类。
这章只讲讲比较常用并且与性能或AI相关的Sctrl与trigger,而且也只是相当概括性的讲讲其用途,
详细想知道更多的请自己阅读Sctrl与trigger两个表。
注:以下内容int代表整型数字,float代表浮点型数字,string代表字符串
===========================================================================
4.1常用Sctrl
===========================================================================
---------------------------------------------------------------------------
Sctrl通用参数
---------------------------------------------------------------------------
IgnoreHitPause
必选参数: 0 = OFF, 1 = ON
无视打击暂停,是每一个Sctrl都可以使用的参数。双方打斗中击中时会有打击暂停(也就是打中的时候卡一下),
ON的话就是在打击暂停时这个Sctrl依旧可以被触发,OFF则不会。实际应用中var改变等某些情况会用到。
例子:IgnoreHitPause = 1
---------------------------------------------------------------------------
改变动作相关
---------------------------------------------------------------------------
ChangeState
ChangeAnim
SelfState
必选参数: value = int
ChangeState为改变状态,是写AI过程中用得最多的Sctrl没有之一。正如前面所提及,
Mugen人物运行其实就是状态切换,此Sctrl的作用就是从当前状态切换到指定状态号的状态。
ChangeAnim为改变动画。多数情况下,一个动作对应一个动画,但是有些情况同一个状态里需要呈现不同的动画,
就会用到ChangeAnim。因为动画涉及攻击框受击框,所以注意。
SelfState其实与ChangeState很类似,不过通常用于拉回自己状态,通常用于把对方拉进特殊状态后让对方还原。
---------------------------------------------------------------------------
改变攻防相关
---------------------------------------------------------------------------
AttackMulSet
DefenceMulSet
必选参数: value = float
攻击/防御改变。当value = N时,AttackMulSet获得效果攻击*N,DefenceMulSet获得效果防御/N(略猎奇)。
另外DefenceMulSet需要在受击开始后才生效。
例子:同样是value = 0.5,对AttackMulSet来说就是攻击变成0.5倍,对DefenceMulSet来说就是防御变成2倍。
---------------------------------------------------------------------------
无敌相关
---------------------------------------------------------------------------
HitBy
NotHitBy
必选参数: value = string (attr,即攻击类型)
可选参数: time = int
HitBy和NotHitBy都是无敌,HitBy是仅可以被描述的攻击类型的攻击击中,而NotHitBy是不能被描述的攻击类型的攻击击中。
如果加入time参数,则无敌时间延长X帧。
例子1:不被任何攻击击中
type = NotHitBy
value = SCA
例子2:仅可被地面普通攻击击中
type = HitBy
value = S, NA
---------------------------------------------------------------------------
血量气量相关
---------------------------------------------------------------------------
LifeAdd
LifeSet
PowerAdd
PowerSet
必选参数: value = int
改变血量及气量的Sctrl,就是简单的加法和直接赋值,不予赘述。
---------------------------------------------------------------------------
打击相关
---------------------------------------------------------------------------
HitDef
Projectile
ReversalDef
必选参数: 太长不写(因为真的很长),具体请看hitdef.txt
三种打击类型,打击定义(通常用来写打击技和投技)、飞行道具和反射定义(通常用来写当身、格挡等特殊防御技)。
打击定义和飞行道具就是我们所说的攻击所造成效果的定义(比如伤害、硬直等),只要我方攻击框接触对方受击框就会生效。
而反射定义比较特殊,需要对方攻击框与我方攻击框才能生效。
---------------------------------------------------------------------------
暂停相关
---------------------------------------------------------------------------
Pause
SuperPause
必选参数: Pause: time = int, SuperPause: None
顾名思义,Pause就是普通的暂停,而SuperPause指的是某些会出现特效的特殊暂停(比如超杀前的暗转暂停)。
---------------------------------------------------------------------------
变量相关
---------------------------------------------------------------------------
VarAdd
VarRandom
VarRangeSet
VarSet
ParentVarAdd
ParentVarSet
变量Var的具体介绍会在第6章出现,暂时大概理解为可以赋值的一些数字吧。
如果说ChangeState是写AI过程中用得最多的Sctrl,那VarAdd和VarSet可以说是紧随其后。
变量对于AI的意义非常重大,可以说相当于人类的记忆。带有学习功能的AI必须使用变量记录。
前四个是对Var的赋值,通常来说VarAdd和VarSet比较常用。VarRandom用于给Var赋予随机值,VarSet则是批量的对Var赋值。至于
ParentVarAdd和ParentVarSet,有时也会用于飞行道具或helper对本体赋值,不过不常用。
---------------------------------------------------------------------------
位置与速度相关
---------------------------------------------------------------------------
PosAdd
PosFreeze
PosSet
VelAdd
VelMul
VelSet
可选参数: x = float, y = float
前缀Pos的是位置相关,前缀是Vel的是速度相关,在正常移动、突进技、移动技等地方广泛使用。
有两个可选参数分别控制横坐标和纵坐标。单纯的改变位置不会有速度变化,但是速度变化会引起位置变化。
另外人物在地面时速度会收到摩擦力影响,在空中时不会。
---------------------------------------------------------------------------
其他
---------------------------------------------------------------------------
AssertSpecial
必选参数: flag = string (flag_name)
可选参数: flag2 = string (flag_name), flag3 = string (flag_name)
特殊断言,每个AssertSpecial可以插最多三个flag。
这些flag的内容多数是一些比较特殊的效果和性能,例如隐藏血条和气条、自身人物不能空防/站防/蹲防、自己的攻击不能被防御
等等。
CtrlSet
必选参数: value = int, 0 = OFF, 非0 = ON
控制设置,设置为0变成不受控制,或设置为非0变成受控制。可控制状态就是指该状态下人物可以通过输入命令做出相应动作,比
如普通的站姿,按前就是向前走,按上就是跳,被攻击时按后就是防御,按ABCXYZ是攻击,这就是处于可控制状态。
DisplayToClipboard
很常用的debug用Sctrl,通常放在-1、-2或-3下,可以直接把想用的最多5个量直接显示在屏幕最下方。
(当然你需要比较好的视力去看清楚究竟里面写了什么...)
例子:
[State -1, Display]
type = DisplaytoClipboard
Trigger1 = 1
text = "X : %d | Y : %d | Var : %d | FX : %d | BX: %d "
params = ceil(P2bodydist X) , ceil(P2bodydist Y) , ceil(Var(0)), ceil(FrontEdgeBodyDist), ceil(BackEdgeBodyDist)
(这个例子所显示的是双方X轴Y轴距离,Var(0)的值,和人物跟画面边缘的前后距离)
Helper
援护,非常有用的东西,飞行道具、画面特效、幽波纹(误)之类的很多制作方面的东西都可以通过helper做到。
另外在AI领域,由于人物本体变量不够用甚至本体变量已经被人物作者用光了,我们可以建立AI helper利用helper里面的Var来记
录我们需要记录的信息。
StateTypeSet
状态种类改变,状态种类一共是4种,S C A L 分别对应站姿 蹲姿 空中 倒地。这个Sctrl可以在某个状态中改变其状态种类。
Turn
转向,把人物的朝向变成反方向。
Width
改变人物宽度,两人物横向宽度重叠的时候会发生排挤。可以把人物宽度理解为排挤框(身位框?)大小。
===========================================================================
4.2常用trigger
===========================================================================
---------------------------------------------------------------------------
重定向
---------------------------------------------------------------------------
在讲trigger之前必须先说说重定向。
我们在读取本体信息的时候不需要加任何前缀。但是我们怎么才能读取其他人(例如对方、队友、援护)信息呢?
这个时候我们需要用重定向,用特定的前缀来获取指定对象的信息。
常用的重定向前缀有:
parent
重定向到人物的亲人物(也就是生成这个援护的人物),而且该人物必须是个援助。不过多数情况下直接用root。
root
重定向到人物的根人物(可以理解为人物本体了)。用于直接调取人物本体相关信息。
helper / helper(ID)
重定向到第一个找到的援助。/ 重定向到相应ID的援助。用于检测自身helper相关信息。
target / target(ID)
重定向到第一个找到的目标。/ 重定向到相应ID号的目标。目标是指你攻击命中的对象。
partner
重定向到人物的队友。很明显常用在双人游戏里。
enemy / enemy(n)
重定向到第一个最远的对手。/ 重定向到第n+1个最远的对手。
enemynear / enemynear(n)
重定向到最靠近的对手。/ 重定向到第n+1个靠近的对手。通常来说,enemynear比enemy要常用因为通常我们关心较近的敌人。
playerID(ID)
重定向到具有唯一对应ID号的人物。这个要通过调查对方ID之后才能用。
例子:
root,statetype人物本体的状态种类
enemynear,time最近敌人的时间
helper(1005),statenoID为1005的援护的状态号
注意:多重重定向(例如,root,target,time)现在还不支持。
---------------------------------------------------------------------------
动画相关
---------------------------------------------------------------------------
Anim
AnimElem
AnimElemNo
AnimElemTime
以上四个都是动画相关的trigger,但是作用还是有挺大差异的。动画里面的每一幅图被称为元素。
Anim是返回当前动画号,其他三个是动画元素及动画时间相关的trigger,具体请看trigger文档,视情况灵活运用。
---------------------------------------------------------------------------
画面边缘相关
---------------------------------------------------------------------------
BackEdgeBodyDist
BackEdgeDist
FrontEdgeBodyDist
FrontEdgeDist
画面的前后边缘距离检测,注意不是场景边缘是画面边缘,场景边缘需要用特殊的方法检测。
另外貌似由于Mugen自带BUG,带不带Body都是一样的OTL,希望E小组尽快修正吧。
---------------------------------------------------------------------------
数学运算用
---------------------------------------------------------------------------
Abs
Ceil
Floor
绝对值、向上取整、向下取整,不予赘述。
---------------------------------------------------------------------------
血量气量相关
---------------------------------------------------------------------------
Life
LifeMax
Power
PowerMax
当前血量、最大血量、当前气量、最大气量,不予赘述。
---------------------------------------------------------------------------
打击接触相关
---------------------------------------------------------------------------
MoveContact
MoveGuarded
MoveHit
MoveReversed
一个人物攻击如果接触了对方,将会出现三种情况:击中,被防御和被反射。以上四个就是分别代表这些情况。
MoveHit用于连段,MoveGuarded用于压制,而MoveReversed就自求多福吧。
另外请注意MoveContact是MoveHit或MoveGuarded,而不包含MoveReversed。
---------------------------------------------------------------------------
人物状态相关
---------------------------------------------------------------------------
StateType
MoveType
状态种类和动作种类。状态种类一共是4种,S C A L 分别对应站姿 蹲姿 空中 倒地。
动作种类一共是3种,A H I分别对应攻击 受击 空闲。AI里时常需要这两个trigger来判断对方的行动。
---------------------------------------------------------------------------
位置、距离与速度相关
---------------------------------------------------------------------------
P2BodyDist X/Y
P2Dist X/Y
Pos X/Y
Vel X/Y
RootDist X/Y
以上五个trigger都有分X轴和Y轴,千万不要忘掉。
P2BodyDist是指我方与对方的身体边界(人物原点坐标-双方人物宽度)之间的距离,而P2Dist是指我方与对方人物原点坐标之间的
距离。需要注意的是由于人物宽度只有X轴存在,所以P2BodyDist Y = P2Dist Y。Pos是绝对坐标,Vel是速度。RootDist用于
helper与本体之间的距离检测。
---------------------------------------------------------------------------
个数相关
---------------------------------------------------------------------------
NumEnemy
NumHelper
NumProj
NumProjID
敌人个数、援护个数、飞行道具个数、相应飞行道具个数,不予赘述。
---------------------------------------------------------------------------
变量相关
---------------------------------------------------------------------------
Var
FVar
SysVar
SysFVar
四种变量,比较常用的是Var和FVar,直接可以调用,返回相应变量的值。变量的具体使用第6章会讲。
---------------------------------------------------------------------------
状态号相关
---------------------------------------------------------------------------
StateNo
PrevStateNo
除了可以用StateNo直接调查当前状态号,我们还可以用PrevStateNo调查当前状态之前的状态号。
---------------------------------------------------------------------------
比赛相关
---------------------------------------------------------------------------
RoundNo
RoundState
RoundNo是当前局数。RoundState是当前局状态号,0:预开场阶段 ,1:开场阶段 ,2:格斗阶段,3:胜负判定阶段,4:结束阶段。
通常AI能动的是RoundState = 2,胜利挑衅之类的属于RoundState = 3。
---------------------------------------------------------------------------
时间相关
---------------------------------------------------------------------------
Time
AnimTime
Time返回当前动作已经使用时间。而AnimTime返回到动画结束还需要多少时间,其值<=0,当=0时动画结束。
因为绝大多数情况下动画结束就引起状态改变,所以可以用AnimTime探测还有多长硬直时间。
另外需要注意的是,如果对方动作是循环的话(例如KOF人物在空中出招完成后会变成循环的下落的动画),因为动画不会结束所以
返回的是Time的值,其值>0。
---------------------------------------------------------------------------
对方相关
---------------------------------------------------------------------------
P2Life
P2MoveType
P2Name
P2StateNo
P2StateType
其实上述这些只是加了P2作为前缀,变成探测对方。用重定向也有类似的效果。
---------------------------------------------------------------------------
其他
---------------------------------------------------------------------------
AILevel
AI等级,1.0新增的trigger,返回option里面设置的难度,对于做手操整合的朋友可谓是福音。
另外可以用于1.0里面不影响手操的AI常时启动。
Alive
存活,通常AI要求人物要存活才能行动,所以会直接加在triggerall以防非存活继续乱动。
AuthorName
作者名,多与Name配合写人物对策。
CanRecover
判断目前受击状态是否可以受身。
Command
手操指令,辨别手操按键满足cmd里面的某个指令。由于AI是模仿人的操作,所以通常有command的地方都要写AI。
还有很重要的一点,关于command的trigger在AI里面基本是不需要的。
因为这个trigger是用来辨别手操按键是否满足cmd里面的某个指令,然而AI的编写不需要辨别手操按键,所以写AI的时候通常不需
要command。
Const
常量,可以用于调查攻击、防御、行走速度、奔跑速度、Y轴重力加速度等等Cns里面标好的常量。
Ctrl
判断是否可控状态,非取消的切换动作都需要这trigger否则会有BUG,
而且不可控状态乱切换动作是新人常犯的错误(我以前就曾经被这个坑过两回)。
Facing
面向,若游戏者面向右方则返回1,若游戏者面向左方则返回-1。通常用于鉴别双方是否面对面(或背对)。
GetHitVar
获得对象被击中时的数据,例如速度、伤害、硬直等等,可选参数很多,具体请到trigger表查找。
HitCount
当前动作打击次数,多用于写连段时到第几次打击时取消。
ID
每个玩家和援护都会有自己独有的ID,有时候需要记下ID来锁定目标。
IfElse
如果...则...否则...,格式为 ifelse(条件,满足时则XX,否则YY),与if语句比较相似,但是要注意的是必须为两项选其一,
即if和else都不能为空。
InGuardDist
判断是否有能打到自己的攻击判定(例如对方本体攻击或者飞行道具)而且自己处于在防御范围内。很有效的防御时机鉴别。
另外防御范围是一个0~N(N>=0)的范围,所以如果攻击方飞过了你的位置的话,你将检测不了攻击方的攻击判定,利用这个可以做
出打逆的效果(这个后面再说)。
IsHelper
判断是否援护,可以用于防止helper乱动。
Name
多与AuthorName配合写人物对策。
PalNo
色表号,1~12,也就是经常被人说的P数,通过选人时的按键锁决定。
Random
随机数,返回一个0到999之间的随机整数(包含0与999)。很常用的trigger,如果不用随机,人物就是一个只会死板运行的程序,
随机令AI变得多样而丰满。
值得注意的是,每次使用Random时,他都会重新在0到到999之间随机找一个整数,所以不要误以为同一帧里面随机数都是一样的。
---------------------------------------------------------------------------
大概清楚上面的这些基本知识以后就可以开始去拆人物了,翻着两个表慢慢弄清楚人物的结构也是一种学习-w-
===========================================================================
4.3常见错误
===========================================================================
---------------------------------------------------------------------------
常见报错类型
---------------------------------------------------------------------------
在此只讨论AI编写过程中常见错误(路径错误那种不在讨论范围之内)
---------------------------------------------------------------------------
2500 loop / 2500循环:
如果电脑不幸进入了死循环,整个电脑就会掉尽无限的轮回而卡住。
Mugen里面为了避免死循环,Mugen程序限定一帧里面只可以改变状态(Changestate)2500次,若超过则会出现2500 loop报错。
死循环例子:
state A 直接 changestate 到 state A
state A 转到 state B 再转回 state A
....
解决方法:根据返回信息检查代码,找出循环部分并合理排除。
---------------------------------------------------------------------------
Type mismatch detected / 种类不匹配:
数据分很多种类,我们Mugen里面通常用到的是数字。而数字也分很多种,例如整型int,浮点型float。
种类不匹配错误通常出现在把浮点型数据和整型数据的不适当使用,例如:
trigger1 = 2.5 % 2用浮点型数据进行只适用整型数据的运算
trigger2 = Var(0) := 1.2把浮点型数据赋值给整型变量Var
...
解决方法:根据返回信息找出错处,用ceil和floor对其取整,或者赋值时用浮点型变量FVar。
---------------------------------------------------------------------------
Need at least 1 trigger / 至少一个触发器
除了忘了写以外,只有triggerall一样会报错。记得至少要有一个数字trigger。
---------------------------------------------------------------------------
Invalid trigger / 触发器无效
Library error message: Died parsing / 错误信息:语法分析错误
除了你打错字的可能性以外,不兼容的语句也可能出现这个问题。
例如在Winmugen里面用1.0代码,比如AIlevel。
若是使用Winmugen,trigger一行有字数限制,trigger写得过长也有可能出现该错误,所以注意及时换行。
---------------------------------------------------------------------------
Error while precaching / 预缓存时错误
打开人物读取数据时发生的错误,多数是打错字或者语法不对,根据返回信息应该比较容易检查出来。
未完待续(欢迎提供各种AI常见报错)
===========================================================================
课后作业:
1.
以下这段语句是什么意思
[State 200, 7]
type = ChangeState
trigger1 = AnimTime = 0
value = 0
ctrl = 1
2.
以下是KFM的[Statedef 240],请解释为什么出招之后人物会有向前的位移。
[State 240, 1]
type = PlaySnd
trigger1 = Time = 2
value = 0, 1
[State 240, 2]
type = HitDef
trigger1 = Time = 0
attr = S, NA
animtype = Medium
damage = 63
guardflag = MA
pausetime = 12,12
sparkno = 1
sparkxy = -10,-60
hitsound = 5,2
guardsound = 6,0
ground.type = Low
ground.slidetime = 12
ground.hittime = 15
ground.velocity = -6
air.velocity = -2.2,-3.2
[State 240, 3]
type = PosAdd
trigger1 = AnimElem = 7
x = 12
[State 240, 4]
type = ChangeState
trigger1 = AnimTime = 0
value = 0
ctrl = 1
3.
在data文件夹里默认common1.cns里的[Statedef 5120](倒地起身动作)有以下描述,请解释这三段是什么意思:
[State 5120, 3]
type = NotHitBy
trigger1 = 1
value = SCA
time = 1
[State 5120, 5] ;Can't be thrown right after getting up
type = NotHitBy
trigger1 = AnimTime = 0
value = , NT,ST,HT
time = 12
[State 5120, 6] ;Can't be hit right after getting up (short time)
type = NotHitBy
trigger1 = AnimTime = 0
value2 = SCA
time = 3
4.
请写出怎么知道对方剩下多少%的血量。
5.
请写出如何令人物常时满气。
6.
请写出每两帧触发一次的trigger,并类推出如何令人物每X帧恢复Y点血量。
提示:使用gametime(自己查表)和取余运算(忘记怎么用的话看上一章)
以上教程由口水轩撰写