Help on Event Tick Performance

I’m currently doing a game that has a drag and drop from (item) widget onto world (board game). The drag operation begins from widget blueprint and fires off the event tick at player control BP. The event tick does the following sequences:

  1. First locating current mouse/touch position (using linetrace) and hits boardgrid actor to get boardgrid’s location
  2. Re-adjust dragged item location to snap it to that boardgrid position.
  3. Does many other various For…Loop functions such as checking if item is too big (out of board, then re-snap correctly), switching on grid highlights wherever the item is being snapped to while dragging.
  4. Event Tick stops firing once the item has been placed on the board (Drop operation / Mouse release)

I’ve tried replacing it with SetTimerbyEvent/Function, but it actually caused more infinite ForLoop errors than Event Tick. Eventhough Event Tick works correctly but it was draining the CPU’s performance causing the dragging operation to lag.

Is there any other alternative way to approach this?

This bit sounds like the problem.

Dragging the mouse around and figuring out the nearest board square and lighting it up, can all be done on tick, without loops.

I shudder to ask ( because it’s probably complicated ), but can we see the code?

Hi ClockworkOcean, thanks for your reply! You are right, the ForLoop functions after Linetrace did caused the lag. My BP is quite messy though hope you dont mind :sweat_smile:


It starts with BP Interface from fired Widget by switching on Grab Mode. And at event Tick, if Grab Mode is switched on, it goes into the Grabbing & Snapping function


This Grabbing & Snapping function has few other functions inside it. First it goes into Snap Mode function, thats where the Linetrace processes and gives the board’s hit location result. If result is true, then it will set the new location for the grabbed item to be at that position.

I think the problem might be accessing my grabbed item block piece. I have grabbable blocks which are like Tetris shape, and each piece is serialised as ABCD. So the ForLoop function checks for each ABCD piece location whether it is out of bounds (from the bound) and re-snaps back to the correct board positions. Below is a video what I’m trying to do. You can also notice the frame rate

I made a ‘snap mouse position’ blueprint. The mouse is snapping to the location of the mesh +/- 100 units in any direction.

I haven’t tried applying this logic to the positioning of the pieces, but maybe it could be adapted?

mousesnap

For it to work correctly, the mesh pivot needs to be in a sensible place

I think I can adapt this for the grid board snapping :smiling_face:

Just a question though, does the ‘Get Hit Result under Cursor For Objects’ work for Touch inputs? Because I’m currently substituting the mouse as touch input under player controller settings.

The logic for ABCD pieces is the troubling part for me, because I needed to run ForLoop process for it (ie. From Piece A to Piece D), check what is it’s location, at every tick frame.

Each block that are spawned, it will be rotated randomly, therefore it needs to go through ForLoop functions. Sometimes, it spawns 2 or 3 pieces (AB or ABC) at random iterations, so I can’t really hardcode it to smoothen the performance.

And while the ‘snapping to board’ logic is workable, the block piece shall also snapped to the other already placed blocks on the board. I applied the logic of having invisible meshplanes on each ABCD piece, and the linetrace will detect on which plane it hits (eg. it hits the top part of piece A) from which it will then snap it on the location above that plane.

I’m just not sure if those logic I applied above were causing it to slow down its performance. :pensive:

image

:slight_smile:

Can you describe the ABCD stuff a bit more?

You only spawn one piece at a time, right? ( or no? ) Or do you mean the possible orientation of the piece? Surely the player can choose that.

Probably better to have a short-circuiting function, rather than a loop. A function will use the first return node that matches and skip the rest.

Ah Cheers for that :laughing:

Yes, it only spawns a block once at a time. But it randomly rotates the block at each spawn. The player has to choose how to place it on the board.

But each block contains 4 pieces (ABCD). Here is an example image of a block that contains pieces ABCD.

So imagine each ABCD piece will occupy a position on the board and I’ve setup a data struct to get each piece’s information like the BP below.

The Block Data Array Index which shows ‘0’ indicates for piece A. (1=B, 2=C, 3=D). I will run ForLoop function to access each piece information.

And then it will compare its location to the Board Grid data location, (eg. is Piece C out of bounds?) or is it clashing with another piece on the board (eg. is Piece B overlapping with another block’s piece A on the board).

Yes, I did apply the ForLoop with Break functions and return node to do this checking process. Not sure if this MANY ForLoop functions was the cause :sweat_smile:

I get it now. Will think about it.

Yes, it will be the cause, but I’m actually wondering if you’re doubling up somehow, loops on top of loops etc…

PS: I’m assuming the shapes will be ‘flat’, ie not 3D?

Cheers for that ClockworkOcean, really appreciate your help :smiling_face: :pray:

Yeah, the gameplay concept is intended to be 3D, not 2D. and yes, I AM doubling up at the moment, cos I can’t think of any other logic :sweat_smile:

I would do it like this:

When positioning pieces, use world coordinates at the last moment, just to physically place the piece. The rest of the time use ‘snapped’ locations like 0,4,7 or 5,0,3. Much easier to compare.

Each time you move a piece, set it up so that all the other pieces bind to a dispatcher in the piece you’re moving. Then, as you move it, each segment dispatches its snapped location.

This will cause all the other pieces to check their location, but only report back if relevant. If they report back, you know the piece is not positioned correctly.

If you’re going to have a tower 300 pieces high, you will need to exclude pieces based on distance, otherwise it will still slow down.

I’ll make a mock up of it.

Also, using snapped coords, it’s much easier to know if a piece is outside the board, because one of its coords will be negative.

This is quite hacky and incomplete, but…

So, we have a central ‘check position’ actor that sets up a dispatcher

Every piece that’s placed in the map, binds to this dispatcher

In other words, when this dispatcher is called, the function ‘segment at position’ looks to see if any of this BPs segments are in that position. If they are, we put ourselves as the blocking actor.

Then we have the code to check if we can place a piece

We ask the dispatcher to send a signal to all pieces. If, after that, there is no blocking piece or it’s us, we can place.

A few notes

  1. We could temporarily disconnect from the dispatcher to avoid our own position checking code being called. Then we also don’t need to check if we are the blocking actor, and it would be more efficient.

  2. I assume that this will work in one tick. IE, the ‘blocked by’ actor will be set by the time we check it. You’d need to test that.

  3. I don’t know how to make a dispatch not call by reference, which is what’s giving the blue NOTEs under the nodes.

Anyway, this is the general concept. Does it make any sense?

1 Like

Yes I got your general concept :smiling_face:

I get that the whole idea is to try avoid using ForLoops and reduce checks at every tick frame as much as possible. What I learned most from your sharing is that I think checking XYZ from a grid data manager to get its coordinate can be done via math calculation alone, because I actually used ForLoop to scan through the grid data array.

Will need to spend a few weeks to re-structure my code again and will let you know by then if it works or not. Cheers and really appreciate your help!

PS. I’m just a hobbyist developer, got a full time job) :joy:

1 Like

Even with this method, every other piece will check all of it’s segments every time you propose a new position. ( That’s another way to cut it down a lot actually, don’t check or move on tick, only bother when the new coord has changed ).

Another great way to avoid unnecessary checking, is to not bother if piece A is further than a certain distance from piece B. This would only apply once you get into 10’s of pieces.

In your vid you only have 2 pieces, and it’s stuttering pretty badly. Even if you’re checking everything on tick, it wouldn’t do that for 2 pieces. That’s why I think there might be something up with your logic…

I just thought of another approach

Is it possible to try Event OnComponent Begin/End Overlap for the Grid highlights? When it ‘touches’ or ‘overlaps’ with the moving pieces, it will do both re-snapping its positions and performs the highlighting function?

Will that help with the performance?

Yes, that’s a good approach, but make the collision boxes smaller than the cubes :slight_smile:

The collision boxes need to be in the board piece BP. Then you immediately know if you’re overlapping another…

Also, why not just put some big collision cubes outside the space? That way you also don’t have to check that!

( like, duh, why didn’t I think of this before… )

I just tried it, works fine :slight_smile:

1 Like

I just tried it out as well, it works! :joy: :joy:

but hey, without your point of views, that thought process wouldve never came to me. At least it helped me to think of another approach

The frame rates improved a lot actually. Really much appreciated bro! :+1: :+1:

No worries. Trouble is, something I try and do, is stay in the mindset of the person I’m trying to help, because it’s not very helpful to say ‘hey, just totally change your approach’.

Here, that didn’t pay off… :rofl: