研究資料1号:重力計算汎用テンプレート(2010/12/26 加筆・修正)


重力計算はいろいろな所で解説されていますが、
そのまま記述に転用できるテンプレートがあまりないので作ってみました。
本サイト公開のアナザーブラッドで使用している記述を、汎用に書き直したものです。

リダイレクトには、EnemyNear,の代わりにEnemy(var(1)),を使用しています(参照:AI研究資料室)。
相手の重力の取得は、平易にする為にConst(movement.yaccel)のみを使用しています。
また、計算用にfvar(0)〜fvar(3)を一時的に使用しています。
これらは状況に応じて、書き換えて使用してください。


まず、空中の相手に対して歩いて近付き、
距離(Enemy(var(1)),Dist X)がD1(近)〜D2(遠)、高さ Enemy(var(1)),Pos Y)がH1(低)〜H2(高)の範囲に対して
Tフレーム目に攻撃発生する技を当てられるかどうかを判断します。


[State -1, 重力計算・追い討ち可否判断]
type = VarSet
triggerall = !IsHelper && var(59) > 0;Helperによる実行の防止、AIフラグONの確認
triggerall = Enemy(var(1)),Alive;死体殴り禁止
triggerall = Enemy(var(1)),Const(movement.yaccel) != 0;相手の重力が0だとエラーが出るので防止
triggerall = Enemy(var(1)),StateType = A && Enemy(var(1)),MoveType = H
triggerall = Enemy(var(1)),GetHitVar(fall) && Enemy(var(1)),HitShakeOver;HitShakeOverはお好みで
;triggerall = !EnemyNear,GetHitVar(fall.recover);相手が受身不能の場合(使用するかどうかはお好みで)
triggerall = StateType != A;使用する技の条件に合わせて書き換えてください
triggerall = fvar(0) := Enemy(var(1)),Pos Y+H1+EnemyNear,Const(mid.pos.y) || 1;mid.pos.yは攻撃位置の微調整
triggerall = fvar(1) := Enemy(var(1)),Pos Y+20 || 1;Pos Yが-20以上だと地上受身が取れるキャラがいるので除外
triggerall = fvar(1) := fvar(fvar(0)>fvar(1)) || 1
triggerall = fvar(1) := fvar(1)/Enemy(var(1)),Const(movement.yaccel)*2 || 1
triggerall = fvar(1) := (Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)**2/4-fvar(1) || 1
triggerall = fvar(1) := Abs(fvar(1))**0.5 || 1
triggerall = fvar(1) := Ceil(fvar(1)-(Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)/2 || 1
triggerall = fvar(1) := fvar(1)-(ID<Enemy(var(1)),ID)-1) || 1
triggerall = fvar(0) := Enemy(var(1)),Pos Y+H2+EnemyNear,Const(mid.pos.y) || 1;mid.pos.yは攻撃位置の微調整
triggerall = fvar(0) := fvar(0)/Enemy(var(1)),Const(movement.yaccel)*2 || 1
triggerall = fvar(0) := (Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)**2/4-fvar(0) || 1
triggerall = fvar(0) := Abs(fvar(0))**0.5 || 1
triggerall = fvar(0) := Ceil(fvar(0)-(Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)/2 || 1
triggerall = fvar(0) := fvar(0)-(ID<Enemy(var(1)),ID)-1) || 1
trigger1 = fvar(0) < fvar(1) && fvar(0) >= T
trigger1 = fvar(2) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(0)-(Enemy(var(1)),ID<ID)) || 1
trigger1 = fvar(2) := fvar(2)-(Const(velocity.walk.back.x)*Const(movement.stand.friction))*(fvar(0)+(Enemy(var(1)),ID<ID)-T) || 1
trigger1 = fvar(2) >= D1 || BackEdgeBodyDist < 1
trigger1 = fvar(3) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(0)-(Enemy(var(1)),ID<ID)) || 1
trigger1 = fvar(3) := fvar(3)-(Const(velocity.walk.fwd.x)*Const(movement.stand.friction))*(fvar(0)+(Enemy(var(1)),ID<ID)-T) || 1
trigger1 = fvar(3) <= D2+Enemy(var(1)),Const(size.air.front);size.air.front は攻撃位置の微調整
trigger2 = fvar(1) >= T
trigger2 = fvar(2) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(1)-(Enemy(var(1)),ID<ID)) || 1
trigger2 = fvar(2) := fvar(2)-(Const(velocity.walk.back.x)*Const(movement.stand.friction))*(fvar(1)+(Enemy(var(1)),ID<ID)-T) || 1
trigger2 = fvar(2) >= D1
trigger2 = fvar(3) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(1)-(Enemy(var(1)),ID<ID)) || 1
trigger2 = fvar(3) := fvar(3)-(Const(velocity.walk.fwd.x)*Const(movement.stand.friction))*(fvar(1)+(Enemy(var(1)),ID<ID)-T) || 1
trigger2 = fvar(3) <= D2+Enemy(var(1)),Const(size.air.front);size.air.front は攻撃位置の微調整

var(XX) = X;空いている変数を適当に使用してください

式自体は複雑ですが、使用する攻撃技のデータをはめ込むだけなので、扱いは楽だと思います。
この後は、ここで変更した変数を参照し、歩いて距離を調整するステートを組めばOKです。
Const(velocity.walk.fwd.x)の部分を変更すれば、ダッシュでの接近や飛び道具による追い討ちなどにも対応できます。

fvar(0)はH2(高)の高さを相手が通過するまでの時間を、
fvar(1)はH1(低)の高さを相手が通過するまでの時間を算出します。
また、
fvar(2)はそれぞれの時間を目一杯後退に費やした場合の最終的な相手との距離を、
fvar(3)はそれぞれの時間を目一杯前進に費やした場合の最終的な相手との距離を算出します。
野球に例えると、フライが落ちてくるまでに走って追いつけるかどうかを判断している訳ですね。

相手と自分のIDを比較しているのは、処理順を確認するためです。
自分よりも相手の方が処理が早い場合、相手のデータ更新が1フレーム分早くなってしまうので対策しています。
攻撃位置の微調整については、相手の当たり判定の大きさを考慮しての余裕です。
X方向のくらい判定は押し合い判定の幅程度はあるだろう、
空中での喰らい判定は立ち状態での体中心付近の高さ程度には浮いているだろうという予測によるものです。
ですので、この辺はお好みでさじ加減を変えてもまったく問題ありません。

ちなみに、相手が高度-20に落下してくる地点を算出するステートは、以下のようになります。


[State -1, 敵落下位置までの距離]
type = VarSet
trigger1 = Enemy(var(1)),Const(movement.yaccel) != 0
trigger1 = fvar(0) := Enemy(var(1)),Pos Y+20 || 1
trigger1 = fvar(0) := fvar(0)/Enemy(var(1)),Const(movement.yaccel)*2 || 1
trigger1 = fvar(0) := (Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)**2/4-fvar(0) || 1
trigger1 = fvar(0) := Abs(fvar(0))**0.5 || 1
trigger1 = fvar(0) := Ceil(fvar(0)-(Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)/2 || 1
trigger1 = fvar(0) := fvar(0)-(ID<Enemy(var(1)),ID)-1) || 1
trigger2 = Enemy(var(1)),Vel Y != 0 && Enemy(var(1)),Const(movement.yaccel) = 0
trigger2 = fvar(0) := Ceil((Enemy(var(1)),Pos Y+20)/Enemy(var(1)),Vel Y-(ID<Enemy(var(1)),ID)) || 1
trigger3 = Enemy(var(1)),Vel Y = 0 && Enemy(var(1)),Const(movement.yaccel) = 0
trigger3 = fvar(0) := 9999 || 1
fvar(0) = Enemy(var(1)),Dist X - Enemy(var(1)),Vel X * fvar(0)



次に、歩いて近付いた後の攻撃の為のステートです。
トリガーを変更すれば、空中の敵に対して普通に攻撃を振る時などにも使用できます。


[State -1,重力計算・追い討ち実行]
Type = ChangeState
value = XXXX
triggerall = !IsHelper && var(59) > 0;Helperによる実行の防止、AIフラグONの確認
triggerall = var(XX) = X;上記で変更した変数を参照(不要なら削ってください)
triggerall = Enemy(var(1)),Alive;死体殴り禁止
triggerall = Enemy(var(1)),Const(movement.yaccel) != 0;相手の重力が0だとエラーが出るので防止
triggerall = Enemy(var(1)),StateType = A && Enemy(var(1)),MoveType = H
triggerall = Enemy(var(1)),GetHitVar(fall) && Enemy(var(1)),HitShakeOver;HitShakeOverはお好みで
;triggerall = !EnemyNear,GetHitVar(fall.recover);相手が受身不能の場合(使用するかどうかはお好みで)
triggerall = StateType != A;使用する技の条件に合わせて書き換えてください
triggerall = fvar(0) := Enemy(var(1)),Pos Y+H1+EnemyNear,Const(mid.pos.y) || 1;mid.pos.yは攻撃位置の微調整
triggerall = fvar(1) := Enemy(var(1)),Pos Y+20 || 1;Pos Yが-20以上だと地上受身が取れるキャラがいるので除外
triggerall = fvar(1) := fvar(fvar(0)>fvar(1)) || 1
triggerall = fvar(1) := fvar(1)/Enemy(var(1)),Const(movement.yaccel)*2 || 1
triggerall = fvar(1) := (Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)**2/4-fvar(1) || 1
triggerall = fvar(1) := Abs(fvar(1))**0.5 || 1
triggerall = fvar(1) := Ceil(fvar(1)-(Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)/2 || 1
triggerall = fvar(1) := fvar(1)-(ID<Enemy(var(1)),ID)-1) || 1
triggerall = fvar(0) := Enemy(var(1)),Pos Y+H2+EnemyNear,Const(mid.pos.y) || 1;mid.pos.yは攻撃位置の微調整
triggerall = fvar(0) := fvar(0)/Enemy(var(1)),Const(movement.yaccel)*2 || 1
triggerall = fvar(0) := (Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)**2/4-fvar(0) || 1
triggerall = fvar(0) := Abs(fvar(0))**0.5 || 1
triggerall = fvar(0) := Ceil(fvar(0)-(Enemy(var(1)),Vel Y/Enemy(var(1)),Const(movement.yaccel)*2+1)/2 || 1
triggerall = fvar(0) := fvar(0)-(ID<Enemy(var(1)),ID)-1) || 1
trigger1 = T = [fvar(0),fvar(1)] || T = [fvar(1),fvar(0)]
trigger1 = fvar(2) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(T-(Enemy(var(1)),ID<ID)) || 1
trigger1 = fvar(2) = [D1,D2+Enemy(var(1)),Const(size.air.front)];size.air.front は攻撃位置の微調整
trigger2 = fvar(1) = T
trigger2 = fvar(0) < T || BackEdgeBodyDist < 1

ちなみに、一般的な飛び道具で追い討ちする場合はこんな感じになります(trigger1以降)
T1は飛び道具の発生時間、T2は飛び道具の消滅時間、Vは飛び道具の速度です。


trigger1 = fvar(0) < fvar(1) && fvar(0) = [T1,T2]
trigger1 = fvar(2) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(0)-(Enemy(var(1)),ID<ID)) || 1
trigger1 = fvar(2) := fvar(2)-Const(velocity.walk.back.x)*Const(movement.stand.friction)*(fvar(0)-T1) || 1
trigger1 = fvar(2) >= D1 || BackEdgeBodyDist < 1
trigger1 = fvar(3) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(0)-(Enemy(var(1)),ID<ID)) || 1
trigger1 = fvar(3) := fvar(3)-V*(fvar(0)-T1) || 1
trigger1 = fvar(3) <= D2+Enemy(var(1)),Const(size.air.front)
trigger2 = fvar(1) = [T1,T2]
trigger2 = fvar(2) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(1)-(Enemy(var(1)),ID<ID)) || 1
trigger2 = fvar(2) := fvar(2)-Const(velocity.walk.back.x)*Const(movement.stand.friction)*(fvar(1)-T1) || 1
trigger2 = fvar(2) >= D1 || BackEdgeBodyDist < 1
trigger2 = fvar(3) := Enemy(var(1)),Dist X-Enemy(var(1)),Vel X*(fvar(1)-(Enemy(var(1)),ID<ID)) || 1
trigger2 = fvar(3) := fvar(3)-V*(fvar(1)-T1) || 1
trigger2 = fvar(3) <= D2+Enemy(var(1)),Const(size.air.front)

参考:クリエイターズJAPAN2様



MUGEN研究所へ戻る
MENUへ戻る