使用Unreal引擎制作游戏或VR产品的时候,需要遵循Unreal引擎已经约定好的框架;
Unreal引擎非常复杂,本人是基于Application的应用层面来使用Unreal封装好的功能;
在制作一款联网端游的时候遇到了网络的问题,特此记录一下,个人的经验分享!
#1 Unreal 的框架简介
#2 Unreal 中的网络框架
#3 Unreal 属性同步,蓝图和C++
#4 Unreal 属性同步,Notify方式
#5 Unreal 中基于Actor同步
#6 Unreal 中使用RPC同步
#1 Unreal 的框架简介
Unreal中默认使用的框架在GameMode的设置中列举出来了
GameModeOverride
游戏模式
The GameModeBase defines the game being played. It governs the game rules, scoring, what actors
are allowed to exist in this game type, and who may enter the game.
It is only instanced on the server and will never exist on the client.
A GameModeBase actor is instantiated when the level is initialized for gameplay in C++ UGameEngine::LoadMap().
The class of this GameMode actor is determined by (in order) either the URL ?game=xxx,
the GameMode Override value set in the World Settings, or the DefaultGameMode entry set in the game’s Project Settings.
简介:每个关卡都可以设置一个游戏模式
作用:设置游戏的规则
网游:只存在于服务器中
单机:每个关卡都有
Default Pawn Class
默认的控制
Pawn is the base class of all actors that can be possessed by players or AI.
They are the physical representations of players and creatures in a level.
简介:游戏默认的操作控制
作用:封装好了游戏的各种控制
网游:由服务器复制到各个客户端
单机:自由控制切换
HUD Class
游戏UI
Base class of the heads-up display. This has a canvas and a debug canvas on which primitives can be drawn. It also contains a list of simple hit boxes that can be used for simple item click detection.
A method of rendering debug text is also included.Provides some simple methods for rendering text, textures, rectangles and materials which can also be accessed from blueprints.
简介:游戏战斗时的UI
作用:可以绘制各种UI,血条、伤害数字等
网游:和服务没有关系
单机:自由控制显示
Player Controller Class
玩家控制器
PlayerControllers are used by human players to control Pawns.
ControlRotation (accessed via GetControlRotation()), determines the aiming
orientation of the controlled Pawn.
In networked games, PlayerControllers exist on the server for every player-controlled pawn,
and also on the controlling client’s machine. They do NOT exist on a client’s
machine for pawns controlled by remote players elsewhere on the network.
简介:游戏玩家的控制器
作用:设置游戏的输入
网游:服务器及客户端同步
单机:每个关卡都有
Game State Class
游戏状态
GameState is a subclass of GameStateBase that behaves like a multiplayer match-based game.
It is tied to functionality in GameMode.
简介:游戏进行的状态
作用:管理当前游戏的状态
网游:服务器及客户端同步
单机:每个关卡都有
Player State Class
玩家状态
A PlayerState is created for every player on a server (or in a standalone game).
PlayerStates are replicated to all clients, and contain network game relevant information about the player, such as playername, score, etc.
简介:游戏玩家的状态
作用:管理当前玩家的状态
网游:服务器及客户端同步
单机:每个关卡都有
Spectator Class
观战控制
SpectatorPawns are simple pawns that can fly around the world, used by
PlayerControllers when in the spectator state.
简介:游戏玩家观战
作用:控制当前玩家的观战
网游:和服务没有关系
单机:一般来说不需要
#2 Unreal 中的网络框架
Unreal中的服务器分为两种:监听服务器(局域网对战)和专用服务器(独立云服务器),两种服务器的游戏在制作的过程中差不多,打包的方式不一样;
制作测试的时候可以使用Unreal提供的便捷功能:
可以设置测试开启的玩家数量和网络模式
HasAuthority()
方法;#3 Unreal 属性同步,蓝图和C++
这种同步的属性无论是否有变化,数据一直在同步,比较耗网络资源
// HowTo_ReplicateProps.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HowTo_ReplicateProps.generated.h"
UCLASS()
class TUTORIALSDEMO_API AHowTo_ReplicateProps : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AHowTo_ReplicateProps();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//Step1. 标记为Replicated
UPROPERTY(Replicated, VisibleAnywhere)
int32 ReplicateValue = 100;
//Step2. 通过这个方法设置为 DOREPLIFETIME(AHowTo_ReplicateProps, ReplicateValue);
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
// HowTo_ReplicateProps.cpp
#include "HowTo_ReplicateProps.h"
#include "Net/UnrealNetwork.h"
// Sets default values
AHowTo_ReplicateProps::AHowTo_ReplicateProps()
{
bReplicates = true;
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AHowTo_ReplicateProps::BeginPlay()
{
Super::BeginPlay();
// 模拟服务器修改了值
if (HasAuthority())
{
ReplicateValue = 500;
}
}
// Called every frame
void AHowTo_ReplicateProps::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (HasAuthority())
{
GLog->Logf(TEXT("Server - %d"), ReplicateValue);
}
else
{
GLog->Logf(TEXT("Client - %d"), ReplicateValue);
}
}
void AHowTo_ReplicateProps::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AHowTo_ReplicateProps, ReplicateValue);
}
#4 Unreal 属性同步,Notify方式
这种方式同步的属性数据只有在变化之后才会接收到通知
OnRep_xxx
OnRep_xxx
里面设置// HowTo_PropReplicateNotify.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HowTo_PropReplicateNotify.generated.h"
UCLASS()
class TUTORIALSDEMO_API AHowTo_PropReplicateNotify : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AHowTo_PropReplicateNotify();
void TimerInterval();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, ReplicatedUsing=OnRep_ReplicateValue)
int32 ReplicateValue = 100;
UFUNCTION()
void OnRep_ReplicateValue();
};
// HowTo_PropReplicateNotify.cpp
#include "HowTo_PropReplicateNotify.h"
#include "Net/UnrealNetwork.h"
// Sets default values
AHowTo_PropReplicateNotify::AHowTo_PropReplicateNotify()
{
bReplicates = true;
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
void AHowTo_PropReplicateNotify::TimerInterval()
{
if (HasAuthority())
{
ReplicateValue = FMath::Rand();
}
}
// Called when the game starts or when spawned
void AHowTo_PropReplicateNotify::BeginPlay()
{
Super::BeginPlay();
FTimerHandle TimerHandle;
GetWorldTimerManager().SetTimer(TimerHandle, this, &AHowTo_PropReplicateNotify::TimerInterval, 1, true);
}
void AHowTo_PropReplicateNotify::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AHowTo_PropReplicateNotify, ReplicateValue);
}
// Called every frame
void AHowTo_PropReplicateNotify::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AHowTo_PropReplicateNotify::OnRep_ReplicateValue()
{
if (HasAuthority())
{
GLog->Logf(TEXT("Server - %d"), ReplicateValue);
}
else
{
GLog->Logf(TEXT("Client - %d"), ReplicateValue);
}
}
C++中的ReplciateNotify只在客户端之间进行传输数据,一般用于专用服务器对客户端进行数据的分发,不能用于局域网里面
#5 Unreal 中基于Actor同步
Actor的同步会复制服务器的生成的对象到客户端,如果服务器有而客户端没有,如果有碰撞,则会出现空气墙,Unreal的人物移动是在服务器计算的,如果服务器发现有碰撞,则无法通过
bReplicates = true;
就可以了,Actor默认带网络复制功能。#6 Unreal 中使用RPC同步
Unreal中可以使用RPC来进行通信
RPCs (Remote Procedure Calls) are functions that are called locally, but executed remotely on another machine (separate from the calling machine).
RPC functions can be very useful and allow either the client or the server to send messages to each other over a network connection.
The primary use case for these features are to do unreliable gameplay events that are transient or cosmetic in nature. These could include events that do things such as play sounds, spawn particles, or do other temporary effects that are not crucial to the Actor functioning. Previously these types of events would often be replicated via Actor properties.
RPC网络通信是Unreal中Online的主要通信网络,用于和服务器传输事件,比如播放声音,生成粒子或者游戏中的伤害数字等;用户可以手动来指定一个事件是否需要RPC到其他的客户端;
比如我这边播放了一个音效,Online的情况下需要把播放音效这个事件同步到其他的客户端,RPC就干这事;
// HowTo_RPC.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HowTo_RPC.generated.h"
UCLASS()
class TUTORIALSDEMO_API AHowTo_RPC : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AHowTo_RPC();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(Client, Reliable, WithValidation)
void FunctionRPC(int32 InValue); // 定义需要RPC的方法,作用域是客户端
void FunctionRPC_Implementation(int32 InValue); // 具体实现
bool FunctionRPC_Validate(int32 InValue); // 验证有效
void TimerInterval();
};
// HowTo_RPC.cpp
#include "HowTo_RPC.h"
// Sets default values
AHowTo_RPC::AHowTo_RPC()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AHowTo_RPC::BeginPlay()
{
Super::BeginPlay();
FTimerHandle TimerHandle;
GetWorldTimerManager().SetTimer(TimerHandle, this, &AHowTo_RPC::TimerInterval, 5, true);
}
// Called every frame
void AHowTo_RPC::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AHowTo_RPC::FunctionRPC_Implementation(int32 InValue)
{
if(HasAuthority())
{
GLog->Logf(TEXT("Server - %d"), InValue);
}
else
{
GLog->Logf(TEXT("Client - %d"), InValue);
}
}
bool AHowTo_RPC::FunctionRPC_Validate(int32 InValue)
{
return true;
}
void AHowTo_RPC::TimerInterval()
{
//!HasAuthority() = !GetWorld()->IsServer() = GetLocalRole() < ROLE_Authority
// 这三个判定方法等同,判定服务器还是客户端
if (!HasAuthority() || !GetWorld()->IsServer() || GetLocalRole() < ROLE_Authority)
{
FunctionRPC(500);
}
}