mieki256's diary



2020/11/17(火) [n年前の日記]

#1 [godot] Godot Engineでダメージエフェクトを作成

Godot Engine 3.2.3 x64 を使って3D表示の簡単なシューティングゲームっぽいものを作る。

今回は、プレイヤーや敵に弾が当たったことを分かりやすくするために簡単なダメージエフェクトをつけてみる。

プレイヤーの点滅表示処理を追加。 :

やはりアクションゲームの類で自機がダメージを受けたら点滅するものだろう。って一体いつの時代の話ですか…昭和か…。何にせよ、とりあえず点滅表示処理を追加してみる。

プレイヤーのシーン、res://assets/Player.tscn を開いて、Timer を2つ追加。DmagaeTimer と BlinkTimer にリネーム。

3d_tuto12_create_damage_effect_ss01.png


DamageTimer には、ダメージを受けてから何秒間はダメージを受けないかを指定。
  • Wait Time を 2 に。
  • One Shot を有効化。

3d_tuto12_create_damage_effect_ss02.png


BlinkTimer には、表示と非表示を切り替える時間間隔を指定。
  • Wait Time を 0.05 に。

3d_tuto12_create_damage_effect_ss03.png


それぞれの timeoutシグナルにメソッドを接続してやる。
  1. DmagaeTimer や BlinkTimer を選んでから、ノードタブをクリック → シグナルをクリック。
  2. timeout を右クリックして「接続」。
  3. Player を選んで「接続」。
プレイヤーのスクリプトファイル、res://scripts/Player.gd に、_on_DamageTimer_timeout() と _on_BlinkTimer_timeout() の2つのメソッドが追記される。

スクリプトファイル Player.gd に処理を追加。内容は以下。今回の処理に関係があるところだけ貼っておく。

_Player.gd
# ...

var damaging = false

func _ready():
    # ...

    damage = 0
    damaging = false

    # ...

func _physics_process(delta):

    # ...

    if not damaging:
        if damage > 0:
            hp -= damage
            damage = 0
            if hp <= 0:
                hp = 0
            emit_signal("player_damaged")
            damaging = true
            $DamageTimer.start()
            $BlinkTimer.start()

# ...

func _on_DamageTimer_timeout():
    $BlinkTimer.stop()
    damage = 0
    damaging = false
    visible = true
    if hp <= 0:
        hp = 0
        emit_signal("player_died")

func _on_BlinkTimer_timeout():
    visible = not visible

  • ダメージ中を示すフラグ、damaging を用意。
  • ダメージ中は、自分がダメージを受けたかどうかは判定しない。
  • ダメージを受けたら、ダメージ中フラグを立ててから、$DamageTimer.start()、$BlinkTimer.start() を呼んで、2つの Timer を開始させる。
  • BlinkTimer は指定した時間間隔で timeoutシグナルを何度も繰り返し発行する。そのたびに _on_BlinkTimer_timeout() が呼ばれる。このメソッドの中で、visibleプロパティを反転させて、表示と非表示を切り替えている。
  • DmagaeTimer は指定時間が経過すると timeoutシグナルを1回だけ発行。_on_DamageTimer_timeout() が呼ばれる。BlinkTimerを停止させて、ダメージ中フラグを降ろして、表示を有効化。

これで、プレイヤーに敵弾が当たってダメージを受けると一定時間点滅するようになった。

画面フラッシュを追加。 :

プレイヤーに弾が当たると点滅するようになったけど、これではまだダメージを受けたことが伝わりにくいので、画面を軽くフラッシュさせてみる。

フラッシュさせるためのノードは、HUDシーンに追加する。res:/assets/Hud.tscn を開く。

ColorRectノードを追加。ColorRectノードは指定色で矩形を描画できる。

3d_tuto12_create_damage_effect_ss04.png


Flash にリネーム。

3d_tuto12_create_damage_effect_ss05.png


Flash (ColorRect) のプロパティを変更。
  • Color を RGBA=(255, 255, 255, 200) に。
  • Size x, y を (1280, 720) に。ゲームウインドウ全体を覆いつくすサイズを指定。

3d_tuto12_create_damage_effect_ss05b.png


Timer を追加。FlashTimer にリネーム。この Timer を使って、一定時間が過ぎたらフラッシュ状態を終了させる。

3d_tuto12_create_damage_effect_ss06.png


FlashTimer のプロパティを変更。
  • Wait Time を 0.125 に。0.125秒だけ Flash を表示させる。
  • One Shot を有効化。

3d_tuto12_create_damage_effect_ss08.png


FlashTimer の timeoutシグナルにメソッドを接続。
  1. FlashTimer を選択してから、ノードタブをクリック → シグナルをクリック。
  2. timeout を右クリックして「接続」。
  3. Hud を選択して「接続」。
res://scripts/Hud.gd に、_on_FlashTimer_timeout() が追記される。

Flash の表示順を変更。ノード一覧の一番上に置くことで、HP表示より奥に表示されるようにする。

3d_tuto12_create_damage_effect_ss07.png


HUDシーンのスクリプト、res://scripts/Hud.gd を修正。内容は以下。

_Hud.gd
# ...

func _ready():
    $Flash.visible = false

# ...

func start_flash():
    $Flash.visible = true
    $FlashTimer.start()
    
func _on_FlashTimer_timeout():
    $Flash.visible = false

  • 初期化処理時に Flashノードを非表示にする。
  • 画面フラッシュを開始するメソッド、start_flash() を追加。Flashノードの表示を有効化して、FlashTimer を開始している。
  • FlashTimer は指定時間が経過すると timeout シグナルを発行して _on_FlashTimer_timeout() が呼ばれる。Flashノードを非表示にする。

Mainシーンのスクリプト、res://scripts/Main.gd も修正。内容は以下。

_Main.gd
# ...

func damage_player():
    # ...
    $Hud.start_flash()

# ...

  • プレイヤーがダメージを受けると Main.gd内の damage_player() が呼ばれる。その中で $Hud.start_flash() を呼んで Hud の画面フラッシュを開始させる。

これで、プレイヤーに敵弾が当たってダメージを受けると、一瞬画面がフラッシュするようになった。

敵のダメージエフェクトを追加。 :

敵のスクリプト、res://scripts/EnemyZako.gd を修正して、敵がダメージを受けた時のエフェクト(?)を追加する。

今回は、一定時間(0.25秒)、ランダムに位置がぶれる処理を追加してみた。

_EnemyZako.gd
# ...

var damage_timer = 0

var rnd = RandomNumberGenerator.new()

func _ready():
    # ...

    damage = 0
    damage_timer = 0

    # ...

func _physics_process(delta):
    # ...
    check_damage()
    damaging_animation(delta)
    
# ...

func check_damage():
    if damage > 0:
        hp -= damage
        damage = 0
        damage_timer = 0.25
        if hp <= 0:
            hp = 0
            emit_signal("enemy_died")
        emit_signal("enemy_damaged")

func damaging_animation(delta):
    if damage_timer > 0:
        damage_timer -= delta
        var target_mesh = $EnemyZakoModel
        if damage_timer <= 0:
            damage_timer = 0
            target_mesh.translation = Vector3()
        else:
            var r = 0.5
            var x = rnd.randf_range(-r, r)
            var z = rnd.randf_range(-r, r)
            target_mesh.translation = Vector3(x, 0, z)

# ...
            
func _on_EnemyZako_area_entered(area):
    if is_queued_for_deletion():
        return
    # print("playerbullet hit the enemy")
    if area.is_in_group("playerbullets"):
        damage = area.attack_point

# ...


  • var rnd = RandomNumberGenerator.new() で疑似乱数生成器を用意する。
  • rnd.randf_range(-r, r) で、-r から r の範囲で乱数を生成。
  • 自分(EnemyZako)の座標ではなく、その下にぶら下がってる EnemyZakoModel(表示モデルを担当)の位置をずらしている。
  • 時間経過を、Timerノードを使わずにスクリプト内の処理で測っている。

これで、プレイヤーや敵がダメージを受けた時に、少しは見た目で分かりやすくなった…かどうかは怪しいけれど、とりあえず簡易の処理は追加できた。

次回はタイトル画面やゲームオーバー画面を作成してみる。

以上です。

過去ログ表示

Prev - 2020/11 - Next
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project