从QuickDraw项目入门,制作一个简单的2D小游戏6
一.NPC的攻击
利用广播和动态多播委托实现,在GM_Duel.h中声明一个动态委托
//声明动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDrawPhaseStart);
再在GM_Duel类中定义一个动态多播的实例
public:
//定义动态委托实例
UPROPERTY(BlueprintAssignable)
FDrawPhaseStart DrawPhaseStart;
然后在GM_Duel.cpp中,在Draw阶段开始时触发广播
void AGM_Duel::Tick(float DeltaTime)
{
this->ElapsedTime += DeltaTime;
//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("%f"), this->ElapsedTime));
switch (this->Phase)
{
case E_Phase::Intro:
{
//在intro阶段,等两个精灵滑动结束后,切换到wait阶段,然后延迟一段时间转进draw阶段
if (this->ElapsedTime >= this->StartTime)
{
this->Phase = E_Phase::Wait;
FLatentActionInfo LatentAction(0, FMath::Rand(), TEXT("TransWaitToDraw"), this);
UKismetSystemLibrary::Delay(this, FMath::FRandRange(MinDrawStartTime, MaxDrawStartTime), LatentAction);
}
break;
}
case E_Phase::Wait:
{
break;
}
case E_Phase::Draw:
{
//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("draw %i"), this->Phase));
if (this->Exclamation != NULL)
{
//假如指针有效,将一个指向Exclamation类的指针指向他,然后设置可见性为true
AExclamation* tem = Cast<AExclamation>(this->Exclamation);
tem->SetVisibility(true);
}
//广播事件,让Samurai_NPC类知道
DrawPhaseStart.Broadcast();
break;
}
case E_Phase::Finished:
{
//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("Finished %i"), this->Phase));
break;
}
default:
{
break;
}
}
}
接下来开始对Samurai_NPC类进行一些代码实现,在Samurai_NPC.h中
#pragma once
#include "CoreMinimal.h"
#include "Samurai.h"
#include "Samurai_NPC.generated.h"
/**
*
*/
UCLASS()
class QUICKDRAW_API ASamurai_NPC : public ASamurai
{
GENERATED_BODY()
public:
//攻击延迟的最小值
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float MinAttackDelay = 0.3;
//攻击延迟的最大值
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float MaxAttackDelay = 1.1;
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
//攻击,简单的调用父类函数,UFUNCTION宏为了能让延迟函数识别到
UFUNCTION()
virtual void Attack() override;
//延迟调用攻击,另外写作一个函数,要有UFUNCTION宏,否则接受不到广播事件
UFUNCTION()
void NPCAttackDelay();
};
在GM_Duel.cpp里实现如下
#include "GM_Duel.h"
#include "Kismet/GameplayStatics.h"
#include "Samurai_NPC.h"
void ASamurai_NPC::BeginPlay()
{
Super::BeginPlay();
//订阅事件
if (this->GameMode)
{
GameMode->DrawPhaseStart.AddDynamic(this, &ASamurai_NPC::NPCAttackDelay);
}
}
void ASamurai_NPC::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
//解除订阅
if (GameMode)
{
GameMode->DrawPhaseStart.RemoveDynamic(this, &ASamurai_NPC::Attack);
}
Super::EndPlay(EndPlayReason);
}
void ASamurai_NPC::Attack()
{
//GEngine->AddOnScreenDebugMessage(-1, 2.0, FColor::Green, FString("NPC Attack"));
Super::Attack();
}
void ASamurai_NPC::NPCAttackDelay()
{
//延迟调用攻击
FLatentActionInfo LatentAction(0, FMath::Rand(), TEXT("Attack"), this);
UKismetSystemLibrary::Delay(this, FMath::FRandRange(MinAttackDelay, MaxAttackDelay), LatentAction);
}
到此为止,转到虚幻编辑器中,选择被打倒时的玩家精灵姿态

再选择NPC武士精灵的攻击姿态,调整攻击滑动的结束位置

至此就完成了这块的功能编写
二.重置
在攻击成功后希望能够重置游戏状态,以此循环。在Samurai.h中,声明重置武士类状态的函数,并定义闲置状态精灵的变量
public:
//闲置状态的精灵
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<UPaperSprite> IdleSprite;
//重置武士状态
void Reset();
在Samurai.cpp中实现重置状态的函数
void ASamurai::Reset()
{
//将叉精灵置为不可见
this->SetCrossVisbility(false);
//复原攻击键按下状态
this->isAttackPressed = false;
//切换精灵至闲置状态
SpriteComponent->SetSprite(IdleSprite);
//调用滑动入场函数,如同游戏开始那样
this->SlideIn();
}
在GM_Duel.h中,为GM_Duel类添加类成员和函数
public:
//重置游戏状态
void Reset();
//定时器
FTimerHandle ResetTimerHandle;
在GM_Duel.cpp中实现重置状态函数,并在成功攻击后使用定时器,延迟一段时间调用它
void AGM_Duel::AttackSuccessfully(bool isPlayer)
{
ASamurai_Player* SamuraiPlayer = Cast<ASamurai_Player>(UGameplayStatics::GetActorOfClass(this->GetWorld(), ASamurai_Player::StaticClass()));
ASamurai_NPC* SamuraiNPC = Cast<ASamurai_NPC>(UGameplayStatics::GetActorOfClass(this->GetWorld(), ASamurai_NPC::StaticClass()));
if (isPlayer)
{
SamuraiNPC->Defeated();
}
else
{
SamuraiPlayer->Defeated();
}
//因为攻击判定成功了,因此将感叹号置为不可见状态
if (this->Exclamation != NULL)
{
AExclamation* tem = Cast<AExclamation>(this->Exclamation);
tem->SetVisibility(false);
}
//使用定时器,延时3秒调用Reset
FTimerManager& TimerManager = this->GetWorldTimerManager();
TimerManager.SetTimer(ResetTimerHandle, this, &AGM_Duel::Reset, 3.0f, false);
}
void AGM_Duel::Reset()
{
//重置游戏阶段
this->Phase = E_Phase::Intro;
ASamurai_Player* SamuraiPlayer = Cast<ASamurai_Player>(UGameplayStatics::GetActorOfClass(this->GetWorld(), ASamurai_Player::StaticClass()));
ASamurai_NPC* SamuraiNPC = Cast<ASamurai_NPC>(UGameplayStatics::GetActorOfClass(this->GetWorld(), ASamurai_NPC::StaticClass()));
//调用武士状态重置
SamuraiPlayer->Reset();
SamuraiNPC->Reset();
}
之后回到虚幻编辑器中,选择武士闲置状态精灵即可



浙公网安备 33010602011771号