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

测试效果:

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

相关推荐
代码盗圣15 天前
GODOT 4 不用scons编译cpp扩展的方法
游戏引擎·godot
知兀1 个月前
单例模式(自动加载)
笔记·游戏引擎·godot
知兀1 个月前
Godot中的信号
笔记·游戏引擎·godot
知兀1 个月前
【godot游戏引擎学习笔记】初识界面
笔记·游戏引擎·godot
知兀1 个月前
Godot中类和静态类型
笔记·游戏引擎·godot
知兀1 个月前
编辑器、节点树、基础设置
笔记·游戏引擎·godot
巽星石2 个月前
【Godot4.3】匀速和匀变速直线运动粒子
godot·物理·加速度·速度曲线
巽星石2 个月前
【Godot4.3】自定义数列类NumList
godot·gdscript·斐波那契·数列
Android技术栈2 个月前
鸿蒙(API 12 Beta6版)图形加速【OpenGL ES平台内插模式】超帧功能开发
elasticsearch·harmonyos·鸿蒙·鸿蒙系统·openharmony·图形·超帧