Godotでパララックススクロールを実装する方法

パララックススクロールは、多くの2Dゲームが奥行き感を演出したり、ゲームの背景に視覚的な興味を加えたりするために使用している手法です。カメラの動きに対して背景の異なるレイヤーを異なる速度で動かすことで効果が得られます。

Godot 4では、パララックススクロールの実装がこれまで以上に簡単になりました。強力な2Dエンジンにはパララックスレイヤーのサポートが組み込まれているため、最小限の手間で素晴らしい視覚効果を作成できます。

Godotゲームの設定

まず、Godotゲームエンジンで新しい2Dプロジェクトを作成し、プレイヤーキャラクターでゲームシーンを設定します。

この記事で使用されているコードは、このGitHubリポジトリで入手でき、MITライセンスに基づいて無料で使用できます。

この例では、プレイヤーの移動のためにCharacterBody2Dノードを追加します。また、長方形の形状を持つCollisionShape2Dと、プレイヤーキャラクターを表すSprite2Dを追加します。

extends CharacterBody2D
var speed = 200
func _physics_process(delta):
    var velocity = Vector2()
    if Input.is_action_pressed('ui_right'):
        velocity.x += 1
    if Input.is_action_pressed('ui_left'):
        velocity.x -= 1
    if Input.is_action_pressed('ui_down'):
        velocity.y += 1
    if Input.is_action_pressed('ui_up'):
        velocity.y -= 1
    velocity = velocity.normalized() * speed
    move_and_collide(velocity * delta)

このコードを使用すると、プレイヤーキャラクターは矢印キーまたは同様の入力を使用して左右上下に移動できます。

ParallaxLayerノードを使用して異なるレイヤーを作成する

次に、複数のParallaxLayerノードをシーンに追加して、パララックス効果を作成します。各ParallaxLayerは、背景の異なるレイヤーを表します。説得力のあるパララックス効果を実現するには、カメラから離れたレイヤーは、より近いレイヤーよりもゆっくりと移動する必要があります。

ParallaxLayerCollisionShape2Dを持つStaticBody2Dノードを追加して、背景に衝突可能なオブジェクトを作成します。これらの衝突可能なオブジェクトはプレイヤーや他のゲーム要素と相互作用し、ゲームプレイに奥行きを加えます。

衝突可能なオブジェクトでパララックスレイヤーを作成するためのGDScriptコードを次に示します。

extends ParallaxBackground
func _ready():
    # 最初のParallaxレイヤーを作成
    var layer1 = ParallaxLayer.new()
    layer1.motion_scale = Vector2(0.2, 0.2)
    add_child(layer1)
    # 最初のレイヤーにCollisionShape2Dを持つStaticBody2Dを追加
    var static_body1 = StaticBody2D.new()
    layer1.add_child(static_body1)
    var collision_shape1 = CollisionShape2D.new()
    var shape1 = RectangleShape2D.new()
    shape1.extents = Vector2(32, 32)
    collision_shape1.shape = shape1
    static_body1.add_child(collision_shape1)
    # 2番目のParallaxレイヤーを作成
    var layer2 = ParallaxLayer.new()
    layer2.motion_scale = Vector2(0.5, 0.5)
    add_child(layer2)
    # 2番目のレイヤーにCollisionShape2Dを持つStaticBody2Dを追加
    var static_body2 = StaticBody2D.new()
    layer2.add_child(static_body2)
    var collision_shape2 = CollisionShape2D.new()
    var shape2 = RectangleShape2D.new()
    shape2.extents = Vector2(64, 64)
    collision_shape2.shape = shape2
    static_body2.add_child(collision_shape2)
    # 3番目のParallaxレイヤーを作成
    var layer3 = ParallaxLayer.new()
    layer3.motion_scale = Vector2(1.0, 1.0)
    add_child(layer3)
    # 3番目のレイヤーにCollisionShape2Dを持つStaticBody2Dを追加
    var static_body3 = StaticBody2D.new()
    layer3.add_child(static_body3)
    var collision_shape3 = CollisionShape2D.new()
    var shape3 = RectangleShape2D.new()
    shape3.extents = Vector2(128, 128)
    collision_shape3.shape = shape3
    static_body3.add_child(collision_shape3)

このコードを使用すると、各パララックスレイヤーに、背景の衝突可能なオブジェクトを表すCollisionShape2Dを持つStaticBody2Dノードが含まれるようになります。

これらの衝突可能なオブジェクトは、プレイヤーのキャラクターや他のゲーム要素と相互作用し、ゲームプレイに奥行きと複雑さを加えます。

異なる速度で異なるレイヤーを移動する

パララックスレイヤーの設定が完了したら、プレイヤーの移動に基づいて位置を更新する必要があります。これにより、カメラに近いレイヤーが離れたレイヤーよりも速く移動するパララックス効果が作成されます。

次のGDScriptコードをプレイヤーシーンに追加します。

extends CharacterBody2D
func _physics_process(delta):
    ...
    move_and_collide(velocity * delta)
    # プレイヤーの移動に基づいてパララックスレイヤーを更新
    var parallax_background = get_parent()
    var motion = -velocity * delta
    parallax_background.set_scroll_offset(parallax_background.scroll_offset + motion)

このコードは、プレイヤーの移動に基づいてパララックスレイヤーの動きを計算し、ParallaxBackgroundノードのスクロールオフセットをそれに応じて更新します。レイヤーがプレイヤーの移動とは逆の方向に移動するように、負号を使用することに注意してください。

ランダムなパララックススクロールで予測不可能性を追加する

ランダムなパララックススクロールは、ゲームの背景に驚きと予測不可能性の要素をもたらします。ゲームプレイ中にパララックスレイヤーを動的に生成して配置することで、プレイヤーにより魅力的でダイナミックな体験を作成できます。

ランダムなパララックススクロールを実装するには、ランダムなモーションスケールと位置を持つ新しいパララックスレイヤーを追加します。

extends ParallaxBackground
const MAX_LAYERS = 5
const MIN_SCALE = 0.2
const MAX_SCALE = 1.5
const MIN_SPEED = 0.01
const MAX_SPEED = 0.03
const MIN_X_POSITION = -500
const MAX_X_POSITION = 500
const MIN_Y_POSITION = -300
const MAX_Y_POSITION = 300
func _ready():
    for i in range(MAX_LAYERS):
        create_random_layer()
func create_random_layer():
    # ランダムなモーションスケールを持つ新しいパララックスレイヤーを追加
    var layer = ParallaxLayer.new()
    var scale = lerp(MIN_SCALE, MAX_SCALE, randf())
    layer.motion_scale = Vector2(scale, scale)
    var x_position = randf_range(MIN_X_POSITION, MAX_X_POSITION)
    var y_position = randf_range(MIN_Y_POSITION, MAX_Y_POSITION)
    layer.global_transform.origin.x = x_position
    layer.global_transform.origin.y = y_position
    add_child(layer)
    # 新しいレイヤーにCollisionShape2Dを持つStaticBody2Dを追加
    var static_body = StaticBody2D.new()
    layer.add_child(static_body)
    var collision_shape = CollisionShape2D.new()
    var shape = RectangleShape2D.new()
    shape.extents = Vector2(32, 32)
    collision_shape.shape = shape
    static_body.add_child(collision_shape)
func remove_random_layer():
    # ランダムなパララックスレイヤーを削除
    if get_child_count() > 0:
        var random_index = randi() % get_child_count()
        var layer_to_remove = get_child(random_index)
        remove_child(layer_to_remove)

このコードは、パララックスレイヤーのランダム性を制御するための定数を定義します。lerp関数を使用して、MIN_SCALEMAX_SCALEの間の値を補間し、新しいレイヤーごとにランダムなモーションスケールを生成します。この関数は次のシグネチャを持ちます。

Variant lerp ( Variant from, Variant to, float weight )

randf()からの結果を重みとして渡すことで、ランダムなスケールを持つレイヤーを生成できます。

randf_range関数は、範囲内でランダムな値を生成する別の方法を提供します。ここでは、create_random_layer関数は、指定された範囲内で新しいレイヤーのランダムな位置を生成するために使用します。

var x_position = randf_range(MIN_X_POSITION, MAX_X_POSITION)

デモゲームは、次のようになります。

追加機能を含める

パララックススクロールは、プラットフォーマーゲームの視覚的な魅力を高めるための確固たる基盤を提供しますが、追加の機能を組み込むことでさらに向上させることができます。考慮すべきアイデアをいくつか紹介します。

背景オブジェクト

浮遊プラットフォーム、移動する障害物、アニメーション化された背景キャラクターなど、パララックスレイヤーにインタラクティブな要素をさらに作成します。これらのオブジェクトは、プラットフォーマーゲームに奥行きとインタラクティビティを追加できます。

動的ライティング

パララックスレイヤーに動的ライティング効果を導入します。光源と影を追加することで、ゲームの世界にリアリズムと奥行き感を作成できます。Godotのライティングシステムは2Dゲームでうまく機能し、視覚品質を大幅に向上させることができます。

パーティクル効果

微妙な視覚効果を追加するために、パララックスレイヤーにパーティクルシステムを統合します。落葉、漂う雲、輝く星は、雰囲気を高め、ゲームの世界をより生き生きとさせることができます。また、著作権フリーのサウンドエフェクトをゲームに追加することもできます。

昼夜サイクル

ゲーム内の時間に基づいてパララックスレイヤーの色と強度を変更する昼夜サイクルを実装します。この動的な機能により、プレイヤーはゲームを進めるにつれて常に変化する体験を提供できます。

パララックススクロールを実装するためのベストプラクティス

パララックススクロールはゲームのビジュアルを向上させることができますが、スムーズで楽しい体験を保証するためにいくつかのベストプラクティスに従うことが重要です。

パフォーマンスの最適化

パララックスレイヤーの数とその複雑さに注意してください。レイヤーが多すぎたり、解像度の高いアセットが多すぎると、特に性能の低いデバイスではパフォーマンスの問題が発生する可能性があります。アートワークを最適化し、可能な限り単純な衝突形状を使用してください。

レイヤーの配置

パララックスレイヤーを慎重に配置します。ビジュアル階層と目的の奥行き効果を考慮してください。カメラに近いレイヤーはより速く移動する必要がありますが、離れたレイヤーはより遅く移動する必要があります。

カメラの境界

プレイヤーがゲームの世界の端に到着したときに不要な空きスペースや視覚的なグリッチを防ぐために、カメラの移動に境界を設定します。これにより、プレイヤーにシームレスな体験が保証されます。

テストと調整

さまざまなデバイスと画面サイズでパララックススクロールをテストして、さまざまなプラットフォームで適切に表示され、動作することを確認します。モーションスケール、レイヤーの位置、およびその他のパラメータを調整することで、パララックス効果を微調整して最高の結果を得ることができます。

パララックススクロールでGodotゲームをより魅力的にする

ランダムなパララックススクロールを追加することで、Godotゲームのエンゲージメントレベルを大幅に向上させることができます。ランダムなパララックススクロールには、ゲームプレイ中にパララックスレイヤーを動的に生成して配置することが含まれます。

これにより、背景に動きと躍動感を持たせ、ゲームの世界を生き生きと予測不可能なものにします。プレイヤーは常に変化する視覚的な環境を体験し、ゲームの楽しさにさらなる層が加わります。