一、给角色的武器添加弹药
1.创建界面,根据笔记23的界面中添加
2.绑定界面控件
cpp
UPROPERTY(meta = (Bindwidget))
UTextBlock* WeaponAmmoAmount;
UPROPERTY(meta = (Bindwidget))
UTextBlock* CarriedAmmoAmount;
3.添加武器类型枚举
3.1创建武器类型枚举头文件
3.2创建文件时,默认添加的路径是在Intermediate/ProjectFiles文件夹中,通过#include 包含头文件时会找不到对应的头文件,需要更改路径,我是将所有武器类的C++文件放到Weapon文件夹中,所以我将武器类型头文件放到了Weapon文件夹中。
3.3创建枚举
cpp
#pragma once
UENUM(BlueprintType)
enum class EWeapoType : uint8
{
EWT_AssaultRifle UMETA(DisplayName = "Assault Rifle"),
EWT_MAX UMETA(DisplayName = "DefaultMAX"),
};
3.4创建武器弹药数量,捡起武器的声音
cpp
/**
* 弹药数量
*/
UPROPERTY(EditAnywhere, ReplicatedUsing = OnRep_Ammo)
int32 Ammo;//弹药数量
UFUNCTION()
void OnRep_Ammo();
UPROPERTY(EditAnywhere)
int32 MagCapacity;//最大弹药数量
void SpendRound();
void SetHUDAmmo();
UPROPERTY()
class ABlasterCharacter* BlasterOwnerCharacter; // 当前持有武器的角色
UPROPERTY()
class ABlasterPlayerController* BlasterOwnerController; // 当前持有武器的角色控制器
UPROPERTY()
EWeapoType WeaponType;
/**
* 武器的声音
*/
UPROPERTY(EditAnywhere)
class USoundCue* EquipSound;
bool IsEmpty();
FORCEINLINE EWeapoType GetWeaponType() const { return WeaponType; }
FORCEINLINE int32 GetAmmo() const { return Ammo; }
FORCEINLINE int32 GetMagCapacity() const { return MagCapacity; }
cpp
bool AWeapon::IsEmpty()
{
return Ammo <= 0;
}
void AWeapon::OnRep_Ammo()
{
//BlasterOwnerCharacter = BlasterOwnerCharacter == nullptr ? Cast<ABlasterCharacter>(GetOwner()) : BlasterOwnerCharacter;
SetHUDAmmo();
}
void AWeapon::SpendRound()
{
Ammo = FMath::Clamp(Ammo - 1,0,MagCapacity);
SetHUDAmmo();
}
void AWeapon::SetHUDAmmo()
{
BlasterOwnerCharacter = BlasterOwnerCharacter == nullptr ? Cast<ABlasterCharacter>(GetOwner()) : BlasterOwnerCharacter;
if (BlasterOwnerCharacter)
{
BlasterOwnerController = BlasterOwnerController == nullptr ? Cast<ABlasterPlayerController>(BlasterOwnerCharacter->Controller) : BlasterOwnerController;
if (BlasterOwnerController)
{
BlasterOwnerController->SetHUDWeaponAmmo(Ammo);
}
}
}
3.5.因为新添加了两个显示弹药数量的地方,所以给PlayerController添加设置界面的函数
cpp
void SetHUDWeaponAmmo(int32 Ammo);
void SetHUDCarriedAmmo(int32 Ammo);
cpp
void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<AABasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->WeaponAmmoAmount;
if (bHUDValid)
{
FString AmmoText = FString::Printf(TEXT("%d"), Ammo); // FloorToInt 向下取整
BlasterHUD->CharacterOverlay->WeaponAmmoAmount->SetText(FText::FromString(AmmoText));
}
}
void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<AABasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->CarriedAmmoAmount;
if (bHUDValid)
{
FString CarriedAmmoText = FString::Printf(TEXT("%d"), Ammo); // FloorToInt 向下取整
BlasterHUD->CharacterOverlay->CarriedAmmoAmount->SetText(FText::FromString(CarriedAmmoText));
}
}
3.6添加重新加载弹药功能,当前武器弹药的数量,播放换弹动画的功能
cpp
/* 换弹 */
UFUNCTION(Server, Reliable)
void ServerReload();
/* 换弹 */
/* 处理换弹 */
void HandleReload();
/* 处理换弹 */
/** 重新加载弹药函数 */
void Reload();
/** 处理设置完成战斗状态 */
UFUNCTION(BlueprintCallable)
void FinishReloading();
/** 计算重新加载弹药的数量 */
int32 AmountToReload();
//当前装备的武器弹药
UPROPERTY(ReplicatedUsing = OnRep_CarriedAmmo)
int32 CarriedAmmo;
UFUNCTION()
void OnRep_CarriedAmmo();
bool CanFire();// 是否可以开火函数
UPROPERTY(ReplicatedUsing = OnRep_CombatState)
ECombatState CombatState = ECombatState::ECS_Unoccupied;
UFUNCTION()
void OnRep_CombatState();
void InitializeCarriedAmmo();
TMap<EWeapoType, int32> CarriedAmmoMap;
cpp
void UCombatComponent::OnRep_CarriedAmmo()
{
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
}
bool UCombatComponent::CanFire()
{
if (EquippedWeapon == nullptr) return false;
return !EquippedWeapon->IsEmpty() && bCanFire && CombatState == ECombatState::ECS_Unoccupied;
}
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Reloading:
HandleReload();
break;
case ECombatState::ECS_Unoccupied:
if (bFireButtonPressed)
{
Fire();
}
break;
}
}
void UCombatComponent::FinishReloading()
{
if (Character == nullptr) return;
if (Character->HasAuthority())
{
CombatState = ECombatState::ECS_Unoccupied;
UpdateAmmoValues();
}
if (bFireButtonPressed)
{
Fire();
}
}
void UCombatComponent::HandleReload()
{
Character->PlayReloadMontage();
}
void UCombatComponent::Reload()
{
if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading)
{
ServerReload();
}
}
void UCombatComponent::ServerReload_Implementation()
{
if (Character == nullptr || EquippedWeapon == nullptr) return;
CombatState = ECombatState::ECS_Reloading;
HandleReload();
}
int32 UCombatComponent::AmountToReload()
{
if (EquippedWeapon == nullptr) return 0;
int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
int32 Least = FMath::Min(RoomInMag,AmountCarried);
return FMath::Clamp(RoomInMag, 0, Least);
}
return 0;
}
void UCombatComponent::InitializeCarriedAmmo() beginplay中调用需要检查HasAuthority()
{
CarriedAmmoMap.Emplace(EWeapoType::EWT_AssaultRifle, StartingARAmmo);
}
3.7.在装备武器时调用
cpp
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
if (EquippedWeapon->EquipSound)
{
UGameplayStatics::PlaySoundAtLocation(
this,
EquippedWeapon->EquipSound,
Character->GetActorLocation()
);
}
if (EquippedWeapon->IsEmpty())
{
Reload();
}
3.8.蓝图设置