Реализуйте базовый компонент здоровья UActorComponent на C++ для Unreal Engine.
Реализуйте переиспользуемый компонент здоровья, который можно прикрепить к любому Actor. Он хранит максимальное и текущее здоровье, применяет урон и лечение с ограничением и уведомляет владельца о смерти Actor — при этом сам компонент не уничтожает владельца.
Требования:
реагировал — компонент не должен сам вызывать или уничтожать владельца.
- Наследуйтесь от
UActorComponent(переиспользуемый компонент), а не отAActor. ApplyDamage/Healдолжны ограничиватьCurrentHealthмежду0иMaxHealth.- При достижении нуля рассылайте multicast-делегат (
OnDeath), чтобы владелец
Допишите две функции-члены:
void UHealthComponent::ApplyDamage(float Amount)
{
// ваш код здесь: ограничьте здоровье снизу и разошлите OnDeath на нуле
}
void UHealthComponent::Heal(float Amount)
{
// ваш код здесь: ограничьте здоровье сверху до MaxHealth
}
Допишите реализацию.
Наследуйтесь от UActorComponent, храните MaxHealth и CurrentHealth, предоставьте ApplyDamage/Heal, которые ограничивают значение, и шлите событие смерти при достижении нуля. Динамический multicast-делегат позволяет владеющему Actor реагировать без жёсткой связанности.
- ✗Не ограничивать здоровье, позволяя ему уйти ниже нуля или выше
MaxHealth - ✗Наследовать держатель здоровья от
AActorвместоUActorComponent - ✗Уничтожать владельца прямо внутри компонента вместо рассылки события
- →Как бы вы реплицировали
CurrentHealth, чтобы все клиенты видели полоску здоровья? - →Почему рассылать делегат, а не вызывать функцию смерти владельца напрямую?
Базовый компонент здоровья
// HealthComponent.h
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDeath);
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class UHealthComponent : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, Category="Health")
float MaxHealth = 100.f;
UPROPERTY(BlueprintAssignable, Category="Health")
FOnDeath OnDeath;
UFUNCTION(BlueprintCallable, Category="Health")
void ApplyDamage(float Amount);
UFUNCTION(BlueprintCallable, Category="Health")
void Heal(float Amount);
bool IsDead() const { return CurrentHealth <= 0.f; }
protected:
virtual void BeginPlay() override;
private:
float CurrentHealth = 0.f;
};
// HealthComponent.cpp
void UHealthComponent::BeginPlay()
{
Super::BeginPlay();
CurrentHealth = MaxHealth; // инициализация полного здоровья
}
void UHealthComponent::ApplyDamage(float Amount)
{
if (Amount <= 0.f || IsDead()) // отрицательный урон и двойная смерть отсекаются
{
return;
}
CurrentHealth = FMath::Clamp(CurrentHealth - Amount, 0.f, MaxHealth);
if (IsDead())
{
OnDeath.Broadcast(); // владелец сам решает, что делать
}
}
void UHealthComponent::Heal(float Amount)
{
if (Amount <= 0.f || IsDead())
{
return;
}
CurrentHealth = FMath::Clamp(CurrentHealth + Amount, 0.f, MaxHealth);
}
Компонент инкапсулирует одну ответственность и переиспользуется на любом Actor. Он не уничтожает владельца сам — он лишь шлёт OnDeath, а Actor подписывается и реагирует. Это разрывает жёсткую связанность.