0 votes

Hi,

I looked for some existing code in Geomery to cut my polygon with the player's tail in a Qix / Gals panic like game I'm working on:

qixall game screenshot

But as far I understand there's no such method exposed.

So I coded my own:

start_edge and end_edge are index of the point in the polygon representing the playground (white square on the screenshot above). In this case start_edge = 2, end_edge = 1

PolygonIterator is a class with a little magic for looping on the edge in the polygon array of point, which on a given size known when to go through the end of the Array and restart at the beginning.

func cut(tail, start_edge, end_edge):
    var pol1 : Array = tail.points

    # process of linking the 2 polygons:
    # pol1
    # 1. all the tail points
    # 2. the area points from where the tail ends in clockwise order throught
    #    where the tail starts

    if is_on_corner(pol1[0], start_edge):
        start_edge = prev_corner(start_edge)

    if is_on_corner(pol1[-1], end_edge):
        end_edge = next_corner(end_edge)

    var iter = PolygonIterator.new(pol.polygon.size(), end_edge, start_edge)
    print(iter)

    for i in iter:
        print("cut: add point %d" % i)
        pol1.append(pol.polygon[i])

    var polys = Geometry.clip_polygons_2d(pol.polygon, pol1)
    print("cliped: %d" % len(polys))
    return [ pol1, polys[0] ]

ThePolygonIterator class code:

class_name PolygonIterator
# this iterator loop over start to the end to cover all points
# excluding  start, including  end

var start
var current
var end
var count = 0
var size
var counter = 0

func _init(size, start, stop):
    self.size = size
    self.start = start
    self.current = start
    if stop < size:
        self.end = stop
    else:
        self.end = size - 1

    if start < end:
        count = end - start
    elif start == end:
        count = 0
    else:
        count = end + (size - start)    

func should_continue():
    return counter > 0

func init_count():
    counter = count

func _iter_init(arg):
    init_count()
    current = next_val(start)
    return should_continue()

func next_val(val):
    return (val + 1 + size) % size

func _iter_next(arg):
    counter -= 1
    current = next_val(current)
    return should_continue()

func _iter_get(arg):
    return current

func _to_string():
    return "iter: (%d) start %d end %d count %d" % [ size, start, end, count ]

So I first complete my Polyline (tail) with some polygon's point in order to have a polygon, and then I subtract it to the playground's polygon with clip_polygons_2d().

Is there better way to perform it?

Regards,
Sylvain.

in Engine by (33 points)

1 Answer

0 votes

There's no such method exposed because the underlying library for polygon clipping in Godot (Clipper) doesn't support such operation.

You can in theory simulate this by using Geometry.offset_polyline_2d with a very small delta, which will grow your polyline into a thin polygon, and then do the clipping between polygons. Or, you can generate two rectangles along with a polyline (if it's a straight line), and do Geometry.intersect_polygons_2d two times against your subject polygon on the both side of the polyline.

by (1,356 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.