引擎: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> pikaMidArr;
//存储左右的地板
UPROPERTY()
TArray> pikaLRArr;
public:
APikaqiuThirdTestGameMode();
virtual void BeginPlay() override;
//添加地板
void PikaAddFloor();
//打印测试
void PikaPirnt(FString piksStr);
TSubclassOf pikaNewFloor;
FTransform pikaNextTransforms;
//获取随机的地板
TSubclassOf PikaRandomInputFloor();
//将UI界面加载到屏幕上
void PikaUIAddToScreen();
//UI实例变量
UUserWidget *PikaMainUI;
TSubclassOf 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 PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
//初始化容器
pikaMidArr.Empty();
pikaLRArr.Empty();
//获取蓝图中的直线地板
TSubclassOf pikaFloorBP01 = LoadClass(NULL , TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP01.PikaFloorBP01_C'"));
pikaMidArr.Add(pikaFloorBP01);
TSubclassOf pikaFloorBP02 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP02.PikaFloorBP02_C'"));
pikaMidArr.Add(pikaFloorBP02);
TSubclassOf pikaFloorBP03 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP03.PikaFloorBP03_C'"));
pikaMidArr.Add(pikaFloorBP03);
//获取蓝图中的上下地板
TSubclassOf pikaFloorBP04 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP04.PikaFloorBP04_C'"));
pikaMidArr.Add(pikaFloorBP04);
TSubclassOf pikaFloorBP05 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP05.PikaFloorBP05_C'"));
pikaMidArr.Add(pikaFloorBP05);
//获取蓝图中的左右地板
TSubclassOf pikaFloorBP06 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP06.PikaFloorBP06_C'"));
pikaLRArr.Add(pikaFloorBP06);
TSubclassOf pikaFloorBP07 = LoadClass(NULL, TEXT("Blueprint'/Game/Floor/BP/PikaFloorBP07.PikaFloorBP07_C'"));
pikaLRArr.Add(pikaFloorBP07);
//获取自定义的UI类实例
static ConstructorHelpers::FClassFinder 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(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 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(GetWorld(), PikaUIMainInstance);
if (PikaMainUI)
{
PikaMainUI->AddToViewport();
UPikaMainUI *PikaMain = Cast(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(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(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(GetWorld()->GetAuthGameMode());
//获取PikaqiuThirdTestCharacter的实例
APikaqiuThirdTestCharacter *PikaCharacter = Cast(GetWorld()->GetFirstPlayerController()->GetPawn());
if (PikaCharacter && pikaGameMode)
{
//计算角色移动距离
//GetMovementComponent()需要GameFramework/CharacterMovementComponent.h头文件
int32 TempDistance = (PikaGetVectorLeng(PikaCharacter->GetMovementComponent()->Velocity))*0.03f;
PikaDistance += TempDistance;
//更新到UI界面上
UPikaMainUI *PikaMain = Cast(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 PikaCoinActor;
//金币数组,存储已经生成的金币,用于在销毁地板时,一同销毁金币
TArray PikaCoinArr;
//类型枚举
UPROPERTY(EditDefaultsOnly, Category = "PikaFloorType")
TEnumAsByte<: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(TEXT("pikaqiuSecene"));
pikaRootFCompoent = CreateDefaultSubobject(TEXT("pikaqiuRoot"));
pikaTurnComponent = CreateDefaultSubobject(TEXT("pikaTurnBox"));
pikaBoxMesh = CreateDefaultSubobject(TEXT("pikaBoxMesh"));
//碰撞
pikaBoxCompoent = CreateDefaultSubobject(TEXT("pikaCollBox"));
//标记地板生成的位置
pikaSpawnPoint = CreateDefaultSubobject(TEXT("pikaSpanwPoint"));
//标记左右金币生成的位置
pikaSpawnPointR = CreateDefaultSubobject(TEXT("pikaSpanwPointR"));
pikaSpawnPointL = CreateDefaultSubobject(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 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(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
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(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(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(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(TEXT("pikaCoinMesh"));
pikaMeshComponent = CreateDefaultSubobject(TEXT("pikaBoxComponents"));
pikaRotatingMovement = CreateDefaultSubobject(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(GetWorld()->GetAuthGameMode());
//获取GameState的实例
APikaGameStateBase *PikaGameState = Cast(GetWorld()->GetGameState());
if (pikaGameMode && PikaGameState)
{
//检测到金币的碰撞后,金币数加1并更新到屏幕上
PikaGameState->PikaGlod++;
UPikaMainUI *PikaMain = Cast(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