【Godot4.2】2D导航04 - TileMap导航的逻辑

基于NavigationRegion2D

我们基于NavigationRegion2D的逻辑一文的场景结构,但是将NavigationRegion2D删除,更改为TileMap节点。
image.png
为TileMap创建Tileset,并创建一个导航层。在TileSet面板中,为草地和黄色泥土地面图块绘制可通行区域(整个矩形)。这样做的含义是只有这连个图块允许通行,其余图块全是障碍物。
image.pngimage.png
切换至TileMap面板,利用矩形和直线绘制方式绘制一个简单的有出口的地图。
image.png
运行场景,会发现基于NavigationAgent2D的导航在TileMap上依旧是可行的。
TileMap导航.mp4 (25.9MB)## 基于AStarGrid2D
可以看出基于NavigationRegion2D的导航总还是有些不尽如人意的地方,偶尔就卡在了半路上。
AStarGrid2D本身基于网格,那么它与TileMap组合可以说是“天作之合”。
删除Player的NavigationRegion2D以及脚本。
image.pngimage.png
查看icon.svg可以发现其图片大小为128×128,而我们的tileset的cell_size为16×16,所以为了将玩家显示在一个网格里,我们需要将icon.svg缩放为16×16。
128/16=8,所以我们需要将其设为原来的1/8,也就是缩小到原来的0.125倍。相应调整碰撞形状的大小。
image.pngimage.png
移动玩家到某个单元格内。
image.png
将world2的脚本改成如下:

# world2.gd
extends Node2D

@onready var player = $Player
@onready var tile_map = $TileMap
var astar_grid = AStarGrid2D.new()
var move_speed = 200.0
var path:PackedVector2Array
var solids:PackedVector2Array

func _ready():
	# 获取tile_map包含所有已绘制图块的矩形
	var rect = tile_map.get_used_rect()
	# 构建AStarGrid2D
	astar_grid.size = rect.size
	astar_grid.cell_size = tile_map.tile_set.tile_size
	astar_grid.offset = astar_grid.cell_size/2
	astar_grid.update()
	# 获取所有已经绘制的图块的数组
	var cells = tile_map.get_used_cells(0)
	for cell in cells:
    	# TileData包含图块的信息
		var data:TileData = tile_map.get_cell_tile_data(0,cell)
		if !data.get_navigation_polygon(0): # 如果图块没有设置导航
			solids.append(cell)
			astar_grid.set_point_solid(cell,true) # 设为障碍物

# 左键点击,获取导航目标位置
func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
			# TileMaplocal_to_map()用于将屏幕坐标转化为TileMap的网格坐标
			var p1 = tile_map.local_to_map(player.position)
			var p2 = tile_map.local_to_map(get_global_mouse_position())
			path = astar_grid.get_point_path(p1,p2)
			queue_redraw()

# 实现沿着路径行走
func _process(delta):
	if path.size() > 0:
		var target_pos = path[0]
		if target_pos.distance_to(player.position)>2:
			player.velocity = player.position.direction_to(target_pos) * move_speed
			player.move_and_slide()
		else:
			path.remove_at(0)
		queue_redraw()

# 绘制路径信息
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
	
	# 绘制路径和其上的点
	if path.size() > 0:
		for pot in path:
			draw_circle(pot,5,Color.YELLOW)
				
		draw_polyline(path,Color.YELLOW,2)

开启显示碰撞区域和导航。
image.png
运行后的效果如下:
2023-06-11_22-40-24.mp4 (5.06MB)基本的导航还是可以的。
:::success
提示
默认由于TileMap是world2的子节点,所以world2上用_draw绘制的内容会被TileMap绘制的地图覆盖而无法显示。解决方法是将TileMap的z_index设为-1。
image.pngimage.png
:::

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巽星石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值