实习周报5.23

May 23, 2025

4 mins read

实习周报5.23

以下部分只是最初实现的代码,后来更改了武器组件化还有网络同步

出现的问题:

​ 1. 已解决 角色混合空间移动缺少左右动画,导致左右腿移动时重叠。—— 骨骼没适配

​ 2. 已解决 多人游戏中玩家奔跑只能自己看到 没办法被其他玩家看到 —— MaxWalkSpeed需要网络同步

实现了人物的移动、奔跑、跳跃、射击。

角色添加了四个骨骼,分别是第一人称视角的:LegMesh自己看自己的腿,FirstPersonMesh自己看自己的手,和其他玩家视角的全身模型:ThirdpersonMesh,以及ShadowMesh影子网格体

img

动画完成了人物的走跑(八方向混合空间)、跳(起跳—在空中—落地)、射击部分。

射击实现

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!