Use bounding foxes.
authorSimon Cross <hodgestar@gmail.com>
Sat, 10 Sep 2016 20:06:55 +0000 (22:06 +0200)
committerSimon Cross <hodgestar@gmail.com>
Sat, 10 Sep 2016 20:06:55 +0000 (22:06 +0200)
tabakrolletjie/rays.py

index 8b532784a46a80e97f354cb9686b6161fe2bbe8b..7d880d0aaa5ea417e38cb08fcfe167c5732c42f2 100644 (file)
@@ -8,30 +8,30 @@ import pymunk
 import pymunk.autogeometry
 import pymunk.pygame_util
 
 import pymunk.autogeometry
 import pymunk.pygame_util
 
-from .constants import SCREEN_SIZE
 from .utils import debug_timer
 
 
 from .utils import debug_timer
 
 
-def screen_rays():
+def screen_rays(pos, bounding_radius):
     """ An iterable that returns ordered rays from pos to the edge of the
         screen, starting with the edge point (0, 0) and continuing clockwise
         in pymunk coordinates.
     """
     """ An iterable that returns ordered rays from pos to the edge of the
         screen, starting with the edge point (0, 0) and continuing clockwise
         in pymunk coordinates.
     """
-    w, h = SCREEN_SIZE
-    left, right, bottom, top = 0, w, 0, h
+    r = int(bounding_radius)
+    left, right = int(pos.x) - r, int(pos.x) + r
+    bottom, top = int(pos.y) + r, int(pos.y) - r
     step = 1
     step = 1
-    for y in range(0, h, step):
+    for y in range(top, bottom + 1, step):
         yield pymunk.Vec2d(left, y)
         yield pymunk.Vec2d(left, y)
-    for x in range(0, w, step):
+    for x in range(left, right + 1, step):
         yield pymunk.Vec2d(x, top)
         yield pymunk.Vec2d(x, top)
-    for y in range(top, -1, -step):
+    for y in range(bottom, top - 1, -step):
         yield pymunk.Vec2d(right, y)
         yield pymunk.Vec2d(right, y)
-    for x in range(right, -1, -step):
+    for x in range(right, left - 1, -step):
         yield pymunk.Vec2d(x, bottom)
 
 
 @debug_timer("rays.calculate_ray_polys")
         yield pymunk.Vec2d(x, bottom)
 
 
 @debug_timer("rays.calculate_ray_polys")
-def calculate_ray_polys(space, position, light_filter):
+def calculate_ray_polys(space, position, bounding_radius, light_filter):
     """ Calculate a set of convex RayPolys that cover all the areas that light
         can reach from the given position, taking into account the obstacles
         present in the space.
     """ Calculate a set of convex RayPolys that cover all the areas that light
         can reach from the given position, taking into account the obstacles
         present in the space.
@@ -40,7 +40,7 @@ def calculate_ray_polys(space, position, light_filter):
     vertices = [position]
     start, end = None, None
     ray_polys = []
     vertices = [position]
     start, end = None, None
     ray_polys = []
-    for ray in screen_rays():
+    for ray in screen_rays(position, bounding_radius):
         info = space.segment_query_first(position, ray, 1, light_filter)
         point = ray if info is None else info.point
         vertices.append(point)
         info = space.segment_query_first(position, ray, 1, light_filter)
         point = ray if info is None else info.point
         vertices.append(point)
@@ -79,7 +79,7 @@ def to_pymunk_radians(deg):
 class RayPolyManager(object):
     def __init__(
             self, body, position, ray_filter, radius_limits, direction,
 class RayPolyManager(object):
     def __init__(
             self, body, position, ray_filter, radius_limits, direction,
-            spread):
+            spread, bounding_radius):
         self._body = body  # light's body
         self._position = pymunk.Vec2d(position)  # light's position
         self._ray_filter = ray_filter  # light filter
         self._body = body  # light's body
         self._position = pymunk.Vec2d(position)  # light's position
         self._ray_filter = ray_filter  # light filter
@@ -88,11 +88,13 @@ class RayPolyManager(object):
         self._start = None  # normal vector in direction of start angle limit
         self._end = None  # normal vector in direction of end angle limit
         self._set_angle_limits(direction, spread)
         self._start = None  # normal vector in direction of start angle limit
         self._end = None  # normal vector in direction of end angle limit
         self._set_angle_limits(direction, spread)
+        self._bounding_radius = None   # absolute maximum radius
         if direction:
             self.direction = direction  # Update direction
         self._max_radius = None  # maximum radius in pixels
         self._min_radius = None  # minimum radius in pixels
         self._set_radius_limits(radius_limits)
         if direction:
             self.direction = direction  # Update direction
         self._max_radius = None  # maximum radius in pixels
         self._min_radius = None  # minimum radius in pixels
         self._set_radius_limits(radius_limits)
+        self._set_bounding_radius(bounding_radius)
         self._old_poly_cache = None  # last polys added to the space
         self._poly_cache = None  # list of pymunk.Polys for rays
         self._space = None  # space the rays form part of
         self._old_poly_cache = None  # last polys added to the space
         self._poly_cache = None  # list of pymunk.Polys for rays
         self._space = None  # space the rays form part of
@@ -100,7 +102,8 @@ class RayPolyManager(object):
     def set_space(self, space):
         self._space = space
         self._rays = calculate_ray_polys(
     def set_space(self, space):
         self._space = space
         self._rays = calculate_ray_polys(
-            self._space, self._position, self._ray_filter)
+            self._space, self._position, self._bounding_radius,
+            self._ray_filter)
         self._poly_cache = None
 
     def update_shapes(self):
         self._poly_cache = None
 
     def update_shapes(self):
@@ -157,6 +160,11 @@ class RayPolyManager(object):
         else:
             self._max_radius = radius_limits[1]
 
         else:
             self._max_radius = radius_limits[1]
 
+    def _set_bounding_radius(self, bounding_radius):
+        if bounding_radius is None:
+            bounding_radius = self._max_radius
+        self._bounding_radius = bounding_radius
+
     def rotatable(self):
         return self._direction is not None
 
     def rotatable(self):
         return self._direction is not None