0

so I have a class called InstalledObjects, and all objects like walls, door etc will inherit from this one. Now, I would like to instantiate a GameObject in a method, and ask in the method for a InstalledObject, that could be a Wall or a Door since they both inherit from InstalledObject.

My problem is that I can store in a variable a script.

First, this method is called

public void CreateBasicWall()
{
     buildHandler.installedObject = new Wall();
}

That its stored here:

public InstalledObject installedObject;

And finally gets called here

BuildTile(t, buildModeTile);

And does that:

void Build(Tile tile, InstalledObject installedObject)
{
    if(installedObject == null)
    {
        Debug.LogError("No se va a construir nada");
        return;
    }
    GameObject go = new GameObject();
    go.AddComponent<installedObject>();

}

Ignore the tile. It wont let me add the installedObject since is a var and not a type.

I remember that the class Wall inherits from InstalledObject, and I would like to have it as var so I can reuse code, but any other solution is appreciated.

Alexxjaz
  • 87
  • 1
  • 8
  • You can't pass in a variable for generics. (`AddComponent`). See [Calling a generic method with a dynamic type](https://stackoverflow.com/questions/4101784/calling-a-generic-method-with-a-dynamic-type) – derHugo Sep 23 '19 at 18:39
  • And this is called inside a void? Never used types before – Alexxjaz Sep 23 '19 at 18:42
  • The return type doesn't matter .. counts for void or anything else – derHugo Sep 23 '19 at 18:43
  • Assuming that `InstalledObject` is of type `MonoBehaviour` since you are trying to use it for `AddComponent` your code is invalid anyway! You can't use `new Wall()` for a class of type `MonoBehaviour` .. it can only be created using `AddComponent()` or alternatively the overload taking a type `AddComponent(typeof(ClassName))` – derHugo Sep 23 '19 at 18:50

2 Answers2

3

As said already using dynamic variables for a generic method (AddComponent<T>) is not possible directly only maybe using reflection but I wouldn't recommend it .. especially not if you are new to c#.


Assuming that InstalledObject is of type MonoBehaviour since you are trying to use it for AddComponent your code is invalid anyway!

You can't use new Wall() for a class of type MonoBehaviour .. it can only be created using AddComponent<ClassName>() or alternatively the overload taking a type AddComponent(typeof(ClassName))

So what you can do instead is not storing an "instance" (as said you can't use new anyway) you could rather only store the according type

public Type typeToInstall;

and then pass it on like

public void CreateBasicWall()
{
     buildHandler.typeToInstall = typeof(Wall);
}

void Build(Tile tile, Type typeToInstall)
{
    if(typeToInstall == null)
    {
        Debug.LogError("No se va a construir nada");
        return;
    }

    GameObject go = new GameObject().AddComponent(typeToInstall);

    // or even a bit shorter
    //new GameObject("New GameObject", typeToInstall);
}

You can also make this method a generic itself and constraint passed the type to Component (the mother class of anything you can attach to a GameObject) just to be sure. Passing in any other type will then already throw a compiler error. Then you can also use AddComponent<T> again

void Build<T>(Tile tile, T typeToInstall) where T : Component // or maybe even InstalledObject ;)
{
    if(typeToInstall == null)
    {
        Debug.LogError("No se va a construir nada");
        return;
    }

    new GameObject().AddComponent<T>();

    // or still use
    //new GameObject("New GameObject", typeof(T));
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
0

There are multiple ways to do it, however if you want to keep your current architecture, you need virtual or abstract functions.

Each class knows its own type, however the functions you call on it depend on the type of the variable holding the class, unless it's an abstract or virtual function.

I'd suggest reading up on this.

Here's one way to do it:

void Build(Tile tile, InstalledObject installedObject)
{
    Assert.IsNotNull(installedObject,
        "No se va a construir nada");

    GameObject go = new GameObject();
    installedObject.AddSelfToGameObject(go);
}

and in your Build.cs

public abstract class Build
{
    [...]
    public abstract void AddSelfToGameObject(GameObject go);
}

public class Building:Build
{
    [...]
    public override void AddSelfToGameObject(GameObject go)
    {
        go.AddComponent<BuildingScript>();
    }
}

The abstract on the Build class is only necessary if you never create a Build class alone, only a child class of Build. You can remove the abstract on the class and replace it on the function by virtual.

Lou Garczynski
  • 624
  • 3
  • 10