Tick Group vs Tick Prerequisite

My character is interacting with moving platforms. It is critical that the platform movement components & scene components for rotating platforms tick before the player’s CharacterMovementComponent. If the character ticks before, it gets stuck in the platforms and has inaccurate sweeps for wall slides, etc.

Platforms tick in TG_PrePhysics
CharacterMovement by default ticks in TG_PrePhysics (and usually ticks before the platforms when sharing the same group)

Option 1: Put CharacterMovementComponent in a later tick group (ie. TG_StartPhysics)
Option 2: At BeginPlay, add CharacterMovement Tick Prerequisite for every platform movement/rotation scene component (will be upwards of 100+ components and/or actors depending on the level)

Both options fix the problem and achieve the result I’m looking for.

I’m just wondering which one of these solutions is more efficient.

I’m unsure how Tick Prerequisites are handled internally and I’m worried that having to iterate a sizable list every tick could get nasty. I feel like Unreal Engine probably does this efficiently and just shuffles tick order at the time AddTickPrerequisite() is called? Is it normal/acceptable to have a large list of tick prerequisites?

I’m inclined to keep the CharacterMovementComponent in TG_PrePhysics because that is logically where it should be ticked even though I’m not using any physics interaction. In theory it shouldn’t matter if I move the Character’s tick group? It feels a bit wrong and is the most simple and elegant (but possibly short-sighted?) solution.

I’m using Unreal Engine 4.27.2

Thanks so much in advance!

if your game has gravity, walls, floor, colliders… then you are using physics
the general effect of physics is just making sure that blocking collision gets corrected for (although processing input before physics sometimes leads to exploits), but performing say movements in Post_Physics can lead to perhaps an actor being inside a wall at the draw step.

The engine holds all Tick groups as separate lists/arrays, and then uses Tick Prerequisites as a sort priority.

because Vector style Lists/Arrays (a TArray is an example) can potentially be “random order” means that it should be sorted every so often (if not every time it is referenced), so in the worst case by supplying a Tick-Prerequisite you can be causing a Sort of the lists every frame. the good news it should be a simple single compare on the sort step, and the TArray utilizes a form of Quick-Sort which is “effectively” O(n) (“low” Big O is not an absolute good, because it simplifies a LOT of things)

in terms of “pure performance” the separate Tick groups should be the “most” performant (why worry about sorting a list if random is ok and the thing that would be at the end is just on a separate list), but doing work on StartPhysics could be fine as long as it isn’t computationally expensive. input is typically dealt with before the Pre-Physics Tick-Group is even called, and that is where player movement “typically” happens.

the Tick-prerequisites can create memory dependency/overhead especially if done in blueprints, because of blueprint references being hard memory includes.

1 Like

Thank you so much for the detailed explanation! Sorry I didn’t notice the response until today.

I assumed Physics tick groups were related to the “Simulate Physics” option on things like static meshes. I’ve heard Character physics is dealt with very differently and purely simulated in the CharacterMovementComponent but there is still a lot of the engine that I’m not super familiar with.

The effect you mentioned with actors being inside a wall at draw step is what I was experiencing when the CharacterMovementComponent was ticking before the platforms’ movements. It seems important that the platforms are in their final destination before the character does all of its penetration resolution.

I’ve only just discovered PrimaryComponentTick.bHighPriority. It seems like if I set this flag to true on the platform’s movement/rotation components, I can achieve the same results as changing tick groups.

I’m still experiencing clipping with fast moving platforms even at very high FPS unfortunately. I’m not sure if you or anyone else has any more advice in that department but I’ll take anything I can get!

Thanks again!

the Tick groups is just when in the “Game Loop” the given Tick() is called.
Game Loop: Input buffer read/resolution → Pre-Physics Logic → Physics → Pre-Render Logic → Render → Post Render Logic → Reset

many game engines will skip the “Pre-Render Logic” portion; because there might be interactions that modify all the resolution the Physics step did. Many Engines would treat the Physics and Render steps as nearly sacred; preventing anything but those things from happening again because it might make unexpected things happen.

“Incorrect” resolution of overlaps for objects that are set to block each other can be a variety of things:
-A smaller response on a given frame can reduce the likelihood of a sudden rapid movement or a “zip” from occuring.
-The actual colliders that the block was calculated against are close to the mesh, and “Floating Point Approximation” didn’t leave a buffer resulting in still a tiny overlap.
-The object(s) moving “too quickly” resulting in a blocking object being fully inside another object it is set to block, meaning the Physics system doesn’t “know” how to resolve the situation (which object does it move out of the way, what direction does it move it, should it be allowed to move it)

it can also vary by how the object is moved, if the object is moved by SetLocation(bTeleport = true, bSweep = false) then according to the physics system the given object just exists there at that moment and it has to deal with it. for anything that could like push another actor make sure that bTeleport = false at the very least, bSweep = false to make sure the movement is not prevented due to “potential” collisions.

The simulate Physics thing has to do with rag-dolls, momentum conservation through collisions, torque, gravity effecting projectile movement, and a few other things that go beyond collider resolution, and objects falling due to gravity.

1 Like

Thanks so much for the info!

As for the “incorrect” overlap resolution, it is unfortunately the 3rd one you mentioned (moving too quickly). But unfortunately the game is inherently about moving quickly.

When I step through frame-by-frame. The platform moves enough in 1 frame to cause the CharacterMovementComponent’s penetration resolution to pop the character out the incorrect side.

The linear moving platforms are moved with MoveUpdatedComponentComponent() where sweep is false and ETeleportType::None. The rotating components are moving child components with PrimitiveComponent->SetRelativeLocation() where sweep is false and ETeleportType::None.

I was hoping you’d mention something obvious I had overlooked but it looks like I need to get my hands dirty.

I’m writing my own penetration resolution that gets called on the CharacterMovementComponent’s Tick that will hopefully pop the character out the proper side. I tried overriding GetPenetrationAdjustment() but it doesn’t seem to get called frequently enough.

Thank you so much for your responses! Its always great getting answers that teach me new things. I really appreciate you taking the time!

a “semi easy” solution if you need to circumvent, or “help” the interpenetration correction would be to give these moving platforms a scene-Component (maybe an arrow so we can have a meaningful/visual indicator of “Forward”) and a collider set to overlap the entities in some meaningful way. Put the SceneComponent on the surface (or slightly above) and have it’s forward point normal to the surface. then you can use the collider to determine if anything is overlapping.
with this setup you know what needs to be corrected and a “safe” direction to move them in, the final step would be managing the offsets (because the relative origin could be either center of mass or animation root depending on your setup)

there is a “dirtier” approach where you give these platforms an overlapping collider, and when you go to move the platform by a known delta-Vector you move everything in that collider by the same delta-Vector.

1 Like

I really want to avoid cluttering up the actors with a ton of scene components and I think I have nearly all the information I need with a sweep and HitComponent->PhysicsLinearVelocity.

I finished a proof of concept yesterday with some (quite literal) edge cases that still need to be worked out.

Before the character moves, I do a capsule sweep from CharLocation->CharLocation+(Velocity*DeltaTime). If bStartedPenetrating==true, I resolve the penetration manually before the default CharacterMovementComponent penetration resolution gets to run.

Since the Sweep HitResult will give us a normal to escape penetration when bStartedPenetrating==true we can easily flip it if we need. If DotProduct(PlatformVelocity, HitResult.Normal) < 0, we are probably trying to clip through in the wrong direction.

Flip the HitResult normal and try to escape in the opposite direction by attempting sweeps every x units in this direction to the character. When one of these sweeps has bStartedPenetrating==false, we move the character to where the sweep encountered the hit + default pullback distance (0.125).

With this its very difficult to clip through a fast moving platform even at lower FPS. However, if the platform was so fast that it never penetrated the character at all, then it falls apart. I’m testing with my “worst-case” platform speed and FPS (20) and it seems to be catching every one.

The edge cases I’m working with now:

  1. Approaching a vertically-moving platform from the side gives us a dot product of ~0 which can zip us all the way through the platform. This is ~hopefully~ easy to fix.
  2. When we’ve clipped in the corner of a platform, its kind of a crap shoot where the HitResult suggests we pop out. This seems like the real final boss.

Here is a silly picture I made when trying to describe the solution to my girlfriend. You might get a laugh out of it.

Anyways I doubt you can reasonably be expected to offer much more help as its getting a bit complex at this point. I figured you might at least be interested in the direction I’m heading. Thank you so much!