# UE4 自定义 NavLink 实现指南
## 概述
本文档详细介绍了如何在 UE4 中实现自定义的 NavLink 系统,包括自定义 NavLink 组件、路径跟随组件和 NavLinkProxy 的完整实现方案。该系统主要用于 Test 功能,支持 AI 在导航过程中与游戏对象(如门)进行交互。
## 系统架构
自定义 NavLink 系统由三个核心组件构成:
1. **UNavLinkTestCustomComponent** - 自定义 NavLink 组件
2. **UTestPathFollowingComponent** - 自定义路径跟随组件
3. **ATestNavLinkProxy** - NavLink 代理 Actor
### 架构图
```
┌─────────────────────────────────────┐
│ ATestMonsterAIController │
│ (AI 控制器) │
│ - 使用自定义 PathFollowingComponent │
└──────────────┬──────────────────────┘
│
│ 使用
▼
┌─────────────────────────────────────┐
│ UTestPathFollowingComponent │
│ (路径跟随组件) │
│ - NavLink 前停顿 │
│ - 触发 NavLink 事件 │
└──────────────┬──────────────────────┘
│
│ 交互
▼
┌─────────────────────────────────────┐
│ ATestNavLinkProxy │
│ (NavLink 代理) │
│ - 包含自定义 NavLink 组件 │
└──────────────┬──────────────────────┘
│
│ 包含
▼
┌─────────────────────────────────────┐
│ UNavLinkTestCustomComponent │
│ (自定义 NavLink 组件) │
│ - 控制通行权限 │
│ - 触发门开关 │
└─────────────────────────────────────┘
```
## 组件详解
### 1. UNavLinkTestCustomComponent
自定义 NavLink 组件继承自 `UNavLinkCustomComponent`,提供了扩展的导航链接功能。
#### 主要特性
- **通行权限控制**:支持分别控制怪物和玩家的通行权限
- **GM 指令支持**:通过控制台变量动态控制 NavLink 的启用状态
- **GPO Actor 关联**:可以关联游戏对象(如门),在 AI 通过时触发交互
- **蓝图扩展**:支持通过蓝图实现自定义的寻路权限判断
#### 头文件定义
```cpp
UCLASS(ClassGroup = (Navigation), meta = (BlueprintSpawnableComponent))
class UNavLinkTestCustomComponent : public UNavLinkCustomComponent, public IUnLuaInterface
{
GENERATED_BODY()
public:
UNavLinkTestCustomComponent(const FObjectInitializer& ObjectInitializer);
// 蓝图可实现的寻路权限判断
UFUNCTION(BlueprintImplementableEvent, Category = "Test|NavLink")
bool IsLinkPathfindingAllowedBP(const UObject* Querier) const;
protected:
// 重写父类虚函数
virtual bool IsLinkPathfindingAllowed(const UObject* Querier) const override;
virtual bool OnLinkMoveStarted(UObject* PathComp, const FVector& DestPoint) override;
virtual void OnLinkMoveFinished(UObject* PathComp) override;
public:
// 通行权限控制
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Test|NavLink")
bool bAllowMonsterPass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Test|NavLink")
bool bAllowPlayerPass;
// GPO Actor 管理
UFUNCTION(BlueprintCallable, Category = "Test|NavLink")
void SetRelativeGPOActor(AActor* InGPOActor);
UFUNCTION(BlueprintCallable, Category = "Test|NavLink")
ATestInteractiveActorBase* GetRelativeGPOActor() const;
protected:
TWeakObjectPtr<ATestInteractiveActorBase> RelativeGPOActor;
};
```
#### 核心实现
##### 1. 寻路权限判断
```cpp
bool UNavLinkTestCustomComponent::IsLinkPathfindingAllowed(const UObject* Querier) const
{
// 检查是否是怪物 AI 控制器
const ATestMonsterAIController* AIController = Cast<ATestMonsterAIController>(Querier);
if (AIController)
{
// 首先检查 GM 指令(控制台变量)
const int32 bGMAllowMonster = CVarTestNavLinkAllowMonster.GetValueOnGameThread();
if (bGMAllowMonster == 0)
{
return false;
}
// 然后检查组件自身的属性
return bAllowMonsterPass;
}
// 检查玩家权限
const int32 bGMAllowPlayer = CVarTestNavLinkAllowPlayer.GetValueOnGameThread();
if (bGMAllowPlayer == 0)
{
return false;
}
return bAllowPlayerPass && Super::IsLinkPathfindingAllowed(Querier);
}
```
##### 2. NavLink 移动事件处理
```cpp
bool UNavLinkTestCustomComponent::OnLinkMoveStarted(UObject* PathComp, const FVector& DestPoint)
{
// 当 AI 开始使用 NavLink 时,打开关联的门
if (RelativeGPOActor.IsValid())
{
auto PathFollowCmp = Cast<UTestPathFollowingComponent>(PathComp);
if (PathFollowCmp)
{
RelativeGPOActor->OpenByAI(PathFollowCmp->GetOwner());
}
}
return Super::OnLinkMoveStarted(PathComp, DestPoint);
}
void UNavLinkTestCustomComponent::OnLinkMoveFinished(UObject* PathComp)
{
// 当 AI 完成 NavLink 移动时,关闭关联的门
if (RelativeGPOActor.IsValid())
{
auto PathFollowCmp = Cast<UTestPathFollowingComponent>(PathComp);
if (PathFollowCmp)
{
RelativeGPOActor->CloseByAI(PathFollowCmp->GetOwner());
}
}
Super::OnLinkMoveFinished(PathComp);
}
```
#### GM 指令
系统提供了两个控制台变量用于调试:
```
// 控制怪物能否使用 NavLink
Test.NavLink.AllowMonster 0/1
// 控制玩家能否使用 NavLink
Test.NavLink.AllowPlayer 0/1
```
### 2. UTestPathFollowingComponent
自定义路径跟随组件继承自 `UPathFollowingComponent`,主要功能是在 AI 使用 NavLink 前添加停顿时间。
#### 主要特性
- **NavLink 前停顿**:在使用 NavLink 前停顿指定时间(例如等待门打开)
- **定时器管理**:使用定时器控制停顿时间
- **状态缓存**:缓存 NavLink 信息,停顿结束后继续移动
#### 头文件定义
```cpp
UCLASS()
class FEATURE_Test_API UTestPathFollowingComponent : public UPathFollowingComponent
{
GENERATED_BODY()
public:
UTestPathFollowingComponent(const FObjectInitializer& ObjectInitializer);
/** 设置 NavLink 停顿时间 */
void SetNavLinkPauseTime(float InPauseTime);
protected:
/** NavLink 停顿时间(秒) */
float NavLinkPauseTime;
/** 是否正在等待 NavLink 停顿 */
bool bWaitingForNavLinkPause;
/** NavLink 停顿计时器句柄 */
FTimerHandle NavLinkPauseTimerHandle;
/** 缓存的 NavLink 目标点 */
FVector CachedNavLinkDestPoint;
/** 缓存的 NavLink 接口 */
TWeakInterfacePtr<INavLinkCustomInterface> CachedCustomNavLink;
/** 重写 StartUsingCustomLink,在使用 NavLink 前停顿 */
virtual void StartUsingCustomLink(INavLinkCustomInterface* CustomNavLink, const FVector& DestPoint) override;
/** NavLink 停顿结束后继续移动 */
void OnNavLinkPauseFinished();
/** 重写 UpdatePathSegment,处理 NavLink 停顿 */
virtual void UpdatePathSegment() override;
virtual void FollowPathSegment(float DeltaTime) override;
/** 清理定时器 */
virtual void Reset() override;
};
```
#### 核心实现
##### 1. 开始使用 NavLink
```cpp
void UTestPathFollowingComponent::StartUsingCustomLink(INavLinkCustomInterface* CustomNavLink, const FVector& DestPoint)
{
// 如果设置了停顿时间,则先停顿
if (NavLinkPauseTime > 0.0f && !bWaitingForNavLinkPause)
{
UE_VLOG(GetOwner(), LogPathFollowing, Log,
TEXT("PVE PathFollowing: Pausing %.2f seconds before using NavLink"),
NavLinkPauseTime);
// 缓存 NavLink 信息
CachedCustomNavLink = CustomNavLink;
CachedNavLinkDestPoint = DestPoint;
bWaitingForNavLinkPause = true;
// 触发 NavLink 开始事件
CustomNavLink->OnLinkMoveStarted(this, DestPoint);
// 暂停移动
if (MovementComp)
{
MovementComp->StopMovementKeepPathing();
}
// 设置定时器,停顿结束后继续
if (AAIController* AIOwner = Cast<AAIController>(GetOwner()))
{
AIOwner->GetWorldTimerManager().SetTimer(
NavLinkPauseTimerHandle,
this,
&UTestPathFollowingComponent::OnNavLinkPauseFinished,
NavLinkPauseTime,
false
);
}
}
else
{
// 没有设置停顿时间,直接调用父类方法
Super::StartUsingCustomLink(CustomNavLink, DestPoint);
}
}
```
##### 2. 停顿结束处理
```cpp
void UTestPathFollowingComponent::OnNavLinkPauseFinished()
{
UE_VLOG(GetOwner(), LogPathFollowing, Log,
TEXT("PVE PathFollowing: NavLink pause finished, continuing move"));
bWaitingForNavLinkPause = false;
NavLinkPauseTimerHandle.Invalidate();
// 继续使用 NavLink
if (CachedCustomNavLink.IsValid())
{
INavLinkCustomInterface* CustomNavLink = CachedCustomNavLink.GetInterface();
Super::StartUsingCustomLink(CustomNavLink, CachedNavLinkDestPoint);
// 清理缓存
CachedCustomNavLink = TWeakInterfacePtr<INavLinkCustomInterface>();
CachedNavLinkDestPoint = FVector::ZeroVector;
}
}
```
##### 3. 路径更新控制
```cpp
void UTestPathFollowingComponent::UpdatePathSegment()
{
// 如果正在等待 NavLink 停顿,不更新路径段
if (bWaitingForNavLinkPause)
{
return;
}
Super::UpdatePathSegment();
}
void UTestPathFollowingComponent::FollowPathSegment(float DeltaTime)
{
// 如果正在等待 NavLink 停顿,不更新路径段
if (bWaitingForNavLinkPause)
{
return;
}
Super::FollowPathSegment(DeltaTime);
}
```
##### 4. 资源清理
```cpp
void UTestPathFollowingComponent::Reset()
{
// 清理定时器
if (NavLinkPauseTimerHandle.IsValid())
{
if (AAIController* AIOwner = Cast<AAIController>(GetOwner()))
{
AIOwner->GetWorldTimerManager().ClearTimer(NavLinkPauseTimerHandle);
}
NavLinkPauseTimerHandle.Invalidate();
}
bWaitingForNavLinkPause = false;
CachedCustomNavLink = TWeakInterfacePtr<INavLinkCustomInterface>();
CachedNavLinkDestPoint = FVector::ZeroVector;
Super::Reset();
}
```
### 3. ATestNavLinkProxy
NavLink 代理 Actor 继承自 `ANavLinkProxy`,用于在关卡中放置和配置 NavLink。
#### 主要特性
- **自定义组件替换**:通过 `ObjectInitializer` 替换默认的 `UNavLinkCustomComponent`
- **动态配置**:支持运行时设置 NavLink 的起点、终点和方向
- **GPO Actor 关联**:支持关联游戏对象并根据距离选择最近的对象
#### 头文件定义
```cpp
UCLASS(Blueprintable, autoCollapseCategories = (SmartLink, Actor), hideCategories = (Input))
class ATestNavLinkProxy : public ANavLinkProxy, public IUnLuaInterface
{
GENERATED_BODY()
public:
ATestNavLinkProxy(const FObjectInitializer& ObjectInitializer);
// 设置 NavLink 数据
UFUNCTION(BlueprintCallable, Category = "Test")
void SetupSmartLinkData(const FVector& Start, const FVector& End, ENavLinkDirection::Type Direction);
// 获取起点和终点
UFUNCTION(BlueprintCallable, Category = "Test")
FVector GetStartPoint();
UFUNCTION(BlueprintCallable, Category = "Test")
FVector GetEndPoint();
// GPO Actor 管理
UFUNCTION(BlueprintCallable, Category = "Test")
void SetRelativeGPOActor(AActor* InGPOActor, bool Force = false);
UFUNCTION(BlueprintCallable, Category = "Test")
AActor* GetRelativeGPOActor() const;
// 通行权限控制
UFUNCTION(BlueprintCallable, Category = "Test")
bool IsAllowMonsterPass() const;
UFUNCTION(BlueprintCallable, Category = "Test")
void SetAllowMonsterPass(bool bInAllowMonsterPass);
};
```
#### 核心实现
##### 1. 构造函数 - 替换默认组件
```cpp
ATestNavLinkProxy::ATestNavLinkProxy(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UNavLinkTestCustomComponent>(TEXT("SmartLinkComp")))
{
// 构造函数中通过 ObjectInitializer 替换默认的 SmartLinkComp 为自定义组件
// 这样 GetSmartLinkComp() 返回的就是 UNavLinkTestCustomComponent 实例
UNavLinkCustomComponent* SmartLinkComponent = GetSmartLinkComp();
if (!SmartLinkComponent)
{
return;
}
uint32 UserId = SmartLinkComponent->GetLinkId();
if (PointLinks.Num() > 0)
{
PointLinks[0].UserId = SmartLinkComponent->GetLinkId();
}
}
```
##### 2. 设置 NavLink 数据
```cpp
void ATestNavLinkProxy::SetupSmartLinkData(const FVector& Start, const FVector& End, ENavLinkDirection::Type Direction)
{
UNavLinkCustomComponent* SmartLinkComponent = GetSmartLinkComp();
if (!SmartLinkComponent)
{
return;
}
uint32 UserId = SmartLinkComponent->GetLinkId();
if (UserId == 0)
{
UE_LOG(LogTemp, Error, TEXT("TestNavLinkProxy's UserId is 0!!!"));
}
// 设置 PointLinks 数据
if (PointLinks.Num() > 0)
{
PointLinks[0].Left = Start;
PointLinks[0].Right = End;
PointLinks[0].Direction = Direction;
PointLinks[0].UserId = SmartLinkComponent->GetLinkId();
}
// 设置组件数据
if (SmartLinkComponent)
{
SmartLinkComponent->SetLinkData(Start, End, Direction);
SmartLinkComponent->SetNavigationRelevancy(true);
}
}
```
##### 3. GPO Actor 关联(智能距离选择)
```cpp
void ATestNavLinkProxy::SetRelativeGPOActor(AActor* InGPOActor, bool Force)
{
UNavLinkTestCustomComponent* SmartLinkComponent = Cast<UNavLinkTestCustomComponent>(GetSmartLinkComp());
if (SmartLinkComponent)
{
if (Force)
{
SmartLinkComponent->SetRelativeGPOActor(InGPOActor);
return;
}
// 如果已经设置了 GPOActor,比较距离,选择更近的
auto RelativeGPOActor = SmartLinkComponent->GetRelativeGPOActor();
if (RelativeGPOActor)
{
float Distance = (RelativeGPOActor->GetActorLocation() - this->GetActorLocation()).Size();
float NewDistance = (InGPOActor->GetActorLocation() - this->GetActorLocation()).Size();
if (NewDistance < Distance)
{
SmartLinkComponent->SetRelativeGPOActor(InGPOActor);
}
return;
}
SmartLinkComponent->SetRelativeGPOActor(InGPOActor);
}
}
```
### 4. AI 控制器集成
在 AI 控制器中使用自定义路径跟随组件:
```cpp
UCLASS()
class FEATURE_Test_API ATestMonsterAIController : public AMoeMonsterAIController
{
GENERATED_BODY()
public:
ATestMonsterAIController(const FObjectInitializer& ObjectInitializer);
};
// 实现文件
ATestMonsterAIController::ATestMonsterAIController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UTestPathFollowingComponent>(TEXT("PathFollowingComponent")))
{
// 通过 ObjectInitializer 替换默认的 PathFollowingComponent
}
```
## 使用流程
### 1. 在关卡中放置 NavLinkProxy
```cpp
// 在蓝图或 C++ 中创建 TestNavLinkProxy
ATestNavLinkProxy* NavLinkProxy = World->SpawnActor<ATestNavLinkProxy>(Location, Rotation);
// 设置 NavLink 的起点和终点
FVector StartPoint = FVector(0, 0, 0);
FVector EndPoint = FVector(0, 0, 100);
NavLinkProxy->SetupSmartLinkData(StartPoint, EndPoint, ENavLinkDirection::BothWays);
// 关联门对象
NavLinkProxy->SetRelativeGPOActor(DoorActor);
// 设置通行权限
NavLinkProxy->SetAllowMonsterPass(true);
```
### 2. 配置 AI 控制器
```cpp
// AI 控制器会自动使用 UTestPathFollowingComponent
ATestMonsterAIController* AIController = Cast<ATestMonsterAIController>(Monster->GetController());
// 可选:设置 NavLink 停顿时间
if (UTestPathFollowingComponent* PathFollowComp = Cast<UTestPathFollowingComponent>(AIController->GetPathFollowingComponent()))
{
PathFollowComp->SetNavLinkPauseTime(3.0f); // 停顿 3 秒
}
```
### 3. AI 寻路
```cpp
// 正常使用 AI 寻路
AIController->MoveToLocation(TargetLocation);
// 当 AI 遇到 NavLink 时:
// 1. PathFollowingComponent 检测到 NavLink
// 2. 调用 NavLinkComponent->IsLinkPathfindingAllowed() 检查权限
// 3. 如果允许,调用 StartUsingCustomLink()
// 4. NavLinkComponent->OnLinkMoveStarted() 被调用,触发门打开
// 5. PathFollowingComponent 停顿指定时间
// 6. 停顿结束后,AI 继续移动通过 NavLink
// 7. NavLinkComponent->OnLinkMoveFinished() 被调用,触发门关闭
```
## 工作流程图
```
┌─────────────────────┐
│ AI 开始寻路 │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ 检测到 NavLink │
└──────────┬──────────┘
│
▼
┌─────────────────────────────────┐
│ IsLinkPathfindingAllowed() │
│ - 检查 GM 指令 │
│ - 检查通行权限 │
└──────────┬──────────────────────┘
│
▼ (允许通过)
┌─────────────────────────────────┐
│ StartUsingCustomLink() │
│ - 缓存 NavLink 信息 │
│ - 触发 OnLinkMoveStarted() │
│ - 停止移动 │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────────────────┐
│ OnLinkMoveStarted() │
│ - 打开关联的门 │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────────────────┐
│ 等待停顿时间 │
│ (定时器) │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────────────────┐
│ OnNavLinkPauseFinished() │
│ - 继续使用 NavLink │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────────────────┐
│ AI 移动通过 NavLink │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────────────────┐
│ OnLinkMoveFinished() │
│ - 关闭关联的门 │
└──────────┬──────────────────────┘
│
▼
┌─────────────────────┐
│ 继续寻路 │
└─────────────────────┘
```
## 关键技术点
### 1. ObjectInitializer 替换默认组件
UE4 允许在构造函数中通过 `ObjectInitializer` 替换默认的子对象类:
```cpp
// 在 AI 控制器中替换 PathFollowingComponent
ATestMonsterAIController::ATestMonsterAIController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UTestPathFollowingComponent>(TEXT("PathFollowingComponent")))
{
}
// 在 NavLinkProxy 中替换 SmartLinkComp
ATestNavLinkProxy::ATestNavLinkProxy(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UNavLinkTestCustomComponent>(TEXT("SmartLinkComp")))
{
}
```
### 2. 弱指针避免循环引用
使用 `TWeakObjectPtr` 和 `TWeakInterfacePtr` 避免循环引用:
```cpp
// 存储 GPO Actor 的弱指针
TWeakObjectPtr<ATestInteractiveActorBase> RelativeGPOActor;
// 存储 NavLink 接口的弱指针
TWeakInterfacePtr<INavLinkCustomInterface> CachedCustomNavLink;
```
### 3. 定时器管理
使用 UE4 的定时器系统实现延迟执行:
```cpp
// 设置定时器
AIOwner->GetWorldTimerManager().SetTimer(
NavLinkPauseTimerHandle,
this,
&UTestPathFollowingComponent::OnNavLinkPauseFinished,
NavLinkPauseTime,
false
);
// 清理定时器
AIOwner->GetWorldTimerManager().ClearTimer(NavLinkPauseTimerHandle);
NavLinkPauseTimerHandle.Invalidate();
```
### 4. 控制台变量(CVar)
使用控制台变量实现运行时调试:
```cpp
static TAutoConsoleVariable<int32> CVarTestNavLinkAllowMonster(
TEXT("Test.NavLink.AllowMonster"),
1,
TEXT("控制怪物 AI 能否使用 NavLink 进行寻路\n")
TEXT("0: 禁止怪物使用 NavLink\n")
TEXT("1: 允许怪物使用 NavLink (默认)"),
ECVF_Cheat
);
// 使用
const int32 bGMAllowMonster = CVarTestNavLinkAllowMonster.GetValueOnGameThread();
```
## 调试技巧
### 1. 可视化日志
使用 UE4 的可视化日志系统:
```cpp
UE_VLOG(GetOwner(), LogPathFollowing, Log,
TEXT("PVE PathFollowing: Pausing %.2f seconds before using NavLink"),
NavLinkPauseTime);
```
### 2. 控制台命令
```
// 禁止怪物使用 NavLink
Test.NavLink.AllowMonster 0
// 允许怪物使用 NavLink
Test.NavLink.AllowMonster 1
// 显示导航网格
show Navigation
```
### 3. 断点调试
关键断点位置:
- `IsLinkPathfindingAllowed()` - 检查寻路权限
- `StartUsingCustomLink()` - NavLink 开始使用
- `OnLinkMoveStarted()` - NavLink 移动开始
- `OnNavLinkPauseFinished()` - 停顿结束
## 最佳实践
### 1. 内存管理
- 使用弱指针(`TWeakObjectPtr`)存储 Actor 引用,避免循环引用
- 在 `Reset()` 方法中清理所有定时器和缓存数据
- 使用 `IsValid()` 检查弱指针的有效性
### 2. 性能优化
- 避免在 `IsLinkPathfindingAllowed()` 中执行耗时操作
- 使用控制台变量进行全局控制,减少单个 NavLink 的检查开销
- 合理设置 NavLink 停顿时间,避免 AI 等待过久
### 3. 扩展性设计
- 通过继承 `UNavLinkCustomComponent` 实现特定功能
- 使用蓝图可实现事件(`BlueprintImplementableEvent`)提供扩展点
- 支持 Lua 脚本扩展(通过 `IUnLuaInterface`)
### 4. 错误处理
- 检查组件指针的有效性
- 验证 UserId 不为 0
- 使用日志记录关键错误信息
## 常见问题
### Q1: AI 不使用 NavLink
**可能原因:**
- `IsLinkPathfindingAllowed()` 返回 false
- GM 指令禁用了 NavLink
- NavLink 的 UserId 为 0
- NavLink 未正确注册到导航系统
**解决方案:**
- 检查控制台变量设置
- 验证 `bAllowMonsterPass` 属性
- 确保调用了 `SetNavigationRelevancy(true)`
### Q2: AI 在 NavLink 处卡住
**可能原因:**
- 定时器未正确触发
- `bWaitingForNavLinkPause` 状态未正确重置
- NavLink 的终点位置不可达
**解决方案:**
- 检查定时器是否正确设置和清理
- 在 `Reset()` 中确保状态重置
- 验证 NavLink 的起点和终点位置
### Q3: 门没有打开/关闭
**可能原因:**
- GPO Actor 未正确关联
- `OnLinkMoveStarted/Finished()` 未被调用
- GPO Actor 的 `OpenByAI/CloseByAI()` 方法未实现
**解决方案:**
- 使用 `SetRelativeGPOActor()` 正确关联门对象
- 添加日志验证事件调用
- 检查 GPO Actor 的实现
## 总结
本文档详细介绍了 UE4 自定义 NavLink 系统的完整实现方案,包括:
1. **三个核心组件**:NavLink 组件、路径跟随组件和 NavLinkProxy
2. **关键技术**:组件替换、弱指针、定时器、控制台变量
3. **完整流程**:从 AI 寻路到 NavLink 使用的完整工作流程
4. **最佳实践**:内存管理、性能优化、扩展性设计
通过这套系统,可以实现 AI 在导航过程中与游戏对象的智能交互,例如自动开门、等待障碍物移除等功能。系统设计灵活,易于扩展,适合在各种 PVE 场景中使用。
## 参考资料
- UE4 官方文档:Navigation System
- UE4 官方文档:AI Navigation
- UE4 源码:`NavLinkCustomComponent.h`
- UE4 源码:`PathFollowingComponent.h`