[GameMaker: Studio] Physicsのおさらい・その2

今回はオブジェクトのPhysics Propertiesについておさらいしてみます。

gms_physics_properties_1


■Collision Shape

当たり判定の形状です。これはわかりますね。
設定できるのは形状のみで、があると正しく動作しないということに注意してください。


■Density

物体の密度です…とだけ書かれていることが多くて、具体的にどう設定していいのか悩んでる方もいるかと思います。

ここには現実の物質密度をそのまま入れるだけで、ほとんどの場合、正しく計算されます。
悩んだら英語版ウィキペディアのDensityの項にある「ρ(kg/m3)」の数値を入れてみましょう。
ただし値は1/1000です。
https://en.wikipedia.org/wiki/Density#Various_materials

たとえばプラスティックなら1175なので、GM:Sでは1.175と入力します。

この値に0を設定すると静的物体(Static Object)となり、そのオブジェクトはその場に固定されます。
phy_position_x/yを書き換えて直接移動させたい場合にも0を設定します。
静的物体の詳細は後述のKinematicの項で説明します。

ちなみに、0以外は動的物体(Dynamic Object)と呼ばれます。


■Restitution

物体同士が当たった際の反発力です。設定値は0.0~1.0です。
当たったときの力(勢い)を反射方向にどれくらい与えるか…というような感じです。
1.0にするとほぼ勢いは失われずに反射します。

これは互いの設定値のうち、もっとも大きな値が採用されるようで、0.8と0.5が当たった場合はどちらも0.8の力で反射します。


■Friction

ちょっと順番を飛ばします。
これは物体同士の摩擦力です。設定値は0.0~1.0です。
1.0に近いほど急ブレーキがかかり、0.0なら当たったことによる抵抗はないということになります。

摩擦は反発と異なり、お互いの設定値の中央値(?)となるようです。
0.8と0.5が当たった場合は0.63です。
ただし、いずれかが0.0の場合は結果は0.0となります。


■密度と反発と摩擦のサンプル

GM:Sでは「材質が○○ならこの値はこう」といった推奨値が示されていません。
他のツールでは、たとえばCarraraではサンプルとしてこの画像のようにパラメーターが設定されています。
Carraraの物理演算エンジンはBox2DではなくBulletですが、物理演算の名が示すように基本となる物体の設定は現実に則したものなので参考になるでしょう。

gms_physics_properties_3


■Linear Damping / Angular Damping

反発と摩擦は物体同士が当たった際の計算に使われるものでしたが、こちらは他の物体には関係なく、単独での空間に対する抵抗力になります。
空気抵抗のようなものだと思ってください。

Linearは移動、Angularは回転の減衰力で、大きいな値ほど止まる力も大きくなります。

設定値は0.0~無限ですが、Box2Dの公式マニュアルでは0.0~0.1の範囲に収めるように書かれています。
0.0にすると他の物体に当たらない限り止らなくなります。


■Collision Group

当たり判定をグループ分けするための設定です。
これは少々複雑です。

値が0の場合、Collisionイベントが設定されていないと判定は行われずにすり抜けます。

値が1以上のプラス(正)値では、同じグループの物体のみ判定が行われます。
グループ1とグループ1は当たりますが、グループ1とグループ2は当たりません。ただしこれは、Collisionイベントが設定されていない場合に限ります。
Collisionイベントが設定されている場合は他のグループであっても、そのCollisionイベントの対象と判定が行われます。

値が-1以下のマイナス(負)値では逆に、同じグループの物体とは当たりません。
Collisionイベントが設定されていない場合は他のグループとも当たりません。
つまりすべてすり抜けます。

マイナス値を設定する場合は基本的にCollisionイベントを設定して使用します。
Collisionイベントの対象の他のオブジェクトとは当たりますが、自分と同じタイプのオブジェクトとは当たらないというわけです。
これはシューティングゲームの弾のようなもので使用できるでしょう。


■Sensor

オブジェクトをセンサーオブジェクトに設定します。
センサーにするとCollisionイベントは発生しますが物体はすり抜けます。

これはPhysicsの当たり判定は行いたいけど衝突によって動かしたくはない…という場合に使用します。
たとえばアクションゲームのチェックポイント等に使えます。


■Kinematic

これはちょっと特殊な設定で、移動可能な静的物体を作るときに使用します。

まず注意点ですが、Kinematicをオンにする場合は必ずDensityは0にしてください。
Densityに0以外が設定されていると、内部ではKinematicはオフとして演算されてしまいます。

公式の説明では「Density=0の静的物体は固定されているため動かすことができないが、Kinematicをオンにすることで動かすことができる」というようなことが書いてありますが、実際のところDensity=0でKinematic=オフでもphy_speed_x/yphy_position_x/y等で自由に動かすことができてしまいます。

ではKinematicで何が変るのでしょうか?

次の図を見てください。

gms_physics_properties_4

基本的にはDensity=0の静的物体はphysics_apply_***系の関数では動かすことはできず、phy_***系のプロパティで直接コントロール可能なのですが、phy_angular_velocityだけは例外でKinematicがオフの場合は設定が無視されます。

Kinematicがオンの場合はphy_angular_velocityで回転ができますが、phy_fixed_rotation=trueでも回転は止まりません。

このようにKinematicの設定による影響はごく僅かで、それも完全に制御下に置かれた状態なので、「自分で動かしたい静的物体」は無条件にKinematic=オンで良いかと思います。

ちなみに静的物体はphy_***系のプロパティ以外に、Pathで動かすこともできます。
Pathで動かす場合もKinematicのオン/オフの違いはないようです。

Kinematicのオン/オフに関わらず、Density=0の静的物体同士は当たり判定が発生しないことにも注意してください。
たとえば、Density=0の固定された地面とDensity=0の動く床が接触してもそのまますり抜け、collisionイベントも発生しません。


■Start Awake

通常のPhysicsオブジェクトは、room開始と同時に演算も始まりますが、Start Awakeをオンにすることで、room開始時の演算を無効にすることができます。

他の物体と接触したり何らかの力をかけることで、演算が開始されます。

これは崖の途中にある岩なんかで使えます。
岩は始めは謎のバランスでその場に止まっていますが、上から落ちてきた小石が当たった瞬間に落下を始める…といったようなことができます。


■phy_bullet

これはオブジェクトパネルからは設定できませんが、重要なのでここで説明しておきます。

通常の物理オブジェクトはお互いが接触した場合のみイベントが発生します。

しかし、弾丸のような小さなオブジェクトが超高速に移動して薄い物体に接近した場合、1回の計算における移動量が薄い物体の幅を超えてしまい、結果的にすり抜けてしまいます。

phy_bullet=trueにすると前回の座標から計算後の座標の間に他の物体がないかという判定を行うようになるため、すり抜けが発生しなくなります。

ただし、計算量が増加するため特に必要がない限りはオフのままが良いでしょう。


■physics_world_update_speed / physics_world_update_iterations

これは本当は前回説明するべきでしたが、すっかり忘れてました。

physics_world_update_speedは1秒あたりの処理回数を設定します。
通常はroom speed(fps)と同じ値になっています。
room speed=30でphysics_world_update_speed=30なら、物理演算の処理はstep毎に1回ずつ行われます。

しかしレースゲームの車のように高速で移動する物体は、1/30秒では移動量が多すぎて他の物体にめり込んでしまうこともあるでしょう。
そのような場合にphysics_world_update_speed=60のように大きな値を設定します。
room speed=30でphysics_world_update_speed=60なら、物理演算の処理はstep毎に2回ずつ行われるので、1回の移動量は1/60秒分なのでめり込む確率も下がるというわけです。

physics_world_update_iterationsは演算精度に関する設定です。
物理演算は内部でいくつもの反復処理を行って少しずつ精度を高めていきますが、その反復回数の上限値を変更することができます。

初期値は10で、高いほど高精度で高負荷となります。
この値は5~30の範囲に収めることが推奨されています。
当たり方や反射の仕方に違和感があれば1ずつ上げ、逆に負荷が高いと感じたら1ずつ下げて最適な値を見つけると良いでしょう。