CoopGame07-增强道具
type: Post
status: Published
date: 2022/10/18
slug: CoopGame07
summary: UE4 C++多人游戏入门
category: Unreal
跟随B站up主“技术宅阿棍儿”的教程制作的笔记。教程链接
加速道具
0.导入素材,导入最新工程版本的Powerups文件夹
1.创建拾取物类
1.创建继承Actor
C++类SPickUpActorC++类,相当于道具的底座。
SPickupActor.h
//球形组件
UPROPERTY(VisibleAnywhere,Category="Components")
class USphereComponent *SphereComp;
//贴花组件
UPROPERTY(VisibleAnywhere,Category="Components")
class UDecalComponent *DecalComp;
//重载重叠函数
virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
SPickupActor.cpp
ASPickupActor::ASPickUpActor()
{
//...
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
SphereComp->SetSphereRadius(75);
RootComponent = SphereComp;
DecalComp = CreateDefaultSubobject<UDecalComponent>(TEXT("DeaclComp"));
DecalComp->SetRelativeRotation(FRotator(90,0,0));
DecalComp->DecalSize=FVector(64,75,75);
DecalComp->SetupAttachment(RootComponent);
}
void ASPickupActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
}
2.创建继承ActorC++类的SPowerUpActorC++类,实际作用的道具。
SPowerUpActor.h
//道具起作用的间隔,类似每隔多少秒加多少血
UPROPERTY(EditDefaultsOnly, Category="Powerups")
float PowerUpInterval;
//道具起作用的总次数
UPROPERTY(EditDefaultsOnly, Category="Powerups")
int32 TotalNrOfTicks;
FTimerHandle TimerHandle_PowerUpTicks;
//道具已经起作用的次数
int32 TickProcessed;
//道具起作用函数
UFUNCTION()
void OnTickPowerUp();
//激活道具
void ActivatePowerUp();
UFUNCTION(BlueprintImplementableEvent, Category="Powerups")
void OnActivated();
UFUNCTION(BlueprintImplementableEvent, Category="Powerups")
void OnPowerUpTicked();
UFUNCTION(BlueprintImplementableEvent, Category="Powerups")
void OnExpired();
SPowerUpActor.cpp
ASPowerUpActor::ASPowerUpActor()
{
PrimaryActorTick.bCanEverTick = true;
//道具作用间隔
PowerUpInterval = 0.f;
//作用总次数
TotalNrOfTicks = 0;
}
void ASPowerUpActor::ActivatePowerUp()
{
//激活道具
OnActivated();
//如果道具是有间隔的道具,则需要使用定时器,比如:10秒内加100滴血的道具
if (PowerUpInterval > 0)
{
//设置定时器每PowerUpInterval时间间隔调用一次OnTickPowerUp()(时间句柄变量,调用对象,调用函数,调用间隔,是否循环,延迟)
GetWorldTimerManager().SetTimer(TimerHandle_PowerUpTicks, this, &ASPowerUpActor::OnTickPowerUp, PowerUpInterval,
true, 0.f);
}
else
{
//如果是不需要作用时间的道具则让道具直接起作用,比如加速道具只加一次速
OnTickPowerUp();
}
}
void ASPowerUpActor::OnTickPowerUp()
{
//道具已经起作用的次数:每起作用一次就自增一次
TickProcessed++;
OnPowerUpTicked();
//如果道具作用次数达到总次数,就使道具失效,同时清除定时器
if (TickProcessed >= TotalNrOfTicks)
{
//使道具失效函数
OnExpired();
//清除定时器
GetWorldTimerManager().ClearTimer(TimerHandle_PowerUpTicks);
}
}
2.修改SPickUpActor类
1.创建SPickUpActor类继承Actor类,相当于道具的底座。
SPickupActor.h
//实际起作用的道具类
UPROPERTY(EditDefaultsOnly, Category="PickUpActor")
TSubclassOf<class ASPowerUpActor> PowerUpClass;
//实际起作用的道具实例
class ASPowerUpActor* PowerUpInstance;
//道具生成冷却时间
UPROPERTY(EditInstanceOnly, Category="PickUpActor")
float CooldownDuration;
//生成道具时间句柄
FTimerHandle TimerHandle_RespawnTimer;
//生成道具函数
void ResPawn();
SPickupActor.cpp
void ASPickUpActor::BeginPlay()
{
Super::BeginPlay();
//刚开始时生成道具
ResPawn();
}
void ASPickUpActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ASPickUpActor::ResPawn()
{
//如果没有实际起作用的道具类则打印错误日志并返回
if (PowerUpClass == nullptr)
{
UE_LOG(LogTemp,Warning,TEXT("PowerUpClass is null in %s"),*GetName());
return;
}
//生成Actor的生成参数
FActorSpawnParameters SpawnParameters;
//设置参数设置Actor总是生成
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
//生成道具实例Actor<生成类型>(类,位置,生成参数)
PowerUpInstance = GetWorld()->SpawnActor<ASPowerUpActor>(PowerUpClass,GetTransform(),SpawnParameters);
}
void ASPickUpActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
//如果生成的道具实例存在,则让道具起作用,然后将道具实例置空,并设置定时器生成下一个道具
if (PowerUpInstance)
{
PowerUpInstance->ActivatePowerUp();
PowerUpInstance = nullptr;
//设置生成道具的定时器,每隔CooldownDuration时间调用一次ResPawn()生成道具的函数。
GetWorldTimerManager().SetTimer(TimerHandle_RespawnTimer,this,&ASPickUpActor::ResPawn,CooldownDuration);
}
}
3.制作贴花材质M_PowerupDecal
蓝图如图
PickUpActor
BP_PickUpActor
1.指定贴画材质M_PowerupDecal5.创建继承PowerUpActorC++类的BP_PowerUpBase蓝图类。
1.手动添加静态网格体组件,并关闭静态网格体的碰撞预设,设置为NoCollision。
4.创建继承BP_PowerUpBase蓝图类的Powerup_SuperSpeed蓝图类。
1指定SpeedIcon静态网格体,
2.蓝图编写如图
3.制作加速道具的材质M_Powerup和材质实例MI_PowerupSpeed。
M_Powerup
MI_PowerupSpeed
4.制作光源函数材质M_PowerupLightFunction并使用,关闭影子
添加点光源组件,并设置光照函数为M_PowerupLightFunction,关闭阴影,设置光照颜色为蓝色
加血道具
1.给健康组件
SHealthComponent
添加回血函数
Heal()
SHealthComponent.h
UFUNCTION(BlueprintCallable,Category="HealthComponent")
void Heal(float HealAmount);
SHealthComponent.cpp
void USHealthComponent::Heal(float HealAmount)
{
//如果加血值为0,或者已经挂了,就返回
if (HealAmount<=0 || Health<=0)
{
return;
}
//加血后的生命值限制在0到默认值100之间
Health = FMath::Clamp(Health+HealAmount,0.0f,DefaultHealth);
//打印生命值改变。
UE_LOG(LogTemp,Log,TEXT("Health Changed: %s (+%s)"),FString::SanitizeFloat(Health));
//广播伤害值为负数则为加血
OnHealthChanged.Broadcast(this,Health,-HealAmount,nullptr,nullptr,nullptr);
}
1.创建继承BP_PowerUpBase
蓝图类的Powerup_HealthRegen
蓝图类。
1.手动添加并选择静态网格体,添加浮点型变量HealAmount,设置默认值为20。
2.编写蓝图逻辑
3.修改PickUpActor.h,意思是放置在场景中的蓝图类,在放置之后用场景中的实例指定更好,比如每个道具的冷却时间不同,要生成的道具的种类不同,在放置后设置。
//实际起作用的道具类,可以在场景实例中设置需要生成的道具类,比如加血的或加速的
// UPROPERTY(EditDefaultsOnly, Category="PickUpActor")
// TSubclassOf<class ASPowerUpActor> PowerUpClass;
UPROPERTY(EditInstanceOnly,Category="PickUpActor")
TSubclassOf<class ASPowerUpActor> PowerUpClass;
4.将道具的材质中颜色转换为参数,创建材质实例以适用蓝色的加速道具,绿色的加血道具。
略5.给加血道具也加上灯光,设置颜色等。
略6.将起作用的道具类
Powerup_HealthRegen
和Powerup_SuperSpeed
的静态网格体位置Z设置为50
,并给它们都添加上旋转移动组件
,实现自转效果。
联机化
1.设置复制
SPowerUpActor.h
//同步激活状态
UPROPERTY(ReplicatedUsing=OnRep_PowerActive)
bool bIsPowerActive;
UFUNCTION()
void OnRep_PowerActive();
//蓝图可实现事件,去蓝图实现
UFUNCTION(BlueprintImplementableEvent, Category = "Powerups")
void OnPowerupStateChanged(bool bNewIsActive);
SPowerUpActor.cpp
ASPowerUpActor::ASPowerUpActor()
{
//...
//设置网络复制
SetReplicates(true);
bIsPowerActive = false;
}
void ASPowerUpActor::OnTickPowerUp()
{
//...
if (TickProcessed>=TotalNrOfTicks)//作用次数达到总次数
{
//...
//设置激活状态为否,调用同步函数。
bIsPowerActive = false;
OnRep_PowerActive();
GetWorldTimerManager().ClearTimer(TimerHandle_PowerUpTicks);//清除时间句柄
}
}
void ASPowerUpActor::ActivatePowerUp()
{
//激活道具
OnActivated();
//设置激活状态为否,调用同步函数。
bIsPowerActive = true;
OnRep_PowerActive();
//...
}
void ASPowerUpActor::OnRep_PowerActive()
{
OnPowerUpStateChanged(bIsPowerActive);
}
void ASPowerUpActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASPowerUpActor,bIsPowerActive);
}
SPickUpActor.h
SpickUpActor.cpp
ASPickUpActor::ASPickUpActor()
{
//...
SetReplicates(true);
}
void ASPickUpActor::BeginPlay()
{
Super::BeginPlay();
//只在服务端生成道具
if (GetLocalRole() == ROLE_Authority)
{
//刚开始时生成道具
ResPawn();
}
}
void ASPickUpActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
//如果生成的道具实例存在,则让道具起作用,然后将道具实例置空,并设置定时器生成下一个道具
//同时需要判断碰到的是不是角色,并且只在服务端激活道具
ASCharacter* Character = Cast<ASCharacter>(OtherActor);
if (Character && PowerUpInstance && GetLocalRole()==ROLE_Authority)
{
PowerUpInstance->ActivatePowerUp();
PowerUpInstance = nullptr;
//设置生成道具的定时器,每隔CooldownDuration时间调用一次ResPawn()生成道具的函数。
GetWorldTimerManager().SetTimer(TimerHandle_RespawnTimer, this, &ASPickUpActor::ResPawn, CooldownDuration);
}
}
2.修改蓝图类
BP_PowerUpBase
,用道具基类实现道具显示和销毁逻辑
3.修改蓝图类
Powerup_HealthRegen,子类负责实现具体功能,删除设置可视性逻辑。
4.修改蓝图类
Powerup_HealthRegen
,修改为玩家群体加血
5.实现联机的单人加速(需要指定道具作用的对象,获取玩家Pawn只能获取到玩家0,思路是在玩家重叠道具的时候传那个OtherActor)
1.SPowerUpActor.h
//激活道具
// void ActivatePowerUp();
//指定道具作用目标ActiveFor
void ActivatePowerUp(AActor* ActiveFor);
// UFUNCTION(BlueprintImplementableEvent,Category="Powerups")
// void OnActivated();
UFUNCTION(BlueprintImplementableEvent,Category="Powerups")
void OnActivated(AActor* ActiveFor);
2.SPowerUpActor.cpp
//void ASPowerUpActor::ActivatePowerUp(){}修改为带参的函数
void ASPowerUpActor::ActivatePowerUp(AActor* ActiveFor)
{
OnActivated(ActiveFor);
//...
}
3.SPickUpActor.cpp
void ASPickUpActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
//...
if (Character && PowerUpInstance && GetLocalRole()==ROLE_Authority)
{
////这里传入碰到道具的玩家为激活对象
PowerUpInstance->ActivatePowerUp(OtherActor);//道具起作用
//...
}
}
4.修改蓝图类 PowerUp_SuperSpeed