X-Git-Url: https://git.ctpug.org.za/?p=tabakrolletjie.git;a=blobdiff_plain;f=tabakrolletjie%2Frays.py;h=a475d8fb27bb6c680a90555cad7dc2a4f6043954;hp=cac7c3bf90833c890d1e6049569104584a4a9709;hb=3341713feb17c2469631de0ef6078e5a4473b28c;hpb=42539dc3ca4c36a556fa1dba1e19169267f5d98f diff --git a/tabakrolletjie/rays.py b/tabakrolletjie/rays.py index cac7c3b..a475d8f 100644 --- a/tabakrolletjie/rays.py +++ b/tabakrolletjie/rays.py @@ -2,6 +2,8 @@ import math +import pygame.rect + import pymunk import pymunk.autogeometry import pymunk.pygame_util @@ -10,7 +12,7 @@ from .constants import SCREEN_SIZE from .utils import debug_timer -def screen_rays(pos): +def screen_rays(): """ 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. @@ -38,7 +40,7 @@ def calculate_ray_polys(space, position, light_filter): vertices = [position] start, end = None, None ray_polys = [] - for ray in screen_rays(position): + for ray in screen_rays(): info = space.segment_query_first(position, ray, 1, light_filter) point = ray if info is None else info.point vertices.append(point) @@ -75,27 +77,104 @@ def to_pymunk_radians(deg): class RayPolyManager(object): - def __init__(self, body, ray_filter): + def __init__( + self, body, position, ray_filter, radius_limits, direction, + spread): self._body = body # light's body + self._position = pymunk.Vec2d(position) # light's position self._ray_filter = ray_filter # light filter self._rays = [] # list of RayPolys + self._direction = None # normal vector for direction 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) + 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._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 - def generate_rays(self, space, position): - self._rays = calculate_ray_polys(space, position, self._ray_filter) + def set_space(self, space): + self._space = space + self._rays = calculate_ray_polys( + self._space, self._position, self._ray_filter) self._poly_cache = None - def set_angle_limits(self, angle_limits): - if angle_limits is None: + def update_shapes(self): + if self._old_poly_cache: + self._space.remove(*self._old_poly_cache) + new_polys = self._old_poly_cache = self.polys() + self._space.add(*new_polys) + + @property + def position(self): + return self._position + + @property + def max_radius(self): + return self._max_radius + + @max_radius.setter + def max_radius(self, value): + self._max_radius = value or 0.0 + + @property + def min_radius(self): + return self._min_radius + + @min_radius.setter + def min_radius(self, value): + self._min_radius = value or 0.0 + + def reaches(self, position): + distance = self.position.get_distance(position) + return (self._min_radius <= distance <= self._max_radius) + + def _set_radius_limits(self, radius_limits): + if radius_limits is None or not radius_limits[0]: + self._min_radius = 0 + else: + self._min_radius = radius_limits[0] + if radius_limits is None or not radius_limits[1]: + self._max_radius = 50.0 + else: + self._max_radius = radius_limits[1] + + def rotatable(self): + return self._direction is not None + + @property + def direction(self): + if self._direction is None: + return 0 + return self._direction.angle_degrees + + @direction.setter + def direction(self, degrees): + spread = self._direction.get_angle_between(self._start) + self._direction.angle_degrees = degrees + self._start = self._direction.rotated(spread) + self._end = self._direction.rotated(-spread) + self._poly_cache = None + + @property + def spread(self): + if not self._direction: + return 2 * math.pi + return math.fabs(self._start.get_angle_between(self._end)) + + def _set_angle_limits(self, direction, spread): + if direction is None or spread is None: + self._direction = 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._direction = pymunk.Vec2d(1, 0) + self._start = self._direction.rotated_degrees(-spread/2.) + self._end = self._direction.rotated_degrees(spread/2.) self._poly_cache = None def polys(self): @@ -109,6 +188,17 @@ class RayPolyManager(object): poly_cache.append(poly) return self._poly_cache + def pygame_position(self, surface): + return pymunk.pygame_util.to_pygame(self._position, surface) + + def pygame_rect(self, surface): + half_width = self.max_radius + rect_width = half_width * 2 + rect_x, rect_y = pymunk.pygame_util.to_pygame(self._position, surface) + dest_rect = pygame.rect.Rect(rect_x, rect_y, rect_width, rect_width) + dest_rect.move_ip(-half_width, -half_width) + return dest_rect + def pygame_polys(self, surface): return [ [pymunk.pygame_util.to_pygame(v, surface) @@ -135,19 +225,19 @@ class RayPoly(object): return trial # no limits start_info = trial.segment_query( - self.position + 0.1 * start, self.position + 1250 * start, 1) + self.position + 1250 * start, self.position + 0.1 * start, 0) end_info = trial.segment_query( - self.position + 0.1 * end, self.position + 1250 * end, 1) + self.position + 1250 * end, self.position + 0.1 * end, 0) 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) ] + if start_info.shape is not None: + vertices.append(start_info.point) + if end_info.shape is not None: + vertices.append(end_info.point) vertices.append(self.position) poly = pymunk.Poly(None, vertices)