Hello everyone!
I am trying in my arms ABP to lerp the ik_hand_gun bone (I lerp the ik_hand_gun but I make it so that the camera ends where I have an aim socket that I placed on the gun) to the camera whenever the the players presses the right mouse button. The whole logic for triggering the aim is there, the problem is that I cannot figure the calculations to correctly lerp the ik_hand_gun. After days I made this code to make it work but the problem was I could not make the calculations in the UpdateNativeAnimations (the tick of ABP) as it would bug the lerping and the ik_hand_gun bone would like go in a circle.
I come from Unity and over there I would just grab the bone lerp it to the camera and then add the aim socket transform and the gun would be where I want it and I would do all of that in the Tick method of Unity (Update) so I do not understand why it bugs the calculations if I do it here the same way. Can someone explain to me the best approach as I do not find my current solution to be the “way to do it” one. Can someone also help me with the rotation when aiming as I would like to have the ik_hand_gun bone rotation zeroed out when aiming but that does not seem to work either.
Arms ABP C++:
void UFPArmsAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
// Get character and save it as a variable
if (Character == nullptr)
{
APawn* Pawn = TryGetPawnOwner();
if (!Pawn) return;
Character = Cast<AFPCharacter>(Pawn);
if (!Character) return;
}
// Read data from character
MoveX = Character->MoveX;
MoveY = Character->MoveY;
LookX = Character->LookX;
LookY = Character->LookY;
bIsMoving = MoveX != 0.0f || MoveY != 0.0f;
bIsRunning = Character->bIsRunning;
bIsJumping = Character->bIsJumping;
bIsCrouching = Character->IsCrouched();
bIsFalling = Character->GetCharacterMovement()->IsFalling();
if (Character->bWantsToSecondary)
{
bIsADS = true;
Aim(DeltaSeconds);
}
else
{
bIsADS = false;
}
// Procedural motions calculations
Sway = CalculateSway(DeltaSeconds);
FinalIkHandGunRotation = Sway;
}
/*
Calculate procedural sway given by mouse input
*/
FRotator UFPArmsAnimInstance::CalculateSway(float DeltaSeconds)
{
AItem* CurrentEquippedItem = Character->GetCurrentEquippedItem();
if (CurrentEquippedItem == nullptr) return FRotator::ZeroRotator;
UItemDataAsset* ItemData = CurrentEquippedItem->GetItemData();
if (ItemData == nullptr) return FRotator::ZeroRotator;
// 1) Target sway from current look input (mouse delta)
SwayTarget.Pitch = LookX * -ItemData->PitchSwayAmount; // Item roll
SwayTarget.Yaw = LookX * ItemData->YawSwayAmount; // Item left-right
SwayTarget.Roll = LookY * -ItemData->RollSwayAmount * 0.5f; // Item up-down
// 2) Clamp target so it never goes crazy
SwayTarget.Pitch = FMath::Clamp(SwayTarget.Pitch, -ItemData->SwayMaxAngle, ItemData->SwayMaxAngle);
SwayTarget.Yaw = FMath::Clamp(SwayTarget.Yaw, -ItemData->SwayMaxAngle, ItemData->SwayMaxAngle);
SwayTarget.Roll = FMath::Clamp(SwayTarget.Roll, -ItemData->SwayMaxAngle, ItemData->SwayMaxAngle);
// 3) Smoothly interpolate current sway toward target
return FMath::RInterpTo(Sway, SwayTarget, DeltaSeconds, SwaySmoothSpeed);
}
void UFPArmsAnimInstance::StartADS()
{
if (USkeletalMeshComponent* SkelComp = GetSkelMeshComponent())
{
const USkeletalMeshComponent* ItemMesh = Character->GetCurrentEquippedItem()->GetMesh();
const FTransform CameraSocketTransform = SkelComp->GetBoneTransform(TEXT("head"), RTS_World);
const FTransform AimSocketTransform = ItemMesh->GetSocketTransform(TEXT("aim_socket"), RTS_World);
const FTransform IkHandGunTransform = SkelComp->GetBoneTransform(TEXT("ik_hand_gun"), RTS_World);
const FTransform AimRel = AimSocketTransform.GetRelativeTransform(IkHandGunTransform);
const FTransform CameraRel = CameraSocketTransform.GetRelativeTransform(IkHandGunTransform);
const FTransform Delta = CameraRel * AimRel.Inverse();
ADS_IkHandGunOffset = Delta.GetLocation();
ADS_IkHandGunRotation = FRotator(0.0f, 0.0f, IkHandGunTransform.Rotator().Roll);
bIsADS = true;
}
}
void UFPArmsAnimInstance::StopADS()
{
bIsADS = false;
}
/*
Procedurally move the weapon to a specified offset for weapon aiming
*/
void UFPArmsAnimInstance::Aim(float DeltaSeconds)
{
const float InterpSpeed = 8.0f;
FVector TargetLoc = bIsADS ? ADS_IkHandGunOffset : FVector::ZeroVector;
FRotator TargetRot = bIsADS ? ADS_IkHandGunRotation : FRotator::ZeroRotator;
AddIkHandGunLocation = FMath::VInterpTo(AddIkHandGunLocation, TargetLoc, DeltaSeconds, InterpSpeed);
AddIkHandGunRotation = FMath::RInterpTo(AddIkHandGunRotation, TargetRot, DeltaSeconds, InterpSpeed);
// Optional snap when close
if (AddIkHandGunLocation.Equals(TargetLoc, 0.1f))
{
AddIkHandGunLocation = TargetLoc;
}
}
Arms ABP Animation Logic:


