Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

キネマティックキャラクター(2D)

はじめに

はい、奇妙な名前に聞こえますね。「キネマティック・キャラクター」それは、何ですか?名前の理由は、物理エンジンが出てきたときに、それらが(主に衝突応答を扱ったため)「ダイナミクス」エンジンと呼ばれたからです。ダイナミクスエンジンを使ってキャラクターコントローラーを作ろうとする試みは数多く行われましたが、思ったほど簡単ではありませんでした。Godotには、(2d/platformerのデモで見ることができるように)色々と発見できるダイナミックキャラクターコントローラーの最高の実装の1つがありますが、それを使用するには、かなりのレベルのスキルと物理エンジンの理解(または試行錯誤の忍耐)が必要です。

Havokなどの一部の物理エンジンは、最適なオプションとしてダイナミックキャラクターコントローラーに誓いをたてているように見えますが、他の物理エンジン(PhysX)は、むしろキネマティックコントローラーを促進します。

だから、違いは何ですか?:

  • ダイナミックキャラクターコントローラーは、無限慣性テンソルを持つリジットボディを使用します。 回転できないリジットボディです。 物理エンジンは常にオブジェクトの移動と衝突を許可し、その後、すべて一緒に衝突を解決します。これにより、ダイナミックキャラクターコントローラーは、プラットフォーマーデモで見られるように、他の物理オブジェクトとシームレスに対話できます。 ただし、これらの相互作用は常に予測できるとは限りません。 衝突は解決するために複数のフレームを必要とする可能性があるため、いくつかの衝突はわずかにずれているように見える場合があります。 これらの問題は修正できますが、ある程度のスキルが必要です。

  • キネマティックキャラクターコントローラーは、常に非衝突状態で始まり、常に非衝突状態に移行すると想定されています。 衝突状態で開始した場合、リジットボディのように自身を解放しようとしますが、これは例外であり、ルールではありません。 これにより、制御と動作がより予測可能になり、プログラムが簡単になります。 ただし、欠点としては、コードで手動で行わない限り、他の物理オブジェクトと直接やり取りすることはできません。

This short tutorial focuses on the kinematic character controller. It uses the old-school way of handling collisions, which is not necessarily simpler under the hood, but well hidden and presented as an API.

Physics process

キネマティックボディまたはキャラクターのロジックを管理するには、常に物理プロセスを使用することをお勧めします。これは、物理ステップの前に呼び出され、その実行が物理サーバーと同期しているため、常に毎秒同じ回数とも呼ばれるためです。 これにより、通常のプロセスを使用するよりも物理学と動きの計算が予測可能な方法で機能します。フレームレートが高すぎたり低すぎたりするとスパイクが発生したり、精度が低下したりします。

extends CharacterBody2D

func _physics_process(delta):
    pass

シーンの設定

To have something to test, here's the scene (from the tilemap tutorial): kinematic_character_2d_starter.zip. We'll be creating a new scene for the character. Use the robot sprite and create a scene like this:

../../_images/kbscene.webp

CollisionShape2Dノードの横に警告アイコンがあります。 それは、形状を定義していないためです。 CollisionShape2Dのshapeプロパティで新しいCircleShape2Dを作成します。 <CircleShape2D>をクリックしてオプションに移動し、半径を30に設定します:

../../_images/kbradius.webp

注: 物理のチュートリアルで前述したように、物理エンジンはほとんどの種類の形状のスケールを処理できないため(コリジョンポリゴン、プレーン、セグメントのみが機能します)、シェイプのパラメーター(半径など)を拡大縮小するのではなく、常に値を変更してください。スケールが形状のスケールに影響するため、同じことがキネマティック/リジッド/スタティックボディ自体にも当てはまります。

ここで、キャラクターのスクリプトを作成します。上記の例として使用したスクリプトがベースとして機能するはずです。

最後に、タイルマップでそのキャラクターシーンをインスタンス化し、マップシーンをメインのシーンにします。再生を押すと実行されます。

../../_images/kbinstance.webp

キネマティック キャラクタの移動

Go back to the character scene, and open the script, the magic begins now! Kinematic body will do nothing by default, but it has a useful function called CharacterBody2D.move_and_collide(). This function takes a Vector2 as an argument, and tries to apply that motion to the kinematic body. If a collision happens, it stops right at the moment of the collision.

それでは、スプライトが床に当たるまで下に移動しましょう:

extends CharacterBody2D

func _physics_process(delta):
    move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame

その結果、キャラクターは移動しますが、床に当たるとすぐに停止します。 かなりクールですね?

次のステップでは、ミックスに重力を追加します。これにより、通常のゲームキャラクターのように動作します:

extends CharacterBody2D

const GRAVITY = 200.0

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    var motion = velocity * delta
    move_and_collide(motion)

これでキャラクターがスムーズに落ちます。 方向キーをタッチして、左右に歩いてみましょう。(少なくとも速度の場合)使用されている値はピクセル/秒であることに注意してください。

This adds basic support for walking when pressing left and right:

extends CharacterBody2D

const GRAVITY = 200.0
const WALK_SPEED = 200

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    if Input.is_action_pressed("ui_left"):
        velocity.x = -WALK_SPEED
    elif Input.is_action_pressed("ui_right"):
        velocity.x =  WALK_SPEED
    else:
        velocity.x = 0

    # "move_and_slide" already takes delta time into account.
    move_and_slide()

そして、それを試してみてください。

これはプラットフォーマーにとって良い出発点です。 より完全なデモは、エンジンとともに配布されるデモzip、または https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character にあります。