【Godot4.3】基于中心点连线的矩形重叠检测

概述

这个方法是我自己想到的,经典的矩形重叠(碰撞)检测,是一段很复杂的逻辑判断,而根据两个矩形中点连线,与两个矩形宽度和高度之和一半的比较,就可以判断两个矩形是否重叠,并且能够计算出重叠向量。

  • 通过给两个矩形施加反向的一半重叠向量,可以将两个矩形"推开"。
  • 通过用鼠标自由移动的矩形,可以使用给原本静止的矩形施加重叠向量,从而推动它

真实的物理碰撞是要考虑两个物体的质量和速度的,本文和ShapeTest所研究的只是几何上的重叠和重叠部分的向量求取。

基本原理

将两矩形中心进行连线:

  • 则横向距离 d w = ∣ c 2 − c 1 ∣ cos ⁡ θ = ( c 2 − c 1 ) . x d_w = |c2-c1|\cos \theta = (c2-c1).x dw=∣c2−c1∣cosθ=(c2−c1).x,纵向距离 d h = ∣ c 2 − c 1 ∣ sin ⁡ θ = ( c 2 − c 1 ) . y d_h = |c2-c1|\sin \theta = (c2-c1).y dh=∣c2−c1∣sinθ=(c2−c1).y
  • 如果 d w < w 1 + w 2 2 d_w<\frac{w_1+w_2}{2} dw<2w1+w2且 d h < h 1 + h 2 2 d_h<\frac{h_1+h_2}{2} dh<2h1+h2说明两个矩形发生了重叠。
  • 重叠的距离: o w = w 1 + w 2 2 − d w o_w=\frac{w_1+w_2}{2} - d_w ow=2w1+w2−dw, o h = h 1 + h 2 2 − d h o_h = \frac{h_1+h_2}{2} - d_h oh=2h1+h2−dh

代码实现

swift 复制代码
# 获取重叠部分的向量
func get_overlap(rect1:Rect2,rect2:Rect2) -> Vector2:
	var overlap:= Vector2()
	
	var c1:Vector2 = rect1.get_center()
	var c2:Vector2 = rect2.get_center()
	var vec12:Vector2 = c2-c1
	
	var half_size = (rect1.size + rect2.size)/2.0
	
	var dw = abs(vec12.x)
	var dh = abs(vec12.y)
	
	if dw < half_size.x and dh < half_size.y:
		overlap.x = (half_size.x - dw)
		overlap.y = (half_size.y - dh)
	return overlap

测试代码

swift 复制代码
extends Node2D

var rect1 = Rect2(300,300,100,60)
var rect2 = Rect2(400,400,100,60)


func _process(delta: float) -> void:
	rect2.position = get_global_mouse_position()
	var ove = get_overlap(rect1,rect2)
	var d_pos = rect2.position - rect1.position
	if ove.x >= ove.y:
		rect1.position -= Vector2(0,ove.y) * sign(d_pos.y)
	else:
		rect1.position -= Vector2(ove.x,0) * sign(d_pos.x)
	queue_redraw()

func _draw() -> void:
	draw_rect(rect1,Color.AQUAMARINE,false,1)
	draw_rect(rect2,Color.AQUAMARINE,false,1)
	
	var c1 = rect1.get_center()
	var c2 = rect2.get_center()

效果:

推动按钮

将矩形换为两个按钮控件:

测试代码:

swift 复制代码
extends Node2D

@onready var button1: Button = $Button1
@onready var button2: Button = $Button2


func _process(delta: float) -> void:
	button2.position = get_global_mouse_position()
	
	var ove = get_overlap(button1.get_rect(),button2.get_rect())
	var d_pos = button2.position - button1.position
	if ove.x >= ove.y:
		button1.position -= Vector2(0,ove.y) * sign(d_pos.y)
	else:
		button1.position -= Vector2(ove.x,0) * sign(d_pos.x)

测试效果:

其实,你可以将按钮替换为任意的控件或容器。

相关推荐
三巧8 小时前
Godot 敌人生成半径和围墙不匹配,导致敌人错误的生成在围墙外的解决代码
游戏引擎·godot
技术小甜甜8 小时前
【Godot引擎】如何使用内置的全局搜索功能提升开发效率
游戏引擎·godot
技术小甜甜8 小时前
【Godot】如何导出 Release 版本的安卓项目
android·游戏引擎·godot
CApp4 天前
GODOT引擎学习日志
学习·游戏引擎·godot
技术小甜甜8 天前
[Godot][游戏开发] 如何在 Godot 中配置 Android 环境(适配新版 Android Studio)
android·android studio·godot
三巧11 天前
Godot的RichTextLabel富文本标签,鼠标拖拽滚动,方向键滚动,底部吸附,自动滚动
游戏引擎·godot
夏有凉风,冬有雪11 天前
AI 制作游戏美术素材流程分享(程序员方向粗糙版)
人工智能·godot·游戏美术
gis分享者23 天前
学习threejs,使用Physijs物理引擎,通过控制重力,实现多米诺骨牌效果
threejs·碰撞·物理·physijs·physi·多米诺
Amctwd1 个月前
【Godot】生命周期详解:从节点诞生到销毁的全流程解析
服务器·godot
Tandy12356_1 个月前
Godot开发2D冒险游戏——第三节:游戏地图绘制
游戏引擎·godot