All player controllers in the C++ game templates are not for strategy games. They all implemented so the player controls just one character. I'm not sure what approach to take when you want to control several units.
What comes in mind: The player should not have a mesh. He should be always in the center of the screen, he will never move. mouse will then control selection/edge-pan instead of him moving.
In the following image, I have a sphere, that's a "Planet", I wish to accomplish that the player to control the planet, produce units, and control them. I'm very new to UE4, using version 4.6.1, any help would be appreciated as I found little in other places.
Here's my current implementation. it's just the default top down template:
// StrategyAlphaCharacter.h
#pragma once
#include "GameFramework/Character.h"
#include "StrategyAlphaCharacter.generated.h"
UCLASS(Blueprintable)
class AStrategyAlphaCharacter : public ACharacter
{
GENERATED_BODY()
/** Top down camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* TopDownCameraComponent;
/** Camera boom positioning the camera above the character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
public:
AStrategyAlphaCharacter(const FObjectInitializer& ObjectInitializer);
/** Returns TopDownCameraComponent subobject **/
FORCEINLINE class UCameraComponent* GetTopDownCameraComponent() const { return TopDownCameraComponent; }
/** Returns CameraBoom subobject **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
};
// StrategyAlphaCharacter.cpp
#include "StrategyAlpha.h"
#include "StrategyAlphaCharacter.h"
AStrategyAlphaCharacter::AStrategyAlphaCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// Set size for player capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// Don't rotate character to camera direction
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Rotate character to moving direction
GetCharacterMovement()->RotationRate = FRotator(0.f, 640.f, 0.f);
GetCharacterMovement()->bConstrainToPlane = true;
GetCharacterMovement()->bSnapToPlaneAtStart = true;
// Create a camera boom...
CameraBoom = ObjectInitializer.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
CameraBoom->AttachTo(RootComponent);
CameraBoom->bAbsoluteRotation = true; // Don't want arm to rotate when character does
CameraBoom->TargetArmLength = 800.f;
CameraBoom->RelativeRotation = FRotator(-60.f, 0.f, 0.f);
CameraBoom->bDoCollisionTest = false; // Don't want to pull camera in when it collides with level
// Create a camera...
TopDownCameraComponent = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this, TEXT("TopDownCamera"));
TopDownCameraComponent->AttachTo(CameraBoom, USpringArmComponent::SocketName);
TopDownCameraComponent->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
}
// StrategyAlphaPlayerController.cpp
#include "StrategyAlpha.h"
#include "StrategyAlphaPlayerController.h"
#include "AI/Navigation/NavigationSystem.h"
AStrategyAlphaPlayerController::AStrategyAlphaPlayerController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bShowMouseCursor = true;
DefaultMouseCursor = EMouseCursor::Crosshairs;
}
void AStrategyAlphaPlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
// keep updating the destination every tick while desired
if (bMoveToMouseCursor)
{
MoveToMouseCursor();
}
}
void AStrategyAlphaPlayerController::SetupInputComponent()
{
// set up gameplay key bindings
Super::SetupInputComponent();
InputComponent->BindAction("SetDestination", IE_Pressed, this, &AStrategyAlphaPlayerController::OnSetDestinationPressed);
InputComponent->BindAction("SetDestination", IE_Released, this, &AStrategyAlphaPlayerController::OnSetDestinationReleased);
// support touch devices
InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AStrategyAlphaPlayerController::MoveToTouchLocation);
InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &AStrategyAlphaPlayerController::MoveToTouchLocation);
}
void AStrategyAlphaPlayerController::MoveToMouseCursor()
{
// Trace to see what is under the mouse cursor
FHitResult Hit;
GetHitResultUnderCursor(ECC_Visibility, false, Hit);
if (Hit.bBlockingHit)
{
// We hit something, move there
SetNewMoveDestination(Hit.ImpactPoint);
}
}
void AStrategyAlphaPlayerController::MoveToTouchLocation(const ETouchIndex::Type FingerIndex, const FVector Location)
{
FVector2D ScreenSpaceLocation(Location);
// Trace to see what is under the touch location
FHitResult HitResult;
GetHitResultAtScreenPosition(ScreenSpaceLocation, CurrentClickTraceChannel, true, HitResult);
if (HitResult.bBlockingHit)
{
// We hit something, move there
SetNewMoveDestination(HitResult.ImpactPoint);
}
}
void AStrategyAlphaPlayerController::SetNewMoveDestination(const FVector DestLocation)
{
APawn* const Pawn = GetPawn();
if (Pawn)
{
UNavigationSystem* const NavSys = GetWorld()->GetNavigationSystem();
float const Distance = FVector::Dist(DestLocation, Pawn->GetActorLocation());
// We need to issue move command only if far enough in order for walk animation to play correctly
if (NavSys && (Distance > 120.0f))
{
NavSys->SimpleMoveToLocation(this, DestLocation);
}
}
}
void AStrategyAlphaPlayerController::OnSetDestinationPressed()
{
// set flag to keep updating destination until released
bMoveToMouseCursor = true;
}
void AStrategyAlphaPlayerController::OnSetDestinationReleased()
{
// clear flag to indicate we should stop updating the destination
bMoveToMouseCursor = false;
}