Why does my implementation of "is 2D point inside 2D polygon" have slightly different results on either side of the same axis?
1
votes
1
votes
Posted by: sneakyRedPanda on 07/26/2017 | Add Revision
My 2D game is tile-based, 16 pixels per tile. Colliders are defined by an array of points which determine a polygon. With debugging enabled (as it is in the photos) those colliders are outlined with red lines. You can see this on the player and on the water tiles I am using to explain the issue.
The following two photos are both what happens when the player moves leftwards into the collider of the water tile.
The difference between these two photos is the fact that the player's collider collides with the tile collider on its corner. The second picture represents the desired effect. I should clarify that in the photos, the second (lower) water tile is not required to be there to have the same effect.
Currently this issue only happens when approaching a tile collider moving upwards or leftwards. This has the effect of preventing the player from moving along the tile into a new tile - the corner of the adjacent tile catches the player's collider and stops movement.
Here is the code I'm using to determine if a point is within a polygon. This function is called on each point that makes up the collider of the player.
def self.point_in_poly(testx, testy, *poly)
return false if outside_bounding_box?(testx, testy, *poly)
point_in_poly = false
i = -1
j = poly.count - 1
while (i += 1) < poly.count
a_point_on_polygon = poly[i]
trailing_point_on_polygon = poly[j]
if point_is_between_the_ys_of_the_line_segment?([testx, testy], a_point_on_polygon, trailing_point_on_polygon)
if ray_crosses_through_line_segment?([testx, testy], a_point_on_polygon, trailing_point_on_polygon)
point_in_poly = !point_in_poly
end
end
j = i
end
return point_in_poly
end
private
def self.point_is_between_the_ys_of_the_line_segment?(point, a_point_on_polygon, trailing_point_on_polygon)
(a_point_on_polygon[1] <= point[1] && point[1] < trailing_point_on_polygon[1]) ||
(trailing_point_on_polygon[1] <= point[1] && point[1] < a_point_on_polygon[1])
end
def self.ray_crosses_through_line_segment?(point, a_point_on_polygon, trailing_point_on_polygon)
(point[0] < (trailing_point_on_polygon[0] - a_point_on_polygon[0]) * (point[1] - a_point_on_polygon[1]) /
(trailing_point_on_polygon[1] - a_point_on_polygon[1]) + a_point_on_polygon[0])
end
def self.outside_bounding_box?(x, y, *poly)
max_x, max_y, min_x, min_y = nil
x_coords = poly.map {|p| p[0]}
y_coords = poly.map {|p| p[1]}
max_x = x_coords.max
max_y = y_coords.max
min_x = x_coords.min
min_y = y_coords.min
return x < min_x || x > max_x || y < min_y || y > max_y
end
Any insight as to why this might be happening at only at leftwards and upwards directions is appreciated.