UE的Gameplay框架(二) —— Actor和Component

这篇博客聊一下UE的Gameplay框架很重要的一部分 Actor 和 Component



Actor

如UE文档所述,所有可以放入关卡的对象都是 Actor,比如摄像机、静态网格体、玩家起始位置。Actor 支持三维变换,例如平移、旋转和缩放。在 C++ 中,AActor是所有Actor的基类。

但这里的变换(位置、旋转和缩放)数据并不是直接作为 Actor 的属性保存起来,而是通过组件(准确的说是场景组件)给Actor提供了三维变换的功能。Actor 本身只提供了一些基础的属性和功能(比如网络同步、Tick、创建销毁、生命周期)的小baby,而组件则是让Actor成为有各种技能的成年人(移动、感知、渲染、物理)。

关于组件的内容放到下一节细说,下面简单介绍下 Actor 本身。

  • 创建 Actor:可以使用泛型 SpawnActor() 函数或它的一个特殊模板化版本进行操作,可以看到用模板的方法内部也是调用了上面传入UClass版本的 SpawnActor()
	/**
	 * Spawn Actors with given transform and SpawnParameters
	 * 
	 * @param	Class					Class to Spawn
	 * @param	Location				Location To Spawn
	 * @param	Rotation				Rotation To Spawn
	 * @param	SpawnParameters			Spawn Parameters
	 *
	 * @return	Actor that just spawned
	 */
	AActor* SpawnActor( UClass* InClass, FVector const* Location=NULL, FRotator const* Rotation=NULL, const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters() );

	/** Templated version of SpawnActor that allows you to specify a class type via the 		template type */
	template< class T >
	T* SpawnActor( const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters() )
	{
		return CastChecked<T>(SpawnActor(T::StaticClass(), NULL, NULL, SpawnParameters),ECastCheckedType::NullAllowed);
	}
  • Ticking:Ticking赋予了Actor生命,以规则间隔(每帧/设定的时间间隔)在一个actor或组件上运行一段代码或蓝图脚本。我们想要对于子类Actor每帧都要执行一定的操作,就可以重写 AActor 的 Tick。
    Ticking的高级用法就涉及到Tick组和Tick依赖关系了,这里不展开(博主也没完全掌握),可以看下官方文档

  • 网络同步:属性值和函数调用均可被复制,以便对客户端上游戏的状态进行完整控制,这里涉及到网络同步了,可以看下博主之前写过的有关网络同步的内容

  • 销毁Actor:Actor通常不会被垃圾回收,因为场景对象保存一个Actor引用的列表。调用 Destroy() 即可显式销毁 Actor。这会将其从关卡中移除,并将其标记为"代销毁",这说明其在下次垃圾回收中被清理之前都将存在(挖个坑,后续好好研究下UE的内存管理和GC)。
    主要就是调用 World 里的 DestroyActor,内部是:

    1. 从World里的Actor列表里移除
    2. 将Attach该Actor的子Actor取消Attach(也就是不会销毁子Actor)
    3. 如果该Actor有Attach的父Actor,也将其从父Actor取消Attach
    4. 如果Actor有Owner,通知Owner其失去了一个孩子
    5. 通知NetDriver这个Actor要被销毁了
    6. Unregister该Actor所有的组件,取消他们的物理和渲染
    7. 标记Actor和其所有组件为PendingKill
    8. Unregister Actor和其组件的 Tick 函数
bool AActor::Destroy( bool bNetForce, bool bShouldModifyLevel )
{
	// It's already pending kill or in DestroyActor(), no need to beat the corpse
	if (!IsPendingKillPending())
	{
		UWorld* World = GetWorld();
		if (World)
		{
			World->DestroyActor( this, bNetForce, bShouldModifyLevel );
		}
		else
		{
			UE_LOG(LogSpawn, Warning, TEXT("Destroying %s, which doesn't have a valid world pointer"), *GetPathName());
		}
	}

	return IsPendingKillPending();
}

Component


Component 给Actor提供各种能力,Actor可以看作是Components的容器。按UE官方文档所述,组件可以按照使用场景分为如下几个主要的类(这里也是存在明显的继承关系,比如Primitive组件自然可以有自己的三维变换,那么继承自Scene组件是很直观的):

  • Actor组件:(类 UActorComponent) 最适用于抽象行为,例如移动、物品栏或属性管理,以及其它非物理概念。Actor组件没有变换,即它们在场景中不存在任何物理位置或旋转,除了 Scene 组件继承自它,其实还有好多没有物理概念没有三维变换的组件继承自它,比如UMovementComponentAIComponent
  • 场景组件:(类 USceneComponent) 支持基于位置的行为,这类行为不需要几何表示。这包括弹簧臂、摄像机、物理力和约束(但不包括物理对象),甚至音频(有位置概念才能根据远近有不同的音量大小)。
  • Primitive组件:(类 UPrimitiveComponent) 是拥有几何表示的场景组件,通常用于渲染视觉元素或与物理对象发生碰撞或重叠。这包括静态或骨架网格体、Sprite或公告板、粒子系统以及盒体、胶囊体和球体碰撞体积。

SceneComponent

除了提供三维变换,SceneComponent还提供了在这一层的嵌套,所以其实对于Actor来说,Actor之间的嵌套也是在SceneComponent这一层实现的,我感觉这里的嵌套更多是为了实现相对于父节点的三维变换。

下面可以看到 AttachToActor 也是转发到 SceneComponent 这一层处理的

void AActor::AttachToActor(AActor* ParentActor, const FAttachmentTransformRules& AttachmentRules, FName SocketName)
{
    if (RootComponent && ParentActor)
    {
        USceneComponent* ParentDefaultAttachComponent = ParentActor->GetDefaultAttachComponent();
        if (ParentDefaultAttachComponent)
        {
            RootComponent->AttachToComponent(ParentDefaultAttachComponent, AttachmentRules, SocketName);
        }
    }
}
void AActor::AttachToComponent(USceneComponent* Parent, const FAttachmentTransformRules& AttachmentRules, FName SocketName)
{
    if (RootComponent && Parent)
    {
        RootComponent->AttachToComponent(Parent, AttachmentRules, SocketName);
    }
}

注册组件

组件还有一个注册的概念,为了让Actor组件能够逐帧更新并影响场景,引擎必须注册这类组件。

如果在Actor产生过程中,作为Actor子对象自动创建了组件,则这类组件会自动注册。游戏期间创建的组件,需要我们手动使用 RegisterComponent 进行注册。

在注册组件的过程中,引擎会将组件与场景关联起来,让其可用于逐帧更新,并会调用如下 UActorComponent 函数:

  • OnRegister 在注册组件时,可以覆写此函数来添加代码
  • CreateRenderState 初始化组件的渲染状态
  • OnCreatePhysicsState 初始化组件的物理状态

与注册对应,我们想从更新、模拟和渲染过程中移除Actor组件,可以使用 UnregisterComponent 函数将其取消注册。

在组件取消注册时,将调用下面的 UActorComponent 函数:

  • OnUnregister 在取消注册组件时,可以覆写此函数来添加代码
  • DestroyRenderState 取消初始化组件的渲染状态
  • OnDestroyPhysicsState 取消初始化组件的物理状态

Actor生命周期


不管是LoadMapAddToWorld 这种从磁盘里加载Actors的方式,还是运行时 spawn 生成Actors,都会经历 PreInitialize Components -> InitializeComponents -> PostInitializeComponents -> BeginPlay 之后 Actors 就会开始 Ticking 了,如果游戏结束了或者Actor设定的生命周期时长到了或者被Destroy了或者发生了关卡迁移等,会触发 EndPlay 也代表Actor的生命周期要结束了,后续也会被标记为 PendingKill 然后从ULevel中的Actors array移除,等待被垃圾回收。


参考资料

《InsideUE4》GamePlay架构(一)Actor和Component
组件
Actors

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UE4中的Gameplay框架是一个强大的工具集,用于开发和实现游戏玩法和用户交互。该框架提供了许多功能和组件,以帮助游戏开发者快速构建出丰富、流畅的游戏体验。 UE4Gameplay框架主要由以下几个方面组成: 1.输入系统:该系统可以处理各种输入设备的操作,如鼠标、键盘和游戏手柄。开发者可以轻松地设置和管理输入映射和按键绑定。此外,还提供了鼠标和手柄的即时响应和移动方向控制功能,使玩家能够自由操作游戏中的角色。 2.角色控制器:角色控制器是游戏玩家在游戏中扮演的角色,他们的控制是通过输入系统和蓝图来实现的。游戏玩家可以移动角色、执行动作、攻击敌人等。角色还可以通过动画系统实现自然的运动和交互。 3.人工智能:UE4Gameplay框架提供了内置的人工智能系统,可以对NPC和敌人进行编程控制。开发者可以设置敌人的行为模式、路径寻找和攻击策略,让游戏中的敌人具有更真实和智能的表现。 4.物理模拟:UE4Gameplay框架使用了物理引擎来实现真实的物理模拟效果,比如碰撞、重力和刚体运动等。这使开发者能够创建更真实和具有交互性的游戏世界,使玩家可以与环境进行互动。 总之,UE4Gameplay框架提供了强大而灵活的工具,帮助开发者轻松地构建出丰富多样的游戏玩法和用户交互。无论是开发动作冒险游戏、射击游戏还是角色扮演游戏,该框架都能满足开发者的需求,并带来令人惊叹的游戏体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值