I've got an XNA project that will be drawing several objects on the screen. I would like the user to be able to interact with those items. So I'm trying to build a method that checks to see which object the mouse is over, out of those which is the top most, and then fire an OnClick event for that object.
Checking for the things above is not the problem, but where to actually put that logic is most of the issue.
My initial feeling is that the checking should be handled by a master object - since it doesn't make sense for an object, who ideally knows only about itself, to determine information about the other objects. However, calling OnClick events remotely from the master object seems to be counter-intuitive as well.
What's the best practice in this situation?
Thanks,
Tyler
Don't put the logic in the event handler. Instead have the event handler call another method, passing the clicked object as argument:
// inside the OnClick event handler
ActOnObject(clickedObject);
Then you can call the same method anywhere else in the code, for any object:
ActOnObject(GetObjectUnderMouse()):
I would probably have something like an "ObjectManager", a class that would hold a collection of the objects and would handle the finding of the current object that should be clicked upon, and then call the click function on that object. Since the object itself isnt handling the click (it could but in my example technically the overall game itself, or possibly the ObjectManager is the one that catches the click) then i would just take the object that you want to click on and call something like
Object.Click(whatever parameters are logical for your situation)
in the end I think I am suggesting a very similar approach as Fredrik, however the main difference is I personally prefer the "Object" to know what should be done with the click, and thus call the function on the object itself - which might be what you would do in the function suggested above as well...
Well , for graphical objects (textures , sprites or the kind ..)
public MyObject()
{
....
public AreTheseMyCoordinates(int X, int Y);
}
Where , you get the screen coordinates of the mouse position.
Or you can make a Helper Class:
public static MouseHelper
{
public static IsObjectClicked(MyObject obj, int X , int Y)
{
....
}
}
I`d go with the static helper.
Related
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
I'm working with a VSTO, that uses a whole lot of buttons on a work sheet. I had problems with the ActiveX controls going missing if I tried to just have them stored in the workbook. To fix that, I'm making all the buttons at runtime. Not supper elegant, but I have function to help me with that:
public object MakeOButton(double LL, double TT, string ButtonName, params object[] ActionArray)
{
Microsoft.Office.Tools.Excel.Controls.Button ButtonXX = new Microsoft.Office.Tools.Excel.Controls.Button();
string ActionCall = ButtonName + "_Click";
ButtonXX = this.Controls.AddButton(LL, TT, 18.75, 14.25, ButtonName);
ButtonXX.Click += Interaction.CallByName(this, ActionCall, CallType.Method, ActionArray);
return ButtonXX;
}
I then call this for all the buttons I want to make, and it drops in the right place and names them accordingly. What I'm having trouble with is setting each one of these buttons to the correct click interaction.
Each button should be handled by a different routine which has the name [ButtonName]_Click. I was hoping to not have to declare each button before hand, especially if I want to be dynamically changing which buttons are called.
To do that I need find some way to refer to the subroutine associated with the button dynamically. At the moment, the only way I can think I might have chance is using the string ButtonName_Click to refer to the subroutine. My thought was ether through a collection of all the subs that are in the worksheet, or to be able to refer to it directly.
My best idea (which is in the above code) successfully calls the sub dynamically, but doesn't set the interaction to the click, it just make's it click at creation:
ButtonXX.Click += Interaction.CallByName(this, ActionCall, CallType.Method, ActionArray);
I feel like I must be so close to the right answer. Any help would be appreciated.
The Interaction.CallByName method is actually invoking the method immediately. What you need to do is set it up so that it's called when the Click occurs. The easiest way to do that is to use an anonymous method
ButtonXX.Click += delegate {
Interaction.CallByName(this, ActionCall, CallType.Method, ActionArray);
};
This creates a method that will be called when the Click event happens. At that time the body of the method will run and execute Interaction.CallByName
I read a question ages ago "How do C# Events work behind the scenes?" and Jon answered that all events are similar to methods...
In a purely hypothetical situation, I was wondering if someone could explain or point me to a resource that says when to use an event over a method?
Basically, If I want to have a big red/green status picture which is linked to a Bool field, and I wanted to change it based on the value of the bool, should I:
a) Have a method called Changepicture which is linked to the field and changes the state of the bool and the picture.
b) Have a get/set part to the field and stick an event in the set part.
c) Have a get/set part to the field and stick a method in the set part.
d) Other?
To gain more information about events see this post.
You have options.
If your object already implements INotifyPropertyChanged and your red/green picture is a control which supports databinding, then you can simply fire the NotifyPropertyCHanged event on the bool's set method, and add a databinding on that property to your control.
If not implementing INotifyPropertyChanged, I would still recommend doing something similar. I.e. creating your own event handler, and having the reg/green picture subscribe to the event. Just straight up calling a method from the set of your property creates a tight coupling, which is generally a bad thing to do.
The answer is: It depends.
If your boolean value is in the codebehind class of your visual component (e.g. WinForm) you can call a method ChangePicture without doing strange things. But if your boolean value is architectural more far away from the visual component an event is the right way to handle the scenario because you can not easily call a method on the visual component because the class that contains the boolean value perhaps doesn´t even know your visual component exists. :)
The best way to figure out what you should do is to look at classes in the .NET framework and see how they are designed.
Methods are "doers" or "actions", while you can see events as notification mechanisms. That is if others could be interested is being notified when something happens in an object then you can surface an event and have one or more subscribers to these events.
Since events in .NET are multi-cast, meaning multiple objects can subscribe and therefore be notified of an event happening, that may be other reason to raise an event in your objects. Events also follow the observer pattern in that the subject (your class) is really unaware of the subscribers (loosely coupled). While in order to call a method, the secondary object needs to have a reference to an instance of your class.
Note that, a method in your class eventually raises and event. So let's say you have a method in your class called ChangePicture. Then in the method's implementation, you could eventually raise an event PictureChanged. if someone is interested in being notified of this event, they can subscribe to this event. This someone is typically not the one that made the method call to change the picture.
Events are delegates. Delegates are objects. Event's are actually MulticastDelegates (a base class in the .NET framework). These objects eventually call a method, which is the method that gets called as part of the event notification. So they are slightly "heavier" then just a method call, but that should almost never determine your design.
In Flash 10 there are methods that require that they are triggered from user-initiated actions like button click, keyboard up/down keys, etc.
Is it possible to implement this behaviour in .NET? For example, if we have this subroutine:
void SomeMethod() {
// Here some stuff
}
how to check inside it whether the method was called from a mouse click event handler?
Also we can think of this methods like the protected functions in World of Warcraft, if anyone knows what I mean.
EDIT: Looks like this behaviour is implemented in Silverlight — we can popup file dialogs (open, save) ONLY by mouse click or other user-initiated action, otherwise a SecurityException will be thrown. I want to achieve this bevaviour but in my case it’s not a file dialog but our own methods.
Why not just provide it as a parameter?
void SomeMethod(bool userInitiated) {
// Here some stuff
}
Given that you're already calling it, sometimes from an event handler and sometimes not, you already have that information.
EDIT: Another approach is to have a thread-static field which you set on entry to an event-handler and then reset on exit (in a finally block). Any code which wants to test whether they're "responding to a user action" can then test that field.
If that's not good enough, then I suspect the answer is simply "no".
EDIT: You can get at the call stack (see the StackTrace class) but that's relatively slow and can miss out stack frames due to inlining. There's also Code Access Security which may just about help you - but I doubt it.
It seems that you are writing some sort of plugin API. You want to provide a method that does something the user might not want, e.g. changes the clipboard contents, and you want to ensure that your plugins can call that method only in response to a user action.
The only way I can think of to do this is that the API needs to be continually aware of whether it is currently processing a user-initiated action or not. Presumably there will be some code in your program that calls the plugin-provided code, e.g.
if (plugin.HasHandlerForMouseClick)
plugin.HandleMouseClick();
At this point you will need to remember that this is a user-initiated action. Once the method returns, that’s the end of the user-initiated action:
if (plugin.HasHandlerForMouseClick)
{
_userInitiated = true;
try
{
plugin.HandleMouseClick();
}
finally
{
_userInitiated = false;
}
}
Then, in your “unsafe” method, e.g. the one to set the clipboard, you will have to check this flag:
public void SetClipboard(object newValue)
{
if (!_userInitiated)
return; // or throw AccessDeniedException?
// set clipboard here
}
As hinted by Jon, the field should be declared thread-static. This means that there is a separate copy of the field for each thread:
[ThreadStatic]
private static bool _userInitiated = false;
I have a class that I want to be able the handle the mouse up event for a grid.
I tried to create it with a static method call like this:
MyDataBinding.BindObjectsToDataGrid(ListOfObjectsToBind, myGrid.MouseUp);
The end goal being that in the method I would assign a delegate to the MouseUp
PassedInMouseUp += myMethodThatWillHandleTheMouseUp;
Looks good here (to me) but the compiler chokes on the first line. It says that I can only use MouseUp with a += or a -=.
Clearly I am going about this the wrong way. How can I get a different class to handle the mouse up with out having to:
Pass in the whole grid
Expose the method that will be handling the mouse up as a public method.
Or, is this just a limitation and I will have to do one of the above?
This is not possible without reflection.
Like properties, .Net events compile to a pair of accessor methods - add_EventName and remove_EventName. There is nothing that you can pass as an argument.