GameObject creation order issue - c#

I'm currently working on an inventory system in Unity3D, and came upon a weird problem. I have created non-MonoBehaviour classes for my inventory system (in case that matters), so that I have an Inventory class which holds a list of Slot objects, which in turn holds a list of Item objects.
Then I added a component script to my "HudInventoryPanel", called "HudInventoryController", which looks like this:
using UnityEngine;
using System.Collections;
public class HudSlotController : MonoBehaviour {
private InventoryController ic;
// Use this for initialization
void Start () {
ic = GetComponent<InventoryController>();
}
// Update is called once per frame
void Update () {
}
}
However, inside the Start() method, the InventoryController (part of my Player) hasn't been created yet, and it seems to me like the gameobjects are created in alphabetical order...?
How should I deal with this problem?

You can specify script execution order in the project settings (Edit -> Project settings -> Script execution order), so use that to make sure your scripts are executed in the correct order. In addition to that, you can use the Awake() method as all Awakes are executed before any Start() method. Hope a combination of these helps you!

I solved this by creating an intermediate variable in my InventoryController script, plus creating a "manual" getter; https://gist.github.com/toreau/f7110f0eb266c3c12f1b
Not sure why I have to do it this way, though.

Related

Finding dynamically generated components Unity

I have a game object and I'm generating a component for that object by
var arcGISMapViewComponent = gameObject.AddComponent<ArcGISMapViewComponent>();
under the Void Start()
However, I have another class that is
public void ReadStringInput(string s)
I also need to show there the existence of arcGISMapViewComponent but since it's not generated yet in the beginning I'm getting an error which is
'arcGISMapViewComponent' could not be found how can I solve this?
You can use Awake() {} to make sure some code (component creation in your case) is called before other Start code. If your different class is not a MonoBehaviour then you should create an event and Invoke it notifying that component was created and from your different class subscribe on that event.

Awake function issues in relation to Singleton

So I was looking into implementing the new Unity input system into my game by reworking my code in my PlayerController script and got stuck pretty early on.
Here is the code that causes issues:
private PlayerInput playerInputController;
private void Awake()
{
playerInputController = new PlayerInput();
}
A green scribbly line appears under the 'Awake()' bit.
The code itself actually works, but it causes a lof of other issues, which makes a bunch of error messages appear saying:
NullReferenceException: Object reference not set to an instance of an object
The error messages all lead to places where I've used lines of code like this one in other scripts, to get variables and methods from my PlayerController script:
if (PlayerController.instance.isGroundedPhys)
Lastly, here's my singleton script, since it's likely relevant, as it's connected to my PlayerController script and allows it to be accessible from other scripts:
using UnityEngine;
public class Singleton<Instance> : MonoBehaviour where Instance : Singleton<Instance>
{
public static Instance instance;
public virtual void Awake()
{
if (!instance)
{
instance = this as Instance;
}
else
{
Destroy(gameObject);
}
}
}
This bit is at the top of my PlayerController script to make it accessible from other scripts:
public class PlayerController : Singleton<PlayerController>
{
I've been looking around and can't find anybody talking about similar issues. I think it's related to my singleton script, but I can't figure it out. :[
[Edit]:
I just found out it also gives this warning in the Unity console:
warning CS0114: 'PlayerController.Awake()' hides inherited member 'Singleton<PlayerController>.Awake()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
PlayerInput is a MonoBehaviour!
No seriously, this is "Not Allowed" and you should actually give you an according warning in the console.
A MonoBehaviour "can"/should only exist attached to an according GameObject and always be created by the underlying c++ framework. It's a c# thing that Unity can't fully prevent you from using new to create one.
The only valid way of creating an instance of a MonoBehaviour are
Instantiate a prefab that has the component attached
use AddComponent on an existing GameObject
use the constructor of GameObject and pass in the according component type(s)
Or you probably rather want to use e.g. GetComponent or FindObjectOfType in order to get a reference to an already existing instance of PlayerInput.
And then the other warning means you implemented
public void Awake()
{
// ...
}
or similar in your PlayerController class. The warning already tells you exactly what to rather do:
// Use "override" in order to not hide the already existing implementation
// of "Awake" in the base class
public override void Awake()
{
// Make sure the base class behavior is executed
// this will initialize the Singleton thing
base.Awake();
// ... your additional behavior here
}

UnityEvent not showing dynamic method call in inspector (other unity events broke partially too)

I have this unity event
[Serializable]
public class UnityEventString : UnityEvent<string>
{
}
Which gets used in this MonoBehaviour
public class EventListenerString : MonoBehaviour, IEventListener<string>
{
//some more code
public EventString Event;
public UnityEventString Response;
//Some more code
}
Problem is, it doesn't show this method in inspector as dynamic.
public void Show(string key)
{
_Show(Animator.StringToHash(key));
}
public void Hide(string key)
{
_Hide(Animator.StringToHash(key));
}
I used to use this pattern for my other events too, and they worked fine until today.
Currently, there are the right methods in the inspector, from earlier this week when i programmed. But today everything stopped working for that.
It also stopped working on a plain test object with a test MonoBehaviour with just one method.
But it still works with that one here
What happened here?
I think unity 2019.2.5 is bugged, going down to 2019.2.4 fixed this for me, all dynamic events came back.
You're attaching a function to run when the event is fired, that function is on a class, the class is a script attached to a gameobject, unity serializes this hooked method as follows GameObject Instance ID -> Script ID -> Method Name -> Parameters.
Now if you move your script to another game object, the serialization system doesn't find said script on the old game object anymore. so the deserialization breaks on the second step, and so does your hooked method.
Hope that makes sense.

How to set different classes at runtime in Unity

I am making a game in Unity C# where the character will have different characterstics and movement functions in each scene. So I am trying to have different scripts for a player in different scenes, while all of them inheriting from the same base class. The definition will be something like below
public class PlayerScript1 : PlayerBase { /* for scene 1*/
public void Move(){
/* my movement code*/
}
}
Similarly, I have a separate class for Scene2 as
public class PlayerScript2 : PlayerBase { /* for scene 2*/
public void Move(){
/* my movement code*/
}
}
Now the problem is, my other scripts, like HealthScript,ScoreScript etc they do not change with scene. But they do access PlayerScript1 script. And thats why, I have the PlayerScript1 declaration in them. Like below:
public class HealthScript : MonoBehaviour {
PlayerScript1 playerScript;
void Start(){
/*accessing the script attached to game object*/
}
}
So how can I have my Health Script access different instances of my PlayerScript based on the scene? I know I could use delegates to call different methods in runtime, but how can I do the same with classes?
So how can I have my Health Script access different instances of my PlayerScript based on the scene?
Well first, you'll want to declare that object as of Type PlayerBase as you will be unable to assign an instance of PlayerScript2 to a variable of type PlayerScript1: those classes might inherit from the same parent, but they are not the same and you cannot convert from one to the other.
After that you will need to search for the player object in the scene, something like...
void Start(){
playerScript = GameObject.Find("Player").GetComponent<PlayerBase>();
}
Assuming, of course, that PlayerBase extends MonoBehaviour. If it doesn't you can't get a reference this way (as it won't exist in the scene at all). Additionally if you want this health object to persist from scene to scene, you need to call DontDestroyOnLoad() for it (as well as remembering that if you don't start testing from Scene 1 where this object is, it won't exist at all, or if you have a copy in every scene, you'll have duplication problems).
Someone answered to my question on the Unity forum which cleared all my doubts:
The key was using the below line in my HealthScript :
PlayerBase player = (PlayerBase)FindObjectOfType(typeof(PlayerBase));
http://answers.unity3d.com/answers/1348311/view.html

Declare a variable class

i need to declare a variable class in my code so i can access a function (having the same name in all classes) but doing each time a different behavior).
and this is my code:
using UnityEngine;
using System;
using System.Collections;
public class Bubble : ItemBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
void OnMouseDown ()
{
theclass.Behaviour ();
}
}
knowing that (theclass gonna be variable ).
Thank you guys for your answer but it is a bit special.
My game is about interaction between player and game objects when the player approach any item that is "interactible" lets say, a bubble shows up, this bubble is a GameObject and it is the same for any object that allow interactions,
So since i am doing a 2D game i thought, it would be great if i make a "universal"
EmptyGameObject that contains all common aspects that anyObject would contain, and i grouped main functions and common ones in a general script and i added it to this emptyGameObject, then i added the Bubble prefab to this Game object and i a dded a code to it this code contains what i wrote in my firs post.
i was thinking that now each time i want an object i just drop this emptygameobject prefab and changes sprites and characteristics.
And each object have a different behavior (ex: i can delete an apple as if the character consumed it but i can not consume a door, the door would rather trigger an animation than being destructed ) i am specifying all this in a class for each item.
now whatever the class is (the object is) the trigger is in the bubble class (which i posted first) but the class will be different each time and i can not make a class that contains polymorphism because its not the same context each time.
I think you should create an interface that declares all the functions you would like to use in different classes.
interface IBehaviour
{
void Behaviour();
void AnotherBehaviour();
}
with this you define a behaviour what a class, which implements the interface, is capable of.
And then your classes would be:
class MyClass1 : Ibehaviour
{
}
class MyClass2 : IBehaviour
{
}
Apart from this you can use abstract classes. There are a lot of well-written articles about these topics on the Internet.
Firstly, I recommend to get familiar with OOP principles.
This link is a good way to start.
Good luck.
Thank you all,
The matter was solved by creating a global (abstract) gameOject that contains the class that we want to inherit from, and then each time the gameObject atached to this class calls (Behavior function) it trigger whatever the override is for this function for this object.

Categories