【Godot4.2】2D导航02 - AstarGrid2D及其使用方法

news2024/11/30 12:52:09

概述

AstarGrid2D是Godot4.0新增的A*寻路辅助类型。可以看做是Astar2D的加强版。它允许你通过设置其sizecell_size属性来创建一个虚拟的网格。

并使用set_point_solid()这样的方法来在指定位置创建障碍物。

AstarGrid2D的好处是你不再需要手动的添加点以及点与点之间的连接,而是直接用get_point_path()这样的方法来获取最短路径(也就是一个包含了最短路径经过的点的数组)。

通过遍历这个数组,就可以实现路径移动了。

extends Control

var astar_grid = AStarGrid2D.new()

var cell_size = Vector2.ONE * 100

func _ready():
	astar_grid.size = Vector2i.ONE * 32
	astar_grid.cell_size = Vector2i.ONE * 32
	astar_grid.update()
	


func _draw():
	# 绘制网格
	var grid_width = astar_grid.size.x * astar_grid.cell_size.x
	var cell_width = astar_grid.cell_size.x
	var cell_height = astar_grid.cell_size.y
	
	for i in range(astar_grid.size.x):
		draw_line(i * Vector2i(0,cell_height),i * Vector2i(grid_width,cell_height),Color.DARK_OLIVE_GREEN,2)
	for j in range(astar_grid.size.y):
		draw_line(j * Vector2i(cell_height,0),j * Vector2i(cell_height,grid_width),Color.DARK_OLIVE_GREEN,2)
	# 绘制路径和其上的点
	var path  = astar_grid.get_point_path(Vector2i(0,0),Vector2i(10,10))
	for pot in path:
		draw_circle(pot,5,Color.YELLOW)
	draw_polyline(path,Color.YELLOW,2)

image.png

extends Control

var astar_grid = AStarGrid2D.new()

var path:PackedVector2Array

var solids = []

func _ready():
	randomize()
	astar_grid.size = Vector2i.ONE * 32
	astar_grid.cell_size = Vector2i.ONE * 32
	astar_grid.offset = astar_grid.cell_size/2
	astar_grid.update()
	
	# 随机生成障碍
	for i in range(50):
		var solid_point = Vector2i(randi_range(0,astar_grid.size.x),randi_range(0,astar_grid.size.y))
		astar_grid.set_point_solid(solid_point,true)
		solids.append(solid_point)
		
	


func _draw():
	var grid_width = astar_grid.size.x * astar_grid.cell_size.x
	var cell_width = astar_grid.cell_size.x
	var cell_height = astar_grid.cell_size.y
	# 绘制网格
	for i in range(astar_grid.size.x):
		draw_line(i * Vector2i(0,cell_height),i * Vector2i(grid_width,cell_height),Color.DARK_OLIVE_GREEN,2)
	for j in range(astar_grid.size.y):
		draw_line(j * Vector2i(cell_height,0),j * Vector2i(cell_height,grid_width),Color.DARK_OLIVE_GREEN,2)
	
	# 绘制路径和其上的点
	if path.size() > 0:
		for pot in path:
			draw_circle(pot,5,Color.YELLOW)
				
		draw_polyline(path,Color.YELLOW,2)
	for p in solids:
		draw_rect(Rect2(p * Vector2i(astar_grid.cell_size),astar_grid.cell_size),Color.GRAY)

func _on_gui_input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT:
			if event.is_pressed():
				path = astar_grid.get_point_path(Vector2i(0,0),floor(get_global_mouse_position()/astar_grid.cell_size))
				queue_redraw()

  • 13行:将AstarGridoffset 设为 astar_grid.cell_size/2,也就实现了整体的坐标偏移。
  • 48行:floor(get_global_mouse_position()/astar_grid.cell_size)获得的就是鼠标点击所在的单元格的坐标。

AstarGrid寻路2.gif
目前为止,AstarGrid显示对角线形式的连接。

如果我们需要设置其只显示横平竖直的连接,则可以设置AstarGriddiagonal_modeDIAGONAL_MODE_NEVER

astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER

AstarGrid寻路3.gif

DiagonalMode说明
DIAGONAL_MODE_ALWAYS0该寻路算法将忽略目标单元格周围的实体邻居,并允许沿对角线通过。
DIAGONAL_MODE_NEVER1该寻路算法将忽略所有对角线,并且路径始终是正交的。
DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE2如果在特定路径段的相邻单元格周围放置了至少两个障碍物,则该寻路算法将避免使用对角线。
DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES3如果在特定路径段的相邻单元格周围放置了任意障碍物,则该寻路算法将避免使用对角线。
DIAGONAL_MODE_MAX4代表 DiagonalMode 枚举的大小。

实现玩家基于AstarGrid2D的移动

用一个简单Sprite2D作为玩家。将其缩放为原始尺寸128×128的四分之一,也就是32×32。刚好可以填入AstarGrid2D的单元格中。
image.pngimage.png

extends Control

var astar_grid = AStarGrid2D.new()
var path:PackedVector2Array
var solids = [] # 障碍物列表

@onready var icon = $Icon
var speed = 200.0
var can_walk = false
var target_pos:Vector2

func _process(delta):
	if can_walk:
		if path.size()>0:
			target_pos = path[0]
			if icon.position.distance_to(target_pos)>0:
				icon.position = icon.position.move_toward(target_pos,speed * delta)
			else:
				path.remove_at(0)
				queue_redraw()
		else:
			can_walk = false

func _ready():
	randomize()
	astar_grid.size = Vector2i.ONE * 32
	astar_grid.cell_size = Vector2i.ONE * 32
	astar_grid.offset = astar_grid.cell_size/2
	icon.position = astar_grid.cell_size/2
	astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
	astar_grid.default_compute_heuristic  = AStarGrid2D.HEURISTIC_MANHATTAN

	astar_grid.update()
	
	# 随机生成障碍
	for i in range(150):
		var solid_point = Vector2i(randi_range(0,astar_grid.size.x),randi_range(0,astar_grid.size.y))
		astar_grid.set_point_solid(solid_point,true)
		solids.append(solid_point)
		
	


func _draw():
	var grid_width = astar_grid.size.x * astar_grid.cell_size.x
	var cell_width = astar_grid.cell_size.x
	var cell_height = astar_grid.cell_size.y
	# 绘制网格
	for i in range(astar_grid.size.x):
		draw_line(i * Vector2i(0,cell_height),i * Vector2i(grid_width,cell_height),Color.DARK_OLIVE_GREEN,2)
	for j in range(astar_grid.size.y):
		draw_line(j * Vector2i(cell_height,0),j * Vector2i(cell_height,grid_width),Color.DARK_OLIVE_GREEN,2)
	
	# 绘制路径和其上的点
	if path.size() > 0:
		for pot in path:
			draw_circle(pot,5,Color.YELLOW)
				
		draw_polyline(path,Color.YELLOW,2)
	for p in solids:
		draw_rect(Rect2(p * Vector2i(astar_grid.cell_size),astar_grid.cell_size),Color.GRAY)

func _on_gui_input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT:
			if event.is_pressed():
				can_walk = true
				path = astar_grid.get_point_path(floor(icon.position/astar_grid.cell_size),floor(get_global_mouse_position()/astar_grid.cell_size))
				queue_redraw()

每次获取路径的第一个点,利用简单的距离判断和移动,到达后,从路径中删除该点。继续获取路径第一个,如此循环,知道路径中的点删除完毕。

基于AstarGrid2D的简单玩家移动

可行动范围的获取

矩形范围查找法:
先不考虑对角线移动的问题,我们假设玩家可行动点数是4,那么我们只需要遍历一个8×8矩阵的每个点到玩家的是否有可行走的路径,如果有且路径的点数<=4,则标记为可到达的点,否则,标记为不能到达的点。
image.png

extends Control

var astar_grid = AStarGrid2D.new()
var path:PackedVector2Array
var solids = [] # 障碍物列表
var max_step:int = 4 # 玩家单次的最大行动点数
var can_walk_rect:Rect2i
var can_walk_points:PackedVector2Array 

@onready var icon = $Icon
var speed = 200.0
var can_walk = false
var target_pos:Vector2

func _process(delta):
	if can_walk:
		if path.size()>0:
			target_pos = path[0]
			if icon.position.distance_to(target_pos)>0:
				icon.position = icon.position.move_toward(target_pos,speed * delta)
			else:
				path.remove_at(0)
				queue_redraw()
		else:
			can_walk = false
			queue_redraw()

func _ready():
	randomize()
	astar_grid.size = Vector2i.ONE * 32
	astar_grid.cell_size = Vector2i.ONE * 32
	astar_grid.offset = astar_grid.cell_size/2
	icon.position = astar_grid.cell_size/2
	astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER

	astar_grid.update()
	
	# 随机生成障碍
	for i in range(150):
		var solid_point = Vector2i(randi_range(0,astar_grid.size.x),randi_range(0,astar_grid.size.y))
		astar_grid.set_point_solid(solid_point,true)
		solids.append(solid_point)

	
	

func _draw():
	var grid_width = astar_grid.size.x * astar_grid.cell_size.x
	var cell_width = astar_grid.cell_size.x
	var cell_height = astar_grid.cell_size.y
	# 绘制网格
	for i in range(astar_grid.size.x):
		draw_line(i * Vector2i(0,cell_height),i * Vector2i(grid_width,cell_height),Color.DARK_OLIVE_GREEN,2)
	for j in range(astar_grid.size.y):
		draw_line(j * Vector2i(cell_height,0),j * Vector2i(cell_height,grid_width),Color.DARK_OLIVE_GREEN,2)
	
	# 绘制路径和其上的点
	if path.size() > 0:
		for pot in path:
			draw_circle(pot,5,Color.YELLOW)
				
		draw_polyline(path,Color.YELLOW,2)
	# 绘制障碍物
	for p in solids:
		draw_rect(Rect2(p * Vector2i(astar_grid.cell_size),astar_grid.cell_size),Color.GRAY)
	# 绘制可行走范围
	# 遍历矩形
	if !can_walk:
		var player_pos = floor(icon.position/astar_grid.cell_size)
		var top_left = clamp(player_pos - Vector2.ONE * max_step,Vector2.ZERO,player_pos)
		var end =  clamp(player_pos + Vector2.ONE * max_step,player_pos,Vector2(astar_grid.size))
		can_walk_rect = Rect2(top_left,end-top_left) # 获取矩形
		for i in range(can_walk_rect.position.x,can_walk_rect.end.x + 1):
			for j in range(can_walk_rect.position.y,can_walk_rect.end.y + 1):
				var v = Vector2(i,j)
				if astar_grid.get_point_path(player_pos,v).size() <= max_step+1:
					if !astar_grid.is_point_solid(v):
						can_walk_points.append(v)
						draw_rect(Rect2(v * astar_grid.cell_size,astar_grid.cell_size),Color.YELLOW_GREEN,false,2)
	
	
	
func _on_gui_input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT:
			if event.is_pressed():
				can_walk = true
				var player_pos = floor(icon.position/astar_grid.cell_size)
				var targ_pos = floor(get_global_mouse_position()/astar_grid.cell_size)
				if targ_pos in can_walk_points: # 如果在可行走的范围内
					path = astar_grid.get_point_path(player_pos,targ_pos)
					can_walk_points.clear() # 清空原来的可行走范围
					queue_redraw()

AstarGrid寻路-显示和限定行走范围.gif
AstarGrid寻路-显示和限定行走范围2.gif

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

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

相关文章

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——自适应大邻域算法(ALNS)

基于python语言&#xff0c;采用经典自适应大邻域算法&#xff08;ALNS&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果4. 代码片段参考 往期优质资源 经过一年多的创作&#xff0c;目前…

OPTEE v3.20.0 FVP环境搭建

目录 一、前提条件 二、下载fvp代码 三、下载工具链 四、下载Foundation_Platform FVP平台 五、编译及运行 一、前提条件 1、安装如下的依赖工具 sudo apt-get install android-tools-adb android-tools-fastboot autoconf \ automake bc bison build-essential ccache c…

精酿啤酒:开启时尚派对的钥匙

Fendi club啤酒&#xff0c;一个代表着时尚与品味的品牌&#xff0c;如今进入了啤酒市场&#xff0c;推出了名为“Fendi club”的啤酒。这一创新的举措不仅展现了品牌的多元化发展&#xff0c;更为消费者提供了一种全新的时尚生活方式。 Fendi club啤酒不仅仅是一种产品&#x…

IPD集成产品开发:塑造企业未来竞争力的关键

随着市场竞争的日益激烈&#xff0c;企业对产品开发的要求也越来越高。如何在快速变化的市场环境中&#xff0c;既保证产品的批量生产效率&#xff0c;又满足客户的个性化需求&#xff0c;成为了企业面临的重要挑战。IPD&#xff08;集成产品开发&#xff09;模式&#xff0c;作…

HarmonyOS NEXT应用开发—投票动效实现案例

介绍 本示例介绍使用绘制组件中的Polygon组件配合使用显式动画以及borderRadius实现投票pk组件。 效果预览图 使用说明 加载完成后会有一个胶囊块被切割成两个等大的图形来作为投票的两个选项&#xff0c;中间由PK两字分隔开点击左边选项&#xff0c;两个图形会随着选择人数…

简单了解多线程

并发和并行 并发&#xff1a; 在同一时刻&#xff0c;多个指令在单一CPU上交替指向 并行&#xff1a;在同一时刻&#xff0c;多个指令在多个CPU上同时执行 2核4线程&#xff0c;4核8线程&#xff0c;8核16线程&#xff0c;16核32线程 基础实现线程的方式 Thread :继承类 &…

英伟达深夜放王炸|字节跳动游戏之路波折不断|文旅短剧风口将至|25岁QQ魅力不减,5亿人在用|云计算市场疯长152%|电商巨头齐瞄向富足悠闲银发族

新闻一分钟速览 文旅短剧风口将至&#xff0c;一地狂拍十部&#xff0c;影视界看法分歧&#xff0c;悬念丛生&#xff01;字节跳动游戏之路波折不断&#xff0c;能否逆风翻盘引关注。折叠屏手机痛症治愈&#xff0c;实力席卷高端市场&#xff0c;势头强劲&#xff01;雷军豪言…

框架篇常见面试题

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

1.IP复习课作业

1.IP复习课作业 1.为路由器各接口配置IP以及环回 R1 R2 R3 R4 R5 R6 2.配置dhcp为主机下发IP PC1 PC2 3.配置静态路由 R1 R2 R3 R4 R5 PC端通信 4.防止成环 R1 R2、4、5一样 5.修改优先级 R1 R2、3、4、5同样进行修改 6.均可访问R6环回 R5配置easy IP R1 ping R6环回 PC ping R…

微信小程序开发学习笔记——4.4常见的导航栏api接口

>>跟着b站up主“咸虾米_”学习微信小程序开发中&#xff0c;把学习记录存到这方便后续查找。 课程连接&#xff1a;https://www.bilibili.com/video/BV19G4y1K74d?p29&vd_source9b149469177ab5fdc47515e14cf3cf74 一、属性 界面 / 导航栏 / wx.showNavigationBar…

Java项目打包成Docker镜像

将项目打包成Docker镜像 将项目打包成Docker镜像的原因是可以在一台电脑的环境下模拟多台不同性能电脑响应高并发请求时候的表现。这里我们模拟半个CPU、一个CPU还有两个CPU的情况 在pom.xml文件中添加jib插件&#xff08;前提电脑安装了maven和Java 的 JDK才能成功完成编译&…

一般做策划的的,上哪儿找策划方案借鉴?

许多策划人担忧&#xff0c;借鉴他人的经验和方案会会削弱自己的创新能力和独立思考。 但是&#xff0c;实际上&#xff0c;借鉴他人的经验和方案可以为自己提供更多的灵感和创意&#xff0c;同时也可以提高策划的成功率。 这里推荐策划人必备的宝藏网站&#xff08;专治不会…

Linux系统学习总结(上)

B站大学地址&#xff1a;第二章-04-ls命令的参数和选项_哔哩哔哩_bilibili 操作系统概述 1、计算机是由硬件和软件两部分组成的 2、操作系统是软件的一类&#xff0c;主要作用是协助用户调度硬件工作&#xff0c;充当用户和计算机硬件之间的桥梁 3、常见的操作系统分为两类…

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

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

0基础 三个月掌握C语言(13)

数据在内存中的存储 整数在内存中的存储 在讲解操作符时 我们就已经学习了该部分的内容 这里我们回顾一下 整数的二进制表示方法有三种&#xff1a;原码 反码 补码 有符号的整数&#xff08;unsigned&#xff09; 三种表达方式均有符号位和数值位两部分 最高位的一位被当…

Tensorflow2.0笔记 - Himmelblau函数优化案例

本笔记记录Himmelblau函数优化案例代码&#xff0c;包括函数的图形绘制和梯度下降求解局部最优解的过程。 import tensorflow as tf import numpy as np from mpl_toolkits.mplot3d import Axes3D from matplotlib import pyplot as plt tf.__version__#Himmelblau函数 #https…

使用vitepress生成文档博客简单demo

先创建个空目录(就是你的项目) 安装vitepress 就是在你刚创建的目录里安装vitepress&#xff1a; npm add -D vitepress初始化项目 还是在你刚操作的目录里执行&#xff1a; npx vitepress init然后按照命令行的指引一步一步走就好了 注意VitePress的项目位置&#xff0c…

网站引用图片但它域名被墙了或者它有防盗链,我们想引用但又不能显示,本文附详细的解决方案非常简单!

最好的办法就是直接读取图片文件&#xff0c;用到php中一个常用的函数file_get_contents(图片地址)&#xff0c;意思是读取远程的一张图片&#xff0c;在输出就完事。非常简单&#xff5e;话不多说&#xff0c;直接上代码 <?php header("Content-type: image/jpeg&quo…

【FPGA】摄像头模块OV5640

本篇文章包含的内容 一、OV5640简介1.1 基本概述1.2 工作时序1.2.1 DVP Timing&#xff08;数据传输时序&#xff09;1.2.2 帧曝光工作模式 1.3 OV5640 闪光灯工作模式1.3.1 Xenon Flash&#xff08;氙灯闪烁&#xff09;模式1.3.2 LED 1&2 模式1.3.3 LED 3模式1.3.4 手动开…

● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇

● 647. 回文子串 1.dp数组含义。 之前的题目&#xff0c;差不多都是求什么就怎么定义dp数组&#xff0c;最后返回dp的最后一个元素。但是这里如果定义一维数组dp[i]是[0,i]范围的回文子串的个数的话&#xff0c;怎么根据dp[i-1]得到dp[i]&#xff1f;发现很难找到递归关系…