当前位置:   article > 正文

UE5 C++ 跑酷游戏练习 Part1

UE5 C++ 跑酷游戏练习 Part1

一.修改第三人称模板的 Charactor

1.随鼠标将四处看的功能的输入注释掉。

  1. void ARunGANCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
  2. {
  3. // Set up action bindings
  4. if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
  5. //Jumping
  6. EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
  7. EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
  8. //Moving
  9. EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ARunGANCharacter::Move);
  10. //Looking
  11. //EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ARunGANCharacter::Look);
  12. }

2.在Tick里,注释掉计算左右方向的部分。只让它获得向前的方向。再加个每帧都朝,正前方输入的逻辑。

  1. void ARunGANCharacter::Tick(float DeltaSeconds)
  2. {
  3. Super::Tick(DeltaSeconds);
  4. GetController()->SetControlRotation(FMath::RInterpConstantTo(GetControlRotation(),DesireRotation,GetWorld()->GetRealTimeSeconds(),10.f));
  5. //
  6. const FRotator Rotation = Controller->GetControlRotation();
  7. const FRotator YawRotation(0, Rotation.Yaw, 0);
  8. // get forward vector
  9. const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
  10. // get right vector
  11. //const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
  12. //
  13. AddMovementInput(ForwardDirection, 1);
  14. }

3.修改按下输入,调用的Move里的逻辑。让它如果转向,就按自己输入的X方向。旋转90度。

如果不转向,按照人物控制当前的朝向,计算左右的向量,并添加左右输入。

相当于一直向前跑,不转向可以左右调整。

  1. if (bTurn)
  2. {
  3. //GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,TEXT("Turn"));
  4. FRotator NewRotation = FRotator(0.f,90.f*(MovementVector.X), 0.f);
  5. FQuat QuatA = FQuat(DesireRotation);
  6. FQuat QuatB = FQuat(NewRotation);
  7. DesireRotation = FRotator(QuatA * QuatB);
  8. bTurn = false;
  9. }
  10. else
  11. {
  12. // find out which way is forward
  13. const FRotator Rotation = Controller->GetControlRotation();
  14. const FRotator YawRotation(0, Rotation.Yaw, 0);
  15. // get forward vector
  16. //const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
  17. // get right vector
  18. const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
  19. //ForwardDirection = FVector(0,0,0);
  20. // add movement
  21. //AddMovementInput(ForwardDirection, 0); //
  22. AddMovementInput(RightDirection, MovementVector.X);
  23. /* if (Controller->IsLocalPlayerController())
  24. {
  25. APlayerController* const PC = CastChecked<APlayerController>(Controller);
  26. }*/
  27. //GetCharacterMovement()->bOrientRotationToMovement = false;
  28. //
  29. }

4.这里转向的方向DesireRotation,会被一直赋值到控制器(Controller->GetControlRotation)。进而影响我们 向前方向。因为Tick里一直在修正。左右会在,Move回调函数里添加,也受控制器的影响。

  1. void ARunGANCharacter::Tick(float DeltaSeconds)
  2. {
  3. Super::Tick(DeltaSeconds);
  4. GetController()->SetControlRotation(FMath::RInterpConstantTo(GetControlRotation(),DesireRotation,GetWorld()->GetRealTimeSeconds(),10.f));
  5. //
  6. const FRotator Rotation = Controller->GetControlRotation();
  7. const FRotator YawRotation(0, Rotation.Yaw, 0);
  8. // get forward vector
  9. const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
  10. // get right vector
  11. //const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
  12. //
  13. AddMovementInput(ForwardDirection, 1);
  14. }

人物逻辑就写好了,一直跑,Turn为True时转90.其余时间,相当于一直按W,你自己决定要不要A,D,斜向跑。

二.写碰撞,碰撞时,能实现转向。

创建TurnBox C++ Actor类。在里面,添加UBoxComponent组件,添加碰撞的回调函数。内容也很简单,如果是 角色碰撞,让它的装箱变量变为True。

  1. #include "TurnBox.generated.h"
  2. class UBoxComponent;
  3. UCLASS()
  4. class RUNGAN_API ATurnBox : public AActor
  5. {
  6. GENERATED_BODY()
  7. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = Box,meta = (AllowPrivateAccess = "true"))
  8. UBoxComponent* Box;
  9. public:
  10. // Sets default values for this actor's properties
  11. ATurnBox();
  12. protected:
  13. // Called when the game starts or when spawned
  14. virtual void BeginPlay() override;
  15. public:
  16. // Called every frame
  17. virtual void Tick(float DeltaTime) override;
  18. UFUNCTION()
  19. void CharacterOverlapStart(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
  20. // UPrimitiveComponent, OnComponentBeginOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult);
  21. UFUNCTION()
  22. void CharacterOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
  23. //UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex);
  24. };

这里实例化组件,就不写了。把角色的头文件,包含进去。绑定回调,回调里判断逻辑。

  1. // Called when the game starts or when spawned
  2. void ATurnBox::BeginPlay()
  3. {
  4. Super::BeginPlay();
  5. Box->OnComponentBeginOverlap.AddDynamic(this,&ATurnBox::CharacterOverlapStart);
  6. Box->OnComponentEndOverlap.AddDynamic(this, &ATurnBox::CharacterOverlapEnd);
  7. }
  8. // Called every frame
  9. void ATurnBox::Tick(float DeltaTime)
  10. {
  11. Super::Tick(DeltaTime);
  12. }
  13. void ATurnBox::CharacterOverlapStart(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
  14. {
  15. if (ARunGANCharacter* InCharacter = Cast<ARunGANCharacter>(OtherActor))
  16. {
  17. InCharacter->bTurn = true;
  18. }
  19. }
  20. void ATurnBox::CharacterOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
  21. {
  22. if (ARunGANCharacter* InCharacter = Cast<ARunGANCharacter>(OtherActor))
  23. {
  24. InCharacter->bTurn = false;
  25. }
  26. }

三.开始写路的逻辑,随机生成。

1.准备好道路资源

2.这里将道路,分为直道,转弯道,上下道。使用了UE创建枚举的方式。

  1. #pragma once
  2. #include"CoreMinimal.h"
  3. #include "RunGANType.generated.h"
  4. UENUM()
  5. enum class FRoadType :uint8 //只需要一个字节,更高效 0-255
  6. {
  7. StraitFloor,
  8. TurnFloor,
  9. UPAndDownFloor,
  10. MAX,
  11. };

3.然后我们创建道路类,写上通用逻辑。在头文件,将道路类型加上,并前项声明 指针 指向的组件类。

  1. #include "../../RunGANType.h"
  2. #include "RunRoad.generated.h"
  3. class UBoxComponent;
  4. class USceneComponent;
  5. class UStaticMeshComponent;
  6. class UArrowComponent;
  7. UCLASS()
  8. class RUNGAN_API ARunRoad : public AActor
  9. {
  10. GENERATED_BODY()
  11. //场景组件
  12. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J", meta = (AllowPrivateAccess = "true"))
  13. USceneComponent* SceneComponent;
  14. //根组件
  15. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J", meta = (AllowPrivateAccess = "true"))
  16. USceneComponent* RunRoadRootComponent;
  17. //碰撞
  18. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J",meta = (AllowPrivateAccess = "true"))
  19. UBoxComponent* BoxComponent;
  20. //模型
  21. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J",meta = (AllowPrivateAccess = "true"))
  22. UStaticMeshComponent* RoadMesh;
  23. //方向
  24. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J",meta = (AllowPrivateAccess = "true"))
  25. UArrowComponent* SpawnPointMiddle;
  26. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J",meta = (AllowPrivateAccess = "true"))
  27. UArrowComponent* SpawnPointRight;
  28. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "C_J",meta = (AllowPrivateAccess = "true"))
  29. UArrowComponent* SpawnPointLeft;
  30. //地板类型
  31. UPROPERTY(EditDefaultsOnly,Category = "TowerType") //EditDefaultsOnly:蓝图可以编译,但是在主编译器不显示所以不可以编译
  32. FRoadType RoadType;
  33. public:
  34. // Sets default values for this actor's properties
  35. ARunRoad();
  36. FTransform GetAttackToTransform(const FVector& MyLocation);
  37. protected:
  38. // Called when the game starts or when spawned
  39. virtual void BeginPlay() override;
  40. public:
  41. // Called every frame
  42. virtual void Tick(float DeltaTime) override;
  43. UFUNCTION()
  44. void CharacterOverlapStart(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
  45. // UPrimitiveComponent, OnComponentBeginOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult);
  46. UFUNCTION()
  47. void CharacterOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

4.实现逻辑

  1. #include"Components/BoxComponent.h"
  2. #include"Components/SceneComponent.h"
  3. #include"Components/StaticMeshComponent.h"
  4. #include"Components/ArrowComponent.h"

CreateDefaultSubobject<T>实例化组件,SetupAttachment添加组件,Root根组件,Father在根组件下,其余在Father组件下。

  1. ARunRoad::ARunRoad()
  2. {
  3. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
  4. PrimaryActorTick.bCanEverTick = false;
  5. //generateBox = CreateDefaultSubobject<UBoxComponent>(TEXT("GenerateBox"));
  6. //实例化
  7. SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Father"));
  8. RunRoadRootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
  9. RootComponent = RunRoadRootComponent;
  10. RoadMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RoadMesh"));
  11. BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));
  12. SpawnPointMiddle = CreateDefaultSubobject<UArrowComponent>(TEXT("SpawnPointMiddle"));
  13. SpawnPointRight = CreateDefaultSubobject<UArrowComponent>(TEXT("SpawnPointRight"));
  14. SpawnPointLeft = CreateDefaultSubobject<UArrowComponent>(TEXT("SpawnPointLeft"));
  15. //附加顺序
  16. SceneComponent->SetupAttachment(RootComponent);
  17. RoadMesh->SetupAttachment(SceneComponent);
  18. BoxComponent->SetupAttachment(SceneComponent);
  19. SpawnPointMiddle->SetupAttachment(SceneComponent);
  20. SpawnPointRight->SetupAttachment(SceneComponent);
  21. SpawnPointLeft->SetupAttachment(SceneComponent);
  22. }

这样初步就将路结构搭建好了。后续开始写GameMode生成每一个路面。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/735675
推荐阅读
相关标签
  

闽ICP备14008679号