当前位置:   article > 正文

UE5 C++跑酷练习(Part2)

UE5 C++跑酷练习(Part2)

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

  1. #include "CoreMinimal.h"
  2. #include "GameFramework/GameModeBase.h"
  3. #include "RunGANGameMode.generated.h"
  4. UCLASS(minimalapi)
  5. class ARunGANGameMode : public AGameModeBase
  6. {
  7. GENERATED_BODY()
  8. UPROPERTY()
  9. TArray<TSubclassOf<class AActor>> StraitArray;
  10. UPROPERTY()
  11. TArray<TSubclassOf<class AActor>> LeftRightArray;
  12. UPROPERTY()
  13. TSubclassOf<AActor> NewRoad;
  14. UPROPERTY()
  15. FTransform NextTransforms;
  16. public:
  17. ARunGANGameMode();
  18. TSubclassOf<AActor> RandomInputFloor();
  19. virtual void BeginPlay();
  20. //添加我们地板
  21. void AddFloor();
  22. };

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)。

  1. #include "RunGANGameMode.h"
  2. #include "RunGANCharacter.h"
  3. #include "UObject/ConstructorHelpers.h"
  4. #include "Actor/CollisionInteraction/RunRoad.h"
  5. ARunGANGameMode::ARunGANGameMode()
  6. {
  7. // set default pawn class to our Blueprinted character
  8. static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter"));
  9. if (PlayerPawnBPClass.Class != NULL)
  10. {
  11. DefaultPawnClass = PlayerPawnBPClass.Class;
  12. }
  13. StraitArray.Add(LoadClass<AActor>(NULL,TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_1.BP_StraightRoad_1_C'")));
  14. StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_2.BP_StraightRoad_2_C'")));
  15. StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_3.BP_StraightRoad_3_C'")));
  16. StraitArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_StraightRoad_4.BP_StraightRoad_4_C'")));
  17. LeftRightArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_TurnLeftRoad.BP_TurnLeftRoad_C'")));
  18. LeftRightArray.Add(LoadClass<AActor>(NULL, TEXT("/Script/Engine.Blueprint'/Game/Environment/BP/BP_TurnRightRoad_2.BP_TurnRightRoad_2_C'")));
  19. }

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随机数从不同的类型中生成下个路面。并在一开始设置生成一个路面的位置。

  1. TSubclassOf<AActor> ARunGANGameMode::RandomInputFloor()
  2. {
  3. int32 i = FMath::RandRange(1,100);
  4. if (i <= 80)
  5. {
  6. int32 Index = FMath::RandRange(0,StraitArray.Num()-1);
  7. return StraitArray[Index];
  8. }
  9. else
  10. {
  11. int32 Index = FMath::RandRange(0, LeftRightArray.Num() - 1);
  12. return LeftRightArray[Index];
  13. }
  14. return TSubclassOf<AActor>();
  15. }
  16. void ARunGANGameMode::BeginPlay()
  17. {
  18. Super::BeginPlay();
  19. if (GetWorld())
  20. {
  21. NextTransforms = GetWorld()->GetFirstPlayerController()->GetPawn()->GetTransform();
  22. FVector InLocation = NextTransforms.GetLocation();
  23. InLocation.Y += 100.f;
  24. InLocation.Z -= 200.f;
  25. NextTransforms.SetLocation(InLocation);
  26. for (int32 i = 0; i < 9; i++)
  27. {
  28. AddFloor();
  29. }
  30. }
  31. }

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

  1. //添加我们的地板
  2. void ARunGANGameMode::AddFloor()
  3. {
  4. NewRoad = RandomInputFloor();
  5. if (NewRoad != NULL)
  6. {
  7. FVector const MyLocation = NextTransforms.GetLocation();
  8. FRotator MyRotation(NextTransforms.Rotator());
  9. if (ARunRoad* MyRunRoad = GetWorld()->SpawnActor<ARunRoad>(NewRoad, MyLocation, MyRotation))
  10. {
  11. MyRunRoad->SetActorScale3D(FVector(10.f));
  12. NextTransforms = MyRunRoad->GetAttackToTransform(MyLocation);
  13. }
  14. }
  15. }

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

  1. FTransform ARunRoad::GetAttackToTransform(const FVector& MyLocation)
  2. {
  3. FTransform Transform;
  4. Transform.SetLocation(SpawnPointMiddle->GetComponentToWorld().GetLocation());
  5. Transform.SetRotation(SpawnPointMiddle->GetComponentQuat());
  6. return Transform;
  7. }

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

  1. #include "TurnBox.h"
  2. #include "Components/BoxComponent.h"
  3. #include "../../RunGANCharacter.h"
  4. // Sets default values
  5. ATurnBox::ATurnBox()
  6. {
  7. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
  8. PrimaryActorTick.bCanEverTick = false;
  9. Box = CreateDefaultSubobject<UBoxComponent>(TEXT("TurnBox"));
  10. RootComponent = Box;
  11. }
  12. // Called when the game starts or when spawned
  13. void ATurnBox::BeginPlay()
  14. {
  15. Super::BeginPlay();
  16. Box->OnComponentBeginOverlap.AddDynamic(this,&ATurnBox::CharacterOverlapStart);
  17. Box->OnComponentEndOverlap.AddDynamic(this, &ATurnBox::CharacterOverlapEnd);
  18. }
  19. // Called every frame
  20. void ATurnBox::Tick(float DeltaTime)
  21. {
  22. Super::Tick(DeltaTime);
  23. }
  24. void ATurnBox::CharacterOverlapStart(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
  25. {
  26. if (ARunGANCharacter* InCharacter = Cast<ARunGANCharacter>(OtherActor))
  27. {
  28. InCharacter->bTurn = true;
  29. }
  30. }
  31. void ATurnBox::CharacterOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
  32. {
  33. if (ARunGANCharacter* InCharacter = Cast<ARunGANCharacter>(OtherActor))
  34. {
  35. InCharacter->bTurn = false;
  36. }
  37. }

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

  碰撞显示

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/910460
推荐阅读
相关标签
  

闽ICP备14008679号