Are closures possible?

Thanks! I appreciate the help. I think I understand what you’re saying, but to be clear: Once I’ve found the “HeroCharacter” that’s overlapping, instead of setting a member + a timer as in the tutorial, I create a struct that has both the HeroCharacter and the timer (basically making my own Closure) and store that in an array. I can be sure I don’t have multiple of the same HeroCharacter in the array since one HeroCharacter can overlap this object once before hitting EndOverlap. This might be a super basic question, but: is a UE4 “array” really more a vector than an actualy array (resizable and stored on the heap, vs having a given maximum size at compile time and stored in place)?

Then in EndOverlap, I have to do a dynamic cast (to HeroCharacter) and then an O(n) search through the array for the HeroCharacter that’s no longer overlapping to remove it. Do you know of a clean way to avoid the dynamic cast and linear lookup? Is it possible to make everything O(1) (which is at least theoretically possible if this were all pure C++), or at least make it O(logn) with a set (or a flat set, depending on how many actor’s you’re expecting, I could see any 1 of the 3 options being best in different cirumstances) instead of an array?

This seems pretty reasonable to me. Furthermore, once animation is added to the enemy’s attack, it’s probably more reasonable to damage all actors within the enemy’s range at one time during the attack animation than it is to damage them all on their own timers (although from a theoretical and maybe even balance perspective, I was really asking about having a timer-per-hero, so I don’t think MJBrune is being unreasonable at all since that’s what my original question was targeted towards, and I’m still wondering how you would do this in the ideal Unreal Engine world).

For the “single timer” solution, the only thing left that bothers me is the “remove the Actor from array”, which, as far as I can tell, would be an O(n) search over all intersecting actors. If, instead of an array, it were an intrusive list, where the entry in the list were a type that is both aware of the intersecting actor and its place in the container (the intrusive part), we could remove it from the list in constant time. This is probably me being bogged down in details too much (because really, how many enemies is any one actor going to ever be damaging at a time? probably never enough to make the difference between O(1) and O(n) run once per intersection noticeable to a player), but for the sake of learning purposes I’m curious if there’s a good/standard way of doing this.

I’m going through the official “Blueprint twin stick shooter” tutorial and have a question about events.

Quick background, since it’s not super relevant: I’m a professional C++ dev, but my only gaming background are hobby projects made 100% from scratch. I want to actually get something done, so I’m diving into UE4. I’m starting with blueprints to try and learn the fundamentals of how things are supposed to fit together, and then I’ll probably switch to C++. (Side question: is this a good idea, or should I just go straight to C++? so far it seems there’s way more “learn UE4” information centered around blueprints, so that’s where I decided to start)

Here’s the actual blueprint I’ll be referencing:

Here, when these objects overlap, he stores the “Hero” as a variable, and sets a timer to hit an event repeatedly until the object is no longer overlap a “HeroCharacter” object. While this timer is running, it damages the stored “Hero” variable.

My question is more theoretical/about “clean code” rather than practical for this project (and maybe worrying about these things is why I can’t ever finish a game on my own). Say there were multiple heroes. How I would want this to act, is that every hero in range would be damaged their own timer, based on when they came in range of the enemy. How I’m guessing this acts is that when any hero is intersected, it starts the timer. From then on, any subsequent hero entering the intersection will replace the single, member-variable “Hero”, and thus will be the only one taking damage from that point on. I’m not sure what happens to the timer, I’m assuming it just gets reset when another hero object intersects (cancels and restarts). What I think should happen, is every hero entering should spawn its own timer, and that timer should hit an event that damages that hero and that timer should be canceled only when that hero is no longer overlapped.

The obvious solution to me is: Have the “DamageTheHero” event take a “hero” as a parameter, rather than storing a single “hero” as a member. The timer would then schedule a closure with that hero parameter captured, which gets called every n seconds (0.5 in the tutorial). This doesn’t seem to be possible, since timers seem like they only work with events that take no parameters. Is there any way to do this in blueprints, or am I trying to stretch blueprints too far? Will this be easy to do if I were to convert this all to C++? Would I be able to create a generic “Timer” blueprint that supports capturing variables to pass to parameterized events?

For the “EndOverlap” part, ideally on the “BeginOverlap” event I’d be able to say “when this overlap ends, launch x event” where “x” is an event that captures that timer (that I have a local reference to, since I’d still be in “BeginOverlap” when doing the capture) in the “set” event, and when it is triggered it simply cancels the timer. Less ideally, I’d store a map of actor references → timers, lookup the actor and cancel the timer if it’s found (which would mean an expensive map lookup that really does not need to happen). I assume the latter will certainly be possible when I delve into UE C++, but is the former possible?

  1. I did the exact same as you. Was using SFML to build my projects. New a ton of C++ but no BP of course. Jumped head first in BP. Would recommend your current path. (I’ve been professionally developing for 3 years with UE4.)

Side note: One thing people don’t seem to understand is the overlap relationship works both ways. So for sayon tick you can get all overlapping actors of a character instead of getting all overlapping actors of the volume.

So personally what I would do for “beautification” and encapsulation is simply create a struct that holds a pointer to a character (hero) and a timer handle. Then instead of set timer by function. Do it by handle. When they end overlap take them out of the array.

This way each damage taker is taken on their timer instead of all at once.

Make a Array(or Set) → Add Actors to it on Overlap → Create timer if there is none yet.

On End Overlap → Remove the Actor from array → Check if array is empty → Clear the Timer.

In the Timer Event → Loop → Add Damage to every Actor.

Dont over complicate things :stuck_out_tongue_winking_eye: if you really want a Timer separate from the Damaging Volume create a UObject that holds and Manages that stuff for you. You can think of it as a Buff Object (Debuffs are the same just with negative Values no need to duplicate Code). There are planty of other things to consider but that depends all on your Game. If you just want to apply Damage to every Actor who entered the Volume a simple array with a single timer is enough.

This doesn’t help at all. This way is the way in the example except for “add an array”. When clearly the solution is simply multiple timers.

What do you mean does not help at all? It does the Job → Damage all in a set interval. And its literally the same as Handeling Multiple Timers except that you start a fresh timer that has to be processed by the Timer manager (it will however start on the exact frame the overlap was called if thats of any relevance → use timers for Precision).

And explain me how you Manage multiple things without a Container like Array/Set/Map? You still have to create Multiple structs with your Solution.

I also made clear that he can Encapsulate in a seperate Object. I choose Objects instead of a Struct since you Probably want some behaviour in said Buff/Debuff Object.

Your Downvote was unecessary. Its a valid Solution.

You can think of a Array as a hybrid. You can set it to a fixed size or preallocate the size but it usually behaves like a vector that dynamicly grows.

You can use Sets or Maps, or roll with your own search algorithm on a TArray. Nothing drasticly different than classic C++. Official docs give you a solid understanding if you look them up.

Btw I don´t think you have to worry to much about this unless you expect a lot of traffic. Premature Optimization basicly =) UE4 has a powerfull Profiler tool that finds you Bottlenecks with ease.

Yes, An array is like std::vector in fact for your first question it has an addunique function but doesn’t have heap allocation if you are using the TFixedAllocator with it: Static array - Programming & Scripting - Unreal Engine Forums . Making sure you only add a unique hero pointer. And yes it would be O(n) but again to avoid that (super premature optimization) you can use the fact that the actor itself can detect it’s overlapping the volume. So you could just as easily just check every tick and take damage * delta time. This avoids the O(n) lookup all together.

There is also tmaps and other containers but they aren’t fully blueprintable. You should be able to make it O(1/logn) possibly. Could you explain a bit on how you would do that?

For the dynamic cast… ehhhhhhhh nope. Not really. You can just create an interface and call the interface message on the actor without attempting to see if it implements the interface… Technically that saves a cast… but I think that might result in a crash. Not sure, try it?

Sure you can start the Timer on the individual Hero/Enemy instances, but what happens if they enter another Volume on the same time? You would run in the same Problem again: Starting multiple Timers, store refs in a container, using a Object to encapsulte or overwrite existing timer or agregate the Values to apply?

You cant get away from this problem more or less =) you have things like Delegates (BP,C++) and lambdas/predicates (in C++) but I dont think it will solve the Problem you facing (if I understood your Problem correctly).

Its either this Volume deals with those Actors instances - or - this Actor deals with those Volumes instances.

If I missunderstood your Problem can you give me some Pseudo code you looking for? And what actuall problem it would solve for you?

The solution you posed gives damage all out on the same tick. Meaning all the damage happens at the same time. The original post is: “How I would want this to act, is that every hero in range would be damaged their own timer”

This directly just says “nah you don’t want that”. Which is honestly why I downvoted your post. It goes directly against the question.

I added a secondary Solution that adressed the Problem. The easy solution I gave is “enough” for the Problem at Hand.

The Timer does not take any Input that he could refference in the event he is calling (would require some changes in C++) or like I said using a UObject that holds any Input he needs, Manages the Timer and has optional custom Behaviour. The actual Problem he faces though is that he wants to get around the the linear Search → when he wants to stop the timer by using closures.

But since he dealing with multiple things regardless what way he Communicates trough thats unavoidable.

Actors have a Hashing Function build in and you can use Set´s with them. TimerHandles don´t custom structures that have a member that has no GetTypeHash implementation will not work with Set´s (so you cant stuff a TimerHandle in there). Another reasson why I suggested a simple Actor ref that would work out of the box with a Set in O(1) search/insert/remove. However wrapping them in a UObject does work (as recommanded by me as secondary solution)

But sure you could provide a hash function inside C++ for the Timer Handle and it would work too. But is all the effort worth it :stuck_out_tongue_winking_eye: to solve the Problem? Thats why we should not overcomplicate things! If its enough to process them in a single timer so be it, if not we do it another way by putting extra effort into it.