[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); 

 

posted @ 2024-04-03 20:27  啊賢  阅读(78)  评论(0编辑  收藏  举报