The Unreal InterpToMovementComponent is a great example of how incomplete the current moving object system is in Unreal. If you put a random physics affected object in the way, the things I’m describing below will happen. (Also try standing on top of the object, it’ll slowly sink into the ground. This may be a bug, I fixed it by adding MoveComponentFlags |= MOVECOMP_IgnoreBases; to the movement component so objects on top don’t push the object they’re standing on top of down)
In Unreal and physics engines in general, Kinematic Bodies are unmoveable and don’t have forces applied to them. They just magically move and push everything that is physics controlled. So a box that’s affected by physics won’t push back against a moving platform that is a kinematic actor. The moving platform will push the box, until that box itself runs into a wall. That moving platform will then happily just keep clipping through physics affected object that are rammed into a wall unless it detects the collision and stops. But detecting a collision and stopping means even the tiniest peice of debris can instantly stop a giant moving platform. Unreal’s Component Movement functions don’t take physics or mass into account, they simply sweep until a blocking hit. Characters are also Kinematic Bodies. So you could be playing as the tiniest character ever but nothing in Unreal can ever stop you from pushing an insanely massive object out of the way, unless the character collision stops short of bumping into the object in the first place.
I did start working on a Crush Detector component that can be added to any actor and it’s sortof working. It feels a bit hacky but basically I’m tracking the current accumulated impulses from hits this game tick. If the dot product of an incoming hit is the opposite of the current accumulated vector then it thinks it’s a crush. It’s far from perfect but as a prototype it kinda works.
I have an idea to make the crush detector component communicate with a moving platform movement component. If the platform should crush the object being crushed, it’ll destroy it. If the platform should keep pushing the object until there’s an obstruction, the platform will be told by the crusher detector that it’s being obstructed, otherwise, the moving platform will keep pushing the physics objects.
void URDBaseCrushDetectorComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
AccumulatedImpulse = FVector::ZeroVector;
}
void URDBaseCrushDetectorComponent::OnComponentHit(UPrimitiveComponent* HitComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
FVector NormalImpulse,
const FHitResult& Hit)
{
float IncomingImpulseSize = NormalImpulse.SizeSquared();
float AccumulatedImpulseSize = AccumulatedImpulse.SizeSquared();
if (IncomingImpulseSize > 0.f && AccumulatedImpulseSize > 0.f)
{
// Since we already have the size squared we can avoid the full normalize calculation
FVector IncomingNormalizedImpulse = NormalImpulse * FMath::InvSqrt(IncomingImpulseSize);
FVector AccumulatedNormalizedImpulse = AccumulatedImpulse * FMath::InvSqrt(AccumulatedImpulseSize);
if (FVector::DotProduct(IncomingNormalizedImpulse, AccumulatedNormalizedImpulse) < -.8f)
{
//UE_LOG_SCREEN_ERROR(RDBase, TEXT("CRUSH IncomingSize: %f (%f) AccumulatedSize: %f (%f)"), IncomingImpulseSize, FMath::Sqrt(IncomingImpulseSize), AccumulatedImpulseSize, FMath::Sqrt(AccumulatedImpulseSize));
}
}
AccumulatedImpulse += NormalImpulse;
}