在UE5游戏开发中,自定义角色类是最基础也是最重要的环节之一。今天我要分享的是如何基于ACharacter类派生自定义角色AMyCharacter,并实现完整的第三人称角色控制功能。这个方案采用了UE5最新的Enhanced Input系统,相比传统的InputComponent方式提供了更强大灵活的输入处理能力。
我最近在一个中型项目中实际应用了这套方案,经过多次迭代优化,目前已经形成了稳定的实现模式。通过本文,你将了解到从C++类创建到蓝图配置的完整流程,包括:
我们的AMyCharacter继承自ACharacter,这是UE中用于第三人称角色的基础类。选择这个父类而不是APawn或AActor的主要原因包括:
cpp复制UCLASS()
class MYPROJECT_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
// 类实现...
};
UE5的Enhanced Input系统相比传统输入处理有以下优势:
在我们的实现中,我们创建了:
在构造函数中我们需要完成基础组件的创建和初始化:
cpp复制AMyCharacter::AMyCharacter()
{
// 摄像机臂组件
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 400.0f;
CameraBoom->bUsePawnControlRotation = true;
// 跟随摄像机
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
FollowCamera->bUsePawnControlRotation = false;
}
注意:CameraBoom的TargetArmLength值需要根据游戏风格调整。第一人称射击游戏通常需要更近的镜头(300-500),而开放世界游戏可能需要更远的镜头(500-1000)。
在BeginPlay中绑定输入处理函数:
cpp复制void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
}
移动处理需要考虑以下几个因素:
cpp复制void AMyCharacter::Move(const FInputActionValue& Value)
{
FVector2D MovementVector = Value.Get<FVector2D>();
if (Controller != nullptr)
{
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 获取前进方向
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
// 获取右方向
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// 添加移动输入
AddMovementInput(ForwardDirection, MovementVector.Y);
AddMovementInput(RightDirection, MovementVector.X);
}
}
第三人称相机需要处理两种旋转:
cpp复制void AMyCharacter::Look(const FInputActionValue& Value)
{
FVector2D LookAxisVector = Value.Get<FVector2D>();
if (Controller != nullptr)
{
// 添加yaw输入(水平旋转)
AddControllerYawInput(LookAxisVector.X);
// 添加pitch输入(垂直旋转)
AddControllerPitchInput(LookAxisVector.Y);
}
}
在实际项目中,相机经常需要处理墙壁遮挡问题。我们可以在CameraBoom上设置碰撞检测:
cpp复制// 在构造函数中
CameraBoom->bDoCollisionTest = true;
CameraBoom->ProbeChannel = ECC_Camera;
CameraBoom->ProbeSize = 12.0f;
在C++类创建完成后,我们需要创建蓝图子类并进行配置:
创建蓝图子类:
输入配置:
组件调整:
可能原因及解决方法:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 完全无输入 | 未正确添加Mapping Context | 检查BeginPlay中的AddMappingContext调用 |
| 部分按键无响应 | Input Action绑定错误 | 检查项目设置中的输入绑定 |
| 输入延迟 | Tick分组设置不当 | 将输入组件设置为Pre Physics |
相机抖动通常由以下原因导致:
相机碰撞检测过于敏感:
Tick顺序问题:
cpp复制// 在构造函数中
PrimaryActorTick.bTickGroup = TG_PostPhysics;
CameraBoom->bEnableCameraLag = true;
CameraBoom->CameraLagSpeed = 10.0f;
输入系统优化:
移动组件优化:
相机优化:
cpp复制// 根据距离调整相机精度
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
float DistanceToPlayer = (GetActorLocation() - FollowCamera->GetComponentLocation()).Size();
float UpdateRate = FMath::GetMappedRangeValueClamped(FVector2D(500, 5000), FVector2D(60, 10), DistanceToPlayer);
FollowCamera->SetComponentTickInterval(1.0f / UpdateRate);
}
在实际项目中实现这套系统时,我建议先从基础功能开始,逐步添加高级特性。特别注意不同版本UE5的API变化,特别是Enhanced Input系统在5.1和5.2版本间有一些不兼容的修改。如果遇到问题,最好的方法是参考官方示例项目中的Lyra Starter Game的实现方式。