欢迎光临散文网 会员登陆 & 注册

UE4 - 2D Side Scroller 模板工程分解

2021-11-07 16:29 作者:紧果呗  | 我要投稿


# 🌟 2D Side Scroller 模板工程分解

UE4 自带的 2D Side Scroller 即 2D 横卷轴游戏工程模板,基于 Paper2D 动画帧来创建运动角色形象是常用技术。使用了 Flipbook 的示范内容,包括 2DCharacter_IdleAnimAtlas 和 2DCharacter_RunAnimAtlas.TGA 两张动画帧图片,可以将它们从工程中导出:右键菜单 Asset Actions -> Export。也可以上 Game Art 2D 网站上找图片资源。


分解一下 2D Side Scroller 模板项目,2DSideScroller 目录下主要是包含了 Textures 目录下的动画帧图片,和 Sprites 目录下和个动画帧对应的精灵对象。


最主要是 2DSideScrollerBP 目录下的蓝图对象,Maps/2DSideScrollerExampleMap 是一个默认关卡地图,打开项目后,视图看到的场景就是它。这个关卡上设置了简单的场景,可以在 World Outline 窗口中看到,Ledges 分组下有几个固定的平台挡板,包括场景两边的边界限制 LeftEdge、RightEdge,还有背景,它们都是 `PaperSprite` 类型,在 Details 可以看到 Collision 设置了 Can Character Step Up On,可以站在这个对象上面而不会掉下来。注意 Collsion Presets 设置了 PhysicsActor,这表示角色对象在模拟的物理世界中,如果没有相应的碰撞设置,物理对象就不会边界接触时产生的效果。


Enable Gravity 默认打开表示受重力,但 Simulate Physics 没有,所以重力模拟并没有生效,物件也不会有下坠跌落的效果。在打开物理模拟的情况下,即使没有重力,其它物理对象踩踏也会有作用。


场景中还有一个人物角色,对应内容浏览器的 Blueprints/2DSideScrollerCharacter,这个蓝图对象的设置才是重点,整个示范工程的逻辑基本都是它编排的。


在选中蓝图对象的情况下,可以点击 Details 面板上的 Edit Blueprint 按钮打开蓝图编辑器,可以看到 2DSideScrollerCharacter 蓝图对象的层次结构,并可以在蓝图的 Viewport 中编辑这些对象:


    +-- 2DSideScrollerCharacter(Blueprint 对象)

        +-- CapsuleComponent(Inherited) 用于碰撞检测的胶囊几何体 

        |   +-- ArrowComponent(Inherited) 箭头组件是简单的形状,表示对象的朝向,箭头不会在实际游戏中显示

        |   +-- Sprite(Inherited) 角色 Flipbook 动画组件

        |   +-- CameraBoom(Spring Arm Component) 弹簧手臂组件

        |       +-- SideViewCameraComponent(Camera Component) 对角色进行摄像

        +-- CharacterMovement(Inherited) 运动组件让角色具有运动能力 


SpringArmComponent 使其子项延长固定距离,然后在发生碰撞时收回,和 CameraComponent 一起使用,可以提供一个第三人称视角,切换摄像机使用 SetViewTargetWithBlend。


打开蓝图对象的 EventGraph,里面主要处理了用户输入时对应的响应逻辑,如跳跃、移动等,还有引擎因为的事件 BeginPlay 和 Tick。此外还有自定义的动画更新 UpdateAnimation 事件,这个事件由 Event Tick 调用,根据状态来调用 SetFlipbook 函数更改角色动画。


`UpdateAnimation` 事件的蓝图逻辑:


- 首先,由 Event Tick 调用,即 Event Tick 节点的执行流接入到 Call Function UpdateAnimation 节点的执行流输入端;

- 调用 Actor 对象的 GetVelocity() 得到移动速度值;

- 经过 Math Library 的 VectorLength() 处理得到向量长度,注意是向量的模,并经过一个浮点值比较,使用 `Float Greater` 节点,看是否大于 0 即有移动; 

- 使用一个 Select 分支选择节点,匹配前面的得到的布尔值,并按布尔值输入 RunningAnimation 或 IdleAnimation;

- 将 Select 分支节点输出的 Flipbook 对象输入到 SetFlipbook 函数节点的 NewFlipbook 参数端口;

- SetFlipbook 的 Target 端口是一个 Flipbook 引用,这里就是蓝图对象中的 Sprite,通过 GetSprite() 获取引用;


UpdateAnimation 事件处理走完流程后,蓝图对象的 Sprite 就会设置正确的一个 Flipbook 动画,如果是 RunningAnimation 则还要在 Tick 流程中处理左右方向,只需要沿 Z 轴即竖直方向翻转 180° 即可。


`Event Tick` 事件的蓝图逻辑:


- 由 UE4 引擎触发 Event Tick 事件的处理;

- 执行流程进入自定义的 UpdateAnimation 事件处理,并设置好 Sprite 对象;

- 另一边,通过 GetMovementComponent() 获取移动组件,获取其 Velocity 属性,也可以直接将 CharacterMovement 组件拖放到 EventGraph;

- 注意,因为是移动组织的属性,所以添加节点时,选择 Movement Component 的 GetVelocity(),可以关闭 Context Sensitive 选项以检索完整的节点列表;

- 使用 `Break Vector` 节点从 Velocity 向量中分离出 X 轴上的分量;

- 将 X 分量通过 `CompareFloat` 节点与 0.0 进行比较,得到 3 种结果,对应三个子流程;

- 小于或大于 0.0 的两种情况表示向左、向右有移动,那么就根据移动方向,执行 SetControllerRotation(),需要做翻转的一个流程输入一个 `MakeRotator` 并配置 Z 值 180,这样 Flipbook 的角色动画方向就正确了;

- 对于等于 0.0 的情况,只需要播放 IdleAnimation,根据蓝图变量 bisMovingRight 来判断角色最后是往什么方向移动,配合 `Branch` 节点做条件分支,使用同样的控制器翻转操作。

- 使用 Pawn GetController() 来获取角色的控制器对象;


`Axis Events MoveRight` 事件处理即运动处理逻辑:


- 由引擎接收到用户输入,并执行 MoveRight 事件,得到 AxisValue 浮点值;

- 使用 Branch 节点做流行执行;

    - 使用 Float Greater 判断,AxisValue 大于 0.0 就执行 Set bisMovingRight 节点,将变量设置为 true 值,表示向右移动了;

    - 否则,使用 Float Less 节点,也可以用 float < float 找到,判断 AxisValue 小于 0.0 就执行 Set bisMovingRight 将变量设置 false 值;

- 最后,执行 Pawn 的 AddMovementInput 函数,WorldDirection 使用单位向量 (1,0,0),AxisValue 作为 ScaleValue 与单位向量运算,得到移动的向量;


Pawn 还有其它类似的叠加输入值的函数 AddControllerPitchInput、AddControllerRollInput、AddControllerYawInput,注意 AController 本身是 AActor 的子类。


跳跃事件处理逻辑中使用了两个事件:


- `Action Events Jump` 引擎默认的跳跃事件,如按空格、向上箭头;

- `Input Touch` 触屏输入,触摸时就会跳跃,离屏就停止跳跃动作;

- 两个事件的 Pressed 执行流程都会调用角色的 Jump 函数;

- 两个事件的 Released 执行流程都会调用角色的 StopJumping 函数;


也可以直接设置一个 Keyboard Events J 事件来触发跳跃动作,但是这样硬编码不是很好。


UE4 的工程配置中,默认设置了用户输入的事件映射关系:


- Action Mappings 配置中将 W、UP、SpaceBar、Gamepad Face Button Bottom 即手柄的 A 按钮映射为 Jump 事件;

- Axis Mappings 配置中将 A、D、Left、Right、Gamepad Left Thumbstick X-Axis 即手柄的左摇杆的左右方向映射为移动事件;


相当于使用 C++ 代码的 BindAxis 和 BindAction 方法绑定事件与调用函数:


```cpp

void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)

{

    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // 移动轴事件逐帧反应,并提供 AxisValue 值。

    PlayerInputComponent->BindAxis("MoveRight", this, &AMyPawn::move);

    // 动作事件只在按下或松开按键时做出响应。

    PlayerInputComponent->BindAction("Jump",IE_Pressed,this,&AMyCharacter::jump);

}

```


绑定是通过委托 Delegate 泛型类型安全实现的,参考 `InputComponent` 类实现。


涉及对象的源代码位于 Paper2D 插件和 Engine\Source\Runtime\Engine\Classes\GameFramework\Actor.h


地图中有一个 PlayerStart 对象,表示游戏玩家的出场位置。


另一个重要的对象是 2DSideScrollerGameMode,它是一个 Data-Only Blueprint Class,只是单纯继承 AGameBase 基类。工程模板只创建这个可使用简单人物的 GameMode 对象,并让它使用人物角色,在 Default Pawn Class 属性指定 2DSideScrollerCharacter,这样开始游戏时,引擎就会将其实例化作为玩家操控的角色。


- 在 Content Browser 中,单击 New 按钮,然后单击 Blueprint Classs 选项。

- 在弹出的窗口内单击 Game Mode 按钮,以它为父类。

- 命名后打开 GameMode 蓝图并单击 Defaults 选项卡。

- 在 Defaults 选项卡的 Classes 部分,单击 Default Pawn Class 下拉菜单并选择新人物。

- Compile 并 Save,然后关闭蓝图。

- 在主编辑器窗口中,单击菜单栏上的 Edit 按钮并选择 Project Settings。

- 现在,我们要让我们的项目使用新建的 GameMode。

- 在 Project Settings 中,单击 Maps & Modes 选项。

- 在 Maps & Modes 的 Default Modes 部分,单击 Default GameMode 下拉菜单并选择你的 GameMode。


最后,游戏的进行还需要一个场所,即 Level Map 中设计的场景,项目提供的是 2DSideScrollerExampleMap,还有相应的 MapBuildData 即地图注册数据。 


通过 Project Settings -> Project -> Maps & Modes 可以给项目指定一个 GameMode 对象:


- Default GameMode 指定工程默认游戏模式对象;

- Game Startup Map 指定开始游戏时加载的关卡地图;

- Editor Startup Map 指定打开编辑器时加载的关卡地图;


每个关卡都有一个默认的关卡蓝图 Level Blueprint。它很特别,与一般的蓝图不同,它是管理整个地图的全局事件,并且 UE 4 不允许自己创建关卡蓝图。


此工程模板中的关卡蓝图并没有设置什么功能,只是布置了场景内容的一些跳台和阻挡物。


这也是一个简单的功能示范,缺少完整游戏的其它功能,比如与敌人的搏杀,关卡的转换,各种上 NPC 角色的设置等等。


下一步,通过官方文档学习其它关键内容,也可以使用官方提供的学习示范资源,如 Content Examples 就包含大量基础的知识点示范案例。



# 🌟 Paper2D 二维游戏系统

- 蓝图中的Flipbook组件 https://docs.unrealengine.com/4.27/zh-CN/AnimatingObjects/Paper2D/Flipbooks/Components/Blueprints/

- 设置 2D 角色的动画状态机 https://docs.unrealengine.com/4.27/zh-CN/AnimatingObjects/Paper2D/HowTo/Animation/

- Paper 2D Import Options https://docs.unrealengine.com/4.27/en-US/AnimatingObjects/Paper2D/Importing/

- Paper 2D Sprites https://docs.unrealengine.com/4.27/en-US/AnimatingObjects/Paper2D/Sprites/

- Paper 2D 组件 https://docs.unrealengine.com/4.27/zh-CN/Basics/Components/Paper2D/

- Components 组件 https://docs.unrealengine.com/4.27/zh-CN/Basics/Components

- Paper 2D 图块集/图块地图 https://docs.unrealengine.com/4.27/zh-CN/AnimatingObjects/Paper2D/TileMaps/

- Paper 2D Content Examples https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/Paper2D/


Paper2D 是 UE4 提供的基于精灵的 2D 游戏系统,可以用于构建 2D 和 2D/3D 混合游戏。


在 2D 游戏中,基于动画帧来创建运动角色形象是常用技术。使用 UE4 自带的 2D Side Scroller 即 2D 横卷轴游戏工程模板就自带了 Flipbook 的示范内容,包括 2DCharacter_IdleAnimAtlas 和 2DCharacter_RunAnimAtlas.TGA 两张动画帧图片,可以将它们从工程中导出:右键菜单 Asset Actions -> Export。也可以上 Game Art 2D 网站上找图片资源。


目前 Paper2D 的动画系统是基于帧动画的,社区讨论中虽然有加入 2D 骨骼动画系统的讨论,但是目前的正式引擎版本中并没有这样的功能。


Paper2D 提供了四种 Components 对象,可以在内容浏览器中添加:


- Sprite 精灵

- Flipbook 帧动画

- Tile Set

- Tile Map


## ⚡ PaperSprite


`Sprite` 是帧动画的基本组织单位,它来源于对 Texture 即动画帧图片的裁剪,形成动画的一个帧精灵并最终用于 FlipBook 动画播放。同时 UE4 支持导入 Texture Packer 和 Adobe Flash CS6 生成的帧动画。


精灵的默认材质是 Paper2D 系统提供的 MaskedUnlitSpriteMaterial 材质,它可以将 Texture 透明区过滤掉,如果需要反转过滤使用 MaskedLitSpriteMaterial。


Sprite 属性参考:


- Source Texture 当前精灵所使用的 2D 图像

- Source UV 裁剪的起始点在原图形上的偏离,像素单位

- Source Dimension 从起点开始裁剪指定的像素大小,和前面一组设置就可以将动画帧中的一个状态图片裁剪出来。

- Default Material 精灵的默认材质,这个材质属性可以被 Flipbook 的设置覆盖。

- Additional Textures 为精灵提供额外的贴图,当前文档中没有给出描述。

- Pixels per unit 设置像素与引擎内部单位之间的缩放比例,用于调整精灵在 UE 世界中的大小。在 Paper2D 的插件设置中有全局设定,也可以对每个精灵进行指定。

- Pivot Mode 中心点位置。设置为 Custom 的话可以进行精细的设置。

- Sockets 和 3D 动画中的 Sockets 功能时类似的,提供一个槽口来放置装饰物件。

- Collision 精灵碰撞系统设置,可以选择无碰撞或者3D。


往 Sprite 添加插槽装饰物,可以生成粒子特效,如身上着火的角色,或将一把武器(如一把枪或一把剑)附加到角色手上,或生成任意数量的各种物品并附加到 Sprite 的插槽。添加插槽后,通过蓝图访问 Sprite 插槽,并设置将其它 Sprite 组件附加到插槽上。可以使用 Property Matrix 同时对所有 sprite 进行修改,节约时间。


通过蓝图访问 Sprite 插槽:


- 在人物角色蓝图的 My Blueprint 窗口中点击眼睛图标和 Show Inherited Variables。

- 将角色的 Character 中的 Sprite 组件拖入到蓝图。

- 在 `Event Begin Play` 节点的引出连线后添加一个 `Spawn Actor from Class` 节点(设为所需的 Actor 类)。

- 添加 `Make Transform` 节点并应用到 Spawn Transform 端,在 Return Value 的引出连线后使用一个 `Attach To` 节点。

- 将 Sprite 组件作为 In Parent 接入,在 In Socket Name 输入选择创建好的插槽。

- 编译并在编辑器中进行游戏,生成的 Actor 类将在插槽位置生成并成功附加。


可添加一个插槽到一个 Sprite,并在插槽中附加任意数量的不同内容。Sprite 是否为 Flipbook 的一部分,是否已设置动画,以及插槽中的内容均完全取决于您的选择。



Paper2D 中可以选择的碰撞使用的引擎内通用的 PhysX,以前的 2D 碰撞使用的是 Box2D,也只能支持 Win32 和 Win64 两个平台,要使用额外的功能还要在项目设置中打开 Enable 2DPhysics 开关。


对于 2D 系统,Sprite 对象可以应用物理系统,及物理约束。物理对象需要对世界场景和玩家交互作出反应,然而需要将其限制在关卡内,使用约束可以防止其在特定的轴上旋转。


在关卡中选择需要应用物理的 Sprite,在 Details 面板中,点击 Physics 下的 Simulate Physics 选项,展开 Constraints 并设置:


- Lock Position(对横卷轴游戏而言,通常锁定到 Y 轴)。

- Lock Rotation(对横卷轴游戏而言,通常锁定到 X 轴)。


Paper2D 的坐标系统,X 轴向右,Y 轴向垂直屏幕向外,Z 轴向上,分别用红、黄、蓝三种色表示,锁定一个轴向,就表示不能在这个轴上移动,或者不能以这个轴为中心进行旋转。


碰撞检测的边界有几个不同的方式,越简单规则的边界运算越快速:


- Source Bounding Box 源边界框式,在 Sprite 上使用源图形的边界框。

- Tight Bounding Box 严格边界框式,将 sprite 的全透明区域排除在外,多数情况下这种方式能生成更佳的碰撞效果。

- Shrink Wrapped 收缩包裹式(实验性)生成匹配 Sprite 不透明区域的复杂几何体,效果最真实,但额外的几何体可能对运行性能产生影响。

- Fully Custom 自定义式,可指定视口中互动使用的几何体。

- Diced 方块式,由多个小方块组合,包括最终几何体中仅为非空的小方块。


使用上的建议是使用默认的简单图形进行碰撞,如果需要使用精细的碰撞的话可以使用 Sockets 来外挂碰撞体来进行碰撞检测,逐帧进行精细的碰撞检测是相当消耗系统运算力的。


渲染区域调整功能更重要的是对渲染区域进行调整,将有的精灵中多余的空白部分排除到渲染之外的话,可以很好的降低渲染压力。


`PaperSpriteComponent` 负责处理 UPaperSprite 实例的渲染和碰撞。 当你将 Sprite 资产从内容浏览器拖到蓝图,该组件就会自动创建;或者,当你将某些 Actor 拖入关卡中时,该组件会包含在其中。


这类组件的一种用途就是充当搭建关卡的 Sprite,比如,岩架或平台、梯子和斜坡等。将这些 Sprite 资产放置在关卡中将创建一个 PaperSpriteActor,该 Actor 使用的 PaperSpriteComponent 实例基于选定 Sprite 资产生成。


## ⚡ FlipBook


`FlipBook` 是帧动画的管理类,将 Sprite 组织成动画进行播放,只需要将创建好的 Sprite 对象添加到 FlipBook 组件的 Frame 中,设置好播放帧率就可以在蓝图中使用。


创建 Sprite 时,先导入原始动画帧图片,再通过 Sprite 编辑器编辑新建的精灵对象,将 Source Texture 指定为刚导入的图片。在编辑器的右上角,有一个四棵小树的图标,即 Edit the sprite source region,点击后可以使用 Extract Sprites 功能将所有帧图像提取为相应的 Sprite,功能位于左上角的格子图标。对于规整的图像,使用 Grid 提取模式,并将 Cell 的宽高设置为适当大小即可。


将多个 Sprite 拖入 Flipbook 的 Frame 列表,即编辑器的底部格子上,可以快速创建动画帧。或者,直接选择所有 Sprite,使用右键菜单的 Create Flipbook 创建。 


属性如下:


- Frames Per Seconds 每秒帧率,值越大运动越快;

- Default Material 动画帧使用的材质;

- Key Frames 中存储的是每一个用到的关键帧的精灵的属性,可以调整的目前只有 Frame Run,为帧的持续帧数;

- Collision Source 为碰撞模式选择,可以选择关闭碰撞、逐帧碰撞或者使用第一帧进行碰撞。


实际运用中更加重要的是 FlipBook,这个蓝图类提供了很多方便的对 Flipbook 进行操作的接口。设置 2D 角色的动画状态机,可以使角色基于定义的条件在不同 Flipbook 动画之间切换。


`PaperFlipbookComponent` 可以在 3D 空间中任意放置、附加到其他组件上或自身附带其他组件。 你可以为每个实例指定一个自定义颜色;该颜色会被传递给 Flipbook 材质作为顶点颜色参数。你也可以为它们指定一个自定义材质,用于替代 SourceFlipbook 中定义的默认材质。


使用脚本,你可通过调用 SetFlipbook 函数更改当前 SourceFlipbook 资产,但是,请注意仅当 Mobility 属性设为可移动(或在 Actor 构建过程中调用该函数)时,上述操作才有效。 你也可使用组件上的各种其他方式来控制播放速度、播放方向以及循环等。


## ⚡ TileSet & TileMap


是瓦片地图功能,原理就是利用一小块图片 Tile 拼接组成一个大地图。TileSet 指定包含多个 Tile 的 Texture 图片资源,并设置好每个 Tile 占据的像素大小。然后将 TileSet 作为绘图色彩一样绘制到 TileMap 的图层上,得到地图,绘制时指定 Active Tile Set。TileMap 也需要设置每个 Tile 的大小,和整个 Map 的大小,即容纳 Tile 数量。


Tile 本身的碰撞在 TileSet 中进行设置和调整,在 TileMap 中也有开关进行碰撞类型的选择,Sprite Collision。


有一个属性需要注意,Sepration Per Layer,这个属性是用于调整每一层地图之间的距离的,在多层地图中,相当于通常的 Z-Order 设置的位置,可以为一些地图特效提供帮助。


UE4 - 2D Side Scroller 模板工程分解的评论 (共 条)

分享到微博请遵守国家法律