Threejs路径规划_基于A*算法案例完整版

        上节利用了A*实现了基础的路径规划,这节把整个功能完善好,A*算法一方面是基于当前点找到可以到达的点,计算从出发点到此点,以及此点到目的地的总成本,比较出最小的那个,再用最小成本的点继续找到它可以到达的点,直到目的地,同时会创建两个集合,一个叫open集合,一个叫close集合,open是用于存放到达过且没有继续探索的点,close集合是存放到达过且继续探索的点,简单的说A*算法会一边探索的同时会把新探索到的点放到open集合中,一边把探索过的点加入到close集合中。这样可以防止重复探索之前的点,如果探测到的点包含目标点。则探索结束。下面我们用图例的方式演示整个过程

        如图在网格中有出发点和目的地,分别在网格的两侧,如果要从出发点到达目的地,A*算法会先获取到Start可以到达的四个点,将四个点放到open集合中,然后选出四个点中到达End成本做小的,

        此时可以明显的看出右侧的格子到End点的成本最小,这里的成本包括已经花费的成本和到End点预估的成本,

得到了成本最小的点后,再继续基于这个点继续探索周围的点,同时会将探索过的Start点放到close集合中,经过探索,仍然是右侧点成本最低,然后将探索到的点放到open中,探索过的点放到close中,继续探索,依此类推,直到探索到End点。

然后我们按照上述方式将方法改造如下:

buildPath() {// 选择的起始点和目标点if (this.beginPoint.x > 30 || this.beginPoint.y > 30 || this.endPoint.x > 30 || this.endPoint.y > 30) {this.$message.error('超出地图范围')return}const begin = (parseInt(this.beginPoint.x) - 1) + '.' + (this.beginPoint.y - 1)const end = (parseInt(this.endPoint.x) - 1) + '.' + (this.endPoint.y - 1)this.removeOnce() // 移除上一次规划的内容this.drawPoint(begin) // 将出发点绘制到地图上this.openPoint.push({ point: begin, distance: 0 })let current = { point: begin, path: [begin], distance: 0 }while (current.point !== end) {const result = this.recursion(current, end)current = result}this.pathRoad = current.path.split('_')for (let i = 0; i < this.pathRoad.length; i++) {this.drawPoint(this.pathRoad[i])}},calcDistance(start, end) {const beginX = start.split('.')[0]const beginY = start.split('.')[1]const endX = end.split('.')[0]const endY = end.split('.')[1]// 获取到达的点与目的地的曼哈顿距离const distance = Math.abs(parseInt(endX - beginX)) + Math.abs(parseInt(endY - beginY))return distance},recursion(current, end) {const tempPoints = [] // 当前点可以连接的路线// 获取到这个点能到达的所有点的路线for (let i = 0; i < this.roadList.length; i++) {if (this.roadList[i].begin === current.point) {tempPoints.push(this.roadList[i].end)}}for (let i = 0; i < tempPoints.length; i++) {const hadSpend = parseInt(current.distance) + 1 // 已经花费的成本,也就是起点到当前点的成本(是上一个点+1得到)const remainingEstimated = this.calcDistance(tempPoints[i], end) // 下一个点到目标点的成本,也就是剩余预估成本const totalCost = parseInt(hadSpend) + parseInt(remainingEstimated)const path = current.path + '_' + tempPoints[i]// 如果点已经在close中了就不加入openList中let havaClose = falsefor (let j = 0; j < this.closePoint.length; j++) {if (this.closePoint[j].point === tempPoints[i]) {havaClose = true}}if (!havaClose) {this.openPoint.push({ point: tempPoints[i], haveCost: hadSpend, path: path, remainingCost: remainingEstimated, distance: totalCost })}}// 从开放点中去掉已经走过的点,并加入到close点集合中for (let i = 0; i < this.openPoint.length; i++) {if (this.openPoint[i].point === current.point) {this.openPoint.splice(i, 1)this.closePoint.push(current)i--}}// 比较openList中哪个distance的成本最小就用此继续递归let result = { point: this.openPoint[0].point, distance: this.openPoint[0].distance }// 获取到目的地最近的点并返回for (let i = 0; i < this.openPoint.length; i++) {if (this.openPoint[i].distance <= result.distance) {result = { point: this.openPoint[i].point, haveCost: this.openPoint[i].haveCost, path: this.openPoint[i].path, distance: this.openPoint[i].distance }}}const data = { point: result.point, path: result.path, distance: result.haveCost }return data},

效果如下:

        此时输入出发点和目标点后会直接算出路径,并把路径绘制在网格上,但是我们是基于threejs的,可以再增加点动画效果,在计算出路径后,通过threejs的动画每隔一定的时间绘制出一个点,就时间了动画效果,代码如下:

      roadIndex: 0,pathRoad: [],times: 0 
initAnimate() {requestAnimationFrame(this.initAnimate)this.renderer.render(this.scene, this.camera)if (this.pathRoad.length > 0 && this.roadIndex < this.pathRoad.length - 1) {this.times += 0.1if (this.times > 1) {this.times = 0this.roadIndex += 1this.drawPoint(this.pathRoad[this.roadIndex])}}},

效果如下:

基于A*算法的Threejs动画

如果觉得不错,给我点个赞吧,需要源码或者有问题欢迎给我留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14611.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

明天(周六)下午!武汉Linux爱好者线下沙龙,我们在华中科技大学等你!

2024 年 5月 25 日&#xff08;周六&#xff09;下午&#xff0c;我们将在「武汉市洪山区」 珞喻路 1037 号华中科技大学南五楼 613 室举办武汉 Linux 爱好者线下沙龙&#xff08;WHLUG&#xff09;&#xff0c;欢迎广大 Linux 爱好者来到现场&#xff0c;与我们一同交流技术&a…

git分支开发主干合并流程

文章目录 一、分支开发二、主干合并三、删除合并过的分支 一、分支开发 创建分支git branch <分支名> # git branch my_new_branch开发后提交代码git commit -m 本次开发内容 # git commit -m 增加登录保持功能同步远端仓库git push origin <分支名> # git push o…

Kubernetes——资源调度与Pod探针

目录 前言 一、资源调度策略 1.默认调度器&#xff08;Default Scheduler&#xff09; 2.自定义调度器&#xff08;Custom Scheduler&#xff09; 3.亲和性与反亲和性&#xff08;Affinity and Anti-Affinity&#xff09; 4.污点与容忍&#xff08;Taints and Toleration…

单体应用与微服务的优缺点

单体应用与微服务的优缺点 单体应用&#xff08;monolith application&#xff09;就是将应用程序的所有功能都打包成一个独立的单元&#xff0c;可以是 JAR、WAR、EAR 或其它归档格式。 随着业务需求的快速发展变化&#xff0c;敏捷性、灵活性和可扩展性需求不断增长&#x…

Window GDI+ API有BUG?GetBounds测不准?

文章目录 GraphicsPath的GetBounds测不准&#xff1f;方法一&#xff1a;GetBounds ()实战 方法二&#xff1a;GetBounds(Matrix)实战 GraphicsPath的GetBounds测不准?实战 .NET 版本的问题&#xff1f;C也一样&#xff0c;不是.NET的问题怀疑人生MiterLimit惹得祸完美结果结束…

MyBatis-Plus介绍及Spring Boot 3集成指南

我们每个Java开发者都在使用springbootmybatis开发时&#xff0c;我们经常发现自己需要为每张数据库表单独编写XML文件&#xff0c;并且为每个表都需要编写一套增删改查的方法&#xff0c;较为繁琐。为了解决这一问题&#xff0c;MyBatis-Plus应运而生。在本文中&#xff0c;我…

第七节:带你全面理解vue3: 其他响应式进阶API

前言: 针对vue3官网中, 响应式:进阶API 中, 我们在上一章中给大家讲解了shallowRef, shallowReactive, shallowReadonly几个API的使用. 本章主要对剩下的API 进行讲解, 我们先看一下官网中进阶API 都有那些 对于剩下这些API, 你需要了解他们创建目的, 是为了解决之前的API存在…

查看cpu进程数

import multiprocessing from multiprocessing import Pool# 导入 Pool 允许你创建一个进程池 # 进程池是一组工作进程&#xff0c;它们可以并行地执行多个任务# multiprocessing.cpu_count(): 返回当前机器上的CPU核心数 sum_cpu multiprocessing.cpu_count()use_cpu max(1,…

LLM多模态——GPT-4o改变人机交互的多模式 AI 模型应用

1. 概述 OpenAI 发布了迄今为止最新、最先进的语言模型 – GPT-4o也称为“全“ 模型。这一革命性的人工智能系统代表了一次巨大的飞跃&#xff0c;其能力模糊了人类和人工智能之间的界限。 GPT-4o 的核心在于其原生的多模式特性&#xff0c;使其能够无缝处理和生成文本、音频…

AWPortrait1.4更新,人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新的高度

AWPortrait1.4更新&#xff0c;人物的生成更加趋近真实感&#xff0c;将SD1.5人像的真实感提升到了一个新的高度 经过5个月&#xff0c;AWPortrait终于迎来了1.4。 本次更新基于1.3训练&#xff0c;使得人物的生成更加趋近真实感&#xff0c;将SD1.5人像的真实感提升到了一个新…

SpringBoot(七)之监控

SpringBoot&#xff08;七&#xff09;之监控 Spring Boot 提供了丰富的监控和管理功能&#xff0c;可以通过 Spring Boot Actuator 组件实现。Actuator 使你能够监控和管理 Spring Boot 应用程序的各个方面&#xff0c;比如健康检查、指标、环境信息等。以下是如何在 Spring …

EUT上电时,测试LISN拾取的脉冲电压对接收机的影响

背景&#xff1a;在2024年4月25日发现G220 IP20 FSF1测试结果不一致&#xff0c;有5dB差异&#xff0c;经排查&#xff0c;是两台接收机测试出的结果不一致&#xff0c;经过进一步确认&#xff0c;使用信号发生器直接灌入接收机DI-111内&#xff0c;测试出的结果会少4dB.使用梳…

linux-ftp服务器搭建简介

安装ftp服务器&#xff1a; vsftpd全称为“very secure FTP daemon”&#xff0c;是一个在UNIX类操作系统上运行的服务&#xff0c;可以提供高安全性的FTP服务。 vsftpd是一个免费和开放源代码的FTP服务器软件&#xff0c;它提供了许多其他FTP服务器不支持的特性&#xff0c;例…

基于python+Django大数据的电影市场预测分析系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

uview1.0 u-form表单回显校验不通过

提交到后端的数据&#xff0c;回显后不做任何修改无法通过表单校验 原因&#xff0c;u-form表单校验的类型默认为string&#xff0c;但是后端返回的是integer类型&#xff0c;导致无法通过校验 解决&#xff0c;既然后端返回的是整数形&#xff0c;那么我们就将校验规则的type…

html 根字号 以及 设置根元素font-size:calc(100vw/18.75)、元素rem实现自适应

rem 单位介绍&#xff1a;rem 是相对文档根元素(html)字体大小的尺寸单位&#xff0c;当元素的尺寸或文字字号等使用 rem 单位时&#xff0c;会随着根元素的 font-size变化而变化。 得出结论&#xff1a;在不同分辨率的设备下动态设置根元素的字体大小就可以实现页面自适应。 …

【企业动态】东胜物联成为AWS硬件合作伙伴,助力实现边缘智能

近日&#xff0c;AIoT硬件设备供应商东胜物联与全球领先的云计算服务提供商亚马逊云&#xff08;AWS&#xff09;达成合作关系&#xff0c;共同致力于推动物联网技术的发展&#xff0c;为企业客户提供更智能、灵活的硬件解决方案&#xff0c;助力智能化升级和数字化转型。 作为…

Android studio关闭自动更新

Windows下&#xff1a; 左上角file - setting - Appearance & Behavier - system setting - update - 取消勾选

图书管理系统(Java版本)

文章目录 前言要求1.设置对象1.1.图书1.2.书架2.管理员3.功能的实现 2.搭建框架2.1.登录(login)2.2.菜单2.3.操作方法的获取 3.操作方法的实现3.1.退出系统(ExitOperation)3.2.显示图书(ShowOperation)3.3.查阅图书(FindOperation)3.4.新增图书(AddOperation)3.5.借出图书(Borr…

现代浏览器性能优化示例-提前加载prefetch:

prefetch就是在核心代码 加载完成后&#xff0c;浏览器有空闲就会帮我们prefetch预取资源 请注意&#xff0c;prefetch 是一种优化手段&#xff0c;而不是必须使用的功能。在决定是否使用它之前&#xff0c;请确保你的应用程序已经进行了其他必要的性能优化&#xff08;如代码压…