当前位置: 首页 > news >正文

【Godot4.3】斜抛运动轨迹曲线点求取函数

概述

原文写于去年9月。一篇测试性的文章。

基于初始位置和初始速度的抛物线

# 抛物运动轨迹曲线 - 基于初始位置和初始速度计算
func projectile_motion_curve(
	start_pos:Vector2,            # 物体的起始位置
	velocity:Vector2,             # 初始速度
	nums:int,                     # 取点的个数
	delta:=1.0,                   # 时间间隔,越小曲线越平滑
	g = 9.8                       # 重力加速度
) -> PackedVector2Array:
	var points:PackedVector2Array
	
	var vx0 = Vector2.RIGHT * velocity.x # x轴方向的初始速度
	var vy0 = Vector2.DOWN * velocity.y  # y轴方向的初始速度
	
	var pos = start_pos
	var v = velocity
	# 计算轨迹点
	for t in range(nums):
		var v1 = vx0 * t * delta
		var v2 = vy0 * t * delta +  Vector2.DOWN * (0.5 * g * pow(t * delta,2))
		v = v1 + v2
		pos = start_pos + v
		points.append(pos)
	return points

测试

# 抛物运动曲线测试
extends Node2D


## 曲线和点颜色
@export var color:=Color.AQUA

var force = 50.0                   # 力的大小
var start_pos := Vector2(100,100)  # 物体起始位置
var velocity = Vector2()           # 初始的速度
var nums:int = 20                  # 取点的个数
var delta:=1.0                     # 时间间隔,越小曲线越平滑
var g = 9.8                        # 重力加速度


func _process(delta: float) -> void:
	velocity = start_pos.direction_to(get_global_mouse_position()) * force
	queue_redraw()


func _draw() -> void:
	var curve = projectile_motion_curve(start_pos,velocity,nums,delta,g)
	draw_polyline(curve,color,1)
	for p in curve:
		draw_circle(p,3,color)
	pass
  • 曲线点的个数由nums参数控制
  • 单位时间间隔由delta参数控制,越小,点之间的距离越小,绘制曲线后越平滑

delta= 1.0,nums=20
delta= 0.1,nums=200

基于指定两点的抛物线

也就是知道抛出点和目标点的抛物线。

# 抛物线轨迹 - 基于初始位置和目标位置
func projectile_motion_curve2(
	start_pos:Vector2,            # 物体的起始位置
	target_pos:Vector2,           # 目标位置
	delta:=1.0,                   # 时间间隔,越小曲线越平滑
	g = 9.8                       # 重力加速度
) -> PackedVector2Array:
	var points:PackedVector2Array
	
	var d = target_pos - start_pos # 位移向量
	
	var t2:float = sqrt((2 * d.y) / g)
	#print(t)
	var velocity = Vector2.UP * 0 + Vector2.RIGHT * (d.x / t2)
	
	var vx0 = Vector2.RIGHT * velocity.x # x轴方向的初始速度
	var vy0 = Vector2.DOWN * velocity.y  # y轴方向的初始速度
	
	var pos = start_pos
	var v = velocity
	# 计算轨迹点
	for t in range(t2/delta):
		var v1 = vx0 * t * delta
		var v2 = vy0 * t * delta +  Vector2.DOWN * (0.5 * g * pow(t * delta,2))
		v = v2 + v1
		pos = start_pos + v
		points.append(pos)
	if points.size() >0:
		if target_pos.distance_to(points[points.size()-1]) > 0.0:
			points.append(target_pos)
	return points

测试

# 抛物运动曲线测试
extends Node2D


## 曲线和点颜色
@export var color:=Color.AQUA

var force = 50.0                   # 力的大小
var start_pos := Vector2(100,100)  # 物体起始位置
var target_pos:Vector2             # 目标位置
var delta:=1.0                     # 时间间隔,越小曲线越平滑
var g = 9.8                        # 重力加速度


func _process(delta: float) -> void:
	target_pos = get_global_mouse_position()
	queue_redraw()


func _draw() -> void:
	var curve = projectile_motion_curve2(start_pos,target_pos,delta,g)
	draw_polyline(curve,color,1)
	for p in curve:
		draw_circle(p,3,color)
	pass

delta= 1.0
delta= 0.1

改进,加入一定的抬高

其中: t = 2 ( 2 k + d y ) g t=\sqrt{\frac{2(2k+dy)}{g}} t=g2(2k+dy) 那么最高点的速度: ∣ v k ∣ = d x t |v_k|= \frac{d_{x}}{t} vk=tdx

又因为: t k = 2 k g t_k=\sqrt{\frac{2k}{g}} tk=g2k 所以 ∣ v k y ∣ = g ⋅ t k |v_{ky}|=g\cdot t_k vky=gtk

所以初始速度: v 0 = v k y + v k v_{0}=v_{ky} + v_{k} v0=vky+vk

当目标点的纵坐标在起始点的上方时:

其中: t = 2 ( 2 k + d y ) g t=\sqrt{\frac{2(2k+dy)}{g}} t=g2(2k+dy) 最高点的速度 ∣ v k ∣ = d x t |v_k|= \frac{d_{x}}{t} vk=tdx还是保持不变。

但是: ∣ v k y ∣ = g ⋅ t ( k + d y ) |v_{ky}|=g \cdot t_{(k+dy)} vky=gt(k+dy) t ( k + d y ) = 2 ( k + d y ) g t_{(k+dy)}=\sqrt{\frac{2(k+dy)}{g}} t(k+dy)=g2(k+dy)

# 抛物线轨迹 - 基于初始位置和目标位置 加入一定的抬高距离k
func projectile_motion_curve3(
	start_pos:Vector2,            # 物体的起始位置
	target_pos:Vector2,           # 目标位置
	k:=50.0,                      # 抬高距离
	delta:=1.0,                   # 时间间隔,越小曲线越平滑
	g = 9.8                       # 重力加速度
) -> PackedVector2Array:
	var points:PackedVector2Array
	
	var d = target_pos - start_pos # 位移向量
	
	# 到目标位置的总时长
	var t2:float
	# 走距离k的时间
	var t1:float
	# 走距离k的时间
	var t3:float
	
	var vx0   # x轴方向的初始速度
	var vy0   # y轴方向的初始速度
	
	
	if target_pos.y < start_pos.y:
		t2 = sqrt(2.0 * (2.0 * k + abs(d.y)) / float(g))
		t3 = sqrt(2.0 * (k + abs(d.y)) / float(g))
	
		vy0 = Vector2.UP * (g * t3)
	else:
		t2 = sqrt(2.0 * (2.0 * k + d.y) / float(g))
		t1 = sqrt((2.0 * k)/ float(g))
		
		vy0 = Vector2.UP * (g * t1)
	vx0 = Vector2.RIGHT * (d.x/float(t2))
	
	
	# 初速度
	var velocity = vx0 + vy0
	
	
	var pos = start_pos
	var v = velocity
	# 计算轨迹点
	for t in range(t2/delta):
		var v1 = vx0 * t * delta
		var v2 = vy0 * t * delta +  Vector2.DOWN * (0.5 * g * pow(t * delta,2))
		v = v2 + v1
		pos = start_pos + v
		points.append(pos)
	if points.size() >0:
		if target_pos.distance_to(points[points.size()-1]) > 0.0:
			points.append(target_pos)
	return points

测试:


可以看到,鼠标位置在起始点上方时,也可以显示曲线,但是不是太精确。

相关文章:

  • 时间序列模型(1):LSTNet
  • 解决ubuntu(jetpack)系统下系统盘存储不够的
  • MongoDB备份与还原
  • 2025年第十届数维杯大学生数学建模挑战赛参赛规则
  • Windows根据文件名批量在文件夹里查找文件并复制出来,用WPF实现的详细步骤
  • 29.代码随想录算法训练营第二十九天|134. 加油站,135. 分发糖果,860. 柠檬水找零,406. 根据身高重建队列
  • [rust] rust学习
  • 【C语言系列】字符函数和字符串函数
  • QT:串口上位机
  • 电脑神器,轻松超越系统自带!
  • 【免费】2006-2020年各省单位GDP能耗增速数据
  • 每日学习之一万个为什么
  • MySQL的 where 1=1会不会影响性能?
  • Stable Diffusion/DALL-E 3图像生成优化策略
  • Linux:自动化构建-make/Makefile
  • 软件开发项目有哪些风险
  • Redis Sentinel (哨兵模式)深度解析:构建高可用分布式缓存系统的核心机制
  • 【大模型学习】第十七章 预训练技术综述
  • [翱捷]功能机 Wifi
  • Pygame实现射击鸭子游戏3-2
  • 飙升至熔断,巴基斯坦股市两大股指收盘涨逾9%
  • 《新时代的中国国家安全》白皮书(全文)
  • 火车站员工迟到,致出站门未及时开启乘客被困?铁路部门致歉
  • 女高音吴睿睿“古词新唱”,穿着汉服唱唐诗宋词
  • 老镇老宅楼:破旧,没产证,要不要更新?
  • 年轻小将绽放光芒!中国短跑男女接力队直通东京世锦赛