Godot插值、贝塞尔曲线和Astar寻路

一、插值

线性插值是采用一次多项式上进行的插值计算,任意给定两个值A和B,那么在A和B之间的任意值可以定义为:P(t) = A * (1 - t) + B * t,0 <= t <= 1。

数学中用于线性拟合,游戏应用可以做出跟随效果(宠物跟随、npc跟随)

java 复制代码
const FOLLOW_SPEED = 4.0

func _physics_process(delta):
	var mouse_pos = get_local_mouse_position()

	$Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, delta * FOLLOW_SPEED)

二、贝塞尔

贝塞尔是插值的应用之一。贝塞尔曲线是为工业设计,是图形软件行业中的流行工具。不过在游戏中会出现曲线扭曲的情况,应用并不好。

1.二次贝塞尔:

我们首先使用 0 到 1 之间的值,在两个线段的每个顶点上逐步插值。当我们把 t 值从 0 变成 1 时,就得到了两个沿着线段移动的点。然后,我们插值 q0 和 q1,以获得沿着曲线移动的单点 r。

java 复制代码
func _quadratic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, t: float):
	var q0 = p0.lerp(p1, t)
	var q1 = p1.lerp(p2, t)
    var r = q0.lerp(q1, t)
    return r

2.三次贝塞尔

同理三个线段的时候称为三次贝塞尔曲线。

java 复制代码
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float):
	var q0 = p0.lerp(p1, t)
	var q1 = p1.lerp(p2, t)
	var q2 = p2.lerp(p3, t)
	var r0 = q0.lerp(q1, t)
	var r1 = q1.lerp(q2, t)
	var s = r0.lerp(r1, t)
	return s

三、Astar寻路

Astar算法是最广泛应用的寻路算法,它的特点是基于网格,而且可以快速的求解某个点到另一个点的最短有效路径。Godot种提供了算法的封装类可以直接使用。2D版本是AStar2D、AStarGrid2D。

1.思路

添加可以到达的位置

将可以行走的点两两连接,形成路径

通过其方法直接求取某个位置到目标位置的最短路径

让玩家或其他角色按照路径上点的顺序依次前进,直到到达目标位置

java 复制代码
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]

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

你也可以用get_point_path()方法直接获取两个点之间的最短路径,返回的额是包含所有经过的点数组。

2.应用

在Tilemap挂载方法(版本4.2.1):

java 复制代码
extends TileMap

@onready var astar_node: AStar2D = AStar2D.new()

var map_size: Vector2i = get_used_rect().size

func _ready():
	# 遍历所有层,将可以寻路的tile加入Astar图的节点
	for layer in range(get_layers_count()):
		var cells = get_used_cells(layer)
		for cell in cells:
			var tileData = get_cell_tile_data(layer, cell)
			var nav = tileData.get_navigation_polygon(0)
			if nav == null:
				continue
			var point_index = calculate_point_index(cell)
			astar_node.add_point(point_index, Vector2(cell.x, cell.y))
			
	# 移除有碰撞体的点
	for layer in range(get_layers_count()):
		var cells = get_used_cells(layer)
		for cell in cells:
			var tileData = get_cell_tile_data(layer, cell)
			var collision = tileData.get_collision_polygons_count(0)
			if collision <= 0:
				continue
			var point_index = calculate_point_index(cell)
			if astar_node.has_point(point_index):
				astar_node.remove_point(point_index)
				
	# 连接图的节点
	for id in astar_node.get_point_ids():
		var cellPosition = Vector2i(astar_node.get_point_position(id))
		var relativeCells: Array[Vector2i] = [
			cellPosition + Vector2i.RIGHT,
			cellPosition + Vector2i.LEFT,
			cellPosition + Vector2i.DOWN,
			cellPosition + Vector2i.UP,			
		]
		for relativeCell in relativeCells:
			var relativeCellIndex = calculate_point_index(relativeCell)
			if is_outside_map_bounds(relativeCell):
				continue
			if astar_node.has_point(relativeCellIndex):
				astar_node.connect_points(id, relativeCellIndex, false)
				
func calculate_point_index(point: Vector2i) -> int:
	return point.x + point.y * map_size.x

func is_outside_map_bounds(point: Vector2i) -> bool:
	return point.x <0 || point.y < 0 || point.x >= map_size.x || point.y >= map_size.y
	
func get_nav_path(startCellPosition: Vector2i, endCellPosition: Vector2i) -> PackedVector2Array:
	var navCellPath = astar_node.get_point_path(calculate_point_index(startCellPosition), calculate_point_index(endCellPosition))
	var localPath = PackedVector2Array()
	for cellPosition in navCellPath:
		localPath.push_back(map_to_local(Vector2i(cellPosition)))
	return localPath
相关推荐
zhchyun20086 小时前
【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(05)
ui·unity·游戏引擎
_ZHOURUI_H_10 小时前
不做完整 ECS,只优化数据布局:Unity EasyECS 到底是什么
unity·性能优化·游戏引擎
郝学胜-神的一滴1 天前
Horse3D 游戏引擎研发笔记(七):Clydesdale——从流式日志到多输出订阅
c++·qt·unity·游戏引擎·图形渲染·unreal engine·opengl
江上闲人.2 天前
Wardogs战犬\战狗Beta测试启动报错UE崩溃卡顿?解决方法来了
游戏·游戏引擎·虚幻·战犬·战狗·wardogs
杨丰玮4182 天前
从零手写Java飞机躲障碍游戏|Swing绘图、鼠标跟随、计时器碰撞检测实战(五)
java·python·游戏·游戏引擎·图形渲染·动画·贴图
鼎艺创新科技3 天前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
huihui3613 天前
校友网管理软件技术选型框架:基于功能核验与系统架构的量化评估
unity·系统架构·游戏引擎
五仁烧饼3 天前
Unity性能优化系列设置篇 - URP 移动端设置基线与分档策略
unity·游戏引擎
新手unity自用笔记3 天前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎