数据驱动
这一部分的含义是角色在不同的运动状态下,比如旋转模式不同(瞄准状态,正常状态),步态不同(走,跑,冲刺),姿态不同(蹲伏,站立)应该有不同运动属性设置。
这里的属性包括,速度(MaxWalkSpeed),加速度(MaxAcceleration),减速度(BrakingDecelerationWalking),摩檫力(BrakingFriction),摩檫力系数(BrakingFrictionFactor)
首先是一个数据结构的定义,配表用
USTRUCT(BlueprintType)
struct FCwlMovementSettings
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = "Movement Settings")
float WalkSpeed = 0.0f;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
float RunSpeed = 0.0f;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
float SprintSpeed = 0.0f;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
UCurveVector* MovementCurve = nullptr;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
UCurveFloat* RotationRateCurve = nullptr;
float GetSpeedForGait(const ECwlGait Gait) const
{
switch (Gait)
{
case ECwlGait::Running:
return RunSpeed;
case ECwlGait::Sprinting:
return SprintSpeed;
case ECwlGait::Walking:
return WalkSpeed;
default:
return RunSpeed;
}
}
};
USTRUCT(BlueprintType)
struct FCwlMovementStanceSettings
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = "Movement Settings")
FCwlMovementSettings Standing;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
FCwlMovementSettings Crouching;
};
USTRUCT(BlueprintType)
struct FCwlMovementStateSettings : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = "Movement Settings")
FCwlMovementStanceSettings VelocityDirection;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
FCwlMovementStanceSettings LookingDirection;
UPROPERTY(EditAnywhere, Category = "Movement Settings")
FCwlMovementStanceSettings Aiming;
};
根据 FCwlMovementStateSettings 创建DataTable 。然后对应的把ALSV4的datatable配置数值抄过来。
然后我们看这个表有三行,分别对应正常的运动,灵活的运动,缓慢的运动
每一项按三种旋转模式继续分。
又按照姿态的站立,蹲下又细分。
3 x 3 x 2
这么多状态每一个都有对应的配置,表示这个状态下走,跑,冲刺的速度应该是多少。
曲线映射
这里主要解释上一小节,配置中,MovementCurve曲线的作用
回到上一篇最后更新数值的地方。不同的步态(走,跑,冲刺)对应不同的速度,加速度数值。
void ACwlCharacter::UpdateDynamicMovementSettings(ECwlGait AllowedGait)
{
const FCwlMovementSettings MovementSettings = GetTargetMovementSettings();
switch (AllowedGait)
{
case ECwlGait::Walking:
GetCharacterMovement()->MaxWalkSpeed = MovementSettings.WalkSpeed;
break;
case ECwlGait::Running:
GetCharacterMovement()->MaxWalkSpeed = MovementSettings.RunSpeed;
break;
case ECwlGait::Sprinting:
GetCharacterMovement()->MaxWalkSpeed = MovementSettings.SprintSpeed;
break;
default:
break;
}
FVector MovementCurve = MovementSettings.MovementCurve->GetVectorValue(MyCharacterMovementComponent->GetMappingSpeed());
GetCharacterMovement()->MaxAcceleration = MovementCurve.X;
GetCharacterMovement()->BrakingDecelerationWalking = MovementCurve.Y;
GetCharacterMovement()->BrakingFriction = MovementCurve.Z;
}
第一部分比较简单,根据走,跑,冲刺选择不同的速度。
第二部分我们先看 GetMappingSpeed()
float UCwlMovement::GetMappingSpeed() const
{
const float Speed = Velocity.Size2D();
const float LocalWalkSpeed = CurrentMovementSettings.WalkSpeed;
const float LocalRunSpeed = CurrentMovementSettings.RunSpeed;
const float LocalSprintSpeed = CurrentMovementSettings.SprintSpeed;
float SpeedMappingWalk = FMath::GetMappedRangeValueClamped(FVector2D(0, LocalWalkSpeed), FVector2D(0, 1), Speed);
float SpeedMappingRun = FMath::GetMappedRangeValueClamped(FVector2D(LocalWalkSpeed, LocalRunSpeed), FVector2D(1, 2), Speed);
float SpeedMappingSprint = FMath::GetMappedRangeValueClamped(FVector2D(LocalRunSpeed, LocalSprintSpeed), FVector2D(2, 3), Speed);
if (Speed > LocalRunSpeed)
{
return SpeedMappingSprint;
}
if (Speed > LocalWalkSpeed)
{
return SpeedMappingRun;
}
return SpeedMappingWalk;
}
目的是将角色速度映射到【0,3】的范围
角色当前有一个速度值,我们画个数轴
0______________A(175)_______________B(375)________________C(650)
0______________A'(1)________________B'(2)_________________C'(3)
A点是走的速度,B是跑的速度,C点是冲刺的速度,当前速度speed落在第一行的某个点,我们可以根据速度范围获得所在的区间。
代码的意思是,把A,B,C映射到0~3的值,然后在读取曲线,从中读取对于数值。
然后我们再看曲线
对于代码,在UpdateDynamicMovementSettings的最后面
FVector MovementCurve = MovementSettings.MovementCurve->GetVectorValue(MyCharacterMovementComponent->GetMappingSpeed());
GetCharacterMovement()->MaxAcceleration = MovementCurve.X;
GetCharacterMovement()->BrakingDecelerationWalking = MovementCurve.Y;
GetCharacterMovement()->BrakingFriction = MovementCurve.Z;
图中曲线横轴0~3,纵轴是数值。看代码X,Y,Z对应不同的加速度,减速度,摩檫力
对比一下
在正常状态,灵敏,迟钝的不同曲线中,加速度的数值就不一样,意味从静止到运动的过程时间不一样。
比如这里红色的线。2开始有一小段,然后马上下降,意味着在冲刺状态的第一段速度加速度是很大的,后面加速度恒定一个小一点的值,
那么具体表现在角色身上就是,我刚刚按了shift,突然冲了一下,然后变慢了一点点。