虚幻4C++编程入门深入了解

这部分我们将讨论基础构建块以及它们之间相互关联的方式。在此我们将了解虚幻引擎如何使用
继承和合成构建自定义游戏性功能。

游戏性类:对象、Actor 和组件

多数游戏性类派生自 4 个主要类型。它们是

UObject、AActor、UActorComponent 和 UStruct

以下部分会对这些构建块进行一一说明。当然,您还可以创建并非派生自这些类的类型,但其无法采用引擎中内置的功能。UObject 层级树之外创建的类的典型用法有:整合第三方库、封装操作系统特定功能等。

虚幻对象(UObject)

虚幻引擎中的基础构建块被称作 UObject。此类结合 UClass 提供引擎中最重要的若干基础服务:

**属性和方法反射
属性序列化
垃圾回收
按命名查找 UObject
可配置属性数值
属性和方法网络支持**

派生自 UObject 的每个类拥有一个为其创建的单例 UClass,此对象包含关于类实例的所有元数据。UObject 和 UClass 是游戏性对象在其生命期中执行所有操作的根源。区分 UClass 和 UObject 的最佳方式:UClass 描述 UObject 实例的组成、可用于序列化的属性、网络等。多数的游戏性开发不会直接从 UObject 进行派生,而从 AActor 和 UActorComponent 进行派生。编写游戏性代码无需了解 UClass/UObject 的工作细节。但了解这些系统的存在也会有所帮助。

AActor

AActor 是作为游戏体验一部分的对象。AActor 将被设计师放置在关卡中,或通过游戏性系统在运行时创建。所有可放入关卡的对象均延展自此类。范例有 AStaticMeshActor、ACameraActor 和 APointLight actor。AActor 派生自 UObject,因此可使用上一部分列出的所有标准功能。可通过游戏性代码(C++ 或蓝图)显式销毁 AActor。拥有关卡从内存被卸载后,通过标准垃圾回收机制进行销毁。AActor 负责游戏对象的高级行为。AActor 还是可进行网络复制的基类。在网络复制中,AActor 还可分布 UActorComponent 的信息。UActorComponent 为需要网络支持的 AActor 所拥有。

AActor 拥有其自身的行为(通过继承的特殊化),但它们仍作为 UActorComponent 层级的容器(通过合成的特殊化)。这通过 AActor 的 RootComponent 成员完成。此成员包含一个单一 UActorComponent,而这个组件又可依次包含其他组件。在 AActor 可被放入关卡之前,它必须包含至少一个 USceneComponent。此组件包含此 AActor 的平移、旋转和尺寸。

AActor 拥有一系列事件,可在生命周期中进行调用。以下列表是说明生命周期的简化事件集。

**BeginPlay - 对象首次出现在游戏进程中时调用
Tick - 每帧调用一次,在一段时间内执行操作
EndPlay - 对象离开游戏进程时调用**

在 Actor 中查看关于 AActor 的详细讨论。

运行时生命周期

之前我们讨论了 AActor 生命周期的一个子集。对于放置在关卡中的 actor 而言,通过想象便可轻松理解生命周期:actor 加载,出现,随后关卡被卸载,actor 被销毁。运行时创建和销毁的过程是怎样的?虚幻引擎在运行时生成调用 AActor 的创建。较之于在游戏中创建一个普通对象,actor 的生成稍显复杂。原因是 AActor 需要通过各种运行时系统进行注册,以满足所有需要。需要设置 actor 的初始位置和旋转。物理可能需要知晓这些信息。负责告知 actor 进行 tick 的管理器需要知晓这些信息。诸如此类。因此,我们拥有一个用于 actor 生成的方法 - UWorld::SpawnActor()。一旦 actor 成功生成后,它的 BeginPlay() 方法将被调用,下一帧将出现 Tick()

一旦 actor 的生命期完结,即可调用 Destroy() 将其销毁。在此过程中将调用 EndPlay(),在此可设置自定义销毁逻辑。控制 actor 存在时长的另一个选项是使用寿命成员。可在对象的构建函数中设置时间段,或通过运行时的其他代码进行设置。时间量耗尽后,actor 将自动调用 Destroy()。

如需了解 actor 生成的更多内容:
https://docs.unrealengine.com/latest/CHN/Programming/UnrealArchitecture/Actors/Spawning/index.html

UActorComponent

UActorComponent 拥有其自身行为,通常负责在多种类型 AActor 之间共享的功能,如提供可视网格体、粒子效果、摄像机透视和物理互动。通常为 AActor 指定的是与其在游戏中全局作用相关的高级目标,而 UActorComponent 通常执行的是支持这些高级目标的单个任务。组件也可附着到其他组件,或为 Actor 的根组件。组件只能附着到一个父组件或 Actor,但可被多个子组件附着。想象一个组件树。子组件拥有与其父组件或 Actor 相对的位置、旋转和尺寸。

使用 Actor 和组件的方法有多种,而理解 Actor - 组件关系的方式是 Actor 会提出问题“这是什么?”,而组件会回答“这由什么组成?”

**RootComponent - 这是在 AActor 组件树中拥有顶层组件的 AActor 成员
Ticking - 组件作为拥有 AActor Tick() 的部分被点击**

剖析第一人称角色

之前的几个部分叙述较多,展示较少。为展示 AActor 和其 UActorComponent 之间的关系,我们一来研究基于第一人称模板创建新项目时创建的蓝图。下图是 FirstPersonCharacter Actor 的 组件 树。RootComponent 为 CapsuleComponent。附着到 CapsuleComponent 的是 ArrowComponent、Mesh 组件和 FirstPersonCameraComponent。叶最多的组件是以 FirstPersonCameraComponent 为父项的 Mesh1P 组件,意味着第一人称网格体与第一人称摄像机相对。

这里写图片描述

视觉外观而言,组件 树与下图相似,可看到除 Mesh 组件外的所有组件均在 3D 空间中。

这里写图片描述

UStruct

使用 UStruct 时不必从任意特定类进行延展,只需要使用 USTRUCT() 标记结构体,编译工具将执行基础工作。和 UObject 不同,UStruct 不会被垃圾回收。如创建其动态实例,则必须自行管理其生命周期。UStruct 为纯旧式数据类型。它们拥有 UObject 反射支持,以便在虚幻编辑器、蓝图操作、序列化和网络通信中进行编辑。

讨论完游戏性类构建中使用的基础层级后,即可再次选择路径。可在 此处 阅读关于游戏性类的内容、使用 launcher 中带有更多信息的样本、或进一步深入研究构建游戏的 C++ 功能。

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的UE4 C++ UDP通信组播的案例。 1. 首先,需要创建一个UDP Socket: ```c++ FSocket* ListenSocket = FUdpSocketBuilder(TEXT("MySocket")).BoundToAddress(FIPv4Address::Any).BoundToPort(3000); ``` 2. 接下来,需要创建一个Multicast组: ```c++ TSharedPtr<FInternetAddr> MulticastAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); bool bIsValid; MulticastAddr->SetIp(TEXT("239.255.0.1"), bIsValid); MulticastAddr->SetPort(3000); ``` 3. 然后,将Socket加入到Multicast组: ```c++ ListenSocket->JoinMulticastGroup(*MulticastAddr); ``` 4. 最后,可以使用以下代码来发送和接收消息: ```c++ // 发送消息 FString Message = TEXT("Hello, World!"); TArray<uint8> SendBuffer; FTCHARToUTF8 Converter(*Message); SendBuffer.Append((uint8*)Converter.Get(), Converter.Length()); int32 BytesSent; ListenSocket->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSent, *MulticastAddr); // 接收消息 TArray<uint8> ReceiveBuffer; FIPv4Endpoint Endpoint; if (ListenSocket->HasPendingData(Size)) { ReceiveBuffer.SetNumUninitialized(FMath::Min(Size, 65507u)); int32 BytesRead; ListenSocket->RecvFrom(ReceiveBuffer.GetData(), ReceiveBuffer.Num(), BytesRead, Endpoint); if (BytesRead > 0) { FString Message = FString(UTF8_TO_TCHAR(reinterpret_cast<const char*>(ReceiveBuffer.GetData()))); UE_LOG(LogTemp, Warning, TEXT("Received message: %s"), *Message); } } ``` 这是一个简单的UDP组播通信案例,可以根据自己的实际需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值