首页/新闻资讯/正文详情

UE5鼠标点击移动实现:屏幕坐标转世界坐标与AI导航

发布时间:2026/9/23 17:12:48 来源:云帆数科 栏目:资讯中心
UE5鼠标点击移动实现:屏幕坐标转世界坐标与AI导航
简介这是一份面向UE4/UE5开发者的鼠标点击寻路交互示例工程适合具备蓝图基础、希望快速实现点击地面移动角色的学习者参考。资源围绕射线碰撞检测、模型边缘高亮、鼠标样式自定义切换以及DoTween移动动画四个技术点展开并附有说明若未购买DoTween插件删除蓝图中对应移动方法即可正常运行。压缩包共572个文件以413个uasset蓝图与资源文件、14个umap关卡地图、41个ini配置及92个log日志为主另含uproject工程文件与少量bin、json等辅助数据整体约675.41MB工程结构完整可直接打开研究。目前已有4416人学习下载读者可从中掌握点击寻路的完整实现链路、高亮与光标切换的细节处理以及借助DoTween平滑移动的动画思路便于迁移到RPG、策略或塔防类项目中。1. 鼠标点地移动从玩家直觉到引擎里的一条射线在第三人称或俯视角项目里玩家最自然的操作就是「鼠标点哪角色走哪」。这个需求听起来像一行代码实际落地时会牵出三件事屏幕坐标怎么变成世界坐标、角色怎么绕过障碍走到目标点、以及移动过程中怎么和动画、输入系统对齐。很多新手第一次做直接拿鼠标位置当世界坐标用结果角色往天上飞或者原地抽搐本质是没理解屏幕空间和世界空间之间隔着相机投影。这套方案适合做 RTS、MOBA、俯视角 RPG、点击式冒险也适合 UE5 里做原型验证。UE4 和 UE5 在这条链路上差异不大主要区别在 UE5 默认启用了 Enhanced Input以及导航系统对 Large World Coordinates 的处理。核心链路是鼠标点击事件 → 屏幕坐标 → 去投影射线 → 与地面碰撞 → 得到世界坐标 → 交给 AI 导航移动。下面按这条链路拆开讲每一段都能直接抄进项目里跑。2. 屏幕坐标转世界坐标Deproject 与射线检测的取舍2.1 为什么不能直接用鼠标坐标当世界坐标鼠标事件给的是屏幕空间坐标原点在视口左上角单位是像素。世界坐标是三维空间里的厘米单位。两者之间差了一个相机投影矩阵和一次深度求解。把屏幕坐标直接赋给SetActorLocationZ 值会是 0 或者视口高度角色自然乱跑。常见做法有两种一种是用DeprojectScreenPositionToWorld把屏幕点转成世界空间的一条射线再和地面求交另一种是用GetHitResultUnderCursorByChannel直接让引擎帮你做射线检测。前者灵活能自己控制射线长度和碰撞通道后者省事适合快速原型。2.2 用 GetHitResultUnderCursorByChannel 拿到地面点这是最省代码的方式适合俯视角和第三人称。在 PlayerController 里绑定输入然后调用// AMyPlayerController.cpp void AMyPlayerController::MoveToCursor() { FHitResult HitResult; // 用 Visibility 通道检测地面需要设置成 Block Visibility bool bHit GetHitResultUnderCursorByChannel( UEngineTypes::ConvertToTraceType(ECC_Visibility), true, // bTraceComplex复杂碰撞更精确但更慢 HitResult); if (bHit MoveTargetActor) { // HitResult.Location 就是鼠标点到的世界坐标 MoveTargetActor-MoveToLocation(HitResult.Location, 50.f); } }ECC_Visibility是碰撞通道地面 StaticMesh 的碰撞预设要能挡住 Visibility否则射线穿过去打不到。bTraceComplex设为 true 时会用复杂碰撞体地形起伏大时更准但每帧调用会有开销点击事件里用一次无所谓。MoveToLocation的第二个参数是接受半径50 表示离目标点 50 厘米内就算到达避免角色在目标点附近抖动。2.3 用 DeprojectScreenPositionToWorld 自己控制射线需要控制射线长度、忽略某些物体、或者做多层检测时用这个void AMyPlayerController::MoveToCursorManual() { FVector WorldLocation, WorldDirection; // 把鼠标屏幕坐标转成世界空间射线 if (!DeprojectMousePositionToWorld(WorldLocation, WorldDirection)) return; const float TraceDistance 10000.f; // 射线长度单位厘米 FVector TraceEnd WorldLocation WorldDirection * TraceDistance; FHitResult Hit; FCollisionQueryParams Params; Params.AddIgnoredActor(GetPawn()); // 忽略角色自身 Params.bTraceComplex true; bool bHit GetWorld()-LineTraceSingleByChannel( Hit, WorldLocation, TraceEnd, ECC_Visibility, Params); if (bHit) { // 命中点就是目标位置 DrawDebugSphere(GetWorld(), Hit.Location, 20.f, 12, FColor::Green, false, 2.f); } }DeprojectMousePositionToWorld内部会处理视口缩放和相机投影比手动算矩阵可靠。TraceDistance给 10000 厘米100 米足够覆盖大多数场景太小会导致远处点不到。AddIgnoredActor把角色自己排除否则射线可能打在角色胶囊体上。DrawDebugSphere是调试用的确认命中点位置对不对正式发布时去掉。2.4 两种方式的对比与选择方式代码量可控性适用场景GetHitResultUnderCursorByChannel少低快速原型、俯视角DeprojectScreenPositionToWorld中高需要过滤、多层检测手动算投影矩阵多最高特殊相机、自定义投影提示如果地面是 Landscape 或者复杂地形bTraceComplex必须开否则射线会穿过凹陷处打到下面的碰撞体。3. 让角色真正走过去AI 导航与 MoveTo 的落地细节3.1 导航网格是前提没有 NavMesh 一切白搭拿到目标点只是第一步角色要绕开障碍走过去必须依赖导航系统。在场景里放一个NavMeshBoundsVolume缩放到覆盖可行走区域按 P 键能看到绿色导航网格。如果地面没变绿检查三件事Volume 是否覆盖、地面碰撞是否设为Blocking Volume或可导航、项目设置里 Navigation Mesh 的 Agent 半径是否合理。UE5 里导航系统默认开启但 Large World Coordinates 下如果场景坐标超过百万级别需要调整Navigation System的Cell Size和Agent Max Step Height。常见做法是保持场景原点附近建模避免坐标过大。3.2 用 AIController 的 MoveToLocation 驱动移动角色蓝图里如果用的是Character需要给它挂一个AIController或者在 PlayerController 里直接调用MoveToLocation。更规范的做法是走 AI 导航// 在 AIController 或 Character 里 void AMyCharacter::MoveToTarget(FVector TargetLocation) { if (AAIController* AICon CastAAIController(GetController())) { // 接受半径 50超时 5 秒绘制调试路径 EPathFollowingRequestResult::Type Result AICon-MoveToLocation(TargetLocation, 50.f, true, true, false, true); if (Result EPathFollowingRequestResult::Failed) { UE_LOG(LogTemp, Warning, TEXT(MoveToLocation failed, check NavMesh)); } } }MoveToLocation的参数依次是目标点、接受半径、是否使用路径优化、是否投影到导航网格、是否绘制调试、是否允许部分路径。第三个参数bProjectDestinationToNavigation设为 true 时如果目标点不在导航网格上会自动投影到最近的可行走点这个在点击地面边缘时很有用。3.3 移动过程中的动画与旋转对齐角色移动时朝向不对会显得很假。常见做法是在CharacterMovementComponent里开启Orient Rotation to Movement让角色自动转向移动方向// 在 Character 构造函数里 GetCharacterMovement()-bOrientRotationToMovement true; GetCharacterMovement()-RotationRate FRotator(0.f, 540.f, 0.f); // 每秒转 540 度 bUseControllerRotationYaw false; // 关闭控制器控制朝向RotationRate控制转身速度540 度每秒比较跟手太小会转得很慢太大像陀螺。bUseControllerRotationYaw必须关掉否则控制器朝向会覆盖移动朝向。动画蓝图里用Velocity的长度驱动 BlendSpace速度为零时切到 Idle这样移动和动画就对齐了。3.4 点击移动的输入绑定与 Enhanced InputUE5 默认用 Enhanced Input需要在IMC_Default里建一个IA_MoveTo映射触发方式选Triggered。然后在 PlayerController 里绑定void AMyPlayerController::SetupInputComponent() { Super::SetupInputComponent(); if (UEnhancedInputComponent* EIC CastUEnhancedInputComponent(InputComponent)) { EIC-BindAction(MoveToAction, ETriggerEvent::Triggered, this, AMyPlayerController::MoveToCursor); } }ETriggerEvent::Triggered在按键按下时触发一次适合点击移动。如果要做按住持续移动改成Started加定时器。UE4 里用InputComponent-BindAction(MoveTo, IE_Pressed, this, ...)即可逻辑一样。4. 实战排错点不到、走不过去、抖动这三类问题4.1 鼠标点地面没反应先查碰撞通道最常见的原因是地面没有阻挡Visibility通道。打开地面 StaticMesh 的碰撞设置确认Collision Presets是BlockAll或至少Block Visibility。如果是自定义通道GetHitResultUnderCursorByChannel里的通道要对应上。另一个原因是 PlayerController 的bShowMouseCursor没开或者bEnableClickEvents没开鼠标事件根本传不到。// 在 PlayerController 初始化里 bShowMouseCursor true; bEnableClickEvents true; bEnableMouseOverEvents true;bEnableClickEvents控制点击事件是否派发bEnableMouseOverEvents控制悬停事件。只做点击移动的话前两个就够。4.2 角色走到一半停住检查导航网格和接受半径如果角色走到障碍物旁边就停多半是导航网格没覆盖到目标点或者接受半径太小导致角色在目标点附近反复寻路。把MoveToLocation的接受半径从 50 调到 80 试试。另外检查NavMeshBoundsVolume是否覆盖了目标区域按 P 键看绿色网格有没有断。还有一种情况是目标点在导航网格边缘bProjectDestinationToNavigation设为 false 时直接失败。设为 true 会自动投影到最近可行走点但投影距离有限太远的目标点还是会失败。常见做法是在点击时先判断目标点是否在导航网格上不在就忽略这次点击。4.3 角色到达后原地抖动用接受半径和停止逻辑解决抖动的原因是角色在目标点附近反复修正位置。MoveToLocation的接受半径设大一点或者在OnMoveCompleted回调里把速度清零void AMyCharacter::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult Result) { if (Result.Code EPathFollowingResult::Success) { GetCharacterMovement()-StopMovementImmediately(); } }StopMovementImmediately会立刻停止移动组件避免惯性导致的微小位移。如果用的是MoveToLocation的返回值判断注意Success和Blocked的区别Blocked表示路径被挡住需要重新寻路。4.4 调试手段DrawDebug 和导航网格可视化排错时最有用的是把射线和路径画出来。DrawDebugLine画射线DrawDebugSphere画命中点DrawDebugPath画导航路径。按 P 键切换导航网格显示按键打开 AI 调试。这些手段能快速定位是射线没打中、还是导航没连通、还是移动组件没响应。注意调试绘制在 Shipping 包里会被编译掉正式发布前确认没有依赖调试绘制的逻辑。5. 进阶点击移动与多播委托、触摸输入的衔接5.1 用多播委托解耦点击事件和移动逻辑点击移动做大了以后点击事件可能还要触发 UI 高亮、技能指示器、音效。用多播委托把「点击到地面」这个事件广播出去比在 PlayerController 里堆逻辑干净// 在 PlayerController 里声明 DECLARE_MULTICAST_DELEGATE_OneParam(FOnGroundClicked, FVector /*Location*/); FOnGroundClicked OnGroundClicked; // 命中后广播 if (bHit) { OnGroundClicked.Broadcast(HitResult.Location); }其他系统比如 UI、音效、特效订阅这个委托即可不用改 PlayerController。UE5 里也可以用Dynamic Multicast Delegate配合蓝图让策划也能挂逻辑。5.2 触摸输入下的点击移动适配移动端或触屏设备上鼠标点击变成触摸。UE5 里用bEnableTouchEvents和bEnableTouchOverEvents触摸事件会走和鼠标类似的派发路径。双指触摸蓝图里常见做法是单指点击移动、双指缩放视角需要在 Input 里区分触摸点数。GetHitResultUnderFingerByChannel是触摸版的命中检测参数和鼠标版类似第一个参数传手指索引。5.3 性能与边界高频点击和大地图的处理高频点击时每次都做射线检测和寻路会有开销。常见做法是加一个最小点击间隔比如 0.1 秒内只响应一次。大地图上导航网格分块加载点击远处时先判断目标点是否在已加载的导航网格内不在就忽略或者提示。UE5 的 World Partition 下导航网格也是流式加载的跨区域点击需要等导航数据加载完再寻路否则会失败。// 简单的点击节流 float LastClickTime 0.f; if (GetWorld()-GetTimeSeconds() - LastClickTime 0.1f) return; LastClickTime GetWorld()-GetTimeSeconds();这段放在MoveToCursor开头能避免连点导致的寻路风暴。0.1 秒是经验值手感上几乎无感但能挡掉大量重复请求。本文还有配套的精品资源点击获取

相关推荐

NSL-KDD入侵检测实战:数据预处理、PCA降维与完整评估
NSL-KDD入侵检测实战:数据预处理、PCA降维与完整评估

简介:基于NSL-KDD网络入侵检测基准数据集的Python项目,面向计算机相关专业毕业设计、课程设计及期末大作业场景,适合需要完成入侵检测实战并提交高评分作品的学生。项目经导师指导并获得九十八分评审成绩,完整覆盖数据获取、特征处… · 2026/9/23 17:12:41

基于YOLOv8的实验室防护服穿戴检测:毕设复现完整指南
基于YOLOv8的实验室防护服穿戴检测:毕设复现完整指南

简介:基于YOLOv8的实验室防护服穿戴规范检测项目,集成源码、可视化界面、完整数据集与部署说明,面向计算机视觉、人工智能等专业的毕业生或课程设计学生,解决毕设缺少完整可运行方案的问题。包内共有8个文件,包含3个Py… · 2026/9/23 17:12:41

Formily 中 Input 组件的三种接入方式与源码解析:从 Schema 到 React 字段绑定的完整实践
Formily 中 Input 组件的三种接入方式与源码解析:从 Schema 到 React 字段绑定的完整实践

Formily 中 Input 组件的三种接入方式与源码解析:从 Schema 到 React 字段绑定的完整实践 【免费下载链接】formily 📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Suppor… · 2026/9/23 17:12:41

水塔水位控制器手写实现优化:从卡顿到丝滑的实战复盘
水塔水位控制器手写实现优化:从卡顿到丝滑的实战复盘

水塔水位控制器手写实现优化:从卡顿到丝滑的实战复盘 很多刚入行嵌入式或者物联网开发的朋友,手里攥着《C语言程序设计》或者《Python编程:从入门到实践》,语法背得滚瓜烂熟,一碰到实际项目就傻眼。特别是做水塔水位控制器这种硬件逻辑时,发现代… · 2026/9/23 17:53:40

RecRecNet深度学习畸变矫正实战:推理、训练与部署指南
RecRecNet深度学习畸变矫正实战:推理、训练与部署指南

简介:基于RecRecNet深度网络实现广角图像畸变矫正,所附Python源码适用于高校计算机相关专业学生与教师,可支撑毕业设计、课程设计及初学进阶。压缩包共26个文件,主要包含py源码、C辅助工具、Shell脚本、Markdown说明与示例图片&am… · 2026/9/23 17:53:40

3个技巧搞定顶上性能优化,高频面试题全解析
3个技巧搞定顶上性能优化,高频面试题全解析

3个技巧搞定顶上性能优化,高频面试题全解析 版本升级后 API 全变了,代码跑不通、性能还卡顿,这是无数开发者深夜崩溃的真实写照。更扎心的是,当你试图修复时,发现连基本的性能瓶颈都定位不准。别慌,今天不聊虚的,直接拆解“顶上”这个看似简单却… · 2026/9/23 17:53:40

ASP.NET Boilerplate 迁移到 MySQL:EF6 与 ASP.NET MVC 5.x 完整集成指南
ASP.NET Boilerplate 迁移到 MySQL:EF6 与 ASP.NET MVC 5.x 完整集成指南

后端Web框架依赖注入认证鉴权 【免费下载链接】aspnetboilerplate ASP.NET Boilerplate - Web Application Framework 项目地址: https://gitcode.com/gh_mirrors/as/aspnetboilerplate 点击查看 免费下载 ASP.NET Boilerplate 的官方免费启动模板默认针对 SQL Ser… · 2026/9/23 17:53:33

阶乘算法核心:小T的魔法数字与末尾零计数法
阶乘算法核心:小T的魔法数字与末尾零计数法

开学第一周,ACM社团的新生群里就炸开了锅,好几个大一小朋友都在刷同一道题:ZZULIOJ 2871,题目名很唬人,叫“小T的魔法数字”,标签是“阶乘算法(大一水平)”。说实话,光看… · 2026/9/23 17:53:27

3个坑让你彻底搞懂waste用法 从入门到精通
3个坑让你彻底搞懂waste用法 从入门到精通

3个坑让你彻底搞懂waste用法 从入门到精通 面试时被问“waste”到底指什么,是不是瞬间大脑一片空白?很多后端开发在复习基础概念时,往往死记硬背了“内存泄漏”或“CPU空转”,却答不上来具体在代码里是怎么产生的。这种只知其名、不知其理… · 2026/9/23 17:53:27

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码