UE5学习笔记24-添加武器弹药

一、给角色的武器添加弹药

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.蓝图设置

相关推荐
sensen_kiss10 分钟前
CPT304 SoftwareEngineeringII 软件工程 2 Pt.8 软件测试 (Software Testing)(上)
学习·软件工程
力学与人工智能13 分钟前
PPT分享 | 洛桑联邦理工学院魏震:深度几何学习在工业设计优化中的应用
学习·优化·工业设计·深度几何学习·洛桑联邦理工学院
sensen_kiss2 小时前
CPT304 SoftwareEngineeringII 软件工程 2 Pt.9 软件测试 (Software Testing)(下)
学习·软件工程
wu_ye_m2 小时前
学习c语言第35天 函数声明和定义
c语言·开发语言·学习
清辞8532 小时前
Coze从入门到实战---第一、二章
大数据·人工智能·学习·语言模型
伊布拉西莫3 小时前
【流畅的Python】第20章:并发执行器 — 学习笔记
笔记·python·学习
jinglong.zha3 小时前
LScript-从零基础到商业变现的AI自动化学习平台
运维·学习·自动化
闪闪发亮的小星星4 小时前
STK_00 学习方案路线
学习
一楼的猫4 小时前
茄子写作助手——品牌搜索突破9万后的技术型品牌认知与官网入口指南
人工智能·学习·机器学习·chatgpt·ai写作
AOwhisky4 小时前
学习自测与解析:MySQL第五、六、七期核心知识点详解
运维·数据库·笔记·学习·mysql·云计算