FlappyBird專案
引入Paper2D外掛
//渲染資產的元件
class UPaperSpriteComponent* RenderLandComponent;
//資產
class UPaperSprite* LandSprite;
GameModeBase.h.cpp
UE列舉宣告
//列舉(用於描述狀態資訊)
UENUM()
enum EBirdStateTest //傳統列舉
{
EBS_Wait,//等待遊戲開始狀態的小鳥
EBS_Fly,//遊戲開始小鳥可以飛
EBS_Dead//遊戲結束,小鳥標記為死亡狀態
};
UENUM()
enum EColor //傳統列舉
{
EC_Wait,//等待遊戲開始狀態的小鳥
EC_Fly,//遊戲開始小鳥可以飛
EC_Dead//遊戲結束,小鳥標記為死亡狀態
};
UENUM()
namespace EBirdStateSecondTest //加名稱空間的列舉,明明空間名是列舉名
{
enum Type
{
Wait,//等待遊戲開始狀態的小鳥
Fly,//遊戲開始小鳥可以飛
Dead//遊戲結束,小鳥標記為死亡狀態
};
}
UENUM()
enum class EBirdState:uint8 //C++11的列舉(UE中常見)
{
Wait,//等待遊戲開始狀態的小鳥
Fly,//遊戲開始小鳥可以飛
Dead//遊戲結束,小鳥標記為死亡狀態
};
//使用
//在一個列舉用於純C++原始碼而不應用於藍圖的時候,需要先寫一個列舉變數記錄狀態,再新增一個函式用於修改狀態
EBirdStateTest CurrentBirdStateTest1;//記錄狀態(傳統列舉)
void SetBirdStateTest(EBirdStateTest BirdState);//高版本Rider不允許成員的名字與區域性變數的名字衝突
//A::B//B屬於A這個作用域
EBirdStateSecondTest::Type CurrentBirdStateSecondTest;//記錄狀態(加名稱空間的列舉)
void SetBirdStateSecondTest(EBirdStateSecondTest::Type BirdState);
EBirdState CurrentBirdState;//記錄狀態(C++11的列舉)
void SetBirdState(EBirdState BirdState);
void ABirdPawn::SetBirdState(EBirdState BirdState)
{
CurrentBirdState = BirdState; //成員屬性被引數修改(傳值)
//根據不同的狀態做出不同的響應
switch (CurrentBirdState)
{
case EBirdState::Wait: RenderBirdComponent->SetSimulatePhysics(false);
break;
case EBirdState::Fly: RenderBirdComponent->SetSimulatePhysics(true);
break;
case EBirdState::Dead: RenderBirdComponent->SetSimulatePhysics(false);
break;
}
}
獲取類的型別資訊
DefaultPawnClass = ABirdPawn::StaticClass();
列舉賦值
CurrentGameState = EGameState::BeginUI;
生成一個SpawnActor
GetWorld()->SpawnActor<ABackgroundActor>(ABackgroundActor::StaticClass(), FVector(0, -50, 0),
FRotator::ZeroRotator);
獲取當前遊戲世界的指標
GetWorld()
BackgroundActor.h.cpp
建立根元件 > 並設定附加關係
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent")); //建立USceneComponent的元件
RenderBackgroundComponent = CreateDefaultSubobject<UPaperSpriteComponent>(TEXT("RenderBackgroundComponent"));//建立UPaperSpriteComponent型別的元件
RenderBackgroundComponent->SetupAttachment(RootComponent); //把RenderBackgroundComponent附著到RootComponent上
載入ue專案檔案
LoadObject<UPaperSprite>(nullptr,TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Background/bg_day_Sprite.bg_day_Sprite'"));
獲取隨機數
FMath::RandRange(1,100)
渲染圖片
//渲染資產的元件
class UPaperSpriteComponent* RenderBackgroundComponent;
//資產
class UPaperSprite* DayBackgroundTexture;
//載入檔案物件
DayBackgroundTexture=LoadObject<UPaperSprite>(nullptr,TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Background/bg_day_Sprite.bg_day_Sprite'"));
//設定渲染
RenderBackgroundComponent->SetSprite(NightBackgroundTexture);
BirdHUD.h.cpp
宣告2d向量
FVector2D PlayButtonSize;
PlayButtonSize = FVector2D(116, 70); //按鈕大小
宣告&&載入紋理&&渲染紋理&&新增命中事件
UTexture* PlayButtonTexture;
//載入紋理
PlayButtonTexture = LoadObject<UTexture>(
nullptr,TEXT("/Script/Engine.Texture2D'/Game/FlappyBird/Textures/UI/button_play.button_play'"))
//渲染簡單紋理
DrawTextureSimple(PlayButtonTexture, Canvas->SizeX / 2 - (PlayButtonSize.X / 2),Canvas->SizeY / 2 - (PlayButtonSize.Y / 2));
//Canvas->SizeX 獲取螢幕X寬度 Canvas->SizeY Y軸
//新增命中事件
AddHitBox(FVector2D(Canvas->SizeX / 2 - (PlayButtonSize.X / 2), Canvas->SizeY / 2 - (PlayButtonSize.Y / 2)),PlayButtonSize,TEXT("Play"), true);
//觸發名字是 Play 的命中事件
void ABirdHUD::NotifyHitBoxRelease(FName BoxName)
{
Super::NotifyHitBoxRelease(BoxName);
if (BoxName == TEXT("Play"))
{
UE_LOG(LogTemp, Log, TEXT("單機"))
}
}
設定單擊事件和顯示滑鼠
// Cast<To>()
BirdPawnInstancePointer = Cast<ABirdPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0);
PC->SetShowMouseCursor(true);
PC->bEnableClickEvents = true;
繪製矩形包括RGBA通道
//RectAlpha 0.38 -> 0.0
DrawRect(FLinearColor(0, 0, 0, RectAlpha), 0, 0, Canvas->SizeX, Canvas->SizeY);
BirdPawn.h.cpp
輸入事件
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
void ABirdPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
InputComponent->BindAction(TEXT("Fly"), EInputEvent::IE_Pressed, this, &ABirdPawn::FlyCallBack);//操作
InputComponent->BindAxis(TEXT("Test"),this,&ABirdPawn::TestBindAxisFunction);//軸對映
}
//回撥函式
void ABirdPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
InputComponent->BindAction(TEXT("Fly"), EInputEvent::IE_Pressed, this, &ABirdPawn::FlyCallBack);//操作對映
InputComponent->BindAxis(TEXT("Test"),this,&ABirdPawn::TestBindAxisFunction);//軸對映
}
void ABirdPawn::FlyCallBack() //操作對映
{
UE_LOG(LogTemp, Log, TEXT("按下"))
RenderBirdComponent->SetPhysicsLinearVelocity(FVector::Zero()); //清除物體當前的線性速度
RenderBirdComponent->AddImpulse(FVector(0, 0, 2000));//物體施加一個衝量
}
void ABirdPawn::TestBindAxisFunction(float AxisValue) //軸對映
{
UE_LOG(LogTemp, Log, TEXT("按下A "))
}
void ABirdPawn::BeginPlay()
{
Super::BeginPlay();
//也可以在BeginPlay呼叫
InputComponent->BindAction();//如果沒有SetupPlayerInputComponent就可以在Begin函式中使用Actor類下的成員屬性呼叫成員函式BindAction或者BindAxis
RenderBirdComponent->SetSimulatePhysics(true);
RenderBirdComponent->OnComponentHit.AddDynamic(this,&ABirdPawn::OnComponentHit);//繫結一個Hit事件並執行回撥函式
SphereCollision->OnComponentBeginOverlap.AddDynamic(this, &ABirdPawn::OnComponentBeginOverlap);
}
設定物理
RenderBirdComponent->SetSimulatePhysics(true)//設定物理
RenderBirdComponent->GetBodyInstance()->bNotifyRigidBodyCollision = true; //如果元件開啟了物理模擬,是否還響應Hit事件
RenderBirdComponent->SetCollisionProfileName(TEXT("BlockAll"));//將碰撞預設修改為BlockAll
RenderBirdComponent->SetCollisionObjectType(ECC_Pawn); //將Object(元件)型別修改為Pawn
RenderBirdComponent->OnComponentHit.AddDynamic(this, &ABirdPawn::OnComponentHit); //繫結一個Hit事件並執行回撥函式
//列印被擊中的Actor名稱
void ABirdPawn::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
FVector NormalImpulse, const FHitResult& Hit)
{
APipeActor* Pipe = Cast<APipeActor>(OtherActor); //轉成bird
if (Pipe)
{
UE_LOG(LogTemp, Log, TEXT("PipeInstanceName = %s"), *Pipe->GetName())
}
if (Cast<ALandActor>(OtherActor))
{
}
}
//建立一個球體設定碰撞型別和大小
SphereCollision = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
SphereCollision->SetupAttachment(RenderBirdComponent);
SphereCollision->SetCollisionProfileName(TEXT("OverlapAll"));
SphereCollision->SetSphereRadius(26.f);
SphereCollision->bHiddenInGame = false;
衝量
void ABirdPawn::FlyCallBack()
{
if (CurrentBirdState != EBirdState::Fly)return;
//UE_LOG(LogTemp, Log, TEXT("按下"))
RenderBirdComponent->SetPhysicsLinearVelocity(FVector::Zero()); //清除原有的速度
RenderBirdComponent->AddImpulse(FVector(0, 0, 1300));
}
設定相對旋轉
ArmComponent->SetRelativeRotation(FRotator(0, -90, 0));
設定相機模式&&和正交
MainCamera->SetProjectionMode(ECameraProjectionMode::Orthographic);
MainCamera->OrthoWidth = 1000.f;
新增本地偏移
RenderLandComponent->AddLocalOffset(FVector(_Speed,0,0));
PipeActor.h.cpp
自定義FString的名稱
FString SceneName = FString::Printf(TEXT("Scene%d"),i);//字串的格式化輸出
FName _SceneName = *SceneName;//當*用到FString變數的前邊的時候,代表的是強制型別轉換(由FString強轉為TCHAR型別的陣列,TEXT("")宏本質就是一個TCHAR型別的陣列)
USceneComponent* Scene=CreateDefaultSubobject<USceneComponent>(_SceneName);//假設迴圈第1次 地址是0X123
匿名載入紋理
ConstructorHelpers::FObjectFinder<UPaperSprite> UpPipePath(TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Prop/pipe_up_Sprite.pipe_up_Sprite'"));
ConstructorHelpers::FObjectFinder<UPaperSprite> DownPipePath(TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Prop/pipe_down_Sprite.pipe_down_Sprite'"));
在UE C++使用過載運算子
//宣告
struct FPipeInfo
{
bool bPlayCoinSound; //控制加分和播放加分音效的屬性
USceneComponent* SceneInstancePointer; //每組管道的父元件的物件地址
FPipeInfo(bool bPlayCoin)
{
this->bPlayCoinSound = bPlayCoin;
UE_LOG(LogTemp, Log, TEXT("FPipeInfo(bool bPlayCoin)"))
}
FPipeInfo(USceneComponent* SceneInstance)
{
UE_LOG(LogTemp, Log, TEXT("FPipeInfo(USceneComponent* SceneInstance)"))
this->SceneInstancePointer = SceneInstance;
bPlayCoinSound = true;
}
//將FPipeInfo強制型別轉換到USceneComponent型別
operator USceneComponent*()
{
return SceneInstancePointer;
}
//運算子過載 ->
USceneComponent* operator->()
{
return SceneInstancePointer;
}
operator bool() //將當前的型別強制轉換為bool型別
{
return bPlayCoinSound;
}
bool operator=(bool Value)
{
this->bPlayCoinSound = Value;
return bPlayCoinSound;
}
};
TArray<FPipeInfo> SceneArray;//使用
//.cpp
//新增
APipeActor::APipeActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComponent=CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
ConstructorHelpers::FObjectFinder<UPaperSprite> UpPipePath(TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Prop/pipe_up_Sprite.pipe_up_Sprite'"));
ConstructorHelpers::FObjectFinder<UPaperSprite> DownPipePath(TEXT("/Script/Paper2D.PaperSprite'/Game/FlappyBird/Textures/Prop/pipe_down_Sprite.pipe_down_Sprite'"));
PipeSpace=220.f;
for(int32 i=0;i<3;i++)
{
FString SceneName = FString::Printf(TEXT("Scene%d"),i);//字串的格式化輸出
FName _SceneName = *SceneName;//當*用到FString變數的前邊的時候,代表的是強制型別轉換(由FString強轉為TCHAR型別的陣列,TEXT("")宏本質就是一個TCHAR型別的陣列)
USceneComponent* Scene=CreateDefaultSubobject<USceneComponent>(_SceneName);//假設迴圈第1次 地址是0X123
FString UpName = FString::Printf(TEXT("Up%d"),i);
FName _UpName = *UpName;
UPaperSpriteComponent*Up=CreateDefaultSubobject<UPaperSpriteComponent>(_UpName);
FString DownName = FString::Printf(TEXT("Down%d"),i);
FName _DownName = *DownName;
UPaperSpriteComponent*Down=CreateDefaultSubobject<UPaperSpriteComponent>(_DownName);
Scene->SetupAttachment(RootComponent);
Up->SetupAttachment( Scene);
Down->SetupAttachment( Scene);
//匯入管道的資產
if(UpPipePath.Object&&DownPipePath.Object)
{
Up->SetSprite(UpPipePath.Object);
Down->SetSprite(DownPipePath.Object);
}
//設定每組上下管道之間的間距
Up->SetRelativeLocation(FVector(0,0,-210));
Down->SetRelativeLocation(FVector(0,0,260));
//重置了宣告
SceneArray.Add(Scene);//Add本來需要一個FPipeInfo型別物件,但是因為有強制型別轉換到
}
SetPipeSpace();//設定管道的左右間距
RandPipeHeight();//設定隨機高度
//PipeMoveSpeed=170.f;
PipeMoveSpeed=0.f;
bAddScoreToggle=true;
CoinSound=nullptr;
}
void APipeActor::UpdatePipeMove(float DeltaTime)
{ float _Speed=DeltaTime*PipeMoveSpeed*-1;
if(SceneArray.Num()) //過載了布林
{
for(int32 i=0;i<SceneArray.Num();i++)
{
//設定本次迴圈中一根管道的移動
SceneArray[i]->AddRelativeLocation(FVector(_Speed,0,0)); //過載了 ->
//移動過程中實時監控管道的位置是不是已經到達需要折返的位置(折返點 -280)
if(SceneArray[i]->GetRelativeLocation().X<=-280)//折返點
{
int32 index=i-1;
if(index<0)
{
index=2;
}
FVector OldLocation=SceneArray[i]->GetRelativeLocation();
OldLocation.X=SceneArray[index]->GetRelativeLocation().X+PipeSpace;
SceneArray[i]->SetRelativeLocation(OldLocation);
RandPipeHeight(SceneArray[i]);
//bAddScoreToggle=true;
//SceneArray[i].bPlayCoinSound=true;
SceneArray[i]=true; //過載了 =
}
if(SceneArray[i]->GetRelativeLocation().X<=-90)//加分點
{
if(BirdGameState)
{
//if(bAddScoreToggle)
if(SceneArray[i])
{
BirdGameState->AddScore();
UGameplayStatics::PlaySound2D(GetWorld(),CoinSound);
//bAddScoreToggle=false;//本次已經加分完成,關閉加分開關
//SceneArray[i].bPlayCoinSound=false;
SceneArray[i]=false; //過載了 =
}
}
}
}
}
}