キャラを製作していると日々発見があります。その中でも目から鱗だったものを書き留めていたのですが、皆さんにも役立つかと思いましたのでここでご紹介します。
なお、間違っている可能性もありますので、実際に自分で確かめてみてください。理解も深まると思います。
もし間違っているものや気付いたことがありましたらBBS等で教えて頂けると助かります。
<09.07.26>"batファイルについて"を修正しました。
<09.11.10>Trigger関連、p2name系についての記述を修正しました。自分がパートナーの位置にいても参考相手は変わりません。
<10.03.07>その他の振り向きに関して、間違えていたようなので削除しました。
<10.06.13>"その他"に"tF後の速度と位置"と"AI暴発の一因"を追加しました。
<10.11.14>"State Controller関連"にFall.〜Velocityが効かない時の対処法を追加、"Trigger関連"のリダイレクトキーワードに追記をしました。
<11.02.03>"State Controller関連"に"処理動作の軽量化とエフェクト化けの防止"、"Trigger関連"に"Triggerの処理順序と代入演算子":=""、"その他"に"固有ゲージ等が画面スクロールについていかない場合の対処法"を追加しました。
≪State Controller関連≫
≪Trigger関連≫
≪その他≫
≪batファイルについて≫
≪State Controller 関連≫
●HitDefは、以下のルールに従う。
1.triggerが1度でも成立すれば、そのState中は継続して起動した状態になる。(hitdefpersistで次のStateに引き継ぐことも可能)
その状態で攻撃判定が出現すれば1回の接触が可能となる。ただしmovetype=Aのときに限る。
2.HitDef内のパラメータに変数が入っている場合、その値はtriggerが成立した時点のものとなる。
3.trigger成立後に再度triggerが成立すると、上書き更新となる。(例えばTime<10だとその間更新され続ける事になる)
・trigger成立 -> 攻撃判定 => 1Hit
・trigger成立 -> 攻撃判定 -> 攻撃判定 => 1Hit
・trigger成立 -> trigger成立 -> 攻撃判定 => 1Hit
・trigger成立 -> 攻撃判定 -> trigger成立 -> 攻撃判定 => 2Hit
必ずしも条件を攻撃判定のある時に設定する必要はないが、変数で直前のデータを参照したい場合などはそうする必要がある。
●ヒットポーズは自分と相手で止まり始める時間が違う。また、movehit系、fall.recovertimeは以下のようにカウントされる。
ex.)pausetime = 5,7 の場合,
time | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | … |
movehit | 0 | 1 | … | 1 | 2 | 3 | 4 | 5 | … | ||
自分 | |-------> | 4| | |||||||||
相手 | |-----------> | 7| | |||||||||
fall.recovertime | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | … | |
相手やられStateのtime | -1 | 0 | 1 | 2 | … |
⇒Down.Bounceを使うべし
"ダウンヒット"の時はfall.xvelocity及びfall.yvelocityが無効となり、同時にdown.〜パラメータが有効になる。
"ダウンヒット"になるのはp2stateno=5100またはp2stateno=5110か5120でPos Y=0の時
"空中ヒット"になるのはp2stateno=5101またはp2stateno=5110か5120でPos Y!=0の時
ただしDown.BounceはDown.Velocity(未設定時はAir.Velocity)のY成分が0の時は無効となるのに注意
⇒StateNo=5101でのHitFallVelが重要
ステコンHitFallVelはFall状態にある時相手のHitDefのFall.〜Velocityパラメータを有効にするというもの
特殊なダウンでない場合は共通のcommon1.cnsにあるように入れておいて欲しい一品
●NotHitByは、S(C,A)と記述するだけで、その後何を書こうと書くまいとS(C,A)全般に対して成立する。HitByは恐らく大丈夫。
ex.)value = S,NP(Sのみでも同様) => 実質S,NA,SA,HA,NT,ST,HT,NP,SP,HP
●同timeでも先に成立したステートコントローラは後のものに影響する。
ex.)以下の順にコントローラがチェックされるとする。
type = Turn, trigger1 = (time = 0) && (p2dist X < 0)
type = Gravity, trigger1 = (time = 0) && (p2dist X < 0)
p2dist X = -50で通過したとき、Gravity時点では条件がp2dist X = 50と変わる為、Gravityは実行されない。
因みにこの場合p2dist Xは符号が変わるだけだが、p2bodydist Xだと双方の基本設定のsizeが値に影響するので注意。
●処理動作の軽量化とエフェクト化けの防止
Helper,OwnPal,AddAlphaは使うと処理が重くなる。
OwnPal=1のエフェクトを沢山使う場合は、OwnPal=1のHelperからOwnPal=0のHelper,なるべくならExplodを出すとかなり違う。
ただしこの時、親Helperの消えるタイミングに注意しないと相手のエフェクトに化けてしまう事がある。
Helper(ownpal=1) ------------> 消去
=>Explod or Helper(ownpal=0) --> 相手に同じAnim番号があった場合に化ける
上のように、ownpal=0のExplodやHelperは親Helperが消えた瞬間相手のエフェクトに化ける可能性がある。
このような場合は、親Helperを消すタイミングを遅くしたり、その中での最長Fを持つAnimを親Helperにしたりすると良い。
ちなみに親Helperがownpal=0の場合はこの限りではないので、親HelperにAnimを表示させないのも手かもしれない。
≪Trigger関連≫
≪その他≫
≪batファイルについて≫
≪Trigger関連≫
●movehit系は自分、numtargetは相手に依存する
・movehit系は基本的にはそのステートが終わるまで持続(movehitpersistを使って引き継ぐ事も可能)。
これは相手のmovetypeがHでなくなっても続く。
・numtargetはp2movetype!=Hになるまで持続。
これはその後helperやタッグメンバーの攻撃が当たっても、自分がどんな状態でも持続する。
●文字列を含む式を否定する時は注意。TeamMode,HitDefAttr,AuthorNameの場合は全体にかける。nameとp2name系は!=でも認識。
ex.)trigger1 = Enemy,TeamMode != Turns ×
trigger1 = !(Enemy,TeamMode = Turns) ○
●Survivalモードでは相手が2人でもTeamModeはTurnsと認識される。よって戦っている人数を知りたいだけならNumEnemyを使う方が吉。
また、同モードでは戦闘終了後、RoundState=0,NumEnemy=0の状態になる為、Enemy系を使用する際は、後述の様にNumEnemyを置いておく方がよい。
自身が2P側の場合も考慮すると、自分の側を参照する際もNumPartnerが便利。
●Triggerの処理順序と代入演算子":="
ステコン内のTriggerが以下の様に並んでいるとすると、処理順はA>B>C>D>E>Fとなる。A>B>C>D>A>B>E>Fではないのに注意。(ex1)
それから、Triggerの途中で偽(0)となった場合はそれ以降の同番号Triggerは読まれない。(ex2)
また、Triggerが成立した場合、それ以降の番号のTriggerは読まれない。これはNullでも同様。(ex3)
ex1) |
triggerall = A @ triggerall = B ↓ trigger1 = C A trigger1 = D ↓ trigger2 = E B正 trigger2 = F ↓ |
triggerall = A @B誤 triggerall = B ↓↓ trigger1 = C A trigger1 = D ↓ trigger2 = E C誤 trigger2 = F ↓ |
ex2) |
triggerall = A triggerall = B trigger1 = 0 trigger1 = D trigger2 = E trigger2 = F |
triggerall = 0 triggerall = B trigger1 = C trigger1 = D trigger2 = E trigger2 = F |
ex3) |
trigger1 = A} trigger1 = B}偽 trigger2 = C} trigger2 = D}真⇒ステコン成立 trigger3 = E} trigger3 = F}読まれない |
|
代入演算子":="はVarSet等を用いずその場でVarに値を代入できる。
trigger1 = fvar(10) := 4.5 ←fvar(10)に4.5を代入
trigger1 = var(5) := var(5)+1 ←var(5)に+1(VarAddと同じ効果)
以上を踏まえて間違え易い例をあげると、
ex4) | 次のステコンは実行されるか?また、最終的なvar(0)の値は? | ||||
triggerall = var(0) := 1 trigger1 = var(0) := 2 trigger1 = var(0) := 0 trigger1 = var(0) := 3 trigger2 = var(0) = 0 trigger3 = var(0) := 4 |
⇒ |
triggerall = var(0) := 1 trigger1 = var(0) := 2 trigger1 = var(0) := 0 trigger1 = var(0) := 3 trigger2 = var(0) = 0 trigger3 = var(0) := 4 |
@ A ↓ ↓ B C |
←以降も読ませたい場合はvar(0) := 0 || 1とすると良い 代入値が0になりそうな時は注意 ←Nullを使う時など、trigger3以降も読ませたい場合は この後にtrigger2 = 0を挟むと良い |
まず基本的な処理順序は番号の通り。そしてここで注意したいのは代入する値が0でも偽となって、それ以降が読まれないこと。
よってTrigger1の時点ではステコンは実行されない。
ただしその行自体は読まれて代入も行われるので、Bの時点ではvar(0)=0となっている。
trigger2 = var(0) = 0となっているがこれは真となるのでこのステコンは実行される事になる。
また、trigger2の時点でステコンが実行される為trigger3以降は読まれないので、最終的なvar(0)の値は0。
●リダイレクトキーワード(※)を使用する際は、エラーの温床になり易いので、それらが存在するかを確認する癖を付けておきたい。
確認の際にはリダイレクトキーワードより前に行う。これらを守らないとエラーメッセージが出る。
また、RootはParentが消失すると参照できなくなるようなので注意が必要。
ex.)Targetが存在しないとき,
@ trigger1 = Target,Vel X < 0 ⇒エラー
A trigger1 = Target,Vel X < 0
trigger1 = NumTarget
⇒エラー(上の行が先に処理される為)
B trigger1 = NumTarget
trigger1 = Target,Vel X < 0
⇒正解(NumTarget=0の場合,その行以降は処理されない為)
C trigger1 = NumTarget&&(Target,Vel X < 0)
⇒エラー(同行ではNumTarget=0でも処理が止まらない為)
ただしCのような時でもこれがHelperで、ゲージ等で常に1つ以上Helperが存在している場合は下記の様に同列に書く事ができる。
trigger1 = NumHelper(1000) && Helper(1000*(NumHelper(1000)>0)),MoveHit > 1
※Enemy,EnemyNear,Partner,PlayerID,Target,Helper,Parent,Rootのこと
●Enemy、p2系について
・enemy(0)は相手側先頭プレイヤー、enemy(1)は相手側パートナーを指す(index省略時は0(enemy=enemy(0)))。
・enemynear(0)は直近、enemynear(1)は2番目に近い相手を指す(index省略時は0)。
自分の向いている方向に依らない=相手との絶対距離で認識。
相手のLifeが0になっても直近であればそちらを認識。
・p2〜のトリガーはenemynearと同様。ただし生きている相手のみ認識、かつtypeがplayerのhelperも認識する。
・p2name系は以下のようになる。
p1name: 自身、p2name: 相手側先頭プレイヤー、p3name: パートナー、p4name: 相手側パートナー
●p2bodydist Xは、p2dist Xから基本データにある自分と相手の前方の幅を引いたもの。
●"AnimElem = N"は"AnimElemTime(N) = 0"と等価, "AnimElemTime(N) >= 0 && AnimElemTime(N+1) < 0"ではないのに注意
●Randomは、同じtimeや行にあってもそれぞれ個別の値をとる。
ex.)type = VarSet, v = 1, value = Random (※簡略化しています)
trigger1 = (var(2):=Random) +1 <= varにRandomを代入しています。+1は条件式を0にしない為。
trigger1 = (var(3):=Random)*(var(4):=Random) +1
var(1)〜var(4)には各々異なる値が入る。
≪State Controller関連≫
≪その他≫
≪batファイルについて≫
≪その他≫
●int同士の剰余はint、floatが入るとfloatとなる。intの値を使うときは要注意。
また、エラーが出るので、var(fvar)等に入れる値は、最終的にそれに合った型(int(float))になるようにしておくこと。
ex.)const(data.defence) = 60 のとき
100.0/const(data.defence) = 1.666667
100/const(data.defence) = 1 <= 小数点以下は切捨てとなる
●fall.defence_upはGetHitVar(fallcount)>=1の時に掛かる。
TargetState等でデフォルトの共通ステートにない落下をしたりすると、fallcountにはカウントされないのに注意。
防御力 = defence*(100+fall.defence_up)/100
●デフォルトのガードではなぜか上を押したままだと機能しないので、cmdファイル内に改めて書いておく。
●ブロッキング等の扱い(攻撃側)
Hさん、586さんキャラ => !movecontact, movereversed, !numtarget
悪咲3号さんキャラ => !movehit, moveguarded, !movereversed, numtarget(一瞬)
如月銃駆さん、漆黒さんキャラ => movehit, !moveguarded, !movereversed, !numtarget
これらから、相手のブロッキング等を感知するには(movecontact||movereversed)&&!numtargetでいいと思われる。
ただし上も含めて一部キャラを調べただけなので、あしからず。
●tF後の速度と位置
<VelAddの場合>
初期位置:Xo, 初速度:Vo, 加速度:a とすると、
V = Vo +a*t
X = Xo +Vo*t +0.5*a*t^2 -0.5*a*t
^はMUGENでは**で表される。MUGENでは1F毎の増加で連続性が無い為、通常の式と少し違う事に注意。
<VelMulの場合>
初期位置:Xo, 初速度:Vo, 乗算速度:r とすると、
V = Vo*r^t
X = Xo +Vo*(1-r^t)/(1-r) ,(r≠1)
なお、同フレーム内でも処理順によって参照できる値が異なってくるので注意。
因みにP2Dist Xよりも、Facing*(Enemy,Pos X-Pos X)の方が端数まで正確に参照できる。
●AI暴発の一因
相手にステートを奪われている時及び戻ったすぐのステート(相手のcmdのbuffer.time分?)ではコマンドが正常に読まれないため、これがAI起動用コマンドと重なると暴発する。
対処法としては、起動させる記述を-3ステートに置くのに加えて、戻ってすぐのステートである事をVarなどを用いて認識させる事が必要。
●固有ゲージ等が画面スクロールについていかない場合の対処法(扇奈の刹月華やアル・アジフのレムリア・インパクトなど)
=>HelperやExplodのSuperMoveTime及びPauseMoveTimeを最大の2147483647にするべし。
この最大というのも重要。PauseMoveTimeはPauseの時間分ではなくExplodやHelperが発生(ステコンの実行)してからの時間分有効と言う事に注意。
≪State Controller関連≫
≪Trigger関連≫
≪batファイルについて≫
≪batファイルについて≫
キャラをテストする時、いちいち本体を立ち上げていては時間がかかってしまいます。
そこで、batファイルというものを作ります。アドオンを使用するときなどに使われていたりするものです。
メモ帳などで開くと大抵こんな感じになっていると思います。
winmugen -r MFJ
これで、MFJフォルダ内のsystem.defを使ってwinmugen.exeを起動することになります。
ここに設定を加えていきます。
winmugen -r MFJ -p1 Kyoudou_Senna -p2 Aselia -s ggxx_paris
これで、"Kyoudou_Senna"と"Aselia"が"ggxx_paris.def"のステージで対戦するという設定です。
winmugen -r MFJ -p1 Kyoudou_Senna -p1.color 7 -p2 Aselia -p2.color 4 -s ggxx_paris
カラーパレットの設定もできます。
このように付け加えていきます。下記はそのオプションの一部です。
ほかも見たい場合は、わざと記述を間違えて起動すれば説明が見られます。
-p2.ai 1 |
: 2PにAIを付けます。"ai 0"の場合は無効になりますが、ctrl+2でAIを起動できます(通常起動時にも使用できます)。 |
::training winmugen -p1 "Kendo&Kyudo" -p1.color 2 -p2 kyoudou_senna -p2.color 7 -s cfj_Training -r MFJ -nomusic ::ggxx_paris ::winmugen -p1 aselia -p1.color 4 -p1.ai 0 -p2 105THchars_M/meiling.def -p2.ai 1 -p2.color 12 -rounds 5 -s ggxx_paris -r MFJ ::SDX_MARX ::winmugen -p1 tiki -p1.ai 0 -p2 patchouli -p2.ai 1 -p3 aselia -p3.ai 1 -p4 len -p4.ai 1 -s ../Nstages/SDX_MARX -r MBC |