May 23, 2025
4 mins read
以下部分只是最初实现的代码,后来更改了武器组件化还有网络同步
1. 已解决 角色混合空间移动缺少左右动画,导致左右腿移动时重叠。—— 骨骼没适配
2. 已解决 多人游戏中玩家奔跑只能自己看到 没办法被其他玩家看到 —— MaxWalkSpeed需要网络同步
实现了人物的移动、奔跑、跳跃、射击。
角色添加了四个骨骼,分别是第一人称视角的:LegMesh自己看自己的腿,FirstPersonMesh自己看自己的手,和其他玩家视角的全身模型:ThirdpersonMesh,以及ShadowMesh影子网格体
动画完成了人物的走跑(八方向混合空间)、跳(起跳—在空中—落地)、射击部分。
protected:
void SetupInputComponent() override;
protected:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "EnhancedInput", meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputMappingContext> DefaultIMC;
void ADemoPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
if(UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
FModifyContextOptions Options;
Options.bForceImmediately = true;
Subsystem->ClearAllMappings();
if(DefaultIMC)
{
Subsystem->AddMappingContext(DefaultIMC, 0, Options);
}
}
}
在SetupPlayerInputComponent中调用自定义输入组件绑定输入。
void ADemoPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UDemoPlayerInputComponent* DemoInput = CastChecked<UDemoPlayerInputComponent>(PlayerInputComponent);
if (DemoInput)
{
DemoInput->SetupInputBindings();
}
}
void UDemoPlayerInputComponent::SetupInputBindings()
{
if(IA_DemoFire)
{
BindAction(IA_DemoFire, ETriggerEvent::Started, this, &UDemoPlayerInputComponent::StartFire);
BindAction(IA_DemoFire, ETriggerEvent::Completed, this, &UDemoPlayerInputComponent::EndFire);
}
}
自定义输入组件中的开火函数用来调用ADemoPlayerCharacter的开火函数
void UDemoPlayerInputComponent::StartFire(const FInputActionValue& InputActionValue)
{
ADemoPlayerCharacter* CharacterOwner = GetOwner<ADemoPlayerCharacter>();
if(IsValid(CharacterOwner))
{ CharacterOwner->OnStartFire();
}
}
void UDemoPlayerInputComponent::EndFire(const FInputActionValue& InputActionValue)
{
ADemoPlayerCharacter* CharacterOwner = GetOwner<ADemoPlayerCharacter>();
if(IsValid(CharacterOwner))
{
CharacterOwner->OnEndFire();
}
}
角色类中的开火逻辑 定时器开火不断调用武器类中的开火
void ADemoPlayerCharacter::OnStartFire()
{
if(CurrentWeapon)
{
GetWorld()->GetTimerManager().SetTimer(FireTimerHandle, this, &ADemoPlayerCharacter::FireWeapon, FireRate, true);
bIsFire = true;
}
}
void ADemoPlayerCharacter::OnEndFire()
{
if(CurrentWeapon)
{
GetWorld()->GetTimerManager().ClearTimer(FireTimerHandle);
bIsFire = false;
}
}
void ADemoPlayerCharacter::FireWeapon()
{
if(CurrentWeapon)
{
CurrentWeapon->Fire();
}
}
武器类的开火逻辑
其中AmmoCount是子弹数量设定为30, CanFire逻辑还没写,之后在里面判定枪械状态,比如说换弹时不能开枪。或者更复杂一些,比如被技能控制不能开火我认为都可以写在CanFire里。
void ADemoWeapon::Fire()
{
if(CanFire() && AmmoCount > 0)
{
CurrentState = EWeaponState::WS_Firing;
AmmoCount --;
UE_LOG(LogTemp, Warning, TEXT("Firing Weapon, AmmoCount:%d"),AmmoCount);
FireRaycast();
}
// TODO:恢复到Idle状态
}
void ADemoWeapon::FireRaycast()
{
ADemoPlayerCharacter* PC = Cast<ADemoPlayerCharacter>(GetOwner());
if(PC)
{
}
FVector Start = PC->FirstPersonCamera->GetComponentLocation();
FVector ForwardVector = PC->FirstPersonCamera->GetForwardVector();
FVector End = (ForwardVector * 1000.f) + Start;
// 绘制射线
DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 1.0f, 0, 1.0f);
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(GetOwner());
bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, CollisionParams);
if (bHit)
{
UE_LOG(LogTemp, Warning, TEXT("HitActor: %s"), *HitResult.GetActor()->GetName());
}
}
Sharing is caring!