Can I create game objects from outside monobehaviour - c#

I want to instantiate in a class that is not a monobevaviour.
At the moment I call a helper class to do it but I want to reduce dePendency.

You can simply do this:
MonoBehaviour.Instantiate(ObjectPrefab);
This is because Instantiate is actually static in the MonoBehaviour class.

You can instantiate GameObjects or anything that derives from GameObject. ScriptableObjects are very useful.
If you don't want the Update/Start/Awake/etc. methods that are part of GameObjects, then you can use constructors of any objects that you want to Instantiate and/or create your own Instantiate methods.

Related

Serialize Script Instance in a ScriptableObject in Unity

I know this can be done because the amazing plugin Odin, has some epic serialization tools.
I was hoping I could do this using Odin but even their [Serialize] tag doesn't work.
I want to serialize a new instance of a script inside of a Scriptable Object.
With Odin, you can serialize dictionaries, and if you serialize a dictionary which holds instance of an interface (script) it allows you to create a new instance of that script inside the dictionary like so:
Since its possible to store an instance of a script inside of a dictionary I am curious how this can be done on its own.
The script I want to save is a generic script with only functions and an empty constructor.
Do you know a why to serialize the instance of an interface (script) inside of a ScriptableObject?
Ideally I could create an attribute some how and just force it to serialize like so:
public class MyClass: MonoBehaviour
{
[ForceSerialize]
public IScript scriptToSerialize;
}
And then in the inspector I could just click the box and create a new instance of that script to be attached to the object.
You don't need any [Serialize] tag, MyClass simply has to inherit from Sirenix.OdinInspector.SerializedMonoBehaviour instead of MonoBehaviour.
These "Serialized" class (also exists for ScriptableObjects and the likes) need to be used in order for Odin's custom serialization to work, which would make your field appear in the inspector.
This script works for me:
using Sirenix.OdinInspector;
public class MyScript : SerializedMonoBehaviour
{
public IScript scriptToSerialize;
}
public interface IScript { }

Unity, Class on instantiated prefab is different between objects

Odd question here - I have a gameobject with a class object attached. I instantiate the gameobject, and assign the class object with data from an existing class.
I then instantiate a second gameobject with the exact same class object attached and assign it the same data as the first object. If I modify the class attached to the first gameobject, it is different to the class attached to the second object, even though they both reference (or should) reference the same original class.
Can anyone think why this would happen?
if you make the variables you want to persist in the class your adding static, it will use the same instance for both cases, modifying both when you mod one.
check out this enemy class from unity3d's own dev pages
https://unity3d.com/learn/tutorials/topics/scripting/statics
using UnityEngine;
using System.Collections;
public class Enemy
{
//Static variables are shared across all instances
//of a class.
public static int enemyCount = 0;
public Enemy()
{
//Increment the static variable to know how many
//objects of this class have been created.
enemyCount++;
}
}
They are different instances of the same class, they don't reference the same class.
You should write a duplicate method to duplicate the values

How does Unity wiki's Singleton work?

I have a "manager" GameObject in my scene with a Manager Script component attached to it.
I need this Manager script to be a singleton since it makes no sense for there to be several managers.
I used the singleton implementation from the Unity wiki.
I have two questions about it:
Why does it create a new GameObject and then use GameObject.AddComponent<T>() to instantiate the singleton? Why not just do new T()?
I have protected both of my Singleton and Manager class constructors. No one should be able to instantiate these classes except themselves. How does the Unity Editor do to instantiate them?
As the comments say:
MonoBehaviour classes cannot be instanciated with new T() because of the way GameObject components work: they must be attached to a GameObject! As such, the GameObject class provides a way of instantiating a new MonoBehaviour attached to that GameObject: AddComponent<T>() which presumably operates through reflection (other MonoBehaviour methods such as Start() and Update() aren't exactly invoked with reflection, not every frame during runtime, but it's easy to make the comparison that they are; it's about as opaque and magical and has significant overhead, so it may as well be reflection).
Preventing the constructor from being called at all would probably just break everything, so don't bother trying to protect it any more than you already are. Because of the way AddComponent works, calling the constructor through reflection, you can't actually prevent a new instance from being created, but you CAN detect that it happened and do something about. My preferred way is the script going "oh, an instance already exists and its not me" and destroys itself.
Additionally, as components can require other components (RigidBody requires a Collider, MonoBehaviours can specify their own requirements as well) which is specified through an attributes, when AddComponent<T>() is called to add the one component, it will search the class attributes to see if there are any [RequireComponents] specified and add them too, automatically. This would also be done through reflection.

How to create instances of a base character class

In order for a class to be attached to a GameObject it needs to inherit from MonoBehaviour. If I create a base character class that contains all the attributes shared by both NPCs and PCs, how do I create instances of that class and attach it to game objects? To give a concrete example of the problem, if the base character class has variables like health, stamina, strength etc, and I want a particular game object to have a particular set of those attributes, how do I attach that to a game object as it cannot inherit the base character class?
I suspect the mistake I'm making is to think that these instances need to even be attached to the objects that I want them to be associated with, but some clear guidance here would be most appreciated.
It seems that what you really want is a base class that also allows its children to be MonoBehaviours. You can accomplish this by making your base class an abstract MonoBehaviour and inheriting from it.
public abstract class Base : MonoBehaviour
{
protected int HP;
}
Then your children of this class will also be MonoBehaviours which you can attach to GameObjects.
public class Ninja : Base
{
void Start()
{
HP = 100;
}
}

How to handle class visibility/access correctly

I'm designing a simple game and I'm not sure how to correctly handle the access and relations between classes. E.g:
Class Game - method Start that will initialiaze objects (fields) Player, CPUPlayer, Board.
Player/CPUPlayer contains a method "Place a pawn" but they would need to access the Board object to check for coordinates.
But they do not see the Board object. Does it mean I need to pass the Board object reference (or any other objects) in their constructor?
Yes, if they have a dependency on that object you need to inject it into them when they are created. The constructor is the right place. Later on, as you get a handle on things, you may want to look into using a DI container like Unity or something, but for now, just receive an instance of the Board in their constructors.
In this particular case, it does indeed seem that they need a reference to a Board object. If you would like to over-engineer that, you could create a specialized interface ICoordinateCheckable, implement it in the Board, and have Player accept an instance of this interface (instead of the Board) in constructor.

Categories

Resources