【Godot4.3】简单物理模拟之圆粒子碰撞检测

news2024/11/17 4:56:40

概述

最近开始研究游戏物理的内容,研究运动、速度、加速度之类的内容。也开始模仿一些简单的粒子模拟。这些都是一些基础、简单且古老的算法,但是对于理解游戏内的物理模拟很有帮助。甚至你可以在js、Python或者其他程序语言中实现它们。

图形的碰撞检测是第一个我想要实践的内容,而在碰撞检测中最简单的应该就是圆的碰撞检测了,本篇就简单实践一下圆的碰撞检测。

从圆开始

为什么,因为圆的圆心到其表面的距离是一样的。那么判断两个圆之间的重叠就非常简单,只要判断两个圆圆心之间的距离是否小于两者半径之和就可以了。如果是大小相同的粒子系统,每个圆的半径一样。

在这里插入图片描述

  • 重叠距离:等于两者半径之和-两圆心之间的距离。
  • 检测到重叠之后,将它们沿着圆形连线所在直线,沿着相反方向各自推动1/2的重叠距离,就可以将它们互相推开。
  • 当然这里没有考虑粒子各自的质量,默认将它们都是相同的质量,否则各自推开的距离应该是不一样的,比如小圆质量小应该推开更大的距离

测试

实现两个圆形粒子间的重叠检测和推开

extends Node2D

var particles:PackedVector2Array = Points2D.Vec2Arr("300,420 320,450")
var radius = 50.0
var color = Color.AQUA

func _draw() -> void:
	for i in range(particles.size()):
		draw_circle(particles[i],radius,color,false,1)

# 鼠标中键改变第二个圆的位置
func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_RIGHT:
			particles[1] = get_global_mouse_position()
			queue_redraw()

# 点击按钮执行重叠检测
func _on_button_pressed() -> void:
	test_overlap()

# 检测圆之间是否重叠
func test_overlap():
	var p1 = particles[0]  # 圆1
	var p2 = particles[1]  # 圆2
	var dis = p1.distance_to(p2)  # 距离
	var dir = p1.direction_to(p2) # 方向
	if dis < radius * 2:
		var over_dis = radius * 2 - dis
		particles[0] = particles[0] - dir  * over_dis/2.0 # 推开重叠距离的1/2
		particles[1] = particles[1] + dir  * over_dis/2.0 # 推开重叠距离的1/2
		queue_redraw()

运行效果:

点击“执行检测”按钮,如果两个圆之间的距离小于它们半径之和,表示有重叠,就会沿两者圆心连线方向将彼此推开重叠距离的1/2。推开后的效果:

这样,基于两个圆之间的重叠检测和推开功能已经实现。

动态检测

通过用鼠标动态控制两圆中的一个,并且将碰撞检测放到_process()中,就可以实现动态的碰撞检测。

extends Node2D

var particles:PackedVector2Array = Points2D.Vec2Arr("300,420 320,450")
var radius = 50.0
var color = Color.AQUA


func _process(delta: float) -> void:
	particles[1] = get_global_mouse_position()
	queue_redraw()
	test_overlap()

func _draw() -> void:
	for i in range(particles.size()):
		draw_circle(particles[i],radius,color,false,1)


# 检测圆之间是否重叠
func test_overlap():
	var p1 = particles[0]  # 圆1
	var p2 = particles[1]  # 圆2
	var dis = p1.distance_to(p2)  # 距离
	var dir = p1.direction_to(p2) # 方向
	if dis < radius * 2:
		var over_dis = radius * 2 - dis
		particles[0] = particles[0] - dir  * over_dis/2.0 # 推开重叠距离的1/2
		particles[1] = particles[1] + dir  * over_dis/2.0 # 推开重叠距离的1/2
		queue_redraw()

运行效果:

可以看到有一种用一个圆推动另一个圆的效果。

多粒子测试

在两个粒子时用PackedVector2Array是没有问题的,但是当粒子比较多时,最好还是使用一个简单的自定义类型来表示粒子。

这里我申明一个Particle类,表示简单的圆形粒子:

# 粒子类型
class Particle:
	var position:Vector2  # 位置
	var radius:float      # 半径
	
	func _init(position:Vector2,radius:float) -> void:
		self.position = position
		self.radius = radius

则测试代码可以改成:

extends Node2D

var particles:Array[Particle]
var radius = 50.0
var color = Color.AQUA
var max_count = 100   # 粒子数目

func _ready() -> void:
	set_process(false) # 禁用process
	var rect = get_viewport_rect()
	# 创建粒子
	for i in range(max_count):
		var pos = Vector2(randf_range(0,rect.size.x),randf_range(0,rect.size.y))
		var p = Particle.new(pos,radius)
		particles.append(p)

func _process(delta: float) -> void:
	for i in range(particles.size()):
		test_overlap_all(i)

func _draw() -> void:
	for i in range(particles.size()):
		draw_circle(particles[i].position,radius,color,false,1)


# 遍历检测所有的粒子
func test_overlap_all(idx:int):
	var p1 = particles[idx]
	for i in range(particles.size()):
		if i != idx:
			var p2 = particles[i]
			test_overlap(p1,p2)

# 检测圆之间是否重叠
func test_overlap(p1:Particle,p2:Particle):
	var dis = p1.position.distance_to(p2.position)  # 距离
	var dir = p1.position.direction_to(p2.position) # 方向
	var min_dis = p1.radius + p2.radius
	if dis < min_dis:
		var over_dis = min_dis - dis
		p1.position = p1.position - dir  * over_dis/2.0 # 推开重叠距离的1/2
		p2.position = p2.position + dir  * over_dis/2.0 # 推开重叠距离的1/2
		queue_redraw()

# 启用重叠检测
func _on_button_pressed() -> void:
	set_process(true)

这里:

  • 在运行时创建随机位置的100个半径为50像素的圆粒子,初始禁用_process和重叠检测
  • 点击“开启检测”按钮时,启用_process和重叠检测
  • 通过不断的遍历所有圆粒子和其他粒子,并进行重叠检测和推开操作,可以让所有粒子都不重叠

通过鼠标操纵其中的一个圆的位置,便可以实现动态的碰撞检测效果。

func _process(delta: float) -> void:
	particles[1].position = get_global_mouse_position()
	queue_redraw()
	for i in range(particles.size()):
		test_overlap_all(i)

运行效果:

总结

  • 本篇简述在Godot用CanvasItem绘图函数实现简单的圆粒子和元粒子的重叠检测与推开操作
  • 这是图形碰撞检测算法的第一篇,后续文章将讨论矩形包围盒的算法
  • 这个算法在粒子数目较多时有明显的延迟,后文将讨论优化算法

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

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

相关文章

Linux操作系统中SpringGateway

1、SpringGateway简介 核心功能有三个&#xff1a; 路由&#xff1a;用于设置转发地址的 断言&#xff1a;用来判断真实应该请求什么地址 过滤器&#xff1a;可以过滤地址和处理参数 1、什么是网关 网关是后台服务的统一入口&#xff0c;类似于平时网络里提到的网关。 2…

ppt压缩有什么简单方法?压缩PPT文件的几种方法

ppt压缩有什么简单方法&#xff1f;许多用户常常面临文件过大的问题&#xff0c;尤其在需要通过电子邮件发送或上传至网络平台时&#xff0c;大文件会带来诸多麻烦。此外&#xff0c;较大的文件可能导致软件响应缓慢&#xff0c;从而影响整体的演示体验。因此&#xff0c;寻找有…

ESP8266/01s模块烧录MQTT AT固件篇

&#xff08;代码完美实现&#xff09;stm32 新版 onenet mqtt物联网(保姆级教程) 地址&#xff1a; &#xff08;代码完美实现&#xff09;stm32 新版 onenet mqtt物联网(保姆级教程)https://blog.csdn.net/Wang2869902214/article/details/142501323 乐鑫ESP8266/安信可…

Python项目Flask框架整合Mysql

一、在配置类中编写Mysql配置信息 二、实现Mysql配置类 import pymysql from config.config import MYSQL_HOST, MYSQL_USER, MYSQL_PASSWD, MYSQL_PROT, MYSQL_DB, MYSQL_CHARSETclass MysqlDB():def __init__(self, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWD, MYSQL_PROT, MYS…

time命令:轻松测量Linux命令执行时间!

一、命令简介 用途&#xff1a; 用于测量 Linux 命令执行的时间&#xff0c;包括实际时间、用户 CPU 时间和系统 CPU 时间。刚开始以为是用来“看现在几点钟”的 &#x1f972;。标签&#xff1a; 实用工具&#xff0c;性能分析。 ‍ 二、命令参数 2.1 命令格式 time [选项…

COSCon'24 第九届中国开源年会议题征集正式启动

一年一度的开源盛会&#xff0c;COSCon24 第九届中国开源年会暨开源社十周年嘉年华将于2024年11月2-3日在中关村国家自主创新示范区会议中心举办。在为期2天的大会中&#xff0c;我们将为大家带来精彩纷呈的 Keynote 主题演讲&#xff08;上午&#xff09;&#xff0c;和百花齐…

【初阶数据结构】排序——选择排序

目录 前言选择排序堆排序 前言 对于常见的排序算法有以下几种&#xff1a; 下面这节我们来看选择排序算法。 选择排序 基本思想&#xff1a;   每一次从待排序的数据元素中遍历选出最大&#xff08;或最小&#xff09;的元素放在序列的起始位置&#xff0c;直到全部待排序…

2024前端技术发展概况

当前前端技术呈现出多方面的发展态势&#xff0c;以下是详细介绍&#xff1a; 前端框架不断演进&#xff1a; React&#xff1a;作为流行的前端框架之一&#xff0c;React 依旧保持着强大的生命力。它具有高效的虚拟 DOM 机制&#xff0c;能够快速更新和渲染页面&#xff0c;极…

如何创建一个docker,给它命名,且下次重新打开它

1.创建一个新的docker并同时命名 docker run -it --name one ubuntu:18.04 /bin/bash 这时候我们已经创建了一个docker,并且命名为"one" 2.关闭当前docker exit 3.这时docker已经终止了&#xff0c;我们需要使用它要重新启动 docker start one 4.现在可以重新打…

多线程篇八

多线程篇八 如笔者理解有误欢迎指正交流&#x1f338;&#x1f338;&#x1f338; 线程池 什么是线程池&#xff1f; 顾名思义&#xff0c;线程池是一个存放了很多线程的池子.既然有很多线程&#xff0c;那一定很方便调用对吧&#xff0c;有很多线程那大家一定喜欢一起玩吧&…

【计算机网络】Tcp报文的组成,Tcp是如何实现可靠传输的?

Tcp的报文组成 TCP&#xff08;传输控制协议&#xff09;是计算机网络中一种重要的传输协议&#xff0c;其报文组成包括多个字段&#xff0c;每个字段具有特定的含义。以下是TCP报文头的主要组成部分&#xff1a; 源端口号&#xff08;Source Port&#xff09;&#xff1a;占用…

c语言中例题:打印出杨辉三角

杨辉三角是一个经典的数学模型 从顶部的单个1开始&#xff0c;下面每一行的数字都是其正上方的两个数之和 每行数字左右对称&#xff0c;且由1开始逐渐变大 1 1 1 1 2 1 1 3 3 1 由以上规律可以看出arr[i][j] arr[i-1][j] ar…

Android使用RecyclerView仿美团分类界面

RecyclerView目前来说对大家可能不陌生了。由于在公司的项目中&#xff0c;我们一直用的listview和gridview。某天产品设计仿照美团的分类界面设计了一个界面&#xff0c;我发现用gridview不能实现这样的效果&#xff0c;所以就想到了RecyclerView&#xff0c;确实是一个很好的…

对话总结:Scale AI的创始人兼CEO Alex Wang

AI的三大支柱 计算:主要由大公司如NVIDIA推动。算法:顶尖实验室如OpenAI主导。数据:Scale致力于推动数据进展。前沿数据的重要性 与人类智能相比较,前沿数据是AI发展的关键。互联网数据是机器与人类合作的结果。语言模型的发展 第一阶段:原始的Transformer论文和GPT的小规…

PHP爬虫淘宝商品SKU详细信息获取指南

在电子商务领域&#xff0c;获取商品的SKU&#xff08;Stock Keeping Unit&#xff0c;库存单位&#xff09;详细信息对于商家进行库存管理、订单处理和客户服务至关重要。淘宝作为中国最大的电商平台之一&#xff0c;提供了丰富的API接口&#xff0c;使得开发者能够通过PHP爬虫…

AI在教育行业应用的启发和未来的方向

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 shelly已经给大家分享了很多AI的工具&#…

ThinkPHP一对多的关联模型运用

一、序言 最近在写ThinkPHP关联模型的时候一些用法总忘&#xff0c;我就想通过写博客的方式复习和整理下一些用法。 具体版本&#xff1a; topthink/framework&#xff1a;6.1.4topthink/think-orm&#xff1a;2.0.61 二、实例应用 1、一对多的关联 本文案例&#xff1a;一个用…

MySQL - 单表查询

DQL (数据查询语言)是用来查询数据库表中的记录的操作。在实际的业务系统中&#xff0c;查询操作的频率远远高于增删改。常见的查询操作包括条件查询、排序、分组等。 1. DQL 语法 SELECT 字段列表 FROM 表名列表 [WHERE 条件列表] [GROUP BY 分组字段] [HAVING 分组后条件]…

玩转图像处理:Python与OpenCV实现高效绿幕背景替换

文章目录 前言色度抠图技术&#xff08;Chroma Keying&#xff09;基本原理 数据准备代码实现性能分析代码优化优化后的速度 前言 现阶段绿幕抠图有很多种方式&#xff0c;比如色度抠图&#xff08;Chroma Keying&#xff09;、亮度抠图&#xff08;Luma Keying&#xff09;、色…

探索Python网络世界的利器:Requests-HTML库

文章目录 探索Python网络世界的利器&#xff1a;Requests-HTML库背景&#xff1a;为何选择Requests-HTML&#xff1f;什么是Requests-HTML&#xff1f;如何安装Requests-HTML&#xff1f;5个简单库函数的使用方法3个场景下库的使用示例常见Bug及解决方案总结 探索Python网络世界…