(Godot)Node型にキャストしても良いことなどない

またハマった。

初心者みたいなことだ。もちろん私はまだ二ヶ月ほどしかやっていないから初心者なんだけど。

今回のバグは型。 LabelをNode型に変換して操作するという謎コードがあった。

これのせいで思ったようにいかない。
色も位置も変更できず、非表示(Visible)にもできない。

モンスターを扱っていたから困る。エフェクトが効かない。

ということで、変更したらうまくいった。
(ちょっとした訳ありなので)UIに画像を入れてモンスターにしているので、Control型だ。

普通はNode2Dにしておいた方が無難だと思う。

とりあえず、Node型は使わない方がいいと思う。

(Godot)CallDeferredが便利な件

CallDeferred();

これを知っているのと知らないとでは全然違う。

これは何か? 

すべてのシーンの_Ready()が実行されてから実行するメソッドだ。

これによって、UI等のロードが全て終わったタイミングで実行することができる。
それで、何が嬉しいのかといえば、Getnodeができるようになるという利点がある。

    
public override void _Ready(){
    CallDeferred(nameof(AfterReady));
}

private void AfterReady()
{
        
}

私の場合は、「シグナル」を使う時にハマって、これを知った。

(ChatGPTが教えてくれた。)

子ノード同士でシグナルを送るとき、相手のノードがまだ読み込まれていないと取得することができず、どうしたもんかと思っていた。全てaddchildが終わってから実行すれば取得できるので1フレーム待つ必要があった。そういうやり方もあるのだが、CallDeferredというものが用意されていた。

これを使うことで無事解決。 まあ詳しくはChatGPTに聞いてみてくれ。

(Godot)_Ready()の順番問題?

_Readyの中で、画像やシーンをロードさせることはよくあることだ。

しかし、今回はこれではまった。

いつものようにロードをしても読み込めていないというエラーが出る。

なぜそうなったのか?

説明がややこしいのだが、メインシーンで使うために小分けしているシーンが複数あり、その小分けしているシーンの間でのロードが必要だったからだ。

ChatGPTに、なんとなくやり方をきくと答えを教えてくれた。

メインシーンでロードをし、それを引数を使って渡せばいい」とのこと。

と、一行書いただけで理解できる人はどのぐらいいるか分からないが一応そういうことだ。

小分けしているシーンで、うまく読み込めないときは、親シーンで読み込んで、それを引数として渡す。

(同じことを2回書いた)

ということで、全て_Readyの中でロードして使えばいいというわけでなく、他からもってくるというテクニックがあるんだということを知った。

(Godot c#)AddChildするときは、そのシーンでやれ

AddChildでハマった。

なんとも初歩的なことだ。

タイトルにある通り、AddChildをするときは、つけたいシーンにあるスクリプトでやったほうが混乱が少ない。

全く関係ないスクリプトで hoge.AddChild(xxxx);なんてやりだしたらエラーが出る確率があがる。

素直に、this.AddChild(xxx)と書けるようにやるべきだ。

なんかエラーが出てしまうと、あれこれ考えて深みに入るが、ちょっとでも複雑そうなことはやめたほうがいいだろう。

という教訓。(ただの寝不足だったのかもしれない)

Godotは基本的にnewではなくGetNodeを使おう

つまらないミスをして1時間ほどハマった。

やっていることはtweenの処理。

tweenを扱っているクラスを別クラスでインスタンス化しようとしたときにnewを使ってインスタンス化したらハマった。

解決策は、シーンにnode2dを追加し、tweenを書いたファイルをアタッチし、そのファイルをGetNodeで読み込めばうまくいけた。

エラーは出ず、なんでtweenが動かないんだろうと考えていた。

AIに聞いてみると、tweenを使う時は必ずAddChildをしなければならないと言ってくるが、別にしなくてもテストでは動いていたので不思議だった。

結局、コードが長くなってきたりして、新しいクラスに分散させるときは、GetNodeで読み込んだ方がミスが少ない。

かなり初歩的なところでハマってなんだか疲れたが一応前進したのでオッケー。

続・Godot4.3(C#) シグナルの書き方メモ

以下のようなクラスを作った。
ゲームではありがちなコンボを管理するクラスだ。

このクラスのコンボ数が変化すると通知をするということになる。

using Godot;

public partial class ComboManager : Node
{
    [Signal]
    public delegate void ComboCountChangedEventHandler(int comboCount);

    private int comboCount = 0;

	public override void _Ready()
	{
        GD.Print("ComboManager 読み込み確認");
    }

    public void IncrementCombo()
    {
        comboCount++;
        EmitSignal(nameof(ComboCountChanged), comboCount);
    }

    public void ResetCombo()
    {
        comboCount = 0;
        EmitSignal(nameof(ComboCountChanged), comboCount);
    }

    public int GetComboCount()
    {
        return comboCount;
    }
}

---

受信側で接続するのだが、「ComboCountChangedEventHandler」という文字列を使うと失敗する。

「ComboCountChanged」というところだけ記述し、「EventHandler」という文字を削除する必要があった。

        // シグナルに接続
comboManager.Connect(nameof(ComboManager.ComboCountChanged), new Callable(this, nameof(_OnComboCountChanged)));

こんな感じ。

「EventHandler」と言う文字をなぜ消さなければいけないのかは知らんけど、これで動いたのでオッケー。

過去記事でも全く同じ話をしたかもしれんが知らん。復習して勉強中。

使っているのChatGPTとGeminiに聞いてみたが、全く別の話をしているので詰んでいた。

困ったものだ。

Godot4.3 C# | シグナルをGeminiに習った日

ずっと気になっていたシグナル。どうやらunirxに近いものを感じた。

ボタンを押したりする時に必要になりそうなので、とりあえず腰を据えて学んでみた。

とはいえ1時間ぐらいかな。

少しでも気になったところをAIに聞き倒して理解を深めた。

一回覚えたらずっと使えるというのが良いところ。


using Godot;

public partial class MyButton_1 : Button
{
    // シグナルの定義
    [Signal]
    public delegate void button_testEventHandler();

    public override void _Ready()
    {
        // ボタンが押されたときの処理
        Pressed += OnButtonPressed; // Godot組み込みのPressedシグナルに接続
    }

    private void OnButtonPressed()
    {
        // カスタムシグナルを発行
     //EmitSignalを呼び出す事に通知するので、何回でも発行して良い。(個人的メモ)

        EmitSignal(nameof(button_test)); // シグナルの名前を変更
    }
}

using Godot;

public partial class Main1 : Node
{
    private Label _myLabel;
    private MyButton_1 _myButton;

    public override void _Ready()
    {
        // ノードの取得
        _myLabel = GetNode<Label>("myLabel");
        _myButton = GetNode<MyButton_1>("koko");

        if (_myLabel == null || _myButton == null)
        {
            GD.PrintErr("Label or Button not found!");
            return;
        }

        // シグナルの接続
		_myButton.button_test += OnMyButtonPressed;
    }

    private void OnMyButtonPressed()
    {
        // ラベルのテキストを変更
        _myLabel.Text = "Button Pressaaaaed!";
    }
}

//受信型は送信側のことを考えなくて良い。
//どのクラスからでもシグナルに接続すると受信できる。

学んだこと

・コードのみで実装可能

・シグナル名は変更できない (Pressedなど)

・xxx_xxxxEventHandlerを必ずつける必要がある
(button_testEventHandler)

・1つのクラスに複数のシグナルをつけることができる。

・ノードにあるものでシグナルをする。

なんとかわかりそう。あとは何度か実際に試していくだけ

Godot4.3 C# | AddChild後に.Nameはどうだろう

以下、初心者の意見です。

「AddChild」というよく使う関数がある。

これを実行する前にシーンに名前をつけることもできるし、後からつけることも可能だ。

個人的には名前や位置などを調整してからAddChildを実行していたが、どうやら逆の方がしっくりくる。

というのも、先に名前をつけておくとシーンに「@Sprite2D@x」というようなシーンが作られることが多かったからだ。これがなんとも気持ち悪い。AIに聞いてみると、「内部的には名前は変わっているので問題ない」と言っている。

しかし、見た目は重要。今のところAddChildをしてから.Nameで名前を変更するとうまくいっている。

もちろんそれでも100%うまくいっているわけではない。「@Sprite2D@x」というようなシーンは作られることがあるが、ゲームを進めていくと消えていく。

ということで、「AddChild」を使う時は、AddChildをしてから名前を変更するという手があるということをシェア。(あまりにマニアックでどっちでもいいと思っているけど)

(Godot ) GetNodeは絶対パスの方が良さそう

同じ階層にあるシーンをGetNodeするとき相対パスではなく絶対パスで取得した方が個人的にはわかりやすい。

というのも昨日この件で詰んでいたからだ。同一階層のとき「../」をつけないでシーン名だけ書いていたらエラーになっていた。

ChatGPTにエラー内容を聞いたら取得できていないと言われて焦った。

そして「まさかな」とも思った。webでは同一階層のときそのままファイルパスを書けばよかったのだが、Godotでは違うみたいだ。

ということで、つまらないところで数時間詰んだ。とりあえず絶対パスで書いて、最終的にテストが終わった後で相対パスにしたいならしたらいいんじゃないか。

(あと、GDを使ってデバックもちゃんとしないとねえ)

Godot 画像を表示させるシンプルな方法

using Godot;
using System;

public partial class Field : Node2D
{
	[Export] private Texture2D[] _textures = new Texture2D[8];
	public override void _Ready()
	{
		LoadAndDisplayImages();
	}
	private void LoadAndDisplayImages()
    {
		for (int i = 0; i < _textures.Length; i++)
		{
			var sprite        = new Sprite2D();
			sprite.Position   = new Vector2(50 + 200 * i, 250);
			sprite.Texture    = _textures[i];
		
			AddChild(sprite);	
		}
	}
	
}

ChatGPTが生成したコード。

Godot上で_texturesに画像をアタッチしておく。

メモ。