fps-bp-notes

FPS Blueprint notes

Subtitle: Youtube 上的 FPS UE 项目笔记
Created: 2023-11-14T21:55+08:00
Published: 2023-11-24T16:54+08:00
Categories: UnrealEngine

Creating A First Person Shooter Game (FPS) With Unreal Engine 4 - YouTube

这个项目要实现的效果:
FPS 游戏,玩家操控角色攻击 NPC,可以快速了解一个 FPS 游戏大概是怎么样的。

  1. 切换枪支
  2. 可以扔手雷
  3. 开镜
  4. 角色移动,Sprint、下蹲、角色看天空和看地面的时候脊椎有变化
  5. 简单的 AI 系统
  6. 小地图 Minimap
  7. 简单的地形编辑

不支持:

  1. 换枪动画、扔手雷动画
  2. AIController
  3. Level Streaming

这种教程可以优化的点是,看一开始就规划好整个项目类的成员变量等、函数、事件,不然临时改来改去。

  1. Intro

  2. True First Person Camera

    • Camera 不要用 rope 了,直接 attach 到 SM 上,并且设置 parent 为 head,并修改 transform
    • 不论是第一人称还是第三人称,都需要确定好相机和人物 rotation 如何被控制,对于第一人称
      1. 相机用 Controller 的 Rotation:相机可以「指哪打哪」
      2. Character 用 Controller 的 Yaw:人物只能左右
  3. Player Health & Armor

    1. Character 需要有 Health 和 Armor,我提取成一个 ActorComp 来处理,任何有这个 comp 的 actor 就认为有血量
    2. 用 Widget 中的 Progress Bar 来显示 Health 和 Armor,注意是浮点数,bar 长度用 percent 控制,CreateBinding > GetPlayerCharacter > ...
    3. 在 Character 的 EventBeginPlay 中 create widget 并 AddToViewport
  4. Regenerating Armor & Damage Function:

    1. 实现 Armor 自增长:Armor 小于 1 的时候要随时间增加
    2. TakeDamage: 先减少 Armor,若 Armor 减少后为负数,说明该负数要作用于 Health 上,最后因为显示的原因,set armor 为 0
      我封装到 Comp 里了,而且 Damage 是浮点函数输入 img
  5. Blood Splash Effect:做一个 Widget,就一张图片,用动画设置透明度,每次受伤就添加到 viewport

    1. 为 UI 添加一个 Fade Animation:牢记动画是属性的变化
    2. 在 UI Graph 中,每次创建就播放动画,不要在 Comp 或者 Actor 创建再播放,UI 动画的播放由 UI 自己管理
    3. TakeDamage 结尾创建 UI 并 AddToViewport,注意给一个 controller
      note. 但是这样会浪费内存吧
  6. Setting Up Character Animations:

    1. Ironsights 的 BlendSpace: Jump
    2. ABP 的状态:Locomotion:Jump
  7. Finishing The Animation Blueprint

    1. 和 UE 自定义的 ABP 的区别在于,Walk/Run 里面直接用 BS_Aiming
    2. 使用 Direction 和 Speed 作为 BS_Aiming 的输入
  8. Adding The AK-47 Weapon

    1. 导入材质:包括以 SK 导入枪支,还有 Texture、Specular 和 Normal Map,Tip 是先在 Content Drawer 中选中 Texture2D,
      然后在新建的 Mat 编辑器中按住 T 再鼠标右键,就可以直接导入,最后在 SK 编辑器里为其设置 Material。 img
    2. 在 Skeletal 编辑器中为角色添加 socket 用来放置枪支,可以开启 preview asset on socket 以及 preview with animation
    3. 在 Character 中 Spawn and Attach spawn-weapon-attach
  9. Firing Our AK-47 Weapon

    1. Make Bullet: BP_BulletBase, 使用 Mesh 和 ProjectileMovement Comp,设置 InitialSpeed MaxSpeed GravityScale,我自定义了 CollisionComp 作为 root
    2. Weapon Can Fire: SK Weapon 的 Muzzle Socket 和 Fire event,商店里那个 Package 已经做好了 Muzzle,同理需要 preview
      note. 一个非常小的细节:如果 Weapon SM 的朝向是 Y,那么后续所有的都是 Y,因为 socket 上 preview 的是 Static Mesh 的坐标系
      就不能修改 SK 的朝向,然后子弹的朝向也要和 Y 一致
    3. 设置 Input Map,通过 Spawn Bullet 开火
  10. Crouching With Animations: 通过新的状态来实现下蹲,记得要在 CharacterMovementComponent 里开启下蹲 和使用 Crouch 和 UnCrouch 函数

    1. 新建 BlendSpace
    2. InputMapping 蹲下,注意设置 MaxSpeed
    3. 状态机,让我惊讶的是,Crouch 进入两个状态的 Condition 是一样的 img
  11. Sprinting With Animations: 类似上面,就是按下 Shift 可以进入 Sprint 状态

    img

  12. Using Control Rotation: 角色看天空和看地面的时候脊椎有变化

    1. 三个 Modify Bones,并且取消 ExposeAsPin Translation、Scale\Alpha,RotationMode 为 AddToExisting,bone 分别为 spine, spine01, spine02,
    2. 用一个 AimRotation 变量,此处有点儿像黑魔法,没有看懂,只能理解只需要修改 Pitch img
  13. Fully Automatic Rifle:按着左键后就开枪,松起就不开枪,同时枪支有弹药数量限制,显示子弹数量

    1. note. 其实就是一个「一直按着」的状态,按下左键后设置 IsFiring 为 True,表示正在按着左键,然后调用 Fire 后,delay 看是否还按着,如果是的话就接着 Fire img
    2. 子弹数量限制就 Weapon 新增变量,并且每次 Fire 前检查是否有子弹
    3. 显示子弹数量用 Text 以及 CreateBinding
  14. Aiming Down Sights: 瞄准视角切换

    1. 加上 SK Weapon,切记不要 attach 到 CharacterMesh 上,否则,Character 会 idle 枪支也会跟着抖动
      Mesh HiddenInGame,attach 一个 Camera 给它,muzzle 上,调整位置,设置 AutoActivate False
    2. 按下鼠标右键就 aim,就是设置 activate 和 deactivate,
      note. 遇到一个 idle 枪支抖动的问题,我的方法是把摄像头往前,不要看到准星
    3. 算了,直接 copy 一个 Camera,搞不定抖动的问题
  15. Spawn Muzzle Flash: 下载一个 Effect 特效在 MarketPlace,在 Weapon SK 中新建并调整 Muzzle preview 这个 effect,
    生成的时候 spawn emitter 就好

  16. Fix:Crouch 和 SPrint 冲突了,需要按下 Sprint 按键的时候,检查是否处于 Crouch,if so,break out of this state,按下 Crouch 同理

  17. Setting Up Ammo & Reloading:
    首先知道什么是 Clip,区别于 Magazine:Why use clips when you can use magazines? - YouTube

    1. 枪支的逻辑:
      CarriedAmmo:士兵携带的总弹药
      CurAmmo:枪支弹匣(Magazine)内的弹药
      Reload 前,弹匣里子弹满,Reload 后,不管 CurAmmo 中是否有剩余,就都丢掉,使用 CarriedAmmon 中 Clip 的数量补充为 CurAmmo
    2. 我自己是制作了一个 Inventory Comp 来完成这个功能
  18. Conservative Ammo Reloading: 和 17P 的逻辑不同,尽量让 CurAmmo 为一个 Clip 的数量,

    if CurAmmo >= Clip:
        print("Full and Don't need Reload")
        return
    AmmoDiff = Clip - CurAmmo
    if CarriedAmmo >= AmmoDiff:
        CarriedAmmo -= AmmoDiff
        CurAmmo += AmmoDiff
    else:
        CarriedAmmo = 0
        CurAmmo += CarriedAmmo
    
  19. Weapon Reload Animation: 也是为 BP_Character 定义状态,一旦 Reload,ABP 中的状态就是一个 Reload Sequence,
    何时从 Reload 转移?在 BP_Character Blueprint 中过 0.2s 后改变状态变量
    note. 这是一种原始的做法,我的方法是 Play Montage,Rewrite UpperBody,在 Sequence 中也可以增加 Notify,并且放到 Montage 后还是会生效
    PlayMontage 结束后再 set Reloading? 这个状态变量

  20. Firing System Fix: Fire 前检查不能是 Sprint 或者 Reload

  21. Aiming With A Crosshair: 在 UI 里加 居中的 image,同时对 image 的 visibility 属性 binding 到 Character 的是否 ADS 状态上

  22. Dynamic Spread Crosshair: 用了一个别人做的 asset,可以配置 crosshair 的长度、厚度,Jump

  23. Picking Up Ammo:角色可以通过 Overlap 到弹匣补充身上的子弹

  24. Setting Up AI & Bullet Damage:

    1. new Character BP,named SimpleAI,add SK and ABP for it
    2. AI Overlap 后转 BulletBase,对自身的 Health 造成损害,可以通过 Comp 实现,Health <= 0 后 destroy self
  25. Enemy AI Following/Chasing:

    1. NavMeshBounds 拖进去,按 P 显示
    2. Add PawnSensingComp For AI, OnSeePawnEvent, PrintString 检查下,有个 AIMoveTo 的 api,像一个 Util,把 Pawn 移动到对应的 actor img
  26. Aiming Fixes:

    1. ADS event 内,若处于 Reload,就啥都不做
    2. ADS Event 内,若处于 Sprint,立刻停止 Sprint 再 ADS
    3. Sprint 时候 Deactivate ADS
      Tip: 可以 Collapse 成 Function
    4. Aim 的时候不要显示那个可以伸缩的 Crosshair,就是复制粘贴四份 Binding 函数
  27. SmarterAI:

    1. AI 被子弹击中,播放中弹粒子效果,
    2. 被子弹击中,MoveTo 开枪对象,这里我用 Spawn Bullet 时候的 Instigator 实现
  28. Random AI Roaming Setup:

    1. 当 AI 看不见角色的时候需要随机移动,所以设置变量表示是否看到了角色,在 SeePawn 里
    2. EventTick 时候检查这个变量,用 GetRandomReachablePointInRadius 随机选点的 api
      random-walk-when-cant-see-pawn
      img
  29. Smooth Gun Movement: 角色左右移动的时候,枪支会抖动,带动准星的视角一起抖动,解决方法是在移动的状态里 LayeredBlendPerBone

  30. Simple Objective System: UI 上显示目标文字,当 Character 和某个 Collision 重合的时候,就改变这个目标文字

  31. Setting Up Our HUD:血条、血量、当前弹匣子弹,所有子弹

    1. 修改 ProgressBar,三个属性,BackgroundImage、FillImage 以及 Appearance,每个 Image 都是可以设置 Tint 属性的
    2. Image 组件要让大小和原来的图片大小一致,这样 Place 好 Health 和 Armor 的 Icon img
  32. Enemy Killfeed: 一个 Kill Who 的 Popup,然后下移并且 Fade,下移的目的是为了不挡住后面 Popup 的

    1. 专门做一个 Widget,Layout img
    2. 动画以 background 为主,两个 Text 的 keyframe 参数直接复制粘贴 img
    3. bug: 如果在 delay 前面 CreateWidget,Widget 就会有延时,如果在 Delay 后就不会 img
  33. Creating a Minimap: 在用户头上放一个摄像机,附带一个 拍摄的画面渲染到一个 texture 上

    1. Camera 下面有一个 RenderComp2D,新建一个 Texture 作为 RenderTarget img
    2. 新建 Material,Domain 是 UserInterface,选 RenderTarget,将此 Material 作为 UI 中 Image 的 brush
  34. Match Timer: 屏幕左上角有倒计时

    1. 摆 UI
    2. GameMode 中新建变量表示游戏开始了多久,用 delay 1s 做更新的逻辑
    3. 有个 api 叫做 GetGameMode img
    4. 要 PauseGame 可以直接用这个名称的 API
  35. Hit Marker With Animation:击中敌人,屏幕中心出现 Marker,并 Fade,Jump

  36. Starting Weapon Switching (HUD): UI 显示 按下 1 切换到武器 1,按下 2 切换到武器 2

    1. InputAction 改变 Character 内一个 选中 Weapon 的 Num
    2. 绑定到 UI 上文字和 两张图片的 visibility
      文字没法直接 MakeText
  37. M4A1 Weapon Pickup

    1. 拖入 FBX 文件和 Diffuse 图片,用 DiffuseTexture 做一个 Material,并且设置 Metallic, Roughness 和 EmissiveColor img
    2. 新建 Actor,M4A1Pickup, ControlledCharacter 内设置变量 是否 Pickup 了 M4A1,if so,才可以进行切换
      我使用一个 Pickup base Class 做这件事,包括 Collision 和 SkeletonMesh
    3. 设置 Collision,碰撞后 set character 的 bPickup 并且 destroy
  38. Weapon Pickup Message:当和 M4A1 发生碰撞后,就 Popup 一个 Message,显示 pickup 了,用动画结合 Opacity 实现

  39. M4A1 Weapon Setup:添加 M4A1 Actor,

    1. 作为 WeaponBase 的子类,可以新加一个 SK 放置 AK47,然后对其二者的大小和扳机位置 img
    2. 对 SK add socket,并且 Preview Flash 和 Bullet,调整 Transform
  40. Changing Weapon Visibility:通过在 Character 内保存两个 Weapon Actor 的引用,通过切换武器的时候 SetVisibility

    1. EventBeginPlay Spawn 并且保存 SecondaryWeapon,SetVisibility
    2. InputAction 时候 SetVisibility img
  41. Displaying Secondary Ammo:在 UI 中显示当前枪支内还剩下多少子弹以及有多少用于填充
    我觉得要用数组来管理

  42. Consuming & Reloading M4A1 Ammo: 所有直接使用 Weapon01 的地方,都要修改,我的方法是做一个 GetEquippedWeapon 的地方。

  43. Weapon Line Tracing:修改 Fire 函数,使用摄像机的 Location 和 Rotation 的 ForwardVector 做 LineTrace
    我的方法是用 ConvertScreenLocationToWorldSpace

    img

  44. Ray Tracing While Aiming Down Sight: 通过 Aiming 变量判断应该使用哪一个相机

  45. Damaging With Line Trace: Jump, 这蓝图连的也太糟了。

  46. Crouch Height Adjustment: 在 CharacterMovementComponent 中有一个 CanCrouch,并且蓝图本身也可以调用 Crouch 和 UnCrouch 函数

  47. Zombie body setup: 导入 Zombie 资源,写 ABP,使用 Zombie SK

  48. Zombie Ragdoll Death Physics: 对死亡后的 NPC 的 Mesh SetSimulatePhysics

  49. Zombie Attack Animation: 为 ZombieCharacter 设置状态切换,攻击是通过 在 Mesh 上加 Socket 并 attach 一个 Collision,重叠就掉血

  50. Grenade Spawning:按下 G,在 Character 前面一点的位置生成一个 Grenade,并且在 BeginPlay 的时候给它一个 Impulse,3s 后 SpawnEmitter

  51. Grenade Damage:添加 Collision,可以 GetOverlappingActors,Destroy 之

  52. Starting The Game Level:使用 Landscape 编辑器让平地周围隆起小丘,中间一个坑,使用 Paint 画出一条小路,最后效果如下:

    img

    1. 下载 OpenWorldDemoCollection
    2. 新建 Level,删除地板,打开 Landscape,新建一个 Landscape,可以探索 Sculpt Tool,有 Sculpt、Erase 和 Erosion 等
      在一个地点 Sculpt 会导致出现山峰,Erase 可以削减山峰,Erosion 可以使地面凹陷

      img
    3. 新建 Material,并且用 Grass 和 Mud Blend,将此 Material 作为 landscape 的 Mat img
      在 Landscape 的 DetailsPanel 中选择它作为 LandscapeMaterial
    4. 在 Paint Tool 中,Create 刷材质。 img
  53. Decorating our level:

    1. FoliageMode,把要的 Tree 的 Mesh 拖进去,然后可以调节 Density 等参数,Paint img
    2. 新建 Plane,水面只是一块有 水的 Material 的平面,
    3. 使用 PostprocessingVolume,调整 Scale 使之 Cover 整个 Level,
    4. 把 Zombie 放进去,记得要 NavMesh 再 Build Path
  54. Smoke Grenades:在 Spawn Grenade 的时候换一种 Emitter,并且记得 Destroy

  55. Grenade Count:可以捡起 Grenade,并计数,Jump

posted @ 2023-11-24 17:50  ticlab  阅读(12)  评论(0编辑  收藏  举报