BP/CPP Player Index, как получить? Unreal Engine 4/5

Player Index, как можно понять по названию, указывает на номер игрока присоединившегося на определённый уровень. При разработке одиночной игры, обычно, не возникает потребности в определении номера игрока, он всегда равен нулю.

Когда игра рассчитана на несколько игроков, то подход в разработке меняется и номер игрока начинает играть огромную роль. Это можно особенно наблюдать в получении определённых компонентов игрока: Player Controller, Character и т.д.

Основные функции получения компонентов игрока, которые требуют Player Index
Основные функции получения компонентов игрока, которые требуют Player Index

Т.к. в открытом доступе информации по этому поводу толком не было либо она была максимально размешена ненужной информацией, я решил описать один из способов получения Player Index.

Суть следующая - когда новый игрок будет присоединятся к новому уровню сервер будет хранить номер данного игрока. Для этого идеально подойдёт GameMode, но обычный игрок(клиент) не имеет доступа к GameMode, да и сам GameMode должен различать, кто к нему обратился и какой у кого номер. Мол я такой-то такой-то, дай мне мой номер. Поэтому игровой режим будет хранить данные в связке ключ-значение(Map), где ключом будет являться уникальный айди пользователя - UniqueNetID, а значением простой int.

Event OnPostLogin - отслеживает присоединение новых игроков и возвращает PlayerController нового игрока. Через контроллер мы обращаемся к PlayerState и через него получаем уникальный ID, а потом заносим в Map с номером игрока. Также надо создать геттер для получения нашего Map.

BP/CPP Player Index, как получить? Unreal Engine 4/5

Как пример, свой PlayerIndex я буду получать через PlayerController по нажатию на клавишу, но разницы в этом особо нет. Так как игрок-клиент(AuotonomousProxy) то для получения информации с GameMode необходимо делать RPC вызов с клиента на сервер. Это будет выглядеть следующим образом:

BP/CPP Player Index, как получить? Unreal Engine 4/5

Конечно для дальнейшего использования на клиенте потребуется сделать ещё один RPC вызов уже с сервера к клиенту(ам).

CPP

На плюсах логика такая же, только за исключением того, что в получении компонентов (как всё тот же пример) PlayerIndex не нужен, если вызывает их клиент.

GameMode

#include "CPP_GameMode.h" #include "Kismet/KismetSystemLibrary.h" #include "GameFramework/PlayerState.h" void ACPP_GameMode::PostLogin(APlayerController* NewPlayer) { Super::PostLogin(NewPlayer); if (const APlayerState* PlayerState = NewPlayer->GetPlayerState<ACPP_PlayerState>()) { UKismetSystemLibrary::PrintString(this, "Get Player State successfully"); MaxPlayers++; FUniqueNetIdRepl UniqueNetIdRepl = PlayerState->GetUniqueId(); PLayerIndexMap.Add(UniqueNetIdRepl, MaxPlayers); } } TMap<FUniqueNetIdRepl, int> ACPP_GameMode::GetPlayerIndexMap() { return PLayerIndexMap; }

PlayerController.CPP

#include "CPP_PlayerController.h" #include "CPP_GameMode.h" #include "Net/UnrealNetwork.h" #include "Kismet/GameplayStatics.h" #include "Kismet/KismetSystemLibrary.h" void ACPP_PlayerController::ChangeCharacter() { if(HasAuthority()) { SelectCharacter = true; OnRepSelectCharacter(); } else { Server_ChangeCharacter(); } } void ACPP_PlayerController::Server_ChangeCharacter_Implementation() { ChangeCharacter(); } void ACPP_PlayerController::OnRepSelectCharacter() { UniqueNetIdRepl = GetPlayerState<APlayerState>()->GetUniqueId(); int* PlayerIndex; if(ACPP_GameMode* GameModeBase = Cast<ACPP_GameMode>(UGameplayStatics::GetGameMode(this))) { PlayerIndex = GameModeBase->GetPlayerIndexMap().Find(UniqueNetIdRepl); } } void ACPP_PlayerController::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME_CONDITION(ACPP_PlayerController, SelectCharacter, COND_SimulatedOnly) }

PlayerController.h

// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/PlayerController.h" #include "CPP_PlayerController.generated.h" UCLASS() class CPP_PROPHUNT_API ACPP_PlayerController : public APlayerController { GENERATED_BODY() public: UPROPERTY(ReplicatedUsing = OnRepSelectCharacter) bool SelectCharacter = false; protected: FUniqueNetIdRepl UniqueNetIdRepl; UFUNCTION(BlueprintCallable) void ChangeCharacter(); UFUNCTION(Server, Reliable) void Server_ChangeCharacter(); UFUNCTION() void OnRepSelectCharacter(); virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; };
4
1
Начать дискуссию