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

测试效果:

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

相关推荐
Y***K4341 天前
C在游戏中的Godot
游戏·游戏引擎·godot
you_get_me_there7 天前
godot-4.5.1导出安卓apk
godot·godot安卓打包
vivo互联网技术8 天前
Android动效探索:彻底弄清如何让你的视频更加酷炫
android·ffmpeg·跨平台·图形·mediaplayer·纹理·opengl es·坐标系
郭逍遥8 天前
[Godot] C#基于噪声的简单TileMap地图生成
游戏引擎·godot
陈尕六15 天前
从零开始的 Godot 之旅 — EP10:有限状态机(二)
godot·游戏开发
陈尕六22 天前
从零开始的 Godot 之旅 — EP9:有限状态机(一)
godot·游戏开发
应用市场25 天前
Godot C++开发指南:正确获取节点的Forward/Up/Right方向向量
c++·游戏引擎·godot
云缘若仙25 天前
Godot游戏开发——C# (一)
c#·godot
陈尕六1 个月前
从零开始的 Godot 之旅 — EP8:角色移动和动画切换
godot·游戏开发
宇宙无敌QT拼图糕手1 个月前
godot4.4 如何让游戏画面没有透视【正交相机】
godot