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
Related
This code should call update the info in the table using the inputted username
This calls the script which is currently on an empty object in the hierarchy
This is saved on a different scene and script on unity
However, if I run the code and try to implement it this way, an error occurs as I have functions in the awake and start which only works for the scene it originally was in.
You have multiple options, but before moving on to those, a few notes about designing your classes especially with regards to things you intend to use for DB updates.
Having such features unchecked is a Really Bad Idea™ !Please make sure you do not publish such code unless you're absolutely certain it can ever get in the wrong hands (which it usually can even if not intended).
So how to get those references? Since you need a monobehaviour to get the input and i'm presuming you want to keep this contained on the same object/script i would recommend using the Singleton pattern, the script would have a static member of it's own type that it sets in Awake (and to avoid a second instance overriding it should nullcheck the setting and destroy itself if one already exists).
public LoginDB : MonoBehaviour
{
public static LoginDB Instance;
private void Awake()
{
if ( Instance == null ) // Don't use equals for monobehaviours, google for why
Instance = this;
else
Destroy(gameObject);
}
}
Then you can use that in the calling class to get the reference like so:
var loginDB = LoginDB.Instance;
string userName = loginDB.userInput; // for example
To ensure fully reliable execution you must obviously ensure an instance of the object exists prior to calling that, or you could use a Coroutine to do what's commonly referred to a Lazy Initialize, where you start a Coroutine when initializing and have it wait for the instance ref to not be null before allowing calls to it.
Singletons are at times frowned upon in some circles but they are quite appropriate in environments where you do not get to dictate the architecture such as when using third party game engines. Make judicious use of them, ie only when the use case is something that only one instance should ever be in existence (presuming your database accessing application does not do split screen multiplayer..)
I've tried looking around online for a solution to this problem, but I just can't seem to find anything. In my game, I have an Interactor (The Player) and and the Interacted (The target object). What I'm trying to is find a way to check that the object that I've chosen to interact with has a MonoBehaviour that contains the Method "Interacted", and if it does, run it.
This is what my code looks like now, or at least the important bit. OnInteract runs fine when the interaction is selected. The foreach loop will also correctly return each MonoBehaviour in the Transform selected. I can't, however, run a method after getting its MonoBehaviour because it doesn't recognize the method as existing yet. Is there a way for me to check whether or not the method exists and then run it, or should I be taking a different route entirely? Thank You.
So there's a smart way to do this and a dumb/brute-force way.
The smart way is to give all MonoBehaviours you intend to interact with an interface like so:
public interface IInteractable
{
void Interacted();
}
and then implement the interface in all required MonoBehaviours, which forces you to implement the Interacted method:
public class InteractableMonobehaviour12 : MonoBehaviour, IInteractable
Which you can then make use of by checking:
if (interacted.TryGetComponent<IInteractable>(out IInteractable interactable))
interactable.Interacted();
The dumb way is to do exactly as you asked and iterate through all Monobehaviours and then search for the method in them - you can achieve this with C# Reflection, but in this case it is absolutely not required unless you have no control over the classes you want to call Interacted on, so I will spare you the details. If you do want to dive into that, the first code example on this page looks up a types method and executes it without compile-time constraints and checks.
In case you expect multiple components to implement IInteractable on one object, you might want to iterate over the MonoBehaviours anyway if you get a first match, just in case there is a second (I don't think GetComponents works here with interfaces, although that might have changed).
In that case, you can check if the MonoBehaviour implements that interface:
if (component is IInteractable)
((IInteractable)component).Interacted();
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.
I have two classes, Human and Monster.
both have a Property called MoveBehavior
Human has HumanMoveBehavior, and Monster has MonsterMoveBehavior
I want the HumanMoveBehavior to move AWAY from Monsters, and MonsterMoveBehavior to move TOWARD Humans.
The problem I'm having is where should I put my code to move?
In the Human/Monster class?
Using this approach, I had a Move() Method, which takes a List of all entities in game, decides whether it's a Monster or Human using a method called GetListOfOpponents(List allsprites) and then runs GetNearestOpponent(List opponents);
But this looks really messy.
Should I have a SpriteController that decides where the Sprites move? I'm unsure where I need to put this code :(
Thanks!
You could think of a AIManager that just says:
foreach(GameObject go in m_myObjects) // m_myObjects is a list of all objects that require updating
{
go.Update(); // standard GameObject function
}
After that, each class should take care of its own piece of code. So updating works in the class itself.
So Human says:
// just a class which is a gameObject and also has moving behaviour
// do the same with monster
public class Human : GameObject, IMoveBehaviour
{
public override Update()
{
GoMove();
}
public void GoMove()
{
// human specific logic here
}
}
// This interface describes that some movement
// will happen with the implementing class
public interface IMoveBehaviour
{
void GoMove();
}
With using an interface, you can make the specific language part of the class and you don't have need to ALSO create some class that will handle that for you. Of course it is possible. But in real life, the human/monster is the one that is moving, not some object he is carrying.
UPDATE
Answer to the comment. Because there is an AIManager, or even a complete GameObjectManager would be nice to maintain all GameObjects, you could ask the AIManager for the placed where you could not go.
Because pathfinding is most of the time done by use of some navigation mesh or a specified grid, the GameObjectManager can return the specific Grid with all navigable points on it. You should for certain not define all positions in every monster. Because most of the time, the monster does not exactly know where everyone is (in real life). So knowing where not to go is indeed good, but knowing where everyone is, will give your AI too much advantage as well.
So think of returning a grid with the points where to go and where not to, instead of maintaining such things inside the monster/human. Always check where you should leave what, by thinking about what would be the thing in real life.
The way Valve handled this for entities in Half Life 2, is one of the better ways, I think. Instead of giving each AI its own separate Move methods and calling those, it simply called the Think() method and let the entity decide what it needed to do.
I'd go with what Marnix says and implement an AIManager that loops through each active AI in the game world, calling the Think() method of each. I would not recommended interfacing your Human class with an "IMoveBehavior" simply because it would be better to abstract that into a "WorldEntity" abstract class.
You might have invisible entities that control things like autosaves, triggers, lighting, etc, but some will have a position in the world. These are the ones who will have a vector identifying their position. Have the AI's Think() method call its own move() method, but keep it private. The only one who needs to think about moving is the AI itself.
If you want to encourage the AI to move outside of the Think) method, I would suggest some kind of imperative, such as a Goal-Oriented Action Planning (GOAP) system. Jeff Orkin wrote about this fantastic concept, and it was used in games such as F.E.A.R. and Fallout 3. It might be a bit overkill for your application, but I thought it was interesting.
http://web.media.mit.edu/~jorkin/goap.html
I'm currently implementing a script engine in a game I wrote using the C# "dynamic" feature.
How the system should work is when a script is called, it should register the events it listens for, then return control to the application. Then when an event that the script is listening for is fired the script should execute. One thing I'd really like to implement in the script engine is to have methods with certain names automatically bind to events. For example, the onTurnStart() listener should automatically bind to the turnStart event.
The scripts will mostly need to execute existing methods and change variable values in classes; stuff like player.takeDamage() and player.HP = somevalue. Most scripts will need to wait for the start of the players' turn and the end of the players' turn before being unloaded.
The complicated part is that these scripts need to be able to be changed without making any code changes to the game. (Security aside) the current plan is to have all the script changes automatically download when the game starts up to ensure all the players are using the same version of the scripts.
However I have three questions:
1) How do I register and unregister the script event listeners?
2) Can dynamic code listen for events?
3) (How) can I register events dynamically?
This is my first time using C#'s dynamic feature, so any help will be appreciated.
Thanks
--Michael
I'm not sure you've got the right end of the stick with the dynamic keyword. It doesn't by itself let you interpret new code at runtime. All it does it let you bypass static type checking by delaying the resolution of operations until runtime.
If you're looking to "script" your game, you probably want to take a look at integrating Lua, IronPython, or one of the other DLR languages:-
C#/.NET scripting library
IronRuby and Handling XAML UI Events
Otherwise, the usual thing to do is have something along the lines of:-
interface IBehavior
{
// Binds whatever events this behaviour needs, and optionally adds
// itself to a collection of behaviours on the entity.
void Register(Entity entity);
}
// Just an example
public abstract class TurnEndingDoSomethingBehavior
{
public void Register(Entity entity)
{
entity.TurnEnding += (s, e) => DoSomething();
}
private abstract void DoSomething();
}
The question is, do you want to be able to add entirely new behaviours after compile-time? If so you'll need to expose some or all of your game-state to a scripting language.
Or is it sufficient to be able to compose existing behaviours at runtime?
After your edit
I'm still unsure, to be honest, about your requirement for the dynamic keyword and the DLR. Your game's launcher can download a class library full of behaviours just as easily as it can pull down a set of scripts! (That's what Minecraft's launcher does if memory serves)
If you absolutely must use the DLR then take a look at the links I posted. You'll have to expose as much of your game state as necessary to one of the DLR languages. Events get exposed as first-order-function properties. You shouldn't even need the "dynamic" keyword for basic stuff.
Quick example in IronPython:-
def DoSomethingWhenDamageTaken(*args):
#do whatever...
player.DamageTaken += DoSomethingWhenDamageTaken
The player class:-
public class Player
{
public event EventHandler DamageTaken;
// ...
}
You set it up like:-
ScriptEngine engine = Python.CreateEngine();
ScriptRuntime runtime = engine.Runtime;
ScriptScope scope = runtime.CreateScope();
// In an actual application you might even be
// parsing the script from user input.
ScriptSource source = engine.CreateScriptSourceFromFile(...);
Player p = new Player();
scope.SetVariable("player", p);
source.Execute(scope);
Some links to get you started:-
IronPython: http://ironpython.net/
IronRuby: http://www.ironruby.net/
Lua: http://www.lua.inf.puc-rio.br/post/9