Skip to content
This repository has been archived by the owner on Jan 25, 2023. It is now read-only.

Commit

Permalink
More spectator and replay system work
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick-Pearson committed Apr 30, 2018
1 parent 83f90e8 commit 527a647
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 82 deletions.
4 changes: 2 additions & 2 deletions ParkourGame/Content/Blueprints/Minigames/BallGame_BP.uasset
Git LFS file not shown
4 changes: 2 additions & 2 deletions ParkourGame/Content/Blueprints/SpectatorCamera_BP.uasset
Git LFS file not shown
Git LFS file not shown
Git LFS file not shown
4 changes: 2 additions & 2 deletions ParkourGame/Content/ThirdPersonCPP/Maps/arena_base.umap
Git LFS file not shown
Git LFS file not shown
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ void AParkourPlayerController::Server_EndCurrentGame_Implementation()

void AParkourPlayerController::Net_StartReplay_Implementation()
{
FParkourSpectatorBroadcasts::StartActionReplay.Broadcast();
FParkourSpectatorBroadcasts::StartActionReplay.Broadcast(GetWorld());
}
95 changes: 70 additions & 25 deletions ParkourGame/Source/ParkourGame/Private/MiniGame/MiniGameBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ bool AMiniGameBase::PlayerJoinGame(AParkourGameCharacter* Player)
return false;
}

SelectedTeam->PlayersInTeam.Add(Player);
SelectedTeam->PlayersInTeam.Add(FPlayerInTeam(Player));

//check if we are full
if (AutoStartWhenTeamsFull &&
Expand All @@ -68,19 +68,20 @@ void AMiniGameBase::PlayerLeaveGame(AParkourGameCharacter* Player)
if (!Player || !HasAuthority()) return;

// ensure the player is already in the game
TArray<AParkourGameCharacter*> AllPlayers;
GetAllPlayers(AllPlayers);
int32 TeamID = GetTeamFromPlayer(Player);

if (TeamID == INDEX_NONE) return;

if (!AllPlayers.Contains(Player)) return;

int32 TeamID = GetTeamFromPlayer(Player);
FMiniGameTeam Team = GetTeamFromID(TeamID);
Team.PlayersInTeam.Remove(Player);
int32 RemoveIdx = Team.PlayersInTeam.FindLastByPredicate([&](const FPlayerInTeam& Plr) {
return Plr.PlayerPtr == Player;
});
if (RemoveIdx != INDEX_NONE) Team.PlayersInTeam.RemoveAtSwap(RemoveIdx);

//check if Team is empty
if (Team.PlayersInTeam.Num() == 0)
{
//END GAME todo
RequestEndGame(EMiniGameEndReason::PlayersLeft);
}

return;
Expand Down Expand Up @@ -223,9 +224,9 @@ void AMiniGameBase::GetAllPlayers(TArray<AParkourGameCharacter*>& AllPlayers) co
{
AllPlayers.Reserve(AllPlayers.Num() + Team.PlayersInTeam.Num());

for (const TWeakObjectPtr<AParkourGameCharacter>& PlayerWeakPtr : Team.PlayersInTeam)
for (const FPlayerInTeam& Plr : Team.PlayersInTeam)
{
if (AParkourGameCharacter* Player = PlayerWeakPtr.Get())
if (AParkourGameCharacter* Player = Plr.PlayerPtr.Get())
AllPlayers.Add(Player);
}
}
Expand All @@ -239,25 +240,27 @@ void AMiniGameBase::GetAllPlayersInTeam(int32 TeamID, TArray<AParkourGameCharact

if (!FoundTeam) return;

for (const TWeakObjectPtr<AParkourGameCharacter>& PlayerWeakPtr : FoundTeam->PlayersInTeam)
for (const FPlayerInTeam& Plr : FoundTeam->PlayersInTeam)
{
if (AParkourGameCharacter* Player = PlayerWeakPtr.Get())
if (AParkourGameCharacter* Player = Plr.PlayerPtr.Get())
Players.Add(Player);
}
}

int32 AMiniGameBase::GetTeamFromPlayer(AParkourGameCharacter* Player) const
{
if (!Player) return INDEX_NONE;

for (const FMiniGameTeam& Team : TeamData)
{
for (const TWeakObjectPtr<AParkourGameCharacter>& WeakPlayer : Team.PlayersInTeam)
for (const FPlayerInTeam& Plr : Team.PlayersInTeam)
{
if (WeakPlayer == Player) return Team.TeamID;
if (Plr.PlayerPtr == Player) return Team.TeamID;
}
}

UE_LOG(ParkourGame, Warning, TEXT("[MinigameBase] Attempted to get the team from a player that is not in this game"));
return 0;
return INDEX_NONE;
}

FMiniGameTeam AMiniGameBase::GetTeamFromID(int32 TeamID) const
Expand All @@ -275,7 +278,7 @@ FMiniGameTeam AMiniGameBase::GetTeamFromID(int32 TeamID) const
return ErrTeam;
}

void AMiniGameBase::ModifyScore(int32 TeamID, int32 Change, int32& NewScore)
void AMiniGameBase::ModifyScore(int32 TeamID, int32 Change, AParkourGameCharacter* Scorer, int32& NewScore)
{
FMiniGameTeam* TeamPtr = TeamData.FindByPredicate([&](const FMiniGameTeam& queryTeam) {
return queryTeam.TeamID == TeamID;
Expand All @@ -287,6 +290,35 @@ void AMiniGameBase::ModifyScore(int32 TeamID, int32 Change, int32& NewScore)
TeamPtr->Score = FMath::Max(0, TeamPtr->Score);
NewScore = TeamPtr->Score;

int32 ScorerTeamID = GetTeamFromPlayer(Scorer);

if (ScorerTeamID != INDEX_NONE)
{
//handle the own goal case
if (ScorerTeamID != TeamID)
{
FMiniGameTeam* ScorerTeamPtr = TeamData.FindByPredicate([&](const FMiniGameTeam& queryTeam) {
return queryTeam.TeamID == ScorerTeamID;
});

FPlayerInTeam* PlayerData = ScorerTeamPtr->PlayersInTeam.FindByPredicate([&](const FPlayerInTeam& Plr) {
return Plr.PlayerPtr == Scorer;
});

PlayerData->OwnGoals += Change;
}
else
{
FPlayerInTeam* PlayerData = TeamPtr->PlayersInTeam.FindByPredicate([&](const FPlayerInTeam& Plr) {
return Plr.PlayerPtr == Scorer;
});

PlayerData->Goals += Change;
}
}

TeamPtr->LastScoringPlayer = Scorer;

CheckWinCondition();
}

Expand All @@ -301,6 +333,16 @@ int32 AMiniGameBase::GetScore(int32 TeamID) const
return TeamPtr->Score;
}

AParkourGameCharacter* AMiniGameBase::GetLastScoringPlayer(int32 TeamID) const
{
const FMiniGameTeam* ScorerTeamPtr = TeamData.FindByPredicate([&](const FMiniGameTeam& queryTeam) {
return queryTeam.TeamID == TeamID;
});

if (!ScorerTeamPtr) return nullptr;
return ScorerTeamPtr->LastScoringPlayer.Get();
}

void AMiniGameBase::OnRep_State()
{
if (!GameManager) return;
Expand Down Expand Up @@ -332,10 +374,10 @@ void AMiniGameBase::OnRep_TeamData()
// no existing team data so all players are new players
GameManager->OnTeamScoreUpdated.Broadcast(this, Team.TeamID);

for (const TWeakObjectPtr<AParkourGameCharacter>& player : Team.PlayersInTeam)
for (const FPlayerInTeam& player : Team.PlayersInTeam)
{
// player only in new array - they have joined the game
GameManager->OnPlayerJoinedTeam.Broadcast(this, player.Get(), Team.TeamID);
GameManager->OnPlayerJoinedTeam.Broadcast(this, player.PlayerPtr.Get(), Team.TeamID);
}

continue;
Expand All @@ -345,27 +387,30 @@ void AMiniGameBase::OnRep_TeamData()
if (oldTeam->Score != Team.Score) GameManager->OnTeamScoreUpdated.Broadcast(this, Team.TeamID);

//compare the two lists of players
TArray<TWeakObjectPtr<AParkourGameCharacter>> mutable_PlayersInTeam = Team.PlayersInTeam;
TArray<FPlayerInTeam> mutable_PlayersInTeam = Team.PlayersInTeam;

for (const TWeakObjectPtr<AParkourGameCharacter>& player : oldTeam->PlayersInTeam)
for (const FPlayerInTeam& player : oldTeam->PlayersInTeam)
{
int32 foundIdx;
if (mutable_PlayersInTeam.FindLast(player, foundIdx))
int32 foundIdx = mutable_PlayersInTeam.FindLastByPredicate([&](const FPlayerInTeam& plr) {
return plr.PlayerPtr == player.PlayerPtr;
});

if (foundIdx != INDEX_NONE)
{
// The player was in both arrays - nothing has changed
mutable_PlayersInTeam.RemoveAt(foundIdx);
}
else
{
// player only in old array - they have left the game
GameManager->OnPlayerLeftTeam.Broadcast(this, player.Get(), Team.TeamID);
GameManager->OnPlayerLeftTeam.Broadcast(this, player.PlayerPtr.Get(), Team.TeamID);
}
}

for (const TWeakObjectPtr<AParkourGameCharacter>& player : mutable_PlayersInTeam)
for (const FPlayerInTeam& player : mutable_PlayersInTeam)
{
// player only in new array - they have joined the game
GameManager->OnPlayerJoinedTeam.Broadcast(this, player.Get(), Team.TeamID);
GameManager->OnPlayerJoinedTeam.Broadcast(this, player.PlayerPtr.Get(), Team.TeamID);
}
}

Expand Down
31 changes: 29 additions & 2 deletions ParkourGame/Source/ParkourGame/Private/MiniGame/MiniGameBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ struct FMiniGameTeamUIInfo : public FTableRowBase

};

USTRUCT()
struct FPlayerInTeam
{
GENERATED_BODY()
public:

FPlayerInTeam(AParkourGameCharacter* Player = nullptr) :
PlayerPtr(Player), Goals(0), OwnGoals(0)
{}

UPROPERTY(Transient)
TWeakObjectPtr<AParkourGameCharacter> PlayerPtr;

UPROPERTY(Transient)
int32 Goals = 0;

UPROPERTY(Transient)
int32 OwnGoals = 0;

};

USTRUCT(BlueprintType)
struct FMiniGameTeam
{
Expand All @@ -61,7 +82,10 @@ struct FMiniGameTeam
int32 TeamID;

UPROPERTY(Transient)
TArray<TWeakObjectPtr<AParkourGameCharacter>> PlayersInTeam;
TArray<FPlayerInTeam> PlayersInTeam;

UPROPERTY(Transient)
TWeakObjectPtr<AParkourGameCharacter> LastScoringPlayer;

UPROPERTY(BlueprintReadOnly, Category = "MinigameTeam")
int32 Score;
Expand Down Expand Up @@ -156,11 +180,14 @@ class AMiniGameBase : public AActor
FMiniGameTeam GetTeamFromID(int32 TeamID) const;

UFUNCTION(BlueprintCallable, Category = "MiniGame")
void ModifyScore(int32 TeamID, int32 Change, int32& NewScore);
void ModifyScore(int32 TeamID, int32 Change, AParkourGameCharacter* Scorer, int32& NewScore);

UFUNCTION(BlueprintCallable, Category = "MiniGame")
int32 GetScore(int32 TeamID) const;

UFUNCTION(BlueprintCallable, Category = "MiniGame")
AParkourGameCharacter* GetLastScoringPlayer(int32 TeamID) const;

FORCEINLINE AMiniGameManager* GetManager() const { return GameManager; }

public:
Expand Down
12 changes: 10 additions & 2 deletions ParkourGame/Source/ParkourGame/Private/ParkourGameCharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/PlayerState.h"
#include "GameFramework/GameStateBase.h"
#include "UnrealNetwork.h"
#include "PhysicsEngine/PhysicalAnimationComponent.h"
#include "Engine/DataTable.h"
Expand Down Expand Up @@ -298,7 +299,7 @@ void AParkourGameCharacter::PlayStandUpAnimation()
EnableJumping(false);

GetWorld()->GetTimerManager().ClearTimer(ResetStandupHandle);
GetWorld()->GetTimerManager().SetTimer(ResetStandupHandle, FTimerDelegate::CreateUObject(this, &AParkourGameCharacter::ResetStandupAnim), FMath::Max(0.1f, Row->Montage->GetSectionLength(0) / (Row->Montage->RateScale * PlayRate)), false);
GetWorld()->GetTimerManager().SetTimer(ResetStandupHandle, FTimerDelegate::CreateUObject(this, &AParkourGameCharacter::ResetStandupAnim), FMath::Max(0.1f, (Row->Montage->GetSectionLength(0) / (Row->Montage->RateScale * PlayRate)) - Row->Montage->BlendOut.GetBlendTime()), false);
}

FName AParkourGameCharacter::ChooseStandUpAnimation(EStandUpDirection Direction) const
Expand Down Expand Up @@ -1233,7 +1234,14 @@ bool AParkourGameCharacter::Server_BecomeSpectator_Validate()
void AParkourGameCharacter::Server_BecomeSpectator_Implementation()
{
#if WITH_EDITOR
AParkourSpectator* SpecatorPawn = GetWorld()->SpawnActor<AParkourSpectator>(AParkourSpectator::StaticClass(), GetTransform());
UClass* SpectatorClass = AParkourSpectator::StaticClass();

if (AGameStateBase const* const GameState = GetWorld()->GetGameState())
{
SpectatorClass = GameState->SpectatorClass;
}

AParkourSpectator* SpecatorPawn = GetWorld()->SpawnActor<AParkourSpectator>(SpectatorClass, GetTransform());

GetController()->Possess(SpecatorPawn);
Destroy();
Expand Down
6 changes: 3 additions & 3 deletions ParkourGame/Source/ParkourGame/Private/ParkourGameCharacter.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,6 @@ class AParkourGameCharacter : public ACharacter
UFUNCTION(BlueprintImplementableEvent)
void DropBall(AActor* Ball, EHandSideEnum Hand);

UFUNCTION(BlueprintPure, Category = "BallHandling")
bool HasBall() const;

UFUNCTION()
void OnRagdollEvent();

Expand Down Expand Up @@ -507,6 +504,9 @@ class AParkourGameCharacter : public ACharacter

UFUNCTION(BlueprintNativeEvent, Category = "Replay")
void InitialiseReplayActor(AParkourGameCharacter* ReplayActor);

UFUNCTION(BlueprintPure, Category = "BallHandling")
bool HasBall() const;

private:
AParkourPlayerController* GetParkourPlayerController() const;
Expand Down
Loading

0 comments on commit 527a647

Please sign in to comment.