关卡切换
设置无缝切换要到编辑器下的项目设置中,搜索转移地图或者Transition Map
即可进行设置
同时应当启用bUseSeamlessTravel
。下例是在继承自GameMode
类的LobbyGameMode
类中对PostLogin
函数的重写,硬编码实现了加入人数为2人时,使用ServerTravel()
以监听方式切换地图到Content/Maps/BlasterMap
这个关卡
void ALobbyGameMode::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
int32 NumberOfPlayers = GameState.Get()->PlayerArray.Num();
if (NumberOfPlayers == 2) {
UWorld* World = GetWorld();
if (World)
{
bUseSeamlessTravel = true;
World->ServerTravel(FString("game/Maps/BlasterMap?listen"));
}
}
}
随后在Lobby关卡下的世界场景设置面板中指定这个游戏模式即可使用。当然,为了灵活性应当对这个游戏模式生成蓝图,指定这个蓝图实例,并在蓝图实例中勾选“使用无缝漫游”。
NetRole
与这部分内容相关的官方文档
在网络游戏中,对于同一个角色,有不同的版本。作为客户端连接到服务器的玩家,
- 其电脑本身有一个客户端控制的角色的版本
- 服务器自然也有一个
- 其他玩家电脑上也有
为了解决代码处理的是哪个版本的角色这个问题,UE引入了Role这个概念。有一个ENetRole的枚举。
enum ENetRole
{
ROLE_None,
ROLE_SimulatedProxy,
ROLE_AutonomousProxy,
ROLE_Authority,
ROLE_MAX,
}
ROLE_Authority
被指定给存在于服务器上的PawnROLE_SimulatedProxy
指代该机器上没有控制的Pawn或角色(比如说别人的角色在你的机器上的版本,即你的机器上别人通过网络控制的Pawn)ROLE_AutonomousProxy
在你的机器上控制的属于你的角色(当然,前提是你不是服务器,否则按1算)
HUD之人头上方名字
创建一个没有父类的控件蓝图,然后去掉根组件(如果有),随后创建文本控件,该控件名字和cpp文件里的要一致,然后就可以通过cpp文件来控制这个文本,cpp文件是继承自UserWidget
类的,然后通过UPROPERTY
说明符将这个c++变量同控件蓝图中的文本块同名控件关联起来。
前缀WBP_
意思就是Widget Blueprint。
继承自UserWidget
类的头文件部分添加三行代码如下:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "OverheadWidget.generated.h"
/**
*
*/
UCLASS()
class BLASTER_API UOverheadWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(meta = (BindWidget))
class UTextBlock* DisplayText;
};
由于这里变量叫做DisplayText
,所以编辑器里的控件蓝图中文本控件的名字就得也叫做DisplayText
。
随后再重新指定该控件蓝图的父类为刚才创建的C++类。通过点击图表->类设置
最终代码:
// OverheadWidget.cpp
#include "OverheadWidget.h"
#include "Components/TextBlock.h"
void UOverheadWidget::SetDisplayText(FString TextToDisplay)
{
if (DisplayText)
{
DisplayText->SetText(FText::FromString(TextToDisplay));
}
}
void UOverheadWidget::ShowPlayerNetRole(APawn* InPawn)
{
ENetRole LocalRole = InPawn->GetLocalRole();
FString Role;
switch (LocalRole)
{
case ENetRole::ROLE_None:
Role = FString("None");
break;
case ENetRole::ROLE_SimulatedProxy:
Role = FString("Simulated Proxy");
break;
case ENetRole::ROLE_AutonomousProxy:
Role = FString("Autonomous Proxy");
break;
case ENetRole::ROLE_Authority:
Role = FString("Authority");
break;
case ENetRole::ROLE_MAX:
break;
default:
break;
}
FString LocalRoleString = FString::Printf(TEXT("Local Role: %s"), *Role);
SetDisplayText(LocalRoleString);
}
void UOverheadWidget::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
{
RemoveFromParent();
Super::OnLevelRemovedFromWorld(InLevel, InWorld);
}
头文件部分:
// OverheadWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "OverheadWidget.generated.h"
/**
*
*/
UCLASS()
class BLASTER_API UOverheadWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(meta = (BindWidget))
class UTextBlock* DisplayText;
void SetDisplayText(FString TextToDisplay);
UFUNCTION(BlueprintCallable)
void ShowPlayerNetRole(APawn* InPawn);
protected:
virtual void OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)override;
};
同时在角色类中添加代码:
// .h file in private section
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
class UWidgetComponent* OverheadWidget;
// .cpp file in constructor function
OverheadWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("OverheadWidget"));
OverheadWidget->SetupAttachment(RootComponent);