首页 > 解决方案 > 我如何能够检测到碰撞形状多边形何时形成一个有碰撞的圆

问题描述

这是一个很难提出问题的想法,我已经制作了一个玩家在屏幕上绘制圆圈的系统,我希望玩家要么触摸了自己的另一条线,从那个位置开始一个新的圆圈,我遇到的问题是不知道如何让它发生碰撞,我有一个想法,但不确定它是否会起作用,我的想法太简单了,它使用不同的碰撞形状,在相互连接的点上以及当鼠标与之碰撞时创建自己特定的碰撞形状再次开始,这是我拥有的最佳选择还是有另一种方法可以检测何时形成圆圈。

这是我想要的视频:https ://youtu.be/wSolVcaIszE?t=998

这是我的视频:https ://www.youtube.com/watch?v=BDnd-n3PEdQ

代码:

extends Node2D

var points_array = PoolVector2Array()
var index : int = 0
onready var collision = $Area2D/CollisionPolygon2D

func _physics_process(delta):
    collision.polygon = points_array
    
    if Input.is_action_just_pressed("Left_click"): #This sets a position so that the next line can work together
        points_array.append(get_global_mouse_position()) # This makes a empty vector and the mouse cords is assigned too it
        points_array.append(Vector2())
    if Input.is_action_pressed("Left_click"): #This checks the distance between last vector and the mouse vector
        points_array[-1] = get_global_mouse_position() # Gets the last position of the array and sets the mouse cords
        if points_array[index].distance_to(get_global_mouse_position()) > 20:
            points_array.append(get_global_mouse_position())
            index += 1
    if points_array.size() > 25: # This adds a length to the circle/line so it wont pass 18 mini lines
        index -= 1
        points_array.remove(0) #Removes the first array to make it look like it has a length
    if Input.is_action_just_released("Left_click"): # This just clears the screen when the player releases the button
        points_array = PoolVector2Array()
        index = 0

标签: godotgdscript

解决方案


鉴于您保持点数较短。一个简单的段-段冲突检查就足以检测到一个循环。

像这样的东西:

func _segment_collision(a1:Vector2, a2:Vector2, b1:Vector2, b2:Vector2) -> bool:
    # if both ends of segment b are to the same side of segment a, they do not intersect
    if sign(_wedge_product(a2 - a1, b1 - a1)) == sign(_wedge_product(a2 - a1, b2 - a1)):
        return false

    # if both ends of segment a are to the same side of segment b, they do not intersect     
    if sign(_wedge_product(b2 - b1, a1 - b1)) == sign(_wedge_product(b2 - b1, a2 - b1)):
        return false

    # the segments must intersect
    return true

func _wedge_product(a:Vector2, b:Vector2) -> float:
    # this is the length of the cross product
    # it has the same sign as the sin of the angle between the vectors
    return a.x * b.y - a.y * b.x

并像这样使用:

    if points_array.size() > 3:
        for index in range(0, points_array.size() - 3):
            if _segment_collision(
                    points_array[-1],
                    points_array[-2],
                    points_array[index],
                    points_array[index + 1]
                ):
                    loop(index)
                    break

哪里loop(index)意味着当有循环时做任何你做的事情。


这并不是真正检测到一个圆圈。只是一个循环。顺便说一句,参考视频也没有检测到圆圈。只是循环。

您可以使用楔形产品检查环是否凸出。如果形状是凸sign(_wedge_product(points_array[-1] - points_array[-2], points_array[-2] - points_array[-3]))的,在添加点之前和之后应该是相同的。如果它改变,那么形状是凹的。

对于一个圆,所有点到中心的距离都差不多。因此,如果您检查到中心的最小和最大长度之间的比例,您就可以衡量循环的圆度。对于一个圆圈,该比例将等于 1。如何找到中心?您可以计算包含点的较小的轴对齐边界框(即计算点之间的最小和最大 x 和 y 坐标),并且框的中心将匹配循环的中心......假设它是对称的,如果它不是,你会发现它不是很圆,所以没关系。


推荐阅读