GameMode.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TDJGameMode.generated.h"
UCLASS(minimalapi)
class ATDJGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
ATDJGameMode();
};
GameMode.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "TDJGameMode.h"
#include "TDJPlayerController.h"
#include "TDJCharacter.h"
#include "UObject/ConstructorHelpers.h"
ATDJGameMode::ATDJGameMode()
{
// 使用我们自定义的PlayerController类
PlayerControllerClass = ATDJPlayerController::StaticClass();
// 设置默认Pawn为我们的蓝图角色
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/TopDown/Blueprints/BP_TopDownCharacter"));
if (PlayerPawnBPClass.Class != nullptr)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
// 设置默认控制器为我们的蓝图控制器
static ConstructorHelpers::FClassFinder<APlayerController> PlayerControllerBPClass(TEXT("/Game/TopDown/Blueprints/BP_TopDownPlayerController"));
if(PlayerControllerBPClass.Class != NULL)
{
PlayerControllerClass = PlayerControllerBPClass.Class;
}
}
Character.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "TDJCharacter.generated.h"
UCLASS(Blueprintable)
class ATDJCharacter : public ACharacter
{
GENERATED_BODY()
public:
ATDJCharacter();
// Called every frame.
virtual void Tick(float DeltaSeconds) override;
/** 返回摄像机组件的子对象 **/
FORCEINLINE class UCameraComponent* GetTopDownCameraComponent() const { return TopDownCameraComponent; }
/** 返回弹簧臂组件的子对象 **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
private:
/** 摄像机组件声明 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* TopDownCameraComponent;
/** 弹簧臂组件声明 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
};
Character.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "TDJCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include "Camera/CameraComponent.h"//摄像机组件
#include "Components/DecalComponent.h"//贴花组件
#include "Components/CapsuleComponent.h"//胶囊体组件
#include "GameFramework/CharacterMovementComponent.h"//角色移动组件
#include "GameFramework/PlayerController.h"//玩家控制器组件
#include "GameFramework/SpringArmComponent.h"//弹簧臂组件
#include "Materials/Material.h"
#include "Engine/World.h"
ATDJCharacter::ATDJCharacter()
{
// 设置胶囊体形状(半径:42.0,半高:96.0)
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// 摄像机视角不影响角色视角
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// 配置角色移动
GetCharacterMovement()->bOrientRotationToMovement = true; // 将旋转朝向运动设置为true
GetCharacterMovement()->RotationRate = FRotator(0.f, 640.f, 0.f);//设置旋转速率
GetCharacterMovement()->bConstrainToPlane = true;//约束到平面
GetCharacterMovement()->bSnapToPlaneAtStart = true;//开始时与平面对齐
// 初始化弹簧臂...
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->SetUsingAbsoluteRotation(true); // Don't want arm to rotate when character does
CameraBoom->TargetArmLength = 1400.f;//目标臂长度
CameraBoom->SetRelativeRotation(FRotator(-60.f, 0.f, 0.f));//相对旋转
CameraBoom->bDoCollisionTest = false; // 进行碰撞测试设置为false
// 初始化摄像机...
TopDownCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("TopDownCamera"));
TopDownCameraComponent->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
TopDownCameraComponent->bUsePawnControlRotation = false; // 使用Pawn控制旋转设置为false
// 激活Tick,以便每帧更新光标。
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
}
void ATDJCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
PlayerController.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Templates/SubclassOf.h"//模板子类组件
#include "GameFramework/PlayerController.h"//玩家控制器组件
#include "InputActionValue.h"
#include "TDJPlayerController.generated.h"
/** 创建粒子系统 */
class UNiagaraSystem;
UCLASS()
class ATDJPlayerController : public APlayerController
{
GENERATED_BODY()
public:
ATDJPlayerController();
/** Time Threshold to know if it was a short press */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
float ShortPressThreshold;
/** Niagara系统声明 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
UNiagaraSystem* FXCursor;
/** 输入映射上下文声明 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputMappingContext* DefaultMappingContext;
/** 跳跃输入操作 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* SetDestinationClickAction;
/** 跳跃输入操作(触摸) */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* SetDestinationTouchAction;
protected:
/** 移动到鼠标位置,返回True. */
uint32 bMoveToMouseCursor : 1;
virtual void SetupInputComponent() override;
// 添加映射上下文
virtual void BeginPlay();
void OnInputStarted();
void OnSetDestinationTriggered();
void OnSetDestinationReleased();
void OnTouchTriggered();
void OnTouchReleased();
private:
FVector CachedDestination;
bool bIsTouch; //是否为触摸设备
float FollowTime; // 按压时间
};
PlayerController.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "TDJPlayerController.h"
#include "GameFramework/Pawn.h"//Pawn组件
#include "Blueprint/AIBlueprintHelperLibrary.h"//AI蓝图助手库
#include "NiagaraSystem.h"//Niagara系统组件
#include "NiagaraFunctionLibrary.h"//Niagara函数库
#include "TDJCharacter.h"
#include "Engine/World.h"
#include "EnhancedInputComponent.h"//增强输入组件
#include "EnhancedInputSubsystems.h"//增强输入子系统组件
ATDJPlayerController::ATDJPlayerController()
{
bShowMouseCursor = true;
DefaultMouseCursor = EMouseCursor::Default;
CachedDestination = FVector::ZeroVector;
FollowTime = 0.f;
}
void ATDJPlayerController::BeginPlay()
{
// 调用基类
Super::BeginPlay();
//添加输入映射上下文
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
void ATDJPlayerController::SetupInputComponent()
{
// 设置游戏按键绑定
Super::SetupInputComponent();
// 设置操作绑定
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent))
{
// 设置鼠标输入事件
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Started, this, &ATDJPlayerController::OnInputStarted);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Triggered, this, &ATDJPlayerController::OnSetDestinationTriggered);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Completed, this, &ATDJPlayerController::OnSetDestinationReleased);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Canceled, this, &ATDJPlayerController::OnSetDestinationReleased);
// 设置触摸输入事件
EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Started, this, &ATDJPlayerController::OnInputStarted);
EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Triggered, this, &ATDJPlayerController::OnTouchTriggered);
EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Completed, this, &ATDJPlayerController::OnTouchReleased);
EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Canceled, this, &ATDJPlayerController::OnTouchReleased);
}
}
void ATDJPlayerController::OnInputStarted()
{
StopMovement();
}
// 按下输入时每帧触发
void ATDJPlayerController::OnSetDestinationTriggered()
{
// 输入正在被按下
FollowTime += GetWorld()->GetDeltaSeconds();
// 角色要前往的目标位置
FHitResult Hit;
bool bHitSuccessful = false;
if (bIsTouch)
{
bHitSuccessful = GetHitResultUnderFinger(ETouchIndex::Touch1, ECollisionChannel::ECC_Visibility, true, Hit);
}
else
{
bHitSuccessful = GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, true, Hit);
}
// If we hit a surface, cache the location
if (bHitSuccessful)
{
CachedDestination = Hit.Location;
}
// 移动到鼠标指针或触摸
APawn* ControlledPawn = GetPawn();
if (ControlledPawn != nullptr)
{
FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();
ControlledPawn->AddMovementInput(WorldDirection, 1.0, false);
}
}
void ATDJPlayerController::OnSetDestinationReleased()
{
// 如果是短按
if (FollowTime <= ShortPressThreshold)
{
// 角色移动到目标位置,目标位置生成粒子
UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, CachedDestination);
UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, FXCursor, CachedDestination, FRotator::ZeroRotator, FVector(1.f, 1.f, 1.f), true, true, ENCPoolMethod::None, true);
}
FollowTime = 0.f;
}
// 按下输入时每帧触发
void ATDJPlayerController::OnTouchTriggered()
{
bIsTouch = true;
OnSetDestinationTriggered();
}
void ATDJPlayerController::OnTouchReleased()
{
bIsTouch = false;
OnSetDestinationReleased();
}