3. Initializing Components in Code

  03. Getting Started No Comments

AddComponent with Arguments

A new component that derives from MonoBehaviour<T…> or implements IArgs<T…> can be attached to GameObject and initialized with arguments using the AddComponent<TComponent, T…> extension methods in the Sisus.Init namespace.

The methods work just like the built-in AddComponent<T> methods, except you also list the types of the component’s Init parameters as generic type arguments, and then pass in the Init arguments when calling the method.

using Sisus.Init;
using UnityEngine;

public static class GameManager
{
    public static IInputManager InputManager { get; } = new InputManager();

    public static Player CreatePlayer()
    {
        var gameObject = new GameObject("Player");
        return gameObject.AddComponent<Player, IInputManager, Camera>(InputManager, Camera.main);
    }
}

public class Player : MonoBehaviour<IInputManager, Camera>
{
    IInputManager inputManager;
    Camera camera;

    protected override void Init(IInputManager inputManager, Camera camera)
    {
        this.inputManager = inputManager;
        this.camera = camera;
    }
}

There are also overloads available which don’t return the created component as a return value, but instead assign it into an out argument. This can help the compiler be able to infer the types of all the generic type arguments of the method from the types of the variables that are passed to it, so you don’t have to explicitly specify all of them.

public static Player CreatePlayer()
{
    var gameObject = new GameObject("Player");
    gameObject.AddComponent(out Player player, InputManager, Camera.main);
    return player;
}

Instantiate with Arguments

A component that derives from MonoBehaviour<T…> or implements IArgs<T…> can be instantiated by cloning a GameObject, and initialized with arguments using the Instantiate<TObject, T…> extension methods in the Sisus.Init namespace.

The methods work just like the built-in AddComponent<T> methods, except you also pass in the Init arguments when calling the method.

using Sisus.Init;
using UnityEngine;

public static class GameManager
{
    public static IInputManager InputManager { get; } = new InputManager();

    public static Player CreatePlayer(Player prefab)
    {
        return prefab.Instantiate(InputManager, Camera.main);
    }
}

You typically don’t need to explicitly specify the generic type arguments of the method, as the compiler can usually infer them from the types of the variables that are passed to it.

If the types of some of the variables passed to the Instantiate method don’t match the types of the corresponding Init parameters exactly, you might need to cast them to the exact types to help out the compiler:

public static Player CreatePlayer(Player prefab)
{
    var inputManager = new InputManager();
    return prefab.Instantiate((IInputManager)inputManager, Camera.main);
}

new GameObject with Arguments

The new GameObject<TComponent…> structure can be used to create a new GameObject, attach one or more components to it, and initialize zero or more of those components with arguments – all in a single line of code.

When attaching a single component to the created GameObject, you can pass Init arguments to the created component using the Init method.

using Sisus.Init;
using UnityEngine;

public static class GameManager
{
    public static IInputManager InputManager { get; } = new InputManager();

    public static Player CreatePlayerWithMainCamera()
    {
        return new GameObject<Player>("Player").Init(InputManager, Camera.main);
    }
}

When attaching a multiple components to the created GameObject, you can pass Init arguments to the first component using the Init1 method, to the second one usings Init2 etc.

public static Player CreatePlayerWithNewCamera()
{
    return new GameObject<Player, Camera>("Player").Init1(InputManager, Second.Component);
}

If a component doesn’t require any Init arguments, you can skip over it by executing its Init method without passing any arguments to it.

public static Player CreatePlayerWithNewCamera()
{
    return new GameObject<Camera, Player>("Player")
        .Init1()
        .Init2(InputManager, First.Component);
}

new GameObject<T…> can be implicitly converted into any of attached components, into a tuple of all the attached components, or into a GameObject:

A a = new GameObject<A, B, C>();
B b = new GameObject<A, B, C>();
C C = new GameObject<A, B, C>();
(A a, B b, C c) components = new GameObject<A, B, C>();
GameObject gameObject = new GameObject<A, B, C>();

Leave a Reply

Your email address will not be published. Required fields are marked *