From 98d62f5dbe35a75ab75d853ae9daa1fd8a625377 Mon Sep 17 00:00:00 2001 From: Simon Cross Date: Thu, 8 Sep 2016 22:54:57 +0200 Subject: [PATCH] Slightly better ray poly updating. --- tabakrolletjie/lights.py | 2 +- tabakrolletjie/rays.py | 115 ++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 52 deletions(-) diff --git a/tabakrolletjie/lights.py b/tabakrolletjie/lights.py index 22f4358..84318d1 100644 --- a/tabakrolletjie/lights.py +++ b/tabakrolletjie/lights.py @@ -97,7 +97,7 @@ class BaseLight(object): def __init__( self, colour, position, intensity=1.0, - radius_limits=(None, None), angle_limits=(None, None)): + radius_limits=(None, None), angle_limits=None): self.colour = colour self.position = pymunk.Vec2d(position) self.on = True diff --git a/tabakrolletjie/rays.py b/tabakrolletjie/rays.py index e187f3d..cac7c3b 100644 --- a/tabakrolletjie/rays.py +++ b/tabakrolletjie/rays.py @@ -50,15 +50,14 @@ def calculate_ray_polys(space, position, light_filter): 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 @@ -77,67 +76,81 @@ def to_pymunk_radians(deg): 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 -- 2.34.1