• Godot Help
  • how to use an instance of custom class in GDScript?

Hi, I defined a instance of a custom class in my Globals file that is at Autostart.

using Godot;
using System;
public class Globals : Node
{
	public static Monstruo monstruito = new Monstruo(10, 10, 30, 20, 10, "Golem", "art/monsters/E_golem.jpeg", 2,
	"A golem is a cursed giant made of mud or stone, that follows the commands of a wizard to kill intruders.",
	new String[2] {"using his fists to crunch her", "trying to smash her with his brute force" },
	Monstruo.tipo.BEAST, Monstruo.magic.AGUA) ;

	string ruta = monstruito.imagen; 
....

Then in another script, I can do this:
$TextureRect.texture = ResourceLoader.load("res://" + Globals.ruta)
and it works, it changes the image of the TextureRect.

But it doesn't work if I use this:
$TextureRect.texture = ResourceLoader.load("res://" + Globals.monstruito.imagen)

The error says:
invalid get index 'imagen' (on base: 'Nil')

Why it can't see the instance of my object?
Thank you!

  • xyz replied to this.
  • intuitive-arts
    Firstly, Monster m; should be declared inside the Globals class not outside of it. So again:

    using Godot;
    
    public partial class Globals: Node
    {
    	Monster m = new Monster();
    }

    Other than that, script sources are fine.

    There were apparently some known issues with this.

    If I make a new autoload class in your project it works just fine, but yours causes a complaint that the class does not inherit from Node, even though it does.

    Try this:

    • delete *.vcproj file in your project folder
    • open the project
    • remove the cs script from autoloads.
    • go to Project->Tools->C#->Create C# solution
    • add the cs script as autoload
    • try to run the project

    Also make sure that the class name and *.cs file name are exactly the same (the case must match too)

    If I don't, the compiler says:
    "A field initializer cannot reference the non-static field, method, or property 'Globals.monstruito'"

    xyz

    • xyz replied to this.

      xyz
      it doesn't change, and the problem is with the string field "imagen". By some reason Godot doesn't recognize the existence of my object monstruito which is an instance of Monstruo, or its field "imagen".

      Thanks for your help. Do you know why it may be happening?

      When I put the value of monstuito.imagen to a variable in the same globals file, it can see it perfectly. But not directly in the instance of the object.

      • xyz replied to this.

        xyz no it doesn't.
        I am adapting a game i made in C#.
        in Visual studio it worked, but i have this problem here.

        • xyz replied to this.

          intuitive-arts Let's see the whole code. Please format it properly using ~~~
          Or better yet post the minimal project that reproduces the problem.

            intuitive-arts Don't forget that your custom class needs to inherit at least from RefCounted (or Reference in 3.x) in order for GDScript to "see" the object.

            public partial class Monster: RefCounted {
            	int eyesCount = 3;
            }

              xyz it seems to stop complaining the same errors, but now it says:
              Invalid get index 'monstruito' (on base: 'Nil').

              It is in this function:
              func _on_Button_pressed():
              $TextureRect.texture = ResourceLoader.load("res://" + Globals.monstruito.imagen)
              pass # Replace with function body.

              And the Monstruo class is this way:

              using System;
              
              	[Serializable]
              	public partial class Monstruo: Reference
              	{
              		public int life;
              		public int maxLife; // vida inicial
              		public int attack;
              		public int defense;
              		public int dexterity;
              		public string name;
              		public string imagen;//Imagen de (Image)Resources.
              		public int level;
              
              		public string descripcion;
              		public string[] ataques;
              
              		public enum tipo
              		{
              			BESTIA = 1,
              			REPTIL = 2,
              			FUEGO = 3,
              			AGUA = 4,
              			PARANORMAL = 5,
              			PERRO = 6,
              			NOMUERTO = 7,
              			DEMONIO = 8,
              			DRAGON = 9
              		};
              		public tipo especie; // tipo de monstruo para sonido de encuentro
              
              		// nota un monstruo puede ser vulnerable solo a un tipo de magia
              		public enum magia
              		{
              			TODO = 1, // le daña todo
              			NADA = 2, // no le daña ninguna magia
              			FUEGO = 3, // solo le daña el fuego
              			AGUA = 4, // solo el agua
              			AIRE = 5, // solo el aire
              			TIERRA = 6, // solo la tierra
              			ESPACIO = 7 // solo vulnerable a magia espaciotemporal
              		};
              		public magia debilidad;
              		///////////////////////////////////////////////////////////////////////////////////////////////////
              		// rutina RUTINAS * RUTINAS * RUTINAS * RUTINAS * RUTINAS * RUTINAS * RUTINAS * RUTINAS * RUTINAS 
              		///////////////////////////////////////////////////////////////////////////////////////////////////
              		public Monstruo
              			(
              			int life,
              			int maxLife,
              			int attack,
              			int defense,
              			int dexterity,
              			string name,
              			string imagen ="",
              			int level=1,
              
              			string descripcion="",
              			string[] ataques = null,
              		
              			tipo especie = tipo.BESTIA, // el monstruo por defecto es una bestia
              			magia debilidad = magia.TODO // y es vulnerable a todo tipo de magia
              			)
              
              		{
              			this.life = life;
              			this.maxLife = maxLife;
              			this.attack = attack;
              			this.defense = defense;
              			this.dexterity = dexterity;
              			this.name = name;
              			this.imagen = imagen;
              			this.level = level;
              
              			this.descripcion = descripcion;
              			this.ataques = ataques;
              
              			this.especie = especie;
              			this.debilidad = debilidad;
              		}
              
              		///////////////////////////////////////////////// END OF PRINT //////////////////////////// END OF PRINT /////////////////////// END OF PRINT /////////////////////////
              	} // fin clase

              And the Globals.cs is this:

              using Godot;
              using System;
              
              public partial class Globals : Node
              {
              	// Declare member variables here. Examples:
              	// private int a = 2;
              	// private string b = "text";
              	
              	
              	public static Monstruo monstruito = new Monstruo(10, 10, 30, 20, 10, "Golem", "art/monsters/E_golem.jpeg", 2,
              	"A golem is a cursed giant made of mud or stone, that follows the commands of a wizard to kill intruders.",
              	new String[2] {"using his fists to crunch her", "trying to smash her with his brute force" },
              	Monstruo.tipo.BESTIA, Monstruo.magia.AGUA) ;
              
              	string ruta = monstruito.imagen; // coloca este atributo en una variable para poderlo invocar desde gdscript
              	// porque no se como hacerlo directamente, o bien es que gdscript se lia
              	
              	// Called when the node enters the scene tree for the first time.
              	public override void _Ready()
              	{
              		
              	}
              • xyz replied to this.

                intuitive-arts Yeah but you still have monstruito declared as a static member.
                This should work:
                Monster.cs:

                using Godot;
                
                public partial class Monster: RefCounted {
                	int eyesCount = 3;
                }

                Globals.cs:

                using Godot;
                
                public partial class Globals: Node
                {
                	Monster m = new Monster();
                }

                something.gd:

                extends Node
                
                func _ready():
                	print(globals.m.eyesCount)

                The singleton/autoload is set under name globals.

                  xyz I made the example you posted, and it happens the same:
                  Invalid get index 'm' (on base: 'Nil').

                  In the Errors list it also says:
                  E 0:00:01:0164 start: Script does not inherit from Node: res://Globals.cs.
                  <C++ Error> Condition "!valid_type" is true. Continuing.
                  <C++ Source> main/main.cpp:2776 @ start()

                  Maybe I should use GDScript only?

                    intuitive-arts It works with GD Script with simple variables, but it doesn't seem to work with C# on custom classes. The m monster doesn't seem to be recognized. A simple string variable is, if I create a GD script that defines it.

                    • xyz replied to this.

                      intuitive-arts No, it must work. You probably overlooked something. Can you post a minimal project with your implementation of the example?

                        xyz

                        caverns-and-dryads.zip
                        7MB

                        Thank you so much for your help. This is a minimal test. If the script in Globals is GDScript it works, but not for C#. There's a line that you can uncomment in "something.gd" so you can test the C# part.

                        • xyz replied to this.

                          intuitive-arts
                          Firstly, Monster m; should be declared inside the Globals class not outside of it. So again:

                          using Godot;
                          
                          public partial class Globals: Node
                          {
                          	Monster m = new Monster();
                          }

                          Other than that, script sources are fine.

                          There were apparently some known issues with this.

                          If I make a new autoload class in your project it works just fine, but yours causes a complaint that the class does not inherit from Node, even though it does.

                          Try this:

                          • delete *.vcproj file in your project folder
                          • open the project
                          • remove the cs script from autoloads.
                          • go to Project->Tools->C#->Create C# solution
                          • add the cs script as autoload
                          • try to run the project

                          Also make sure that the class name and *.cs file name are exactly the same (the case must match too)

                            xyz

                            The instance "m" of Monster is declared inside Globals here:

                            `using Godot;

                            Monster m;

                            public partial class Globals: Node
                            {
                            m = new Monster();
                            }
                            `

                            Do you mean that I should put the declaration of the class Monster inside Globals, instead that in another file (Monster.cs)?

                            • xyz replied to this.

                              xyz can you upload the version that works for you, that uses the C# class, so I can have a look? Thank you so much!

                              intuitive-arts Do you mean that I should put the declaration of the class Monster inside Globals, instead that in another file (Monster.cs)?

                              I meant to put the declaration of the variable m inside class body.

                              Here's the project:

                              caverns-and-dryads.zip
                              363kB