feature/fix-time-sync #1
|
@ -76,3 +76,6 @@ Plugins/*/Intermediate/*
|
|||
|
||||
# Cache files for the editor to use
|
||||
DerivedDataCache/*
|
||||
|
||||
#Config files
|
||||
Config/User*.ini
|
|
@ -22,6 +22,14 @@
|
|||
"Editor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "OnlineSubsystemSteam",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "OnlineSubsystemEOS",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "Bridge",
|
||||
"Enabled": true,
|
||||
|
|
|
@ -21,6 +21,8 @@ r.ReflectionMethod=1
|
|||
r.Shadow.Virtual.Enable=1
|
||||
|
||||
[/Script/WorldPartitionEditor.WorldPartitionEditorSettings]
|
||||
bEnableWorldPartition=False
|
||||
bEnableConversionPrompt=True
|
||||
CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet'
|
||||
|
||||
[/Script/Engine.Engine]
|
||||
|
@ -43,19 +45,25 @@ bUseManualIPAddress=False
|
|||
ManualIPAddress=
|
||||
|
||||
[/Script/Engine.GameEngine]
|
||||
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
|
||||
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemEOS.NetDriverEOS",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
|
||||
|
||||
[OnlineSubsystem]
|
||||
DefaultPlatformService=Steam
|
||||
DefaultPlatformService=EOS
|
||||
|
||||
[OnlineSubsystemSteam]
|
||||
bEnabled=true
|
||||
bEnabled=false
|
||||
SteamDevAppId=480
|
||||
bInitServerOnClient=true
|
||||
|
||||
[/Script/OnlineSubsystemSteam.SteamNetDriver]
|
||||
NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
|
||||
|
||||
[OnlineSubsystemEOS]
|
||||
bEnabled=true
|
||||
|
||||
[/Script/OnlineSubsystemEOS.NetDriverEOS]
|
||||
bIsUsingP2PSockets=true
|
||||
|
||||
[/Script/OnlineSubsystemUtils.IpNetDriver]
|
||||
NetServerMaxTickRate=120
|
||||
|
||||
|
@ -116,3 +124,18 @@ NetServerMaxTickRate=120
|
|||
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
|
||||
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
|
||||
|
||||
[/Script/OnlineSubsystemEOS.EOSSettings]
|
||||
CacheDir=CacheDir
|
||||
DefaultArtifactName=Blaster
|
||||
TickBudgetInMilliseconds=0
|
||||
bEnableOverlay=True
|
||||
bEnableSocialOverlay=True
|
||||
bShouldEnforceBeingLaunchedByEGS=False
|
||||
TitleStorageReadChunkLength=0
|
||||
bUseEAS=False
|
||||
bUseEOSConnect=False
|
||||
bMirrorStatsToEOS=False
|
||||
bMirrorAchievementsToEOS=False
|
||||
bUseEOSSessions=False
|
||||
bMirrorPresenceToEAS=False
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ MaxPlayers=100
|
|||
Build=IfProjectHasCode
|
||||
BuildConfiguration=PPBC_Development
|
||||
BuildTarget=
|
||||
LaunchOnTarget=
|
||||
StagingDirectory=(Path="C:/UEProjects/Blaster/Build")
|
||||
StagingDirectory=(Path="")
|
||||
FullRebuild=False
|
||||
ForDistribution=False
|
||||
IncludeDebugFiles=False
|
||||
|
@ -20,7 +19,6 @@ bIncludeNativizedAssetsInProjectGeneration=False
|
|||
bExcludeMonolithicEngineHeadersInNativizedCode=False
|
||||
UsePakFile=True
|
||||
bUseIoStore=True
|
||||
bUseZenStore=False
|
||||
bMakeBinaryConfig=False
|
||||
bGenerateChunks=False
|
||||
bGenerateNoChunks=False
|
||||
|
@ -91,12 +89,10 @@ bSkipMovies=False
|
|||
+IniKeyBlacklist=MobileProvision
|
||||
+IniKeyBlacklist=IniKeyBlacklist
|
||||
+IniKeyBlacklist=IniSectionBlacklist
|
||||
-IniSectionBlacklist=HordeStorageServers
|
||||
+IniSectionBlacklist=HordeStorageServers
|
||||
+MapsToCook=(FilePath="/Game/Maps/Lobby")
|
||||
+MapsToCook=(FilePath="/Game/Maps/GameStartupMap")
|
||||
+MapsToCook=(FilePath="/Game/Maps/TransitionMap")
|
||||
+MapsToCook=(FilePath="/Game/Maps/BlasterMap")
|
||||
PerPlatformBuildConfig=()
|
||||
PerPlatformTargetFlavorName=(("Android", "Android_ASTC"))
|
||||
PerPlatformBuildTarget=()
|
||||
PerPlatformTargetPlatformName=()
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
+AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||
|
@ -65,7 +69,6 @@ bUseMouseForTouch=False
|
|||
bEnableMouseSmoothing=True
|
||||
bEnableFOVScaling=True
|
||||
bCaptureMouseOnLaunch=True
|
||||
bEnableLegacyInputScales=True
|
||||
bAlwaysShowTouchInterface=False
|
||||
bShowConsoleOnFourFingerTap=True
|
||||
bEnableGestureRecognizer=False
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -29,6 +29,10 @@
|
|||
{
|
||||
"Name": "OnlineSubsystemSteam",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "OnlineSubsystemEOS",
|
||||
"Enabled": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -28,6 +28,7 @@ public class MultiplayerSessions : ModuleRules
|
|||
"Core",
|
||||
"OnlineSubsystem",
|
||||
"OnlineSubsystemSteam",
|
||||
"OnlineSubsystemEOS",
|
||||
"UMG",
|
||||
"Slate",
|
||||
"SlateCore"
|
||||
|
|
|
@ -32,7 +32,7 @@ void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch, FStr
|
|||
}
|
||||
|
||||
UGameInstance* GameInstance = GetGameInstance();
|
||||
if (GetGameInstance())
|
||||
if (GameInstance)
|
||||
{
|
||||
MultiplayerSessionsSubsystem = GameInstance->GetSubsystem<UMultiplayerSessionsSubsystem>();
|
||||
}
|
||||
|
@ -44,6 +44,20 @@ void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch, FStr
|
|||
MultiplayerSessionsSubsystem->MultiplayerOnJoinSessionComplete.AddUObject(this, &ThisClass::OnJoinSession);
|
||||
MultiplayerSessionsSubsystem->MultiplayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession);
|
||||
MultiplayerSessionsSubsystem->MultiplayerOnStartSessionComplete.AddDynamic(this, &ThisClass::OnStartSession);
|
||||
MultiplayerSessionsSubsystem->MultiplayerOnLoginComplete.AddDynamic(this, &ThisClass::OnLoginComplete);
|
||||
|
||||
if (!MultiplayerSessionsSubsystem->IsLoggedIn())
|
||||
{
|
||||
LoginButton->SetIsEnabled(true);
|
||||
HostButton->SetIsEnabled(false);
|
||||
JoinButton->SetIsEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoginButton->SetIsEnabled(false);
|
||||
HostButton->SetIsEnabled(true);
|
||||
JoinButton->SetIsEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +78,11 @@ bool UMenu::Initialize()
|
|||
JoinButton->OnClicked.AddDynamic(this, &UMenu::JoinButtonClicked);
|
||||
}
|
||||
|
||||
if (LoginButton)
|
||||
{
|
||||
LoginButton->OnClicked.AddDynamic(this, &UMenu::LoginButtonClicked);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -164,6 +183,13 @@ void UMenu::OnStartSession(bool bWasSuccessful)
|
|||
{
|
||||
}
|
||||
|
||||
void UMenu::OnLoginComplete(bool bWasSuccessful)
|
||||
{
|
||||
JoinButton->SetIsEnabled(!bWasSuccessful);
|
||||
HostButton->SetIsEnabled(bWasSuccessful);
|
||||
JoinButton->SetIsEnabled(bWasSuccessful);
|
||||
}
|
||||
|
||||
void UMenu::HostButtonClicked()
|
||||
{
|
||||
HostButton->SetIsEnabled(false);
|
||||
|
@ -184,6 +210,16 @@ void UMenu::JoinButtonClicked()
|
|||
}
|
||||
}
|
||||
|
||||
void UMenu::LoginButtonClicked()
|
||||
{
|
||||
LoginButton->SetIsEnabled(false);
|
||||
|
||||
if (MultiplayerSessionsSubsystem)
|
||||
{
|
||||
MultiplayerSessionsSubsystem->Login();
|
||||
}
|
||||
}
|
||||
|
||||
void UMenu::MenuTearDown()
|
||||
{
|
||||
RemoveFromParent();
|
||||
|
|
|
@ -13,16 +13,76 @@ UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem():
|
|||
DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this, &ThisClass::OnDestroySessionComplete)),
|
||||
StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartSessionComplete))
|
||||
{
|
||||
IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get();
|
||||
Subsystem = IOnlineSubsystem::Get();
|
||||
if (Subsystem)
|
||||
{
|
||||
Identity = Subsystem->GetIdentityInterface();
|
||||
SessionInterface = Subsystem->GetSessionInterface();
|
||||
if (GetSubsystemName() != EOS_SUBSYSTEM) // Non EOS OSS don't need to login
|
||||
{
|
||||
bIsLoggedIn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FName UMultiplayerSessionsSubsystem::GetSubsystemName()
|
||||
{
|
||||
return Subsystem ? Subsystem->GetSubsystemName() : FName("NULL");
|
||||
}
|
||||
|
||||
void UMultiplayerSessionsSubsystem::Login()
|
||||
{
|
||||
if (IsLoggedIn())
|
||||
{
|
||||
MultiplayerOnLoginComplete.Broadcast(true);
|
||||
return;
|
||||
}
|
||||
|
||||
EOSLogin();
|
||||
}
|
||||
|
||||
void UMultiplayerSessionsSubsystem::EOSLogin()
|
||||
{
|
||||
if (!Identity.IsValid()) return;
|
||||
|
||||
LoginDelegateHandle = Identity->OnLoginCompleteDelegates->AddUObject(this, &UMultiplayerSessionsSubsystem::HandleLoginComplete);
|
||||
|
||||
FOnlineAccountCredentials Credentials;
|
||||
Credentials.Id = FString();
|
||||
Credentials.Token = FString();
|
||||
Credentials.Type = FString("accountportal");
|
||||
|
||||
if (!Identity->Login(0, Credentials))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Unable to perform EOS Login"));
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Display, TEXT("Performed EOS Login successful"));
|
||||
}
|
||||
}
|
||||
|
||||
void UMultiplayerSessionsSubsystem::HandleLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
|
||||
{
|
||||
bIsLoggedIn = bWasSuccessful;
|
||||
|
||||
if (Identity)
|
||||
{
|
||||
// Deregister the event handler.
|
||||
Identity->ClearOnLoginCompleteDelegate_Handle(LocalUserNum, LoginDelegateHandle);
|
||||
LoginDelegateHandle.Reset();
|
||||
}
|
||||
|
||||
// Broadcast our own custom delegate
|
||||
MultiplayerOnLoginComplete.Broadcast(bWasSuccessful);
|
||||
}
|
||||
|
||||
void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)
|
||||
{
|
||||
if (!IsLoggedIn()) return;
|
||||
|
||||
DesiredNumPublicConnections = NumPublicConnections;
|
||||
DesiredMatchType = MatchType;
|
||||
if (!SessionInterface.IsValid())
|
||||
{
|
||||
return;
|
||||
|
@ -42,15 +102,17 @@ void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FS
|
|||
CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);
|
||||
|
||||
LastSessionSettings = MakeShareable(new FOnlineSessionSettings());
|
||||
LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
|
||||
LastSessionSettings->bIsDedicated = false;
|
||||
LastSessionSettings->bIsLANMatch = GetSubsystemName() == "NULL" || GetSubsystemName() == "LAN" ? true : false;
|
||||
LastSessionSettings->NumPublicConnections = NumPublicConnections;
|
||||
LastSessionSettings->bAllowJoinInProgress = true;
|
||||
LastSessionSettings->bAllowJoinViaPresence = true;
|
||||
LastSessionSettings->bShouldAdvertise = true;
|
||||
LastSessionSettings->bUsesPresence = true;
|
||||
LastSessionSettings->bUseLobbiesIfAvailable = true; // For UE5 when not finding sessions
|
||||
LastSessionSettings->Set(FName("MatchType"), FString(MatchType), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
|
||||
LastSessionSettings->Set(SEARCH_KEYWORDS, FString("BlasterLobby"), EOnlineDataAdvertisementType::ViaOnlineService);
|
||||
LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
|
||||
LastSessionSettings->BuildUniqueId = 1;
|
||||
LastSessionSettings->bUseLobbiesIfAvailable = true;
|
||||
|
||||
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
|
||||
if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))
|
||||
|
@ -64,22 +126,29 @@ void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FS
|
|||
|
||||
void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
|
||||
{
|
||||
if (!IsLoggedIn())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SessionInterface.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FindSessionCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);
|
||||
FindSessionsCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);
|
||||
|
||||
LastSessionSearch = MakeShareable(new FOnlineSessionSearch);
|
||||
LastSessionSearch = MakeShareable(new FOnlineSessionSearch());
|
||||
LastSessionSearch->MaxSearchResults = MaxSearchResults;
|
||||
LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
|
||||
LastSessionSearch->QuerySettings.Set(SEARCH_KEYWORDS, FString("BlasterLobby"), EOnlineComparisonOp::Equals);
|
||||
LastSessionSearch->QuerySettings.Set(SEARCH_LOBBIES, true, EOnlineComparisonOp::Equals);
|
||||
LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);
|
||||
|
||||
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
|
||||
if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef()))
|
||||
{
|
||||
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle);
|
||||
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
|
||||
|
||||
MultiplayerOnFindSessionsComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);
|
||||
}
|
||||
|
@ -87,6 +156,8 @@ void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
|
|||
|
||||
void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
|
||||
{
|
||||
if (!IsLoggedIn()) return;
|
||||
|
||||
if (!SessionInterface.IsValid())
|
||||
{
|
||||
MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);
|
||||
|
@ -152,7 +223,7 @@ void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful)
|
|||
{
|
||||
if (SessionInterface)
|
||||
{
|
||||
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle);
|
||||
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
|
||||
}
|
||||
|
||||
if (LastSessionSearch->SearchResults.Num() <= 0)
|
||||
|
@ -180,17 +251,15 @@ void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName,
|
|||
{
|
||||
SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);
|
||||
}
|
||||
|
||||
if (bWasSuccessful && bCreateSessionOnDestroy)
|
||||
{
|
||||
bCreateSessionOnDestroy = false;
|
||||
CreateSession(LastNumPublicConnections, LastMatchType);
|
||||
}
|
||||
|
||||
MultiplayerOnDestroySessionComplete.Broadcast(bWasSuccessful);
|
||||
}
|
||||
|
||||
void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful)
|
||||
void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionName, bool bWasSuccessful)
|
||||
{
|
||||
if (SessionInterface)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@ class MULTIPLAYERSESSIONS_API UMenu : public UUserWidget
|
|||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll")), FString LobbyPath = FString(TEXT("/Game/ThirdPerson/Maps/Lobby")));
|
||||
void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll")), FString LobbyPath = FString(TEXT("/Game/Maps/Lobby")));
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -36,6 +36,8 @@ protected:
|
|||
void OnDestroySession(bool bWasSuccessful);
|
||||
UFUNCTION()
|
||||
void OnStartSession(bool bWasSuccessful);
|
||||
UFUNCTION()
|
||||
void OnLoginComplete(bool bWasSuccessful);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -45,15 +47,22 @@ private:
|
|||
UPROPERTY(meta=(BindWidget))
|
||||
UButton* JoinButton;
|
||||
|
||||
UPROPERTY(meta=(BindWidget))
|
||||
UButton* LoginButton;
|
||||
|
||||
UFUNCTION()
|
||||
void HostButtonClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void JoinButtonClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void LoginButtonClicked();
|
||||
|
||||
void MenuTearDown();
|
||||
|
||||
// The subsystem designed to handle all online session functionality
|
||||
UPROPERTY()
|
||||
class UMultiplayerSessionsSubsystem* MultiplayerSessionsSubsystem;
|
||||
|
||||
int32 NumPublicConnections {4};
|
||||
|
|
|
@ -4,17 +4,21 @@
|
|||
|
||||
#include "CoreMinimal.h"
|
||||
#include "OnlineSessionSettings.h"
|
||||
#include "OnlineSubsystem.h"
|
||||
#include "Interfaces/OnlineIdentityInterface.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "Interfaces/OnlineSessionInterface.h"
|
||||
#include "MultiplayerSessionsSubsystem.generated.h"
|
||||
|
||||
|
||||
//
|
||||
// Declaring our own custom delegates for the Menu class to bind callbacks to
|
||||
//
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful);
|
||||
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionsComplete, const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful);
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result)
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestroySessionComplete, bool, bWasSuccessful);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnStartSessionComplete, bool, bWasSuccessful);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnLoginComplete, bool, bWasSuccessful);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -27,6 +31,8 @@ class MULTIPLAYERSESSIONS_API UMultiplayerSessionsSubsystem : public UGameInstan
|
|||
public:
|
||||
|
||||
UMultiplayerSessionsSubsystem();
|
||||
void Login();
|
||||
FORCEINLINE bool IsLoggedIn() const { return bIsLoggedIn; }
|
||||
|
||||
/*
|
||||
* To handle session functionality. The Menu class will call these
|
||||
|
@ -45,7 +51,10 @@ public:
|
|||
FMultiplayerOnJoinSessionComplete MultiplayerOnJoinSessionComplete;
|
||||
FMultiplayerOnDestroySessionComplete MultiplayerOnDestroySessionComplete;
|
||||
FMultiplayerOnStartSessionComplete MultiplayerOnStartSessionComplete;
|
||||
FMultiplayerOnLoginComplete MultiplayerOnLoginComplete;
|
||||
|
||||
int32 DesiredNumPublicConnections{};
|
||||
FString DesiredMatchType{};
|
||||
protected:
|
||||
|
||||
/*
|
||||
|
@ -56,9 +65,11 @@ protected:
|
|||
void OnFindSessionsComplete(bool bWasSuccessful);
|
||||
void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);
|
||||
void OnDestroySessionComplete(FName SessionName, bool bWasSuccessful);
|
||||
void OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful);
|
||||
void OnStartSessionComplete(FName SessionName, bool bWasSuccessful);
|
||||
|
||||
private:
|
||||
IOnlineSubsystem* Subsystem;
|
||||
IOnlineIdentityPtr Identity;
|
||||
|
||||
IOnlineSessionPtr SessionInterface;
|
||||
TSharedPtr<FOnlineSessionSettings> LastSessionSettings;
|
||||
|
@ -66,12 +77,12 @@ private:
|
|||
|
||||
/*
|
||||
* To add to the Online Session Interface delegate list.
|
||||
* We'll bind our MultiplayerSessionSubsystem internal callbacks to these.
|
||||
* We'll bind our MultiplayerSessionsSubsystem internal callbacks to these.
|
||||
*/
|
||||
FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
|
||||
FDelegateHandle CreateSessionCompleteDelegateHandle;
|
||||
FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate;
|
||||
FDelegateHandle FindSessionCompleteDelegateHandle;
|
||||
FDelegateHandle FindSessionsCompleteDelegateHandle;
|
||||
FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;
|
||||
FDelegateHandle JoinSessionCompleteDelegateHandle;
|
||||
FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate;
|
||||
|
@ -82,4 +93,12 @@ private:
|
|||
bool bCreateSessionOnDestroy { false };
|
||||
int32 LastNumPublicConnections;
|
||||
FString LastMatchType;
|
||||
|
||||
void EOSLogin();
|
||||
|
||||
FDelegateHandle LoginDelegateHandle;
|
||||
void HandleLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error);
|
||||
|
||||
FName GetSubsystemName();
|
||||
bool bIsLoggedIn = false;
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ public class Blaster : ModuleRules
|
|||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "MultiplayerSessions", "OnlineSubsystem", "OnlineSubsystemSteam" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
|
||||
#include "BlasterAnimInstance.h"
|
||||
|
||||
#include "BlasterCharacter.h"
|
||||
#include "Blaster/Weapon/Weapon.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
#include "Blaster/Weapon/Weapon.h"
|
||||
#include "Blaster/Types/CombatState.h"
|
||||
|
||||
void UBlasterAnimInstance::NativeInitializeAnimation()
|
||||
{
|
||||
|
@ -15,15 +15,14 @@ void UBlasterAnimInstance::NativeInitializeAnimation()
|
|||
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
|
||||
}
|
||||
|
||||
void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
|
||||
void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaTime)
|
||||
{
|
||||
Super::NativeUpdateAnimation(DeltaSeconds);
|
||||
Super::NativeUpdateAnimation(DeltaTime);
|
||||
|
||||
if (BlasterCharacter == nullptr)
|
||||
{
|
||||
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
|
||||
}
|
||||
|
||||
if (BlasterCharacter == nullptr) return;
|
||||
|
||||
FVector Velocity = BlasterCharacter->GetVelocity();
|
||||
|
@ -31,7 +30,7 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
|
|||
Speed = Velocity.Size();
|
||||
|
||||
bIsInAir = BlasterCharacter->GetCharacterMovement()->IsFalling();
|
||||
bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0.f;
|
||||
bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0.f ? true : false;
|
||||
bWeaponEquipped = BlasterCharacter->IsWeaponEquipped();
|
||||
EquippedWeapon = BlasterCharacter->GetEquippedWeapon();
|
||||
bIsCrouched = BlasterCharacter->bIsCrouched;
|
||||
|
@ -43,23 +42,22 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
|
|||
FRotator AimRotation = BlasterCharacter->GetBaseAimRotation();
|
||||
FRotator MovementRotation = UKismetMathLibrary::MakeRotFromX(BlasterCharacter->GetVelocity());
|
||||
FRotator DeltaRot = UKismetMathLibrary::NormalizedDeltaRotator(MovementRotation, AimRotation);
|
||||
DeltaRotation = FMath::RInterpTo(DeltaRotation, DeltaRot, DeltaSeconds, 6.f);
|
||||
DeltaRotation = FMath::RInterpTo(DeltaRotation, DeltaRot, DeltaTime, 6.f);
|
||||
YawOffset = DeltaRotation.Yaw;
|
||||
|
||||
CharacterRotationLastFrame = CharacterRotation;
|
||||
CharacterRotation = BlasterCharacter->GetActorRotation();
|
||||
const FRotator Delta = UKismetMathLibrary::NormalizedDeltaRotator(CharacterRotation, CharacterRotationLastFrame);
|
||||
const float Target = Delta.Yaw / DeltaSeconds;
|
||||
const float Interp = FMath::FInterpTo(Lean, Target, DeltaSeconds, 6.f);
|
||||
const float Target = Delta.Yaw / DeltaTime;
|
||||
const float Interp = FMath::FInterpTo(Lean, Target, DeltaTime, 6.f);
|
||||
Lean = FMath::Clamp(Interp, -90.f, 90.f);
|
||||
|
||||
// Aim offset
|
||||
AO_Yaw = BlasterCharacter->GetAO_Yaw();
|
||||
AO_Pitch = BlasterCharacter->GetAO_Pitch();
|
||||
|
||||
if (bWeaponEquipped && EquippedWeapon && EquippedWeapon->GetWeaponMesh() && BlasterCharacter->GetMesh())
|
||||
{
|
||||
LeftHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("LeftHandSocket"), RTS_World);
|
||||
LeftHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("LeftHandSocket"), ERelativeTransformSpace::RTS_World);
|
||||
FVector OutPosition;
|
||||
FRotator OutRotation;
|
||||
BlasterCharacter->GetMesh()->TransformToBoneSpace(FName("hand_r"), LeftHandTransform.GetLocation(), FRotator::ZeroRotator, OutPosition, OutRotation);
|
||||
|
@ -69,9 +67,9 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
|
|||
if (BlasterCharacter->IsLocallyControlled())
|
||||
{
|
||||
bLocallyControlled = true;
|
||||
const FTransform RightHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("Hand_R"), RTS_World);
|
||||
FTransform RightHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("Hand_R"), ERelativeTransformSpace::RTS_World);
|
||||
FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(RightHandTransform.GetLocation(), RightHandTransform.GetLocation() + (RightHandTransform.GetLocation() - BlasterCharacter->GetHitTarget()));
|
||||
RightHandRotation = FMath::RInterpTo(RightHandRotation, LookAtRotation, DeltaSeconds, 30.f);
|
||||
RightHandRotation = FMath::RInterpTo(RightHandRotation, LookAtRotation, DeltaTime, 30.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class BLASTER_API UBlasterAnimInstance : public UAnimInstance
|
|||
public:
|
||||
|
||||
virtual void NativeInitializeAnimation() override;
|
||||
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
|
||||
virtual void NativeUpdateAnimation(float DeltaTime) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ ABlasterCharacter::ABlasterCharacter()
|
|||
SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
||||
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
||||
CameraBoom->SetupAttachment(GetMesh());
|
||||
CameraBoom->TargetArmLength = 350.f;
|
||||
CameraBoom->TargetArmLength = 600.f;
|
||||
CameraBoom->bUsePawnControlRotation = true;
|
||||
|
||||
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
||||
|
@ -44,11 +44,12 @@ ABlasterCharacter::ABlasterCharacter()
|
|||
Combat->SetIsReplicated(true);
|
||||
|
||||
GetCharacterMovement()->NavAgentProps.bCanCrouch = true;
|
||||
GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
|
||||
GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
|
||||
GetMesh()->SetCollisionObjectType(ECC_SkeletalMesh);
|
||||
GetMesh()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
|
||||
GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
||||
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
|
||||
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
|
||||
GetCharacterMovement()->RotationRate = FRotator(0.f, 850.f, 0.f);
|
||||
|
||||
TurningInPlace = ETurningInPlace::ETIP_NotTurning;
|
||||
NetUpdateFrequency = 66.f;
|
||||
MinNetUpdateFrequency = 33.f;
|
||||
|
@ -56,17 +57,6 @@ ABlasterCharacter::ABlasterCharacter()
|
|||
DissolveTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("DissolveTimelineComponent"));
|
||||
}
|
||||
|
||||
void ABlasterCharacter::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
UpdateHUDHealth();
|
||||
if (HasAuthority())
|
||||
{
|
||||
OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
@ -79,11 +69,81 @@ void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Ou
|
|||
void ABlasterCharacter::OnRep_ReplicatedMovement()
|
||||
{
|
||||
Super::OnRep_ReplicatedMovement();
|
||||
|
||||
SimProxiesTurn();
|
||||
TimeSinceLastMovementReplication = 0.f;
|
||||
}
|
||||
|
||||
void ABlasterCharacter::Eliminated()
|
||||
{
|
||||
if (Combat && Combat->EquippedWeapon)
|
||||
{
|
||||
Combat->EquippedWeapon->Dropped();
|
||||
}
|
||||
MulticastEliminated();
|
||||
GetWorldTimerManager().SetTimer(
|
||||
EliminationTimer,
|
||||
this,
|
||||
&ABlasterCharacter::EliminationTimerFinished,
|
||||
EliminationDelay
|
||||
);
|
||||
}
|
||||
|
||||
void ABlasterCharacter::MulticastEliminated_Implementation()
|
||||
{
|
||||
if (BlasterPlayerController)
|
||||
{
|
||||
BlasterPlayerController->SetHUDWeaponAmmo(0);
|
||||
}
|
||||
bEliminated = true;
|
||||
PlayEliminatedMontage();
|
||||
// Start dissolve effect
|
||||
if (DissolveMaterialInstance)
|
||||
{
|
||||
DynamicDissolveMaterialInstance = UMaterialInstanceDynamic::Create(DissolveMaterialInstance, this);
|
||||
GetMesh()->SetMaterial(0, DynamicDissolveMaterialInstance);
|
||||
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Dissolve"), 0.55f);
|
||||
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Glow"), 200.f);
|
||||
}
|
||||
StartDissolve();
|
||||
|
||||
// Disable character movement
|
||||
GetCharacterMovement()->DisableMovement();
|
||||
GetCharacterMovement()->StopMovementImmediately();
|
||||
bDisableGameplay = true;
|
||||
// Disable collision
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
|
||||
// Elimination bot
|
||||
if (EliminationBotEffect)
|
||||
{
|
||||
const FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f);
|
||||
EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation(
|
||||
GetWorld(),
|
||||
EliminationBotEffect,
|
||||
EliminationBotSpawnPoint,
|
||||
GetActorRotation()
|
||||
);
|
||||
}
|
||||
if (EliminationBotSound)
|
||||
{
|
||||
UGameplayStatics::SpawnSoundAtLocation(
|
||||
this,
|
||||
EliminationBotSound,
|
||||
GetActorLocation()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::EliminationTimerFinished()
|
||||
{
|
||||
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
|
||||
if (BlasterGameMode)
|
||||
{
|
||||
BlasterGameMode->RequestRespawn(this, Controller);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::Destroyed()
|
||||
{
|
||||
Super::Destroyed();
|
||||
|
@ -98,151 +158,24 @@ void ABlasterCharacter::Destroyed()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PostInitializeComponents()
|
||||
void ABlasterCharacter::BeginPlay()
|
||||
{
|
||||
Super::PostInitializeComponents();
|
||||
|
||||
if (Combat)
|
||||
{
|
||||
Combat->Character = this;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayFireMontage(bool bAiming)
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && FireWeaponMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(FireWeaponMontage);
|
||||
const FName SectionName = bAiming ? FName("RifleADS") : FName("RifleHip");
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayReloadMontage()
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && ReloadMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(ReloadMontage);
|
||||
FName SectionName;
|
||||
switch (Combat->EquippedWeapon->GetWeaponType())
|
||||
{
|
||||
case EWeaponType::EWT_AssaultRifle:
|
||||
SectionName = FName("Rifle");
|
||||
break;
|
||||
}
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayEliminatedMontage()
|
||||
{
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && EliminatedMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(EliminatedMontage);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::Eliminated()
|
||||
{
|
||||
if (Combat && Combat->EquippedWeapon)
|
||||
{
|
||||
Combat->EquippedWeapon->Dropped();
|
||||
}
|
||||
MulticastEliminated();
|
||||
GetWorldTimerManager().SetTimer(EliminationTimer, this, &ABlasterCharacter::EliminationTimerFinished, EliminationDelay);
|
||||
}
|
||||
|
||||
void ABlasterCharacter::MulticastEliminated_Implementation()
|
||||
{
|
||||
if (BlasterPlayerController)
|
||||
{
|
||||
BlasterPlayerController->SetHUDWeaponAmmo(0);
|
||||
}
|
||||
bEliminated = true;
|
||||
PlayEliminatedMontage();
|
||||
|
||||
// Start dissolve effect
|
||||
if (DissolveMaterialInstance)
|
||||
{
|
||||
DynamicDissolveMaterialInstance = UMaterialInstanceDynamic::Create(DissolveMaterialInstance, this);
|
||||
GetMesh()->SetMaterial(0, DynamicDissolveMaterialInstance);
|
||||
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Dissolve"), 0.55f);
|
||||
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Glow"), 200.f);
|
||||
}
|
||||
StartDissolve();
|
||||
|
||||
// Disable character movement
|
||||
GetCharacterMovement()->DisableMovement();
|
||||
GetCharacterMovement()->StopMovementImmediately();
|
||||
bDisableGameplay = true;
|
||||
|
||||
// Disable collision
|
||||
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
|
||||
// Elimination bot
|
||||
if (EliminationBotEffect)
|
||||
{
|
||||
const FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f);
|
||||
EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), EliminationBotEffect, EliminationBotSpawnPoint, GetActorRotation());
|
||||
|
||||
}
|
||||
if (EliminationBotSound)
|
||||
{
|
||||
UGameplayStatics::SpawnSoundAtLocation(this, EliminationBotSound, GetActorLocation());
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::EliminationTimerFinished()
|
||||
{
|
||||
ABlasterGameMode* GameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
|
||||
if (GameMode)
|
||||
{
|
||||
GameMode->RequestRespawn(this, Controller);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayHitReactMontage()
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && HitReactMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(HitReactMontage);
|
||||
const FName SectionName = FName("FromFront");
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController,
|
||||
AActor* DamageCauser)
|
||||
{
|
||||
Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);
|
||||
Super::BeginPlay();
|
||||
|
||||
UpdateHUDHealth();
|
||||
if (Health > 0.f)
|
||||
if (HasAuthority())
|
||||
{
|
||||
PlayHitReactMontage();
|
||||
OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage);
|
||||
}
|
||||
}
|
||||
|
||||
if (Health == 0.f)
|
||||
{
|
||||
ABlasterGameMode* GameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
|
||||
if (GameMode)
|
||||
{
|
||||
BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
|
||||
ABlasterPlayerController* AttackerController = Cast<ABlasterPlayerController>(InstigatorController);
|
||||
GameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController);
|
||||
}
|
||||
}
|
||||
void ABlasterCharacter::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
RotateInPlace(DeltaTime);
|
||||
HideCameraIfCharacterClose();
|
||||
PollInit();
|
||||
}
|
||||
|
||||
void ABlasterCharacter::RotateInPlace(float DeltaTime)
|
||||
|
@ -253,7 +186,7 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime)
|
|||
TurningInPlace = ETurningInPlace::ETIP_NotTurning;
|
||||
return;
|
||||
}
|
||||
if (GetLocalRole() > ROLE_SimulatedProxy && IsLocallyControlled())
|
||||
if (GetLocalRole() > ENetRole::ROLE_SimulatedProxy && IsLocallyControlled())
|
||||
{
|
||||
AimOffset(DeltaTime);
|
||||
}
|
||||
|
@ -268,46 +201,111 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime)
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
RotateInPlace(DeltaTime);
|
||||
HideCameraIfCharacterClose();
|
||||
PollInit();
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PollInit()
|
||||
{
|
||||
if (BlasterPlayerState == nullptr)
|
||||
{
|
||||
BlasterPlayerState = GetPlayerState<ABlasterPlayerState>();
|
||||
if (BlasterPlayerState)
|
||||
{
|
||||
// Initialize Score now we have the PlayerState
|
||||
BlasterPlayerState->IncreaseScore(0.f);
|
||||
BlasterPlayerState->IncreaseDefeats(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
|
||||
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABlasterCharacter::Jump);
|
||||
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
|
||||
PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed);
|
||||
PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed);
|
||||
PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed);
|
||||
PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased);
|
||||
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed);
|
||||
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased);
|
||||
|
||||
PlayerInputComponent->BindAxis("MoveForward", this, &ABlasterCharacter::MoveForward);
|
||||
PlayerInputComponent->BindAxis("MoveRight", this, &ABlasterCharacter::MoveRight);
|
||||
PlayerInputComponent->BindAxis("Turn", this, &ABlasterCharacter::Turn);
|
||||
PlayerInputComponent->BindAxis("LookUp", this, &ABlasterCharacter::LookUp);
|
||||
|
||||
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
|
||||
PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed);
|
||||
PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed);
|
||||
PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased);
|
||||
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed);
|
||||
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased);
|
||||
PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed);
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PostInitializeComponents()
|
||||
{
|
||||
Super::PostInitializeComponents();
|
||||
if (Combat)
|
||||
{
|
||||
Combat->Character = this;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayFireMontage(bool bAiming)
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && FireWeaponMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(FireWeaponMontage);
|
||||
FName SectionName;
|
||||
SectionName = bAiming ? FName("RifleADS") : FName("RifleHip");
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayReloadMontage()
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && ReloadMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(ReloadMontage);
|
||||
FName SectionName;
|
||||
|
||||
switch (Combat->EquippedWeapon->GetWeaponType())
|
||||
{
|
||||
case EWeaponType::EWT_AssaultRifle:
|
||||
SectionName = FName("Rifle");
|
||||
break;
|
||||
}
|
||||
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayEliminatedMontage()
|
||||
{
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && EliminatedMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(EliminatedMontage);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PlayHitReactMontage()
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||
if (AnimInstance && HitReactMontage)
|
||||
{
|
||||
AnimInstance->Montage_Play(HitReactMontage);
|
||||
FName SectionName("FromFront");
|
||||
AnimInstance->Montage_JumpToSection(SectionName);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, AActor* DamageCauser)
|
||||
{
|
||||
Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);
|
||||
UpdateHUDHealth();
|
||||
if (Health > 0.f)
|
||||
{
|
||||
PlayHitReactMontage();
|
||||
}
|
||||
|
||||
if (Health == 0.f)
|
||||
{
|
||||
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
|
||||
if (BlasterGameMode)
|
||||
{
|
||||
BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
|
||||
ABlasterPlayerController* AttackerController = Cast<ABlasterPlayerController>(InstigatorController);
|
||||
BlasterGameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::MoveForward(float Value)
|
||||
|
@ -317,7 +315,6 @@ void ABlasterCharacter::MoveForward(float Value)
|
|||
{
|
||||
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
|
||||
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X));
|
||||
|
||||
AddMovementInput(Direction, Value);
|
||||
}
|
||||
}
|
||||
|
@ -329,7 +326,6 @@ void ABlasterCharacter::MoveRight(float Value)
|
|||
{
|
||||
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
|
||||
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y));
|
||||
|
||||
AddMovementInput(Direction, Value);
|
||||
}
|
||||
}
|
||||
|
@ -360,13 +356,9 @@ void ABlasterCharacter::EquipButtonPressed()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::ReloadButtonPressed()
|
||||
void ABlasterCharacter::ServerEquipButtonPressed_Implementation()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
if (Combat)
|
||||
{
|
||||
Combat->Reload();
|
||||
}
|
||||
EquipButtonPressed();
|
||||
}
|
||||
|
||||
void ABlasterCharacter::CrouchButtonPressed()
|
||||
|
@ -382,6 +374,15 @@ void ABlasterCharacter::CrouchButtonPressed()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::ReloadButtonPressed()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
if (Combat)
|
||||
{
|
||||
Combat->Reload();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::AimButtonPressed()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
|
@ -400,47 +401,24 @@ void ABlasterCharacter::AimButtonReleased()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::Jump()
|
||||
float ABlasterCharacter::CalculateSpeed()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
if (bIsCrouched)
|
||||
{
|
||||
UnCrouch();
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::Jump();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::FireButtonPressed()
|
||||
{
|
||||
if (Combat)
|
||||
{
|
||||
Combat->FireButtonPressed(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::FireButtonReleased()
|
||||
{
|
||||
if (Combat)
|
||||
{
|
||||
Combat->FireButtonPressed(false);
|
||||
}
|
||||
FVector Velocity = GetVelocity();
|
||||
Velocity.Z = 0.f;
|
||||
return Velocity.Size();
|
||||
}
|
||||
|
||||
void ABlasterCharacter::AimOffset(float DeltaTime)
|
||||
{
|
||||
if (Combat && Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
const float Speed = CalculateSpeed();
|
||||
const bool bIsInAir = GetCharacterMovement()->IsFalling();
|
||||
float Speed = CalculateSpeed();
|
||||
bool bIsInAir = GetCharacterMovement()->IsFalling();
|
||||
|
||||
if (Speed == 0.f && !bIsInAir) // Standing still, not jumping
|
||||
{
|
||||
bRotateRootBone = true;
|
||||
const FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);
|
||||
const FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation);
|
||||
FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);
|
||||
FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation);
|
||||
AO_Yaw = DeltaAimRotation.Yaw;
|
||||
if (TurningInPlace == ETurningInPlace::ETIP_NotTurning)
|
||||
{
|
||||
|
@ -464,13 +442,11 @@ void ABlasterCharacter::AimOffset(float DeltaTime)
|
|||
void ABlasterCharacter::CalculateAO_Pitch()
|
||||
{
|
||||
AO_Pitch = GetBaseAimRotation().Pitch;
|
||||
|
||||
// Fix pitch/yaw compression
|
||||
if (AO_Pitch > 90.f && !IsLocallyControlled())
|
||||
{
|
||||
// map pitch from [270, 360) to [-90, 0)
|
||||
const FVector2d InRange(270.f, 360.f);
|
||||
const FVector2d OutRange(-90.f, 0.f);
|
||||
FVector2D InRange(270.f, 360.f);
|
||||
FVector2D OutRange(-90.f, 0.f);
|
||||
AO_Pitch = FMath::GetMappedRangeValueClamped(InRange, OutRange, AO_Pitch);
|
||||
}
|
||||
}
|
||||
|
@ -478,10 +454,8 @@ void ABlasterCharacter::CalculateAO_Pitch()
|
|||
void ABlasterCharacter::SimProxiesTurn()
|
||||
{
|
||||
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
|
||||
|
||||
bRotateRootBone = false;
|
||||
|
||||
const float Speed = CalculateSpeed();
|
||||
float Speed = CalculateSpeed();
|
||||
if (Speed > 0.f)
|
||||
{
|
||||
TurningInPlace = ETurningInPlace::ETIP_NotTurning;
|
||||
|
@ -508,13 +482,39 @@ void ABlasterCharacter::SimProxiesTurn()
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TurningInPlace = ETurningInPlace::ETIP_NotTurning;
|
||||
|
||||
}
|
||||
|
||||
void ABlasterCharacter::ServerEquipButtonPressed_Implementation()
|
||||
void ABlasterCharacter::Jump()
|
||||
{
|
||||
EquipButtonPressed();
|
||||
if (bDisableGameplay) return;
|
||||
if (bIsCrouched)
|
||||
{
|
||||
UnCrouch();
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::Jump();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::FireButtonPressed()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
if (Combat)
|
||||
{
|
||||
Combat->FireButtonPressed(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::FireButtonReleased()
|
||||
{
|
||||
if (bDisableGameplay) return;
|
||||
if (Combat)
|
||||
{
|
||||
Combat->FireButtonPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::TurnInPlace(float DeltaTime)
|
||||
|
@ -537,18 +537,6 @@ void ABlasterCharacter::TurnInPlace(float DeltaTime)
|
|||
StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);
|
||||
}
|
||||
}
|
||||
// switch (TurningInPlace)
|
||||
// {
|
||||
// case ETurningInPlace::ETIP_Left:
|
||||
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Left"));
|
||||
// break;
|
||||
// case ETurningInPlace::ETIP_Right:
|
||||
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Right"));
|
||||
// break;
|
||||
// case ETurningInPlace::ETIP_NotTurning:
|
||||
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: NotTurning"));
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
void ABlasterCharacter::HideCameraIfCharacterClose()
|
||||
|
@ -572,13 +560,6 @@ void ABlasterCharacter::HideCameraIfCharacterClose()
|
|||
}
|
||||
}
|
||||
|
||||
float ABlasterCharacter::CalculateSpeed()
|
||||
{
|
||||
FVector Velocity = GetVelocity();
|
||||
Velocity.Z = 0.f;
|
||||
return Velocity.Size();
|
||||
}
|
||||
|
||||
void ABlasterCharacter::OnRep_Health()
|
||||
{
|
||||
UpdateHUDHealth();
|
||||
|
@ -597,6 +578,20 @@ void ABlasterCharacter::UpdateHUDHealth()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::PollInit()
|
||||
{
|
||||
if (BlasterPlayerState == nullptr)
|
||||
{
|
||||
BlasterPlayerState = GetPlayerState<ABlasterPlayerState>();
|
||||
if (BlasterPlayerState)
|
||||
{
|
||||
// Initialize Score now we have the PlayerState
|
||||
BlasterPlayerState->IncreaseScore(0.f);
|
||||
BlasterPlayerState->IncreaseDefeats(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::UpdateDissolveMaterial(float DissolveValue)
|
||||
{
|
||||
if (DynamicDissolveMaterialInstance)
|
||||
|
@ -621,7 +616,6 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
|
|||
{
|
||||
OverlappingWeapon->ShowPickupWidget(false);
|
||||
}
|
||||
|
||||
OverlappingWeapon = Weapon;
|
||||
if (IsLocallyControlled())
|
||||
{
|
||||
|
@ -632,6 +626,18 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon)
|
||||
{
|
||||
if (OverlappingWeapon)
|
||||
{
|
||||
OverlappingWeapon->ShowPickupWidget(true);
|
||||
}
|
||||
if (LastWeapon)
|
||||
{
|
||||
LastWeapon->ShowPickupWidget(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ABlasterCharacter::IsWeaponEquipped()
|
||||
{
|
||||
return Combat && Combat->EquippedWeapon;
|
||||
|
@ -645,14 +651,12 @@ bool ABlasterCharacter::IsAiming()
|
|||
AWeapon* ABlasterCharacter::GetEquippedWeapon()
|
||||
{
|
||||
if (Combat == nullptr) return nullptr;
|
||||
|
||||
return Combat->EquippedWeapon;
|
||||
}
|
||||
|
||||
FVector ABlasterCharacter::GetHitTarget() const
|
||||
{
|
||||
if (Combat == nullptr) return FVector();
|
||||
|
||||
return Combat->HitTarget;
|
||||
}
|
||||
|
||||
|
@ -661,15 +665,3 @@ ECombatState ABlasterCharacter::GetCombatState() const
|
|||
if (Combat == nullptr) return ECombatState::ECS_MAX;
|
||||
return Combat->CombatState;
|
||||
}
|
||||
|
||||
void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon)
|
||||
{
|
||||
if (OverlappingWeapon)
|
||||
{
|
||||
OverlappingWeapon->ShowPickupWidget(true);
|
||||
}
|
||||
if (LastWeapon)
|
||||
{
|
||||
LastWeapon->ShowPickupWidget(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ void UCombatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out
|
|||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(UCombatComponent, EquippedWeapon);
|
||||
DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly);
|
||||
DOREPLIFETIME(UCombatComponent, bAiming);
|
||||
DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly);
|
||||
DOREPLIFETIME(UCombatComponent, CombatState);
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,273 @@ void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActo
|
|||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::FireButtonPressed(bool bPressed)
|
||||
{
|
||||
bFireButtonPressed = bPressed;
|
||||
if (bFireButtonPressed && EquippedWeapon)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::Fire()
|
||||
{
|
||||
if (CanFire())
|
||||
{
|
||||
bCanFire = false;
|
||||
ServerFire(HitTarget);
|
||||
if (EquippedWeapon)
|
||||
{
|
||||
CrosshairShootingFactor = .75f;
|
||||
}
|
||||
StartFireTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::StartFireTimer()
|
||||
{
|
||||
if (EquippedWeapon == nullptr || Character == nullptr) return;
|
||||
Character->GetWorldTimerManager().SetTimer(
|
||||
FireTimer,
|
||||
this,
|
||||
&UCombatComponent::FireTimerFinished,
|
||||
EquippedWeapon->FireDelay
|
||||
);
|
||||
}
|
||||
|
||||
void UCombatComponent::FireTimerFinished()
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return;
|
||||
bCanFire = true;
|
||||
if (bFireButtonPressed && EquippedWeapon->bAutomatic)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
if (EquippedWeapon->IsEmpty())
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
|
||||
{
|
||||
MulticastFire(TraceHitTarget);
|
||||
}
|
||||
|
||||
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return;
|
||||
if (Character && CombatState == ECombatState::ECS_Unoccupied)
|
||||
{
|
||||
Character->PlayFireMontage(bAiming);
|
||||
EquippedWeapon->Fire(TraceHitTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
|
||||
{
|
||||
if (Character == nullptr || WeaponToEquip == nullptr) return;
|
||||
if (EquippedWeapon)
|
||||
{
|
||||
EquippedWeapon->Dropped();
|
||||
}
|
||||
EquippedWeapon = WeaponToEquip;
|
||||
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
||||
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
|
||||
if (HandSocket)
|
||||
{
|
||||
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
|
||||
}
|
||||
EquippedWeapon->SetOwner(Character);
|
||||
EquippedWeapon->SetHUDAmmo();
|
||||
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
}
|
||||
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
||||
}
|
||||
|
||||
if (EquippedWeapon->EquipSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(
|
||||
this,
|
||||
EquippedWeapon->EquipSound,
|
||||
Character->GetActorLocation()
|
||||
);
|
||||
}
|
||||
|
||||
if (EquippedWeapon->IsEmpty())
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
|
||||
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
||||
Character->bUseControllerRotationYaw = true;
|
||||
}
|
||||
|
||||
void UCombatComponent::Reload()
|
||||
{
|
||||
if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading)
|
||||
{
|
||||
ServerReload();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::ServerReload_Implementation()
|
||||
{
|
||||
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
||||
|
||||
// return if weapon mag is at max capacity
|
||||
if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return;
|
||||
|
||||
CombatState = ECombatState::ECS_Reloading;
|
||||
HandleReload();
|
||||
}
|
||||
|
||||
void UCombatComponent::FinishedReloading()
|
||||
{
|
||||
if (Character == nullptr) return;
|
||||
if (Character->HasAuthority())
|
||||
{
|
||||
CombatState = ECombatState::ECS_Unoccupied;
|
||||
UpdateAmmoValues();
|
||||
}
|
||||
if (bFireButtonPressed)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::UpdateAmmoValues()
|
||||
{
|
||||
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
||||
int32 ReloadAmount = AmountToReload();
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount;
|
||||
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
}
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
||||
}
|
||||
EquippedWeapon->AddAmmo(-ReloadAmount);
|
||||
}
|
||||
|
||||
void UCombatComponent::OnRep_CombatState()
|
||||
{
|
||||
switch (CombatState)
|
||||
{
|
||||
case ECombatState::ECS_Reloading:
|
||||
HandleReload();
|
||||
break;
|
||||
case ECombatState::ECS_Unoccupied:
|
||||
if (bFireButtonPressed)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::HandleReload()
|
||||
{
|
||||
Character->PlayReloadMontage();
|
||||
}
|
||||
|
||||
int32 UCombatComponent::AmountToReload()
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return 0;
|
||||
int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
|
||||
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
int32 Least = FMath::Min(RoomInMag, AmountCarried);
|
||||
return FMath::Clamp(RoomInMag, 0, Least);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UCombatComponent::OnRep_EquippedWeapon()
|
||||
{
|
||||
if (EquippedWeapon && Character)
|
||||
{
|
||||
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
||||
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
|
||||
if (HandSocket)
|
||||
{
|
||||
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
|
||||
}
|
||||
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
||||
Character->bUseControllerRotationYaw = true;
|
||||
|
||||
if (EquippedWeapon->EquipSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(
|
||||
this,
|
||||
EquippedWeapon->EquipSound,
|
||||
Character->GetActorLocation()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult)
|
||||
{
|
||||
FVector2D ViewportSize;
|
||||
if (GEngine && GEngine->GameViewport)
|
||||
{
|
||||
GEngine->GameViewport->GetViewportSize(ViewportSize);
|
||||
}
|
||||
|
||||
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
|
||||
FVector CrosshairWorldPosition;
|
||||
FVector CrosshairWorldDirection;
|
||||
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
|
||||
UGameplayStatics::GetPlayerController(this, 0),
|
||||
CrosshairLocation,
|
||||
CrosshairWorldPosition,
|
||||
CrosshairWorldDirection
|
||||
);
|
||||
|
||||
if (bScreenToWorld)
|
||||
{
|
||||
FVector Start = CrosshairWorldPosition;
|
||||
|
||||
if (Character)
|
||||
{
|
||||
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
|
||||
Start += CrosshairWorldDirection * (DistanceToCharacter + 100.f);
|
||||
}
|
||||
|
||||
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
|
||||
|
||||
GetWorld()->LineTraceSingleByChannel(
|
||||
TraceHitResult,
|
||||
Start,
|
||||
End,
|
||||
ECollisionChannel::ECC_Visibility
|
||||
);
|
||||
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
|
||||
{
|
||||
HUDPackage.CrosshairsColor = FLinearColor::Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
HUDPackage.CrosshairsColor = FLinearColor::White;
|
||||
}
|
||||
|
||||
if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End;
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
|
||||
{
|
||||
if (Character == nullptr || Character->Controller == nullptr) return;
|
||||
|
@ -80,22 +347,22 @@ void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
|
|||
HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter;
|
||||
HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft;
|
||||
HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight;
|
||||
HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;
|
||||
HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom;
|
||||
HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;
|
||||
}
|
||||
else
|
||||
{
|
||||
HUDPackage.CrosshairsCenter = nullptr;
|
||||
HUDPackage.CrosshairsLeft = nullptr;
|
||||
HUDPackage.CrosshairsRight = nullptr;
|
||||
HUDPackage.CrosshairsTop = nullptr;
|
||||
HUDPackage.CrosshairsBottom = nullptr;
|
||||
HUDPackage.CrosshairsTop = nullptr;
|
||||
}
|
||||
|
||||
// Calculate crosshair spread
|
||||
// Velocity [0, 600] -> Spread [0, 1]
|
||||
const FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed);
|
||||
const FVector2D VelocityMultiplierRange(0.f, 1.f);
|
||||
|
||||
// [0, 600] -> [0, 1]
|
||||
FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed);
|
||||
FVector2D VelocityMultiplierRange(0.f, 1.f);
|
||||
FVector Velocity = Character->GetVelocity();
|
||||
Velocity.Z = 0.f;
|
||||
|
||||
|
@ -170,59 +437,9 @@ void UCombatComponent::ServerSetAiming_Implementation(bool bIsAiming)
|
|||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::Fire()
|
||||
{
|
||||
if (CanFire())
|
||||
{
|
||||
bCanFire = false;
|
||||
ServerFire(HitTarget);
|
||||
|
||||
if (EquippedWeapon)
|
||||
{
|
||||
CrosshairShootingFactor = 0.75f;
|
||||
}
|
||||
|
||||
StartFireTimer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UCombatComponent::FireButtonPressed(bool bPressed)
|
||||
{
|
||||
bFireButtonPressed = bPressed;
|
||||
|
||||
if (bFireButtonPressed && EquippedWeapon)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::StartFireTimer()
|
||||
{
|
||||
if (EquippedWeapon == nullptr || Character == nullptr) return;
|
||||
|
||||
Character->GetWorldTimerManager().SetTimer(FireTimer, this, &UCombatComponent::FireTimerFinished, EquippedWeapon->FireDelay);
|
||||
}
|
||||
|
||||
void UCombatComponent::FireTimerFinished()
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return;
|
||||
|
||||
bCanFire = true;
|
||||
if (bFireButtonPressed && EquippedWeapon->bAutomatic)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
if (EquippedWeapon->IsEmpty())
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
|
||||
bool UCombatComponent::CanFire()
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return false;
|
||||
|
||||
return !EquippedWeapon->IsEmpty() && bCanFire && CombatState == ECombatState::ECS_Unoccupied;
|
||||
}
|
||||
|
||||
|
@ -239,212 +456,3 @@ void UCombatComponent::InitializeCarriedAmmo()
|
|||
{
|
||||
CarriedAmmoMap.Emplace(EWeaponType::EWT_AssaultRifle, StartingARAmmo);
|
||||
}
|
||||
|
||||
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
|
||||
{
|
||||
MulticastFire(TraceHitTarget);
|
||||
}
|
||||
|
||||
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return;
|
||||
if (Character && CombatState == ECombatState::ECS_Unoccupied)
|
||||
{
|
||||
Character->PlayFireMontage(bAiming);
|
||||
EquippedWeapon->Fire(TraceHitTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult)
|
||||
{
|
||||
FVector2d ViewPortSize;
|
||||
if (GEngine && GEngine->GameViewport)
|
||||
{
|
||||
GEngine->GameViewport->GetViewportSize(ViewPortSize);
|
||||
}
|
||||
|
||||
FVector2d CrosshairLocation(ViewPortSize.X / 2.f, ViewPortSize.Y / 2.0f);
|
||||
FVector CrosshairWorldPosition;
|
||||
FVector CrosshairWorldDirection;
|
||||
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
|
||||
UGameplayStatics::GetPlayerController(this, 0),
|
||||
CrosshairLocation,
|
||||
CrosshairWorldPosition,
|
||||
CrosshairWorldDirection
|
||||
);
|
||||
|
||||
if (bScreenToWorld)
|
||||
{
|
||||
FVector Start = CrosshairWorldPosition;
|
||||
if (Character)
|
||||
{
|
||||
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
|
||||
Start += CrosshairWorldDirection * (DistanceToCharacter + 60.f);
|
||||
}
|
||||
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
|
||||
|
||||
GetWorld()->LineTraceSingleByChannel(
|
||||
TraceHitResult,
|
||||
Start,
|
||||
End,
|
||||
ECollisionChannel::ECC_Visibility
|
||||
);
|
||||
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
|
||||
{
|
||||
HUDPackage.CrosshairColor = FLinearColor::Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
HUDPackage.CrosshairColor = FLinearColor::White;
|
||||
}
|
||||
|
||||
if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End;
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
|
||||
{
|
||||
if (Character == nullptr || WeaponToEquip == nullptr) return;
|
||||
if (EquippedWeapon)
|
||||
{
|
||||
EquippedWeapon->Dropped();
|
||||
}
|
||||
EquippedWeapon = WeaponToEquip;
|
||||
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
||||
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
|
||||
if (HandSocket)
|
||||
{
|
||||
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
|
||||
}
|
||||
EquippedWeapon->SetOwner(Character);
|
||||
EquippedWeapon->SetHUDAmmo();
|
||||
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
}
|
||||
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
||||
}
|
||||
|
||||
if (EquippedWeapon->EquipSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation());
|
||||
}
|
||||
|
||||
if (EquippedWeapon->IsEmpty())
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
||||
Character->bUseControllerRotationYaw = true;
|
||||
}
|
||||
|
||||
void UCombatComponent::Reload()
|
||||
{
|
||||
if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading)
|
||||
{
|
||||
ServerReload();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::FinishedReloading()
|
||||
{
|
||||
if (Character == nullptr) return;
|
||||
if (Character->HasAuthority())
|
||||
{
|
||||
CombatState = ECombatState::ECS_Unoccupied;
|
||||
UpdateAmmoValues();
|
||||
}
|
||||
if (bFireButtonPressed)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::UpdateAmmoValues()
|
||||
{
|
||||
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
||||
const int32 ReloadAmount = AmountToReload();
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount;
|
||||
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
}
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
||||
}
|
||||
EquippedWeapon->AddAmmo(-ReloadAmount);
|
||||
}
|
||||
|
||||
void UCombatComponent::ServerReload_Implementation()
|
||||
{
|
||||
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
||||
|
||||
// return if weapon mag is at max capacity
|
||||
if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return;
|
||||
|
||||
CombatState = ECombatState::ECS_Reloading;
|
||||
HandleReload();
|
||||
}
|
||||
|
||||
void UCombatComponent::OnRep_CombatState()
|
||||
{
|
||||
switch (CombatState)
|
||||
{
|
||||
case ECombatState::ECS_Reloading:
|
||||
HandleReload();
|
||||
break;
|
||||
case ECombatState::ECS_Unoccupied:
|
||||
if (bFireButtonPressed)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UCombatComponent::HandleReload()
|
||||
{
|
||||
Character->PlayReloadMontage();
|
||||
}
|
||||
|
||||
int32 UCombatComponent::AmountToReload()
|
||||
{
|
||||
if (EquippedWeapon == nullptr) return 0;
|
||||
|
||||
const int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
|
||||
|
||||
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
||||
{
|
||||
const int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
||||
const int32 Least = FMath::Min(RoomInMag, AmountCarried);
|
||||
return FMath::Clamp(RoomInMag, 0, Least);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UCombatComponent::OnRep_EquippedWeapon()
|
||||
{
|
||||
if (EquippedWeapon && Character)
|
||||
{
|
||||
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
||||
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
|
||||
if (HandSocket)
|
||||
{
|
||||
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
|
||||
}
|
||||
if (EquippedWeapon->EquipSound)
|
||||
{
|
||||
UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation());
|
||||
}
|
||||
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
||||
Character->bUseControllerRotationYaw = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,30 +27,30 @@ void ABlasterGameMode::BeginPlay()
|
|||
LevelStartingTime = GetWorld()->GetTimeSeconds();
|
||||
}
|
||||
|
||||
void ABlasterGameMode::Tick(float DeltaSeconds)
|
||||
void ABlasterGameMode::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
if (MatchState == MatchState::WaitingToStart)
|
||||
{
|
||||
CountDownTime = WarmupTime - GetWorld()->GetTimeSeconds() + LevelStartingTime;
|
||||
if (CountDownTime <= 0.f)
|
||||
CountdownTime = WarmupTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
|
||||
if (CountdownTime <= 0.f)
|
||||
{
|
||||
StartMatch();
|
||||
}
|
||||
}
|
||||
else if (MatchState == MatchState::InProgress)
|
||||
{
|
||||
CountDownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime;
|
||||
if (CountDownTime <= 0.f)
|
||||
CountdownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
|
||||
if (CountdownTime <= 0.f)
|
||||
{
|
||||
SetMatchState(MatchState::Cooldown);
|
||||
}
|
||||
}
|
||||
else if (MatchState == MatchState::Cooldown)
|
||||
{
|
||||
CountDownTime = WarmupTime + MatchTime + CooldownTime - GetWorld()->GetTimeSeconds() + LevelStartingTime;
|
||||
if (CountDownTime <= 0.f)
|
||||
CountdownTime = WarmupTime + MatchTime + CooldownTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
|
||||
if (CountdownTime <= 0.f)
|
||||
{
|
||||
RestartGame();
|
||||
}
|
||||
|
@ -61,19 +61,20 @@ void ABlasterGameMode::OnMatchStateSet()
|
|||
{
|
||||
Super::OnMatchStateSet();
|
||||
|
||||
for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
|
||||
for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
|
||||
{
|
||||
ABlasterPlayerController* PlayerController = Cast<ABlasterPlayerController>(*Iterator);
|
||||
if (PlayerController)
|
||||
ABlasterPlayerController* BlasterPlayer = Cast<ABlasterPlayerController>(*It);
|
||||
if (BlasterPlayer)
|
||||
{
|
||||
PlayerController->OnMatchStateSet(MatchState);
|
||||
BlasterPlayer->OnMatchStateSet(MatchState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterGameMode::PlayerEliminated(ABlasterCharacter* EliminatedCharacter, ABlasterPlayerController* VictimController,
|
||||
ABlasterPlayerController* AttackerController)
|
||||
void ABlasterGameMode::PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController, ABlasterPlayerController* AttackerController)
|
||||
{
|
||||
if (AttackerController == nullptr || AttackerController->PlayerState == nullptr) return;
|
||||
if (VictimController == nullptr || VictimController->PlayerState == nullptr) return;
|
||||
ABlasterPlayerState* AttackerPlayerState = AttackerController ? Cast<ABlasterPlayerState>(AttackerController->PlayerState) : nullptr;
|
||||
ABlasterPlayerState* VictimPlayerState = VictimController ? Cast<ABlasterPlayerState>(VictimController->PlayerState) : nullptr;
|
||||
|
||||
|
@ -99,12 +100,11 @@ void ABlasterGameMode::RequestRespawn(ACharacter* EliminatedCharacter, AControll
|
|||
EliminatedCharacter->Reset();
|
||||
EliminatedCharacter->Destroy();
|
||||
}
|
||||
|
||||
if (EliminatedController)
|
||||
{
|
||||
TArray<AActor*> PlayerStarts;
|
||||
UGameplayStatics::GetAllActorsOfClass(this, APlayerStart::StaticClass(), PlayerStarts);
|
||||
const int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1);
|
||||
int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1);
|
||||
RestartPlayerAtPlayerStart(EliminatedController, PlayerStarts[Selection]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class BLASTER_API ABlasterGameMode : public AGameMode
|
|||
|
||||
public:
|
||||
ABlasterGameMode();
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
virtual void PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController,
|
||||
class ABlasterPlayerController* AttackerController);
|
||||
virtual void RequestRespawn(ACharacter* EliminatedCharacter, AController* EliminatedController);
|
||||
|
@ -43,8 +43,8 @@ protected:
|
|||
virtual void OnMatchStateSet() override;
|
||||
|
||||
private:
|
||||
float CountDownTime = 0.f;
|
||||
float CountdownTime = 0.f;
|
||||
|
||||
public:
|
||||
FORCEINLINE float GetCountdownTime() const { return CountDownTime; }
|
||||
FORCEINLINE float GetCountdownTime() const { return CountdownTime; }
|
||||
};
|
||||
|
|
|
@ -5,13 +5,25 @@
|
|||
|
||||
#include "Announcement.h"
|
||||
#include "CharacterOverlay.h"
|
||||
#include "DebugWidget.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Components/TextBlock.h"
|
||||
|
||||
void ABlasterHUD::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void ABlasterHUD::AddDebugWidget()
|
||||
{
|
||||
APlayerController* PlayerController = GetOwningPlayerController();
|
||||
if (PlayerController && DebugWidgetClass)
|
||||
{
|
||||
DebugWidget = CreateWidget<UDebugWidget>(PlayerController, DebugWidgetClass);
|
||||
DebugWidget->AddToViewport();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterHUD::AddCharacterOverlay()
|
||||
{
|
||||
APlayerController* PlayerController = GetOwningPlayerController();
|
||||
|
@ -46,27 +58,27 @@ void ABlasterHUD::DrawHUD()
|
|||
if (HUDPackage.CrosshairsCenter)
|
||||
{
|
||||
const FVector2D Spread(0.f, 0.f);
|
||||
DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairColor);
|
||||
DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
|
||||
}
|
||||
if (HUDPackage.CrosshairsLeft)
|
||||
{
|
||||
const FVector2D Spread(-SpreadScaled, 0.f);
|
||||
DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairColor);
|
||||
DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
|
||||
}
|
||||
if (HUDPackage.CrosshairsRight)
|
||||
{
|
||||
const FVector2D Spread(SpreadScaled, 0.f);
|
||||
DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairColor);
|
||||
DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
|
||||
}
|
||||
if (HUDPackage.CrosshairsTop)
|
||||
{
|
||||
const FVector2D Spread(0.f, -SpreadScaled);
|
||||
DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairColor);
|
||||
DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
|
||||
}
|
||||
if (HUDPackage.CrosshairsBottom)
|
||||
{
|
||||
const FVector2D Spread(0.f, SpreadScaled);
|
||||
DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairColor);
|
||||
DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
UTexture2D* CrosshairsTop;
|
||||
UTexture2D* CrosshairsBottom;
|
||||
float CrosshairSpread;
|
||||
FLinearColor CrosshairColor;
|
||||
FLinearColor CrosshairsColor;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@ class BLASTER_API ABlasterHUD : public AHUD
|
|||
|
||||
public:
|
||||
virtual void DrawHUD() override;
|
||||
void AddDebugWidget();
|
||||
void AddCharacterOverlay();
|
||||
void AddAnnouncementOverlay();
|
||||
|
||||
|
@ -40,6 +41,12 @@ public:
|
|||
UPROPERTY()
|
||||
class UCharacterOverlay* CharacterOverlay;
|
||||
|
||||
UPROPERTY()
|
||||
class UDebugWidget* DebugWidget;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Widget")
|
||||
TSubclassOf<class UUserWidget> DebugWidgetClass;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Announcements")
|
||||
TSubclassOf<class UUserWidget> AnnouncementClass;
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "DebugWidget.h"
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "DebugWidget.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class BLASTER_API UDebugWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
class UTextBlock* DebugMsg1;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg2;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg3;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg4;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg5;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg6;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* DebugMsg7;
|
||||
|
||||
|
||||
};
|
|
@ -9,6 +9,7 @@
|
|||
#include "Blaster/HUD/Announcement.h"
|
||||
#include "Blaster/HUD/BlasterHUD.h"
|
||||
#include "Blaster/HUD/CharacterOverlay.h"
|
||||
#include "Blaster/HUD/DebugWidget.h"
|
||||
#include "Components/ProgressBar.h"
|
||||
#include "Components/TextBlock.h"
|
||||
#include "GameFramework/GameMode.h"
|
||||
|
@ -31,38 +32,69 @@ void ABlasterPlayerController::GetLifetimeReplicatedProps(TArray<FLifetimeProper
|
|||
DOREPLIFETIME(ABlasterPlayerController, MatchState);
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::Tick(float DeltaSeconds)
|
||||
void ABlasterPlayerController::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
SetHUDTime();
|
||||
CheckTimeSync(DeltaSeconds);
|
||||
CheckTimeSync(DeltaTime);
|
||||
PollInit();
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::OnPossess(APawn* InPawn)
|
||||
{
|
||||
Super::OnPossess(InPawn);
|
||||
|
||||
if (const ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(InPawn))
|
||||
if (DebugWidget)
|
||||
{
|
||||
SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth());
|
||||
SetDebugMsg1(TEXT("GetWorld()->GetTimeSeconds(): "), FString::Printf(TEXT("%02f"), GetWorld()->GetTimeSeconds()));
|
||||
SetDebugMsg2(TEXT("GetServerTime(): "), FString::Printf(TEXT("%02f"), GetServerTime()));
|
||||
SetDebugMsg3(TEXT("ClientServerDelta: "), FString::Printf(TEXT("%f"), ClientServerDelta));
|
||||
SetDebugMsg4(TEXT("LevelStartingTime: "), FString::Printf(TEXT("%f"), LevelStartingTime));
|
||||
SetDebugMsg5(TEXT("CountdownInt: "), FString::Printf(TEXT("%d"), CountdownInt));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ReceivedPlayer()
|
||||
void ABlasterPlayerController::SetDebugMsg1(FString Key, FString Value)
|
||||
{
|
||||
Super::ReceivedPlayer();
|
||||
|
||||
if (IsLocalController())
|
||||
{
|
||||
ServerRequestServerTime(GetWorld()->GetTimeSeconds());
|
||||
}
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg1;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg1->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds)
|
||||
void ABlasterPlayerController::SetDebugMsg2(FString Key, FString Value)
|
||||
{
|
||||
TimeSyncRunningTime += DeltaSeconds;
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg2;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg2->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetDebugMsg3(FString Key, FString Value)
|
||||
{
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg3;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg3->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetDebugMsg4(FString Key, FString Value)
|
||||
{
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg4;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg4->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetDebugMsg5(FString Key, FString Value)
|
||||
{
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg5;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg5->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetDebugMsg6(FString Key, FString Value)
|
||||
{
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg6;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg6->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetDebugMsg7(FString Key, FString Value)
|
||||
{
|
||||
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg7;
|
||||
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg7->SetText(FText::FromString(Key.Append(Value)));
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::CheckTimeSync(float DeltaTime)
|
||||
{
|
||||
TimeSyncRunningTime += DeltaTime;
|
||||
if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency)
|
||||
{
|
||||
ServerRequestServerTime(GetWorld()->GetTimeSeconds());
|
||||
|
@ -70,51 +102,257 @@ void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds)
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ServerCheckMatchState_Implementation()
|
||||
{
|
||||
ABlasterGameMode* GameMode = Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this));
|
||||
if (GameMode)
|
||||
{
|
||||
WarmupTime = GameMode->WarmupTime;
|
||||
MatchTime = GameMode->MatchTime;
|
||||
CooldownTime = GameMode->CooldownTime;
|
||||
LevelStartingTime = GameMode->LevelStartingTime;
|
||||
MatchState = GameMode->GetMatchState();
|
||||
ClientJoinMidgame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ClientJoinMidgame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime)
|
||||
{
|
||||
WarmupTime = Warmup;
|
||||
MatchTime = Match;
|
||||
CooldownTime = Cooldown;
|
||||
LevelStartingTime = StartingTime;
|
||||
MatchState = StateOfMatch;
|
||||
OnMatchStateSet(MatchState);
|
||||
if (BlasterHUD && MatchState == MatchState::WaitingToStart)
|
||||
{
|
||||
BlasterHUD->AddAnnouncementOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::OnPossess(APawn* InPawn)
|
||||
{
|
||||
Super::OnPossess(InPawn);
|
||||
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(InPawn);
|
||||
if (BlasterCharacter)
|
||||
{
|
||||
SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth());
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->HealthBar &&
|
||||
BlasterHUD->CharacterOverlay->HealthText;
|
||||
if (bHUDValid)
|
||||
{
|
||||
const float HealthPercent = Health / MaxHealth;
|
||||
BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent);
|
||||
FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth));
|
||||
BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDHealth = Health;
|
||||
HUDMaxHealth = MaxHealth;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDScore(float Score)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->ScoreValue;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
FString ScoreText = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score));
|
||||
BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreText));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDScore = Score;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDDefeats(int32 Defeats)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->DefeatsValue;
|
||||
if (bHUDValid)
|
||||
{
|
||||
FString DefeatsText = FString::Printf(TEXT("%d"), Defeats);
|
||||
BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsText));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDDefeats = Defeats;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->WeaponAmmoValue;
|
||||
if (bHUDValid)
|
||||
{
|
||||
FString AmmoText = FString::Printf(TEXT("%d"), Ammo);
|
||||
BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(AmmoText));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->CarriedAmmoValue;
|
||||
if (bHUDValid)
|
||||
{
|
||||
FString AmmoText = FString::Printf(TEXT("%d"), Ammo);
|
||||
BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(AmmoText));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->CharacterOverlay &&
|
||||
BlasterHUD->CharacterOverlay->MatchCountdownText;
|
||||
if (bHUDValid)
|
||||
{
|
||||
if (CountdownTime < 0.f)
|
||||
{
|
||||
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText());
|
||||
return;
|
||||
}
|
||||
|
||||
int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f);
|
||||
int32 Seconds = CountdownTime - Minutes * 60;
|
||||
|
||||
FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
|
||||
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = BlasterHUD &&
|
||||
BlasterHUD->Announcement &&
|
||||
BlasterHUD->Announcement->CountdownText;
|
||||
if (bHUDValid)
|
||||
{
|
||||
if (CountdownTime < 0.f)
|
||||
{
|
||||
BlasterHUD->Announcement->CountdownText->SetText(FText());
|
||||
return;
|
||||
}
|
||||
|
||||
int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f);
|
||||
int32 Seconds = CountdownTime - Minutes * 60;
|
||||
|
||||
FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
|
||||
BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDTime()
|
||||
{
|
||||
float TimeLeft = 0.f;
|
||||
if (MatchState == MatchState::WaitingToStart) TimeLeft = WarmupTime - GetServerTime(); // + LevelStartingTime;
|
||||
else if (MatchState == MatchState::InProgress) TimeLeft = WarmupTime + MatchTime - GetServerTime(); // + LevelStartingTime;
|
||||
else if (MatchState == MatchState::Cooldown) TimeLeft = WarmupTime + MatchTime + CooldownTime - GetServerTime(); // + LevelStartingTime;
|
||||
|
||||
uint32 SecondsLeft = FMath::CeilToInt(TimeLeft);
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
BlasterGameMode = BlasterGameMode == nullptr ? Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this)) : BlasterGameMode;
|
||||
if (BlasterGameMode)
|
||||
{
|
||||
SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (CountdownInt != SecondsLeft)
|
||||
{
|
||||
if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown)
|
||||
{
|
||||
SetHUDAnnouncementCountdown(TimeLeft);
|
||||
}
|
||||
if (MatchState == MatchState::InProgress)
|
||||
{
|
||||
SetHUDMatchCountdown(TimeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
CountdownInt = SecondsLeft;
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::PollInit()
|
||||
{
|
||||
if (BlasterHUD && BlasterHUD->DebugWidget == nullptr)
|
||||
{
|
||||
BlasterHUD->AddDebugWidget();
|
||||
if (BlasterHUD->DebugWidget)
|
||||
{
|
||||
DebugWidget = BlasterHUD->DebugWidget;
|
||||
}
|
||||
}
|
||||
|
||||
if (CharacterOverlay == nullptr)
|
||||
{
|
||||
if (BlasterHUD && BlasterHUD->CharacterOverlay)
|
||||
{
|
||||
CharacterOverlay = BlasterHUD->CharacterOverlay;
|
||||
if (CharacterOverlay)
|
||||
{
|
||||
SetHUDHealth(HUDHealth, HUDMaxHealth);
|
||||
SetHUDScore(HUDScore);
|
||||
SetHUDDefeats(HUDDefeats);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest)
|
||||
{
|
||||
float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds();
|
||||
ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt);
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest)
|
||||
{
|
||||
float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest;
|
||||
float CurrentServerTime = TimeServerReceivedClientRequest + 0.5f * RoundTripTime;
|
||||
ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds();
|
||||
}
|
||||
|
||||
float ABlasterPlayerController::GetServerTime()
|
||||
{
|
||||
if (HasAuthority()) return GetWorld()->GetTimeSeconds();
|
||||
|
||||
return GetWorld()->GetTimeSeconds() + ClientServerDelta;
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::HandleMatchHasStarted()
|
||||
void ABlasterPlayerController::ReceivedPlayer()
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
if (BlasterHUD)
|
||||
Super::ReceivedPlayer();
|
||||
if (IsLocalController())
|
||||
{
|
||||
BlasterHUD->AddCharacterOverlay();
|
||||
if (BlasterHUD->Announcement)
|
||||
{
|
||||
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::HandleCooldown()
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
if (BlasterHUD)
|
||||
{
|
||||
BlasterHUD->CharacterOverlay->RemoveFromParent();
|
||||
bool bHUDValid =
|
||||
BlasterHUD->Announcement &&
|
||||
BlasterHUD->Announcement->AnnouncementText &&
|
||||
BlasterHUD->Announcement->AnnouncementMessage;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
const FString AnnouncementText("New match starts in:");
|
||||
BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText));
|
||||
BlasterHUD->Announcement->AnnouncementMessage->SetText(FText());
|
||||
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
}
|
||||
|
||||
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(GetPawn());
|
||||
if (BlasterCharacter && BlasterCharacter->GetCombat())
|
||||
{
|
||||
BlasterCharacter->bDisableGameplay = true;
|
||||
BlasterCharacter->GetCombat()->FireButtonPressed(false);
|
||||
ServerRequestServerTime(GetWorld()->GetTimeSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,211 +382,45 @@ void ABlasterPlayerController::OnRep_MatchState()
|
|||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ServerCheckMatchState_Implementation()
|
||||
void ABlasterPlayerController::HandleMatchHasStarted()
|
||||
{
|
||||
ABlasterGameMode* GameMode = Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this));
|
||||
if (GameMode)
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
if (BlasterHUD)
|
||||
{
|
||||
LevelStartingTime = GameMode->LevelStartingTime;
|
||||
WarmupTime = GameMode->WarmupTime;
|
||||
MatchTime = GameMode->MatchTime;
|
||||
CooldownTime = GameMode->CooldownTime;
|
||||
MatchState = GameMode->GetMatchState();
|
||||
ClientJoinMidGame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ABlasterPlayerController::ClientJoinMidGame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime)
|
||||
{
|
||||
LevelStartingTime = StartingTime;
|
||||
WarmupTime = Warmup;
|
||||
MatchTime = Match;
|
||||
CooldownTime = Cooldown;
|
||||
MatchState = StateOfMatch;
|
||||
OnMatchStateSet(MatchState);
|
||||
|
||||
if (BlasterHUD && MatchState == MatchState::WaitingToStart)
|
||||
{
|
||||
BlasterHUD->AddAnnouncementOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest)
|
||||
{
|
||||
const float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds();
|
||||
ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt);
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest)
|
||||
{
|
||||
const float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest;
|
||||
const float CurrentServerTime = TimeServerReceivedClientRequest + 0.5f * RoundTripTime;
|
||||
|
||||
ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds();
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDTime()
|
||||
{
|
||||
float TimeLeft = 0.f;
|
||||
if (MatchState == MatchState::WaitingToStart) TimeLeft = WarmupTime - GetServerTime() + LevelStartingTime;
|
||||
else if (MatchState == MatchState::InProgress) TimeLeft = WarmupTime + MatchTime - GetServerTime() + LevelStartingTime;
|
||||
else if (MatchState == MatchState::Cooldown) TimeLeft = WarmupTime + MatchTime + CooldownTime - GetServerTime() + LevelStartingTime;
|
||||
uint32 SecondsLeft = FMath::CeilToInt(TimeLeft);
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
BlasterGameMode = BlasterGameMode == nullptr ? Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this)) : BlasterGameMode;
|
||||
if (BlasterGameMode)
|
||||
BlasterHUD->AddCharacterOverlay();
|
||||
if (BlasterHUD->Announcement)
|
||||
{
|
||||
SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime() + LevelStartingTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (CountdownInt != SecondsLeft)
|
||||
{
|
||||
if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown) SetHUDAnnouncementCountdown(TimeLeft);
|
||||
if (MatchState == MatchState::InProgress) SetHUDMatchCountdown(TimeLeft);
|
||||
}
|
||||
|
||||
CountdownInt = SecondsLeft;
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::PollInit()
|
||||
{
|
||||
if (CharacterOverlay == nullptr)
|
||||
{
|
||||
if (BlasterHUD && BlasterHUD->CharacterOverlay)
|
||||
{
|
||||
CharacterOverlay = BlasterHUD->CharacterOverlay;
|
||||
if (CharacterOverlay)
|
||||
{
|
||||
SetHUDHealth(HUDHealth, HUDMaxHealth);
|
||||
SetHUDScore(HUDScore);
|
||||
SetHUDDefeats(HUDDefeats);
|
||||
}
|
||||
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth)
|
||||
void ABlasterPlayerController::HandleCooldown()
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->HealthBar && CharacterOverlay->HealthText;
|
||||
|
||||
if (bHUDValid)
|
||||
if (BlasterHUD)
|
||||
{
|
||||
const float HealthPercent = Health / MaxHealth;
|
||||
BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent);
|
||||
const FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth));
|
||||
BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDHealth = Health;
|
||||
HUDMaxHealth = MaxHealth;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDScore(float Score)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->ScoreValue;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
const FString ScoreAmount = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score));
|
||||
BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreAmount));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDScore = Score;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDDefeats(int32 Defeats)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->DefeatsValue;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
const FString DefeatsAmount = FString::Printf(TEXT("%d"), Defeats);
|
||||
BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsAmount));
|
||||
}
|
||||
else
|
||||
{
|
||||
bInitializeCharacterOverlay = true;
|
||||
HUDDefeats = Defeats;
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->WeaponAmmoValue;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
const FString WeaponAmmoAmount = FString::Printf(TEXT("%d"), Ammo);
|
||||
BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(WeaponAmmoAmount));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->CarriedAmmoValue;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
const FString CarriedAmmoAmount = FString::Printf(TEXT("%d"), Ammo);
|
||||
BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(CarriedAmmoAmount));
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid = CharacterOverlay && CharacterOverlay->MatchCountdownText;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
if (CountdownTime < 0.f)
|
||||
if (BlasterHUD->CharacterOverlay)
|
||||
{
|
||||
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText());
|
||||
return;
|
||||
BlasterHUD->CharacterOverlay->RemoveFromParent();
|
||||
}
|
||||
const int32 Minutes = FMath::FloorToInt(CountdownTime / 60);
|
||||
const int32 Seconds = CountdownTime - Minutes * 60;
|
||||
|
||||
const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
|
||||
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText));
|
||||
}
|
||||
}
|
||||
bool bHUDValid = BlasterHUD->Announcement &&
|
||||
BlasterHUD->Announcement->AnnouncementText &&
|
||||
BlasterHUD->Announcement->AnnouncementMessage;
|
||||
|
||||
void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime)
|
||||
{
|
||||
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
|
||||
bool bHUDValid =
|
||||
BlasterHUD &&
|
||||
BlasterHUD->Announcement &&
|
||||
BlasterHUD->Announcement->AnnouncementText &&
|
||||
BlasterHUD->Announcement->CountdownText;
|
||||
|
||||
if (bHUDValid)
|
||||
{
|
||||
if (CountdownTime < 0.f)
|
||||
if (bHUDValid)
|
||||
{
|
||||
BlasterHUD->Announcement->CountdownText->SetText(FText());
|
||||
return;
|
||||
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible);
|
||||
FString AnnouncementText("New match starts in:");
|
||||
BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText));
|
||||
BlasterHUD->Announcement->AnnouncementMessage->SetText(FText());
|
||||
}
|
||||
const int32 Minutes = FMath::FloorToInt(CountdownTime / 60);
|
||||
const int32 Seconds = CountdownTime - Minutes * 60;
|
||||
|
||||
const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
|
||||
BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText));
|
||||
}
|
||||
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(GetPawn());
|
||||
if (BlasterCharacter && BlasterCharacter->GetCombat())
|
||||
{
|
||||
BlasterCharacter->bDisableGameplay = true;
|
||||
BlasterCharacter->GetCombat()->FireButtonPressed(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,18 @@ class BLASTER_API ABlasterPlayerController : public APlayerController
|
|||
|
||||
public:
|
||||
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
virtual void OnPossess(APawn* InPawn) override;
|
||||
virtual void ReceivedPlayer() override; // Sync with server clock as soon as possible
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
void SetDebugMsg1(FString Key, FString Value);
|
||||
void SetDebugMsg2(FString Key, FString Value);
|
||||
void SetDebugMsg3(FString Key, FString Value);
|
||||
void SetDebugMsg4(FString Key, FString Value);
|
||||
void SetDebugMsg5(FString Key, FString Value);
|
||||
void SetDebugMsg6(FString Key, FString Value);
|
||||
void SetDebugMsg7(FString Key, FString Value);
|
||||
void SetHUDHealth(float Health, float MaxHealth);
|
||||
void SetHUDScore(float Score);
|
||||
void SetHUDDefeats(int32 Defeats);
|
||||
|
@ -38,7 +45,7 @@ public:
|
|||
protected:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
void CheckTimeSync(float DeltaSeconds);
|
||||
void CheckTimeSync(float DeltaTime);
|
||||
void HandleMatchHasStarted();
|
||||
void SetHUDTime();
|
||||
void PollInit();
|
||||
|
@ -65,9 +72,12 @@ protected:
|
|||
void ServerCheckMatchState();
|
||||
|
||||
UFUNCTION(Client, Reliable)
|
||||
void ClientJoinMidGame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime);
|
||||
void ClientJoinMidgame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime);
|
||||
private:
|
||||
|
||||
UPROPERTY()
|
||||
class UDebugWidget* DebugWidget;
|
||||
|
||||
UPROPERTY()
|
||||
class ABlasterHUD* BlasterHUD;
|
||||
|
||||
|
|
|
@ -7,21 +7,6 @@
|
|||
#include "Blaster/PlayerController/BlasterPlayerController.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
void ABlasterPlayerState::IncreaseScore(float ScoreAmount)
|
||||
{
|
||||
SetScore(GetScore() + ScoreAmount);
|
||||
|
||||
Character = GetCharacter();
|
||||
if (Character)
|
||||
{
|
||||
Controller = GetController();
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDScore(GetScore());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
@ -29,14 +14,28 @@ void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>&
|
|||
DOREPLIFETIME(ABlasterPlayerState, Defeats);
|
||||
}
|
||||
|
||||
void ABlasterPlayerState::IncreaseScore(float ScoreAmount)
|
||||
{
|
||||
SetScore(GetScore() + ScoreAmount);
|
||||
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
|
||||
if (Character)
|
||||
{
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDScore(GetScore());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ABlasterPlayerState::OnRep_Score()
|
||||
{
|
||||
Super::OnRep_Score();
|
||||
|
||||
Character = GetCharacter();
|
||||
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
|
||||
if (Character)
|
||||
{
|
||||
Controller = GetController();
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDScore(GetScore());
|
||||
|
@ -47,11 +46,10 @@ void ABlasterPlayerState::OnRep_Score()
|
|||
void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount)
|
||||
{
|
||||
Defeats += DefeatsAmount;
|
||||
|
||||
Character = GetCharacter();
|
||||
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
|
||||
if (Character)
|
||||
{
|
||||
Controller = GetController();
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDDefeats(Defeats);
|
||||
|
@ -61,29 +59,13 @@ void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount)
|
|||
|
||||
void ABlasterPlayerState::OnRep_Defeats()
|
||||
{
|
||||
Character = GetCharacter();
|
||||
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
|
||||
if (Character)
|
||||
{
|
||||
Controller = GetController();
|
||||
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
if (Controller)
|
||||
{
|
||||
Controller->SetHUDDefeats(Defeats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ABlasterCharacter* ABlasterPlayerState::GetCharacter() const
|
||||
{
|
||||
return Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
|
||||
}
|
||||
|
||||
ABlasterPlayerController* ABlasterPlayerState::GetController() const
|
||||
{
|
||||
if (Character)
|
||||
{
|
||||
return Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ private:
|
|||
class ABlasterCharacter* Character;
|
||||
UPROPERTY()
|
||||
class ABlasterPlayerController* Controller;
|
||||
ABlasterCharacter* GetCharacter() const;
|
||||
ABlasterPlayerController* GetController() const;
|
||||
|
||||
UPROPERTY(ReplicatedUsing = OnRep_Defeats)
|
||||
int32 Defeats;
|
||||
|
|
Loading…
Reference in New Issue