[6] UE C++ 基础操作
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; //重载了 =
}
}
}
}
}
}
切换相机为当前类的相机
UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetViewTarget(this);