UE4一些模块 乱写的

 Actor Pawns Character

Actor是能放置在UE4游戏世界里面的东西。任何能放置在World里面的东西都必须继承自它。

Pawns指的是可控制物,自然继承自Actor。

Character继承自Pawns,指的是havea mesh, collision, and built-in movement logicPawns

 

UClass()宏:让你的c++代码可以在Editor里面获得

GENERATED_UCLASS_BODY()宏:让你的c++类可以作为UE4 Editor所需要的类一样工作

 

 

GameInstance:

GameInstance是凌驾于GameMode和Levels之上的类。你在场景里面都存不了的东西就放在这里就对了。比如在进入比赛场景之前还有游戏状态,需要把游戏状态相关信息放在GameInstance里面管理。

GameMode:

EgAShooterGame_FreeForAll

 

一个游戏可以有任何数量的游戏类型,因此有任何数量的 “AGameMode” 类的子类;然而,在任何特定时间只可以使用一种游戏类型。每次通过“UGameEngine::LoadMap()” 函数初始化一个游戏等级时都会实例化一个 GameMode Actor

 

PawnPlayerControllerAIController也都是由GameMode负责

加载PersisitentLevel的时候创建GameMode

 

调用顺序:

UGameInstance::StartPIEGameInstance这种的是在创建play inenditor模式下的实例的时候

UWorld::SpawnActor ( GameClass

AShooterGame_FreeForAll::AShooterGame_FreeForAll

以上是PIE模式的GameMode的创建,并不具有一般性。

一般当你在界面选择创建场景的话,执行流程:

FShooterMainMenu::HostGame –UShooterGameInstance::HostGame 需要参数ULocalPlayer* LocalPlayer

在这里根据选项获取StartURL,就是要进入的场景信息,以及GameType比如FFA意思是FreeForAll

。。。

创建GameSession 其中的bIsLAN参数应该是从settings里面读出来的。(哪个settings?)

-FOnlineSessionNull::CreateSession

比如你想通过GameInstance->HostGame执行两次让一个session来创建两个Game那是不行滴。因为session已经创建过了就不能重复创建了。

 

在创建结束之后的UShooterGameInstance::FinishSessionCreation里面调用UWorld::ServerTravel 进而调用AGameMode::ProcessServerTravel

在这个里面会告诉客户端离开场景ProcessClientTravel

并且World->NextURL=URL这里面NextURL就表示接下来要转移到的场景。

 

 

GameEngin模块里面的WorldList中选取一个FWorldContent并且执行TickWorldTravel(Context, DeltaSeconds);

UEngine::LoadMapLoadMap

WorldContext.World()->SetGameMode(URL);

World.cpp中:

AuthorityGameMode = SpawnActor<AGameMode>( GameClass, SpawnInfo );

 

其中,UWorld类是一种最为顶级的object,代表着一个地图。World类对象也是由GameInstance创建的。

要理解的是,GameMode也是一种AAcotor

GameClass就是代表了你要创建的GameMode类型,是从GlobalDefaultServerGameMode中获得的。

 

GameMode是不可replicate的,只会存在于服务器,所以它需要一个扩展,这个扩展就是GameStateGameState是可以replicate的。客户端取数据还是需要在GameState里面取。

 

bUseSeamlessTravel

根据bUseSeamlessTravel的不同,UE可以选择哪些Actor迁移到下一个World中去(实现方式是先创建个中间过渡World进行二段迁移(为了避免同时加载进两个大地图撑爆内存)

 

 

 

GameState:

 

GameState的创建:

voidAGameMode::PreInitializeComponents()

通过GameState = GetWorld()->SpawnActor<AGameState>(GameStateClass, SpawnInfo);

创建出来的

 

    /** GameState is used to replicate game state relevantproperties to all clients. */

    UPROPERTY(Transient)

    classAGameState* GameState;

 

GameState中的内容由GameMode负责管理,也就是手动设置

Eg

改变比赛状态的时候GameState->SetMatchState(NewState);

在这个函数当中如果Role==ROLE_Authority则会调用OnRep_MatchState();这是因为:如果是把MatchState变量设置上ReplicatedUsing=OnRep_MatchState那么只有客户端会在MatchState发生变化的时候执行OnRep_MatchState,而如果想让服务器也执行,那么需要主动调用。

 

客户端也有一个gamestate

是在接收到bunch之后创建的

 

Gamestate中包含一个

TArray<classAPlayerState*> PlayerArray;

是所有玩家的列表同样是服务器和客户端都有的

PlayerState里面包含了基本客户端所需要的所有信息比如你在哪个组你的剩余子弹,得分之类的

 

PlayerState是服务器和客户端都有的也需要replicate

PlayerState是在建立controller的时候创建的

PlayerArray中加入PlayerState的行为是通过AGameState::AddPlayerStateSpawnActor之后做的

 

 

 

以角色死亡为例:在服务器接收到远程调用 ServerNotifyHit之后AShooterWeapon相关类的ServerNotifyHit_Implementation会判断此次打击时间的有效性,然后如果在有效的情况下调用ProcessInstantHit_Confirmed,在这个函数中:

AShooterWeapon_Instant::DealDamage会被调用,根据Impact所记录的actor信息调用AShooterCharacter::TakeDamage

Impact信息是FHitResult类的对象,包含了比如trace的信息,打中的actor等。

AShooterCharacter::TakeDamage中会获得AShooterGameMode的指针然后执行AShooterGameMode::ModifyDamage。。。

当发现受到攻击者的血量少于0了那就AShooterCharacter::Die 这里面调用了GetDamageInstigator,规定了一件事,如果是正常的打击类型,那么killer就是杀人者,否则就是叫做环境伤害,那么造成lasthit的人就是killer

然后调用AShooterGameMode::Killed对于killer给予奖励,对于死亡者给予惩罚。

 

HitNotify的信息会被赋值,后面将会同步到客户端。如果在配置文件中要求显示弹道,那么如果不是专用服务器实例的话,还需要画弹道。

 

 

Character:

ACharacter类是以pawn为基础的包含着网格,碰撞,运动等信息的类。与controller之间的关系就是:Character(Pawn)负责表现,Controller负责行为。

Pawn死亡了之后controller是继续存在的。APwan类里面有一个AController* Controller;就是记录那个controller控制的这个pawn。控制的过程是APlayerController::Possess(APawn* PawnToPossess)。放弃控制是APlayerController::UnPossess(),比如在角色死亡的时候。

 

 

 

 

 

 

 

如果 Role ROLE_AuthorityRemoteRole ROLE_SimulatedProxyROLE_AutonomousProxy,就说明这个引擎实例负责将此 actor 复制到远程连接?

 

ROLE_AutonomousProxy这种模拟通常只用于PlayerController 所拥有的 actor

 

AShooterCharacter::OnDeath

 

FNetworkPredictionData_Server_Character

预判机制

在服务器计算移动的时候ServerMove_ImplementationVerifyClientTimeStamp会验证客户端发过来的时间戳是否正常,计算转向信息并且给服务器的controller设置PC->SetControlRotation(ViewRot);设置偏航角俯仰角和旋转角,然后设置Actor的朝向。

然后调用UCharacterMovementComponent::ServerMoveHandleClientError来修正客户端的错误。

UNetDriver::ServerReplicateActors的时候会执行UCharacterMovementComponent::SendClientAdjustment()会把ServerData->PendingAdjustment信息同步到客户端。

 

APlayerController是用来控制Pawns的,服务器和客户端都有。其父类AController拥有一个APawn* Pawn;是用来指向真正的pawn

 

碰撞

碰撞是在PhysXCollision模块中进行的,比如对于射弹类型碰撞物体的判断,会在每一帧对于moveRotationBeginEnd进行计算,从而根据所穿透的几何截面做出返回。比如GeomSweepMulti就会返回一个ArrayOutput

碰撞是在MoveComponentImpl也就是组件的移动时候调用的。

比如对于instant类型的武器射击过程,会通过AShooterWeapon::WeaponTrace来进行光线追踪,然后依然是通过物理的RaycastSingle进行计算的,

 

 

登陆过程

协议OnValidQueryPacket:用于客户端向局域网内的服务器请求服务器信息

协议OnValidResponsePacket:用于服务器向客户端返回服务器信息

AGameSessionGameInstance进行管理,只在服务器存在

首先目前的流程是:界面操作完毕-FShooterMainMenu::OnJoinServer-FShooterMainMenu::OnUserCanPlayOnlineJoin也就是在检查完userprivilidge之后调用的函数。这里面会获取想要加入的游戏类型的一个过滤。

-ServerListWidget->BeginServerSearchUShooterGameInstance::FindSessions

搜索服务器的时候会

LanBeacon->Init(LanAnnouncePort)会在这里面初始化socket

执行FOnlineSessionNull::FindLANSession()在这里面会通过LANSessionManager.CreateClientQueryPacket(Packet, LANSessionManager.LanNonce);创建一个探索包,其中LANSessionManager.LanNonce标示一个客户端它自己。然后调用LANSessionManager.Search(Packet, ResponseDelegate, TimeoutDelegate)对这个网络包进行广播。

问题:join的时候lan选择off是什么概念?

 

Search完成后会执行voidSShooterServerList::UpdateServerList()双击结果会触发SShooterServerList::OnListItemDoubleClicked(TSharedPtr<FServerEntry> InItem)在这里会设置SelectedItem

à

SShooterServerList::ConnectToServer()

会根据你设置的SelectedItem调用UShooterGameInstance::JoinSession-AShooterGameSession::JoinSession

这个函数里面根据sessionnameFOnlineSessionNull的数组sessions里面获得session,FOnlineSessionNull负责管理session以及它们的state。如果已经获取到了,说明此session已经加入到了游戏中,不用再次加入,否则执行AddNamedSessionAddNamedSessionnew出一个FOnlineSessionNull,对其进行赋值后会调用JoinLANSession

 ……->FOnlineSessionNull::JoinLANSession其中有一个参数SearchSession包含了被搜索到的session的全部信息,其中包含了adress信息。

如果JoinLANSession失败了那就RemoveNamedSession,也就是从Sessions里面remove掉。(RemoveAtSwap

如果成功了,FOnlineSessionNull::RegisterLocalPlayers,主要是跟语音相关的?

接下来:

在每一个tick的时候会走UEngine::TickWorldTravel,这个时候Context.TravelURL就不空了,这里面记录的是地址信息,--UEngine::Browse

--WorldContext.PendingNetGame->InitNetDriver();

这里面会FNetControlMessage<NMT_Hello>::Send( NetDriver->ServerConnection, IsLittleEndian,LocalNetworkVersion );

其底层调用的是UControlChannel::SendBunch

发送一个NMT_Hello到服务器。NMT_Hello相当于是一种消息类型。

服务器接到这个消息包的地方:UWorld::NotifyControlMessage根据messagetype执行到FNetControlMessage<NMT_Hello>::Receive(Bunch, IsLittleEndian, RemoteNetworkVersion);

然后会对比版本号,如果版本不对会返回NMT_Upgrade这个消息。如果版本号是正确的则返回一个NMT_Challenge

NMT_Challenge协议的目的是验证想要login的客户端的完整性。

客户端在接到之后,填充信息,然后发送NMT_Login

服务器在接到消息之后,会调用AuthorityGameMode->PreLogin以检查是否可以登录。这个地方基类(AGameMode)实现只是检查了分屏上限,其他的检查需要在派生类实现,比如AShooterGameMode::PreLogin里面判断match是否结束,如果已经结束了则拒绝。

拒绝客户端会返回NMT_Failure,否则WelcomePlayer(Connection)

这里面会发送NMT_Welcome给客户端,其参数重定向URL是干什么的?

客户端接到NMT_Welcome之后,会向服务器发送NMT_Netspeed,服务器怎么用这个speed的?

 

 

特效

比如:在发射instant类型的子弹的时候会有开火特效,在HandleFiring中会调用AShooterWeapon::SimulateWeaponFire()主要负责放置一个粒子发射器(UGameplayStatics::SpawnEmitterAttached函数),以一个UParticleSystem* MuzzleFX为模板来进行创建,并且设置挂点,方位大小等。这个模板是在武器的classDefaults里面的Effects里面选择的。当然SimulateWeaponFire还包含了枪的射击动画和对于角色的反馈。

概念:一个粒子系统包含N个粒子发射器。

 

Tick

UUnrealEdEngine::Tick ->UWorld::Tick->… ->FActorTickFunction::ExecuteTick

->AActor::TickActor ->AShooterCharacter::Tick(floatDeltaSeconds)

通常来说这个时间是由FixedFrameRate决定的

FActorTickFunction::ExecuteTick这里面对DeltaTime进行了修改DeltaTime*Target->CustomTimeDilation,这个变量允许不同的Actor拥有不同的tick时间间隔。

tick :用于确定在帧中何时进行 tick

actors 或组件还可设置 tick 依赖性,意味着其他特定 actor 或组件的 tick 函数完成后它们才会进行 tick

 

 

NavMesh寻路:

其算法中的2d寻路部分仍然是A*算法,只不过其可以支持3d寻路。

原始数据是ANavigationData* MainNavData这个数据是在NavDataRegistrationQueue中获得的,其中的数据是在场景中的RecastNavMesh类型的actor放置的。

 

AI

 

 

UE4文件结构

最主要的首先是source下分为public和private文件夹。Private下一般是.cpp文件,public下面一般放着外部Moudle可以引用的.h或者.cpp文件。没有继承自UObject的类一般是放置在private下面。

比如:classFShooterMainMenu : publicTSharedFromThis<FShooterMainMenu>, publicFTickableGameObject这个类,就要放在private下面。

继承TSharedFromThis模板可以让这个子类获得这个对象的sharedptr。这两个被继承的基类都没有继承自UObject,所以FShooterMainMenu.h也要放在private下面。

A TArray is a

dynamicallygrowable C++ array.

 

 

 

 

 

 

 

 

材质编辑

材质函数

 

TextureSample(纹理取样)表达式输出纹理中的颜色值。

我的理解 其实TextureSample是对Texture的封装。

Multiply 每个分量相乘 可以大于1

Clamp 限制 必须介于最小和最大值之间

 

DepthFade(深度消退)表达式用来隐藏半透明对象与不透明对象相交时出现的不美观接缝。

 

PixelDepth(像素深度)表达式输出当前所渲染像素的深度

 

SphereMask 这个节点在指定的位置生成一个球形并进行距离计算,圆心处为1,外围为0

Desaturation     去色   去除颜色,当赋予Fraction0时,无作用,数值越靠近1,去色越明显

Programmers:Define desaturated color D, input color I and luminance factor L.The output will be O = (1-Percent)*(D.dot(I)) + Percent*I

 

 

Actor

TSet<UActorComponent*> OwnedComponents 保存着这个Actor所拥有的所有Component,一般其中会有一个SceneComponent作为RootComponent 

 

Actor之间的父子关系: UE里是通过Child:AttachToActorChild:AttachToComponent来创建父子连接的。

StartPIEGameInstance的时候,会对UWorld里面的Levels进行遍历,对每一个level执行Level->RouteActorInitialize();

这个函数主要是对Levels里面所有的Actors执行:

Actor->InitializeComponents();这个主要就是对所有components初始化。

Actor->PostInitializeComponents();这个主要是更新ReplicatedComponents,根据一个component是不是replicated.

RouteActorInitialize函数最后还把需要beginplay的actor执行Actor->BeginPlay();

 

 

World

    可以认为是一个逻辑概念,不像Level是一个实体。

猜你喜欢

转载自blog.csdn.net/icebergliu1234/article/details/80708805
今日推荐