I’m making a character climbing system. When the character is in climbing mode, I generate a collision-detecting capsule in front of the character at every tick and sweep forward one unit distance to continuously detect wall collisions and handle the climbing problem of the character movement component.
In order to facilitate observation, I used a transparent wall for the character to climb, and drew a white detection capsule and a yellow Impact Point.
[image]
[When the character climbs normally, the Impact Point detected by the capsule is directly in front of the character capsule.]
Although the character can already start climbing up the wall, the problem is that when the character climbs and moves somewhere on a flat wall vertical to the ground, the Impact Point position in the HitResult structure returned by capsule collision detection sometimes changes. It’s very weird (as shown in the picture, the yellow point represents the Impact Point). This incorrect Impact Point leads to the incorrect Impact Normal (affecting the rotation direction of my character when climbing). Can someone tell me this? Why?
Here is my code:
‘’'cpp
void UALCMovementClimbObject::SweepAndStoreWallHits()
{
const FALCMovementClimbCondition& currentConditionSettings = GetCurrentClimbModeDA()->ClimbConditionSettings;
const FCollisionShape CollisionShape = FCollisionShape::MakeCapsule(currentConditionSettings.ClimbCapsuleTraceRadius,currentConditionSettings.ClimbCapsuleTraceHalfHeight);
const FVector StartOffset = ALCMovementComp->UpdatedComponent->GetForwardVector() * currentConditionSettings.CapsuleTraceStartOffset;
const FVector Start = ALCMovementComp->UpdatedComponent->GetComponentLocation() + FVector(0,0,currentConditionSettings.CapsuleTraceVerticalOffset) + StartOffset;
const FVector End = Start + ALCMovementComp->UpdatedComponent->GetForwardVector(); // Avoid using the same Start/End location for a Sweep, as it doesn't trigger hits on Landscapes.
TArray<FHitResult> Hits;
bool HitWall = false;
HitWall= UKismetSystemLibrary::CapsuleTraceMultiForObjects(
GetWorld(),
Start,
End,
currentConditionSettings.ClimbCapsuleTraceRadius,
currentConditionSettings.ClimbCapsuleTraceHalfHeight,
currentConditionSettings.ClimbableObjectTypes,
false,
TArray<AActor*>(),
EDrawDebugTrace::ForOneFrame,
Hits,
true
);
if(ALCMovementComp->DebugRules.bEnableClimbObjectDebug)
{
if (CollisionShape.IsCapsule())
{
float CapsuleRadius = CollisionShape.GetCapsuleRadius();
float CapsuleHalfHeight = CollisionShape.GetCapsuleHalfHeight();
DrawDebugCapsule(
GetWorld(),
Start,
CapsuleHalfHeight,
CapsuleRadius,
FQuat::Identity,
FColor::White,
false,
0.f,
0,
1
);
DrawDebugCapsule(
GetWorld(),
End,
CapsuleHalfHeight,
CapsuleRadius,
FQuat::Identity,
FColor::White,
false,
0.f,
0,
1
);
}
if(HitWall)
{
for(auto x:Hits)
{
DrawDebugPoint(GetWorld(),x.ImpactPoint,15,FColor::Yellow,false,0,0);
DrawDebugPoint(GetWorld(),x.Location,15,FColor::Orange,false,0,0);
DrawDebugDirectionalArrow(GetWorld(),Start, x.Location,1.5,FColor::Purple,false,0,0,1);
}
}
}
ClimbableSurfacesTracedResults = HitWall ? Hits : TArray<FHitResult>();
}
‘’’