Merge branch 'master' of ctpug.org.za:tabakrolletjie
authorSimon Cross <hodgestar@gmail.com>
Wed, 7 Sep 2016 21:30:33 +0000 (23:30 +0200)
committerSimon Cross <hodgestar@gmail.com>
Wed, 7 Sep 2016 21:30:33 +0000 (23:30 +0200)
data/stations/station-alpha.json
tabakrolletjie/lights.py
tabakrolletjie/rays.py
tabakrolletjie/scenes/day.py
tabakrolletjie/scenes/night.py

index 176794d98ddad0d21c9ebf1b8aef8657f9136bf0..259a64500c9f44e617e0a7ed7af98d5fa4379348 100644 (file)
@@ -31,8 +31,9 @@
       "position": [700, 500],
       "direction": 90.0,
       "spread": 45.0,
-      "radius_limits": [20, 200],
-      "angle_limits": [90, 270],
+      "radius_limits": [20, 400],
+      "angle_limits": [90, 180],
+      "angular_velocity": 10,
       "intensity": 0.8
     },
     {
index c143b98862326dc385658b53998934d45b7ff179..22f43586e44343c23c7481dc46df02098e7a3d1d 100644 (file)
@@ -76,6 +76,10 @@ class LightManager(object):
         for light in self._lights:
             light.render_fitting(surface)
 
+    def tick(self):
+        for light in self._lights:
+            light.tick()
+
 
 class BaseLight(object):
     """ Common light functionality. """
@@ -119,6 +123,7 @@ class BaseLight(object):
         if self.body.space is not None:
             space.remove(self.body, *self.body.shapes)
         self.ray_manager.generate_rays(space, self.position)
+        self.ray_manager.set_angle_limits(self.angle_limits)
         ray_shapes = self.ray_manager.polys()
         space.add(self.body, self.fitting, *ray_shapes)
 
@@ -188,9 +193,21 @@ class BaseLight(object):
             pymunk.pygame_util.to_pygame(self.fitting.offset, surface),
             int(self.fitting.radius))
 
+    def tick(self):
+        pass
+
 
 class SpotLight(BaseLight):
     def __init__(self, **kw):
         kw.pop("direction", None)
         kw.pop("spread", None)
+        self.angular_velocity = kw.pop("angular_velocity", None)
         super(SpotLight, self).__init__(**kw)
+
+    def tick(self):
+        if self.angular_velocity:
+            start, end = self.angle_limits
+            start = (start + self.angular_velocity) % 360.0
+            end = (end + self.angular_velocity) % 360.0
+            self.angle_limits = (start, end)
+            self.ray_manager.set_angle_limits(self.angle_limits)
index f7e69cc32d36b27c502daeba340ab307adaa32c5..f893828112a8084157fe353ea2e2a37b124c19d8 100644 (file)
@@ -1,5 +1,7 @@
 """ Light ray manipulation. Pew. Pew. Pew. Wommmm. """
 
+import math
+
 import pymunk
 import pymunk.autogeometry
 import pymunk.pygame_util
@@ -26,8 +28,12 @@ def screen_rays(pos):
         yield pymunk.Vec2d(x, bottom)
 
 
-@debug_timer("rays.calculate_ray_polys", True)
+@debug_timer("rays.calculate_ray_polys")
 def calculate_ray_polys(space, position, 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.
+    """
     position = pymunk.Vec2d(position)
     vertices = [position]
     start, end = None, None
@@ -44,7 +50,8 @@ 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, end, vertices[:-1]))
+                ray_polys.append(RayPoly(
+                    start - position, end - position, vertices[:-1]))
                 start = vertices[-1]
                 vertices = [position, start]
             else:
@@ -55,26 +62,68 @@ def calculate_ray_polys(space, position, light_filter):
     return ray_polys
 
 
+def to_pymunk_radians(deg):
+    """ Convert degrees in [0, 360] to radians in (-pi, pi].
+
+        Return None if degrees is None.
+    """
+    if deg is None:
+        return None
+    deg = deg * math.pi / 180.0
+    if deg > math.pi:
+        deg -= 2 * math.pi
+    return 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
 
     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))
+        self._poly_cache = None
+        self._pygame_poly_cache = None
 
     def polys(self):
-        return [rp.poly(self._body, self._ray_filter) for rp in self._rays]
+        if self._poly_cache is None:
+            print "===="
+            self._poly_cache = [
+                rp.poly(self._body, self._ray_filter) for rp in self._rays
+                if rp.within_limits(*self._angle_limits)
+            ]
+            print "===="
+
+        return self._poly_cache
 
     def pygame_polys(self, surface):
-        return [rp.pygame_poly(surface) for rp in self._rays]
+        if self._pygame_poly_cache is None:
+            print "REGEN ...", self._angle_limits
+            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
 
 
 class RayPoly(object):
-    def __init__(self, start, end, vertices):
-        self.start = start
-        self.end = end
+    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):
@@ -82,8 +131,22 @@ class RayPoly(object):
         shape.filter = filter
         return shape
 
-    def pygame_poly(self, surface):
-        return [
-            pymunk.pygame_util.to_pygame(v, surface)
-            for v in self.vertices
-        ]
+    def within_limits(self, start_limit, end_limit):
+        if start_limit is None or end_limit is None:
+            return True
+        print "----"
+        print "LIM: ", start_limit, end_limit
+        print "ANG: ", self.start.angle, self.end.angle
+        n1 = self.start.normalized()
+        n2 = self.end.normalized()
+        s = pymunk.Vec2d(1, 0).rotated(start_limit)
+        e = pymunk.Vec2d(1, 0).rotated(end_limit)
+        n1bet = s.dot(e) < s.dot(n1) and s.dot(e) < s.dot(n1)
+        n2bet = s.dot(e) < e.dot(n2) and s.dot(e) < e.dot(n2)
+        print "DOTS n1: ", n1.dot(n2), n1.dot(s), n2.dot(s)
+        print "DOTS n2: ", n1.dot(n2), n1.dot(e), n2.dot(e)
+        print "BET: ", n1bet, n2bet
+        if n1bet:
+            print "TRUE\n----"
+            return True
+        return False
index 20b297e1ae7b070a1c99981f01f813fdb2480a69..87193e89e124a118a752de3b0f46fcebb6c028fe 100644 (file)
@@ -37,4 +37,4 @@ class DayScene(BaseScene):
 
     @debug_timer("day.tick")
     def tick(self, gamestate):
-        pass
+        self._lights.tick()
index b4e19e8379704b46655a9338452cbd6f498115df..6944f5f00359fb89f764e96e667e8de68dd0924f 100644 (file)
@@ -40,3 +40,4 @@ class NightScene(BaseScene):
     @debug_timer("night.tick")
     def tick(self, gamestate):
         self._mould.tick(gamestate, self._space, self._lights)
+        self._lights.tick()