Skip to content

Commit

Permalink
Add vision height levels and line of sight, and update vision for act…
Browse files Browse the repository at this point in the history
…ors that have moved onto new tiles, only.
  • Loading branch information
npruehs committed Jun 17, 2020
1 parent 8ce0f99 commit 9e523ae
Show file tree
Hide file tree
Showing 15 changed files with 691 additions and 102 deletions.
1 change: 1 addition & 0 deletions Documents/Manual/Maps.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ For the plugin, you'll design and create your maps the same way you're used to w

1. Add an `RTSVisionVolume` to the very center of your map, encompassing the whole valid visible map area.
1. Set the _Size In Tiles_ of the vision volume to match your minimap background images (e.g. 256).
1. Set the _Tile Height_ of the vision volume to the height of a single height level of your map, in cm (e.g. 250).
1. Add a `PostProcessVolume` to your map, and check _Infinite Extent (Unbound)_.
1. Add an `RTSFogOfWarActor` to your map.
1. Set the _Fog Of War Volume_ reference to the post process volume created before.
Expand Down
1 change: 1 addition & 0 deletions Documents/Manual/Units.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ As mentioned before, most features of the plugin are implemented by the means of
### Vision

1. Add the `RTSVision` component to your units and set their _Sight Radius_ (e.g. 1000).
1. If your actor should be able to ignore height levels for vision (e.g. watchtowers), check _Ignore Height Levels_.
1. Add a `RTSVisible`component to your actor. That component will manage vibility of that actor, in case multiple effects want to show/hide it (e.g. fog of war, containers).

### Combat
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "CoreMinimal.h"

#include "RTSVisionActor.generated.h"


class AActor;
class URTSVisionComponent;


/** Performance optimization. Caches an actor that can update team vision, along with relevant components. */
USTRUCT()
struct REALTIMESTRATEGY_API FRTSVisionActor
{
GENERATED_BODY()

public:
FRTSVisionActor();
FRTSVisionActor(AActor* InActor);

UPROPERTY()
AActor* Actor;

UPROPERTY()
URTSVisionComponent* VisionComponent;

bool IsActorValid() const;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "Components/ActorComponent.h"

#include "Vision/RTSVisionInfoTileList.h"

#include "RTSVisionComponent.generated.h"


Expand All @@ -18,15 +20,29 @@ class REALTIMESTRATEGY_API URTSVisionComponent : public UActorComponent
public:
URTSVisionComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

/** Performance Optimization. Tile the actor has been updated its vision at most recently. */
FIntVector ActorLocationTile;

/** Performance Optimization. Remembers the tiles we've got vision at. */
UPROPERTY()
TArray<FRTSVisionInfoTileList> VisibleTiles;

/** Gets the radius in which the actor reveals areas covered by fog of war, in cm. */
UFUNCTION(BlueprintPure)
float GetSightRadius() const;

/** Whether the actor can see tiles above its own height level. */
bool IgnoresHeightLevels() const;

private:
/** Radius in which the actor reveals areas covered by fog of war, in cm. */
UPROPERTY(EditDefaultsOnly, Category = "RTS", meta = (ClampMin = 0))
float SightRadius;

/** Whether the actor can see tiles above its own height level. */
UPROPERTY(EditDefaultsOnly, Category = "RTS")
bool bIgnoreHeightLevels;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "GameFramework/Info.h"

#include "Vision/RTSVisionState.h"
#include "Vision/RTSVisionTile.h"

#include "RTSVisionInfo.generated.h"

Expand All @@ -30,7 +31,8 @@ class REALTIMESTRATEGY_API ARTSVisionInfo : public AInfo
/** Prepares this actor for gameplay. */
void Initialize(ARTSVisionVolume* InVisionVolume);

virtual void Tick(float DeltaSeconds) override;
/** Whether vision info is already set up and available. */
bool IsInitialized() const;

/** Whether the whole map is currently being considered revealed (e.g. cheat, cinematic mode.) */
bool IsRevealed() const;
Expand All @@ -51,7 +53,16 @@ class REALTIMESTRATEGY_API ARTSVisionInfo : public AInfo
UFUNCTION(BlueprintPure, meta = (WorldContext = "WorldContextObject"))
static ARTSVisionInfo* GetVisionInfoForTeam(UObject* WorldContextObject, uint8 InTeamIndex);

/** Applies vision for the passed actor for this team. */
void ApplyVisionForActor(AActor* Actor, TArray<int32>& CachedTiles);

/** Resets all vision applied by the passed actor for this team. */
void ResetVisionForActor(AActor* Actor);

private:
/** Whether vision info is already set up and available. */
bool bInitialized;

/** Whether the whole map is currently being considered revealed (e.g. cheat, cinematic mode.) */
bool bRevealed;

Expand All @@ -62,8 +73,15 @@ class REALTIMESTRATEGY_API ARTSVisionInfo : public AInfo
UPROPERTY()
ARTSVisionVolume* VisionVolume;

/** Which tiles are currently unknown, known and visible. */
TArray<ERTSVisionState> Tiles;
/** Which tiles are currently known. */
TArray<bool> KnownTiles;

/** Which tiles are currently visible. */
UPROPERTY()
TArray<FRTSVisionTile> VisibleTiles;

/** Temporary grid for line of sight checks. */
TArray<int32> LocalVisionGrid;

bool GetTileCoordinates(int Index, int* OutX, int* OutY) const;
int32 GetTileIndex(int X, int Y) const;
Expand All @@ -72,4 +90,9 @@ class REALTIMESTRATEGY_API ARTSVisionInfo : public AInfo

UFUNCTION()
virtual void ReceivedTeamIndex();

/** Checks whether we've got vision on the specified tile; cached for a short duration. */
bool HasLocalVisionAt(int32 LocalTileX, int32 LocalTileY, int32 ActorSightRadiusTile, int32 GlobalTileX,
int32 GlobalTileY, int32 ActorLocationTileX, int32 ActorLocationTileY,
int32 ActorLocationHeightLevel);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "CoreMinimal.h"

#include "RTSVisionInfoTileList.generated.h"

class ARTSVisionInfo;

/** Tiles associated with a specific vision info. */
USTRUCT()
struct REALTIMESTRATEGY_API FRTSVisionInfoTileList
{
GENERATED_BODY()

public:
UPROPERTY()
ARTSVisionInfo* VisionInfo;

TArray<int32> VisibleTiles;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "GameFramework/Actor.h"

#include "Vision/RTSVisibleActor.h"
#include "Vision/RTSVisionActor.h"

#include "RTSVisionManager.generated.h"

Expand Down Expand Up @@ -36,6 +37,12 @@ class REALTIMESTRATEGY_API ARTSVisionManager : public AActor
/** Unregisters the specified actor for updating its own visibility. */
void RemoveVisibleActor(AActor* Actor);

/** Registers the specified actor for updating team vision. */
void AddVisionActor(AActor* Actor);

/** Unregisters the specified actor for updating team vision. */
void RemoveVisionActor(AActor* Actor);

private:
/** Fog of war actor of the current world. */
UPROPERTY()
Expand All @@ -56,4 +63,14 @@ class REALTIMESTRATEGY_API ARTSVisionManager : public AActor
/** Actors that may become invisible. */
UPROPERTY()
TArray<FRTSVisibleActor> VisibleActors;

/** All actors that may update team vision. */
UPROPERTY()
TArray<FRTSVisionActor> VisionActors;

/** Checks whether vision needs to be updated for the specified actor, and does so if necessary. */
void UpdateVisionActor(const FRTSVisionActor& VisionActor);

/** Resets vision for the specified actor (e.g. because update is imminent, or actor has been removed.) */
void ResetVisionForActor(const FRTSVisionActor& VisionActor);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include "CoreMinimal.h"

#include "RTSVisionTile.generated.h"


class AActor;


/** Tile of the vision grid. */
USTRUCT(BlueprintType)
struct REALTIMESTRATEGY_API FRTSVisionTile
{
GENERATED_BODY()

public:
/** Adds the specified actor as having vision on this tile. */
void AddActor(AActor* Actor);

/** Removes the specified actor from having vision on this tile. */
void RemoveActor(AActor* Actor);

/** Checks whether any actor has vision on this tile. */
bool IsVisible() const;

private:
/** Number of actors seeing this tile. */
UPROPERTY()
int32 NumActors = 0;
};
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,33 @@ class REALTIMESTRATEGY_API ARTSVisionVolume : public AVolume
/** Gets the width and height of a single vision grid tile, in cm. */
float GetTileSize() const;

/** Gets the height level of the specified vision grid tile. */
int32 GetTileHeight(const FIntVector& Tile) const;

/** Gets the minimum vision state of the world. */
ERTSVisionState GetMinimumVisionState() const;

inline FVector2D TileToWorld(const FIntVector& Tile) const
{
return TileToWorldXY(Tile.X, Tile.Y);
}

inline FVector2D TileToWorldXY(int32 TileX, int32 TileY) const
{
return TileWorldLocations[TileY * SizeInTiles + TileX];
}

FIntVector WorldToTile(const FVector& WorldPosition) const;

private:
/** Width and height of the vision grid imposed on the world. */
UPROPERTY(EditInstanceOnly, Category = "RTS")
int32 SizeInTiles;

/** Height of a height level imposed on the world. */
UPROPERTY(EditInstanceOnly, Category = "RTS", meta = (ClampMin = 0))
float LevelHeight;

/** Minimum vision state of the world. Change this for removing the black part of fog of war, or disabling it entirely. */
UPROPERTY(EditInstanceOnly, Category = "RTS")
ERTSVisionState MinimumVisionState;
Expand All @@ -51,4 +68,16 @@ class REALTIMESTRATEGY_API ARTSVisionVolume : public AVolume

/** Width and height of a single vision grid tile, in cm. */
float TileSize;

/** Cached world locations of all vision grid tiles. */
TArray<FVector2D> TileWorldLocations;

/** Cached height levels of all vision grid tiles. */
TArray<int32> TileHeights;

/** Gets the index of the tile with the specified coordinates. */
int32 GetTileIndex(int32 X, int32 Y) const;

/** Traces the height of the specified world location. */
float CalculateWorldHeightAtLocation(const FVector2D& WorldLocation);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "Vision/RTSVisionActor.h"

#include "GameFramework/Actor.h"

#include "Vision/RTSVisionComponent.h"


FRTSVisionActor::FRTSVisionActor()
: Actor(nullptr),
VisionComponent(nullptr)
{
}

FRTSVisionActor::FRTSVisionActor(AActor* InActor)
: Actor(InActor)
{
VisionComponent = InActor->FindComponentByClass<URTSVisionComponent>();
}

bool FRTSVisionActor::IsActorValid() const
{
return IsValid(Actor) && IsValid(VisionComponent);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#include "Vision/RTSVisionComponent.h"

#include "Kismet/GameplayStatics.h"

#include "RTSGameState.h"
#include "Vision/RTSVisionManager.h"


URTSVisionComponent::URTSVisionComponent(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
: Super(ObjectInitializer)
Expand All @@ -8,7 +13,51 @@ URTSVisionComponent::URTSVisionComponent(const FObjectInitializer& ObjectInitial
SightRadius = 1000.0f;
}

void URTSVisionComponent::BeginPlay()
{
Super::BeginPlay();

// Register actor with game.
ARTSGameState* GameState = Cast<ARTSGameState>(UGameplayStatics::GetGameState(this));

if (IsValid(GameState))
{
ARTSVisionManager* VisionManager = GameState->GetVisionManager();

if (IsValid(VisionManager))
{
VisionManager->AddVisionActor(GetOwner());
}
}
}

void URTSVisionComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);

if (EndPlayReason == EEndPlayReason::Destroyed)
{
// Unregister actor from game.
ARTSGameState* GameState = Cast<ARTSGameState>(UGameplayStatics::GetGameState(this));

if (IsValid(GameState))
{
ARTSVisionManager* VisionManager = GameState->GetVisionManager();

if (IsValid(VisionManager))
{
VisionManager->RemoveVisionActor(GetOwner());
}
}
}
}

float URTSVisionComponent::GetSightRadius() const
{
return SightRadius;
}

bool URTSVisionComponent::IgnoresHeightLevels() const
{
return bIgnoreHeightLevels;
}
Loading

0 comments on commit 9e523ae

Please sign in to comment.