俺に解るように説明する "Godot Engine 3.x" 入門+

ゲームエンジン Godot Engine に関すること。入門とか使い方とかチュートリアルとか、あれとかこれとか。日本語解説。

Godot 音シュー13「シーンのインスタンスとアニメ 2/2」 preload/ instance/ add_child

作ったシーンをノードにくっ付けよう。実はコレ、「大昔」にやってたようだが、どうもそれは間違ったやり方だったようだ。こわいこわい。間違いポイントは、「一旦queue_free()したノードは2度とadd_child()出来ない」って事を知らなかった所。今回はちゃんとやろう。

f:id:ore2wakaru:20180622172713p:plain


スクリプト

左エリアに貼るスクリプトだけ持ってきた。

extends MeshInstance

var spaMat                              #自身が持つSpaialMaterialの情報操作用
var colorIn =  Color("#ff0000")         #ビートキューブが入った時の色(赤)
var colorOut = Color("#3fffffff")       #ビートキューブが出た時の色(白)

var nLabelScore                         #得点表示用Label_score2の操作用
var nCamera                             #Cameraノード用

var sGood = preload("res://Good.tscn")  #goodSceneインスタンス用
var sMiss = preload("res://Miss.tscn")  #goodSceneインスタンス用

func _ready():
    #メッシュとマテリアルが入ってないとエラーになるから注意
    spaMat = get_surface_material(0)                #0番目に入ってるヤツ ゲット

    nLabelScore = get_node("../../../Label_score2") #得点表示用Label_score2ゲット
    nCamera = get_node("../../Camera")

func _physics_process(delta):
    if Input.is_action_just_pressed("myA"):         #キーを押した時瞬間
        if spaMat.albedo_color == colorIn:          #ビートキューブが入っている場合
            spaMat.albedo_color = colorOut          #連打禁止、色戻す
            #加点
            G.myScore = G.myScore + 10
            nLabelScore.text = str(G.myScore)
            #Good表示(シーンのインスタンス)
            var inst = sGood.instance()
            inst.rect_position = nCamera.unproject_position(global_transform.origin)
            add_child(inst)
        else:                                       #ビートキューブが入っていない場合
            #減点
            G.myScore = G.myScore - 50
            nLabelScore.text = str(G.myScore)
            #Miss表示(シーンのインスタンス)
            var inst = sMiss.instance()
            inst.rect_position = nCamera.unproject_position(global_transform.origin)
            add_child(inst)

#キューブ入ったよ(signal from 「Area_l」)
func _on_Area_l_body_entered(body):
    #色変えるぜ
    spaMat.albedo_color = colorIn

#キューブ出たよ(signal from 「Area_l」)
func _on_Area_l_body_exited(body):
    #色戻すぜ
    spaMat.albedo_color = colorOut


変更部分の解説

[1] 変数

f:id:ore2wakaru:20180622151335p:plain

L8

  • カメラを変数として取るため用意する。今回はエリアの3D位置を、カメラから見た2D位置に変換したポジションを取得したいので、どのカメラから見たか情報をゲットする必要がある。

L10~11

  • preload()でシーンを変数に入れる。「大昔」参照。
  • あくまでも「シーン」の型で入るので、このままではノードにくっ付けられない。

[2] _ready()

f:id:ore2wakaru:20180622152824p:plain

L18

  • プレイヤに付けたカメラノードをゲットしただけ。

[3] if

f:id:ore2wakaru:20180622153226p:plain

L23

  • コメントに書いた通り。色を戻してやらないと、連打でいつまでも得点が入ってしまう。

f:id:ore2wakaru:20180622153353p:plain

L28

  • 新しく変数を用意し、そこにinstance()させたものを入れる。
  • instance()は「シーン」を「ノード」にする関数。"sGood"は「シーン」としての型だが、新しく作った変数"inst"は「ノード」としての型になる。
  • だが"inst"は、ノードはノードでも元の「シーン」のルートノードの型、つまり「Control」ノードとしての扱いになる。ここ重要!
  • たまたま最近覚えたget_class()で見て確認したけど、get_class()、最強だな。

L29

  • 変数"inst"は「Control」ノード扱いなので、そのプロパティにRect > Positionを持っている。ここをいじって表示位置を変えようって考え。
  • unproject_position()は、3D空間の物体が2Dのゲーム画面のどの位置になるか教えてくれる関数。簡単に言うと、3次元位置を2次元位置に変換するって事。で、どのカメラを基にしてるかをドット"."の前に置く。
    f:id:ore2wakaru:20180622160153p:plain
  • カッコ内のglobal_transform.originはこのスクリプトが付いてる「MeshInstance」ノードの中心。グローバル位置。
  • これで、3D空間所にある「MeshInstance」が2D画面上のどの位置にあるのかが、"inst"に入った。

L30

  • add_child()でノードを追加する。これで画面上に表示されることとなる。
  • 単にinstance()するだけじゃダメね。add_child()しないと見えないから。

f:id:ore2wakaru:20180622161419p:plain

L35~38


以上の事を上下左右のエリアにやればいいだけなので、省略。

    if Input.is_action_just_pressed("myA"):

の所の"myA"を"myD"、"myW"、"myS"にそれぞれ変えるのを間違わなければだいじょぶだろう。あと、

func _on_Area_l_body_entered(body):

func _on_Area_l_body_exited(body):

の所は、"l"をそれぞれ"r"、"u"、"d"に。


忘れてた

アニメのAutoplayを有効にしとかないとadd_child()した瞬間にアニメが始まらない。青くしておくこと。

f:id:ore2wakaru:20180622162428p:plain


もうちょい

これで、タイミングよく指定のキーが押されればアニメする「Good」表示が、変なところでキーを押せばアニメする「Miss」表示が出る。

だが、instance()してadd_child()しまくると追加されるノードがドンドコ増えていくので、適当な時間が経ったら消えるようにスクリプトする。

f:id:ore2wakaru:20180622163732p:plain

extends Control

var myTimer = 0.5

func _process(delta):
    myTimer = myTimer -delta
    if myTimer < 0.0:
        queue_free()

消えるスクリプトは、なんでもyield()っていうのを使うのがイイらしいんだが、よく分からんかったので"delta"で数えて消す。


インスタンスのまとめ
  1. preload()して
  2. instance()して
  3. add_child()
  4. queue_free()忘れずに。

だな。


ふむ

f:id:ore2wakaru:20180622164943g:plain

文字表示の場所、OK!

一応これで、「音ゲー」部分はOKとして、次からは「シューター」部分の作成に入ろうかと思う。