mieki256's diary



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

#2 [godot] Godot Engineでアタリ判定処理を書く

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

今回は各オブジェクトのアタリ判定処理を作っていく。

プレイヤーの弾にアタリ判定処理を追加。 :

プレイヤーの弾にアタリ判定処理を追加する。

プレイヤーの弾は、敵(EnemyZako)とだけ衝突するように Layer と Mask を使って設定してあるけれど、敵は Areaノードをルートノードとして作ってあるので…。

プレイヤーの弾と敵が衝突した際、プレイヤーの弾は「Areaとぶつかったよ」と、area_entered(area:Area) というシグナルを発行してくれる。そのシグナルにメソッドを接続してやれば、プレイヤーの弾と敵が当たった時にそのメソッドが呼ばれるので、そのメソッドの中に敵と当たった時の処理を書いておけばいい。

プレイヤーの弾のシーン、res://assets/PlayerBullet.tscn を開いて、シグナルにメソッドを接続する。ノードタブをクリック → シグナルをクリック。「area_entered(area:Area)」を選択して右クリックして「接続」。

3d_tuto10_collison_ss01.png


PlayerBullet を選択して「接続」。

3d_tuto10_collison_ss02.png


スクリプトファイル PlayerBullet.gd の最後に、_on_PlayerBullet_area_entered(area) というメソッドが追記されたので、敵と当たった時の処理を書く。

3d_tuto10_collison_ss03.png

記述内容は以下になる。

_PlayerBullet.gd
extends Area

var velocity = Vector3()
var speed = 90

func _ready():
    velocity = Vector3(0, 0, -1)

#func _process(delta):
#   pass

func _physics_process(delta):
    translate(velocity * speed * delta)

func _on_Timer_timeout():
    queue_free()

func _on_PlayerBullet_area_entered(area):
    if is_queued_for_deletion():
        return
    print("PlayerBullet Hit!")
    queue_free()

  • とりあえず仮の処理として、print() を呼んで当たったことを示すメッセージを出力してみる。
  • プレイヤーの弾が敵に当たったら、その場でプレイヤーの弾は消滅してほしいので、自分を消去する queue_free() を呼んでおく。
  • is_queued_for_deletion() は、自分に消去処理が要求されているかを調べることができる。もし自分が消去予定になっていたら、何も処理をせずにメソッドを抜けるようにしてある。

動作確認してみる。 :

Mainシーンを開いてF6キーを押して動作確認してみる。

プレイヤーの弾と敵が当たった時に「PlayerBullet Hit!」というメッセージが出力ウインドウに出力された。ちゃんと当たってることが判別できた。

3d_tuto10_collison_ss04.png


画面内でも、プレイヤーの弾が敵に当たった時に、プレイヤーの弾がその場で消滅している様子が見て取れる。

3d_tuto10_collison_ss05.png

動作確認できたので、メッセージを出力する print() は、頭に「# 」を追加してコメントアウトしておく。

    # print("PlayerBullet Hit!")

敵弾にアタリ判定処理を追加。 :

敵弾シーン EnemyBullet.tscn にもアタリ判定処理を追加していく。

敵弾は Layer と Mask を使ってプレイヤーとだけ当たるように設定してある。そしてプレイヤーキャラは KinematicBody をルートノードにして作ってあるので…。

敵弾 EnemyBullet (Area) は、プレイヤー Player (KinematicBody) と当たった際に、body_entered(body: Node) というシグナルを発行する。(area_entered()ではなくて、body_entered()。相手が Area ではなくて KinematicBody なので。)

このシグナルにメソッドを接続してやれば、敵弾がプレイヤーと当たった時にそのメソッドが呼ばれるので、そのメソッドの中にプレイヤーと当たった時の処理を書いておけばいい。

敵弾のシーン、res://assets/EnemyBullet.tscn を開いて、シグナルにメソッドを接続する。ノードタブをクリック → シグナルをクリック。「body_entered(body: Node) を選択して右クリックして「接続」。EnemyBullet を選択して「接続」。

3d_tuto10_collison_ss06.png


スクリプトファイル EnemyBullet.gd の最後に、_on_EnemyBullet_body_entered(body) というメソッドが追加された。このメソッドにプレイヤーと当たった時の処理を書く。

3d_tuto10_collison_ss07.png

内容は以下。

_EnemyBullet.gd
extends Area

var velocity = Vector3()
var direction = 0
var speed = 3

func _ready():
    pass # Replace with function body.

#func _process(delta):
#   pass

func _physics_process(delta):
    translate(velocity * speed * 60 * delta)

func set_dir_and_speed(angle, spd):
    direction = angle
    speed = spd
    var x = cos(deg2rad(angle))
    var z = sin(deg2rad(angle))
    velocity = Vector3(x, 0, z)
    
func _on_KillTimer_timeout():
    queue_free()

func _on_EnemyBullet_body_entered(body):
    if is_queued_for_deletion():
        return
    print("EnemyBullet Hit!")
    queue_free()

PlayerBullet とほとんど同じ処理になっている。

動作確認。Mainシーンを開いてF6キーを押す。敵弾がプレイヤーと当たるたびに、出力ウインドウにメッセージが表示された。ちゃんとアタリ判定ができている。

3d_tuto10_collison_ss08.png

動作確認できたので、print() をコメントアウト。

    # print("EnemyBullet Hit!")

敵にアタリ判定処理を追加。 :

敵にアタリ判定処理を追加していく。

敵は、Layer と Mask を使って、プレイヤー、及び、プレイヤーの弾と当たるように設定されている。そして、プレイヤーは KinematicBody、プレイヤーの弾は Area をルートノードにして作ってあるので…。
  • body_entered(body: Node) シグナルにメソッドを接続すれば、そのメソッドにプレイヤーと当たった時の処理を書ける。
  • area_entered(area: Area) シグナルにメソッドを接続すれば、そのメソッドにプレイヤーの弾と当たった時の処理を書ける。

敵のシーン、res://assets/EnemyZako.tscn を開いて、area_entered() シグナルと、body_entered() シグナルにメソッドを接続してやる。ノードタブをクリック → シグナルをクリック。それぞれのシグナルを右クリックして「接続」。EnemyZako を選択して「接続」。

3d_tuto10_collison_ss09.png

3d_tuto10_collison_ss10.png

3d_tuto10_collison_ss11.png

3d_tuto10_collison_ss12.png

スクリプトファイル EnemyZako.gd に、_on_EnemyZako_area_entered(area) と、_on_EnemyZako_body_entered(body) が追記された。

それぞれのメソッドに処理を書く。

3d_tuto10_collison_ss13.png

内容は以下。

_EnemyZako.gd
extends Area

export (PackedScene) var enemybullet

var base_pos = Vector3()
var angle = 0
export var move_w = 22
export var move_h = 12
var bullets

func _ready():
    base_pos = translation
    angle = 0
    bullets = get_tree().root.get_node("Main/EnemyBullets")

#func _process(delta):
#   pass

func _physics_process(delta):
    move(delta)
    
func move(delta):
    angle += delta
    translation.x = base_pos.x + move_w * cos(deg2rad(angle * 90))
    translation.z = base_pos.z + move_h * sin(deg2rad(angle * 70))
    
func _on_ShotTimer_timeout():
    var angle_add = 12
    var angle = 90 - angle_add * 3
    var spd = 0.2
    for i in range(7):
        _shot(translation, angle, spd)
        _shot(translation, angle, spd * 0.8)
        angle += angle_add
    
func _shot(pos, angle, spd):
    var bullet = enemybullet.instance()
    bullet.translation = pos
    bullet.set_dir_and_speed(angle, spd)
    bullets.add_child(bullet)

func _on_EnemyZako_area_entered(area):
    if is_queued_for_deletion():
        return
    print("playerbullet hit the enemy")

func _on_EnemyZako_body_entered(body):
    if is_queued_for_deletion():
        return
    print("player hit the enemy")


動作確認してみる。Mainシーンを開いてF6キーを押す。

プレイヤーを操作して敵と当ててみたり、プレイヤーの弾を敵に当ててみたりする。出力ウインドウに、当たってる旨を伝えるメッセージが出力された。

3d_tuto10_collison_ss14.png

これで一応、アタリ判定はできた。

さて、プレイヤーに敵弾が当たったらプレイヤーのHP(体力?)を減らしたり、敵にプレイヤーの弾が当たったら敵のHPを減らしたりしたい。次回は各HPを画面に表示するために、HUD(Head-Up Display)シーンを作成する。

以上です。

過去ログ表示

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