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

news2024/11/16 7:22:45

一、插值

线性插值是采用一次多项式上进行的插值计算,任意给定两个值A和B,那么在A和B之间的任意值可以定义为:P(t) = A * (1 - t) + B * t,0 <= t <= 1。
数学中用于线性拟合,游戏应用可以做出跟随效果(宠物跟随、npc跟随)

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。

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.三次贝塞尔

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

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.思路

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

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):

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

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

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

相关文章

揭开“栈和队列”的神秘面纱

前言 在线性表中不止有顺序表和链表&#xff0c;今天的主角就如标题所说--->认识栈和队列。把他们俩放一起总结是有原因的&#xff0c;还请看官听我娓娓道来~ 什么是栈&#xff1f; 栈&#xff08;stack&#xff09;是限定仅在表尾进行插入和删除操作的线性表 咱可以把栈理…

书生·浦语大模型实战营之茴香豆:搭建你的 RAG 智能助理

书生浦语大模型实战营之茴香豆&#xff1a;搭建你的 RAG 智能助理 RAG&#xff08;Retrieval Augmented Generation&#xff09;技术&#xff0c;通过检索与用户输入相关的信息&#xff0c;并结合外部知识库来生成更准确、更丰富的回答。解决 LLMs 在处理知识密集型任务时可能遇…

Redis中的Sentinel(五)

Sentinel 检测主观下线状态 在默认情况下&#xff0c;Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他Sentinel在内) 发送PING命令&#xff0c;并通过实例返回的PING命令回复来判断实例是否在线。如图所示&#xff0c;带箭头的连线显…

CAS单点登录简介

1、传统cookie认证 通常在登录的时候&#xff0c;前端将用户名和密码传送给后端&#xff0c;然后后端将加密后的认证字符串设置成cookie&#xff0c;在以后的每次请求中&#xff0c;都会将cookie发过去&#xff0c;再解密校验请求者的信息&#xff0c;或者进行一系列的鉴权。 这…

【C++ STL容器适配器】stack 栈

文章目录 【 1. 基本原理 】【 2. stack 的创建 】2.1 创建一个空的的 stack 适配器&#xff0c;并采用默认的 deque 基础容器2.2 指定其他序列式容器2.3 通过基础容器初始化 stack2.4 通过一个 stack 初始化另一个 stack 【 3. stack 支持的成员函数 】 【 1. 基本原理 】 st…

实测STM32的RTC,什么校准都不做,不断电,半年后快了13分钟

【测试结果】 TOOL的RTC时钟一直都是通过上位机这里手动校准的&#xff0c;这次做了了实验&#xff0c;测试期间不做任何校准&#xff0c;看看半年后效果。 测试是从去年的9月29号开始 截至到今年的4月5号&#xff0c;快了13分钟 【误差原因】 因为晶振对温度敏感&#xff0…

windows 系统下 mysql 数据库的下载与安装(包括升级安装)

windows 系统下 mysql 数据库的下载与安装&#xff08;包括升级安装&#xff09; 一、mysql 介绍&#xff1a; MySQL 是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。 MySQL 是最流行的关系型数据库管理系统之一&#xf…

算法 第34天 贪心3

1005 K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数组 可能…

Unity Meta Quest MR 开发(五):空间锚点

文章目录 &#x1f4d5;教程说明 此教程相关的详细教案&#xff0c;文档&#xff0c;思维导图和工程文件会放入 Spatial XR 社区。这是一个高质量 XR 开发者社区&#xff0c;博主目前在内担任 XR 开发的讲师。该社区提供专人答疑、完整进阶教程、从零到一项目孵化保姆服务&…

华为海思2024春招数字芯片岗机试题(共9套)

huawei海思2024春招数字芯片岗机试题(共9套&#xff09;&#xff08;WX:didadidadidida313&#xff0c;加我备注&#xff1a;CSDN huawei数字题目&#xff0c;谢绝白嫖哈&#xff09; 题目包含数字集成电路、System Verilog、Verilog2001、半导体制造技术、高级ASIC芯片综合、…

微信小程序使用自己的布局

我第一天学习微信小程序&#xff0c;照着黑马程序员老师的操作模仿编辑。因为视频是23年的&#xff0c;我24年4月份学习发现很多地方不一样了。 新版微信开发者工具中没有自带wxss文件。我自己建了一个list.wxss文件&#xff0c;发现用不了&#xff0c;在list.wxml文件中编写v…

安卓java打包uniapp原生插件 和 uniapp使用安卓android原生插件

1.uniapp dcloud官方文档 简介 | uni小程序SDK 2.前提&#xff0c;需要有经验的安卓java开发人员&#xff0c;并且同时具备uniapp移动端开发经验。说明&#xff1a;android打包的.aar和uniapp需要的.aar是不一样的&#xff0c;uniapp需要的.aar是需要有一些特定配置的&#x…

vue结合Elempent-Plus/UI穿梭框更改宽度以及悬浮文本显示

由于分辨率不同会导致文本内容显示不全&#xff0c;如下所示&#xff1a; 因此需要 1、悬浮到对应行上出现悬浮信息 实现代码如下所示&#xff1a; 这里只演示Vue3版本代码&#xff0c;Vue2版本不再演示 区别就在插槽使用上Vue3使用&#xff1a;#default“”&#xff1b;Vu…

阿里云服务器租赁一年收费标准

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

C#基础:类,对象,类成员简介(第四节课)

本节内容&#xff1a; 类与对象的关系 什么时候叫“对象”&#xff0c;什么时候叫实例引用变量与实例的关系 类的三大成员 属性方法事件 类的静态成员与实例成员 关于“绑定” 1.什么是类&#xff1a;&#xff08;再详细一点&#xff09; 类是对现实世界事物进行抽象所…

蓝桥杯练习系统(算法训练)ALGO-959 P0705 集合运算

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 输入两个整数集合A、B&#xff0c;求出他们的交集、并集以及B在A中的余集。交集、并集和余集的计算都要求写成一个单独的函数。   输…

VMware虚拟机(Rocky9.3)硬盘扩容详细图文教程

参考<<鸟哥的Linux>>以及VMware虚拟机硬盘扩容详细图文教程 原因: 用户空间不足,且系统是用LVM&#xff08;logical volume manager&#xff09;进行分区 df -h #查看/home目录下磁盘容量不足磁盘扩容步骤 关闭虚拟机,选择编辑虚拟机, 点击硬盘,再点击扩容 这个…

2024年租用阿里云服务器多少钱一年?连夜整理分享

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

代码随想录第32天|455.分发饼干 376. 摆动序列

理论基础 贪心算法核心&#xff1a;选择每一阶段的局部最优&#xff0c;从而达到全局最优。 455.分发饼干 455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09;代码随想录 (programmercarl.com)455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 贪心算法理论基础&am…

Spring之ApplicationListener实现监听原理

文章目录 ApplicationListener使用方式ApplicationListener实现原理1.引入并实例化时机2.作用时机3.发布事件&#xff0c;生效 总结 ApplicationListener使用方式 package com.cyl.listener;import org.springframework.context.ApplicationEvent; import org.springframework…