I am following a specific Unity tutorial and are told to put a specific line of code in one of my "scene initialization routines". Can anyone elaborate on what this means specifically? Where should I put this line.
maybe he means before scene load?
if yes, try use RuntimeInitializeOnLoadMethod like this example
public class Main : MonoBehaviour
{
// Runs before a scene gets loaded
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void LoadMain()
{
// type your script here
}
}
Related
So, I am working on a unity project that involves a lot of math. It takes about 1-2 seconds for the math to finish on start.
Is there any way to "bake" or "compute" this data before the game starts. I saw something similar done in this script from this project. My project has nothing to do with this script, it is just an example.
I would prefer not to share my code. I need to compute the variables from a method called Initialize()
I fixed this by using [SerializeField, HideInInspector] before the variables I wanted to bake.
Then I would create a new class (can be in the same script). You have to using UnityEditor then your class should be something like
[CustomEditor(typeof(classToBake))]
public class BakeGUI : Editor
{
}
Call function override public void OnInspectorGUI() then call functions of the type EditorGUILayout Then you have to create a variable of the type of script.
using UnityEditor;
[CustomEditor(typeof(classToBake))]
public class BakeGUI: Editor
{
override public void OnInspectorGUI()
{
classToBake bake = (classToBake)target;
if (GUILayout.Button("Compile Data"))
{
bake.Compile();
}
if (GUILayout.Button("Delete Data"))
{
bake.ResetData();
}
DrawDefaultInspector();
}
}
Finally, how to use this.
change classtoBake to the script with the data you want to bake
In the if statements, you can run methods when they click the buttons.
The most important thing
After you have this working, to save your data, YOU MUST have the variables you are going to change have the attributes [SerializeField, HideInInspector]
I work on a physics-heavy project with a lot of rigid-bodies which is also code-heavy. I have a lot of scripts, that create forces, manage joints and so on.
For some reason, sometimes a randomly a certain Object is destroyed. It just disappears and is gone. I can't figure out which script causes that. Is there a way to find out which script called Ondestroy or something.
Thanks for you help.
Put a brakpoint in the OnDestroy() method of your monobehaviour and check the call stack.
To debug your project you can check Debugging C# code in Unity. Once you figure that out and check how to attack unity and stop execution at the set breakpoints you can do with Window->Debug->Callstack to see the call stack with the execution stopped at your breakpoint and see what is being called that leads to your object destruction.
Simply have a component like e.g.
public class DestroyDebug : MonoBehaviour
{
void OnDestroy ()
{
Debug.Log($"{name} was just destroyed");
}
}
Either put a breakpoint there while Debugging your code if you need the exact instances and circumstances or also in the console you already can at least see the entire stacktrace of which classes and calls exactly led to destroy of this object.
If this is still an issue for you (or if anyone else has this issue), I had the same issue and found the solution here, which is to check gameObject.activeInHierarchy in OnDisable like so:
void OnDisable()
{
// If object will destroy in the end of current frame...
if (gameObject.activeInHierarchy)
{
Debug.LogError("Log an error with a stack trace in debug mode");
}
// If object just deactivated..
else
{
}
}
What I'm trying to do is to make the GameManager object persistent between scenes, reading a bit I realized that the DontDestroyOnLoad() method allows this behavior, however I don't understand why it doesn't allow me to instantiate objects in new scenes.
The following code perfectly replicates the main problem:
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject objectPrefab;
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene("Scene2");
GameObject instance = Instantiate(objectPrefab);
}
}
}
From Unity docs:
"When using SceneManager.LoadScene, the scene loads in the next frame, that is it does not load immediately. This semi-asynchronous behavior can cause frame stuttering and can be confusing because load does not complete immediately."
The instantiation happens right away and then one frame latter scene change is triggered. So your game object is instantiated in the old scene and lives there for one frame.
As shingo proposed in the comments you can use SceneManager.sceneLoaded to execute code right after a scene is loaded.
I have a script attached to an UI gameobject that find and get reference to the canvas root gameobject. Right now i keep refreshing the reference every update() in case the gameobject is moved to other place in hierarchy and the canvas root changed .
But i found it performance heavy for my script to keep running GetComponentInParent<Canvas>().rootCanvas every single update() especially when the object is at the bottom of a hierarchy with 1000+ gameobject. So i want my script to only find root canvas at start() and when the object hierarchy changed.
I've found https://docs.unity3d.com/ScriptReference/EditorApplication-hierarchyChanged.html but it is editor-only and won't follow after build. Is there any way to do something similar to OnHierarchyChanged() ? Also using loop to check the current state of hierarchy is out of option .
Some ideas:
First one, GetComponentInParent<Canvas> is expensive, but what
about simply call Transform.parent? You only need to instantiate
parent reference at the begining, and even if you check it on
Update, is less expensive.
Second one, if you know (and you should know) which are the events
that changes your hierarchy, you can create your own delegate,
event, action whatever to track it.
And finally, I'm not sure about this one, but have you checked
Transform.hasChanged? I think this last one won't work, cause
only affect rotation, position etc...but I can't assure it right
now.
To exemplify Idea 2 (I think the other 2 are pretty clear):
using UnityEngine;
using System.Collections;
public class ClassThatCanChangeHierarchy : MonoBehaviour
{
private List<GameObject> objectsThatWantToKnow = new List<GameObject>();
private void MethodThatChangeHierarchy()
{
//your code that affects hierarchy...
foreach(GameObject go in objectsThatWantToKnow)
{
go.GetComponent<ClassThatWantsToKnowWhenHierarchyChanges>().OnHierarchyChange?.Invoke();
}
}
}
using UnityEngine;
using System;
public class ClassThatWantsToKnowWhenHierarchyChanges : MonoBehaviour
{
public Action OnHierarchyChange = null;
private void Awake()
{
OnHierarchyChange = () => Debug.log("hierarchy has changed");
}
}
Unity3D has an interface like this, for any Component on a MonoBehavior you just do this:
public class LaraCroft:MonoBehaviour,IPointerDownHandler
{
public void OnPointerDown(PointerEventData data)
{
Debug.Log("With no other effort, this function is called
for you, by the Unity engine, every time someone touches
the glass of your iPhone or Android.");
}
You do not have to register, set a delegate or anything else. OnPointerDown (the only item in IPointerDownHandler) gets called for you every single time someone touches the screen.
Amazing!
Here's a similar interface I wrote ...
public interface ISingleFingerDownHandler
{
void OnSingleFingerDown();
}
Now, I want consumers to be able to do this...
public class LaraCroft:MonoBehaviour,ISingleFingerDownHandler
{
public void OnSingleFingerDown(PointerEventData data)
{
Debug.Log("this will get called every time
the screen is touched...");
}
Just to recap, using Unity's interface, the function gets called automatically with no further effort - the consumer does not have to register or anything else.
Sadly, I can achieve that only like this:
I write a "daemon" ..
public class ISingleFingerDaemon:MonoBehaviour
{
private ISingleFingerDownHandler needsUs = null;
// of course that would be a List,
// just one shown for simplicity in this example code
void Awake()
{
needsUs = GetComponent(typeof(ISingleFingerDownHandler))
as ISingleFingerDownHandler;
// of course, this could search the whole scene,
// just the local gameobject shown here for simplicity
}
... when something happens ...
if (needsUs != null) needsUs.OnSingleFingerDown(data);
}
And I get that daemon running somewhere.
If you're not a Unity user - what it does is looks around for and finds any of the ISingleFingerDownHandler consumers, keeps a list of them, and then appropriately calls OnPointerDown as needed. This works fine BUT
the consumer-programmer has to remember to "put the daemon somewhere" and get it running etc.
there are obvious anti-elegancies whenever you do something like this (in Unity or elsewhere), re efficiency, placement, etc etc
• this approach fails of course if a consumer comes in to existence at a time when the daemon is not searching for them (Unity's magic interfaces don't suffer this problem - they have more magic to deal with that)
(PS, I know how to write an automatic helper that places the daemon and so on: please do not reply in that vein, thanks!)
Indeed, obviously the developers at Unity have some system going on behind the scenes, which does all that beautifully because "their" interfaces are perfectly able to call all the needed calls, regardless of even items being created on the fly etc.
What's the best solution? Am I stuck with needing a daemon? And perhaps having to register?
(It would surely suck - indeed generally not be usable in typical Unity projects - to just make it a class to inherit from; that type of facility is naturally an interface.)
So to recap, Unity has this:
public class LaraCroft:MonoBehaviour,IPointerDownHandler
Surely there's a way for me to make a replacement, extension, for that...
public class LaraCroft:MonoBehaviour,ISuperiorPointerDownHandler
which can then be used the same way / which shares the magic qualities of that interface? I can do it fine, but only my making a daemon.
Update
Full solution for "ISingleFingerHandler" "IPinchHandler" and similar concepts in Unity is here: https://stackoverflow.com/a/40591301/294884
You say you don't want to do a daemon but that is exactly what Unity is doing. The StandaloneInputModule class that is automatically added when you add a UI component is that daemon.
What you can do is create a new class derived from one of the classes derived from BaseInputModule (likey PointerInputModule for your case) that can handle listening to trigger and raising your extra events then add that new class to the EventSystem object.
See the Unity manual section on the Event System for notes on how to create your custom events and more details on what the input module does.
I hate to answer my own questions, but the answer here is really:
You cannot. You do have to add a daemon.
But then, it's very much worth noting that
Indeed, Unity add a daemon - they just hide it a little.
The final absolutely critical point to understand is that:
Unity screwed-up: you cannot in fact inherit from their lovely StandAloneInputModule. This is a big mistake.
Unity's StandAloneInputModule and IPointerDownHandler family - are brilliant. But you can't inherit from them properly.
The fact is, you just have to inherit sideways from IPointerDownHandler. That's all there is to it.
The fact is you have to make your own daemon ("as if" it inherits from StandAloneInputModule) which actually just goes sideways from IPointerDownHandler family.
So the actual answer is (A) you have this
public interface ISingleFingerHandler
{
void OnSingleFingerDown (Vector2 position);
void OnSingleFingerUp (Vector2 position);
void OnSingleFingerDrag (Vector2 delta);
}
public class SingleFingerInputModule:MonoBehaviour,
IPointerDownHandler,IPointerUpHandler,IDragHandler
and (B) you do have to put that on a game object (it's a daemon), and then (C) it's just stupidly easy to finally handle pinches, etc.
public class YourFingerClass:MonoBehaviour, IPinchHandler
{
public void OnPinchZoom (float delta)
{
_processPinch(delta);
}
That's it!
Full production code for PinchInputModule ...
https://stackoverflow.com/a/40591301/294884
...which indeed inherits sideways from ("uses") IPointerDownHandler family.
My assumption is that MonoBehaviour runs a type check in ctor. Which is why you cannot use the ctor on those to avoid overriding that process. The common solution is that your interface would also require to implement a registering method (Vuforia does that for instance) so any new instance registers itself.
You could also extend MB class with your own MB system:
public class JoeMonoBehaviour : MonoBehaviour
{
protected virtual void Awake(){
Init();
}
private void Init(){
if(this is ISuperiorPointerDownHandler)
{
if(ISuperiorHandler.Instance != null){
ISuperiorHandlerInstance.RegisterPointerDownHandler(this as ISuperiorPointerDownHandler);
}
}
}
}
It does not have the magic of Unity but you cannot achieve the magic of Unity with MonoBehaviour. It require the sub class to make sure it calls the base.Awake() if overriding it.
You'd have to come up with your own side engine system to run your own engine logic. Not sure that'd be worth it.
Another solution is to create your own Instantiate:
namespace JoeBlowEngine{
public static GameObject Instantiate(GameObject prefab, Vector3 position, Quaternion rotation){
GameObject obj = (GameObject)Instantiate(prefab, position, rotation);
MonoBehaviour [] mbs = obj.GetComponentsInChildren<MonoBehaviour>(true); // I think it should also get all components on the parent object
foreach(MonoBehaviour mb in mbs){
CheckForSuperior(mb);
CheckForInferior(mb);
// so on...
}
return obj;
}
internal static CheckForSuperior(MonoBehaviour mb)
{
if(mb is SomeType) { SomeTypeHandler.Instance.Register(mb as SomeType); }
}
}
Now it look like you are doing some magic only with :
JoeBlowEngine.Instantiate(prefab, Vector3.zero, Quaternion.identity);