Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

物理の紹介

ゲーム開発では、多くの場合、ゲーム内の2つのオブジェクトが交差または接触するタイミングを知る必要があります。これは衝突検出として知られています。衝突が検出された場合、通常は何かが発生します。これは衝突応答として知られています。

Godotは、衝突の検出と応答の両方を提供するために、2Dおよび3Dで多数のコリジョン(衝突)オブジェクトを提供します。プロジェクトに使用するものを決定しようとすると、混乱する可能性があります。それぞれがどのように機能し、その長所と短所が何であるかを理解すれば、問題を回避して開発を簡素化できます。

このガイドでは、次の内容について学習します:

  • Godotの4つのコリジョンオブジェクトタイプ

  • 各コリジョンオブジェクトの仕組み

  • 別のタイプよりもあるタイプを選択するべきタイミングと理由

注釈

このドキュメントの例では、2Dオブジェクトを使用します。すべての2D物理オブジェクトとコリジョン形状は3Dでもまったく同等であり、ほとんどの場合、ほぼ同じように機能します。

オブジェクトのコリジョン

Godotは4種類のコリジョンオブジェクトを提供しており、それらは全てCollisionObject2Dを継承しています。リストの下の3つは物理ボディで更にPhysicsBody2Dを継承しています。

  • Area2D

    Area2D ノードは 検出影響 を提供します。オブジェクトの重なり合いを検出し、物体が出入りするときにシグナルを発することができます。`` Area2D`` を使用して、定義された領域で重力や減衰などの物理特性をオーバーライドすることもできます。

  • StaticBody2D

    静的ボディとは、物理エンジンによって動かされないものです。コリジョン検出に参加しますが、衝突に応じて移動しません。これらは、環境の一部であるオブジェクトや動的な動作を必要としないオブジェクトに最もよく使用されます。

  • RigidBody2D

    これはシミュレーションされた2D物理を実装するノードです。RigidBody2Dを直接操作するのではなく、代わりに力(重力、衝撃など)を加えて物理エンジンがその結果の動きを計算します。 rigid body の使用についてより詳しくはここを参照してください。

  • CharacterBody2D

    コリジョン検出を提供しますが、物理は提供しません。すべての移動および衝突応答はコードで実装する必要があります。

物理マテリアル

StaticBodyとRigidBodyはPhysicsMaterialを使うように設定できます。これにより、オブジェクトの摩擦や跳ね返りを調整したり、吸収性やざらつきを設定することができます。

コリジョン形状

物理ボディは、任意の数の Shape2D オブジェクトを子として保持できます。これらの形状は、オブジェクトのコリジョン境界を定義し、他のオブジェクトとの接触を検出するために使用されます。

注釈

コリジョンを検出するには、少なくとも1つの Shape2D をオブジェクトに割り当てる必要があります。

シェイプを割り当てる最も一般的な方法は、CollisionShape2D または CollisionPolygon2D をオブジェクトの子として追加することです。これらのノードを使用すると、エディタのワークスペースでシェイプを直接描画できます。

重要

エディタでコリジョン形状をスケーリングしないように注意してください。インスペクタの”Scale”プロパティは (1, 1) `` のままにしてください。コリジョン形状のサイズを変更するときは、\ ``Node2D スケールハンドルではなく、常にサイズハンドルを使用する必要があります。シェイプをスケーリングすると、予期しない衝突が発生する場合があります。

../../_images/player_coll_shape1.webp

物理プロセスのコールバック

物理エンジンは固定レート(デフォルトは60回/秒)で動作します。このレートは通常、フレームレートとは異なります。フレームレートは描画内容や利用可能なリソースに応じて変わります。

物理関連のコードはすべてこの固定レートで実行されることが重要です。そのためGodotはアイドル処理と物理処理を区別しています。フレームごとに実行されるコードはアイドル処理と呼ばれ、物理Tickごとに実行されるコードは物理処理と呼ばれます。Godotは2つの異なるコールバックを提供します。

物理コールバックのNode._physics_process()は、各物理ステップの前に呼び出されます。ボディのプロパティにアクセスする必要があるコードはここで実行されるべきです。このメソッドにはdeltaパラメーターが渡されます。このパラメーターは、最後のステップからの経過時間を単位の浮動小数で表したものです。デフォルトの60Hzの物理演算の更新レートを使用する場合、通常は0.01666...になります(ただし、常にそうなるわけではありません)。

注釈

プレーヤーのデバイスが更新レートを維持できない場合でも状態の変更が適切に物理計算に反映されるように、常に delta パラメーターを使うことを推奨します。

コリジョンレイヤーとマスク

最も強力ですが、誤解されることが多い衝突機能の1つが、コリジョンレイヤーシステムです。このシステムによりさまざまなオブジェクト間の複雑な相互作用を構築できます。重要な概念はレイヤーマスクです。各CollisionObject2Dは、32の異なる物理レイヤーを持っていて、相互作用を設定できます。

各プロパティを順番に見てみましょう:

  • collision_layer

    これは、オブジェクトが in で表示されるレイヤーを記述します。デフォルトでは、すべてのボディはレイヤー 1 上にあります。

  • collision_mask

    これは、ボディが衝突を スキャン するレイヤーを記述します。オブジェクトがマスクレイヤーのいずれかにない場合、ボディはそれを無視します。デフォルトでは、すべてのボディがレイヤー 1 をスキャンします。

これらのプロパティは、コードを介して、またはインスペクタで編集して構成できます。

Keeping track of what you're using each layer for can be difficult, so you may find it useful to assign names to the layers you're using. Names can be assigned in Project Settings > Layer Names > 2D Physics.

../../_images/physics_layer_names.webp

GUIの例

ゲームには、Walls、Player、Enemy、およびCoinの4つのノードタイプがあります。 PlayerとEnemyの両方がWallsと衝突するはずです。 PlayerノードはEnemyとCoinの両方との衝突を検出する必要がありますが、EnemyとCoinは互いに無視する必要があります。

レイヤー1〜4に"walls"、"player"、"enemies"、"coins"という名前を付けて開始し、"Layer" プロパティを使用して各ノードタイプをそれぞれのレイヤーに配置します。次に、相互作用するレイヤーを選択して、各ノードの"Mask"プロパティを設定します。たとえば、プレイヤーの設定は次のようになります:

../../_images/player_collision_layers.webp ../../_images/player_collision_mask.webp

コード例

関数呼び出しでは、レイヤーはビットマスクで指定されます。関数がデフォルトで全レイヤーを有効にする場合、レイヤーマスクは 0xffffffff になります。レイヤーマスクには、2進数、16進数、10進数表記を使用できます。

上記の1,3,4番目のレイヤーが有効な場合の、同等なコード例は次のようになります:

# Example: Setting mask value for enabling layers 1, 3 and 4

# Binary - set the bit corresponding to the layers you want to enable (1, 3, and 4) to 1, set all other bits to 0.
# Note: Layer 32 is the first bit, layer 1 is the last. The mask for layers 4,3 and 1 is therefore
0b00000000_00000000_00000000_00001101
# (This can be shortened to 0b1101)

# Hexadecimal equivalent (1101 binary converted to hexadecimal)
0x000d
# (This value can be shortened to 0xd)

# Decimal - Add the results of 2 to the power of (layer to be enabled - 1).
# (2^(1-1)) + (2^(3-1)) + (2^(4-1)) = 1 + 4 + 8 = 13
pow(2, 1-1) + pow(2, 3-1) + pow(2, 4-1)

You can also set bits independently by calling set_collision_layer_value(layer_number, value) or set_collision_mask_value(layer_number, value) on any given CollisionObject2D as follows:

# Example: Setting mask value to enable layers 1, 3, and 4.

var collider: CollisionObject2D = $CollisionObject2D  # Any given collider.
collider.set_collision_mask_value(1, true)
collider.set_collision_mask_value(3, true)
collider.set_collision_mask_value(4, true)

Export annotations can be used to export bitmasks in the editor with a user-friendly GUI:

@export_flags_2d_physics var layers_2d_physics

Additional export annotations are available for render and navigation layers, in both 2D and 3D. See ビットフラグのエクスポート.

Area2D

エリア(Area)ノードは 検出 および 影響 を提供します。オブジェクトの重なり合いを検出し、物体が出入りするときにsシグナルを発します。エリアは、定義されたエリアで重力や減衰などの物理特性をオーバーライドするためにも使用できます。

Area2D には主に3つの用途があります:

  • 特定の領域での物理パラメーター(重力など)のオーバーライド。

  • 他のボディが領域に出入りするとき、または現在どのボディが領域にあるかを検出します。

  • 他の領域のオーバーラップを確認します。

デフォルトでは、エリアはマウスとタッチスクリーンの入力も受け取ります。

StaticBody2D

静的(Static)ボディとは、物理エンジンによって動かされないものです。コリジョン検出に参加しますが、衝突に応じて移動しません。ただし、constant_linear_velocity および constant_angular_velocity プロパティを使用して、衝突している物体に動きや回転をあたかも移動しているかのように伝えることができます。

StaticBody2D ノードは、環境の一部であるか、動的な動作を必要としないオブジェクトに最もよく使用されます。

StaticBody2D の使用例:

  • プラットフォーム(移動プラットフォームを含む)

  • コンベヤベルト

  • 壁やその他の障害物

RigidBody2D

これは、シミュレートされた2D物理を実装するノードです。RigidBody2D を直接制御することはできません。代わりに、それに力を適用し、物理エンジンは、他のボディとの衝突、跳ね返り、回転などの衝突応答を含む結果の動きを計算します。

You can modify a rigid body's behavior via properties such as "Mass", "Friction", or "Bounce", which can be set in the Inspector.

The body's behavior is also affected by the world's properties, as set in Project Settings > Physics, or by entering an Area2D that is overriding the global physics properties.

リジッドボディが静止していて、しばらく動かない場合、スリープ状態になります。眠っている体は静的な体のように動作し、その力は物理エンジンによって計算されません。衝突またはコードを介して力が加えられると、ボディが起動します。

RigidBody2Dを使用する

リジッドボディを使用する利点の1つは、コードを記述せずに多くの動作を「無料」で行えることです。たとえば、落下するブロックを持つ「Angry Birds」スタイルのゲームを作成している場合、RigidBody2Dを作成してプロパティを調整するだけで済みます。スタッキング、落下、および跳ね返りは、物理エンジンによって自動的に計算されます。

However, if you do wish to have some control over the body, you should take care - altering the position, linear_velocity, or other physics properties of a rigid body can result in unexpected behavior. If you need to alter any of the physics-related properties, you should use the _integrate_forces() callback instead of _physics_process(). In this callback, you have access to the body's PhysicsDirectBodyState2D, which allows for safely changing properties and synchronizing them with the physics engine.

たとえば、"Asteroids(Atariのゲーム)"スタイルの宇宙船のコードは次のとおりです:

extends RigidBody2D

var thrust = Vector2(0, -250)
var torque = 20000

func _integrate_forces(state):
    if Input.is_action_pressed("ui_up"):
        state.apply_force(thrust.rotated(rotation))
    else:
        state.apply_force(Vector2())
    var rotation_direction = 0
    if Input.is_action_pressed("ui_right"):
        rotation_direction += 1
    if Input.is_action_pressed("ui_left"):
        rotation_direction -= 1
    state.apply_torque(rotation_direction * torque)

linear_velocity または angular_velocity プロパティを直接設定するのではなく、力(`` thrust`` および torque)をボディに適用し、物理エンジンに結果の動きを計算させることに注意してください。

注釈

リジッドボディがスリープ状態になると、_integrate_forces() 関数は呼び出されません。この振る舞いをオーバーライドするには、コリジョンを作成するか、それに力を加えるか、can_sleep プロパティを無効にすることで、ボディを起こしたままにする必要があります。これはパフォーマンスに悪影響を及ぼす可能性があることに注意してください。

接触のレポート

By default, rigid bodies do not keep track of contacts, because this can require a huge amount of memory if many bodies are in the scene. To enable contact reporting, set the max_contacts_reported property to a non-zero value. The contacts can then be obtained via PhysicsDirectBodyState2D.get_contact_count() and related functions.

シグナルによる接触の監視は、contact_monitor プロパティを使用して有効にできます。使用可能なシグナルのリストについては、RigidBody2D を参照してください。

CharacterBody2D

CharacterBody2D bodies detect collisions with other bodies, but are not affected by physics properties like gravity or friction. Instead, they must be controlled by the user via code. The physics engine will not move a character body.

When moving a character body, you should not set its position directly. Instead, you use the move_and_collide() or move_and_slide() methods. These methods move the body along a given vector, and it will instantly stop if a collision is detected with another body. After the body has collided, any collision response must be coded manually.

Character collision response

After a collision, you may want the body to bounce, to slide along a wall, or to alter the properties of the object it hit. The way you handle collision response depends on which method you used to move the CharacterBody2D.

move_and_collide

move_and_collide() を使用すると、関数は KinematicCollision2D オブジェクトを返します。このオブジェクトには、コリジョンと衝突するボディに関する情報が含まれます。この情報を使用して、応答を判別できます。

たとえば、衝突が発生した空間内のポイントを検索する場合:

extends PhysicsBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        var collision_point = collision_info.get_position()

または、衝突するオブジェクトから跳ね返るには:

extends PhysicsBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        velocity = velocity.bounce(collision_info.get_normal())

move_and_slide

スライディングは一般的な衝突応答です。トップダウンゲームで壁に沿って移動するプレイヤー、またはプラットフォーマーで坂を上下に走るプレイヤーを想像してください。move_and_collide() を使用した後、この応答を自分でコーディングすることは可能ですが、move_and_slide() は、多くのコードを書かずにスライド移動を実装する便利な方法を提供します。

警告

move_and_slide() automatically includes the timestep in its calculation, so you should not multiply the velocity vector by delta. This does not apply to gravity as it is an acceleration and is time dependent, and needs to be scaled by delta.

たとえば、次のコードを使用して、地面(坂を含む)に沿って歩き、地面に立っているときにジャンプできるキャラクターを作成します:

extends CharacterBody2D

var run_speed = 350
var jump_speed = -1000
var gravity = 2500

func get_input():
    velocity.x = 0
    var right = Input.is_action_pressed('ui_right')
    var left = Input.is_action_pressed('ui_left')
    var jump = Input.is_action_just_pressed('ui_select')

    if is_on_floor() and jump:
        velocity.y = jump_speed
    if right:
        velocity.x += run_speed
    if left:
        velocity.x -= run_speed

func _physics_process(delta):
    velocity.y += gravity * delta
    get_input()
    move_and_slide()

move_and_slide() の使い方に関する詳細については、詳細なコードを含むデモプロジェクトを含んだ キネマティックキャラクター(2D) を参照してください。