Enter Boyd, from not exactly stage left.
authorNeil <neil@dip.sun.ac.za>
Tue, 6 Sep 2016 15:44:25 +0000 (17:44 +0200)
committerNeil <neil@dip.sun.ac.za>
Tue, 6 Sep 2016 15:47:21 +0000 (17:47 +0200)
tabakrolletjie/constants.py
tabakrolletjie/enemies.py [new file with mode: 0644]
tabakrolletjie/scenes/night.py

index 8e6bac7d4ba92dacb82cd72f5ee83e98e967e57f..5acf89aa9fb83519d9aec53157076357cff2adc2 100644 (file)
@@ -15,3 +15,4 @@ FPS = 60
 # Pymunk categories
 OBSTACLE_CATEGORY = 1 << 0
 LIGHT_CATEGORY = 1 << 1
+MOULD_CATEGORY = 1 << 2
diff --git a/tabakrolletjie/enemies.py b/tabakrolletjie/enemies.py
new file mode 100644 (file)
index 0000000..3f9210b
--- /dev/null
@@ -0,0 +1,111 @@
+# Boyd, the friendly, misunderstood turnip loving, light hating space mould
+
+import pymunk
+import pymunk.pygame_util
+import pygame.draw
+import pygame.surface
+import pygame.display
+
+import pygame.locals as pgl
+
+from .constants import SCREEN_SIZE, MOULD_CATEGORY, OBSTACLE_CATEGORY
+
+MOULD_FILTER = LIGHT_FILTER = pymunk.ShapeFilter(
+    mask=MOULD_CATEGORY | OBSTACLE_CATEGORY,
+    categories=MOULD_CATEGORY)
+
+
+class Mould(pymunk.Body):
+    """A segment of Boyd"""
+
+    def __init__(self, gamestate, space, pos):
+        super(Mould, self).__init__(0, 0, pymunk.Body.STATIC)
+        self.position = pos
+        self._shape = pymunk.Circle(self, 16)
+        space.add(self, self._shape)
+        self._shape.filter = MOULD_FILTER
+        self._resistances = {}
+        self._age = 0
+        self._img = None
+
+    def get_image(self):
+        if not self._img:
+            img = pygame.surface.Surface((32, 32))
+            img.convert_alpha(pygame.display.get_surface())
+            img.fill((0, 0, 0, 0))
+            pygame.draw.circle(img, (255, 255, 255, 255), (16, 16), 16)
+            self._img = img
+        return self._img
+
+    def tick(self, gamestate, space, moulds):
+        """Grow and / or Die"""
+        self._age += 1
+
+        refresh = False
+
+        if (self._age % 15) == 0 and len(moulds) < 1000:
+            # Spawn a new child, if we can
+            spawn = True
+            import random
+            choice = random.randint(0, 4)
+            if choice == 0:
+                pos = self.position + (0, 24)
+            elif choice == 1:
+                pos = self.position + (24, 0)
+            elif choice == 2:
+                pos = self.position + (-24, 0)
+            else:
+                pos = self.position + (0, -24)
+            # check for bounds
+            if pos[0] < 0 or pos[0] >= SCREEN_SIZE[0]:
+                spawn = False
+            if pos[1] < 0 or pos[1] >= SCREEN_SIZE[1]:
+                spawn = False
+            # Check for free space
+            # We allow some overlap, hence not checking full radius
+            query = space.point_query(pos, 8, MOULD_FILTER)
+            if query:
+                # for x in query:
+                #     if not isinstance(x.shape.body, Mould):
+                #         print x.shape, x.shape.body
+                spawn = False
+            if spawn:
+                child = Mould(gamestate, space, pos)
+                moulds.append(child)
+                refresh = True
+
+        if self._age > 120:
+            # We die of old age
+            space.remove(self, self._shape)
+            moulds.remove(self)
+            refresh = True
+        return refresh
+
+    def damage(self, light_color, intensity):
+        """Take damage for light, adjusted for resistances."""
+
+
+class Boyd(object):
+
+    def __init__(self, gamestate, space):
+        seed = Mould(gamestate, space, (400, 400))
+        self._moulds = [seed]
+        self._image = pygame.surface.Surface(SCREEN_SIZE)
+        self._image.convert_alpha(pygame.display.get_surface())
+        self._image.fill((0, 0, 0, 0))
+
+    def tick(self, gamestate, space):
+        redraw = False
+        for mould in self._moulds[:]:
+            if mould.tick(gamestate, space, self._moulds):
+                redraw = True
+        if redraw:
+            self._image.fill((0, 0, 0, 0))
+            for mould in self._moulds:
+                pos = pymunk.pygame_util.to_pygame(mould.position, self._image)
+                self._image.blit(mould.get_image(), pos, None,
+                                 pgl.BLEND_RGBA_ADD)
+
+    def render(self, surface):
+        """Draw ourselves"""
+        surface.blit(self._image, (0, 0), None, pgl.BLEND_RGBA_ADD)
index 16d8cf692a6aa9336cf2e008c30a07e019afd4a4..7f6b5bbbfb191310ecf7e6aafc04c1a9bdbbd7cc 100644 (file)
@@ -3,12 +3,16 @@
 import pygame.locals as pgl
 
 import pymunk
+import time
 
 from .base import BaseScene
 from ..lights import BaseLight
 from ..obstacles import BaseObstacle
+from ..enemies import Boyd
 from ..events import SceneChangeEvent
 
+from ..constants import DEBUG
+
 
 class NightScene(BaseScene):
     def enter(self, gamestate):
@@ -22,7 +26,10 @@ class NightScene(BaseScene):
         for light in self._lights:
             light.add(self._space)
 
+        self._mould = Boyd(gamestate, self._space)
+
     def render(self, surface, gamestate):
+        start_time = time.time()
         surface.fill((0, 0, 155))
         for light in self._lights:
             light.render_light(surface)
@@ -30,9 +37,21 @@ class NightScene(BaseScene):
             obs.render(surface)
         for light in self._lights:
             light.render(surface)
+        self._mould.render(surface)
+
+        end_time = time.time()
+        if DEBUG:
+            print "Night Render", end_time - start_time
 
     def event(self, ev, gamestate):
         if ev.type == pgl.KEYDOWN:
             if ev.key in (pgl.K_q, pgl.K_ESCAPE):
                 from .menu import MenuScene
                 SceneChangeEvent.post(scene=MenuScene())
+
+    def tick(self, gamestate):
+        start_time = time.time()
+        self._mould.tick(gamestate, self._space)
+        end_time = time.time()
+        if DEBUG:
+            print "Night Tick", end_time - start_time