引擎:UE4 4.18.3
代码结构
运行图
PikaqiuThirdTestGameMode.h
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "PikaqiuThirdTestGameMode.generated.h" UCLASS(minimalapi) class APikaqiuThirdTestGameMode : public AGameModeBase { GENERATED_BODY() //存储直线的地板 UPROPERTY() TArray<TSubclassOf<class AActor>> pikaMidArr; //存储左右的地板 UPROPERTY() TArray<TSubclassOf<class AActor>> pikaLRArr; public: APikaqiuThirdTestGameMode(); virtual void BeginPlay() override; //添加地板 void PikaAddFloor(); //打印测试 void PikaPirnt(FString piksStr); TSubclassOf<AActor> pikaNewFloor; FTransform pikaNextTransforms; //获取随机的地板 TSubclassOf<AActor> PikaRandomInputFloor(); //将UI界面加载到屏幕上 void PikaUIAddToScreen(); //UI实例变量 UUserWidget *PikaMainUI; TSubclassOf<UUserWidget> PikaUIMainInstance; //确定金币的生成方向X轴或Y轴 //1:X轴负方向 2:Y轴负方向 3:X轴正方向 4:Y轴正方向 //LEFT -1 RIGHT +1 int32 IsX; };
PikaqiuThirdTestGameMode.cpp
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PikaqiuThirdTestGameMode.h" #include "PikaqiuThirdTestCharacter.h" #include "UObject/ConstructorHelpers.h" #include "PikaFloor.h" #include "PikaMainUI.h" #include "Engine.h" #include "PikaGameStateBase.h" APikaqiuThirdTestGameMode::APikaqiuThirdTestGameMode() { // set default pawn class to our Blueprinted character static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter")); if (PlayerPawnBPClass.Class != NULL) { DefaultPawnClass = PlayerPawnBPClass.Class; } //初始化容器 pikaMidArr.Empty(); pikaLRArr.Empty(); //获取蓝图中的直线地板 TSubclassOf<AActor> pikaFloorBP01 = LoadClass<AActor>(NULL , TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP01.PikaFloorBP01_C'")); pikaMidArr.Add(pikaFloorBP01); TSubclassOf<AActor> pikaFloorBP02 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP02.PikaFloorBP02_C'")); pikaMidArr.Add(pikaFloorBP02); TSubclassOf<AActor> pikaFloorBP03 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP03.PikaFloorBP03_C'")); pikaMidArr.Add(pikaFloorBP03); //获取蓝图中的上下地板 TSubclassOf<AActor> pikaFloorBP04 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP04.PikaFloorBP04_C'")); pikaMidArr.Add(pikaFloorBP04); TSubclassOf<AActor> pikaFloorBP05 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP05.PikaFloorBP05_C'")); pikaMidArr.Add(pikaFloorBP05); //获取蓝图中的左右地板 TSubclassOf<AActor> pikaFloorBP06 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP06.PikaFloorBP06_C'")); pikaLRArr.Add(pikaFloorBP06); TSubclassOf<AActor> pikaFloorBP07 = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP07.PikaFloorBP07_C'")); pikaLRArr.Add(pikaFloorBP07); //获取自定义的UI类实例 static ConstructorHelpers::FClassFinder<UUserWidget> PikaWidget(TEXT("/Game/UMG/PikaMainUI")); PikaUIMainInstance = PikaWidget.Class; //加载我们的GameState GameStateClass = APikaGameStateBase::StaticClass(); IsX = 1; } void APikaqiuThirdTestGameMode::BeginPlay() { Super::BeginPlay(); if (GetWorld()) { for (int32 i=0 ; i<10 ; i++) { PikaAddFloor(); } } //将UI界面加载到屏幕上 PikaUIAddToScreen(); } void APikaqiuThirdTestGameMode::PikaAddFloor() { pikaNewFloor = PikaRandomInputFloor(); if (pikaNewFloor != NULL) { FVector const pikaLoction = pikaNextTransforms.GetLocation(); FRotator pikaRotation(pikaNextTransforms.Rotator()); //在场景中放入地板 APikaFloor *pikaFloor = GetWorld()->SpawnActor<APikaFloor>(pikaNewFloor, pikaLoction, pikaRotation); //记录当前地板的位置,做为下一个生成的地板的初始位置 pikaNextTransforms = pikaFloor->PikaGetAttachToTransform(); //PikaPirnt(pikaNextTransforms.ToString()); } } void APikaqiuThirdTestGameMode::PikaPirnt(FString piksStr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, piksStr); } } //获取随机的地板 TSubclassOf<AActor> APikaqiuThirdTestGameMode::PikaRandomInputFloor() { //return pikaMidArr[2]; int32 pikaRandom = FMath::RandRange(1, 100); //生成直线地板(包括上下地板)的概率 int32 pikaProbMid = 60; if (pikaRandom <= pikaProbMid) { //生成直线地板 int32 pikaSumMidArr = pikaMidArr.Num(); if (pikaSumMidArr) { //组数开始的下标为0 int32 pikaIndexMid = FMath::RandRange(0, pikaSumMidArr - 1); return pikaMidArr[pikaIndexMid]; } } else { //生成左右地板 int32 pikaSumLRArr = pikaLRArr.Num(); if (pikaSumLRArr) { int32 pikaIndexLR = FMath::RandRange(0, pikaSumLRArr - 1); return pikaLRArr[pikaIndexLR]; } } return NULL; } //将UI界面加载到屏幕上PikaMainUI void APikaqiuThirdTestGameMode::PikaUIAddToScreen() { if (PikaUIMainInstance) { if (GetWorld()) { PikaMainUI = CreateWidget<UUserWidget>(GetWorld(), PikaUIMainInstance); if (PikaMainUI) { PikaMainUI->AddToViewport(); UPikaMainUI *PikaMain = Cast<UPikaMainUI>(PikaMainUI); if (PikaMain) { //初始化金币数和步数 PikaMain->pikaCoinNum = FText::FromString(TEXT("0")); PikaMain->pikaCharacterDistance = FText::FromString(TEXT("0")); } } } } }
PikaqiuThirdTestCharacter.h
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "PikaqiuThirdTestCharacter.generated.h" UCLASS(config = Game) class APikaqiuThirdTestCharacter : public ACharacter { GENERATED_BODY() /** Camera boom positioning the camera behind the character */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) class USpringArmComponent* CameraBoom; /** Follow camera */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) class UCameraComponent* FollowCamera; public: APikaqiuThirdTestCharacter(); /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera) float BaseTurnRate; /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera) float BaseLookUpRate; protected: /** Resets HMD orientation in VR. */ void OnResetVR(); /** Called for forwards/backward input */ void MoveForward(float Value); /** Called for side to side input */ void MoveRight(float Value); /** * Called via input to turn at a given rate. * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate */ void TurnAtRate(float Rate); /** * Called via input to turn look up/down at a given rate. * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate */ void LookUpAtRate(float Rate); /** Handler for when a touch input begins. */ void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location); /** Handler for when a touch input stops. */ void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location); protected: // APawn interface virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; // End of APawn interface public: /** Returns CameraBoom subobject **/ FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; } /** Returns FollowCamera subobject **/ FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; } /********************************系统生成的代码分割线**********************************/ private: //右手状态 bool rightState; //左手状态 bool leftState; //能否旋转 bool canTrun; //死亡状态 bool deathState; //导向旋转 FRotator desireRotation; protected: //右转身函数 void RightTurn(); //左转身函数 void LeftTurn(); //按键响应函数 void PikaSetupPlayerInputComponent(class UInputComponent *InputComponent); public: //模拟的构造函数 void PikaStructure(); //重载BeginPlay和Tick函数 virtual void BeginPlay() override; virtual void Tick(float DeltaSeconds) override; //自动向前跑 void KeepMoving(); FVector JudgeRAndL(FRotator pikaRotation); FVector AddInputMoveForworld(); void PikaPirnt(FString pikaStr); FRotator PikaCombinRotation(FRotator rotation1, FRotator rotation2); //设置角色的转向 void PikaCharacterTurn(); };
PikaqiuThirdTestCharacter.cpp
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PikaqiuThirdTestCharacter.h" #include "HeadMountedDisplayFunctionLibrary.h" #include "Camera/CameraComponent.h" #include "Components/CapsuleComponent.h" #include "Components/InputComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/Controller.h" #include "GameFramework/SpringArmComponent.h" #include "Engine.h" ////////////////////////////////////////////////////////////////////////// // APikaqiuThirdTestCharacter APikaqiuThirdTestCharacter::APikaqiuThirdTestCharacter() { // Set size for collision capsule GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); // set our turn rates for input BaseTurnRate = 45.f; BaseLookUpRate = 45.f; // Don't rotate when the controller rotates. Let that just affect the camera. bUseControllerRotationPitch = false; bUseControllerRotationYaw = false; bUseControllerRotationRoll = false; // Configure character movement GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input... GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate GetCharacterMovement()->JumpZVelocity = 600.f; GetCharacterMovement()->AirControl = 0.2f; // Create a camera boom (pulls in towards the player if there is a collision) CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); CameraBoom->SetupAttachment(RootComponent); CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller // Create a follow camera FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera")); FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++) PikaStructure(); } ////////////////////////////////////////////////////////////////////////// // Input void APikaqiuThirdTestCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) { // Set up gameplay key bindings check(PlayerInputComponent); PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); PlayerInputComponent->BindAxis("MoveForward", this, &APikaqiuThirdTestCharacter::MoveForward); PlayerInputComponent->BindAxis("MoveRight", this, &APikaqiuThirdTestCharacter::MoveRight); // We have 2 versions of the rotation bindings to handle different kinds of devices differently // "turn" handles devices that provide an absolute delta, such as a mouse. // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); PlayerInputComponent->BindAxis("TurnRate", this, &APikaqiuThirdTestCharacter::TurnAtRate); PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); PlayerInputComponent->BindAxis("LookUpRate", this, &APikaqiuThirdTestCharacter::LookUpAtRate); // handle touch devices PlayerInputComponent->BindTouch(IE_Pressed, this, &APikaqiuThirdTestCharacter::TouchStarted); PlayerInputComponent->BindTouch(IE_Released, this, &APikaqiuThirdTestCharacter::TouchStopped); // VR headset functionality PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &APikaqiuThirdTestCharacter::OnResetVR); //皮卡丘按键响应 //PikaSetupPlayerInputComponent(PlayerInputComponent); } void APikaqiuThirdTestCharacter::OnResetVR() { UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition(); } void APikaqiuThirdTestCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location) { Jump(); } void APikaqiuThirdTestCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location) { StopJumping(); } void APikaqiuThirdTestCharacter::TurnAtRate(float Rate) { // calculate delta for this frame from the rate information AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds()); } void APikaqiuThirdTestCharacter::LookUpAtRate(float Rate) { // calculate delta for this frame from the rate information AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds()); } void APikaqiuThirdTestCharacter::MoveForward(float Value) { if ((Controller != NULL) && (Value != 0.0f)) { // find out which way is forward const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get forward vector const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); AddMovementInput(Direction, Value); } } void APikaqiuThirdTestCharacter::MoveRight(float Value) { if ((Controller != NULL) && (Value != 0.0f)) { // find out which way is right const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get right vector const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); // add movement in that direction AddMovementInput(Direction, Value); } } /********************************系统生成的代码分割线**********************************/ //模拟的构造函数 void APikaqiuThirdTestCharacter::PikaStructure() { //初始化基础变量 //右手状态 rightState = false; //左手状态 leftState = false; //能否旋转 canTrun = true; //死亡状态 deathState = false; //导向旋转 desireRotation = FRotator(0); } //重载BeginPlay和Tick函数 void APikaqiuThirdTestCharacter::BeginPlay() { Super::BeginPlay(); } void APikaqiuThirdTestCharacter::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); if (deathState) { } else { //PikaCharacterTurn(); KeepMoving(); } } //自动向前跑 void APikaqiuThirdTestCharacter::KeepMoving() { AddMovementInput(JudgeRAndL(desireRotation), 1); } FVector APikaqiuThirdTestCharacter::JudgeRAndL(FRotator pikaRotation) { if (rightState) { rightState = false; return AddInputMoveForworld(); } else if (leftState) { leftState = false; return AddInputMoveForworld(); } else { return AddInputMoveForworld(); } } FVector APikaqiuThirdTestCharacter::AddInputMoveForworld() { //获取角色的旋转值 const FRotator pikaRotation = Controller->GetControlRotation(); //保证只有Yaw变化 const FRotator yawRotation(0, pikaRotation.Yaw, 0); const FVector desiron = FRotationMatrix(yawRotation).GetUnitAxis(EAxis::X); return desiron; } void APikaqiuThirdTestCharacter::PikaPirnt(FString pikaStr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Red, pikaStr); } } //按键响应 void APikaqiuThirdTestCharacter::PikaSetupPlayerInputComponent(class UInputComponent *InputComponent) { //键盘按键 InputComponent->BindAction("pikaRight", IE_Pressed, this, &APikaqiuThirdTestCharacter::RightTurn); InputComponent->BindAction("pikaLeft", IE_Pressed, this, &APikaqiuThirdTestCharacter::LeftTurn); } FRotator APikaqiuThirdTestCharacter::PikaCombinRotation(FRotator rotation1, FRotator rotation2) { FQuat aQuat = FQuat(rotation1); FQuat bQuat = FQuat(rotation2); return FRotator(aQuat * bQuat); } //右转身函数 void APikaqiuThirdTestCharacter::RightTurn() { if (canTrun) { //顺时针旋转90度 FRotator pikaRotation = FRotator(0, 90, 0); desireRotation = PikaCombinRotation(desireRotation, pikaRotation); rightState = true; } } //左转身函数 void APikaqiuThirdTestCharacter::LeftTurn() { if (canTrun) { //逆时针旋转90度 FRotator pikaRotation = FRotator(0, -90, 0); desireRotation = PikaCombinRotation(desireRotation, pikaRotation); leftState = true; } } // 设置角色的转向 void APikaqiuThirdTestCharacter::PikaCharacterTurn() { GetController()->SetControlRotation(FMath::RInterpTo(GetControlRotation(), desireRotation, GetWorld()->GetRealTimeSeconds(), 10)); }
PikaqiuThirdTest.Build.cs
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class PikaqiuThirdTest : ModuleRules { public PikaqiuThirdTest(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; //模块加入 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" , "UMG"}); } }
PikaMainUI.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "PikaMainUI.generated.h" /** * */ UCLASS() class PIKAQIUTHIRDTEST_API UPikaMainUI : public UUserWidget { GENERATED_BODY() public: //主界面UI上记录金币数和步数的变量 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = UI) FText pikaCoinNum; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = UI) FText pikaCharacterDistance; };
PikaGameStateBase.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/GameStateBase.h" #include "PikaGameStateBase.generated.h" /** * */ UCLASS() class PIKAQIUTHIRDTEST_API APikaGameStateBase : public AGameStateBase { GENERATED_BODY() public: APikaGameStateBase(); //记录用户的金币数和步数 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = UI) int32 PikaGlod; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = UI) int32 PikaDistance; bool PikaStopLoopForCharacterDistance; virtual void BeginPlay() override; //计算角色移动的距离 void PikaAddDistance(); //计算三维空间的距离,即角色移动向量的模 float PikaGetVectorLeng(FVector Vctor); FTimerHandle PikaHandle; };
PikaGameStateBase.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "PikaGameStateBase.h" #include "PikaqiuThirdTestCharacter.h" #include "PikaqiuThirdTestGameMode.h" #include "PikaMainUI.h" #include "GameFramework/CharacterMovementComponent.h" APikaGameStateBase::APikaGameStateBase() { //金币 PikaGlod = 0; //角色距离 PikaDistance = 0; PikaStopLoopForCharacterDistance = true; } void APikaGameStateBase::BeginPlay() { Super::BeginPlay(); GetWorldTimerManager().SetTimer(PikaHandle, this, &APikaGameStateBase::PikaAddDistance, 0.03f, true); } //计算角色移动的距离 void APikaGameStateBase::PikaAddDistance() { if (PikaHandle.IsValid()) { //GetWorldTimerManager().ClearTimer(PikaHandle); } if (PikaStopLoopForCharacterDistance) { if (GetWorld()) { //获取GameMode的实例 APikaqiuThirdTestGameMode *pikaGameMode = Cast<APikaqiuThirdTestGameMode>(GetWorld()->GetAuthGameMode()); //获取PikaqiuThirdTestCharacter的实例 APikaqiuThirdTestCharacter *PikaCharacter = Cast<APikaqiuThirdTestCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()); if (PikaCharacter && pikaGameMode) { //计算角色移动距离 //GetMovementComponent()需要GameFramework/CharacterMovementComponent.h头文件 int32 TempDistance = (PikaGetVectorLeng(PikaCharacter->GetMovementComponent()->Velocity))*0.03f; PikaDistance += TempDistance; //更新到UI界面上 UPikaMainUI *PikaMain = Cast<UPikaMainUI>(pikaGameMode->PikaMainUI); if (PikaMain) { PikaMain->pikaCharacterDistance = FText::FromString(FString::FromInt(PikaDistance)); } } //设置计算一次距离的时间 GetWorldTimerManager().SetTimer(PikaHandle, this, &APikaGameStateBase::PikaAddDistance, 0.03f, true); } } } //计算三维空间的距离,即角色移动向量的模 float APikaGameStateBase::PikaGetVectorLeng(FVector Vctor) { return sqrt(Vctor.X*Vctor.X + Vctor.Y*Vctor.Y + Vctor.Z*Vctor.Z); }
PikaFloor.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Components/BoxComponent.h" #include "Components/ArrowComponent.h" #include "PikaFloor.generated.h" //Floor类型 //暴露给蓝图后,在蓝图中设置好本蓝图的类型,再在代码中根据当前类型来决定金币的生成规则 UENUM() namespace PikaFloorType { enum PikaType { StraightFloor,//直线地板 UpFloor,//往上的地板 DownFloor,//往下的地板 LeftFloor,//左转的地板 RightFloor,//右转的地板 }; } UCLASS() class PIKAQIUTHIRDTEST_API APikaFloor : public AActor { GENERATED_BODY() //场景组件 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) USceneComponent *pikaSeceneComponent; //根组件 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) USceneComponent *pikaRootFCompoent; //碰撞 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UBoxComponent *pikaBoxCompoent; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UBoxComponent *pikaTurnComponent; //模型 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent *pikaBoxMesh; //标记地板生成的位置 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UArrowComponent *pikaSpawnPoint; //标记左右金币生成的位置 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UArrowComponent *pikaSpawnPointR; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaqiu", meta = (AllowPrivateAccess = "true")) UArrowComponent *pikaSpawnPointL; //金币Actor,生成金币时用 TSubclassOf<AActor> PikaCoinActor; //金币数组,存储已经生成的金币,用于在销毁地板时,一同销毁金币 TArray<AActor*> PikaCoinArr; //类型枚举 UPROPERTY(EditDefaultsOnly, Category = "PikaFloorType") TEnumAsByte<PikaFloorType::PikaType> PikFloorTypeBP; public: // Sets default values for this actor's properties APikaFloor(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; //获取当前Actor(地板)的位置信息 FTransform PikaGetAttachToTransform(); //地板里pikaBoxCompoent碰撞体的碰撞函数,使用前需要先进行绑定 UFUNCTION() void PikaOverlap(UPrimitiveComponent *pikaOverlapppedComponent , AActor *pikaOtherActor , UPrimitiveComponent *pikaOtherComp , int32 pikaOtherBodyIndex , bool pikaFromSweepBool , const FHitResult & pikaSweepResult); //打印测试 void PikaPrint(FString piksStr); //计时器 FTimerHandle pikaTimer; //销毁对象实例 void PikaDestroy(); //在地板随机放置金币 void PikaGetCoinForFloor(); //金币生成函数 void PikaSpawnCoinArr(UArrowComponent *PikaSpawnPos , bool IsMid); };
PikaFloor.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "PikaFloor.h" #include "Components/StaticMeshComponent.h" #include "Engine.h" #include "PikaqiuThirdTestCharacter.h" #include "PikaqiuThirdTestGameMode.h" #include "UnrealMathUtility.h" // Sets default values APikaFloor::APikaFloor() { // 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; //组件加载 //场景组件 pikaSeceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("pikaqiuSecene")); pikaRootFCompoent = CreateDefaultSubobject<USceneComponent>(TEXT("pikaqiuRoot")); pikaTurnComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("pikaTurnBox")); pikaBoxMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("pikaBoxMesh")); //碰撞 pikaBoxCompoent = CreateDefaultSubobject<UBoxComponent>(TEXT("pikaCollBox")); //标记地板生成的位置 pikaSpawnPoint = CreateDefaultSubobject<UArrowComponent>(TEXT("pikaSpanwPoint")); //标记左右金币生成的位置 pikaSpawnPointR = CreateDefaultSubobject<UArrowComponent>(TEXT("pikaSpanwPointR")); pikaSpawnPointL = CreateDefaultSubobject<UArrowComponent>(TEXT("pikaSpanwPointL")); //将本组件的根组件设置为场景组件pikaSeceneComponent RootComponent = pikaSeceneComponent; //绑定 pikaRootFCompoent->AttachToComponent(pikaSeceneComponent, FAttachmentTransformRules::KeepRelativeTransform); pikaSpawnPoint->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); pikaSpawnPointR->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); pikaSpawnPointL->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); pikaBoxCompoent->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); pikaTurnComponent->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); pikaBoxMesh->AttachToComponent(pikaRootFCompoent, FAttachmentTransformRules::KeepRelativeTransform); //获取金币蓝图的Actor static ConstructorHelpers::FClassFinder<AActor> PikaCoinBP(TEXT("/Game/Coin/BP/PikaCoinBP01")); PikaCoinActor = PikaCoinBP.Class; } // Called when the game starts or when spawned void APikaFloor::BeginPlay() { Super::BeginPlay(); //绑定pikaBoxCompoent的碰撞函数 //该函数放在构造函数中时,有可能出现UBoxComponent类没有创建完成,就执行绑定,从而导致绑定失败的情况 //OnComponentBeginOverlap.AddUniqueDynamic和OnComponentEndOverlap.AddUniqueDynamic分别为碰到碰撞体和离开碰撞体时调用的事件 pikaBoxCompoent->OnComponentBeginOverlap.AddUniqueDynamic(this, &APikaFloor::PikaOverlap); //三渲二 //pikaBoxMesh->SetRenderCustomDepth(true); //获取gameMode类的实例 APikaqiuThirdTestGameMode *PikaGameMode = Cast<APikaqiuThirdTestGameMode>(GetWorld()->GetAuthGameMode()); //如果不是左右转弯的地板,则生成金币 if (PikFloorTypeBP == PikaFloorType::LeftFloor) { PikaGameMode->IsX -= 1; } else if (PikFloorTypeBP == PikaFloorType::RightFloor) { PikaGameMode->IsX += 1; } else if (PikFloorTypeBP == PikaFloorType::UpFloor || PikFloorTypeBP == PikaFloorType::DownFloor) { } else { PikaGetCoinForFloor(); } if (PikaGameMode->IsX > 4) PikaGameMode->IsX = 1; if (PikaGameMode->IsX < 1) PikaGameMode->IsX = 4; } // Called every frame void APikaFloor::Tick(float DeltaTime) { Super::Tick(DeltaTime); } FTransform APikaFloor::PikaGetAttachToTransform() { FTransform pikaTransform; //获取当前组件的Location和Rotation pikaTransform.SetLocation(pikaSpawnPoint->GetComponentToWorld().GetLocation()); pikaTransform.SetRotation(pikaSpawnPoint->GetComponentQuat()); return pikaTransform; } void APikaFloor::PikaPrint(FString piksStr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 6.0f, FColor::Red, piksStr); } } //地板里pikaBoxCompoent碰撞体的碰撞函数,使用前需要先进行绑定 void APikaFloor::PikaOverlap(UPrimitiveComponent *pikaOverlapppedComponent, AActor *pikaOtherActor, UPrimitiveComponent *pikaOtherComp, int32 pikaOtherBodyIndex, bool pikaFromSweepBool, const FHitResult & pikaSweepResult) { //检测碰撞体碰撞到的对象是否是玩家角色 if (pikaOtherActor->IsA(APikaqiuThirdTestCharacter::StaticClass())) { if (GetWorld()) { //获取GameMode的实例 APikaqiuThirdTestGameMode *pikaGameMode = Cast<APikaqiuThirdTestGameMode>(GetWorld()->GetAuthGameMode()); if (pikaGameMode) { pikaGameMode->PikaAddFloor(); //延时5秒执行销毁地板 if (pikaTimer.IsValid()) { GetWorldTimerManager().ClearTimer(pikaTimer); } GetWorldTimerManager().SetTimer(pikaTimer , this , &APikaFloor::PikaDestroy, 5.0f , true); } } } } //销毁对象实例 void APikaFloor::PikaDestroy() { //销毁金币 if (PikaCoinArr.Num() > 0) { for (AActor *PikaCoinDestory:PikaCoinArr) { if (PikaCoinDestory) { PikaCoinDestory->Destroy(true); } } } //销毁地板 Destroy(true); } //在地板随机放置金币 void APikaFloor::PikaGetCoinForFloor() { int32 RandomNum = FMath::FRandRange(0 , 2); switch (RandomNum) { case 0://在右边生成金币 if (pikaSpawnPointR) { PikaSpawnCoinArr(pikaSpawnPointR, false); } break; case 1://在左边生成金币 if (pikaSpawnPointL) { PikaSpawnCoinArr(pikaSpawnPointL, false); } break; default: break; } /*switch (RandomNum) { case 0://不生成金币 break; case 1://在左边生成金币 if (pikaSpawnPointL) { PikaSpawnCoinArr(pikaSpawnPointL , false); } break; case 2://在中间生成金币 //PikaSpawnCoinArr(pikaSpawnPointL, true); break; case 3://在右边生成金币 if (pikaSpawnPointR) { PikaSpawnCoinArr(pikaSpawnPointR , false); } break; default: break; }*/ } //金币生成函数 void APikaFloor::PikaSpawnCoinArr(UArrowComponent *PikaSpawnPos , bool IsMid) { PikaCoinArr.Empty(); if (PikaCoinActor && GetWorld()) { FVector PikaLocation = PikaSpawnPos->GetComponentLocation(); FRotator PikaRotator = PikaSpawnPos->GetComponentRotation(); if (IsMid) { //PikaLocation.Y += 340; } FVector PikaTempLocation; for (int32 i=0 ; i<=15 ; i++) { //每隔一段距离生成一个金币 PikaTempLocation = PikaLocation; //获取gameMode类的实例 APikaqiuThirdTestGameMode *PikaGameMode = Cast<APikaqiuThirdTestGameMode>(GetWorld()->GetAuthGameMode()); if (1 == PikaGameMode->IsX) { PikaTempLocation.X -= (i * 120); } else if (2 == PikaGameMode->IsX) { PikaTempLocation.Y += (i * 120); } else if (3 == PikaGameMode->IsX) { PikaTempLocation.X += (i * 120); } else if (4 == PikaGameMode->IsX) { PikaTempLocation.Y -= (i * 120); } else { PikaTempLocation.X -= (i * 120); } /*if (PikFloorTypeBP == PikaFloorType::UpFloor) { PikaTempLocation.Z -= (i * 45); } else if (PikFloorTypeBP == PikaFloorType::DownFloor) { PikaTempLocation.Z += (i * 60); }*/ AActor *PikaCoinBPObj = GetWorld()->SpawnActor<AActor>(PikaCoinActor, PikaTempLocation, PikaRotator); if (PikaCoinBPObj) { //存储已经生成的金币,当地板被销毁时,金币也一同销毁 PikaCoinArr.Add(PikaCoinBPObj); } } } }
PikaCoin.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Components/BoxComponent.h" #include "GameFramework/RotatingMovementComponent.h" #include "PikaCoin.generated.h" UCLASS() class PIKAQIUTHIRDTEST_API APikaCoin : public AActor { GENERATED_BODY() UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaCoin", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent *pikaCoinMesh; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaCoin", meta = (AllowPrivateAccess = "true")) UBoxComponent *pikaMeshComponent; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "pikaCoin", meta = (AllowPrivateAccess = "true")) URotatingMovementComponent *pikaRotatingMovement; //声音播放 UPROPERTY(EditDefaultsOnly, Category = "PikaSound") USoundBase *PikaEatCoinSound; public: // Sets default values for this actor's properties APikaCoin(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; //金币的碰撞函数 UFUNCTION() void PikaCharacterOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult); //打印测试 void PikaPirnt(FString piksStr); };
PikaCoin.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "PikaCoin.h" #include "PikaqiuThirdTestCharacter.h" #include "PikaqiuThirdTestGameMode.h" #include "Engine.h" #include "PikaGameStateBase.h" #include "PikaMainUI.h" // Sets default values APikaCoin::APikaCoin() { // 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; pikaCoinMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("pikaCoinMesh")); pikaMeshComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("pikaBoxComponents")); pikaRotatingMovement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("pikaRotatingMovement")); RootComponent = pikaMeshComponent; pikaCoinMesh->SetupAttachment(pikaMeshComponent); } // Called when the game starts or when spawned void APikaCoin::BeginPlay() { Super::BeginPlay(); //碰撞方式要选择OnComponentBeginOverlap,OnComponentHit方式的碰撞会产生阻力,使碰撞对象停顿 pikaMeshComponent->OnComponentBeginOverlap.AddDynamic(this, &APikaCoin::PikaCharacterOverlap); } // Called every frame void APikaCoin::Tick(float DeltaTime) { Super::Tick(DeltaTime); } //金币的碰撞函数 void APikaCoin::PikaCharacterOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult) { if (OtherActor->IsA(APikaqiuThirdTestCharacter::StaticClass())) { if (GetWorld()) { //获取GameMode的实例 APikaqiuThirdTestGameMode *pikaGameMode = Cast<APikaqiuThirdTestGameMode>(GetWorld()->GetAuthGameMode()); //获取GameState的实例 APikaGameStateBase *PikaGameState = Cast<APikaGameStateBase>(GetWorld()->GetGameState()); if (pikaGameMode && PikaGameState) { //检测到金币的碰撞后,金币数加1并更新到屏幕上 PikaGameState->PikaGlod++; UPikaMainUI *PikaMain = Cast<UPikaMainUI>(pikaGameMode->PikaMainUI); if (PikaMain) { PikaMain->pikaCoinNum = FText::FromString(FString::FromInt(PikaGameState->PikaGlod)); } } //当吃掉金币后发出金币的声音 if (PikaEatCoinSound) { UGameplayStatics::PlaySoundAtLocation(GetWorld(), PikaEatCoinSound, GetActorLocation()); } } Destroy(true); } } void APikaCoin::PikaPirnt(FString piksStr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 6.0f, FColor::Red, piksStr); } }
1