Cannot assign function in EventTrigger - c#

As you can see at the attached image, The OnDrag function is not appearing in the event trigger. It was assign before but when i re-open the project, it prompt as missing. It is still working though even with the missing prompt but my problem is when I change or transfer the script to other gameobject. I cannot re assign it again.
public void OnDrag(BaseEventData eventData)
{
RegisterPoint(Input.mousePosition);
}
public void Test()
{
}

Which Unity Version is this?
There was a BUG making the dynamic parameter methods disappear and only display the static ones
Since they are very limited in which parameter can be passed static (BaseEventData not being one of them) it is now not longer listed.
Did you change the Unity version shortly? If so you should use one of the versions this bug was fixed for
2018.4, 2019.2 or 2020.1
At least for 2019.2 I know it wasn't fixed before 2019.2.5 but maybe they also patched them back downwards.

It's better to stick to official recomendations: use only the methods with no parameters or with simple type parameters with Event Triger component - int, string, float etc. Your method OnDrag looks like implemented interface method so it should be called if cursor drag over it will be detected and the object either a child of a Canvas or has an active collider attached, so you actually don't need additional event trigger here.

Related

How can I access a function with the same name held on multiple different scripts in Unity C#

I'm working in Unity on a game with a spell casting system where I have a casting manager script that has a game object list of all the equipped spells (called spells and selectedSpell is just an int that determines which spell in the list is selected so I can cycle through them) and then on each game object/spell, I have a script that will do different things based on the spell. Each game object only has the one script, a sprite renderer, and a transform. The issue I'm having is here:
//Cast manager Script
if (Input.GetKeyUp("c"))
{
Debug.Log($"Cast {spells[selectedSpell]}");
spells[selectedSpell].GetComponent<FireballSpell>().Cast();
}
The Cast function contained in the script I'm trying to access looks like this:
///Water spell named "WaterSpell"
public void Cast()
{
Debug.Log("Sploosh");
}
//FireballSpell
public void Cast()
{
Debug.Log("Kabloom");
}
I threw in a script for now (the "FireballSpell") and it accesses Cast() just fine when I've got the fireball spell selected, however I'm not sure how to access Cast() from my "WaterSpell" for example. I tried doing GetComponent(nameof($"{spells[selectedSpell]}")).Cast() because I've been giving the scripts the same name as the game object, but I just get an error saying, "component does not contain a definition for cast". I'm not really sure how to proceed with this aside from making a bunch of "if selected spell is named x look for this script" for each spell but while it would work, I feel like it could be much more efficient and I don't want to have to worry about adding to the casting manager script if I decide to add more spells down the line.
Thanks in advance to anyone who stumbles on this. If more information is needed I'll try to provide it.
It took a little bit of research since I'm still a bit of a newbie but BugFinder's suggestion of using Interfaces worked. In case anyone finds this and needs it, I created a new script that was just an interface called ISpell that had the Cast method in it and then I made it so my spells could use the ISpell interface. In my casting manager I changed
spells[selectedSpell].GetComponent<FireballSpell>().Cast();
to
var Spell = spells[selectedSpell].GetComponent<ISpell>();
and then I just had to add Spell.Cast();
Thank you BugFixer and also this video

Unity Animation Event - No function selected

I googled and tried a lot and right now just going crazy, cause its just a simple thing that takes to much time to be solved.
So in the web there are two types of posts:
Console gives error "No function selected" and the solution is that some ppl added by accident an animation event and didnt set it up. <-This not what Im looking for
I added an animation event to my clip, but clicking on the drop-down "Function" says "No Function Selected"and does not let me select anything. <- This is what Im looking for. This kind of posts never got an answer.
This is how it looks like:
Hierarchy:
Object 1
 Object 1.1 <- Has a script from where I start animations
 Object 1.2 <- Has the animator. Rotate and scale object 1.2
More Information:
Yes, I selected at first my Object 1.2, selected then the right clip in the Animation-Window and added an animation event.
This kind of posts never got an answer
Please allow me to doubt that.
Simply make sure that your setup fulfills the following conditions:
AnimationEvent requires
the Component from which you want to use a method is attached to the same GameObject as the Animator component
the method you want to call has accessibility and return type public void
the method you want to call has none or maximum one parameter
the supported types for the parameter are int, float, string, UnityEngine.Object, AnimationEvent
Since your script is on another GameObject you could redirect the call e.g. like
public Redirector : MonoBehaviour
{
// Either drag in via Inspector
[SerializeField] private ScriptOnOtherObject _scriptOnOtherObject;
// or get at runtime if you are always sure about the hierachy
private void Awake()
{
_scriptOnOtherObject = transform.parent.GetComponent<ScriptOnOtherObject>();
}
// and now call this from the AnimationEvent
public void DoIt()
{
_scriptOnOtherObject.TheMethodToCall();
}
}

Unity Camera.onprerender & Camera.onPreCull

So I've been researching how to make certain players (both offline and online for consoles and PC) invisible to other players in Unity for both 2D and 3D. I know having a separate layer for each player and their camera isn't efficient or effective and I was looking for something better. After days of research I finally found these:
Camera-onPreRender, Camera-onPreCull, and Making GameObejcts dynamically invisible
But I'm still very confused.
Are the public void MyPreRender(Camera cam) & public void MyPreCull(Camera cam) delegates or something and the Enable/Disable just changing the value of camera to exclude game objects listed in the function? If so shouldn't they be labeled as a delegate to work? If not how does this function change the value of what game objects should or shouldn't be culled/rendered?
Also would this work well for what I'm doing with little hit on performance and frame rate? The other person said it did but does it really? Is there a better and faster way?
Yes, MyPreRender and MyPreCull are delegates (or rather, a method that matches the signature of a defined delegate elsewhere). Specifically, they are Event Handler methods.
When the camera does a Render (or Cull) task, it first invokes all methods that have been subscribed to the PreRender (or PreCull) events (through the use of the += to tell the other system about your handler method).
You can find out more about events from this Unity tutorial.

In Unity, how does Unity magically call all "Interfaces"?

Unity has an "interface":
IPointerDownHandler (doco)
You simply implement OnPointerDown ...
public class Whoa:MonoBehaviour,IPointerDownHandler
{
public void OnPointerDown (PointerEventData data)
{ Debug.Log("whoa!"); }
}
and Unity will "magically" call the OnPointerDown in any such MonoBehavior.
You do NOT have to register them, set an event, nor do anything else.
All you do syntactically is add "IPointerDownHandler" and "public void OnPointerDown" to a class, and you can get those messages magically.
(If you're not a Unity dev - it even works if you suddenly add one in the Editor while the game is running!)
How the hell do they do that, and how can I do it?
So, I want to do this:
public interface IGetNews
{
void SomeNews(string s);
}
and then I can add SomeNews to any MonoBehavior.
The alternate solutions are obvious, I want to know specifically how Unity achieve that "magic" behavior.
(BTW: I feel they should not have called these "interfaces", since, it's basically nothing at all like an interface - it's sort of the opposite! You could say they magically made a way to inherit from more than one abstract class, I guess.)
Aside:
if you've not used Unity before, the conventional way to do this - since we don't have access to Unity magic - is just add a UnityEvent to your daemon which will be sending the message in question:
public class BlahDaemon:MonoBehaviour
{
public UnityEvent onBlah;
...
onBlah.Invoke();
Say you have classes Aaa, Bbb, Ccc which want to get the message. Simply connect the Unity event (either by dragging in the editor or in code), example:
public class Aaa:MonoBehaviour
{
void Awake()
{
BlahDaemon b = Object.FindObjectOfType<BlahDaemon>();
b.onBlah.AddListener(OnBlah);
}
public void OnBlah()
{
Debug.Log("almost as good as Unity's");
}
}
You're basically "registering" your call in Awake, you are indeed piggybacking on the magic Unity use - whatever it is. But I want to use the magic directly.
When it comes to XXXUpdate, OnCollisionXXX and other MonoBehaviours, the way Unity registers is not reflection as it has been widely believed but some internal compilation process.
HOW UPDATE IS CALLED
No, Unity doesn’t use System.Reflection to find a magic method every time it needs to call one.
Instead, the first time a MonoBehaviour of a given type is accessed the underlying script is inspected through scripting runtime (either
Mono or IL2CPP) whether it has any magic methods defined and this
information is cached. If a MonoBehaviour has a specific method it is
added to a proper list, for example if a script has Update method
defined it is added to a list of scripts which need to be updated
every frame.
During the game Unity just iterates through these lists and executes methods from it — that simple. Also, this is why it doesn’t matter if
your Update method is public or private.
http://blogs.unity3d.com/2015/12/23/1k-update-calls/
In the case of an interface, I would assume it does a bit more since the interface is required. Else, you would just add the method like any other MonoBehaviour methods.
My assumption (that could be wrong), it uses a basic GetComponents on this GameObject. Then iterate the resulting array and call the method that HAS TO BE implemented since it is from the interface.
You could reproduce the pattern with:
NewsData data;
if(GetNews(out data))
{
IGetNews [] getNews = data.gameObject.GetComponents<IGetNews>();
foreach(IGetNews ign in getNews){ ign.SomeNews(); }
}
GetNews is a method that checks if some news should be sent to the object. You could think of it like Physics.Raycast that assigns values to a RaycastHit. Here it fills a data reference if that object is meant to receive news for any valid reasons.
You can use reflection to get all types in an assembly that implements a specific interface and then instantiate those types and call the methods on those instances through the interface.
var types = this.GetType().Assembly.GetTypes()
.Where(t=>t.GetInterfaces().Contains(typeof(IGetNews)));
foreach (var type in types)
{
var instance = (IGetNews) Activator.CreateInstance(type);
instance.SomeNews("news");
}
The UI-dependent built-in interfaces like IPointerDownHandler, IDragHandler Etc are called by EventsSystem class/script [this is attached on the EventSystem GameObject that is created automatically, when you create UI/Canvas object] and only work on UI Elements [for testing if you turn off or delete the EventSystem GameObject from the scene or even disable EventsSystem script, these interfaces will not be called and all UI elements will stop working (functionality point-of-view, means your register functions will not be called)].
So, these interfaces methods didn't get called as magically on their own. These are called via EventsSystem script.
Read About Event system: CLICK HERE
There are 3 main components that you need to remember for interaction with the UI elements in Unity:
GraphicRaycaster: It is attached to the Canvas object itself. It is responsible for sending the raycasts to UI elements of that canvas and determines if any of them have been hit. if you remove it from the canvas, no interaction can happen with UI elements of that canvas like click, scroll Etc and these interfaces will not also call. [LINK FOR MORE][2]
InputSystemUIInputModule:: this is attached on EventSystem Gameobject is responsible to tell canvases in the whole Unity scene, What to consider as input for the UI and vice versa. Like what will mouse left-click on UI to consider as input to UI elements, etc.
and It calls method link OnPointDown, OnDragStarted Etc interface related. Read More: LINK
EventSystem: it is responsible for processing and handling UI events in a whole Unity scene. It doesn't work independently and required BaseInputModules to work properly and it also maintains elements' status or user interactions. For Details: LINK
Just for understanding, consider it as a story: The EventSystem uses InputSystemUIInputModule to get input from your mouse, keyboard or touch and on the bases of these inputs, the EventSystem calls to does RayCast for whether you have interacted with any element or not (save references of that element in it) if yes then call built-in functions like hover, select, mouse down/up, drag canceled on that element based on life cycle (the mouse/touch pointed elements are stored in EventSystem.current) via InputSystemUIInputModule.
Now, if you want to call any IPointerDownHander method, maybe they do like this internally on click on the element of the UI and vice versa:
IPointerDownHander pointerDownHander = EventSystem.Current.GetComponent<IPointerDownHander>(); //assumption for making an understanding with the interface being cast to object, if that interface is attached to object then that object will be returned and you will be able to call the interface registered method.
if(ipd) ipd.OnPointerDown(var etc)
or below code Copied from Unity UI Package, where you can learn more accurately about this execution
// Invoke OnPointerDown, if present.
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, eventData, ExecuteEvents.pointerDownHandler);
if (newPressed == null)
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); //copied from the Unity UI package

How to use the "On Value Change" in Unity3D Input Field UI component

I'm following a tutorial on how to work with Unity3d and I've hit a dead end.
I believe something changed in a newer version of Unity since the tutorial seems to work nice the way I'm doing it.
I have an Input Field UI component that I want to call a C# function every time I change it.
According to the tutorial I just have to use the "On Value Change" property of the Input Field (script) and tell it to call some function that takes a string as an argument.
public string playerName;
public void setName (string name)
{
playerName = name;
Debug.Log("Set playerName: "+name, gameObject);
Debug.Log("Get playerName: "+playerName, gameObject);
}
Yet, this does nothing, my playerName property it's always empty and I don't receive anything in name.
How do I go about doing this? I've seen an answer setting up a listener in the Start() function, and then using an UnityEvent in here: Get text from Input field
But is there another way to do this using the Unity3d graphical editor that doesn't involve writing so much code?
Yes you can add event handlers via the inspector. Select the InputField game object and scroll down to the bottom of the InputField section in the inspector. Click + to add a new event handler then select the receiving game object and method you want to call.
Use the Dynamic string version of the function to pass the input string as a parameter. The Static Parameters callbacks let you set the function parameter in the inspector, which likely isn't what you want when responding to InputField changes.
with your comment you just made it all clear. When you use the Dynamic Parameter, the value of your input entry is passed to your function. When you choose the Static Parameter, a new input box is shown in the inspector, for you to write the "static parameter" you want to receive.
Not sure yet how this is useful. But it should make clear the difference.

Categories