Hi,
this mini tutorial is the extension/rework of the RTS camera code you can find at the Wiki. It contains hopefully all the usual camera and keyboard movement and rotation features you may need.
After you created a new C++ project (call it RTS or whatever), or if you have an existing one, first set up inputs in the editor as follows:
For mouse wheel:
https://i.postimg.cc/44wKMb3y/RTSAction-Mappings.jpg
For keyboard:
https://i.postimg.cc/ZYjccNtF/RTSAxis-Mappings.jpg
Then you need to add some new classes: a Player Controller, and a Spectator Pawn, let’s call them RTSPlayerController and RTSPlayerCameraSpectatorPawn respectively. The player controller will be used only for handling RTS unit selection and orders by mouse clicks (not part of this tutorial), and the spectator pawn will contain a camera and handle its movement. This way you can easily replace your default camera with something else during development e.g. a free camera, or the player can select from different camera styles…
Next, in the Game Mode (in case of a new project called RTS its name is RTSGameMode and automatically created), add a constructor to set your default player controller and pawn:
.h
#pragma once
#include "GameFramework/GameMode.h"
#include "RTSGameMode.generated.h"
/**
*
*/
UCLASS()
class RTS_API ARTSGameMode : public AGameMode
{
GENERATED_BODY()
ARTSGameMode();
};
.cpp
#include "RTS.h"
#include "RTSGameMode.h"
#include "RTSPlayer/RTSPlayerController.h"
#include "RTSPlayer/RTSPlayerCameraSpectatorPawn.h"
ARTSGameMode::ARTSGameMode()
{
// C++ classes
PlayerControllerClass = ARTSPlayerController::StaticClass();
DefaultPawnClass = ARTSPlayerCameraSpectatorPawn::StaticClass();
}
Jump to the Player Controller to set some basic things, most importantly to have a visible mouse pointer:
.h
#pragma once
#include "GameFramework/PlayerController.h"
#include "RTSPlayerController.generated.h"
/**
*
*/
UCLASS()
class RTS_API ARTSPlayerController : public APlayerController
{
GENERATED_BODY()
ARTSPlayerController();
};
.cpp
#include "RTS.h"
#include "RTSPlayerController.h"
ARTSPlayerController::ARTSPlayerController()
{
bShowMouseCursor = true;
bEnableClickEvents = true;
bEnableTouchEvents = true;
}
Now we are ready to set up our camera handling spectator pawn. As you can see mouse wheel and keyboard handling is separated, because keyboard inputs always have to deal with the delta time of the actual tick to set movement amount according to frame rate. It can be Blueprinted where you can set its default parameters from the editor. Please read through the comments above the variables and functions to have an overview what happens in the .cpp.
.h
#pragma once
#include "GameFramework/SpectatorPawn.h"
#include "RTSPlayerCameraSpectatorPawn.generated.h"
/**
* this is the default RTS camera handling movememnt, rotation, and zoom
*/
UCLASS()
class RTS_API ARTSPlayerCameraSpectatorPawn : public ASpectatorPawn
{
GENERATED_BODY()
public:
//------------------------------------
/** Constructor */
ARTSPlayerCameraSpectatorPawn(const FObjectInitializer& ObjectInitializer);
//------------------------------------
/** Camera Component */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
class UCameraComponent* CameraComponent;
//------------------------------------
//** Camera XY limit */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraXYLimit;
//** Camera height over terrain */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeight;
//** Camera min height over terrain */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeightMin;
//** Camera max height over terrain */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeightMax;
/** Camera Rotation around Axis Z */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraZAnlge;
/** Camera Height Angle */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeightAngle;
/** Camera Pitch Angle Max */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeightAngleMax;
/** Camera Pitch Angle Min */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraHeightAngleMin;
/** Camera Radius (Distance) From Pawn Position */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraRadius;
/** Camera Radius Max */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraRadiusMax;
/** Camera Radius Min */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraRadiusMin;
/** Camera Zoom Speed */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraZoomSpeed;
/** Camera Rotation Speed */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraRotationSpeed;
/** Camera Movement Speed */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraMovementSpeed;
/** Camera Scroll Boundary */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
float CameraScrollBoundary;
/** Should the camera move? */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Camera)
bool bCanMoveCamera;
//------------------------------------
private:
/** Sets up player inputs
* @param InputComponent - Input Component
*/
void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent);
//------------------------------------
public:
/** Zooms In The Camera */
void ZoomInByWheel();
/** Zooms Out The Camera */
void ZoomOutByWheel();
/** Rotate The Camera Left */
void RotateLeftByWheel();
/** Rotate The Camera Right */
void RotateRightByWheel();
/** Rotate The Camera Up */
void RotateUpByWheel();
/** Rotate The Camera Down */
void RotateDownByWheel();
//---
/** Calculates the new Location and Rotation of The Camera */
void RepositionCamera();
//------------------------------------
private:
// set them to +/-1 to get player input from keyboard
float FastMoveValue; // movement speed multiplier : 1 if shift unpressed, 2 is pressed
float RotateValue; // turn instead of move camera
float MoveForwardValue;
float MoveRightValue;
float MoveUpValue;
float ZoomInValue;
//---
public:
/** Left or Right Shift is pressed
* @param direcation - (1.0 for Right, -1.0 for Left)
*/
void FastMoveInput(float Direction);
/** Left or Right Ctrl is pressed
* @param direcation - (1.0 for Right, -1.0 for Left)
*/
void RotateInput(float Direction);
/** Input recieved to move the camera forward
* @param direcation - (1.0 for forward, -1.0 for backward)
*/
void MoveCameraForwardInput(float Direction);
/** Input recieved to move the camera right
* @param direcation - (1.0 for right, -1.0 for left)
*/
void MoveCameraRightInput(float Direction);
/** Input recieved to move the camera right
* @param direcation - (1.0 for right, -1.0 for left)
*/
void MoveCameraUpInput(float Direction);
/** Input recieved to move the camera right
* @param direcation - (1.0 for right, -1.0 for left)
*/
void ZoomCameraInInput(float Direction);
//---
private:
/** Moves the camera forward
* @param direcation - (+ forward, - backward)
*/
FVector MoveCameraForward(float Direction);
/** Moves the camera right
* @param direcation - (+ right, - left)
*/
FVector MoveCameraRight(float Direction);
/** Gets the roatation of the camera with only the yaw value
* @return - returns a rotator that is (0, yaw, 0) of the Camera
*/
FRotator GetIsolatedCameraYaw();
//---
/** Moves the camera up/down
* @param direcation - (+ up, - down)
*/
float MoveCameraUp(float Direction);
//---
/** Zooms the camera in/out
* @param direcation - (+ in, - out)
*/
void ZoomCameraIn(float Direction);
/** Turns the camera up/down
* @param direcation - (+ up, - down)
*/
void TurnCameraUp(float Direction);
/** Turns the camera right/left
* @param direcation - (+ right, - left)
*/
void TurnCameraRight(float Direction);
//------------------------------------
public:
/** Tick Function, handles keyboard inputs */
virtual void Tick(float DeltaSeconds) override;
//------------------------------------
// detect landscape and terrain static-mesh
// usage: RTS Obstacle and RTS Building placement onto landscape, terrain static-mesh
float GetLandTerrainSurfaceAtCoord(float XCoord, float YCoord) const;
//------------------------------------
};
Here comes the heavy part.
- In the constructor we set the default values of the public parameters, and add a camera component.
- Then user inputs are assigned to functions.
- Mouse wheel actions are called directly.
- Keyboard inputs first set a corresponding value parameter storing their direction. This way it is easy to handle different key combinations.
- After the input functions you can find the executive functions resonsible for camera movement and rotation.
- All of them are handled by the Tick function, where first a screen edge region mouse position is checked, which can result in a movement input similarly to pressing a button, then it calles the executive functions with frame rate corrected parameters.
- Reworked usage of RepositionCamera() resulting in smoother movement
- Ray tracing of landscape surface using channel ECC_WorldStatic to disable moving under ground.
.cpp
#include "RTS.h"
#include "RTSPlayerCameraSpectatorPawn.h"
//////////////////////////////////////////////////////////////////
ARTSPlayerCameraSpectatorPawn::ARTSPlayerCameraSpectatorPawn(const FObjectInitializer& ObjectInitializer)
{
// enable Tick function
PrimaryActorTick.bCanEverTick = true;
// disable standard WASD movement
bAddDefaultMovementBindings = false;
// not needed Pitch Yaw Roll
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// collision
GetCollisionComponent()->bGenerateOverlapEvents = false;
GetCollisionComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
GetCollisionComponent()->SetCollisionProfileName(TEXT("NoCollision"));
GetCollisionComponent()->SetSimulatePhysics(false);
// set defaults
CameraXYLimit = 25000.f;
CameraHeight = 1000.f;
CameraHeightMin = 300.f; // 100 for debugging
CameraHeightMax = 5000.f;
CameraRadius = 2000.f;
CameraRadiusMin = 1000.f; // 100 for debugging
CameraRadiusMax = 8000.f;
CameraZAnlge = 0.f; // yaw
CameraHeightAngle = 30.f; // pitch
CameraHeightAngleMin = 15.f;
CameraHeightAngleMax = 60.f;
CameraZoomSpeed = 200.f; // wheel
CameraRotationSpeed = 10.f; // wheel + ctrl
CameraMovementSpeed = 3000.f; // in all directions
CameraScrollBoundary = 25.f; // screen edge width
bCanMoveCamera = true;
// intialize the camera
CameraComponent = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this, TEXT("RTS Camera"));
CameraComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
CameraComponent->bUsePawnControlRotation = false;
RepositionCamera();
}
//////////////////////////////////////////////////////////////////
void ARTSPlayerCameraSpectatorPawn::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
if (!PlayerInputComponent) return;
Super::SetupPlayerInputComponent(PlayerInputComponent);
// action mappings
// mouse zoom
PlayerInputComponent->BindAction("ZoomOutByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::ZoomOutByWheel);
PlayerInputComponent->BindAction("ZoomInByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::ZoomInByWheel);
// mouse rotate (+Ctrl or +Alt)
// unnecessary...
//PlayerInputComponent->BindAction("RotateLeftByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::RotateLeftByWheel);
//PlayerInputComponent->BindAction("RotateRightByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::RotateRightByWheel);
// needed...
PlayerInputComponent->BindAction("RotateUpByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::RotateUpByWheel);
PlayerInputComponent->BindAction("RotateDownByWheel", IE_Pressed, this, &ARTSPlayerCameraSpectatorPawn::RotateDownByWheel);
// axis mappings
// keyboard move (WASD, Home/End)
PlayerInputComponent->BindAxis("MoveForward", this, &ARTSPlayerCameraSpectatorPawn::MoveCameraForwardInput);
PlayerInputComponent->BindAxis("MoveRight", this, &ARTSPlayerCameraSpectatorPawn::MoveCameraRightInput);
PlayerInputComponent->BindAxis("MoveUp", this, &ARTSPlayerCameraSpectatorPawn::MoveCameraUpInput);
PlayerInputComponent->BindAxis("ZoomIn", this, &ARTSPlayerCameraSpectatorPawn::ZoomCameraInInput);
// double speed (WASD +Shift)
PlayerInputComponent->BindAxis("FastMove", this, &ARTSPlayerCameraSpectatorPawn::FastMoveInput);
// yaw and pitch (WASD +Ctrl)
PlayerInputComponent->BindAxis("Rotate", this, &ARTSPlayerCameraSpectatorPawn::RotateInput);
}
//////////////////////////////////////////////////////////////////
void ARTSPlayerCameraSpectatorPawn::ZoomInByWheel()
{
if (!bCanMoveCamera) return;
CameraRadius -= CameraZoomSpeed * FastMoveValue;
CameraRadius = FMath::Clamp(CameraRadius, CameraRadiusMin, CameraRadiusMax);
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::ZoomOutByWheel()
{
if (!bCanMoveCamera) return;
CameraRadius += CameraZoomSpeed * FastMoveValue;
CameraRadius = FMath::Clamp(CameraRadius, CameraRadiusMin, CameraRadiusMax);
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::RotateLeftByWheel()
{
if (!bCanMoveCamera) return;
CameraZAnlge -= CameraRotationSpeed * FastMoveValue;
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::RotateRightByWheel()
{
if (!bCanMoveCamera) return;
CameraZAnlge += CameraRotationSpeed * FastMoveValue;
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::RotateUpByWheel()
{
if (!bCanMoveCamera) return;
CameraHeightAngle += CameraRotationSpeed * FastMoveValue;
CameraHeightAngle = FMath::Clamp(CameraHeightAngle, CameraHeightAngleMin, CameraHeightAngleMax);
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::RotateDownByWheel()
{
if (!bCanMoveCamera) return;
CameraHeightAngle -= CameraRotationSpeed * FastMoveValue;
CameraHeightAngle = FMath::Clamp(CameraHeightAngle, CameraHeightAngleMin, CameraHeightAngleMax);
//RepositionCamera();
}
//---------------
void ARTSPlayerCameraSpectatorPawn::RepositionCamera()
{
FVector NewLocation(0.f, 0.f, 0.f);
FRotator NewRotation(0.f, 0.f, 0.f);
float sinCameraZAngle = FMath::Sin(FMath::DegreesToRadians(CameraZAnlge));
float cosCameraZAngle = FMath::Cos(FMath::DegreesToRadians(CameraZAnlge));
float sinCameraHeightAngle = FMath::Sin(FMath::DegreesToRadians(CameraHeightAngle));
float cosCameraHeightAngle = FMath::Cos(FMath::DegreesToRadians(CameraHeightAngle));
NewLocation.X = cosCameraZAngle * cosCameraHeightAngle * CameraRadius;
NewLocation.Y = sinCameraZAngle * cosCameraHeightAngle * CameraRadius;
NewLocation.Z = sinCameraHeightAngle * CameraRadius;
// do not allow camera component to go under ground - not enough alone, actor also needed to be limited
float TerrainSurfaceZ = GetLandTerrainSurfaceAtCoord(GetActorLocation().X + NewLocation.X, GetActorLocation().Y + NewLocation.Y);
if (GetActorLocation().Z + NewLocation.Z < TerrainSurfaceZ + CameraHeight)
{
//FVector NewLocation = CameraComponent->GetComponentLocation();
NewLocation.Z = TerrainSurfaceZ - GetActorLocation().Z + CameraHeight;
}
// new camera location
CameraComponent->SetRelativeLocation(NewLocation);
// new camera rotation
NewRotation = (FVector(0.0f, 0.0f, 0.0f) - NewLocation).Rotation();
CameraComponent->SetRelativeRotation(NewRotation);
}
//////////////////////////////////////////////////////////////////
void ARTSPlayerCameraSpectatorPawn::FastMoveInput(float Direction)
{
if (!bCanMoveCamera) return;
// left or right does not matter, to set double speed in any direction
FastMoveValue = FMath::Abs(Direction) * 2.0f;
// used as multiplier so must be 1 if not pressed
if (FastMoveValue == 0.0f)
{
FastMoveValue = 1.0f;
}
}
void ARTSPlayerCameraSpectatorPawn::RotateInput(float Direction)
{
if (!bCanMoveCamera) return;
// left or right does not matter
RotateValue = FMath::Abs(Direction);
}
void ARTSPlayerCameraSpectatorPawn::MoveCameraForwardInput(float Direction)
{
if (!bCanMoveCamera) return;
MoveForwardValue = Direction;
}
void ARTSPlayerCameraSpectatorPawn::MoveCameraRightInput(float Direction)
{
if (!bCanMoveCamera) return;
MoveRightValue = Direction;
}
void ARTSPlayerCameraSpectatorPawn::MoveCameraUpInput(float Direction)
{
if (!bCanMoveCamera) return;
MoveUpValue = Direction;
}
void ARTSPlayerCameraSpectatorPawn::ZoomCameraInInput(float Direction)
{
if (!bCanMoveCamera) return;
ZoomInValue = Direction;
}
//------------------------------------------------------------
FVector ARTSPlayerCameraSpectatorPawn::MoveCameraForward(float Direction)
{
float MovementValue = Direction * CameraMovementSpeed;
FVector DeltaMovement = MovementValue * GetIsolatedCameraYaw().Vector();
//FVector NewLocation = GetActorLocation() + DeltaMovement;
//SetActorLocation(NewLocation);
return DeltaMovement;
}
FVector ARTSPlayerCameraSpectatorPawn::MoveCameraRight(float Direction)
{
float MovementValue = Direction * CameraMovementSpeed;
FVector DeltaMovement = MovementValue * (FRotator(0.0f, 90.0f, 0.0f) + GetIsolatedCameraYaw()).Vector();
//FVector NewLocation = GetActorLocation() + DeltaMovement;
//SetActorLocation(NewLocation);
return DeltaMovement;
}
FRotator ARTSPlayerCameraSpectatorPawn::GetIsolatedCameraYaw()
{
// FRotator containing Yaw only
return FRotator(0.0f, CameraComponent->ComponentToWorld.Rotator().Yaw, 0.0f);
}
//---------------
float ARTSPlayerCameraSpectatorPawn::MoveCameraUp(float Direction)
{
float MovementValue = Direction * CameraMovementSpeed;
//FVector DeltaMovement = FVector(0.0f, 0.0f, MovementValue);
//FVector NewLocation = GetActorLocation() + DeltaMovement;
//NewLocation.Z = FMath::Clamp(NewLocation.Z, CameraRadiusMin, CameraRadiusMax);
//SetActorLocation(NewLocation);
return MovementValue;
}
//---------------
void ARTSPlayerCameraSpectatorPawn::ZoomCameraIn(float Direction)
{
float MovementValue = Direction * CameraMovementSpeed;
CameraRadius += MovementValue;
CameraRadius = FMath::Clamp(CameraRadius, CameraRadiusMin, CameraRadiusMax);
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::TurnCameraUp(float Direction)
{
CameraHeightAngle -= Direction * CameraRotationSpeed * 10.0f;
CameraHeightAngle = FMath::Clamp(CameraHeightAngle, CameraHeightAngleMin, CameraHeightAngleMax);
//RepositionCamera();
}
void ARTSPlayerCameraSpectatorPawn::TurnCameraRight(float Direction)
{
CameraZAnlge += Direction * CameraRotationSpeed * 10.0f;
//RepositionCamera();
}
//////////////////////////////////////////////////////////////////
void ARTSPlayerCameraSpectatorPawn::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
// mouse position and screen size
FVector2D MousePosition;
FVector2D ViewportSize;
UGameViewportClient* GameViewport = GEngine->GameViewport;
// it is always nullptr on dedicated server
if (!GameViewport) return;
GameViewport->GetViewportSize(ViewportSize);
// if viewport is focused, contains the mouse, and camera movement is allowed
if (GameViewport->IsFocused(GameViewport->Viewport)
&& GameViewport->GetMousePosition(MousePosition) && bCanMoveCamera)
{
//-------------------
// movement direction by mouse at screen edge
if (MousePosition.X < CameraScrollBoundary)
{
MoveRightValue = -1.0f;
}
else if (ViewportSize.X - MousePosition.X < CameraScrollBoundary)
{
MoveRightValue = 1.0f;
}
if (MousePosition.Y < CameraScrollBoundary)
{
MoveForwardValue = 1.0f;
}
else if (ViewportSize.Y - MousePosition.Y < CameraScrollBoundary)
{
MoveForwardValue = -1.0f;
}
//-------------------
// tweak camera actor position
FVector ActualLocation = GetActorLocation();
FVector ActualMovement = FVector::ZeroVector;
// horizontal movement
if (RotateValue == 0.f)
{
ActualMovement += MoveCameraForward(MoveForwardValue * FastMoveValue * DeltaSeconds);
ActualMovement += MoveCameraRight(MoveRightValue * FastMoveValue * DeltaSeconds);
}
ActualLocation += ActualMovement;
// vertical movement
CameraHeight += MoveCameraUp(MoveUpValue * FastMoveValue * DeltaSeconds);
CameraHeight = FMath::Clamp(CameraHeight, CameraHeightMin, CameraHeightMax);
// adjust actor height to surface
float TerrainSurfaceZ = GetLandTerrainSurfaceAtCoord(ActualLocation.X, ActualLocation.Y);
ActualLocation.Z = TerrainSurfaceZ + CameraHeight;
// limit movement area
ActualLocation.X = FMath::Clamp(ActualLocation.X, -CameraXYLimit, CameraXYLimit);
ActualLocation.Y = FMath::Clamp(ActualLocation.Y, -CameraXYLimit, CameraXYLimit);
// move actor
SetActorLocation(ActualLocation);
//-------------------
// tweak camera component relative transform
// set rotation parameters
if (RotateValue != 0.f)
{
TurnCameraUp(MoveForwardValue * FastMoveValue * DeltaSeconds);
TurnCameraRight(MoveRightValue * FastMoveValue * DeltaSeconds);
}
// set zoom distance
ZoomCameraIn(ZoomInValue * FastMoveValue * DeltaSeconds);
// adjust camera component relative location and rotation
RepositionCamera();
//-------------------
// debug
//DrawDebugSphere(
// GetWorld(),
// GetCollisionComponent()->GetComponentLocation(),
// GetCollisionComponent()->GetScaledSphereRadius(),
// 8,
// FColor::White,
// false,
// -1.f
// );
//-------------------
}
}
//////////////////////////////////////////////////////////////////
float ARTSPlayerCameraSpectatorPawn::GetLandTerrainSurfaceAtCoord(float XCoord, float YCoord) const
{
FCollisionQueryParams TraceParams(FName(TEXT("LandTerrain")), false, this); // TraceTag (info for debugging), bTraceComplex, AddIgnoredActor
TraceParams.bFindInitialOverlaps = false; // needed
FHitResult Hit;
FVector Start = FVector(XCoord, YCoord, GetActorLocation().Z + CameraRadius);
FVector End = FVector(XCoord, YCoord, -500.f);
// ECC_ channels should be set properly !!!
bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldStatic, TraceParams);
if (bHit)
{
return Hit.ImpactPoint.Z; // for shape trace it differs from Location
}
return 0.f; // water level
}
//////////////////////////////////////////////////////////////////
I hope it was detailed enough (anyway the in-code comments should help), ask me if something unclear, or scream if you found a bug/mistake.
Maybe later I will add unit selection to the player controller…
Have fun with it!