Here’s how I have it in my project: the Switch BP has an array of actor variables called Affected Actors. When switch is turned on, it sends and interface message called “On/Open” to each actor in the array. Since the variable is of Actor type, the switch can send the On/Open message to any actor in the level, and even if the array is empty, the switch will still work fine, but no other actors will be affected. If a BP functions properly with no reference to any other actor, that’s not tight coupling. Yes, I have to manually select the affected actors after I place the switch into the level, but that’s the most convenient way to establish connections between actors.
So in this case, in my Switch BP, I don’t “specify the specific object”, I use the empty array of actor-type variables.
When Light1 calls the “subscribeTo”-method on EventService1, the EventService1-object would
store a reference to Light1. If the “toggle light”-event on the EventService1 gets called by any object it would notify all subscribed objects (in this case only Light1) by calling the event “toggleLight” inside of Light1. If Light1 doesn’t implement “toggleLight” then nothing happens otherwise it executes the implementation inside of Light1.
Sure, my diagram is very banal switching both lights off at the same time.
Taking your example: Imagine if one of the switches change the type of class to Switch2, then I would have to change the light blueprint and call Gets All Actors of Class [Switch] and Gets All Actors of Class [Switch2] to make it work again and subscribe to their events.
Ok, clearly I’m doing something wrong. This is actually what I initially thought how interfaces would work. In my caller object I call the message of the interface but I always get the following error:“Message node Interact must have a valid target or reference to self.” So I thought I’d always need to cast and call the object directly… Thanks for clarifying!
One more question: What object needs to implement the interface? Only the object that receives the interface event, correct?
Ok, thanks! I’m using the envelope version (message) but UE always complains and says: “Message node Interact must have a valid target or reference to self.” That’s why I am confused about the decoupling aspect of interfaces
That’s exactly the idea behind the interfaces – you don’t have to cast. You can send an interface message to any actor, regardless anything. However, if you see the yellow pin in the interface call, it means you’re doing it wrong – maybe that’s why you can’t achieve what you’re trying to achieve?
You have to use your_interface_name (message), not your_interface_name (interface call). You can use Interface Call to call it within the same BP, but to communicate between different BPs, you have to use Message.
I’m really tired of people using casts with interfaces.
Like Tuerer said: one of the main points of interfaces is: “DO NOT CAST”.
In the exact moment you cast an object, interfaces becomes useless, since casts allows you to have direct access to the objects.
And in that case, yes, direct tight coupling exists.
So remove the cast. And there it’s: no more tight coupling.
PS: that function “Interact” doesn’t have a little enveloppe in the upper right corner, so, right there is an indication you’re using it wrong. You need to use the “Interact” node with the enveloppe.
Thanks for the explanation! Ok, if I understand correctly the interface allows you to call a function on an object and you don’t need to know what the object type is. However what I wanted to accomplish was avoid having to even send a call to anyspecific object. I wanted to call an event on an eventService object and that eventService would then forward the event to any objects that have subscribed to that event on the eventService, therefore even decoupling the events themselves. As pointed out UE4 only allows sending events or calling functions on objects that implement the events themselves not allowing having a middle man in between. I wanted to abstract the event-sending part as well. But that’s not possible I guess…
The approach Tuerer is describing (having an array with bound objects) is probably as close as I can get.
If for example you have 2 BPs: a light and a door.
Both have to interact with the player and both have different behaviours when interacted with.
So, in both of them you implement an interface that contains, for example, the function Interact:
If the player uses linetrace to interact with objects and if it hits something, it will call the interface function Interact of that object. If the object hitted doesn’t have that interface’s function implemented then it won’t do nothing:
If you have an Actor and you make a child class with the only purpose of having event dispatchers that would also solve the problem. You would only need to cast to the Event Dispatcher Child class and its children could be substituted without any refactoring.
Interfaces are nice for decoupling but when you have a lot of them and all those functions are “exposed” it starts to get messy when looking for specific functions.
Cool, thanks! This is an awesome idea! I just did that and it works! I created a new actor subclass, called it EventService and bound the events to it with the event dispatcher. Both the sender and receiver objects now need to get just the EventService and sender and receiver objects only communicate through the EventService not knowing about each other and therefore having decoupled events. Nice!
The initial question is perfectly legit. And I can also understand and worked on this doing a personal message system.
There is not a basic publish\subscribe system through BP.
It should be something like
publish(senders) → broker(dispatchers) → subscribe (listeners).
It can be done with some workaround.
And yes there is an abuse of Interfaces that are used for something that they are not.
The interfaces should be interfaces that describe an Object(what should do). My opinion they are not the best solution to communicate making the code a mess if you are not able to organize the code very well. That is only My Personal opinion. A system as publish\subscribe could do the code very clear and simple for a lot of situations.
Very simple situation:
I have an inventory, I have 8 slots in the inventory. I click on the first slot. I just want inform all other slots that I have clicked on the first slot (so the slots can change the property themselves - example I want deactivate all slots not clicked).
I could do a “Get all widgets with class” or “Get all widgets with interface” and >>> CALL <<< a function\event\interface. But please note that from a code point of view it means:
not so good for performance ( I Could have a a lot of widgets with that class or interface)
I need to do a loop with the result returned (it is an array)
I also need the node that call the function to deactivate the slots.
with a publish / subcribe system I resolve the situation in a simple and clean way:
on the click event of the slot I simply send a message to all subscribers to the topic “OnSlotClicked”.
All subscribers (the other slots) thare are in “listen mode” on that topic receive the event and can edit their proprierty deactivating themselves.
It is easy from every point of view: