How would I be able to detect when a collision shape polygon has made a circle with collision

Viewed 411

This is a hard idea to put into a question, I have made a system where the player draws circles on screen, I want the player has either touched another line of its self start a new circle from that position, the issue I am having is having no clue on how would I make it collide, I have an idea but not sure if it will work, my idea is too simply use a different collision shape that creates its self on points that connect each other and when the mouse collides with that specific collision shape start again, is this the best option I have or is there another way of detecting when a circle is made.

heres a video of what I want: https://youtu.be/wSolVcaIszE?t=998

and heres my video of what I have: https://www.youtube.com/watch?v=BDnd-n3PEdQ

code:

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
1 Answers

Given that you keep the number of points short. A simple segment-segment collision check would suffice to detect a loop.

Something like this:

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

And use like this:

    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

Where loop(index) means do whatever you do when there is a loop.


This is not really detecting a circle. Just a loop. By the way, the reference video does not detect circles either. Just loops.

You could check if the loop is convex, using the wedge product. If the shape is convex sign(_wedge_product(points_array[-1] - points_array[-2], points_array[-2] - points_array[-3])) should be the same before and after adding a point. If it changes, then the shape is concave.

For a circle, all points would be about the same distance from the center. Thus, if you check the proportion between minimum and maximum length to the center, you have a measure of how circular the loop is. The proportion would be equal to one for a circle. How to find the center? You could compute the smaller axis aligned bounding box that contains the points (i.e compute the minimum and maximum x and y coordinates across the points), and the center of the box would match the center of the loop… Assuming it is symmetrical, if it isn't, you would get that it is not very circular anyway, so that is fine.

Related