mieki256's diary



2020/04/02(木) [n年前の日記]

#1 [godot] Godot Engineで弾を撃つ

Godot Engine でプレイヤーの弾を撃つ処理をどう書けばいいのか悩んでいたのだけど。公式ドキュメントのFPS関連チュートリアル記事を眺めて、なんとなく分かってきた。環境は、Windows10 x64 1909 + Godot Engine 3.2.1 x64。

_パート2 - Godot Engine latest ドキュメント

とりあえず、プレイヤーの弾を担当するシーン、PlayerBullet.tscn を作成しておいて…。

プレイヤーキャラを担当するシーン、Player.tscn に割り当てたスクリプトの中で、以下のような感じで処理。ちなみにプレイヤーは、KinematicBody から作った。
extends KinematicBody

var bullet = preload("res://assets/PlayerBullet.tscn")

# ...

var shot_counter = 0

func _ready():
    shot_counter = 0

    # ...

func _physics_process(delta):

    # ...

    # born player bullets
    shot_counter += delta
    if shot_counter >= (4 * 1.0 / 60.0):
        shot_counter = 0
        _born_player_bullet(translation)

    # ...
            
func _born_player_bullet(pos):
    var clone = bullet.instance()
    clone.translation = pos
    clone.translation.z -= 2.5
    var scene_root = get_tree().root.get_children()[0]
    scene_root.add_child(clone)

var bullet = preload("res://assets/PlayerBullet.tscn") で、事前にプレイヤー弾のシーンを読み込んでおいて、bullet.instance() でインスタンスを作成。しかるべきノードに、add_child(clone) で、子ノードとして追加。これで一応画面上にプレイヤーの弾が次々に発生してくれた。

プレイヤーの弾の移動。 :

プレイヤーの弾は、画面奥へと飛んでいってほしい。そのあたりの処理を試したり。

プレイヤーの弾は、Area で用意した。
Area
    MeshInstance
    CollisionShape

スクリプトは以下のような感じで。
extends Area

var counter = 0
export var kill_time = 2.0
export var speed = 1.5
var velocity = Vector3()

func _ready():
    counter = 0


func _physics_process(delta):
    counter += delta
    if counter >= kill_time:
        queue_free()
        return
    
    velocity = Vector3(0, 0, -speed * 60 * delta)
    translation += velocity

translation の z に値を加算、というか減算してみたら、奥方向に移動していく感じで動いてくれた。

ただ、こういう動かし方でいいのか分からんけど…。KinematicBody の場合は move_and_slide() を呼んで動かしてたけど、Area の場合は move_and_slide() を呼ぼうとしても「そんなメソッドは無い」と言われてしまって。しかし、こんな動かし方をしてもいいのだろうか…。どうなんだろう…。

そのままだと、ずっとどこまでも飛んで残り続けてしまうので、時間を測って一定時間が経ったら自分を殺す、みたいな処理も一応入れた。本当は画面外に出たかどうかチェックして消すべきだろうけど、どうやってソレを調べればいいのか…。

衝突判定で悩んだ。 :

プレイヤーの弾、及び、敵を、Area から作っていったのだけど。何かと衝突したら body_entered シグナルが発生するはず、と思って処理を書いたら無反応で悩んだり。

調べてみたら、body_entered は、xxxxBody と衝突した時にだけ発生するようで…。StaticBody とか、RigidBody とか、KinematicBody とか。

Area と Area が衝突した際は、area_entered が発生するらしい。

しかし、自分に何が当たったのかを、どうやって調べたらいいのか…。ググってみたら、どうやらグループというものが使えそうな気配。

プレイヤーの弾には「player_bullet」を、敵には「enemy」を、グループ登録しておいて…。例えば敵の側の area_entered と接続した関数内で、以下のように書けば…。
func _on_EnemyZako_area_entered(area):
    if area.is_in_group("player_bullet"):
        # Collide with player bullets
        damage_timer = 0.3
        hp -= area.attack_point
        print("Hit. My HP = " + String(hp))
        if hp <= 0:
            queue_free()  # I am dead.
area.is_in_group("グループ名") で、当たった何かがそのグループなら、てな感じの処理が書ける。

このあたり、レイヤーとマスクを使うことでも処理ができそうな気もするけれど、まだそこまで調べてなかったり。

以上です。

過去ログ表示

Prev - 2020/04 - 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