Download

Good way to implement global triggers for round based game

Hi,

whenever a round in my game ends, there are obviously a lot of actors that will need to be notified. Some units will move, some buildings will produce resources, some AI will calculate the next move…

How would you essentially globally trigger events in most actors without a whole mess of casts and references?
Right now I have a widget button triggering an event in the player controller.
The P.C. has arrays for every type of to-be-notified actors, and multiple for-each Loops triggering “RoundEnded” custom events in the actor-arrays. I can’t even trigger them all in one go, since obviously even though the actor events are named the same I cannot trigger different events from multiple actors.

I also fail to see the advantage of a blueprint interface - since I’d still have to set up all connections manually all the same.
I thought maybe a “Round-ends”-Blueprint component. But that still requires some messaging setup.
Ideally of course would be an event along the lines of “Event Begin Play” - just for ending rounds.
But I guess that does not work.
How would you do it? What would you consider efficient?

Thanks in advance and kind regards!

If you’re single player, or if these events are server side, then the GameMode is a reasonable place to put events like these. Everything that needs to know about turn progression, can register themselves with the game mode. (You’d presumably have a TurnBasedGameMode subclass of some sort.)

1 Like

But still with the same process I am doing already, just in the GameMode rather than Playercontroller?
I just got a random theoretical Idea… I know i can’t “pass through” events from a BP.Component to its parent without setting up an interface. But an event can be fired if a component activates. Maybe I could get all objects with some roundEnd component in the gamemode and instantly deactivate and reactivate them whenever a round ends. That triggers the event in the parent actor. Sounds a bit shoddy, but it might works^^

…and said component could write its parent into the Gamemode. No need for unnecessary casts and get actors. And this way I only need one array for actors of any type rather than specific ones.
Then I would just drop the nextRound component on an actor, click “on component activate” and im done! :slight_smile:

Make messaging system something like windows has:

  • in game mode create event dispatcher, lets call it my_message, make it triggerable by event or something that you can call from other blueprints
  • in every actor that needs to know about round end etc, assign to that dispatcher.
  • create two parameters that can be sent to dispatcher and received: enumerator (like type of message), and string value. Trough string you can “Transmit” any kind of data, integers, strings etc.

When you have all working you can try to place all actor side code into blueprintable component (that you can add to actor later), sometimes it can be done but sometimes it is not worth all that coding trouble (lots of complicated casts etc.)

Also if you want create flexible systems like that look into inheritance:
make base class that has all that message code
then inherit all different blueprints from that parent

1 Like

That’s because you aren’t thinking about placing your code inside a component and adding the component to the actors…

If the code is standard, this works well.
You also have access to “parent” and theoretically do not need to cast to it in order to pull variables (as they become part of the same BP).

You can do this with child actors too, but those do need casting.

Event Delegates.

I use them to communicate with 100’s to 1000’s of actors across the game. No need for loops, actor look ups, casting, or arrays etc.

If i may ask: Are your mentioned Delegates and Event dispatchers the same thing, or are they different? I just have discovered event dispatchers recently and how they work ^.^
(since i too wanted something, that allow communication between 100 - 1000 actors of different classes, still not sure, how exactly they work, but right now, they work as i imagined it).
And is there a performance hit noticeable, or an upper limit for how much messages at once you should send or how many actors should listen to those event dispatchers?

Honestly, this method seemed extraordinarily easy and convenient compared to the node-salad of the alternatives. It worked aswell - but just because of the possibility of it messing up later on - after all it’s not really standard practice - I will maybe switch over to event dispatchers.

I second this.

How is that? I mean I know I don’t have to look for the parent, since it’s accessible with the “get owner” node, but if I want to grab a variable from it wouldn’t I still need to cast the ‘get owner’ to some specific actor?

Thanks for all your replies so far!

Yes, Dispatchers.

The dispatch execution doesn’t have any weight. The logic processed on the receiving end is what matters. If Heavy you should probably call in batches, or have separate events that are called in sequence with a delay in between. Personally I’d use Set timer by Event.

My game has large levels with interactable actors such as doors, windows and player collision overlap item spawning. When players join they are spawned in the game world and are allowed to free roam until round start. During this time the majority of interactions (windows, item spawning etc) are disabled. On round start the GM fires a round start event. This event enables interaction on the world actors.

Not using event dispatchers I would have to use Get all actors of class → Loop → call event. This is expensive. Especially the loops when dealing with say 1000 doors that have to be reset (closed). Then say 3,000 item spawners collision enabled, 1,800 windows (destructible glass) collision enabled, not hidden, 100’s of vehicle spawners initiated. Etc and so forth.

Example…

Game Mode:

Event Receiving actor:

1 Like

Not if you setup your parent actor class efficiently.

For example say I have a Gun Class. I create all the structs, variables etc in the Parent class, then create a child class … “M416_Weapon”. In the child I use Begin Play to “set” values pulled from a data table. Now when the actor is referenced (Gun Class Object Ref), I have access to all the pertinent values without casting to the specific class.

Thanks for that great explanaition and example :slight_smile: and for that hint with timers. For what i had in mind, i already played with the idea to have some kind of delay or batch etc… because there would be a ton of actors communicating with each other.

My idea until now was like: Every actor does not immediately execute it´s logic, but registers itself in a list, and then an event sends an execute signal to all those in that list to allow them doing their stuff. And if the number in that list grows to big or above a certain number, only the first half (or all actors until number X) shall be allowed to execute their logic, while the rest have to wait until the first half is finished.
And in a kind of round based fashion, the next game round would only start after all actors from that list were able to execute their stuff, no matter how long it takes (cuz the list was way to big to make it in one go).

The way I’d approach batching would be through config based grouping (enum identifier in parent class). Create multiple dispatcher events per class and call those dispatchers with a timer.

Using my previous example I’d have 2 or more item spawner dispatchers ( dispatch 0, 1, 2 etc), then the same setup for the next large group. In the parent class for spawners I’d bind all of the relevant dispatchers, but only execute based on a branch check.

Game Mode:

Actor:

The enum “Batch Group” is the identifier. All spawners will get each dispatched event, but only execute logic matching its assigned group. The Logic after the branch can even be different, or simply pipe to the same function.

Bit of a manual approach, but it negates any need for multiple classes of the same actor. Drag the actor into the map, set the config based group, done.

As for the GM’s execution chain I wouldn’t worry with call back check ins for “we are done” processing. Profile your times for each group.

e.g. Item spawner group 0 takes 0.2 seconds to complete. group 1 takes 0.212 seconds.

Add a buffer to processing times. So if the average is 0.15 add another 0.05 to it, then multiply by loop count. You’ll see this in image 1… “0.2 per, 0.4 total”. The next timer adds an additional buffer of 0.05 to its its time.

You’ll have to do a lot of profiling. These values will change as you add more to your game and game mode. They may change based on player load, number of players… even the connection quality (ping, loss, jitter) could have an effect. The GM only resides on the server. Player connections effect its performance.

Callbacks can also induce hitches. For example say Group 0 doesn’t callback. There’s a soft error or other issue. The rest of the chain/sequence never executes. Dead Game.

For this type of processing I wouldn’t want to rely on any form of check-in. Time base sequences and troubleshoot any and all dev hitches during the process.

3 Likes

Extending on my last post…

You can pass a value in the event dispatcher. So instead of making multiple dispatchers per group (spawner, door, vehicle etc) you’d simply pass the group you would want to process.

And on the actor side …

Lots of great suggestions already but its getting intricate / complex quickly too. :stuck_out_tongue: So FWIW I’m going to take the flip side / counter-view on this, maybe because I’m not that big a fan of Event-Dispatchers anyway if I’m being totally honest. :wink:

They’re a great tool. But even when using Create-Event to loosely bind everything, they tend to get in the way and clutter gameplay code imho, and so feel more invasive as regards game-code plumbing. Whereas Interfaces definitely feel lighter. As some of the boilerplate / lifting is done in self-contained BPI / Class settings.

However what if you have lots and lots of small actors or BP’s in your game. How much re-wiring are you going to have to do to implement Event-Dispatchers? IDK… A little / A lot??? But if you’re already ticking these actors or running them on timers and the performance is fine, what then??? Is old-school polling for a central game-over var in Gamemode to reset all the actors such an awful and bad thing? Maybe… Or maybe not…

It just depends on whether code simplicity is a factor vs performance. The golden rule is to make everything in a game event driven. But if that comes at a cost of code reading or complexity, then maybe its time to tear up the big rule book and just keep things simple / simpler. After all this is game dev not a SCADA control system. :stuck_out_tongue_winking_eye:

Another approach also, is to think about breaking-up parts of gameplay into separate BP classes, that can be destroyed and recreated (or procedurally driven). In that case just throw away the old game actors (destroy them) and recreate them again. It does require research on the subtle differences between Level-Design and BP-Level-Design. But hopefully Epic will improve this area, as it offers lots of options versus always having to rely on Levels and running into lots of Level-Streaming grievances. :wink: