query_prev = trial_poly.point_query(end)
query_pos = trial_poly.point_query(position)
if query_prev.distance < -0.01 or query_pos.distance < -0.01:
- ray_polys.append(RayPoly(
- start - position, end - position, vertices[:-1]))
+ ray_polys.append(RayPoly(position, vertices[:-1]))
start = vertices[-1]
vertices = [position, start]
else:
vertices = trial_poly.get_vertices()
end = point
if len(vertices) > 2:
- ray_polys.append(RayPoly(start, end, vertices))
+ ray_polys.append(RayPoly(position, vertices))
return ray_polys
class RayPolyManager(object):
def __init__(self, body, ray_filter):
- self._body = body
- self._ray_filter = ray_filter
- self._rays = []
- self._angle_limits = (None, None)
- self._poly_cache = None
- self._pygame_poly_cache = None
+ self._body = body # light's body
+ self._ray_filter = ray_filter # light filter
+ self._rays = [] # list of RayPolys
+ self._start = None # normal vector in direction of start angle limit
+ self._end = None # normal vector in direction of end angle limit
+ self._poly_cache = None # list of pymunk.Polys for rays
def generate_rays(self, space, position):
self._rays = calculate_ray_polys(space, position, self._ray_filter)
self._poly_cache = None
- self._pygame_poly_cache = None
def set_angle_limits(self, angle_limits):
- start, end = angle_limits
- self._angle_limits = (
- to_pymunk_radians(start), to_pymunk_radians(end))
+ if angle_limits is None:
+ self._start = None
+ self._end = None
+ else:
+ self._start = pymunk.Vec2d(1, 0).rotated(
+ to_pymunk_radians(angle_limits[0]))
+ self._end = pymunk.Vec2d(1, 0).rotated(
+ to_pymunk_radians(angle_limits[1]))
self._poly_cache = None
- self._pygame_poly_cache = None
def polys(self):
if self._poly_cache is None:
- self._poly_cache = [
- rp.poly(self._body, self._ray_filter) for rp in self._rays
- if rp.within_limits(*self._angle_limits)
- ]
+ self._poly_cache = poly_cache = []
+ for rp in self._rays:
+ poly = rp.poly(self._start, self._end)
+ if poly:
+ poly.body = self._body
+ poly.filter = self._ray_filter
+ poly_cache.append(poly)
return self._poly_cache
def pygame_polys(self, surface):
- if self._pygame_poly_cache is None:
- self._pygame_poly_cache = [
- [
- pymunk.pygame_util.to_pygame(v, surface)
- for v in poly.get_vertices()
- ]
- for poly in self.polys()
- ]
- return self._pygame_poly_cache
+ return [
+ [pymunk.pygame_util.to_pygame(v, surface)
+ for v in poly.get_vertices()]
+ for poly in self.polys()
+ ]
class RayPoly(object):
- def __init__(self, start_vec, end_vec, vertices):
- self.start = start_vec # vector from position to first point
- self.end = end_vec # vector from position to last point
- self.vertices = vertices
-
- def poly(self, body, filter):
- shape = pymunk.Poly(body, self.vertices)
- shape.filter = filter
- return shape
-
- def within_limits(self, start_limit, end_limit):
- if start_limit is None or end_limit is None:
- return True
-
- def between(n):
- if start_limit < end_limit:
- return start_limit <= n <= end_limit
- return (start_limit <= n) or (n <= end_limit)
-
- start_within = between(self.start.angle)
- end_within = between(self.end.angle)
- if start_within or end_within:
- return True
- return False
+ def __init__(self, position, vertices):
+ self.position = position # pointy end of the conical polygon
+ self.vertices = vertices # all vertices in the polygon
+
+ def _between(self, v, start, end):
+ if start < end:
+ return start <= v <= end
+ return (start <= v) or (v <= end)
+
+ def poly(self, start, end):
+ trial = pymunk.Poly(None, self.vertices)
+ trial.update(pymunk.Transform.identity())
+
+ if start is None or end is None:
+ return trial # no limits
+
+ start_info = trial.segment_query(
+ self.position + 0.1 * start, self.position + 1250 * start, 1)
+ end_info = trial.segment_query(
+ self.position + 0.1 * end, self.position + 1250 * end, 1)
+
+ vertices = self.vertices[:]
+ if start_info:
+ vertices.append(start_info.point)
+ if end_info:
+ vertices.append(end_info.point)
+ vertices = [
+ v for v in vertices
+ if self._between((v - self.position).angle, start.angle, end.angle)
+ ]
+ vertices.append(self.position)
+
+ poly = pymunk.Poly(None, vertices)
+ if len(poly.get_vertices()) < 3:
+ return None
+ return poly