示例#1
0
    def on_update(self, update: ppb_events.Update, signal):
        if self.health <= 0:
            update.scene.remove(self)
            update.scene.add(
                RunOnceAnimation(
                    position=self.position,
                    life_span=0.25,
                    image=Animation(
                        "shooter/resources/explosions/player/sprite_{1..7}.png",
                        24),
                    end_event=shooter_events.PlayerDied(),
                    size=2))
            signal(ppb_events.PlaySound(sounds["dead"]))

        controller = update.controls
        self.heading = Vector(controller.get("horizontal"),
                              controller.get("vertical"))
        if self.heading:
            self.heading = self.heading.normalize()
        self.move(update.time_delta)
示例#2
0
 def on_pre_render(self, event, signal):
     core_position = event.scene.player.position
     min_x = int((core_position.x // 10) * 10)
     min_y = int((core_position.y // 10) * 10)
     cells = list(
         product(range(min_x - 10, min_x + 20, 10),
                 range(min_y - 10, min_y + 20, 10)))
     for c_x, c_y in cells:
         if (c_x, c_y) in self.created_zones:
             continue
         _seed = self.seed + f"{c_x}-{c_y}"
         seed(_seed)
         results = choices(self.choices, weights=self.weights, k=100)
         self.created_zones[(c_x, c_y)] = {
             "spawned": True,
             "classes": results
         }
         for (x, y), cls in zip(
                 product(range(c_x, c_x + 10), range(c_y, c_y + 10)),
                 results):
             if cls is not None:
                 event.scene.add(cls(pos=Vector(x, y)))
示例#3
0
class Rotatable:
    """
    A simple rotation mixin. Can be included with sprites.
    """
    _rotation = 0
    # This is necessary to make facing do the thing while also being adjustable.
    #: The baseline vector, representing the "front" of the sprite
    basis = Vector(0, -1)
    # Considered making basis private, the only reason to do so is to
    # discourage people from relying on it as data.

    @property
    def facing(self):
        """
        The direction the "front" is facing
        """
        return Vector(*self.basis).rotate(self.rotation).normalize()

    @facing.setter
    def facing(self, value):
        self.rotation = self.basis.angle(value)

    @property
    def rotation(self):
        """
        The amount the sprite is rotated, in degrees
        """
        return self._rotation

    @rotation.setter
    def rotation(self, value):
        self._rotation = value % 360

    def rotate(self, degrees):
        """
        Rotate the sprite by a given angle (in degrees).
        """
        self.rotation += degrees
示例#4
0
 def bottom(self):
     self._attribute_gate(BOTTOM, [TOP, BOTTOM])
     return Vector(self.value, self.parent.bottom.value)
示例#5
0
class BaseSprite(EventMixin):
    """
    The base Sprite class. All sprites should inherit from this (directly or
    indirectly).

    Attributes:
    * image (str): The image file
    * resource_path (pathlib.Path): The path that image is relative to
    * position: Location of the sprite
    * facing: The direction of the "top" of the sprite (rendering only)
    * size: The width/height of the sprite (sprites are square)
    """
    image = None
    resource_path = None
    position: Vector = Vector(0, 0)
    facing: Vector = Vector(0, -1)
    _size: Union[int, float] = 1
    _offset_value = None

    def __init__(self, **kwargs):
        super().__init__()

        # Make these instance properties with fresh instances
        # Don't use Vector.convert() because we need copying
        self.position = Vector(*self.position)
        self.facing = Vector(*self.facing)

        # Initialize things
        for k, v in kwargs.items():
            # Abbreviations
            if k == 'pos':
                k = 'position'
            # Castings
            if k in ('position', 'facing'):
                v = Vector(*v)  # Vector.convert() when that ships.
            setattr(self, k, v)

        # Trigger some calculations
        self.size = self.size

    @property
    def center(self) -> Vector:
        return self.position

    @center.setter
    def center(self, value: Sequence[float]):
        x = value[0]
        y = value[1]
        self.position.x = x
        self.position.y = y

    @property
    def left(self) -> Side:
        return Side(self, LEFT)

    @left.setter
    def left(self, value: float):
        self.position.x = value + self._offset_value

    @property
    def right(self) -> Side:
        return Side(self, RIGHT)

    @right.setter
    def right(self, value):
        self.position.x = value - self._offset_value

    @property
    def top(self):
        return Side(self, TOP)

    @top.setter
    def top(self, value):
        self.position.y = value + self._offset_value

    @property
    def bottom(self):
        return Side(self, BOTTOM)

    @bottom.setter
    def bottom(self, value):
        self.position.y = value - self._offset_value

    @property
    def size(self) -> Union[int, float]:
        return self._size

    @size.setter
    def size(self, value: Union[int, float]):
        self._size = value
        self._offset_value = self._size / 2

    def rotate(self, degrees: Number):
        self.facing.rotate(degrees)

    def __image__(self):
        if self.image is None:
            self.image = f"{type(self).__name__.lower()}.png"
        return self.image

    def __resource_path__(self):
        if self.resource_path is None:
            self.resource_path = Path(realpath(getfile(type(self)))).absolute().parent
        return self.resource_path
示例#6
0
 def right(self):
     self._attribute_gate(RIGHT, [LEFT, RIGHT])
     return Vector(self.parent.right.value, self.value)
示例#7
0
 def test_bottom_bottom(self):
     self.assertRaises(AttributeError, getattr, self.sprite.bottom,
                       "bottom")
     self.assertRaises(AttributeError, setattr, self.sprite.bottom,
                       "bottom", Vector(1, 1))
示例#8
0
 def test_top_top(self):
     self.assertRaises(AttributeError, getattr, self.sprite.top, "top")
     self.assertRaises(AttributeError, setattr, self.sprite.top, "top",
                       Vector(1, 1))
示例#9
0
 def test_right_left(self):
     self.assertRaises(AttributeError, getattr, self.sprite.right, "left")
     self.assertRaises(AttributeError, setattr, self.sprite.right, "left",
                       Vector(1, 1))
示例#10
0
 def bottom(self) -> Vector:
     """
     Get the corner vector
     """
     self._attribute_gate(BOTTOM, [TOP, BOTTOM])
     return Vector(float(self), float(self.parent.bottom))
示例#11
0
 def top(self) -> Vector:
     """
     Get the corner vector
     """
     self._attribute_gate(TOP, [TOP, BOTTOM])
     return Vector(float(self), float(self.parent.top))
示例#12
0
 def bottom(self, value):
     self.position = Vector(self.position.x, value + self._offset_value)
示例#13
0
 def top(self, value):
     self.position = Vector(self.position.x, value - self._offset_value)
示例#14
0
 def right(self, value):
     self.position = Vector(value - self._offset_value, self.position.y)
示例#15
0
 def left(self, value: float):
     self.position = Vector(value + self._offset_value, self.position.y)
示例#16
0
class MoverMixin(ppb.Sprite):
    velocity = Vector(0, 0)

    def on_update(self, update, signal):
        self.position += self.velocity * update.time_delta
示例#17
0
 def test_pos(self):
     self.assertEqual(self.sprite.position, Vector(0, 0))
     self.assertEqual(self.wide_sprite.position, Vector(2, 2))
示例#18
0
 def right(self) -> Vector:
     """
     Get the corner vector
     """
     self._attribute_gate(RIGHT, [LEFT, RIGHT])
     return Vector(float(self.parent.right), float(self))
示例#19
0
    def test_top_center(self):
        self.assertEqual(self.sprite.top.center, Vector(0, -0.5))

        self.sprite.top.center = (1, 1)
        self.assertEqual(self.sprite.top.center, Vector(1, 1))
示例#20
0
 def viewport_height(self, value: Union[int, float]):
     self._viewport_height = value
     self.viewport_offset = Vector(self.viewport_width / 2, value / 2)
示例#21
0
    def test_bottom_center(self):
        self.assertEqual(self.sprite.bottom.center, Vector(0, 0.5))

        self.sprite.bottom.center = (1, 1)
        self.assertEqual(self.sprite.bottom.center, Vector(1, 1))
示例#22
0
 class TestRotatable(Rotatable):
     _rotation = 180
     basis = Vector(0, 1)
示例#23
0
 class TestSprite(BaseSprite):
     position = Vector(4, 2)
示例#24
0
def test_camera_viewport():
    cam = Camera(viewport=(0, 0, 800, 600))
    assert cam.point_in_viewport(Vector(400, 400))
    assert not cam.point_in_viewport(Vector(900, 600))
    assert cam.viewport_offset == Vector(400, 300)
示例#25
0
 def center(self):
     if self.side in (TOP, BOTTOM):
         return Vector(self.parent.center.x, self.value)
     else:
         return Vector(self.value, self.parent.center.y)
示例#26
0
def test_camera_point_in_viewport_not_at_origin():
    cam = Camera(viewport=(100, 100, 800, 600))
    assert cam.point_in_viewport(Vector(150, 650))
    assert cam.point_in_viewport(Vector(899, 300))
    assert not cam.point_in_viewport(Vector(50, 50))
    assert not cam.point_in_viewport(Vector(901, 600))
示例#27
0
 def top(self):
     self._attribute_gate(TOP, [TOP, BOTTOM])
     return Vector(self.value, self.parent.top.value)
示例#28
0
def test_camera_move():
    cam = Camera()
    cam.position = Vector(500, 500)
    assert cam.position == Vector(500, 500)
    cam.position += Vector(100, 100)
    assert cam.position == Vector(600, 600)
示例#29
0
 def left(self):
     self._attribute_gate(LEFT, [LEFT, RIGHT])
     return Vector(self.parent.left.value, self.value)
示例#30
0
 def __init__(self, position=Vector(2, 2)):
     super().__init__()
     self.size = 2
     self.position = position