【Godot4.2】2D导航01 - AStar2D及其使用方法

概述

对于2D平台跳跃或飞机大战,以及一些直接用键盘方向键操控玩家的游戏,是根本用不到寻路的,因为只需要检测碰撞就可以了。
但是对于像RTS或战棋这样需要操控玩家到地图指定位置的移动方式,就绝对绕不开寻路了。

导航、碰撞与寻路

在Godot中导航(navigation)可以被理解为是可通行区域。
碰撞(collision)是体积,指代障碍物,提示“不可通行”。
所以可以把导航和碰撞看做是反义的。也可以看做是0和1,true和false。有导航的地方就能通行,有碰撞的地方就不能通形。
寻路(Pathfinding)则是指在可通行区域和不可通行区域中找出一条可以行走的路径,而且这条路径往往是最短的。

寻路算法

任何计算机问题,都会有多种不同的编程解法,计算机问题的编程解法就可以称为“算法”。而算法是跨语言的,同样的算法你可以用不同编程语言实现。
对于寻路问题,也会有不同的编程解法,也就是不同寻路算法。
A*(A-Star)就是前辈大神们创造的寻路算法之一。它的特点是基于网格,而且可以快速的求解某个点到另一个点的最短有效路径。
Godot的AStar是封装了A*(A-Star)算法的类,2D版本的AStar2DAStarGrid2D也是如此。封装的好处是你不必从头实现算法,而是专注于使用。
Godot4.0中A*算法相关的类

Godot的AStar2D

AStar2D的使用思路是:

  • 添加可以到达的位置
  • 将可以行走的点两两连接,形成路径
  • 通过其方法直接求取某个位置到目标位置的最短路径
  • 让玩家或其他角色按照路径上点的顺序依次前进,直到到达目标位置

AStar2D的整体思路
以下是对应上图的代码实现:

extends Node2D

var astar = AStar2D.new() # 实例化

func _ready():
	# 添加可以到达的位置
	astar.add_point(0,Vector2(0,0))
	astar.add_point(1, Vector2(0, 0))
	astar.add_point(2, Vector2(0, 1), 1) # 默认权重为 1
	astar.add_point(3, Vector2(1, 1))
	astar.add_point(4, Vector2(2, 0))
	# 在点之间创建连接,形成路径
	astar.connect_points(1, 2, false)
	astar.connect_points(2, 3, false)
	astar.connect_points(4, 3, false)
	astar.connect_points(1, 4, false)
	# 查询某两个位置之间的路径
	var res = astar.get_id_path(1, 4) # [1,4]

AStar2D就是如此简单。

  • add_point()的时候传入了一个ID,可以将其想象为是一个唯一索引值,对点的标记。
  • get_id_path()方法获取的是两个对应ID的点之间的最短路径,返回的是包含路径经过的所有点的ID所组成的数组。
  • 你也可以用get_point_path()方法直接获取两个点之间的最短路径,返回的额是包含所有经过的点数组。

定义网格

你可以看到,如果是单纯的使用Vector2(0,0)Vector2(2,1)这样的坐标是毫无意义的,因为它们只代表屏幕上一个很小的像素区域,根本无法实现移动。
回过头看看上面对A*(A-Star)算法的描述:

A*(A-Star)就是前辈大神们创造的寻路算法之一。它的特点是基于网格,而且可以快速的求解某个点到另一个点的最短有效路径。

可以看到它是“基于网格”的。所以我们要使用AStar2D就需要基于网格。
这个网格可以是你自己用代码创建的,也可以是基于TileMap这样现成的网格体系。
比如如下代码,我们自定义了一个网格,并在屏幕上绘制。

extends Node2D

var astar = AStar2D.new() # 实例化
# 定义网格
var grid_size = Vector2i(32,32) # 尺寸 - 有多少行、多少列
var cell_size = Vector2i(32,32) # 单元格大小


func _ready():
	# 添加可以到达的位置
	astar.add_point(0,Vector2(0,0))
	astar.add_point(1, Vector2(0, 0))
	astar.add_point(2, Vector2(0, 1), 1) # 默认权重为 1
	astar.add_point(3, Vector2(1, 1))
	astar.add_point(4, Vector2(2, 0))
	# 在点之间创建连接,形成路径
	astar.connect_points(1, 2, false)
	astar.connect_points(2, 3, false)
	astar.connect_points(4, 3, false)
	astar.connect_points(1, 4, false)
	# 查询某两个位置之间的路径
	var res = astar.get_id_path(1, 4) # [1,4]

func _draw():
	# 绘制网格
	for x in grid_size.x:
		for y in grid_size.y:
			draw_rect(Rect2i(Vector2i(x,y) * cell_size,cell_size),Color.YELLOW,false,1)

运行效果:
image.png

绘制Astar的点和路径到网格

extends Node2D

var astar = AStar2D.new() # 实例化
# 定义网格
var grid_size = Vector2i(32,32) # 尺寸 - 有多少行、多少列
var cell_size = Vector2i(32,32) # 单元格大小


func _ready():
	# 添加可以到达的位置
	astar.add_point(0,Vector2(0,0))
	astar.add_point(1, Vector2(0, 0))
	astar.add_point(2, Vector2(0, 1), 1) # 默认权重为 1
	astar.add_point(3, Vector2(1, 1))
	astar.add_point(4, Vector2(2, 0))
	# 在点之间创建连接,形成路径
	astar.connect_points(1, 2, false)
	astar.connect_points(2, 3, false)
	astar.connect_points(4, 3, false)
	astar.connect_points(1, 4, false)
	# 查询某两个位置之间的路径
	var res = astar.get_id_path(1, 4) # [1,4]

func _draw():
	# 绘制网格
	for x in grid_size.x:
		for y in grid_size.y:
			draw_rect(Rect2i(Vector2i(x,y) * cell_size,cell_size),Color.YELLOW,false,1)
	# 绘制点
	for i in range(astar.get_point_count()):
		var pos = astar.get_point_position(i) * Vector2(cell_size) + Vector2(cell_size/2)
		draw_circle(pos,10,Color.YELLOW)

image.png

extends Node2D

var astar = AStar2D.new() # 实例化
# 定义网格
var grid_size = Vector2i(32,32) # 尺寸 - 有多少行、多少列
var cell_size = Vector2i(32,32) # 单元格大小


func _ready():
	# 添加可以到达的位置
	astar.add_point(0,Vector2(0,0))
	astar.add_point(1, Vector2(0, 0))
	astar.add_point(2, Vector2(0, 1), 1) # 默认权重为 1
	astar.add_point(3, Vector2(1, 1))
	astar.add_point(4, Vector2(2, 0))
	# 在点之间创建连接,形成路径
	astar.connect_points(1, 2, false)
	astar.connect_points(2, 3, false)
	astar.connect_points(4, 3, false)
	astar.connect_points(1, 4, false)
	# 查询某两个位置之间的路径
	var res = astar.get_point_connections(1)
	print(res)

func _draw():
	# 绘制网格
	for x in grid_size.x:
		for y in grid_size.y:
			draw_rect(Rect2i(Vector2i(x,y) * cell_size,cell_size),Color.YELLOW,false,1)
	# 绘制点
	for i in range(astar.get_point_count()):
		var pos = get_grid_pos(astar.get_point_position(i))
		draw_circle(pos,5,Color.YELLOW)
	# 绘制所有路径
	for i in range(astar.get_point_count()):
		var pos = get_grid_pos(astar.get_point_position(i))
		if i+1 <= astar.get_point_count():
			var pos2 = get_grid_pos(astar.get_point_position(i+1))
			draw_line(pos,pos2,Color.GREEN_YELLOW,2)
		
# 返回屏幕中的点或路径中的点对应在网格中的坐标
func get_grid_pos(point_pos:Vector2):
	return point_pos * Vector2(cell_size) + Vector2(cell_size/2)

image.png

extends Node2D

var astar = AStar2D.new() # 实例化
# 定义网格
var grid_size = Vector2i(32,32) # 尺寸 - 有多少行、多少列
var cell_size = Vector2i(32,32) # 单元格大小


func _ready():
	# 添加可以到达的位置
	astar.add_point(0,Vector2(0,0))
	astar.add_point(1, Vector2(0, 0))
	astar.add_point(2, Vector2(0, 1), 1) # 默认权重为 1
	astar.add_point(3, Vector2(1, 1))
	astar.add_point(4, Vector2(2, 0))
	# 在点之间创建连接,形成路径
	astar.connect_points(1, 2, false)
	astar.connect_points(2, 3, false)
	astar.connect_points(4, 3, false)
	astar.connect_points(1, 4, false)
	# 查询某两个位置之间的路径
	var res = astar.get_point_connections(1)
	print(res)

func _draw():
	# 绘制网格
	for x in grid_size.x:
		for y in grid_size.y:
			draw_rect(Rect2i(Vector2i(x,y) * cell_size,cell_size),Color.YELLOW,false,1)
	# 绘制点
	for i in range(astar.get_point_count()):
		var pos = get_grid_pos(astar.get_point_position(i))
		draw_circle(pos,5,Color.YELLOW)
	# 绘制所有路径
	for i in range(astar.get_point_count()):
		var pos = get_grid_pos(astar.get_point_position(i))
		if i+1 <= astar.get_point_count():
			var pos2 = get_grid_pos(astar.get_point_position(i+1))
			draw_line(pos,pos2,Color.GREEN_YELLOW,2)
	# 绘制寻找到的路径
	var path = astar.get_point_path(1,4)
	for i in path.size()-1:
		var pos = get_grid_pos(path[i])
		if i+1 <= path.size():
			var pos2 = get_grid_pos(path[i+1])
			draw_line(pos,pos2,Color.RED,2)
	
	

# 返回屏幕中的点或路径中的点对应在网格中的坐标
func get_grid_pos(point_pos:Vector2):
	return point_pos * Vector2(cell_size) + Vector2(cell_size/2)

image.png

建立障碍物

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序接口请求出错:request:fail url not in domain list:xxxxx

一、微信小程序后台和开发者工具配的不一样导致了这个错误 先说结论&#xff1a; 开发者工具配置了https://www.xxx.cn/prod-api/ 微信后台配置了 https://www.xxx.cn 一、最开始 开发者工具配置了https://www.xxx.cn:7500 微信后台配置了 https://www.xxx.cn 报错:reques…

代码随想录算法训练营第53天 | 1143.最长公共子序列 ,1035.不相交的线 ,53. 最大子序和

动态规划章节理论基础&#xff1a; https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 1143.最长公共子序列 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-subsequence/description/ 思路&…

ASP .Net Core ILogger日志服务

&#x1f433;简介 ILogger日志服务是.NET平台中的一个内置服务&#xff0c;主要用于应用程序的日志记录。它提供了灵活的日志记录机制&#xff0c;允许开发者在应用程序中轻松地添加日志功能。以下是其主要特点和组件&#xff1a; ILogger接口&#xff1a;这是ILogger日志服…

电脑数据安全新利器:自动备份文件的重要性与实用方案

一、数据安全的守护神&#xff1a;自动备份文件的重要性 在数字化时代&#xff0c;电脑中的文件承载着我们的工作成果、个人回忆以及众多重要信息。然而&#xff0c;数据丢失的风险无处不在&#xff0c;无论是硬件故障、软件崩溃&#xff0c;还是恶意软件的攻击&#xff0c;都…

JupytetNotebook常用的快捷键

Jupyter Notebook 中常用的快捷键&#xff1a; 切换到命令模式&#xff1a;按 Esc 键。切换到编辑模式&#xff1a;按 Enter 键。运行当前单元格并选择下面的单元格&#xff1a;按 Shift Enter。运行当前单元格并插入新的单元格在下面&#xff1a;按 Alt Enter。删除当前单元…

【Vue3】Vue3中的编程式路由导航 重点!!!

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

test测试类-变量学习

test测试类 作用&#xff1a;标记到类上成为测试类&#xff0c;标记到方法上成为测试方法 变量&#xff1a;测试类的变量&#xff0c;在测试类括号中应用 1、invocationCount变量 意思是这个方法应该被调用的次数。 在测试框架中&#xff0c;特别是当使用参数化测试或数据驱动…

HarmonyOS(鸿蒙)快速入门

一:下载开发工具 鸿蒙的开发工具叫DevEco 下载点击 其他部分都一直next 就行,这个页面出现的install 建议都点击install 然后单独选择安装目录 可能存在的问题 就是之前安装nodejs&#xff08;比如自己开发web或者RN等情况&#xff09;版本低 等情况 所以建议你单独安装一次 …

Avalon总线学习

Avalon总线学习 avalon总线可以分为&#xff1a; Avalon clock interface Avalon reset interface Avalon Memory mapped interface Avalon iterrupt interface Avalon streaming interface Avalon tri-state conduit interface Avalon conduit interface 1、Avalon c…

杨氏矩阵的查找(复杂度<O(N))

题目&#xff1a; 解释&#xff1a;时间复杂度小于O(N)即不要一个一个的去遍历查找。 思路&#xff1a; 一个33的二维数组如图所示&#xff1a; 一&#xff1a;先找到一个最关键的数字&#xff0c;3&#xff08;下标为0,2&#xff09; 关键数的关键之处在于&#xff08;处于…

SpringBoot + MyBatisPlus分页查询

文章目录 1.思路分析2.分页查询后端实现1.com/sun/furn/config/MybatisConfig.java 注入MyBatisPlus分页拦截器2.com/sun/furn/controller/FurnController.java 添加方法3.postman测试 3.分页查询前端实现1.src/views/HomeView.vue 引入分页导航条组件2.src/views/HomeView.vue…

外包干了6天,技术明显进步。。。

我是一名大专生&#xff0c;自19年通过校招进入湖南某软件公司以来&#xff0c;便扎根于功能测试岗位&#xff0c;一晃便是近四年的光阴。今年8月&#xff0c;我如梦初醒&#xff0c;意识到长时间待在舒适的环境中&#xff0c;已让我变得不思进取&#xff0c;技术停滞不前。更令…

springboot企业级抽奖项目-整体展示

项目地址 GitHub - kiorr/lottery: 企业红包雨项目 star截图q&#xff1a;3353441618可以领取资料 原型效果 前台 后台 业务分析 项目介绍 项目概述 京东的红包雨大家可能都参与过&#xff0c;在某段时间内随机发放不同的红包 本项目为一个通用的红包雨模式抽奖系统&…

腾讯云服务器多少钱一个月?5元1个月,这价格没谁了

2024腾讯云服务器多少钱一个月&#xff1f;5元1个月起&#xff0c;腾讯云轻量服务器4核16G12M带宽32元1个月、96元3个月&#xff0c;8核32G22M配置115元一个月、345元3个月&#xff0c;腾讯云轻量应用服务器61元一年折合5元一个月、4核8G12M配置646元15个月、2核4G5M服务器165元…

linux单机部署hadoop

1.下载安装包 https://archive.apache.org/dist/hadoop/common/ 2.上传压缩 3.修改配置文件 1)设置JDK的路径 cd /usr/local/software/hadoop-3.1.3/etc/hadoop vi hadoop-env.sh export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/ 查看…

RK3588_Qt交叉编译环境搭建

buildroot编译 进入 /home/linux/plat/rk3588/sdk/buildroot 目录下&#xff0c;执行 Source ./envsetup.sh 选择具体平台编译&#xff0c;后再执行make编译 /home/linux/plat/rk3588/sdk/buildroot/output/OK3568/images 生成的rootfs.ext2镜像重新烧写到rk3568开发板中&…

简单对已有云服务器进行linux环境搭建以及共享服务器

前言&#xff1a; 外壳程序&#xff1a;Xshell7 云服务器&#xff1a;华为云 服务器操作系统&#xff1a;centos7 1.云服务的设置&#xff08;这里购买的华为云&#xff0c;阿里腾讯都可以&#xff09; 区域尽量选择距离所处地距离自己最近的区域。镜像这里选择的为centos7.…

流畅的Python(二十一)-类元编程

一、核心要义 1.类元编程时指在运行时创建或定制类的技艺 2.类是一等对象,因此任何时候都可以使用函数新建类&#xff0c;而无需使用class关键字 3.类装饰器也是函数&#xff0c;不过能够审查、修改&#xff0c;甚至把被装饰的类替换为其它类。 4.元类(type类的子类)类编程…

框架篇常见面试题

1、Spring框架的单例bean是线程安全的吗&#xff1f; 2、什么是AOP&#xff1f; 3、Spring的事务是如何实现的&#xff1f; 4、Spring事务失效的场景 5、SpringBean的声明周期 6、Spring的循环依赖 7、SpringMVC的执行流程 8、SpringBoot自动配置原理 9、Spring常见注解
最新文章