You need to enable JavaScript to run this app. Godot中如何检测玩家绘制的碰撞形状多边形是否自碰撞形成闭合圆形
优惠活动
大模型
产品
解决方案
定价
更多

Godot中如何检测玩家绘制的碰撞形状多边形是否自碰撞形成闭合圆形

方案评估与实现

原碰撞体方案的问题

  • 你最初设想的"随绘制点生成分段碰撞形状"的方案不是最优选择,核心原因有两个:
    • Godot的CollisionPolygon2D仅对闭合多边形生成有效碰撞体,你当前将开放线条数组赋值给它,根本无法生成可用的碰撞检测逻辑
    • 每帧更新绘制点时重建碰撞体的性能开销远高于纯几何计算,绘制点较多时容易出现卡顿

更适配的替代方案

针对"绘制线条自相交即判定闭合"的需求,按优先级排序的可行方案:

1. 纯几何线段相交检测(推荐)

  • 原理:你绘制的内容本质是连续折线段,每更新一次鼠标位置就生成一个新的活动线段(倒数第二个绘制点到当前鼠标点),只需检测这个活动线段和之前的所有旧线段(排除相邻的共点线段)是否相交,即可快速判断是否自交闭合
  • 优点:纯数学计算,无物理引擎开销,100%适配现有绘制逻辑,不会出现碰撞体的延迟或误判

2. 分段LineShape2D碰撞方案

  • 如果一定要用物理碰撞逻辑实现,可以将每个绘制出的小段单独生成一个LineShape2D类型的CollisionShape2D挂在Area2D下,同时将当前鼠标轨迹设为小型碰撞体,检测两者的碰撞
  • 缺点:需要管理大量动态生成的碰撞节点,性能开销远高于纯几何检测,调试复杂度也更高

适配现有代码的具体实现

基于推荐的纯几何方案,对现有代码的调整如下:

  • 利用Godot内置的Geometry2D.segment_intersects_segment()做线段相交检测,无需自行实现几何算法
  • 新增最小绘制点阈值,避免刚下笔时的误判
  • 跳过与活动线段直接相邻的共点线段,排除无效交叉判断

调整后的完整代码:

extends Node2D

var points_array = PoolVector2Array()
var index : int = 0
# 新增:最小绘制点阈值,避免刚下笔就误判闭合
const MIN_POINTS_TO_CHECK = 5

func _physics_process(delta):
    if Input.is_action_just_pressed("Left_click"):
        points_array.append(get_global_mouse_position())
        points_array.append(Vector2())
    if Input.is_action_pressed("Left_click"):
        var mouse_pos = get_global_mouse_position()
        points_array[-1] = mouse_pos
        
        # 绘制点足够时触发自相交检测
        if points_array.size() >= MIN_POINTS_TO_CHECK:
            # 当前活动线段:倒数第二个点 → 当前鼠标位置
            var active_start = points_array[-2]
            var active_end = points_array[-1]
            
            # 遍历所有旧线段,排除相邻共点线段
            for i in range(points_array.size() - 2):
                # 跳过与活动线段直接相连的前一个线段(共点不算交叉)
                if i == points_array.size() - 3:
                    continue
                # 内置线段相交检测,返回null即未相交
                if Geometry2D.segment_intersects_segment(
                    active_start, active_end,
                    points_array[i], points_array[i+1]
                ):
                    # 检测到闭合,从当前位置开始新绘制
                    points_array = PoolVector2Array([mouse_pos, mouse_pos])
                    index = 0
                    break
        
        # 原有逻辑:鼠标移动超过阈值时新增绘制点
        if points_array[index].distance_to(mouse_pos) > 20:
            points_array.append(mouse_pos)
            index += 1
    
    # 原有逻辑:限制线条最大长度
    if points_array.size() > 25:
        index -= 1
        points_array.remove(0)
    
    if Input.is_action_just_released("Left_click"):
        points_array = PoolVector2Array()
        index = 0

可根据需求调整规则:比如增加最小闭合面积判断,避免绘制极小的闭合图形就触发重置;或调整MIN_POINTS_TO_CHECK的数值优化检测灵敏度。

内容的提问来源于stack exchange,提问作者Dragon20C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 08:54:03