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]
Related
I want to use Coroutine in my script. But I couldn't use "StartCoroutine" because I didn't inherit MonoBehaviour.
As far as I know, I have to inherit Monobehaviour to use Coroutine. But now I can't inherit Monobehaviour. Is there any way to use Coroutine in this situation? The same goes for the Invoke function.
Coroutine doesn't work without MonoBehaviour, but if you want to use Coroutine in non-MonoBehaviour class you can transmit MonoBehaviour class in constructor or create empty MonoBehaviour to run coroutines on them. It`s will looks like:
pubclic class CoroutineHost : MonoBehaviour{}
public class NonMonoClass
{
private CoroutineHost _host;
NonMonoClass()
{
_host = new GameObject("CoroutineHost")
.AddComponent<CoroutineHost>();
}
public void RunYourCoroutine()
{
_host.StartCoroutine(nameof(YourCoroutine));
}
// Here is should be your coroutine logic
private IEnumerator YourCoroutine();
//Finalizer need to destroy gameobject
//when non-mono class will be ready for garbage collection.
~NonMonoClass()
{
_host.StopAllCoroutines();
GameObject.Destroy(_host.gameobject);
_host = null;
}
}
I will call what you want to achieve: a Coroutine Management feature and my understanding is that you want to include that feature inside your non-MonoBehaviour class. But thanks to my Remember quote above you cannot do it right now.
But including it in-side a .dll might be possible as a .dll can contain many classes. And you can use Access Modifiers to enforce your rules (the internal modifier is my favorite).
If I were you I would treat Coroutine Management as a separate problem and would build a .dll to handle them separately so that it would not mess up with my game-play business.
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
}
}
I´m using the Lean Touch+ Asset to implement drag and drop for 3D objects. Unfortunately the needed function is not showing up in the OnDelta() event editor.
The example is working, but showing in the event editor. Also I tried an older 2018 unity version and there it works fine. Anyway I´d like to use the newer one.
If I change the Vector2 to a float, it gets listed in the editor, but Vector2 should work as well or am I wrong?
This code is not complete, because it´s not mine and I´m not sure if I can just share it. But I hope it helps understanding my problem.
using UnityEngine;
namespace Lean.Touch
{
[HelpURL(LeanTouch.PlusHelpUrlPrefix + "LeanManualTranslate")]
[AddComponentMenu(LeanTouch.ComponentPathPrefix + "Manual Translate")]
public class LeanManualTranslate : MonoBehaviour
{
public void TranslateAB(Vector2 magnitude)
{
Translate(DirectionA * magnitude.x + DirectionB * magnitude.y);
}
There are basically two types of callbacks for UnityEvent
Static
Static calls are preconfigured calls, with preconfigured values that are set in the UI. This means that when the callback is invoked, the target function is invoked with the argument that has been entered into the UI.
Dynamic
Dynamic calls are invoked using an argument that is sent from code, and this is bound to the type of UnityEvent that is being invoked. The UI filters the callbacks and only shows the dynamic calls that are valid for the UnityEvent.
UI refers to the Inspector in the Unty Editor here.
BUT .. unfortunately there is a Bug in newer versions so dynamic parameters do not work with UnityEvent currently.
(Fixed in 2019.3 and 2020.1 ... don't use those though as the are still in Alpha & Beta state!)
In general Vector2 was afaik never a parameter to be displayed and edited via the Inspector when choosing a static callback type and was only applicable for passing it to a dynamic callback.
Only the basic types like int, string, float, bool and Object references work for the static ones.
As a workaround you can still add callbacks on runtime via script - though it is kind of shitty and only makes sense if the target component sits on the same GameObject as the one with the UnityEvent
public class LeanManualTranslate : MonoBehaviour
{
private void Awake()
{
GetComponent<LeanMultiSet>().OnDelta.AddCallback(TranslateAB);
}
private void TranslateAB(Vector2 magnitude)
{
Translate(DirectionA * magnitude.x + DirectionB * magnitude.y);
}
}
Or alternatively stick with 2019.1.14 where it works as well. There bug seems to be introduced since 2019.2
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);
Alright so I've been continuing to learn about classes and oop languages. And am a bit confused.
If I was to have a separate class for player stats. And in that class I have some private ints and then some functions to change them publicly.
Say I want to change and get those ints From my main class. I make an object and assign them to local variables then I can call the local variables in my main script. Then update the variable in the stat class.
It seems a little silly that I have to make a local variable as well as a separate variable in a different class.
To me it would make sense to just be able to call the separate class in a new object whenever I wanted to access the variables in the stat class but I can't...
Let me know if this isn't clear as I can try to expand more.
Thanks
Ben
You do not have to make new variables in the "main" class ....
you can just use the getters and setters through the object that you created.
Also copying variables from player stats to main class is not a good idea because now you have to maintain two copies of same data, at least until you are in scope of main class. If not handled correctly it can also cause data inconsistencies.
Assuming you are using Java, you can do this.
public class PlayerStats{
private int var1=20;
public void setVar1(int var1){
this.var1=var1
}
public int getVar1(){
return var1
}
}
public class mainClass{
PlayerStats pStats = new PlayerStats();
pStats.getVar1();
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
Thanks for that answer definately cleared things up however, in the object created in mainClass if I create the object in one function how do I use it in another function in the same class?
Depends on how and if the two functions are connected and how central that object is to your class.
If the object is very central to class :
That is, you are using it almost in all the function, your class revolves around playing with that object, then you can create it at class level something along these lines
public class mainClass{
PlayerStats pStats = new PlayerStats();
public void function1() {
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
public void function2(int x) {
pStats.setVar1(x);
System.out.println(pStats.getVar1());
}
}
If two functions are not connected :
Just make a new object inside the function scope, if possible.
This is better than creating an object at class level, because the object becomes eligible for garbage collection after the function is finished executing. Whereas, the object created at class level stays in the memory as long as the object (instance of main class) is in the memory.
If two functions are connected, i.e you are calling one function from inside the second function :
you can just pass the object as an argument, something along these lines
public class mainClass{
public void function1() {
PlayerStats pStats = new PlayerStats();
pStats.setVar1(14);
function2(pStats)
}
public void function2(PlayerStats x) {
System.out.println(pStats.getVar1());
}
}
Also google dependency injection, it is an important concept, try to use it as often as possible. It produces good decoupled and testable design
There is so much more to say, people have written books on this topic, OO Design is an art in itself.