You’d use them if you wanted to communicate with a bunch of unrelated classes. The interface is a collection of functions with no implementation. The actors with the interface can implement the functions as they see fit.
In short: you call an interface function -sending a message to an actor and it’s up to the actor to interpret it. No need to cast, if the target actor has no interface, or no implementation, the call fails gracefully.
Easiest for constants is to use function library, then make functions “pure” you will get blueprint node that gives some value, just like global constant.
For “global variables” use game mode or game state (depending on multiplayer networking and what works for you best).
Also make sure that your “global variables” survive level load etc.
Great!! now It works, but again…I always need an ‘object container’ for make it persistent, right?
In your example you are using gamemode to make the value persistent. So there is no a ‘pure global’ place to keep the value, right?
I wanted to use function libraries more often and reuse along my projects but I always end creating a custom UObject with the functions instead so I have a container for the persistent data like this:
So I am concluding for now that there is no way a data can be stored GLOBALLY without a container.
I read somewhere using the_project_namename.h file to make global variables but I tried to create some variables there using UPROPERTY(BlueprintReadWrite) there and it compiles but cant access it from blueprints.
I really appreciate all the time you dedicated to this !!
Thanks!!!
Hi Nawrot. for using gamemode or gamestate in function library we must cast and that is what I want to avoid. For performance and for portability to other projects using different gamemodes or gamestates.
I think there is no good and simple way to do it. Constants in pure functions yes. However global variables always need some blueprint or actor to survive, and that means casting. Also Blueprint interfaces are form of casting, you cast to interface class instead of blueprint, but it is casting.
However i am not sure why people are so afraid of casting, it is just telling compiler or whatever: “use this data structure to find your stuff in this area of memory” not much more.
And if your concern is performance, use C++ for critical parts of code (those big cthulu like spaghetti bluerpints), it is amazing how 3 4k screeens of blueprints fit in 10 lines.
There is some kind of ‘avoid casts at all cost’ sect around LOL
I mean…I believe Cast could be expensive y you cast a lot of objects in every tick or something like that…I agree with you that cast has a purpose and we should not be so afraid of using it. But I always try to find a workaround before casting. for example I use a lot of tags and then I cast if I am sure the object I want to process is the object I expect before casting
Yes I Use C++, but usually when I am in my [research and test] free time I do fast tests and try things in blueprints and then I learn and test the C++ part of it
No doubt blueprints is A LOT faster for game prototyping than C++ so my normal workflow is mostly BP…then once things are working as I expect then I translate some blocks of it to a C++ parent class and replace the variables and functions of the BP. Sometimes I even en up with some BP actor that is empty because everything is happening in its C++ parent Class and I use the BP for setting up components and things like that.
ok…I did the performance test for casting…is not perfect but at least I can make some metrics.
I created a level where I spawn 5000 basic actors in the beginplay BP (actor is just a BP with a cube mesh, one boolean variable and a bind event to a dispatch for invert the bool value)
Binded 3 keys for shoot the test.
D - call the dispatcher and all the actors switch the bool. I measure the time before and after the dispatch call and show results in yellow.
T - get all actors with a tag…then for each ( I have to case em! :() switch the variable (val = !val)
show results in green
C - get all actors then for each I cast all the actors to find the right ones and switch the bool.
Results in light blue.
absolute winner: dispatcher.
mindblown: difference between Editor run and Standalone in performance.
Editor results:
Standalone:
wow!! hard to measure and incredible performance boost!
missed a last test to include: put all created actors in an ARRAY and then just a for loop to switch the values without casting at all…surprising results too:
Dispatch is even faster than a simple for loop in an array!
I think that is due async nature of dispatchers because in theory all binded actors are ‘receiving the order to switch at the same time’ (I know it not like that but is async and multi threading task.) while the for loop is sequential so each actor must wait their turn to switch.
This is the editor test with the array, right? Could you please show, how the arrays perform in standalone too? Or could you upload this test project for personal testing? ^.^
Because i had a scenario, where i also would have to deal with hundreds or thousands actors (still unsure, how to set that up, because of communication with each actor), where those actors would be just cubes (cubes, that would be interactable) and your test here covers pretty much covers that scenario.
And does that have a noticeable impact on your GPU or CPU? What does Taskmanager say, if 5000 actors are listening?
Because an array, loop or cast might be slower, but they only hit performance, if you call/use them. Aren´t dispatchers always listening, and therefore always requiring some CPU or GPU power?
I made some asteroids prototype with around thousand of asteroids and it was for mobiles, so optimizations were important.
Best way is to place logic/code directly inside actor , and run it 4-5 times per second. Most actor interactions may be that slow, you will not notice difference, that stuff does not need to be processed every tick. Make parent class with this code, then inherit from it.
To do it we made dispatcher that had integer (just integer counter +1 every dispatcher trigger) sent over to all actors. Then actor had random number in range 0…49. If integer from dispatcher modulo 50 was same as random number from actor it performed its logic code.
So every actor run code every 50th dispatcher call, or we split all actors in 50 groups. With this (and inheritance) you can even improve all that and give different range for random int and modulo operation, so different types of actors can run at different nth dispatcher trigger. Like some every 50th other every 20th call etc.
Then having dispatcher game could monitor FPS, and trigger that dispatcher faster or slower.