Slightly better ray poly updating.
authorSimon Cross <hodgestar@gmail.com>
Thu, 8 Sep 2016 20:54:57 +0000 (22:54 +0200)
committerSimon Cross <hodgestar@gmail.com>
Thu, 8 Sep 2016 20:54:57 +0000 (22:54 +0200)
tabakrolletjie/lights.py
tabakrolletjie/rays.py

index 22f43586e44343c23c7481dc46df02098e7a3d1d..84318d15e253616dbe529fcd5a0f0d869e8a1ad2 100644 (file)
@@ -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
index e187f3d3c532633540f41b330f68be6f15b38867..cac7c3bf90833c890d1e6049569104584a4a9709 100644 (file)
@@ -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