mini: false, //迷你模式 autoplay: false, //自动播放 theme: '#FADFA3', //主题色 loop: 'all', //音频循环播放, 可选值: 'all'全部循环, 'one'单曲循环, 'none'不循环 order: 'random', //音频循环顺序, 可选值: 'list'列表循环, 'random'随机循环 preload: 'auto', //预加载,可选值: 'none', 'metadata', 'auto' volume: 0.7, //默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 mutex: true, //互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 listFolded: false, //列表默认折叠 listMaxHeight: 90, //列表最大高度 lrcType: 3, //歌词传递方式

AISystemPlugin

创建 Behavior Tree 和 Blackboard

创建行为树和黑板:
屏幕截图 2025-10-25 180616
在黑板中添加一个Object类型的Key:
屏幕截图 2025-10-25 180855
将Base Class设置为Actor:
屏幕截图 2025-10-25 181008
将行为树的Move To函数中的BlackboardKey设置为刚刚设置的AttackTarget:
屏幕截图 2025-10-25 181105

使用 AIController 运行 Behavior Tree 并给 Blackboard 中的变量赋值

创建AIContorller C++类:
屏幕截图 2025-10-25 182057
需要包含AIModule模块:
屏幕截图 2025-10-25 182516
创建AIController蓝图类:
屏幕截图 2025-10-25 182622
屏幕截图 2025-10-25 182654
为Enemy中的AI Controller Class赋值:
屏幕截图 2025-10-25 182715
将行为树和黑板键AttackTargetKeyName传入:
屏幕截图 2025-10-25 194410
运行 Behavior Tree 并给 Blackboard 中的变量赋值
屏幕截图 2025-10-25 194424
添加Nav Mesh Bounds Volume
屏幕截图 2025-10-25 193105
按P键显示:
屏幕截图 2025-10-25 193231

Custom Task

创建Task类C++类:
注意:Task类是UBTTaskNode而不是UBTTask_BlueprintBase蓝图类型
{E4B8FA8A-64A7-4F4D-A4DE-5EBF7A592323}
在行为树中添加自定义Task:
屏幕截图 2025-10-25 200409
屏幕截图 2025-10-25 200457
Task中的继承函数:
屏幕截图 2025-10-25 210304
在BaseEnemy中创建Attack函数并创建AttackEnd委托:
屏幕截图 2025-10-25 214949
方法一:在AttackMontage动画播放完成后调用委托:
屏幕截图 2025-10-25 214954

屏幕截图 2025-10-25 215003
在执行Task函数中绑定委托并调用Attack函数,然后返回InProgress
当Attack函数调用委托时,就会调用HandleAttackEnd函数来手动结束任务
如果是异步执行,必须要有AbortTask和OnTaskFinished函数来兜底,同步执行(ExecuteTask 立即返回 Succeeded/Failed)可以不加
屏幕截图 2025-10-25 215024

Custom AnimNotify

方法二:使用AnimNotify来结束Montage动画:
创建UAnimNotify C++类:
屏幕截图 2025-10-25 215832
屏幕截图 2025-10-25 220325
调用委托:
屏幕截图 2025-10-25 220331
在Montage动画中添加AnimNotify:
屏幕截图 2025-10-25 220342
屏幕截图 2025-10-25 220409

Focus Target Task

用于在攻击时Focus Target:
创建Task:
屏幕截图 2025-10-26 105454
创建黑板键,用于在行为树中赋值:
屏幕截图 2025-10-26 111928
获取黑板,黑板通过KeyName来读取TargetActor,通过AIController设置Focus为目标角色:
屏幕截图 2025-10-26 111936
在行为树中添加Task并给Attack Target key赋值:
屏幕截图 2025-10-26 111957
使用Use Contorller Desired Rotation,取消Orient Rotation to Movement:
屏幕截图 2025-10-26 112033

Clear Focus Task

用于在行走时清除Focus:
屏幕截图 2025-10-26 113024
屏幕截图 2025-10-26 113306
屏幕截图 2025-10-26 113318
屏幕截图 2025-10-26 113459

Spawn Weapon Task

创建Weapon类:
屏幕截图 2025-10-26 135432
屏幕截图 2025-10-26 143233
屏幕截图 2025-10-26 143238
在Enemy中创建Spawn Weapon的函数:
屏幕截图 2025-10-26 143258
屏幕截图 2025-10-26 143348
创建Task:
屏幕截图 2025-10-26 135051
屏幕截图 2025-10-26 143408
屏幕截图 2025-10-26 143418
屏幕截图 2025-10-26 143530

Decorator(修饰器)

创建修饰器,用于判断Enemy是否装备了武器:
屏幕截图 2025-10-26 221715
屏幕截图 2025-10-26 221828
添加修饰器并反转:
屏幕截图 2025-10-26 224302
在Enemy中添加bool变量用于判断:
屏幕截图 2025-10-26 223642
当Spawn武器后,bWeaponEquipped设置为true:
屏幕截图 2025-10-26 223334
修饰器:
屏幕截图 2025-10-26 223701
屏幕截图 2025-10-26 223706

按路线巡逻

创建Actor类型用作Patrol Route:
屏幕截图 2025-10-26 225637
添加更新PatroulRoute的函数和获取当前PointLocation的函数:
屏幕截图 2025-10-26 230912
屏幕截图 2025-10-26 230919
创建蓝图类:
屏幕截图 2025-10-26 235806
屏幕截图 2025-10-26 235834
将蓝图拖到Map中:
屏幕截图 2025-10-27 000000
创建Interface:
屏幕截图 2025-10-26 233037
创建一个获取PatrolRoute的纯虚函数:
屏幕截图 2025-10-27 000835
在Enemy中实现这个纯虚函数:
屏幕截图 2025-10-27 000935
屏幕截图 2025-10-27 001000
创建按路线巡逻Task:
屏幕截图 2025-10-26 232340
屏幕截图 2025-10-27 001232
通过Actor来获取Interface,从而获取到对应的PatrolRoute,通过PatrolRoute获取到对应的点位置,MoveTo到点位置,MoveTo完成后调用OnMoveCompleted函数,在回调函数中更新PatrolRoute,若被打断,则停止Move:
屏幕截图 2025-10-27 001249
其中AbortTask中必须加上RemoveDynamic,否则中断时会静止不动:
{73DAC6E1-E396-456F-BFC8-E00BEF6F4218}
设置Enemy的Patrol Route:
屏幕截图 2025-10-27 000035
设置行为树:
屏幕截图 2025-10-27 001722

设置移动速度

创建Interface用于设置速度:
屏幕截图 2025-10-27 122335
创建速度类型的Enum:
屏幕截图 2025-10-27 120134
在Enemy中重写纯虚函数:
屏幕截图 2025-10-27 120159
屏幕截图 2025-10-27 120241
创建Task:
屏幕截图 2025-10-27 122958
在行为树中赋值SpeedType:
屏幕截图 2025-10-27 135547
使用接口调用SetMovementSpeed:
屏幕截图 2025-10-27 135552
在行为树中使用:
屏幕截图 2025-10-27 135318

随机巡逻

添加修饰器,判断是否有路线:
屏幕截图 2025-10-27 140323
屏幕截图 2025-10-27 141723
屏幕截图 2025-10-27 141712
如果没有路线则进行随机巡逻:
在Build中添加NavigatonSystem模块:
屏幕截图 2025-10-27 155226
在Enemy中添加获取随机巡逻点的函数并设置巡逻范围,以及MoveTo可接受范围:
屏幕截图 2025-10-27 164355
使用NavigationSystemV1来获取可导航区域的随机点:
屏幕截图 2025-10-27 164913
创建随机巡逻的Task:
屏幕截图 2025-10-27 150937
屏幕截图 2025-10-27 164921
在Task中MoveToLocation,如果当前的RandomLocation已经处于AcceptRadius范围内,则直接返回成功,否则会导致Enemy不返回任何值从而卡住:
屏幕截图 2025-10-27 165219
其中AbortTask中必须加上RemoveDynamic,否则中断时会静止不动:
{73DAC6E1-E396-456F-BFC8-E00BEF6F4218}
在行为树中添加:
屏幕截图 2025-10-27 165347

创建State

屏幕截图 2025-10-27 185543
在黑板中添加Enum:
屏幕截图 2025-10-27 185557
设置EnumeName与cpp中的Enum名称一样:
屏幕截图 2025-10-27 185652
在Selector中添加BlackBoard的Decorator:
屏幕截图 2025-10-27 190132
如果BlackBoard中的State==Attacking,则进入:
屏幕截图 2025-10-27 190249
如果BlackBoard中的State==Passive,则进入:
屏幕截图 2025-10-27 190337
添加ClearFocus:
屏幕截图 2025-10-27 200818
添加AIStateKeyName并添加设置EnemyState的函数:
屏幕截图 2025-10-27 201127
初始化设置为Passive:
屏幕截图 2025-10-27 201159

添加拔剑和收剑

在Enemy中:
创建动画结束事件的委托
创建PlayMontage函数
设置Sword绑定位置的DrawSword函数:(SheatheSword同理)

屏幕截图 2025-10-28 162815
屏幕截图 2025-10-28 163050
创建DrawSword的Task:
屏幕截图 2025-10-27 215134
在Task中调用Enemy来播放蒙太奇动画并绑定DrawSwordEnd委托:
屏幕截图 2025-10-28 163258
创建DrawSword的AnimNotify:
屏幕截图 2025-10-27 234718
调用Enemy的DrawSword用于切换Sword的绑定位置:
屏幕截图 2025-10-28 163146
创建DrawSwordEnd的AnimNotify:
屏幕截图 2025-10-27 220812
在DrawSwordEnd结束事件中调用在DrawSword Task中实现的委托OnDrawSwordEnd:
屏幕截图 2025-10-28 163207
创建IsSwordDrawed的修饰器:
屏幕截图 2025-10-27 224924
返回bSwordDrawed:
屏幕截图 2025-10-28 163158
在Montage中添加DrawSword和DrawSwordEnd的AnimNotify:
屏幕截图 2025-10-28 164348
取消Enable Root Motion,否则无法Focus Target:
屏幕截图 2025-10-28 164416
在行为树中添加DrawSword和SheatheSword:
屏幕截图 2025-10-28 164827

添加AI Perception Component(AI感知系统)和Team(队伍系统)

创建TeamType的枚举类型,并添加转换的辅助函数:
屏幕截图 2025-10-28 205851
创建TeamComponent,用于在Character中设置Team:
屏幕截图 2025-10-28 192420
继承IGenericTeamAgentInterface,并重写GetGenericTeamId函数,初始化TeamId为Player:
屏幕截图 2025-10-28 210249
返回TeanId:
屏幕截图 2025-10-28 210254
创建蓝图类:
屏幕截图 2025-10-28 210348
在Character中添加TeamComponent:
屏幕截图 2025-10-28 210329
在AIController中添加AIPerception并重写Team类:
屏幕截图 2025-10-28 205929
重写Team函数:
屏幕截图 2025-10-28 210241
配置AIPerception:
屏幕截图 2025-10-28 212054
在Character中临时加入测试:
屏幕截图 2025-10-28 212208
按下”键并按下小键盘4键:测试AIPerception
屏幕截图 2025-10-28 175840

配置AIPerception

创建感知处理函数
创建AIPerception自带的感知回调函数
创建兴趣点,用于Enemy调查兴趣点
创建最大检测距离和最大移动距离,用于Enemy受到Damage时,不会一直走到兴趣点,而是朝向兴趣点移动:

屏幕截图 2025-10-29 220452
绑定函数:
屏幕截图 2025-10-29 220518
通过SenseID来调用不同的感知回调函数:
屏幕截图 2025-10-29 224336
在感知状态中设置对应的EnemyState:
屏幕截图 2025-10-29 224344
屏幕截图 2025-10-29 224357
Investigate中设置兴趣点:
屏幕截图 2025-10-29 224413
创建设置EnemyState的Task:
屏幕截图 2025-10-28 224122
屏幕截图 2025-10-29 224454
屏幕截图 2025-10-29 224458
要想使用OnTargetPerceptionForgotten,必须在AIPerception中设置Age(最大记得的事件)不能为0,并且勾选Forget Stale Actors:
屏幕截图 2025-10-29 115356
在黑板中创建PointOfInterest:
屏幕截图 2025-10-28 222220
创建Investigate的行为树:
{FCD76D5E-46A2-4DE1-87E8-354D5597F526}

EQS

创建EQS:
屏幕截图 2025-10-30 132916
屏幕截图 2025-10-30 171326
在蓝图中创建用于测试EQS的Pawn:
屏幕截图 2025-10-30 171526
屏幕截图 2025-10-30 171538
将Pawn拖入世界中:
屏幕截图 2025-10-30 171631
创建Context类用于将攻击目标设置为查询系统的上下文数据:
屏幕截图 2025-10-30 180535
从EnemyAIController中存储AttackTarget:
屏幕截图 2025-10-31 084857
屏幕截图 2025-10-31 084904
屏幕截图 2025-10-31 085045
在EQS中设置Circle Center为AttackTarget,这样就会围绕角色生成一圈的球:
通过PathExist确保球体是Enemy可以到达的:
通过DIstance确保Enemy只会在左右最近的两个球体中选择:

屏幕截图 2025-10-31 084522
屏幕截图 2025-10-31 083840
创建一个新的Context用于Test:
屏幕截图 2025-10-31 084756
获取Player Start作为中心点用于测试:
屏幕截图 2025-10-31 084803
屏幕截图 2025-10-31 084730
在行为树中添加Strafe并为Attack添加Cooldown:
屏幕截图 2025-10-31 084100

完善Strafe的EQS

创建Decorator判断是否处于目标范围内:
屏幕截图 2025-10-31 144250
在Interface中创建获取AttackRadius和DefendRadius的函数:
屏幕截图 2025-10-31 211239
在Enemy中初始化:
屏幕截图 2025-10-31 211257
在Enemy中实现Interface:
屏幕截图 2025-10-31 211344
判断Enemy与AttackTarget的距离是否小于目标值:
屏幕截图 2025-10-31 211402
屏幕截图 2025-10-31 211433
创建MoveToTargetRange的Task,将Acceptance Radius作为黑板参数传递:
屏幕截图 2025-10-31 161140
屏幕截图 2025-10-31 211446
屏幕截图 2025-10-31 211458
在黑板中创建两个Radius:
屏幕截图 2025-10-31 102949
在Strafe中加上判断是否处于防御范围内,若不处于,则MoveToTargetRange到防御范围:
屏幕截图 2025-10-31 211102

添加FindCover的EQS

创建EQS:
屏幕截图 2025-10-31 213251
添加Trace,确保在Target看不见的地方,并设置Item Height:
屏幕截图 2025-11-01 202949
在行为树中添加FindCover:
屏幕截图 2025-10-31 215917

添加子类Enemy并添加SubBehaviorTree

创建BaseEnemy的子类,用于设置近战Enemy和远程Enemy:
屏幕截图 2025-11-01 112001
屏幕截图 2025-11-01 191757
创建两个树用于作为子树:
{0A50DFAF-FB23-40D5-9344-153FF25B870A}
将树中的Investigate逻辑复制到子树中:
{2671848C-45C6-44FE-8222-F6FFAE9D68C1}
创建一个新的Rotate To face PointOfInterest,确保直接转向目标:
屏幕截图 2025-11-04 123151
将树中的Patrol逻辑复制到子树中:
{587AEBBF-BF69-4930-BE6B-8C59AB6B7344}
在树中使用Run Behavior来替代原有逻辑:
屏幕截图 2025-11-01 192051
为近战Enemy和远程Enemy分别创建行为树:
{F52173B8-4832-4BC8-9CD3-DB1D562F4DEF}
将BaseEnemy中的大部分逻辑删除:
{386C8F8B-0634-4AF1-A086-DD718997F61F}
近战Enemy:
{D6AF8257-01FD-4679-B4FC-19D116B73ED8}
在不同的Enemy中设置对应的BehaviorTree,然后再传递为AIController:
屏幕截图 2025-11-01 192604

设置远程敌人的BehaviorTree

创建开火的Notify
屏幕截图 2025-11-01 213317
{FC4632A1-9982-447B-8609-3053625AB259}
通过射线检测来ApplyDamage并ReportDamageEvent给AIPerception:
{16D9A6D6-EE41-4367-A391-AC4E6B717396}
在Notify中调用Fire:
{5AC1E02A-512D-4833-8A07-5699A7274EE6}
创建Decorator判断Enemy是否能看见Target:
屏幕截图 2025-11-02 001653
{45A23161-069F-4BF2-A838-3AF940E5663A}
创建Health和Damage:
屏幕截图 2025-11-02 210820
屏幕截图 2025-11-02 210809
创建恢复Health的Task:
屏幕截图 2025-11-02 133948
{8FBBB1FC-EB5B-4290-B714-728EC07FC696}
创建判断是否Health低于阈值的函数:
屏幕截图 2025-11-02 131950
{FFAF66C0-6D36-4D01-A3EB-4455A685C42C}
如果在Attack中,Health低于阈值,则执行FindCover的EQS移动到Cover并HealHealth:
如果Enemy看不见Target,则MoveToSeeTarget:
屏幕截图 2025-11-02 211341

添加Sword

在Weapon中添加Box和Start,End:
屏幕截图 2025-11-03 202932
创建Box的OnOverlap函数,当Overlap时,通过Start和End的位置来BoxTrace判断是否碰到Block Visibility Channel的物体:
屏幕截图 2025-11-03 202957
设置Weapon的Owner:
屏幕截图 2025-11-03 203039
设置Enemy的Mesh为WorldDynamic,从而与Capsule进行区分,并将Visibility设置为Block,从而可以进行BoxTrace:
屏幕截图 2025-11-03 204723
在Enemy中创建EnableCollision和DisableCollision并清空IgnoreActors防止重复检测:
屏幕截图 2025-11-03 203048
创建AnimNotifyState:
屏幕截图 2025-11-03 184802
开始时启用Collision,结束时关闭:
屏幕截图 2025-11-03 203054
在CanSeeTarget中也需要Ignore目标,不然会被Target的Visibility通道阻挡并返回,从而导致一直CanNotSeeTarget:
屏幕截图 2025-11-03 203105
在AttackMontage中添加AnimNotifyState:
屏幕截图 2025-11-03 204533
在剑中添加Box和Start,End:
屏幕截图 2025-11-03 204602

添加Dead和HitReaction动画

添加Service,用于当Enemy的Attack目标死亡时,将Enemy的State重新设置为Passive:
屏幕截图 2025-11-03 220134
屏幕截图 2025-11-04 223423
屏幕截图 2025-11-04 223454
在Attack上添加Service:
屏幕截图 2025-11-04 223408
在Enemy的TakeDamage中添加GetHit和Die的函数:
屏幕截图 2025-11-04 223605
GetHit通过角度来判断受击方向,HitReactMontage设置为可以与其他动画一起播放,如果在Attack,则不播放GetHitMontage:
屏幕截图 2025-11-04 224036
Die不使用动画,使用模拟物理来达到布娃娃效果:
屏幕截图 2025-11-04 224144
在Attack中设置是否被打断,打断则调用OnAttackEnd:
屏幕截图 2025-11-04 224239
创建各个方向的GetHitAnimation,并创建一个新的Slot专门用于播放GetHitMontage:
屏幕截图 2025-11-04 223312
在Anim中使用LayeredBlendPerBone来融合播放GetHitMontage:
屏幕截图 2025-11-04 223144

posted @ 2025-10-22 08:45  pone1  阅读(3)  评论(0)    收藏  举报