【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.mfbz.cn/a/469642.html

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

相关文章

企业培训考试系统数字化解决方案优势有哪些?

企业员工内部培训考试系统&#xff0c;用数字技术和互联网平台&#xff0c;为企业提供高效、便捷、个性化的员工培训服务的解决方案。 企业员工培训考试数字化解决方案不仅能够提供更加高效、灵活和互动的学习体验&#xff0c;还能够帮助企业实现长期的人才发展战略&#xff0…

好委屈,东方甄选为何总是被供应商骗?

东方甄选最近很委屈。 315晚会过后&#xff0c;知名打假人王海爆料&#xff0c;称315晚会曝光的槽头肉扣肉在东方甄选和小杨哥的直播间里销售过。 东方甄选赶忙去问了问供应商情况。 供应商的回答让他感到暖心&#xff0c;表示虽然315晚会曝光了我们公司违规使用糟头肉&…

如何在三个简单步骤中为对象检测标注图像

初始通过彻底清洗和处理原始图像数据来奠定有效对象检测注释的基础。选择适合的工具、方法和清晰的注释过程指南来建立注释工作空间。通过在图像中划定对象并附上类别标签来执行注释&#xff0c;随后进行细致的核验&#xff0c;以确保数据集的精确性和完整性。 图像注释是计算…

极大似然估计和最大参数后验估计

概率是已知模型和参数&#xff0c;推数据&#xff1b;统计&#xff08;似然&#xff09;是已知数据&#xff0c;推模型和参数。对于函数 x表示某一个具体的数据&#xff1b;θ表示模型的参数。 如果θ是已知确定的&#xff0c;x 是变量&#xff0c;这个函数叫做概率函数(prob…

MYSQL概念和编译安装

目录 一、数据库概述 1.1数据 1.2表 1.3数据库 总结&#xff1a; 2.数据库管理系统&#xff08;DBMS&#xff09; 3.DBMS工作模式 4.数据库系统原理 二、数据库发展史 三、主流数据库 四、关系型数据库和非关系型数据库 1.关系型数据库 2.非关系数据库 MYSQL数据…

蓝桥杯--全球气温变暖

import java.util.Scanner;public class top7 {//全球边暖//思路&#xff0c;就是找出上下左右都是#的地方&#xff0c;如果这个地方是的&#xff0c;那么此时countstatic int count0;public static void main(String[] args) {Scanner scanner new Scanner(System.in);int ns…

Day14 代码随想录(1刷) 42接雨水+二叉树遍历

42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

【C++】用红黑树模拟实现set、map

目录 前言及准备&#xff1a;一、红黑树接口1.1 begin1.2 end1.3 查找1.4 插入1.5 左单旋和右单旋 二、树形迭代器&#xff08;正向&#xff09;2.1 前置 三、模拟实现set四、模拟实现map 前言及准备&#xff1a; set、map的底层结构是红黑树&#xff0c;它们的函数通过调用红…

【CSS练习】万年历 html+css+js

效果图 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><style>bod…

车辆运动学和动力学模型

参考&#xff1a;路径规划与轨迹跟踪系列算法学习_第9讲_车辆运动学和动力学模型 1 车辆运动学模型和动力学模型概述 要控制车辆的运动&#xff0c;首先要对车辆的运动建立数字化模型&#xff0c;模型建立的越准确&#xff0c;对车辆运动的描述越准确&#xff0c;对车辆的跟踪…

Django分页器

Django分页器 分页器前瞻之url urls.py不需要做修改 urlpatterns [path(test/, views.test,nametest), ]假设此时在原有的路径http://127.0.0.1:8000/app01/test后面添加/?page2 然后再后端获取到page def test(request):page request.GET.get(page)print(page) # 2retu…

Linux--如何在Linux上运行一个helloworld

一.安装vim和gcc sudo --是进入管理员模式 apt --是 Advanced Package Tool&#xff08;高级软件包工具&#xff09;的缩写&#xff0c;这是用于管理软件包的一种工具。 install --是安装的意思 后面跟软件的名称 完整的意思&#xff1a;在管理员的模式下安装 某个软件 …

使用jQuery的autocomplete实现数据查询一次,联想自动补全

书接上回&#xff0c;上次说到在jsp页面中&#xff0c;通过监听输入框的数值变化&#xff0c;实时查询数据库&#xff0c;得到返回值使用autocomplete属性自动补全&#xff0c;实现一个联想补全辅助操作&#xff0c;链接&#xff1a;使用jquery的autocomplete属性实现联想补全操…

C++--STL标准库

一.模板 模板是C中泛型编程的基础。一个模板就是一个创建类或函数的蓝图。 生活中常见的模板有: 编写一个比较两个值大小的函数&#xff0c;如果第一个值大于第二个值返回大于0的数字,两个值相等返回0,第一个值小于第二个值返回小于0的数字。 我们可以根据值类型定义多个函数&…

2024年阿里云服务器搭建幻兽帕鲁游戏_保姆级教程

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

SecureCRT出现乱码的解决方法

SecureCRT是一个商业终端连接工具&#xff0c;它支持多种自定义设置。默认设置下&#xff0c;通过SecureCRT连接SSH服务器可能出现中文乱码的情况。这是由于SecureCRT字符编码与服务器的字符编码不一致造成的。 当然解决这个问题也很简单&#xff0c;将SecureCRT字符编码设置成…

深入探讨Python中的文件操作与文件IO操作【第141篇—Python实现】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 深入探讨Python中的文件操作与文件IO操作 在Python编程中&#xff0c;文件操作和文件IO操作…

计算机缺失msvcp110.dll如何修复,多种修复方法教给你

当电脑系统中msvcp110.dll文件丢失时&#xff0c;可能会对计算机的正常运行产生一系列显著的影响。msvcp110.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;这个动态链接库文件对于许多基于Windows的应用程序至关重要&#xff0c;尤其是一些使用C编译器…

干货整理!火石控股创始人吴渔夫的 AI 游戏思维20条

近日&#xff0c;在一场面对面的直播中&#xff0c;自媒体「极新」创始人姜稳与火石控股创始人、奇酷网络董事长吴渔夫进行视频对话中&#xff0c;探讨了AI技术对游戏行业的新机遇和新挑战。 中国网游先锋&#xff0c;火石控股创始人&#xff0c;奇酷网络董事长吴渔夫认为&…

【亲测】Onlyfans年龄认证怎么办?Onlyfans需要年龄验证?

1. 引言 什么是OnlyFans&#xff1a;OnlyFans是一种内容订阅服务&#xff0c;成立于2016年&#xff0c;允许内容创作者从用户那里获得资金&#xff0c;用户需要支付订阅费用才能查看他们的内容。它在多个领域受到欢迎&#xff0c;包括音乐、健身、摄影&#xff0c;以及成人内容…
最新文章