Game controller design
This commit is contained in:
parent
5b7eb7a75b
commit
0718b4ad23
|
@ -0,0 +1,26 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "CarlaGameController.h"
|
||||
|
||||
CarlaGameController::CarlaGameController()
|
||||
{
|
||||
bCanEverTick = true;
|
||||
}
|
||||
|
||||
APlayerStart *CarlaGameController::ChoosePlayerStart(
|
||||
const TArray<APlayerStart *> &AvailableStartSpots)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Not implemented"));
|
||||
return AvailableStartSpots[0u];
|
||||
}
|
||||
|
||||
void CarlaGameController::RegisterPlayer(AController *NewPlayer)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Not implemented"));
|
||||
}
|
||||
|
||||
void CarlaGameController::Tick(float DeltaSeconds)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Not implemented"));
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CarlaGameControllerBase.h"
|
||||
|
||||
/// Implements remote control of game and player.
|
||||
class CARLA_API CarlaGameController : public CarlaGameControllerBase
|
||||
{
|
||||
public:
|
||||
|
||||
CarlaGameController();
|
||||
|
||||
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) override;
|
||||
|
||||
virtual void RegisterPlayer(AController *NewPlayer) override;
|
||||
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Array.h"
|
||||
|
||||
class APlayerStart;
|
||||
class AController;
|
||||
|
||||
/// Base class for a CARLA game controller.
|
||||
class CARLA_API CarlaGameControllerBase
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CarlaGameControllerBase() {}
|
||||
|
||||
bool CanEverTick() const
|
||||
{
|
||||
return bCanEverTick;
|
||||
}
|
||||
|
||||
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) = 0;
|
||||
|
||||
virtual void RegisterPlayer(AController *NewPlayer) = 0;
|
||||
|
||||
virtual void Tick(float DeltaSeconds) {}
|
||||
|
||||
protected:
|
||||
|
||||
bool bCanEverTick = false;
|
||||
};
|
|
@ -3,13 +3,96 @@
|
|||
#include "Carla.h"
|
||||
#include "CarlaGameMode.h"
|
||||
|
||||
#include "Engine/PlayerStartPIE.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/PlayerStart.h"
|
||||
|
||||
#include "CarlaGameController.h"
|
||||
#include "CarlaGameState.h"
|
||||
#include "CarlaPlayerState.h"
|
||||
#include "CarlaServerController.h"
|
||||
#include "CarlaPlayerState.h"
|
||||
#include "CarlaVehicleController.h"
|
||||
#include "MockGameController.h"
|
||||
|
||||
ACarlaGameMode::ACarlaGameMode()
|
||||
ACarlaGameMode::ACarlaGameMode() :
|
||||
Super(),
|
||||
GameController(nullptr)
|
||||
{
|
||||
PlayerControllerClass = ACarlaServerController::StaticClass();
|
||||
PlayerControllerClass = ACarlaVehicleController::StaticClass();
|
||||
GameStateClass = ACarlaGameState::StaticClass();
|
||||
PlayerStateClass = ACarlaPlayerState::StaticClass();
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
}
|
||||
|
||||
void ACarlaGameMode::InitGame(
|
||||
const FString &MapName,
|
||||
const FString &Options,
|
||||
FString &ErrorMessage)
|
||||
{
|
||||
Super::InitGame(MapName, Options, ErrorMessage);
|
||||
|
||||
if (bUseMockController) {
|
||||
GameController = MakeUnique<MockGameController>();
|
||||
UE_LOG(LogCarla, Warning, TEXT("Using mock CARLA controller"));
|
||||
} else {
|
||||
GameController = MakeUnique<CarlaGameController>();
|
||||
}
|
||||
}
|
||||
|
||||
void ACarlaGameMode::RestartPlayer(AController* NewPlayer)
|
||||
{
|
||||
TArray<APlayerStart *> UnOccupiedStartPoints;
|
||||
APlayerStart *PlayFromHere = FindUnOccupiedStartPoints(NewPlayer, UnOccupiedStartPoints);
|
||||
if (PlayFromHere != nullptr) {
|
||||
RestartPlayerAtPlayerStart(NewPlayer, PlayFromHere);
|
||||
GameController->RegisterPlayer(NewPlayer);
|
||||
return;
|
||||
} else if (UnOccupiedStartPoints.Num() > 0u) {
|
||||
APlayerStart *StartSpot = GameController->ChoosePlayerStart(UnOccupiedStartPoints);
|
||||
if (StartSpot != nullptr) {
|
||||
RestartPlayerAtPlayerStart(NewPlayer, UnOccupiedStartPoints[0u]);
|
||||
GameController->RegisterPlayer(NewPlayer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
UE_LOG(LogCarla, Error, TEXT("No start spot found!"));
|
||||
}
|
||||
|
||||
void ACarlaGameMode::Tick(float DeltaSeconds)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
GameController->Tick(DeltaSeconds);
|
||||
}
|
||||
|
||||
APlayerStart *ACarlaGameMode::FindUnOccupiedStartPoints(
|
||||
AController *Player,
|
||||
TArray<APlayerStart *> &UnOccupiedStartPoints)
|
||||
{
|
||||
APlayerStart* FoundPlayerStart = nullptr;
|
||||
UClass* PawnClass = GetDefaultPawnClassForController(Player);
|
||||
APawn* PawnToFit = PawnClass ? PawnClass->GetDefaultObject<APawn>() : nullptr;
|
||||
for (TActorIterator<APlayerStart> It(GetWorld()); It; ++It) {
|
||||
APlayerStart* PlayerStart = *It;
|
||||
|
||||
if (PlayerStart->IsA<APlayerStartPIE>()) {
|
||||
FoundPlayerStart = PlayerStart;
|
||||
break;
|
||||
} else {
|
||||
FVector ActorLocation = PlayerStart->GetActorLocation();
|
||||
const FRotator ActorRotation = PlayerStart->GetActorRotation();
|
||||
if (!GetWorld()->EncroachingBlockingGeometry(PawnToFit, ActorLocation, ActorRotation)) {
|
||||
UnOccupiedStartPoints.Add(PlayerStart);
|
||||
}
|
||||
#ifdef WITH_EDITOR
|
||||
else if (GetWorld()->FindTeleportSpot(PawnToFit, ActorLocation, ActorRotation)) {
|
||||
UE_LOG(
|
||||
LogCarla,
|
||||
Warning,
|
||||
TEXT("Player start cannot be used, occupied location: %s"),
|
||||
*PlayerStart->GetActorLocation().ToString());
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
}
|
||||
}
|
||||
return FoundPlayerStart;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "CarlaGameControllerBase.h"
|
||||
#include "CarlaGameMode.generated.h"
|
||||
|
||||
class APlayerStart;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -13,7 +16,29 @@ class CARLA_API ACarlaGameMode : public AGameModeBase
|
|||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Use a mock controller instead of connecting to a client */
|
||||
UPROPERTY(Category = "CARLA Game Controller", EditAnywhere)
|
||||
bool bUseMockController = false;
|
||||
|
||||
public:
|
||||
|
||||
ACarlaGameMode();
|
||||
|
||||
virtual void InitGame(const FString &MapName, const FString &Options, FString &ErrorMessage) override;
|
||||
|
||||
virtual void RestartPlayer(AController *NewPlayer) override;
|
||||
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
private:
|
||||
|
||||
/// Iterate all the APlayerStart present in the world and add the ones with
|
||||
/// unoccupied locations to @a UnOccupiedStartPoints.
|
||||
///
|
||||
/// @return APlayerStart if "Play from Here" was used while in PIE mode.
|
||||
APlayerStart *FindUnOccupiedStartPoints(
|
||||
AController *Player,
|
||||
TArray<APlayerStart *> &UnOccupiedStartPoints);
|
||||
|
||||
TUniquePtr<CarlaGameControllerBase> GameController;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,17 @@ class CARLA_API ACarlaPlayerState : public APlayerState
|
|||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
/// @todo ?
|
||||
// virtual void Reset();
|
||||
// virtual void CopyProperties(APlayerState *PlayerState);
|
||||
|
||||
void RegisterCollision(AActor *Actor, FVector NormalImpulse) {}
|
||||
|
||||
FVector Location;
|
||||
|
||||
FVector Orientation;
|
||||
|
||||
float ForwardSpeed;
|
||||
};
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "CarlaServerController.h"
|
||||
|
||||
#include "DrawDebugHelpers.h"
|
||||
#include "Engine.h"
|
||||
|
||||
void ACarlaServerController::Tick(float DeltaTime)
|
||||
{
|
||||
Super::PlayerTick(DeltaTime);
|
||||
|
||||
if (!IsPossessingAVehicle())
|
||||
return;
|
||||
|
||||
auto Speed = GetVehicleForwardSpeed();
|
||||
auto Location = GetVehicleLocation();
|
||||
auto Orientation = GetVehicleOrientation();
|
||||
auto LineEndPoint = Location + std::min(1.0f, Speed) * 1000.0f * Orientation;
|
||||
auto Color = FColor(255u, 0u, 0u);
|
||||
DrawDebugPoint(GetWorld(), Location, 10.0f, Color);
|
||||
DrawDebugLine(GetWorld(), Location, LineEndPoint, Color);
|
||||
}
|
||||
|
||||
void ACarlaServerController::OnCollisionEvent(
|
||||
AActor* Actor,
|
||||
AActor* OtherActor,
|
||||
FVector NormalImpulse,
|
||||
const FHitResult& Hit)
|
||||
{
|
||||
if(GEngine)
|
||||
GEngine->AddOnScreenDebugMessage(
|
||||
-1,
|
||||
15.0f,
|
||||
FColor::Yellow,
|
||||
FString::Printf(TEXT("We hit a %s"), *OtherActor->GetName()));
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CarlaVehicleController.h"
|
||||
#include "CarlaServerController.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class CARLA_API ACarlaServerController : public ACarlaVehicleController
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
virtual void OnCollisionEvent(
|
||||
AActor* Actor,
|
||||
AActor* OtherActor,
|
||||
FVector NormalImpulse,
|
||||
const FHitResult& Hit) override;
|
||||
};
|
|
@ -13,7 +13,9 @@
|
|||
// -- Constructor and destructor -----------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
ACarlaVehicleController::ACarlaVehicleController()
|
||||
ACarlaVehicleController::ACarlaVehicleController() :
|
||||
Super(),
|
||||
MovementComponent(nullptr)
|
||||
{
|
||||
bAutoManageActiveCameraTarget = false;
|
||||
|
||||
|
@ -60,14 +62,35 @@ void ACarlaVehicleController::SetupInputComponent()
|
|||
void ACarlaVehicleController::Possess(APawn *aPawn)
|
||||
{
|
||||
Super::Possess(aPawn);
|
||||
if (IsPossessingAVehicle()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Controller already possessing a pawn!"));
|
||||
return;
|
||||
}
|
||||
auto *WheeledVehicle = Cast<AWheeledVehicle>(aPawn);
|
||||
if (WheeledVehicle != nullptr) {
|
||||
// Attach the camera's spring arm to the pawn.
|
||||
SpringArm->AttachToComponent(
|
||||
aPawn->GetRootComponent(),
|
||||
FAttachmentTransformRules::KeepRelativeTransform);
|
||||
// Bind hit events.
|
||||
aPawn->OnActorHit.AddDynamic(this, &ACarlaVehicleController::OnCollisionEvent);
|
||||
// Get vehicle movement component.
|
||||
MovementComponent = WheeledVehicle->GetVehicleMovementComponent();
|
||||
check(MovementComponent != nullptr);
|
||||
// Get custom player state.
|
||||
CarlaPlayerState = Cast<ACarlaPlayerState>(PlayerState);
|
||||
check(CarlaPlayerState != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ACarlaVehicleController::Tick(float DeltaTime)
|
||||
{
|
||||
Super::PlayerTick(DeltaTime);
|
||||
|
||||
if (IsPossessingAVehicle()) {
|
||||
CarlaPlayerState->Location = GetVehicleLocation();
|
||||
CarlaPlayerState->Orientation = GetVehicleOrientation();
|
||||
CarlaPlayerState->ForwardSpeed = GetVehicleForwardSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,10 +165,13 @@ void ACarlaVehicleController::ToggleManualMode()
|
|||
// =============================================================================
|
||||
|
||||
void ACarlaVehicleController::OnCollisionEvent(
|
||||
AActor* Actor,
|
||||
AActor* /*Actor*/,
|
||||
AActor* OtherActor,
|
||||
FVector NormalImpulse,
|
||||
const FHitResult& Hit) {}
|
||||
const FHitResult& /*Hit*/)
|
||||
{
|
||||
CarlaPlayerState->RegisterCollision(OtherActor, NormalImpulse);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Input bindings -----------------------------------------------------------
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
|
||||
virtual void Possess(APawn *aPawn) override;
|
||||
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
virtual void CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult) override;
|
||||
|
||||
/// @}
|
||||
|
@ -105,7 +107,7 @@ public:
|
|||
private:
|
||||
|
||||
UFUNCTION()
|
||||
virtual void OnCollisionEvent(
|
||||
void OnCollisionEvent(
|
||||
AActor* Actor,
|
||||
AActor* OtherActor,
|
||||
FVector NormalImpulse,
|
||||
|
@ -150,4 +152,7 @@ private:
|
|||
|
||||
UPROPERTY()
|
||||
UWheeledVehicleMovementComponent *MovementComponent;
|
||||
|
||||
// Cast for quick access to the custom player state.
|
||||
ACarlaPlayerState *CarlaPlayerState;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "MockGameController.h"
|
||||
|
||||
MockGameController::MockGameController()
|
||||
{
|
||||
bCanEverTick = false;
|
||||
}
|
||||
|
||||
APlayerStart *MockGameController::ChoosePlayerStart(
|
||||
const TArray<APlayerStart *> &AvailableStartSpots)
|
||||
{
|
||||
return AvailableStartSpots[0u];
|
||||
}
|
||||
|
||||
void MockGameController::RegisterPlayer(AController *NewPlayer)
|
||||
{
|
||||
ACarlaVehicleController *VehicleController = Cast<ACarlaVehicleController>(NewPlayer);
|
||||
if (VehicleController != nullptr) {
|
||||
if (!VehicleController->IsInManualMode())
|
||||
VehicleController->SetManualMode(true);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Player is not a ACarlaVehicleController"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CarlaGameControllerBase.h"
|
||||
|
||||
/// Mocks the CARLA game controller class for testing purposes.
|
||||
class CARLA_API MockGameController : public CarlaGameControllerBase
|
||||
{
|
||||
public:
|
||||
|
||||
MockGameController();
|
||||
|
||||
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) override;
|
||||
|
||||
virtual void RegisterPlayer(AController *NewPlayer) override;
|
||||
};
|
Loading…
Reference in New Issue