Exemple #1
0
class TemporaryEntity(Entity):
    defaults = {
        'width': 48,
        'height': 48,
    }

    attributes = {
        'image_file': 'app/assets/corpse.png',
        'chunk': None,
        'timer': 60
    }

    def init(self, **kwargs):
        self.image = load_image(self.image_file)
        self.sprite = Sprite(self.image, self.x, self.y,
                             batch=self.batch, group=self.group)
        self.chunk.objects.append(self)

        clock.schedule_once(self.delete, self.timer)

    def delete(self, dt):
        if self in self.chunk.objects:
            self.chunk.objects.remove(self)
        self.sprite.delete()

    def update(self):
        pass

    def draw(self):
        self.sprite.draw()
Exemple #2
0
class Scroll(object):
    def __init__(self, text, pos, batch):
        self.text = text
        x, y = self.pos = pos

        group = OrderedGroup(1)
        self.label = Label(text,
                           font_name=FONT_NAME,
                           font_size=28,
                           color=COLOUR,
                           x=x + 20,
                           y=y + 15,
                           group=group,
                           batch=batch)
        w = self.label.content_width + 40
        self.bg = ScrollBG(x, x + w, y, batch=batch, group=OrderedGroup(0))
        self.left = Sprite(scroll_left, x=x, y=y, group=group, batch=batch)
        self.right = Sprite(scroll_right,
                            x=x + w,
                            y=y,
                            group=group,
                            batch=batch)

    def delete(self):
        self.label.delete()
        self.left.delete()
        self.right.delete()
        self.bg.delete()
Exemple #3
0
class MapSpriteV2(SpriteV2, ABC):
    def __init__(self, logger, parent_viewport, map_id):
        super().__init__(logger, parent_viewport)
        self.map_id = map_id
        self.rotation = 0
        self.x = 0
        self.y = 0

    @final
    def on_update(self):
        if not self.sprite and self.is_located_inside_viewport():
            self.sprite = PygletSprite(self.texture,
                                       x=self.x,
                                       y=self.y,
                                       batch=self.batch,
                                       group=self.group,
                                       usage=self.usage,
                                       subpixel=self.subpixel)
            self.sprite.opacity = self.opacity
            self.sprite.rotation = self.rotation
        elif self.is_located_outside_viewport() and self.sprite:
            self.sprite.delete()
            self.sprite = None

    @final
    def on_position_update(self, x=0, y=0, rotation=0):
        self.x = x
        self.y = y
        self.rotation = rotation
        if self.sprite:
            self.sprite.update(x=self.x, y=self.y, rotation=self.rotation)

    @final
    def is_located_outside_viewport(self):
        return self.x - self.texture.anchor_x \
               - (MAP_CAMERA.offset_x + self.parent_viewport.x2) / MAP_CAMERA.zoom \
               > SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_X \
               or self.x + self.texture.width - self.texture.anchor_x \
               - (MAP_CAMERA.offset_x + self.parent_viewport.x1) / MAP_CAMERA.zoom \
               < -SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_X \
               or self.y - self.texture.anchor_y \
               - (MAP_CAMERA.offset_y + self.parent_viewport.y2) / MAP_CAMERA.zoom \
               > SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_Y \
               or self.y + self.texture.height - self.texture.anchor_y \
               - (MAP_CAMERA.offset_y + self.parent_viewport.y1) / MAP_CAMERA.zoom \
               < -SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_Y

    @final
    def is_located_inside_viewport(self):
        return not self.is_located_outside_viewport()
Exemple #4
0
 def value(self, value):
     new = min(self.display_max, value)
     delta = new - self.value
     self._value = value
     while delta > 0:
         sprite = Sprite(self.__class__.icon_img, y=self.y)
         self.icons.append(sprite)
         self.add_sprite(sprite, self.__class__.sprite_group)
         self.x = self.x
         delta -= 1
     while delta < 0:
         sprite = self.icons.pop()
         sprite.delete()
         delta += 1
Exemple #5
0
    class StockLabelElement(pyglet.text.document.InlineElement):
        """Ammunition image representing first character of a StockLabel.

        Center of ammunition image will be vertically alligned with center 
        of the StockLabel's text that follows it.
        """
        def __init__(self, image: pyglet.image.Texture, separation=2):
            """
            ++image++ Image representing ammunition type.
            ++separation++ distance between edge of image and subsequent 
                text, in pixels.
            """
            image = copy(image)
            image.anchor_x = 0
            image.anchor_y = 0

            self.image = image
            self.height = image.height
            super().__init__(ascent=0,
                             descent=0,
                             advance=image.width + separation)

        def place(self, layout, x: int, y: int):
            """Position ammunition image.
            
            +layout+ StockLabel object to which this StockLabelElement was 
                inserted. Layout should have anchor_y set to 'bottom' and 
                'content_valign' set to 'center'.
            +x+ Left edge of box reserved for in-line element and in which 
                ammunition image is to be positioned.
            +y+ Baseline level, on which layout text sits.
            """
            # Defines y at level so center of in-line image alligns vertically
            # with center of subsequent text, for which requires:
            # layout.anchor_y is'bottom' and layout_content_valign is 'center'
            y = layout.y + (layout.content_height //
                            2) - (self.image.anchor_y + (self.height // 2))
            self._sprite = Sprite(self.image,
                                  x,
                                  y,
                                  batch=layout.batch,
                                  group=layout.top_group)
            self._sprite.draw()

        def remove(self, layout):
            """Remove image from in-line element."""
            self._sprite.delete()
Exemple #6
0
class SpriteItem(GameItem):
    '''GameItem that is rendered as a single sprite'''

    images = None
    render_layer = 2 # birds and feathers


    def __init__(self, x=0, y=0):
        GameItem.__init__(self)
        self.x = x
        self.y = y
        self.rotation = 0

        self.sprite = None
        self.frame_idx = 0


    def add_to_batch(self, batch, groups):
        self.sprite = Sprite(
            self.images[self.frame_idx],
            batch=batch,
            group=groups[self.render_layer] )


    def remove_from_batch(self, batch):
        self.sprite.batch = None
        self.sprite.delete()


    def animate(self):
        self.sprite._x = self.x
        self.sprite._y = self.y
        self.sprite._rotation = degrees(self.rotation)
        image = self.images[self.frame_idx]
        if self.sprite.image != image:
            self.sprite.image = image
        else:
            self.sprite._update_position()
Exemple #7
0
class MuzzleFlash:
    def __init__(self, pos, rot, game):
        self.pos = pos

        self.rot = rot

        self.time = 0

        self.sprite = Sprite(game.muzzle_flash_img, batch=game.effects_batch)
        self.sprite.update(rotation=rot)
        self.sprite.image.anchor_x = self.sprite.width / 3
        self.sprite.image.anchor_y = self.sprite.height / 2
        self.dead = False

        self.sprite.x = pos.x
        self.sprite.y = pos.y

    def update(self, dt):
        self.time += dt

        if self.time > MUZZLE_FLASH_LIFESPAWN:
            self.sprite.delete()
            self.dead = True
Exemple #8
0
class Object(SpriteWrapper):

    sprite_img = None
    sprite_group = ''

    def __init__(self, x, y, hb=None):
        super().__init__()
        cls = self.__class__
        self.rect = primitives.Rect(0, 0, cls.sprite_img.width,
                cls.sprite_img.height)
        self.hb = hb
        self.sprite = Sprite(cls.sprite_img)
        self.add_sprite(self.sprite, cls.sprite_group)
        self.x, self.y = x, y

    @property
    def x(self):
        return self.rect.centerx

    @x.setter
    def x(self, value):
        self.rect.centerx = value
        if isinstance(self.hb, primitives.Circle):
            self.hb.x = value
        elif isinstance(self.hb, primitives.Rect):
            self.hb.centerx = value
        self.sprite.x = value

    @property
    def y(self):
        return self.rect.centery

    @y.setter
    def y(self, value):
        self.rect.centery = value
        if isinstance(self.hb, primitives.Circle):
            self.hb.y = value
        elif isinstance(self.hb, primitives.Rect):
            self.hb.centery = value
        self.sprite.y = value

    @property
    def left(self):
        return self.rect.left

    @left.setter
    def left(self, value):
        self.rect.left = value

    @property
    def right(self):
        return self.rect.right

    @right.setter
    def right(self, value):
        self.rect.right = value

    @property
    def top(self):
        return self.rect.top

    @top.setter
    def top(self, value):
        self.rect.top = value

    @property
    def bottom(self):
        return self.rect.bottom

    @bottom.setter
    def bottom(self, value):
        self.rect.bottom = value

    @property
    def center(self):
        return self.rect.center

    @center.setter
    def center(self, value):
        self.rect.center = value

    def delete(self):
        self.sprite.delete()

    def collide(self, other):
        if isinstance(other, Object):
            return self.hb.collide(other.hb)
        elif isinstance(other, Group):
            x = []
            for object in other:
                if self.collide(object):
                    x.append(object)
            return x
        else:
            raise NotImplementedError
Exemple #9
0
class InfoRow(object):
    """Row of Labels collectively providing player information.

    Provides information on:
        Lives, as images of player ship, one image per life remaining.
        Ammunition stock levels, as series of StockLabels associated with 
            each of player's weapons.
        Radiation level, as RadiationMonitor.gauge associated with player
        Score, as created score label.

    Information positioned right-to-left if player is blue, or from 
    left-to-right if red.

    METHODS
    --remove_a_life()--  Remove the life furthest from the screen edge.
    --update_score_label()--  Update score label
    --delete()--  Delete all objects that comprise InfoRow
    """

    _text_colors = {'blue': BLUE, 'red': RED}

    _radiation_symbol = load_image('radiation_20.png', anchor='origin')

    def __init__(self, window: pyglet.window.Window,
                 batch: pyglet.graphics.Batch, control_sys, num_lives: int,
                 level_label: Label):
        """
        ++window++ Window to which InfoRow to be displayed.
        ++batch++ Batch to which InfoRow objects to be added.
        ++control_sys++ .game_objects.ControlSystem of player for whom 
            providing information.
        ++num_lives++ Number of lives player starts with.
        ++level_label++ Label that expresses current level.
        """
        self._win = window
        self._info_row_base = self._win.height - 30
        self._batch = batch
        self._control_sys = control_sys
        self._color = self._control_sys.color
        self._text_color = self._text_colors[self._color]
        self._num_lives = num_lives
        self._lives = []
        self._level_label = level_label

        # Current position of _x, updated --_advance_x()-- as set objects
        self._x = self._win.width if self._color == 'blue' else 0

        self._set_lives()
        self._set_stocks_labels()
        self._set_radiation_gauge()
        self._create_score_label()

    def _advance_x(self, pixels: int):
        """Move _x by +pixels+ pixels in the direction that labels are being 
        sequentially placed.
        """
        pixels *= -1 if self._color == 'blue' else 1
        self._x += pixels

    def _get_object_x(self, obj: Union[Sprite, StockLabel]):
        """Return 'x' coordinate to place object at required separation on 
        from last object placed ASSUMING +obj+ is anchored to bottom left 
        and --_x-- positioned at the required spacing on from the last 
        object placed.
        """
        if self._color == 'blue':
            width = obj.content_width if isinstance(obj, StockLabel) \
                else obj.width
            return self._x - width
        else:
            return self._x

    def _set_object(self,
                    obj: Union[Sprite, StockLabel],
                    x: Optional[int] = None,
                    y: Optional[int] = None,
                    batch: Optional[pyglet.graphics.Batch] = None,
                    sep: int = 0):
        """Position and batch +obj+.
        
        Position and batch according to passed parameters, or according 
        to default behaviour otherwise. NB Default behaviour ASSUMES +obj+ 
        anchored to bottom left corner.
        """
        if sep is not 0:
            self._advance_x(sep)
        obj.batch = self._batch if batch is None else batch
        obj.y = self._info_row_base if y is None else y
        obj.x = self._get_object_x(obj) if x is None else x
        width = obj.content_width if isinstance(obj, StockLabel)\
            else obj.width
        self._advance_x(width)  # Leave _x at end of info row

    def _set_lives(self):
        for i in range(self._num_lives):
            img = copy(self._control_sys.ShipCls[self._color].img)
            img.anchor_x = 0
            img.anchor_y = 0
            life = Sprite(img)
            life.scale = 0.36
            self._lives.append(life)
            self._set_object(life, sep=3)

    def remove_a_life(self):
        """Remove the life image furthest from the screen edge."""
        self._lives.pop()

    def _set_stocks_labels(self):
        for weapon in self._control_sys.weapons:
            label = weapon.stock_label
            label.set(style_attrs={'color': self._text_color, 'bold': True})
            self._set_object(label, sep=10)
            label.positioned()

    def _set_radiation_gauge(self):
        self._set_object(self._control_sys.radiation_monitor.gauge, sep=15)
        self._rad_symbol = Sprite(self._radiation_symbol)
        self._set_object(self._rad_symbol, sep=5)

    def _score_label_x_coordinate(self) -> int:
        """Returns x coordinate for score label to position to side of level 
        label.
        """
        direction = 1 if self._color == 'blue' else -1
        dist = (self._level_label.content_width // 2) + 34
        x = self._level_label.x + (dist * direction)
        return x

    def _create_score_label(self):
        self._score_label = Label('0',
                                  x=self._score_label_x_coordinate(),
                                  y=self._win.height,
                                  font_size=30,
                                  bold=True,
                                  batch=self._batch,
                                  anchor_x='center',
                                  anchor_y='top')
        self._score_label.set_style('color', self._text_color)

    def update_score_label(self, score: int):
        """Update score label to +score+."""
        self._score_label.text = str(score)

    def delete(self):
        """Delete all objects that comprise InfoRow."""
        for life in self._lives:
            life.delete()
        for weapon in self._control_sys.weapons:
            weapon.stock_label.delete()
        self._score_label.delete()
        self._control_sys.radiation_monitor.gauge.delete()
        self._rad_symbol.delete()
Exemple #10
0
class Player(InertialObject):
    def __init__(self, name="", hull_image=None, engine_image=None,
                 x=0.0, y=0.0, thrust=200.0, maneuvering_thrust=360.0,
                 weapon_projectile_image=None, weapon_projectile_speed=700.0,
                 *args, **kwargs):

        super(Player, self).__init__(img=hull_image, name=name,
                                     vulnerable=True, x=x, y=y,
                                     *args, **kwargs)

        self.engineflame = Sprite(img=engine_image, x=x, y=y, *args, **kwargs)
        self.engineflame.visible = False

        self.thrust = thrust
        self.maneuvering_thrust = maneuvering_thrust

        self.weapon_projectile_image = weapon_projectile_image
        self.weapon_projectile_speed = weapon_projectile_speed

        self.center_x = x
        self.center_y = y

        self.key_handler = key.KeyStateHandler()

    def fire(self):
        angle_radians = math.radians(self.rotation)
        ship_radius = self.image.width/2 + 5.0
        bullet_x = self.x + math.sin(angle_radians) * ship_radius
        bullet_y = self.y + (math.cos(angle_radians) * ship_radius)
        new_bullet = Projectile(name="bullet",
                                img=self.weapon_projectile_image,
                                x=bullet_x, y=bullet_y, batch=self.batch)
        new_bullet.velocity_x = (
            self.velocity_x +
            math.sin(angle_radians) * self.weapon_projectile_speed
        )
        new_bullet.velocity_y = (
            self.velocity_y +
            math.cos(angle_radians) * self.weapon_projectile_speed
        )
        self.new_objects.append(new_bullet)

    def update(self, dt):
        rotational_dv = self.maneuvering_thrust * dt
        propulsive_dv = self.thrust * dt

        modified_rot_speed = self.rotation_speed
        if self.key_handler[key.RIGHT]:
            modified_rot_speed += rotational_dv
        if self.key_handler[key.LEFT]:
            modified_rot_speed -= rotational_dv
        if self.key_handler[key.DOWN]:
            direction = 1.0
            if self.rotation_speed < 0:
                direction = -1.0
            abs_rotation = modified_rot_speed * direction
            modified_rot_speed = direction * (abs_rotation - rotational_dv)
            if (direction * modified_rot_speed) < 0:
                modified_rot_speed = 0.0
        if self.key_handler[key.SPACE]:
            self.fire()

        # interpolate accelerated rotation change
        self.rotation_speed = (modified_rot_speed + self.rotation_speed) / 2.0

        modified_vx = self.velocity_x
        modified_vy = self.velocity_y
        if self.key_handler[key.UP]:
            angle_radians = math.radians(self.rotation)
            modified_vx += math.sin(angle_radians) * propulsive_dv
            modified_vy += math.cos(angle_radians) * propulsive_dv
            self.engineflame.visible = True
        else:
            self.engineflame.visible = False

        # iterpolate accelerated velocity change
        self.velocity_x = (modified_vx + self.velocity_x) / 2.0
        self.velocity_y = (modified_vy + self.velocity_y) / 2.0

        super(Player, self).update(dt)

        # update subsprites
        self.engineflame.x = self.x
        self.engineflame.y = self.y
        self.engineflame.rotation = self.rotation

        self.rotation_speed = modified_rot_speed
        self.velocity_x = modified_vx
        self.velocity_y = modified_vy

        if self.key_handler[key.C]:
            self.x = self.center_x
            self.y = self.center_y
            self.velocity_x = 0.0
            self.velocity_y = 0.0
            self.rotation = 0.0
            self.rotation_speed = 0.0

    def delete(self):
        self.engineflame.delete()
        super(Player, self).delete()
Exemple #11
0
class MobileEntity(Entity):
    defaults = {
        'collidable': True,
        'mobile': True,
        'width': 50,
        'height': 50,
        'stat_modifiers': {
            'str': 0,
            'dex': 0,
            'wis': 0,
            'int': 0,
            'con': 0,
            'lck': 0
        }
    }

    attributes = {
        'dead': False,
        'image_file': 'app/assets/zombie.png',
        'moving_to': None,
        'chunk': None,
        'sprinting': False,
        'in_combat': False,
        #'in_combat_with': [],
        'attack_cooldown': 0,
        'projectile_cooldown': 0,
        'damage_text_color': (255, 255, 255, 255),
        'chunk_container': 'npcs'
    }

    overwrite = {}

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

    def init(self, **kwargs):
        self.in_combat_with = []
        self.image = load_image(self.image_file)
        self.sprite = Sprite(self.image, self.x, self.y)
        self.hp_image = load_image('app/assets/healthbar.png')
        self.hp_sprite = Sprite(self.hp_image, self.x + 1,
                                self.y + self.height + 5)
        self.set_sprite_render(self.group)
        self.stats = Stats(modifiers=self.stat_modifiers)

        entity_container = getattr(self.chunk, self.chunk_container)
        if self.chunk and self not in entity_container:
            entity_container.append(self)

        self.post_init(**kwargs)

    def pre_init(self, **kwargs):
        self.attributes = {**self.attributes, **self.overwrite}

    def post_init(self, **kwargs):
        pass

    def set_sprite_render(self, group):
        self.sprite.batch = self.chunk.draw_batch
        self.sprite.group = group
        self.hp_sprite.batch = self.chunk.draw_batch
        self.hp_sprite.group = group

    @property
    def speed(self):
        walk_speed = self.stats.dex // 3
        if self.sprinting:
            return walk_speed * config.sprint_modifier
        return walk_speed

    def check_state(self):
        if self.dead:
            self.on_death()
        elif self.in_combat:
            if not self.in_combat_with:
                self.in_combat = False
            else:
                self.do_combat()
        else:
            self.do_idle()

    def on_death(self):
        print(f'{self.name} died!')
        if self.in_combat:
            for entity in self.in_combat_with:
                if self in entity.in_combat_with:
                    entity.in_combat_with.remove(self)
        self.remove_from_chunk()
        self.sprite.delete()
        self.hp_sprite.delete()
        self.after_death()

    def remove_from_chunk(self):
        if self.chunk:
            container = getattr(self.chunk, self.chunk_container)
            if self in container:
                container.remove(self)

    def after_death(self):
        pass

    def do_combat(self):
        pass

    def do_idle(self):
        pass

    def check_bounds(self):
        if (self.x + self.width) > config.window_width:
            self.out_of_bounds('e')
        elif self.x < 0:
            self.out_of_bounds('w')
        elif (self.y + self.height) > config.window_height:
            self.out_of_bounds('n')
        elif self.y < 0:
            self.out_of_bounds('s')

    def out_of_bounds(self, direction):
        pass

    def on_collision(self, obj):
        x_intersect = calc_1D_intersect(*self.x_1D, *obj.x_1D)
        y_intersect = calc_1D_intersect(*self.y_1D, *obj.y_1D)

        if x_intersect < y_intersect:
            if self.x < obj.x:
                self.x = obj.x - self.width
            else:
                self.x = obj.x + obj.width
        else:
            if self.y < obj.y:
                self.y = obj.y - self.height
            else:
                self.y = obj.y + obj.height
        self.after_collision(obj)

    def after_collision(self, obj):
        pass

    def attack(self):
        if not self.attack_cooldown:
            atk_range = 75
            for entity in self.chunk.attackable_objects:
                if entity is not self:
                    if distance(*self.coord, *entity.coord) < atk_range:
                        self.in_combat = True
                        if entity not in self.in_combat_with:
                            self.in_combat_with.append(entity)
                        self.do_damage(entity, d6(num=self.stats.str // 2))
                        self.attack_cooldown = 50

    def do_damage(self, target, dmg):
        target.take_damage(self, dmg)

    def take_damage(self, source, dmg):
        dmg_text = Label(f'{dmg}',
                         x=randint((self.x - 5) // 1,
                                   (self.x + self.width + 5) // 1),
                         y=self.y + self.height + 15,
                         font_name='courier new',
                         color=self.damage_text_color,
                         bold=True,
                         batch=self.chunk.draw_batch,
                         group=self.chunk.foreground)
        clock.schedule_once(lambda df: dmg_text.delete(), 0.5)

        if (source is not None) and (source is not self):
            self.in_combat = True
            if source not in self.in_combat_with:
                self.in_combat_with.append(source)

        self.stats.hp -= dmg
        if self.stats.hp < 1:
            self.dead = True

        print(
            f'{self.name} ({self.stats.hp}/{self.stats.base_hp}) took {dmg} damage from {source.name}!'
        )

    def fire_proj(self):
        velocity = 10
        p_x = self.cursor_coord.x - self.center.x
        p_y = self.cursor_coord.y - self.center.y
        d = distance(self.center.x, self.center.y, self.cursor_coord.x,
                     self.cursor_coord.y)
        r = velocity / d
        r_p = 30 / d
        if not self.projectile_cooldown:
            proj = Projectile(owner=self,
                              chunk=self.chunk,
                              x=self.center.x + p_x * r_p,
                              y=self.center.y + p_y * r_p,
                              damage=d20(num=self.stats.int // 3),
                              velocity_x=p_x * r,
                              velocity_y=p_y * r,
                              batch=self.chunk.draw_batch,
                              group=self.chunk.foreground)
            self.chunk.objects.append(proj)
            self.projectile_cooldown = 10

    def update_cooldowns(self):
        if self.attack_cooldown > 0:
            self.attack_cooldown -= 1
        if self.projectile_cooldown > 0:
            self.projectile_cooldown -= 1

    def move(self):
        if self.moving_to:
            dist_from_target = np.sqrt((self.x - self.moving_to.x)**2 +
                                       (self.y - self.moving_to.y)**2)

            if dist_from_target <= self.speed:
                self.x = self.moving_to.x
                self.y = self.moving_to.y
            else:
                dist_ratio = self.speed / dist_from_target
                self.x = (1.0 -
                          dist_ratio) * self.x + dist_ratio * self.moving_to.x
                self.y = (1.0 -
                          dist_ratio) * self.y + dist_ratio * self.moving_to.y

    def update_sprites(self):
        self.sprite.update(x=self.x, y=self.y)
        self.hp_sprite.update(x=self.x + 1,
                              y=self.y + self.height + 5,
                              scale_x=self.stats.hp / self.stats.base_hp)

    def update(self):
        self.check_state()
        if not self.dead:
            self.update_cooldowns()
            self.move()
            self.check_bounds()
            self.update_sprites()
        else:
            self.after_death()

    def draw(self):
        self.sprite.draw()
Exemple #12
0
class Character(object):

    def __init__(self, x, y, facing=Direction.NORTH):
        self.sprite = Sprite(self.Sprite.faces[facing], x, y)
        self.facing = facing
        self.movement_queue = []
        self.movement_ticks = 0

        self.current_health = self.health

    def draw(self):
        self.sprite.draw()

    def delete(self):
        self.sprite.delete()

    @property
    def x(self):
        return self.sprite.x

    @x.setter
    def x(self, nx):
        self.sprite.x = nx

    @property
    def y(self):
        return self.sprite.y

    @y.setter
    def y(self, ny):
        self.sprite.y = ny

    @property
    def color(self):
        return self.sprite.color

    @color.setter
    def color(self, ncolor):
        self.sprite.color = ncolor

    def look(self, direction):
        self.facing = direction
        self.sprite.image = self.Sprite.faces[direction]

    def move_to(self, x, y, duration=1):
        self.movement_queue.append((x, y, duration))

    def update(self, dt):
        if self.movement_queue:
            if self.movement_ticks == 0:
                self.last_stop = self.x, self.y
            ex, ey, time = self.movement_queue[0]
            sx, sy = self.last_stop
            if ex < sx and ey < sy:
                self.look(Direction.WEST)
            elif ex < sx:
                self.look(Direction.NORTH)
            elif ey < sy:
                self.look(Direction.SOUTH)
            else:
                self.look(Direction.EAST)
            self.movement_ticks += dt
            ex, ey, time = self.movement_queue[0]
            sx, sy = self.last_stop
            self.x += (ex - sx) * (dt / time)
            self.y += (ey - sy) * (dt / time)

            if self.movement_ticks >= time:
                self.x, self.y = int(ex), int(ey)
                del self.movement_queue[0]
                self.movement_ticks = 0
        else:
            self.look(self.facing)


    class Sprite(namedtuple("CharacterSprite", "x y facing moving_to internal_clock")):
#
#        @property
#        def image(self):
#            return self.faces[self.facing]
#
#        def update(self, dt):
#            return self.__class__(self.x, self.y, self.facing, self.moving_to, self.internal_clock + dt)
#
#        def move(self, new_x, new_y):
            pass
Exemple #13
0
class Player(Object):

    sprite_img = None
    sprite_group = 'player'
    hb_img = None
    hb_group = 'player_hb'
    _die_invuln = 3

    def __init__(self, x, y, hb=None):
        super().__init__(x, y, hb=hb)
        self._focus = 0
        self.speed_multiplier = 500
        self.focus_multiplier = 0.5
        self.shooting = 0
        self.shot_rate = 20
        self.shot_state = 0
        self.bullets = BulletGroup()
        self.invuln = 0
        self.v = Vector(0, 0)
        self.hbsprite = None

    @property
    def x(self):
        return super().x

    @x.setter
    def x(self, value):
        super(Player, self.__class__).x.fset(self, value)
        if hasattr(self, 'hbsprite') and self.hbsprite is not None:
            self.hbsprite.x = value

    @property
    def y(self):
        return super().y

    @y.setter
    def y(self, value):
        super(Player, self.__class__).y.fset(self, value)
        if hasattr(self, 'hbsprite') and self.hbsprite is not None:
            self.hbsprite.y = value

    @property
    def speed(self):
        if self.focus:
            return self.speed_multiplier * self.focus_multiplier
        else:
            return self.speed_multiplier

    @property
    def focus(self):
        return int(self._focus)

    @focus.setter
    def focus(self, value):
        f = self.focus
        v = bool(value)
        if f != v:
            self._focus = v
            if v:
                cls = self.__class__
                self.hbsprite = Sprite(cls.hb_img, self.x, self.y)
                self.add_sprite(self.hbsprite, cls.hb_group)
            else:
                self.hbsprite.delete()
                self.hbsprite = None

    def die(self):
        if self.invuln > 0:
            return 1
        else:
            self.invuln += Player._die_invuln
            return 0

    def on_key_press(self, symbol, modifiers):
        if symbol == key.LSHIFT:
            self.focus = 1
        elif symbol == key.Z:
            self.shooting = 1

    def on_key_release(self, symbol, modifiers):
        if symbol == key.LSHIFT:
            self.focus = 0
        elif symbol == key.Z:
            self.shooting = 0

    def update(self, dt):
        # movement
        self.x += self.speed * self.v.x * dt
        self.y += self.speed * self.v.y * dt
        # bound movement
        if self.right > GAME_AREA.right:
            self.right = GAME_AREA.right
        elif self.left < GAME_AREA.left:
            self.left = GAME_AREA.left
        if self.bottom < GAME_AREA.bottom:
            self.bottom = GAME_AREA.bottom
        elif self.top > GAME_AREA.top:
            self.top = GAME_AREA.top
        # invuln
        if self.invuln > 0:
            self.invuln -= dt
        # bullet generation
        if self.shooting:
            self.shot_state += dt
            self.update_fire(dt)
        # bullet update
        self.bullets.update(dt)
        self.add_sprites(self.bullets)

    def update_fire(self, dt):
        pass
Exemple #14
0
class RectangleProgressBarV2(UIObject, ABC):
    def __init__(self, logger, parent_viewport):
        super().__init__(logger, parent_viewport)
        self.inactive_image = None
        self.inactive_sprite = None
        self.active_image = None
        self.active_sprite = None
        self.current_percent = 0

    @abstractmethod
    def get_position(self):
        pass

    @abstractmethod
    def get_scale(self):
        pass

    @final
    @is_not_active
    def on_activate(self):
        super().on_activate()
        if not self.inactive_sprite:
            self.inactive_sprite = Sprite(self.inactive_image,
                                          x=self.viewport.x1,
                                          y=self.viewport.y1,
                                          batch=BATCHES['ui_batch'],
                                          group=GROUPS['button_background'])

        self.inactive_sprite.scale = self.get_scale()
        self.inactive_sprite.opacity = self.opacity
        if self.current_percent == 0:
            image_region = self.active_image.get_region(
                self.active_image.height // 2, self.active_image.height // 2,
                1, 1)
        else:
            image_region = self.active_image.get_region(
                0, 0, self.current_percent * self.active_image.width // 100,
                self.active_image.height)

        if not self.active_sprite:
            self.active_sprite = Sprite(image_region,
                                        x=self.viewport.x1,
                                        y=self.viewport.y1,
                                        batch=BATCHES['ui_batch'],
                                        group=GROUPS['button_text'])
        else:
            self.active_sprite.image = image_region

        self.active_sprite.scale = self.get_scale()
        self.active_sprite.opacity = self.opacity

    @final
    @window_size_has_changed
    def on_window_resize(self, width, height):
        super().on_window_resize(width, height)
        self.viewport.x1, self.viewport.y1 = self.get_position()
        self.viewport.x2 = self.viewport.x1 + int(
            self.inactive_image.width * self.get_scale())
        self.viewport.y2 = self.viewport.y1 + int(
            self.inactive_image.height * self.get_scale())
        if self.inactive_sprite:
            self.inactive_sprite.position = (self.viewport.x1,
                                             self.viewport.y1)
            self.inactive_sprite.scale = self.get_scale()

        if self.active_sprite:
            self.active_sprite.position = (self.viewport.x1, self.viewport.y1)
            self.active_sprite.scale = self.get_scale()

    @final
    def on_update_opacity(self, new_opacity):
        self.opacity = new_opacity
        if self.opacity <= 0:
            if self.inactive_sprite:
                self.inactive_sprite.delete()
                self.inactive_sprite = None

            if self.active_sprite:
                self.active_sprite.delete()
                self.active_sprite = None
        else:
            if self.inactive_sprite:
                self.inactive_sprite.opacity = self.opacity

            if self.active_sprite:
                self.active_sprite.opacity = self.opacity

    @final
    def on_update_progress_bar_state(self, current_value, maximum_value):
        if maximum_value == 0:
            self.current_percent = 0
        else:
            self.current_percent = int(current_value / maximum_value * 100)
            if self.current_percent > 100:
                self.current_percent = 100

        if self.is_activated:
            if self.current_percent == 0:
                self.active_sprite.image = self.active_image.get_region(
                    self.active_image.height // 2,
                    self.active_image.height // 2, 1, 1)
            else:
                self.active_sprite.image = self.active_image.get_region(
                    0, 0,
                    self.current_percent * self.active_image.width // 100,
                    self.active_image.height)
Exemple #15
0
class Grenade:
    def __init__(self, game, type, owner=False):
        self.game = game

        self.type = type

        self.explode = False

        self.tossed = False

        self.duration = 0
        self.opacity = 255

        self.sent = False

        self.owner = owner

    def throw(self, pos, vel, rot, o=False):
        self.distance = 0
        self.pos = pos
        self.vel = vel.rotate(-rot)

        if self.type == "grenade":
            self.sprite = Sprite(self.game.granade_img,
                                 pos.x,
                                 pos.y,
                                 batch=self.game.main_batch)

        elif self.type == "smoke":
            self.sprite = Sprite(self.game.smoke_img,
                                 pos.x,
                                 pos.y,
                                 batch=self.game.main_batch)

        self.sprite.image.anchor_x = self.sprite.width / 2
        self.sprite.image.anchor_y = self.sprite.height / 2

        self.explode_sprite = None

        self.hit_box = GRENADE_HIT_BOX.copy()
        self.hit_box.x = pos.x - self.hit_box.width / 2
        self.hit_box.y = pos.y - self.hit_box.height / 2

        self.tossed = True

        if o is True:
            self.game.grenades.append(self)

        self.game.o_grenades.append({
            "pos": {
                "x": pos.x,
                "y": pos.y
            },
            "vel": {
                "x": vel.x,
                "y": vel.y
            },
            "rot": rot,
            "type": self.type
        })

    def collide_with_walls(self, dir):
        if dir == "x":
            for wall in self.game.walls:
                if (self.hit_box.x + self.hit_box.width > wall.pos.x
                        and self.hit_box.y + self.hit_box.height > wall.pos.y
                    ) and (self.hit_box.x < wall.pos.x + wall.width
                           and self.hit_box.y < wall.pos.y + wall.height):
                    if wall.center.x > self.hit_box.get_center().x:
                        self.hit_box.x = wall.pos.x - self.hit_box.width

                    elif wall.center.x < self.hit_box.get_center().x:
                        self.hit_box.x = wall.pos.x + wall.width

                    self.vel.x = -self.vel.x

        elif dir == "y":
            for wall in self.game.walls:
                if (self.hit_box.x + self.hit_box.width > wall.pos.x
                        and self.hit_box.y + self.hit_box.height > wall.pos.y
                    ) and (self.hit_box.x < wall.pos.x + wall.width
                           and self.hit_box.y < wall.pos.y + wall.height):
                    if wall.center.y > self.hit_box.get_center().y:
                        self.hit_box.y = wall.pos.y - self.hit_box.height

                    elif wall.center.y < self.hit_box.get_center().y:
                        self.hit_box.y = wall.pos.y + wall.height

                    self.vel.y = -self.vel.y

    def draw_hit_box(self):
        glBegin(GL_LINES)

        glVertex2i(int(self.hit_box.x), int(self.hit_box.y))
        glVertex2i(int(self.hit_box.x),
                   int(self.hit_box.y + self.hit_box.height))

        glVertex2i(int(self.hit_box.x),
                   int(self.hit_box.y + self.hit_box.height))
        glVertex2i(int(self.hit_box.x + self.hit_box.width),
                   int(self.hit_box.y + self.hit_box.height))

        glVertex2i(int(self.hit_box.x + self.hit_box.width),
                   int(self.hit_box.y + self.hit_box.height))
        glVertex2i(int(self.hit_box.x + self.hit_box.width),
                   int(self.hit_box.y))

        glVertex2i(int(self.hit_box.x + self.hit_box.width),
                   int(self.hit_box.y))
        glVertex2i(int(self.hit_box.x), int(self.hit_box.y))

        glEnd()

    def update(self, dt):
        if self.distance <= GRENADE_DISTANCE and self.tossed:
            # check hit box collisions
            self.hit_box.x += self.vel.x * dt
            self.collide_with_walls("x")

            self.hit_box.y += self.vel.y * dt
            self.collide_with_walls("y")

            self.pos.x = self.hit_box.x + self.hit_box.width / 2
            self.pos.y = self.hit_box.y + self.hit_box.height / 2

            self.sprite.x = self.pos.x
            self.sprite.y = self.pos.y

            self.distance += self.vel.magnitude() * dt

        else:
            if self.explode is False:
                self.sprite.delete()

                self.vel.multiply(0)
                self.explode = True
                if self.type == "grenade":
                    self.explode_sprite = Animation(
                        self.game.explosion_anim,
                        self.pos.x,
                        self.pos.y,
                        batch=self.game.effects_batch)

                elif self.type == "smoke":
                    self.explode_sprite = Animation(
                        self.game.smoke,
                        self.pos.x,
                        self.pos.y,
                        batch=self.game.effects_batch)

                    self.duration = SMOKE_DURATION

                self.explode_sprite.x = self.pos.x - self.explode_sprite.width / 2
                self.explode_sprite.y = self.pos.y - self.explode_sprite.height / 2

        if self.type == "smoke" and self.explode is True:
            if self.duration <= 0:
                if self.opacity <= 0:
                    self.explode_sprite.deleted = True

                self.explode_sprite.opacity = self.opacity
                if self.opacity > 0:
                    self.opacity -= int(300 * dt)

            else:
                self.duration -= dt
class Player(physicalobject.PhysicalObject):
    """Physical player object"""
    def __init__(self,*args, **kwargs):
        super().__init__(img=resources.player_image, *args, **kwargs)
        del kwargs['screen_size'] # remove screen_size for sprite usage

        self.engine_sprite = Sprite(img=resources.engine_image, *args, **kwargs)
        self.engine_sprite.visible = False

        self.engine_sound = resources.engine_sound
        self.engine_player = pyglet.media.Player()
        self.engine_player.queue(self.engine_sound)
        self.engine_player.volume = 0
        self.engine_player.eos_action = pyglet.media.Player.EOS_LOOP

        self.shield = shield.Shield(self.batch)
        self.shield_sound = resources.shield_sound


        # vector mechanics
        self.thrust = 100.0
        self.recoil = 200.0

        # rotational mechanics
        self.max_rotation = 250
        self.rotation_speed = 0
        self.rotation_force = 2.0
        self.rotation_resistance = 2.5

        self.ship_radius = self.image.width/2

        self.key_handler = key.KeyStateHandler()
        self.event_handlers += [self, self.key_handler]

        self.score_dif = -25

        self.reacts_to_bullets = False
        self.bullet_speed = 750.0
        self.bullet_sound = resources.bullet_sound
        self.loaded = True


    def update(self, dt):
        super().update(dt)


        right = self.key_handler[key.RIGHT]
        left = self.key_handler[key.LEFT]

        def _apply_resistance(modifier=0):
            """Slows down ship rotation"""
            if self.rotation_speed < 0.0:
                self.rotation_speed += (modifier + self.rotation_resistance) * dt
            if self.rotation_speed > 0.0:
                self.rotation_speed -= (modifier + self.rotation_resistance) * dt

        if left and right:
            modifier = self.rotation_force
            _apply_resistance(modifier/2)

        elif right:
            self.rotation_speed += self.rotation_force * dt

        elif left:
            self.rotation_speed -= self.rotation_force * dt
        
        else:
            _apply_resistance()


        if self.rotation > -360:
            self.rotation += 360
        elif self.rotation < 360:
            self.rotation -= 360


        # rotate ship
        self.rotation += self.rotation_speed

        if self.key_handler[key.UP]:
            angle_radians = -math.radians(self.rotation)
            force_x = math.cos(angle_radians) * self.thrust * dt
            force_y = math.sin(angle_radians) * self.thrust * dt
            self.velocity_x += force_x
            self.velocity_y += force_y

            self.engine_sprite.rotation = self.rotation
            self.engine_sprite.x = self.x
            self.engine_sprite.y = self.y
            self.engine_sprite.visible = True

            # smooth sound ==
            self.engine_player.play()
            if self.engine_player.volume < 1.8:
                self.engine_player.volume += 1.2 * dt
        else:
            self.engine_sprite.visible = False
            if self.engine_player.volume > 0.01:
                self.engine_player.volume -= 1.5 * dt
            else:
                self.engine_player.pause()
            # ===============



        if self.invulnerable:
            self.shield.up = True
        else:
            self.shield.up = False

        self.shield.x = self.x
        self.shield.y = self.y
        self.shield.update(dt)


        if self.key_handler[key.SPACE]:
            # fires has long has space is held
            self.fire(dt)


    """Methods that control shield invulnerability
    Can take 1 argument, deltatime(dt), invulnerability leght"""
    def set_invulnerable(self, dt=5.0):
        self.shield_sound.play()
        self.invulnerable = True

        # time to vulnerable
        pyglet.clock.schedule_once(self.set_vulnerable, dt)
    def set_vulnerable(self, dt):
        self.invulnerable = False


    def fire(self, dt):
        # fires only if loaded
        if self.loaded:
            angle_radians = -math.radians(self.rotation)
            force_x = math.cos(angle_radians) * self.recoil * dt
            force_y = math.sin(angle_radians) * self.recoil * dt
            self.velocity_x -= force_x
            self.velocity_y -= force_y

            angle_radians = -math.radians(self.rotation)

            ship_radius = self.ship_radius
            bullet_x = self.x + math.cos(angle_radians) * ship_radius
            bullet_y = self.y + math.sin(angle_radians) * ship_radius
            new_bullet = bullet.Bullet(screen_size=self.screen_size,
                                x=bullet_x, y=bullet_y, batch=self.batch)

            bullet_vx = (self.velocity_x +
                math.cos(angle_radians) * self.bullet_speed)
            bullet_vy = (self.velocity_y +
                math.sin(angle_radians) * self.bullet_speed)
            new_bullet.velocity_x = bullet_vx
            new_bullet.velocity_y = bullet_vy

            self.bullet_sound.play()
            self.new_objects.append(new_bullet)

            # unloading gun
            self.loaded = False
            pyglet.clock.schedule_once(self.reload, 0.1)

    def reload(self, dt):
        self.loaded = True

    #def on_key_press(self, symbol, modifiers):
    ## single short fire
    #    if symbol == key.SPACE:
    #        self.fire()

    def delete(self):
        self.shield.delete()
        self.engine_sprite.delete()
        self.engine_player.delete()
        super().delete()
Exemple #17
0
class GameUI(GameObject):
    """In game UI that shows score etc."""
    def __init__(self,
                 *,
                 player: Player,
                 space: pymunk.Space,
                 ui_batch=None,
                 background_batch=None):
        super().__init__()

        self.player = player
        self.space = space
        self.background_batch = background_batch

        self.danger_sprite = Sprite(img=resources.danger_image,
                                    batch=background_batch,
                                    x=128,
                                    y=128)
        self.danger_sprite.visible = False

        # Internal score modified by the property below
        self._score = 0
        # Show the score
        self.score_label = Label('',
                                 font_name='m5x7',
                                 font_size=48,
                                 x=WIDTH - 10,
                                 y=HEIGHT,
                                 anchor_x='right',
                                 anchor_y='top',
                                 batch=ui_batch)
        # "call" the property setter below
        self.score = self._score

    def tick(self, dt: float):
        # Don't show danger sprite by default
        self.danger_sprite.visible = False
        # Okay so to find out where to possibly show the danger sprite
        # We need to do a ray cast from the center of the map to the player
        # And when we hit a wall, that is where it would be shown if it is close enough to the player
        # The reason we need this, is that the logic for snapping from the players position to a wall position
        # without raycasting in the case of corners (where two walls meet) is quite complicated so this is simply easier

        # get some preliminary start and end points
        start = Vec2d(WIDTH, HEIGHT) / 2
        end = (self.player.pos - start)
        # We can't divide by 0, so make sure the player has moved away from the center
        if end.get_length_sqrd() > 0:
            # Then set the length to be the diagonal of the screen, so that the ray will always hit a wall somewhere
            end.length = math.sqrt(WIDTH**2 + HEIGHT**2)
            # Remove the start as we don't want vector relative to the center of the screen but rather proper coords
            end += start
            # Raycast, finding only wall sensors
            results = self.space.segment_query(
                start, end, 1,
                pymunk.ShapeFilter(mask=CollisionType.WallSensor))
            # If we hit something
            if results:
                # Find our distance to it
                wall_result = results[0]
                distance = (self.player.pos - wall_result.point).length
                # And if our distance is less than half of danger_sprite's width/height
                if distance < self.danger_sprite.width / 2:
                    # Show the sprite with increasing opacity as player nears wall
                    self.danger_sprite.visible = True
                    self.danger_sprite.opacity = min(
                        valmap(distance, self.danger_sprite.width / 2, 0, 0,
                               255), 255)
                    self.danger_sprite.x = wall_result.point.x
                    self.danger_sprite.y = wall_result.point.y

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        self._score = value
        # Update the label text with the new score
        self.score_label.text = f'Score: {self._score}'

    def delete(self):
        self.score_label.delete()
        self.danger_sprite.delete()
        super().delete()
Exemple #18
0
class Enemy(Creature):
    def __init__(self,
                 tex_name,
                 tile_width,
                 tile_height,
                 game_state,
                 xpos=0,
                 ypos=0,
                 group=None,
                 health=3,
                 move_pattern=unlucky,
                 move_params=(),
                 name='enemy',
                 gold=1,
                 exp=1,
                 hitsound='bandit_hit',
                 damage=1):
        super().__init__(tex_name,
                         tile_width,
                         tile_height,
                         game_state,
                         xpos=xpos,
                         ypos=ypos,
                         group=group,
                         damage=damage,
                         health=health,
                         name=name,
                         hitsound=hitsound)

        self.is_guard = 'guard' in tex_name
        if type(move_pattern) == str:
            self.move_pattern = patterns[move_pattern](self, *move_params)
        else:
            self.move_pattern = move_pattern(self, *move_params)
        self.game.enemies.add(self)
        self.stats[G] = gold
        self.stats[EXP] = exp
        self.healthbar = Sprite(create(24, 4, SolidColorImagePattern(RED)),
                                x=self.x,
                                y=self.y,
                                batch=self.batch,
                                group=self.game.groups[1])

    def move(self):
        dx, dy = next(self.move_pattern)
        new_x = self.xpos + dx
        new_y = self.ypos + dy

        collision = [
            e for e in (self.game.enemies - {self}) | {self.game.pc}
            if new_x == e.xpos and new_y == e.ypos
        ]
        if collision != [] and collision[0] is self.game.pc:
            self.attack(collision[0])
        elif (collision == [] and 0 < new_x < self.game.width - 1
              and 0 < new_y < self.game.height - 1
              and self.game.map[new_y][new_x] in tile.TRAVERSABLE):
            self.xpos += dx
            self.ypos += dy
            self.update_pos()

    def on_damage(self, damage, source: Creature):
        super().on_damage(damage, source)
        if self.stats[HP] <= 0:
            self.game.enemies.remove(self)
            if source == self.game.pc:
                source.stats[G] += self.stats[G]
                source.stats[EXP] += self.stats[EXP]
            self.delete()
            return None
        self.healthbar.scale_x = self.stats[HP] / self.stats[HPMAX]
        self.healthbar.draw()

    def update_pos(self):
        super().update_pos()
        self.healthbar.x = self.x
        self.healthbar.y = self.y

    def delete(self):
        self.healthbar.delete()
        return super().delete()

    @staticmethod
    def from_json(path, game, xp=0, yp=0):
        with open(path, 'r') as json:
            base_stats = loads(''.join(json.readlines()))

        if xp == yp == 0:
            xp, yp = get_clear_tile(game)
        ret = Enemy(tile_height=24,
                    tile_width=24,
                    game_state=game,
                    xpos=xp,
                    ypos=yp,
                    **base_stats)
        for stat in LEVELED_STATS:
            ret.stats[stat] *= 1 + LEVELING_FACTOR * \
                game.stage * (2 * game.difficulty + 1)
        for stat in RANDOMIZED_STATS:
            ret.stats[stat] *= normalvariate(1, VAR)
        for stat in LEVELED_STATS | RANDOMIZED_STATS:
            ret.stats[stat] = int(ret.stats[stat])
Exemple #19
0
class Player(PhysicalObject):
    """
    Player class
    """
    def __init__(self, *args, **kwargs):
        super(Player, self).__init__(img=player_image, *args, **kwargs)

        # Name
        self.name = 'Player'

        # Bullets
        self._num_bullets = 0

        # Thrust & rotate speed
        self.thrust = 20000.0
        self.rotate_speed = 200.0

        # Flame image
        self.engine_sprite = Sprite(img=engine_image, *args, **kwargs)
        self.engine_sprite.visible = False

        # Obtain key state handler
        self.key_handler = key.KeyStateHandler()

    def update(self, dt):
        """
        Override super update method
        :param dt:
        :return:
        """
        super(Player, self).update(dt)
        # ----- Rotate ----- #
        if self.key_handler[key.LEFT]:
            self.rotation -= self.rotate_speed * dt
        if self.key_handler[key.RIGHT]:
            self.rotation += self.rotate_speed * dt

        # ----- Forward or backward ----- #
        if self.key_handler[key.UP]:
            self.__run(dt)
        elif self.key_handler[key.DOWN]:
            self.__run(-dt)
        else:
            self.__stop()

        # ----- Speed up and slow down ----- #
        if self.key_handler[key.J]:
            self.__speed_up()
        if self.key_handler[key.K]:
            self.__slow_down()

    def on_key_press(self, symbol, modifiers):
        if symbol == key.SPACE:
            self._do_shoot_bullet()

    def _do_shoot_bullet(self):
        if self.can_shoot():
            self.shoot_bullet(700)
            self.add_shoot()

    def __run(self, dt):
        """
        Speed up
        """
        # 正方向定义不同,加负号
        angle_radians = -math.radians(self.rotation)
        force_x = math.cos(angle_radians) * self.thrust * dt
        force_y = math.sin(angle_radians) * self.thrust * dt
        self.velocity_x = force_x
        self.velocity_y = force_y
        # Ignite engine flame
        self.__ignite_engine_flame()

    def __stop(self):
        self.velocity_x = 0
        self.velocity_y = 0
        # Ignite engine flame
        self.__stop_engine_flame()

    def __speed_up(self):
        self.thrust += 4000

    def __slow_down(self):
        """
        Slow down
        """
        self.thrust -= 4000
        if self.thrust <= 2000:
            self.thrust = 2000

    def __ignite_engine_flame(self):
        self.engine_sprite.visible = True
        self.engine_sprite.rotation = self.rotation
        self.engine_sprite.x = self.x
        self.engine_sprite.y = self.y

    def __stop_engine_flame(self):
        self.engine_sprite.visible = False

    def can_shoot(self):
        return self._num_bullets <= 1

    def add_shoot(self):
        self._num_bullets += 1

    def remove_shoot(self):
        self._num_bullets -= 1

    def delete(self):
        """
        Operations when destroyed
        :return:
        """
        self.engine_sprite.delete()
        super(Player, self).delete()
Exemple #20
0
class Window(pyglet.window.Window):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        self.score = 0
        self.difficulty = self.score + 50
        self.lives = 3
        self.time = 0.5
        self.ships = pyglet.graphics.Batch()
        self.rocks = pyglet.graphics.Batch()
        self.missiles = pyglet.graphics.Batch()
        self.started = False
        self.rock_trigger = 0

        # Images
        self.background = pyglet.image.load('static/images/nebula_blue.s2014.png')

        self.rock_img = pyglet.image.load('static/images/asteroid_blue.png')
        utils.center_image_anchor(self.rock_img)

        ship_sequence = pyglet.image.load('static/images/double_ship.png')
        self.ship_imgs = pyglet.image.ImageGrid(ship_sequence, 1, 2)
        utils.center_image_grid_anchors(self.ship_imgs)
        self.splash_img = pyglet.image.load('static/images/splash.png') 

        # Sounds
        self.thruster_snd = pyglet.media.load('static/sounds/rocket.ogg', streaming=False)
        self.explosion_snd = pyglet.media.load('static/sounds/explosion.ogg', streaming=False)
        self.background_music = pyglet.media.load('static/sounds/space1.mp3', streaming=False)
        self.background_music.play()

        # Sprite Groups
        self.rock_group = set()
        self.missile_group = set()

        # Spites 
        self.ship = PlayerSprite(self.ship_imgs, self.thruster_snd, 400, 250, 0, 0, 270, 35, self.ships, self.missiles)
        self.splash = Sprite(self.splash_img, 200, 125)

        # Screen Text
        self.text_lives = pyglet.text.Label('Lives=' + str(self.lives),
                                            font_name='Times New Roman',
                                            font_size=36, x=10, y=10)
        self.text_score = pyglet.text.Label('Score=' + str(self.score),
                                            font_name='Times New Roman',
                                            font_size=36, x=10, y=60)

        # Keymaps
        self.key_downs = {key.UP:self.accel, key.LEFT:self.left, key.RIGHT:self.right, key.SPACE:self.fire, key.ESCAPE:pyglet.app.exit}
        self.key_ups = {key.UP:self.decel, key.LEFT:self.right, key.RIGHT:self.left}

        pyglet.clock.schedule_interval(self.update, 1/60.0)  # update at 60Hz
    def game_reset(self):
        self.started = False
        self.rock_group = set()
        self.ship = PlayerSprite(self.ship_imgs, self.thruster_snd, 400, 250, 0, 0, 270, 35, self.ships, self.missiles)
        self.lives = 3
        self.score = 0
        # intro screen 
        # self.splash.draw()

    def display_score(self):
        self.text_lives = pyglet.text.Label('Lives=' + str(self.lives),
                                            font_name='Times New Roman',
                                            font_size=36, x=10, y=10)
        self.text_score = pyglet.text.Label('Score=' + str(self.score),
                                            font_name='Times New Roman',
                                            font_size=36, x=10, y=60)
    def start_game(self):
        #Function to start game on initial mouse click
        self.splash.delete()
        self.started = True

    def accel(self):
        self.ship.thrusters = True
    
    def decel(self):
        self.ship.thrusters = False

    def left(self):
        self.ship.angle_vel -= 5

    def right(self):
        self.ship.angle_vel += 5
    
    def fire(self):
        self.ship.shoot(self.missile_group)

    def on_mouse_press(self, x, y, button, modifiers):
        self.start_game()

    def on_key_press(self, symbol, modifiers):
        for key in self.key_downs:
            if key == symbol:
                self.key_downs[symbol]()

    def on_key_release(self, symbol, modifiers):
        for key in self.key_ups:
            if key == symbol:
                self.key_ups[symbol]()

    def put_rock(self):
        rock_position = utils.random_position(WIDTH, HEIGHT)
        rock = MovingSprite (self.rock_img, rock_position[0], rock_position[1],
                             sound=self.explosion_snd, diff=self.difficulty,
                             radius=40, batch=self.rocks)
        self.rock_group.add(rock)

    def trigger_put_rock(self):
        self.rock_trigger += 1
        if self.rock_trigger > 60 and len(self.rock_group) < 10:
            self.put_rock()
            self.rock_trigger = 0
    # TODO Implement Sheilds
    def on_draw(self):
        self.clear()
        self.background.blit(0, 0)
        self.ships.draw()
        self.rocks.draw()
        self.missiles.draw()
        self.text_lives.draw()
        self.text_score.draw()
        if not self.started:
           self.splash = Sprite(self.splash_img, 200, 125)
           self.splash.draw()

    def update(self, dt):
        if self.started:
            self.trigger_put_rock()
            for rock in self.rock_group:
                rock.update(WIDTH, HEIGHT) 
            self.ship.update(WIDTH, HEIGHT) 

            local_missiles = set(self.missile_group)
            for missile in local_missiles:
                if not missile.update(WIDTH, HEIGHT):
                    self.missile_group.remove(missile)
                    missile.delete()

            if group_collide(self.rock_group, self.ship):
                self.lives -= 1
                self.explosion_snd.play()

            if group_group_collide(self.missile_group, self.rock_group):
                self.score += 10
                self.difficulty  += self.score + 50
                self.explosion_snd.play()

            self.display_score()
        
        if self.lives < 0:
            self.game_reset()
Exemple #21
0
class Window(pyglet.window.Window):
    """This class renders the game data within a pyglet window."""

    def __init__(self, my_controller, size):
        super(Window, self).__init__(700, 700, fullscreen=False, caption='')
        
        # Link the view to the controller
        self.controller = my_controller
		
        # Gamplay information passed by the controller
        self.data = {   'size' : size,
                        'stones' : [[None for x in range(size)] for y in range(size)],
                        'territory': [[None for x in range(size)] for y in range(size)],
                        'color' : None,
                        'game_over': False,
                        'score' : [0, 20]
                        }
        
        # Set default background color
        pyglet.gl.glClearColor(0.5,0.5,0.5,1)
        
        # Load background image and stones
        self.image_background = BACKGROUND
        self.image_black_stone = BLACK_STONE
        self.image_white_stone = WHITE_STONE

        # Center black and white stones
        self.init_resources()
        
        # Initialize the display
        self.init_display()

    def init_resources(self):
        """Center black and white stones for proper visualization

        Attributes updated by this function:
            self.image_black_stone
            self.image_white_stone
        """
        def center_image(image):
            """Set an image's anchor point to its center

            Arguments:
                image (pyglet.resource.image) - image to center

            Attributes updated by this function:
                image
            """
            image.anchor_x = image.width/2
            image.anchor_y = image.height/2
            
        center_image(self.image_black_stone)
        center_image(self.image_white_stone)

    def init_display(self):
        """Gather all graphical elements together and draw them simutaneously.

            Attributes updated by this function:
                self.batch
                self.grp_back
                self.grp_grid
                self.grp_label
                self.grp_stones
                self.grp_territory
                self.background
                self.grid
                self.info
                self.score_black
                self.black_label_stone
                self.score_white
                self.white_label_stone
                self.player_color
                self.current_player_stone
                self.button_pass
                self.button_newgame
        """
        # Creating a batch to display all graphics
        self.batch = pyglet.graphics.Batch()
        
        # Graphic groups (groups of lower index get drawn first)
        self.grp_back = pyglet.graphics.OrderedGroup(0)
        self.grp_grid = pyglet.graphics.OrderedGroup(1)
        self.grp_label = pyglet.graphics.OrderedGroup(2)
        self.grp_stones = pyglet.graphics.OrderedGroup(3)
        self.grp_territory = pyglet.graphics.OrderedGroup(4)

        # Initially load all graphic groups.
        self.init_back()
        self.init_grid()
        self.init_label()

    def init_back(self):
        """Load the background.

            Attributes updated by this function:
                self.background
        """
        # Display background image
        self.background = Sprite(self.image_background, batch=self.batch, group=self.grp_back)

    def init_grid(self):
        """Load the grid.

            Attributes updated by this function:
                self.grid
        """
        # Display grid
        self.grid = Grid(x=self.width/2,
                         y=self.height/2,
                         width=self.width*MAX_GRID_SIZE,
                         height=self.height*MAX_GRID_SIZE,
                         batch=self.batch,
                         group=self.grp_grid,
                         n=self.data['size'])

    def init_label(self):
        """Load all labels and buttons.

            Attributes updated by this function:
                self.info
                self.score_black
                self.black_label_stone
                self.score_white
                self.white_label_stone
                self.player_color
                self.current_player_stone
                self.button_pass
                self.button_newgame
        """
        # Game Information Display
        label_y = 670                 # y position of scores and next turn labels
        label_font_size = 12
        label_text_color = (0, 0, 0, 255)
        
        # Controller-Info Panel
        # The Text of this label is directly changed inside the controller
        self.info = Label(x=10, y=10, text="Let's start!", color=label_text_color,
                          font_size=label_font_size, batch=self.batch, group=self.grp_label)

        # Score-Label
        Label(x=10, y=label_y, text='Score:', color=label_text_color,
                          font_size=label_font_size, bold=True, batch=self.batch, group=self.grp_label)

        # SCORES BLACK PLAYER
        self.score_black = Label(x=100, y=label_y, text=str(self.data['score'][1]), color=label_text_color,
                          font_size=label_font_size, batch=self.batch, group=self.grp_label)
        self.black_label_stone = Sprite(self.image_black_stone,
                           batch=self.batch, group=self.grp_label,
                           x=0, y=0)
        self.black_label_stone.scale = LITTLE_STONE_SIZE
        self.black_label_stone.set_position(80, label_y + self.black_label_stone.height/4)

        # SCORES WHITE PLAYER
        self.score_white = Label(x=170, y=label_y, text=str(self.data['score'][0]), color=label_text_color,
                          font_size=label_font_size, batch=self.batch, group=self.grp_label)
        self.white_label_stone = Sprite(self.image_white_stone,
                           batch=self.batch, group=self.grp_label,
                           x=0, y=0)
        self.white_label_stone.scale = LITTLE_STONE_SIZE
        self.white_label_stone.set_position(150, label_y + self.white_label_stone.height/4)

        # CURRENT PLAYER STONE
        self.player_color = Label(x=550, y=label_y, text="Your color: ", color=label_text_color,
            font_size=label_font_size, bold=True, batch=self.batch, group=self.grp_label)

        # INITIAL PLAYER STONE
        self.current_player_stone = Sprite(self.image_black_stone,
                           batch=self.batch, group=self.grp_label,
                           x=0, y=0)
        self.current_player_stone.scale = LITTLE_STONE_SIZE
        self.current_player_stone.set_position(660, label_y + self.current_player_stone.height/4)

        # Game Buttons  
        # Button that can be pressed to pass on current round
        self.button_pass = Button(pos=(600,40), text='Pass', batch=self.batch)
        
        # New-Game Button
        self.button_newgame = Button(pos=(480,40), text='New Game')

    def update(self, *args):
        """This function does all the calculations when the data gets updated.
            For other games that require permanent simulations you would add
            the following line of code at the end of __init__():
            pyglet.clock.schedule_interval(self.update, 1/30)

            Attributes updated by this function:
                self.batch_stones
                self.stone_sprites
                self.image_black_stone
                self.image_white_stone
                self.batch_territory
                self.score_black
                self.score_white
                self.current_player_stone
        """
        # Game Information Updates
        # Scores of each player
        self.update_stones()
        self.update_territories()
        self.update_scores()
        self.update_current_player()
            
        # If the new size in the data is different than the current size
        if self.data['size'] != self.grid.size:
            self.init_display()
    
    def update_stones(self):
        """Update the black and white stones on the game board.

            Attributes updated by this function:
                self.batch_stones
                self.stone_sprites
                self.image_black_stone
                self.image_white_stone
        """
        # Display the stones on the regular batch
        self.batch_stones = self.batch
        self.stone_sprites = []

        # Center black and white stones
        def center_image(image):
            """Sets an image's anchor point to its center"""
            image.anchor_x = image.width/2
            image.anchor_y = image.height/2
            
        center_image(self.image_black_stone)
        center_image(self.image_white_stone)

        # Place all stones on the grid

        # Scale stone images
        scaling = self.grid.field_width / self.image_black_stone.width

        # Limit max size of stones
        if scaling > MAX_STONE_SCALING:
            scaling = MAX_STONE_SCALING

        # Iterate trough all data stones and place the corresponding black or
        # white stone on the grid
        for i in range(0, self.data['size']):
            for j in range(0, self.data['size']):
                if self.data['stones'][j][i] != None:
                    # Get x and y grid coordinates
                    x_coord, y_coord = self.grid.get_coords(i, j)

                    # Get the stone color to place
                    stone_color = self.image_black_stone if self.data['stones'][j][i] == BLACK else None
                    stone_color = self.image_white_stone if self.data['stones'][j][i] == WHITE else stone_color

                    # Place the stone on the grid
                    if stone_color:
                        _s = Sprite(stone_color,
                                    batch=self.batch_stones,
                                    group=self.grp_stones,
                                    x=x_coord,
                                    y=y_coord)
                        _s.scale = scaling
                        self.stone_sprites.append(_s)   
    
    def update_territories(self):
        """Update the black and white territories on the board.

            Attributes updated by this function:
                self.batch_territory
        """
        # Display the territory an the regular batch
        # Display the stones on the regular batch
        self.batch_territory = self.batch
        
        rad = 5
        
        # Iterate trough all territory indicators and place the corresponding
        # black or white circle on the grid or above stones
        for i in range(0, self.data['size']):
            for j in range(0, self.data['size']):
                if self.data['territory'][j][i] != None:
                    x_coord, y_coord = self.grid.get_coords(i, j)
                    if self.data['territory'][j][i] == BLACK:
                        Circle(x_coord,
                               y_coord,
                               color=BLACK_TERRITORY,
                               r=rad,
                               batch=self.batch_territory,
                               group=self.grp_territory)
                    elif self.data['territory'][j][i] == WHITE:
                        Circle(x_coord,
                               y_coord,
                               color=WHITE_TERRITORY,
                               r=rad,
                               batch=self.batch_territory,
                               group=self.grp_territory)

    def update_scores(self):
        """Update scores for BLACK and WHITE.
        
            Attributes updated by this function:
                self.score_black
                self.score_white
        """
        self.score_black.text = str(self.data['score'][1])
        self.score_white.text = str(self.data['score'][0])

    def update_current_player(self):
        """Update stone of current player.
        
            Attributes updated by this function:
                self.current_player_stone
        """
        # Remve the last current player stone
        self.current_player_stone.delete()

        # If its the BLACK players turn
        if self.data['color']:
            self.current_player_stone = Sprite(self.image_black_stone,
                           batch=self.batch, group=self.grp_label,
                           x=0, y=0)
            self.current_player_stone.scale = LITTLE_STONE_SIZE
            self.current_player_stone.set_position(660, 670 + self.current_player_stone.height/4)
        # If its the WHITE players turn
        else:
            self.current_player_stone = Sprite(self.image_white_stone,
                           batch=self.batch, group=self.grp_label,
                           x=0, y=0)
            self.current_player_stone.scale = LITTLE_STONE_SIZE
            self.current_player_stone.set_position(660, 670 + self.current_player_stone.height/4)


    def on_draw(self):
        """Draw the interface.
        
            Attributes updated by this function:
                self
                self.batch
                self.button_newgame
        """
        # Clear out old graphics
        self.clear()

        # Drawing the batch (which does not contain any graphics yet)
        self.batch.draw()

        # Check if Game is over, if True, draw the New Game Button
        if(self.data['game_over']):
            self.button_newgame.draw()

    def on_mouse_press(self, mousex, mousey, button, modifiers):
        """Function called on any mouse button press.

        Arguments:
            mousex    : x-coord of the click
            mousey    : y-coord of the click
            button    :
            modifiers :


        The buttons are saved as constants in pyglet.window.mouse,
        the modifiers under pyglet.window.key

        E.g.
        >>> if button == pyglet.window.mouse.LEFT: pass

        Look at the documentation for more information:
        >>> import pyglet
        >>> help(pyglet.window.mouse)
        """
        # Check for clicks on New Game Button only when game is Over
        if(self.data['game_over']):
            if (mousex, mousey) in self.button_newgame:
                self.controller.new_game()
                
            if button == pyglet.window.mouse.LEFT:
                # Mark territory if the game is over
                pos = self.grid.get_indices(mousex, mousey)
                if pos != None:
                    self.controller.mark_territory(pos)

        # Handle clicks during game
        
        # Check if pass-button was pressed
        if (mousex, mousey) in self.button_pass:
            self.controller.passing()

        # Grid position clicked (only if above buttons)
        elif button == pyglet.window.mouse.LEFT and mousey > 60:
            # Place a stone at clicked position
            pos = self.grid.get_indices(mousex, mousey)
            if pos != None:
                self.controller.play(pos)

    def on_key_press(self, symbol, modifiers):
        """Function that gets called on any key press (keyboard).

        Arguments:
            symbol   : symbol that was pressed
            modifiers : modifiers (e.g. l-shift, r-shift, ctrl, ...)

        You can compare symbol/modifiers to the constants defined
        in pyglet.window.key:

        E.g.
        >>> if symbol == pyglet.window.key.A: pass

        For more information look on the help page:
        >>> import pyglet
        >>> help(pyglet.window.key)
        """
        pass
    
    def receive_data(self, data):
        """Receive data from the controller and update view.
        
            Attributes updated by this function:
                self.data
        """
        self.data.update(data)
        self.update()

    def new_game(self, data):
        """Receive data from the controller and start a new game.
        
            Attributes updated by this function:
                self.data
        """
        # Initialize the display
        self.data.update(data)
        self.init_display()
        self.update()
Exemple #22
0
class Sprite2D(fixture2d.Fixture2D):
    def __init__(self, img, x, y, batch=default_batch, group=None):
        self._sprite = Sprite(img, x=x, y=y, batch=batch, group=group)

        super().__init__(x, y)

    def update(self, dt):
        super().update(dt)

        self._sprite.update(x=self._pos.x,
                            y=self._pos.y,
                            rotation=self._rot,
                            scale_x=self._sx,
                            scale_y=self._sy)

    def delete(self):
        super().delete()

        self._sprite.delete()

    def _create_physical_body(self):
        return pymunk.Body(self._mass, self._inertia, self._body_type)

    def _create_physical_shape(self):
        return pymunk.Poly(self._body, [(-self.width / 2, self.height / 2),
                                        (self.width / 2, self.height / 2),
                                        (self.width / 2, -self.height / 2),
                                        (-self.width / 2, -self.height / 2)])

    def _get_inertia_for_shape(self):
        return pymunk.moment_for_poly(self._mass,
                                      [(-self.width / 2, self.height / 2),
                                       (self.width / 2, self.height / 2),
                                       (self.width / 2, -self.height / 2),
                                       (-self.width / 2, -self.height / 2)])

    def _get_bounding_box(self):
        return AABB.computeAABB(self.x, self.y, self.width, self.height,
                                self._rot)

    @property
    def width(self):
        return self._sprite.width

    @property
    def height(self):
        return self._sprite.height

    @property
    def batch(self):
        return self._sprite.batch

    @batch.setter
    def batch(self, value):
        self._sprite.batch = value

    @property
    def image(self):
        return self._sprite.image

    @image.setter
    def image(self, value):
        self._sprite.image = value

    @property
    def group(self):
        return self._sprite.group

    @group.setter
    def group(self, value):
        self._sprite.group = value

    @property
    def opacity(self):
        return self._sprite.opacity

    @opacity.setter
    def opacity(self, value):
        self._sprite.opacity = value

    @property
    def color(self):
        return self._sprite.color

    @color.setter
    def color(self, value):
        self._sprite.color = value

    @property
    def visible(self):
        return self._sprite.visible

    @visible.setter
    def visible(self, value):
        self._sprite.visible = value