Hello.
I’m very new to UE4 C++ programming and stuck at implementing character control bindings with PlayerController class.
For learning, and realizing loose coupling, I want to implement control bindings in Controller Class.
(I’m supposing API connection like: Controller ⇔ Character Control Interface class, or Character Base class ⇔ individual Character classes. through this pattern, I think I can avoid implementing control bindings in each Character class. if this design pattern/concept is weird in UE4 C++ programming/game development, please tell me common pattern),
How can I do that?
Here’s my code.
FPSSandBoxControllerBase.cpp is a main section of this topic.
FPSsandBoxControllerBase.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include <Runtime/Engine/Classes/Camera/CameraComponent.h>
#include "FPSsandBoxControllerBase.generated.h"
/**
*
*/
UCLASS()
class FPSSANDBOX_API AFPSsandBoxControllerBase : public APlayerController
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
APawn* ControlledPawn;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
float BaseTurnRate = 25.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
float BaseLookUpRate = 25.0f;
public:
AFPSsandBoxControllerBase();
virtual void OnPossess(APawn* InPawn) override;
virtual void SetupInputComponent() override;
virtual void AddPitchInput(float) override;
virtual void AddYawInput(float) override;
void MoveForward(float);
void MoveRight(float);
void Attack();
};
FPSsandBoxControllerBase.cpp
#include "FPSsandBoxControllerBase.h"
AFPSsandBoxControllerBase::AFPSsandBoxControllerBase()
{
}
void AFPSsandBoxControllerBase::OnPossess(APawn* InPawn)
{
ControlledPawn = InPawn;
}
void AFPSsandBoxControllerBase::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAxis("MoveForward", this, &AFPSsandBoxControllerBase::MoveForward);
InputComponent->BindAxis("MoveRight", this, &AFPSsandBoxControllerBase::MoveRight);
InputComponent->BindAction("Attack", IE_Pressed, this, &AFPSsandBoxControllerBase::Attack);
InputComponent->BindAxis("LookUp", this, &AFPSsandBoxControllerBase::AddPitchInput);
InputComponent->BindAxis("Turn", this, &AFPSsandBoxControllerBase::AddYawInput);
//InputComponent->BindAxis("TurnRate", this, &AFPSCodeReadingCharacter::TurnAtRate);
//InputComponent->BindAxis("LookUpRate", this, &AFPSCodeReadingCharacter::LookUpAtRate);
}
void AFPSsandBoxControllerBase::MoveForward(float Value)
{
if (ControlledPawn != NULL && Value != 0.0f)
{
// with this code, character does not move forward
ControlledPawn->AddMovementInput(PlayerCameraManager->GetActorForwardVector(), Value);
// code below not worked either
//auto Rotation = GetControlRotation();
//const auto Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);
//ControlledPawn->AddMovementInput(Direction, Value);
}
}
void AFPSsandBoxControllerBase::MoveRight(float Value)
{
if (ControlledPawn != NULL && Value != 0.0f)
{
//ControlledPawn->AddMovementInput(PlayerCameraManager->GetActorRightVector(), Value);
}
}
void AFPSsandBoxControllerBase::Attack()
{
}
void AFPSsandBoxControllerBase::AddPitchInput(float Value)
{
APlayerController::AddPitchInput(Value);
}
void AFPSsandBoxControllerBase::AddYawInput(float Value)
{
APlayerController::AddYawInput(Value);
}
FPSsandBoxCharacterBase.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "FPSSandBoxCharacterBase.generated.h"
UCLASS()
class FPSSANDBOX_API AFPSSandBoxCharacterBase : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AFPSSandBoxCharacterBase();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
FPSSandBoxCharacterBase.cpp
#include "FPSSandBoxCharacterBase.h"
// Sets default values
AFPSSandBoxCharacterBase::AFPSSandBoxCharacterBase()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
//PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AFPSSandBoxCharacterBase::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AFPSSandBoxCharacterBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}