UE5 C++跑酷练习(Part2)

一.首先GameMode里有Actor数组,组装直线路,和左右路

cpp 复制代码
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "RunGANGameMode.generated.h"

UCLASS(minimalapi)
class ARunGANGameMode : public AGameModeBase
{
	GENERATED_BODY()
	UPROPERTY()
	TArray<TSubclassOf<class AActor>> StraitArray;
	UPROPERTY()
	TArray<TSubclassOf<class AActor>> LeftRightArray;
	UPROPERTY()
	TSubclassOf<AActor> NewRoad;
	UPROPERTY()
	FTransform NextTransforms;
public:
	ARunGANGameMode();
	TSubclassOf<AActor> RandomInputFloor();
	virtual void BeginPlay();
	//添加我们地板
	void AddFloor();
};

UPROPERTY()不会被GC掉

TSubclassOf

在Unreal中经常会有在蓝图或者C++中声明某些UClass,便于后续用来创建对应的对象,但是如果只是填了一个UClass指针的话,这并不好用。这是因为UClass*可以指代任意UObject,所以在蓝图或者编辑器中选择对应的UClass的时候不好选择,因为基本上所有的UClass都会出现在下拉框内。Unreal也提出对应的解决方案,那就是TSubclassOf,它能够避免能上面说的问题,TSubclassOf能够约束下拉框中只会出现继承于T的类或者T本身,并且C++层面也能实现类型安全,如果给TSubclassOf对象赋值一个类型不兼容的UClass,则会得到编译错误。

二.在GameMode构造函数时,可以使用动态加载 Actor到路面类型。静态加载主角到PlayerPawnBPClass类中,再设置到Gamemode默认的Pawn里(DefaultPawnClass)。

cpp 复制代码
#include "RunGANGameMode.h"
#include "RunGANCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include "Actor/CollisionInteraction/RunRoad.h"
ARunGANGameMode::ARunGANGameMode()
{
	// set default pawn class to our Blueprinted character
	static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter"));
	if (PlayerPawnBPClass.Class != NULL)
	{
		DefaultPawnClass = PlayerPawnBPClass.Class;
	}
	StraitArray.Add(LoadClass<AActor>(NULL,TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_1.BP_StraightRoad_1_C'")));
	StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_2.BP_StraightRoad_2_C'")));
	StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_3.BP_StraightRoad_3_C'")));
	StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_4.BP_StraightRoad_4_C'")));
	LeftRightArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_TurnLeftRoad.BP_TurnLeftRoad_C'")));
	LeftRightArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_TurnRightRoad_2.BP_TurnRightRoad_2_C'")));
}

ConstructorHelpers::FClassFinder()和FObjectFinder()

静态加载指的是在构造函数中完成的加载方式,这种方式的弊端明显,就是需要写死路径,一旦改变路径读取失败很容易造成程序崩溃。

LoadObject<UClass>

也就是说LoadObject和LoadClass函数都用于在运行时加载UObject派生的对象,但是它们的用途和返回值有所不同。

`LoadObject`用于加载单个对象,可以是任何UObject派生类的实例,包括UClass、UTexture、UMaterial等。它会返回加载的对象,或者在加载失败时返回nullptr

同时,如果使用LoadClass()方法,路径名也必须带_C后缀(LoadObject不需要带_C后缀),例如,蓝图路径是:Blueprint'/Game/Blueprints/Test', 加后缀以后,则是:Blueprint'/Game/Blueprints/Test_C'

三.通过FMath::RandRange随机数从不同的类型中生成下个路面。并在一开始设置生成一个路面的位置。

cpp 复制代码
TSubclassOf<AActor> ARunGANGameMode::RandomInputFloor()
{
	int32 i = FMath::RandRange(1,100);
	if (i <= 80)
	{
		int32 Index = FMath::RandRange(0,StraitArray.Num()-1);
		return StraitArray[Index];
	}
	else
	{
		int32 Index = FMath::RandRange(0, LeftRightArray.Num() - 1);
		return LeftRightArray[Index];
	}
	return TSubclassOf<AActor>();
}
void ARunGANGameMode::BeginPlay()
{
	Super::BeginPlay();
	if (GetWorld())
	{
		NextTransforms = GetWorld()->GetFirstPlayerController()->GetPawn()->GetTransform();
		FVector InLocation = NextTransforms.GetLocation();
		InLocation.Y += 100.f;
		InLocation.Z -= 200.f;
		NextTransforms.SetLocation(InLocation);
		for (int32 i = 0; i < 9; i++)
		{
			AddFloor();
		}
	}
}

四.添加地板逻辑,拼贴点位。

cpp 复制代码
//添加我们的地板
void ARunGANGameMode::AddFloor()
{
	NewRoad = RandomInputFloor();
	if (NewRoad != NULL)
	{
		FVector const MyLocation = NextTransforms.GetLocation();
		FRotator MyRotation(NextTransforms.Rotator());
		if (ARunRoad* MyRunRoad = GetWorld()->SpawnActor<ARunRoad>(NewRoad, MyLocation, MyRotation))
		{
			MyRunRoad->SetActorScale3D(FVector(10.f));
			NextTransforms = MyRunRoad->GetAttackToTransform(MyLocation);
		}
	}
}

五.AddFloor里使用的GetAttackToTransform是使用每个,路面自己对准的下一个路面的位置。

cpp 复制代码
FTransform ARunRoad::GetAttackToTransform(const FVector& MyLocation)
{
	FTransform Transform;
	Transform.SetLocation(SpawnPointMiddle->GetComponentToWorld().GetLocation());
	Transform.SetRotation(SpawnPointMiddle->GetComponentQuat());
	return Transform;
}

六.通过跑步碰撞,判断。开启角色可以转弯的功能,

cpp 复制代码
#include "TurnBox.h"
#include "Components/BoxComponent.h"
#include "../../RunGANCharacter.h"

// Sets default values
ATurnBox::ATurnBox()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;
	Box = CreateDefaultSubobject<UBoxComponent>(TEXT("TurnBox"));
	RootComponent = Box;
}

// Called when the game starts or when spawned
void ATurnBox::BeginPlay()
{
	Super::BeginPlay();	
	Box->OnComponentBeginOverlap.AddDynamic(this,&ATurnBox::CharacterOverlapStart);
	Box->OnComponentEndOverlap.AddDynamic(this, &ATurnBox::CharacterOverlapEnd);
}

// Called every frame
void ATurnBox::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void ATurnBox::CharacterOverlapStart(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (ARunGANCharacter* InCharacter =  Cast<ARunGANCharacter>(OtherActor))
	{
		InCharacter->bTurn = true;
	}
}

void ATurnBox::CharacterOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (ARunGANCharacter* InCharacter = Cast<ARunGANCharacter>(OtherActor))
	{
		InCharacter->bTurn = false;
	}
}

TurnBox,位置不对。可以用蓝图具象化调整。

碰撞显示

BP_TurnBox 的位置就是Arrow的位置,记住Dlay延迟一下,预防Scale位置会有问题偏差。

相关推荐
qq_441996058 分钟前
Mybatis官方生成器使用示例
java·mybatis
巨大八爪鱼14 分钟前
XP系统下用mod_jk 1.2.40整合apache2.2.16和tomcat 6.0.29,让apache可以同时访问php和jsp页面
java·tomcat·apache·mod_jk
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田2 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
小白学大数据3 小时前
Python爬虫开发中的分析与方案制定
开发语言·c++·爬虫·python
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
枫叶_v4 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
wclass-zhengge4 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud