说明
正式的攀爬功能,攀爬功能其实就是跳跃功能的Plus版本,在面对不同凸起地面墙壁时,有不同的动画效果,使得角色可以越过障碍,而不是只有跳跃动画以及跳跃高度恒定,导致角色无法运动
该攀爬功能实现了面对薄墙(高、低)和厚墙(高、低)的基础攀爬动作,在面对厚墙时,角色在成功攀爬后会站在平台上,而面对薄墙角色会直接进行翻越
墙壁种类
上面已经提到,一般来说可以分为4类,但其实还可以加上2类即墙的高度比高强还高一点,所以一共是6类,所以基本上需要6种的动画蒙太奇进行实现
主要流程就是,按下按键后,通过射线检测,获取墙的高度以及厚度,然后判断需要播放哪一个动画。从而进行播放
对于是否有墙壁的射线检测
检测类型可以就为WorldStatic,也可以自定义类型,通过检测角色身前一定距离,如果有墙壁返回墙壁的位置(用于求解墙壁的高度)和法线(用于求解墙壁的厚度)
其中涉及到检测距离,可以通过判断当前角色的速度来判断,当在奔跑时,检测距离可以适当的增加。
//Arrow为增加的角色组件,用来指示当前角色的朝向
FVector ArrowStart = Arrow->GetComponentLocation();
//150.f为检测距离控制
FVector ArrowEnd = ArrowStart + Arrow->GetForwardVector() * 150.0f;
EObjectTypeQuery w = UEngineTypes::ConvertToObjectType(ECC_WorldStatic);
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes = { TEnumAsByte<EObjectTypeQuery>(w) };
FHitResult ArrowHit;
bool bIsArrowHit = UKismetSystemLibrary::LineTraceSingleForObjects(
GetWorld(),
ArrowStart,
ArrowEnd,
ObjectTypes,
false,
TArray<AActor*>{},
EDrawDebugTrace::ForDuration,
ArrowHit,
true,
FColor::Red,
FColor::Green,
5.0f
);
通过对击中结果的检测来判断是否有墙,如果有就可以返回检测结果。
对于是否墙的上表面是否可以站立的判断
可以直接使用CharacterMovement组件的IsWalkable(Hit),传入射线检测命中结果,使用这个检测主要是为了处理无法站立的情况
通过对检测结果以及平台坡度的判断来决定角色是否可以在平台上行走,如果不能行走那么就需要判断墙的厚度来决定翻越的动画
射线检测获取墙的厚度
IsWalkable(Hit)只是确定了当前墙上表面是否可以行走,还可以自定义一个函数,来控制上表面是否能够站立即自己判断墙的厚度是否支持人的站立
厚度控制
FVector Thick = UKismetMathLibrary::GetForwardVector(UKismetMathLibrary::MakeRotFromX(WallNormal)) * -75.0f;
-3=75为系数,通过对墙壁法线向量的X方向进行处理获得要检测的墙壁厚度
从墙的位置向后移动3被的法线x向量的距离,以此点为靠近人的墙壁的检测点,从上向下进行射线检测,如果检测到墙壁,就说明是比较厚的墙,没有则说明是比较薄的墙
如果是比较薄的墙,还可以再进行细分为ledge和fence,同样只用修改-75这个系数即可
动画播放
首先对于比较厚的墙,可以通过求解高度,来判断厚墙是通过攀爬还是翻越实现登上墙的上表面,接着就可以通过之前射线检测对于攀爬方式的控制,来选择不同的动画效果了,以跳跃攀爬为例(墙壁较高)
首先设置当前运动模式为Flying,因为蒙太奇动画为根运动,如果不设置那么将导致一直在地面上。然后利用角色的PlayAnimMontage函数进行蒙太奇动画的播放
//关闭控制,设置运动模式
//禁止输入
CharacterRef->DisableInput(ControllerRef);
//关闭胶囊体碰撞 -- 不要关闭,否则会出现穿模情况
//CapsuleComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CharacterMovementIns->SetMovementMode(EMovementMode::MOVE_Flying, 0);
//播放动画
//设置初始翻越位置,以及翻越时位置和朝向的控制
SetPlayerLocationSmooth(JumpFenceVaultDistanceOffset, JumpFenceVaultHeightOffset);
//播放翻越的动画
int len = FAnimations.VaultAnims.JumpFenceVault.Num();
UAnimMontage* AnimMontage = FAnimations.VaultAnims.JumpFenceVault[UKismetMathLibrary::RandomInteger(len)];
CharacterRef->PlayAnimMontage(AnimMontage, 1.0f, NAME_None);
SetPlayerLocationSmooth函数
利用UE中的时间轴节点,来实现角色在翻越过程中Loc和Rot的平滑变化
通过设置的曲线,对Loc和Rot进行插值求解
//时间轴调用函数
void AXClimbingManager::CWTimelineTickCallBack(float value)
{
if (!XClimbCharacer) return;
Time = value;
UXClimbComponent* ClimbComp = Cast<UXClimbComponent>(XClimbCharacer->GetComponentByClass(UXClimbComponent::StaticClass()));
if (!ClimbComp) return;
//对高度进行插值
float Alpha = InterpolateTimeByHeight(Time, ClimbComp);
if (Alpha <= 0.0f) return;
//插值结果传入攀爬组件中实现对Loc的iu该
ClimbComp->SetPlayerLocation(PlayerDistanceOffset, HeightOffset, Alpha);
ClimbComp->FaceWall(Time);
}
InterpolateTimeByHeight
该函数主要是通过墙壁高度以及设定的速度与时间轴动画时间做运算得到一个合理的插值结果,从而用来控制Loc的改变
float AXClimbingManager::InterpolateTimeByHeight(float time, UXClimbComponent* ComponentRef)
{
if (!ComponentRef) return -1.0f;
float res = (ComponentRef->GetWallHeight() - ComponentRef->GetWallLocation()).Z;
res /= ComponentRef->GetInterpolationSpeed();
res = time / res;
res /= 2;
return res;
}
标签:动画,角色,墙壁,检测,攀爬,res,UE4
From: https://www.cnblogs.com/XTG111/p/18217032