IKEMEN GOで追加されたZSS(Zantei State Script)とはCNSの代わりに使うことができるステート記述フォーマットのこと。 基本的な構造はCNSと同じだが、文法が大幅に異なる。
CNSの記述はほぼ全てZSSで置き換えることができ、CNSに無い機能としてローカル変数と関数を使うことができる。 以下の特徴に当てはまる人向けの機能。
サンプルとしてcommon1.cns.zssが付属している。元のcommon1.cnsと比較することで理解の助けになるかもしれない。
以下にMUGENのCNSを理解している方に向けた簡単なマニュアルを書いておく。
キャラのdefのCNSファイルを指定する箇所で、ZSSファイルを指定する。
CNSファイルとZSSファイルは同時に読み込むことが可能なので、自由に使い分けよう。
ZSSを記述したファイルの拡張子は.zssで固定。
例:ファイル名
kfm.cns.zss
例:defファイル内([Files]以下)の記述
st = kfm.cns
注意点として、ここでは拡張子(.zss)を省いたファイル名を書くこと。
何故そうする必要があるのかというと、最初にCNSファイルの読み込みを試み、それが失敗した場合にZSSファイルの読み込みを行うという動作になっているため。
CNSファイルの拡張子は固定されておらず自由なので、このようになっている。
文字コードはUTF-8にしておくこと。
ZSSはCNSと同様にStatedefの集まりで構成される。
Statedef定義は[]の中に書き、Statedefオプションもすべてこの中に記述する。
例:CNS
[Statedef 0] type = S physics = S sprpriority = 0
例:ZSS
[Statedef 0; type: S; physics: S; sprpriority: 0;]
値の指定では=の代わりに:を書き、改行の代わりに;を書く。 []で括ればよいので以下のようにも書ける。
[Statedef 0; type: S; physics: S; sprpriority: 0;]
このStatedef定義の下にコードを書いていく。
ステートコントローラ名{パラメータ名: 値}
の形式で書く。CNSのtriggerはここでは書かない。
例:CNS
[State Sample] type = PosAdd trigger1 = 1 x = 10
例:ZSS
PosAdd{x: 10}
複数パラメータを書く場合は;で区切りを入れる。
例:CNS
[State Sample] type = PosAdd trigger1 = 1 x = 10 y = -10
例:ZSS
PosAdd{x: 10; y: -10}
PosAdd{ x: 10; y: -10; }
パラメータの無いステコンは{}内に何も書かない。
Turn{}
ここまでの例では周囲に何も書いてないのでステコンが毎フレーム実行される記述になる。
そこでZSSではCNSのtriggerの代わりにif文を使う。使い方は一般的なプログラミング言語のif文とだいたい同じ。
if 条件文 { 実行する記述 }
の形式で書く。
例:CNS
[State Sample] type = PosAdd trigger1 = Time = 0 x = 10
例:ZSS
if Time = 0 { PosAdd{x: 10} }
ifの後にtriggerで使うものと同じ条件文を使用する。 条件文の後ろに{}で括った記述を入れたら、{}内の記述は条件が成立している間だけ実行される状態となる。
複数の条件を入れたい時はこんな感じに書ける。
例:CNS
[State Sample] type = PosAdd triggerall = Time = 0 trigger1 = statetype = S trigger2 = statetype = C trigger3 = statetype = L x = 10
例:ZSS
if Time = 0 { if statetype = S || statetype = C || statetype = L { PosAdd{x: 10} } }
if文の{}中にif文を入れて、より複雑な条件を書くことができる。
ifが成立しなかった場合のelseとelseifももちろん使用可能
例:CNS
[State Sample] type = PosAdd triggerall = Time = 0 trigger1 = statetype = S y = -50 [State Sample] type = VelAdd triggerall = Time = 0 trigger1 = statetype = A y = 0.1 [State Sample] type = PosSet triggerall = Time = 0 trigger1 = statetype != S trigger1 = statetype != A y = -20
例:ZSS
if Time = 0 { if statetype = S { PosAdd{y: -50} }else if statetype = A { VelAdd{y: 0.1} }else{ PosSet{y: -20} } }
ヒットポーズを無視させるignorehitpauseと実行フレームの間隔を指定するpersistentはステコン内ではなく、 if文と同様に{}で括って使う。
例:CNS
[State Sample] type = PosAdd trigger1 = 1 x = 10 ignorehitpause = 1
例:ZSS
ignorehitpause { PosAdd{x: 10} }
例:CNS
[State Sample] type = PosAdd trigger1 = 1 x = 10 persistent = 5
例:ZSS
persistent(5) { PosAdd{x: 10} }
※ただしExplodに限りignorehitpauseは任意に指定できる。
もちろんそれぞれ同時に指定可能。複数指定する場合はif文を最後に持ってくること。
例:CNS
[State Sample] type = PosAdd trigger1 = Time = 0 x = 10 ignorehitpause = 1 persistent = 5
例:ZSS
ignorehitpause persistent(5) if Time = 0{ PosAdd{x: 10} }
ZSSではVarsetなどの単純なVar操作ステコンは廃止になっている。
その代わりに:=による代入式でVarを操作する。
CNSのtriggerで書ける代入式と似たような感じ。
例:CNS
[State Sample] type = VarSet trigger1 = 1 var(59) = 1
例:ZSS
var(59) := 1;
例:CNS
[State Sample] type = VarAdd trigger1 = 1 var(59) = 1
例:ZSS
ZSS var(59) := var(59) + 1;
代入式の末尾には;をつけること。
別のキャラにVarを代入したい場合はそのキャラへのリダイレクトを指定する。
例:CNS
[State Sample] type = ParentVarSet trigger1 = 1 var(59) = 1
例:ZSS
Parent,var(59) := 1;
ZSSでは;の代わりに#でコメントになる
定義されたステート内でのみ使うことができ、他のステートには影響を与えない変数。256個まで設定可能。
主にステート内で使い捨てにする変数や、関数の数値受け渡しに使う。
let 変数名 = 値;
の形式で書く。末尾には;をつけること。
例
let RandomValue100 = Random%100;
この値を後で変更したい場合もこれと全く同様に書く。
ローカル変数に値を入れるときの記述は、全てこの形式でよいと覚えておこう。
$変数名
の形式で書く。
上記の例で宣言した変数を参照する場合は
$RandomValue100
と書く。
関数とは処理のひとかたまりのこと。
Statedefとは別の場所にあらかじめ書いておいた処理を、ステート内から個別に呼び出して実行することができる機能。
何度も使う処理を何度も書くのではなく、関数という形に処理を抽象化して呼び出し文だけを何度も書くだけで済ませることができる。 CNSでは実装する機能を複雑にしようとすればするほど記述が煩雑になってしまう問題があるが、ZSSでは関数を使うことによってこれをある程度解消できる。
[Function 関数名()]
の形式で書く。この定義の下に処理を書く点ではStatedef定義と似たような感じ。
例:KO時のボイスを流す関数
[Function PlayKOSound()] PlaySnd{value: 11,0}
引数と返り値を書くこともできるので、それらが必要な場合は
[Function 関数名( 引数名 ) 返り値名] と書く。詳細は下記参照。
call 関数名(); の形式で書く。ステートの中にこれを記述することで、定義した関数を呼び出す。
呼び出せるのは記述ステートより上に書いた関数だけなので、記述する順番に注意。
例:上で書いたKOボイスを流す関数を呼び出す記述
call PlayKOSound();
関数に数値を渡す引数を使う場合は
call 関数名(引数名); と書く。詳細は下記参照。
入力した引数を関数が受け取って処理をすることができる。これによって、数値が違うだけの同じような処理をひとまとめにして書くことができるようになる。
例:上で書いた関数の()の中にボリュームの数値を入れてみる
[Function PlayKOSound(VoiceVolume)] PlaySnd{ value: 11,0; volumescale: $VoiceVolume; }
※受け取った数値は関数内でローカル変数として扱う。
#通常の2倍のボリューム call PlayKOSound(200);
#通常の半分のボリューム call PlayKOSound(50);
引数は複数入力することができる。
例:ボリュームの他に周波数の数値も入れてみる。
[Function PlayKOSound(VoiceVolume, Frequency)] PlaySnd{ value: 11,0; volumescale: $VoiceVolume; freqmul: $Frequency; }
#通常の2倍のボリュームと低音 call PlayKOSound(200, 0.5);
#通常の半分のボリュームと高音 call PlayKOSound(50, 2);
関数定義の際、関数内で使用するローカル変数の一つを返り値に指定しておくことができる。
この返り値は処理が終わった後に関数の呼び出し元に送られる。
ローカル変数宣言に代入する形で返り値を設定した関数を呼ぶと、そのローカル変数に返り値が入る。
例:自身のhelperIDが1から5の時、helperIDの数値が入るローカル変数
[Function IshelperID() ret] let ret = 0; if ishelper(1){ let ret = 1; }else if ishelper(2){ let ret = 2; }else if ishelper(3){ let ret = 3; }else if ishelper(4){ let ret = 4; }else if ishelper(5){ let ret = 5; }
let helperIdValue = call IshelperID();