コード例 #1
0
ファイル: input.py プロジェクト: sradigan/Tuxemon
    def startup(self, *items, **kwargs):
        """

        Accepted Keyword Arguments:
            prompt:   String used to let user know what value is being inputted (ie "Name?", "IP Address?")
            callback: Function to be called when dialog is confirmed.  The value will be sent as only argument
            initial:  Optional string to pre-fill the input box with.

        :param items:
        :param kwargs:
        :return:
        """
        super(InputMenu, self).startup(*items, **kwargs)
        self.input_string = kwargs.get("initial", "")

        # area where the input will be shown
        self.text_area = TextArea(self.font, self.font_color, (96, 96, 96))
        self.text_area.animated = False
        self.text_area.rect = Rect(tools.scale_sequence([90, 30, 80, 100]))
        self.text_area.text = self.input_string
        self.sprites.add(self.text_area)

        # prompt
        self.prompt = TextArea(self.font, self.font_color, (96, 96, 96))
        self.prompt.animated = False
        self.prompt.rect = Rect(tools.scale_sequence([50, 20, 80, 100]))
        self.sprites.add(self.prompt)

        self.prompt.text = kwargs.get("prompt", "")
        self.callback = kwargs.get("callback")
        assert self.callback
コード例 #2
0
ファイル: combat.py プロジェクト: sradigan/Tuxemon
    def draw_hp_bars(self):
        """ Go through the HP bars and redraw them

        :returns: None
        """
        for monster, hud in self.hud.items():
            rect = Rect(0, 0, tools.scale(70), tools.scale(8))
            rect.right = hud.image.get_width() - tools.scale(8)
            rect.top += tools.scale(12)
            self._hp_bars[monster].draw(hud.image, rect)
コード例 #3
0
ファイル: combat.py プロジェクト: jonnypjohnston/Tuxemon
    def draw_exp_bars(self):
        """ Go through the EXP bars and redraw them

        :rtype: None
        """
        for monster, hud in self.hud.items():
            if hud.player:
                rect = Rect(0, 0, tools.scale(70), tools.scale(6))
                rect.right = hud.image.get_width() - tools.scale(8)
                rect.top += tools.scale(31)
                self._exp_bars[monster].draw(hud.image, rect)
コード例 #4
0
ファイル: __init__.py プロジェクト: sradigan/Tuxemon
    def initialize_items(self):
        # position the monster portrait
        try:
            monster = local_session.player.monsters[self.selected_index]
            image = monster.sprites["front"]
        except IndexError:
            image = pygame.Surface((1, 1), pygame.SRCALPHA)

        # position and animate the monster portrait
        width, height = prepare.SCREEN_SIZE
        self.monster_portrait.rect = image.get_rect(centerx=width // 4,
                                                    top=height // 12)
        self.sprites.add(self.monster_portrait)
        self.animations.empty()
        self.animate_monster_down()

        width = prepare.SCREEN_SIZE[0] // 2
        height = prepare.SCREEN_SIZE[1] // (local_session.player.party_limit *
                                            1.5)

        # make 6 slots
        for i in range(local_session.player.party_limit):
            rect = Rect(0, 0, width, height)
            surface = pygame.Surface(rect.size, pygame.SRCALPHA)
            item = MenuItem(surface, None, None, None)
            yield item

        self.refresh_menu_items()
コード例 #5
0
ファイル: __init__.py プロジェクト: sradigan/Tuxemon
    def startup(self, **kwargs):
        super(MonsterMenuState, self).startup(**kwargs)

        # make a text area to show messages
        self.text_area = TextArea(self.font, self.font_color, (96, 96, 96))
        self.text_area.rect = Rect(tools.scale_sequence([20, 80, 80, 100]))
        self.sprites.add(self.text_area, layer=100)

        # Set up the border images used for the monster slots
        self.monster_slot_border = {}
        self.monster_portrait = pygame.sprite.Sprite()
        self.hp_bar = HpBar()
        self.exp_bar = ExpBar()

        # load and scale the monster slot borders
        root = "gfx/ui/monster/"
        border_types = ["empty", "filled", "active"]
        for border_type in border_types:
            filename = root + border_type + "_monster_slot_border.png"
            border = graphics.load_and_scale(filename)

            filename = root + border_type + "_monster_slot_bg.png"
            background = graphics.load_image(filename)

            window = GraphicBox(border, background, None)
            self.monster_slot_border[border_type] = window

        # TODO: something better than this global, load_sprites stuff
        for monster in local_session.player.monsters:
            monster.load_sprites()
コード例 #6
0
ファイル: world_menus.py プロジェクト: sradigan/Tuxemon
    def animate_open(self):
        """ Animate the menu sliding in

        :return:
        """
        self.state = "opening"  # required

        # position the menu off screen.  it will be slid into view with an animation
        right, height = prepare.SCREEN_SIZE

        # TODO: more robust API for sizing (kivy esque?)
        # this is highly irregular:
        # shrink to get the final width
        # record the width
        # turn off shrink, then adjust size
        self.shrink_to_items = True  # force shrink of menu
        self.menu_items.expand = False  # force shrink of items
        self.refresh_layout()  # rearrange items
        width = self.rect.width  # store the ideal width

        self.shrink_to_items = False  # force menu to expand
        self.menu_items.expand = True  # force menu to expand
        self.refresh_layout()  # rearrange items
        self.rect = Rect(right, 0, width, height)  # set new rect

        # animate the menu sliding in
        ani = self.animate(self.rect, x=right - width, duration=.50)
        ani.callback = lambda: setattr(self, "state", "normal")
        return ani
コード例 #7
0
def strip_coords_from_sheet(sheet, coords, size):
    """Strip specific coordinates from a sprite sheet."""
    frames = []
    for coord in coords:
        location = (coord[0] * size[0], coord[1] * size[1])
        frames.append(sheet.subsurface(Rect(location, size)))
    return frames
コード例 #8
0
ファイル: combat.py プロジェクト: jonnypjohnston/Tuxemon
    def show_combat_dialog(self):
        """ Create and show the area where battle messages are displayed
        """
        # make the border and area at the bottom of the screen for messages
        x, y, w, h = self.client.screen.get_rect()
        rect = Rect(0, 0, w, h // 4)
        rect.bottomright = w, h
        border = graphics.load_and_scale(self.borders_filename)
        self.dialog_box = GraphicBox(border, None, self.background_color)
        self.dialog_box.rect = rect
        self.sprites.add(self.dialog_box, layer=100)

        # make a text area to show messages
        self.text_area = TextArea(self.font, self.font_color)
        self.text_area.rect = self.dialog_box.calc_inner_rect(self.dialog_box.rect)
        self.sprites.add(self.text_area, layer=100)
コード例 #9
0
ファイル: test_map.py プロジェクト: jonnypjohnston/Tuxemon
 def test_snap_y_axis(self):
     rect = Rect(1, 16, 16, 30)
     grid_size = (16, 16)
     result = snap_rect(rect, grid_size)
     self.assertEqual(0, result.x)
     self.assertEqual(16, result.y)
     self.assertEqual(16, result.w)
     self.assertEqual(32, result.h)
コード例 #10
0
ファイル: combat.py プロジェクト: sradigan/Tuxemon
    def show_monster_action_menu(self, monster):
        """ Show the main window for choosing player actions

        :param monster: Monster to choose an action for
        :type monster: tuxemon.core.monster.Monster

        :returns: None
        """
        message = T.format('combat_monster_choice', {"name": monster.name})
        self.alert(message)
        x, y, w, h = self.client.screen.get_rect()
        rect = Rect(0, 0, w // 2.5, h // 4)
        rect.bottomright = w, h

        state = self.client.push_state("MainCombatMenuState", columns=2)
        state.monster = monster
        state.rect = rect
コード例 #11
0
def strip_from_sheet(sheet, start, size, columns, rows=1):
    """Strips individual frames from a sprite sheet given a start location,
    sprite size, and number of columns and rows."""
    frames = []
    for j in range(rows):
        for i in range(columns):
            location = (start[0] + size[0] * i, start[1] + size[1] * j)
            frames.append(sheet.subsurface(Rect(location, size)))
    return frames
コード例 #12
0
ファイル: worldstate.py プロジェクト: jonnypjohnston/Tuxemon
    def _collision_box_to_pgrect(self, box):
        """Returns a Rect (in screen-coords) version of a collision box (in world-coords).
        """

        # For readability
        x, y = self.get_pos_from_tilepos(box)
        tw, th = self.tile_size

        return Rect(x, y, tw, th)
コード例 #13
0
ファイル: sprite.py プロジェクト: sradigan/Tuxemon
class RelativeGroup(SpriteGroup):
    """
    Drawing operations are relative to the group's rect
    """
    rect = Rect(0, 0, 0, 0)

    def __init__(self, **kwargs):
        self.parent = kwargs.get('parent')
        super(RelativeGroup, self).__init__(**kwargs)

    def calc_bounding_rect(self):
        """A rect object that contains all sprites of this group
        """
        rect = super(RelativeGroup, self).calc_bounding_rect()
        # return self.calc_absolute_rect(rect)
        return rect

    def calc_absolute_rect(self, rect):
        self.update_rect_from_parent()
        return rect.move(self.rect.topleft)

    def update_rect_from_parent(self):
        try:
            self.rect = self.parent()
        except TypeError:
            self.rect = Rect(self.parent.rect)

    def draw(self, surface):
        self.update_rect_from_parent()
        topleft = self.rect.topleft

        spritedict = self.spritedict
        surface_blit = surface.blit
        dirty = self.lostsprites
        self.lostsprites = []
        dirty_append = dirty.append

        for s in self.sprites():
            if s.image is None:
                continue

            if not getattr(s, 'visible', True):
                continue

            r = spritedict[s]
            newrect = surface_blit(s.image, s.rect.move(topleft))
            if r:
                if newrect.colliderect(r):
                    dirty_append(newrect.union(r))
                else:
                    dirty_append(newrect)
                    dirty_append(r)
            else:
                dirty_append(newrect)
            spritedict[s] = newrect
        return dirty
コード例 #14
0
ファイル: map.py プロジェクト: jonnypjohnston/Tuxemon
def snap_rect(rect, grid_size):
    """ Align all vertices to the nearest point

    :param rect:
    :param grid_size:
    :return:
    """
    left, top = snap_point(rect.topleft, grid_size)
    right, bottom = snap_point(rect.bottomright, grid_size)
    return Rect((left, top), (right - left, bottom - top))
コード例 #15
0
ファイル: sprite.py プロジェクト: sradigan/Tuxemon
 def calc_bounding_rect(self):
     """A rect object that contains all sprites of this group
     """
     sprites = self.sprites()
     if not sprites:
         return self.rect
     elif len(sprites) == 1:
         return Rect(sprites[0].rect)
     else:
         return sprites[0].rect.unionall([s.rect for s in sprites[1:]])
コード例 #16
0
ファイル: text.py プロジェクト: jonnypjohnston/Tuxemon
 def __init__(self, font, font_color, bg=(192, 192, 192)):
     super().__init__()
     self.rect = Rect(0, 0, 0, 0)
     self.drawing_text = False
     self.font = font
     self.font_color = font_color
     self.font_bg = bg
     self._rendered_text = None
     self._text_rect = None
     self._image = None
     self._text = None
コード例 #17
0
ファイル: save_menu.py プロジェクト: sradigan/Tuxemon
 def initialize_items(self):
     empty_image = None
     rect = self.client.screen.get_rect()
     slot_rect = Rect(0, 0, rect.width * 0.80, rect.height // 6)
     for i in range(self.number_of_slots):
         # Check to see if a save exists for the current slot
         if os.path.exists(prepare.SAVE_PATH + str(i + 1) + ".save"):
             image = self.render_slot(slot_rect, i + 1)
             item = MenuItem(image, T.translate('menu_save'), None, None)
             self.add(item)
         else:
             if not empty_image:
                 empty_image = self.render_empty_slot(slot_rect)
             item = MenuItem(empty_image, "SAVE", None, None)
             self.add(item)
コード例 #18
0
ファイル: controller.py プロジェクト: sradigan/Tuxemon
    def load(self):
        from tuxemon.core import prepare
        self.dpad["surface"] = graphics.load_and_scale("gfx/d-pad.png")
        self.dpad["position"] = (0, prepare.SCREEN_SIZE[1] -
                                 self.dpad["surface"].get_height())

        # Create the collision rectangle objects for the dpad so we can see if we're pressing a button
        self.dpad["rect"] = {}
        self.dpad["rect"]["up"] = Rect(
            self.dpad["position"][0] + (self.dpad["surface"].get_width() / 3),
            self.dpad["position"][1],  # Rectangle position_y
            self.dpad["surface"].get_width() / 3,  # Rectangle size_x
            self.dpad["surface"].get_height() / 2)  # Rectangle size_y
        self.dpad["rect"]["down"] = Rect(
            self.dpad["position"][0] + (self.dpad["surface"].get_width() / 3),
            self.dpad["position"][1] + (self.dpad["surface"].get_height() / 2),
            self.dpad["surface"].get_width() / 3,
            self.dpad["surface"].get_height() / 2)
        self.dpad["rect"]["left"] = Rect(
            self.dpad["position"][0],
            self.dpad["position"][1] + (self.dpad["surface"].get_height() / 3),
            self.dpad["surface"].get_width() / 2,
            self.dpad["surface"].get_height() / 3)
        self.dpad["rect"]["right"] = Rect(
            self.dpad["position"][0] + (self.dpad["surface"].get_width() / 2),
            self.dpad["position"][1] + (self.dpad["surface"].get_height() / 3),
            self.dpad["surface"].get_width() / 2,
            self.dpad["surface"].get_height() / 3)

        # Create the buttons
        self.a_button = {}
        self.a_button["surface"] = graphics.load_and_scale("gfx/a-button.png")
        self.a_button["position"] = (
            prepare.SCREEN_SIZE[0] -
            int(self.a_button["surface"].get_width() * 1.0),
            (self.dpad["position"][1] +
             (self.dpad["surface"].get_height() / 2) -
             (self.a_button["surface"].get_height() / 2)))
        self.a_button["rect"] = Rect(self.a_button["position"][0],
                                     self.a_button["position"][1],
                                     self.a_button["surface"].get_width(),
                                     self.a_button["surface"].get_height())

        self.b_button = {}
        self.b_button["surface"] = graphics.load_and_scale("gfx/b-button.png")
        self.b_button["position"] = (
            prepare.SCREEN_SIZE[0] -
            int(self.b_button["surface"].get_width() * 2.1),
            (self.dpad["position"][1] +
             (self.dpad["surface"].get_height() / 2) -
             (self.b_button["surface"].get_height() / 2)))
        self.b_button["rect"] = Rect(self.b_button["position"][0],
                                     self.b_button["position"][1],
                                     self.b_button["surface"].get_width(),
                                     self.b_button["surface"].get_height())
コード例 #19
0
ファイル: map_loader.py プロジェクト: jonnypjohnston/Tuxemon
    def region_tiles(region, grid_size):
        """ Apply region properties to individual tiles

        Right now our collisions are defined in our tmx file as large regions
        that the player can't pass through. We need to convert these areas
        into individual tile coordinates that the player can't pass through.
        Loop through all of the collision objects in our tmx file. The
        region's bounding box will be snapped to the nearest tile coordinates.

        :param region:
        :param grid_size:
        :return:
        """
        region_conditions = copy_dict_with_keys(region.properties, region_properties)
        rect = snap_rect(
            Rect(region.x, region.y, region.width, region.height), grid_size
        )
        for tile_position in tiles_inside_rect(rect, grid_size):
            yield tile_position, extract_region_properties(region_conditions)
コード例 #20
0
ファイル: test_map.py プロジェクト: jonnypjohnston/Tuxemon
 def test_snap_rect_result_is_rect(self):
     rect = Rect(1, 1, 14, 14)
     grid_size = (16, 16)
     result = snap_rect(rect, grid_size)
     self.assertIsInstance(result, Rect)
コード例 #21
0
ファイル: test_map.py プロジェクト: jonnypjohnston/Tuxemon
 def test_correct_result(self):
     rect = Rect(0, 16, 32, 48)
     grid_size = (16, 16)
     expected = [(0, 1), (1, 1), (0, 2), (1, 2), (0, 3), (1, 3)]
     result = list(tiles_inside_rect(rect, grid_size))
     self.assertEqual(expected, result)
コード例 #22
0
ファイル: worldstate.py プロジェクト: jonnypjohnston/Tuxemon
 def _npc_to_pgrect(self, npc):
     """Returns a Rect (in screen-coords) version of an NPC's bounding box.
     """
     pos = self.get_pos_from_tilepos(npc.tile_pos)
     return Rect(pos, self.tile_size)
コード例 #23
0
ファイル: npc.py プロジェクト: jonnypjohnston/Tuxemon
    def __init__(self,
                 npc_slug,
                 sprite_name=None,
                 combat_front=None,
                 combat_back=None):
        super().__init__()

        # load initial data from the npc database
        npc_data = db.lookup(npc_slug, table="npc")

        self.slug = npc_slug

        # This is the NPC's name to be used in dialog
        self.name = T.translate(self.slug)

        # use 'animations' passed in
        # Hold on the the string so it can be sent over the network
        self.sprite_name = sprite_name
        self.combat_front = combat_front
        self.combat_back = combat_back
        if self.sprite_name is None:
            # Try to use the sprites defined in the JSON data
            self.sprite_name = npc_data["sprite_name"]
        if self.combat_front is None:
            self.combat_front = npc_data["combat_front"]
        if self.combat_back is None:
            self.combat_back = npc_data["combat_back"]

        # general
        self.behavior = "wander"  # not used for now
        self.game_variables = {}  # Tracks the game state
        self.interactions = []  # List of ways player can interact with the Npc
        self.isplayer = False  # used for various tests, idk
        self.monsters = [
        ]  # This is a list of tuxemon the npc has. Do not modify directly
        self.inventory = {}  # The Player's inventory.
        # Variables for long-term item and monster storage
        # Keeping these seperate so other code can safely
        # assume that all values are lists
        self.monster_boxes = dict()
        self.item_boxes = dict()

        # combat related
        self.ai = None  # Whether or not this player has AI associated with it
        self.speed = 10  # To determine combat order (not related to movement!)
        self.moves = []  # list of techniques

        # pathfinding and waypoint related
        self.pathfinding = None
        self.path = []
        self.final_move_dest = [
            0, 0
        ]  # Stores the final destination sent from a client

        # This is used to 'set back' when lost, and make movement robust.
        # If entity falls off of map due to a bug, it can be returned to this value.
        # When moving to a waypoint, this is used to detect if movement has overshot
        # the destination due to speed issues or framerate jitters.
        self.path_origin = None

        # movement related
        self.move_direction = None  # Set this value to move the npc (see below)
        self.facing = "down"  # Set this value to change the facing direction
        self.moverate = CONFIG.player_walkrate  # walk by default
        self.ignore_collisions = False

        # What is "move_direction"?
        # Move direction allows other functions to move the npc in a controlled way.
        # To move the npc, change the value to one of four directions: left, right, up or down.
        # The npc will then move one tile in that direction until it is set to None.

        # TODO: move sprites into renderer so class can be used headless
        self.playerHeight = 0
        self.playerWidth = 0
        self.standing = {}  # Standing animation frames
        self.sprite = {}  # Moving animation frames
        self.moveConductor = pyganim.PygConductor()
        self.load_sprites()
        self.rect = Rect(
            self.tile_pos,
            (self.playerWidth, self.playerHeight))  # Collision rect
コード例 #24
0
ファイル: sprite.py プロジェクト: sradigan/Tuxemon
 def update_rect_from_parent(self):
     try:
         self.rect = self.parent()
     except TypeError:
         self.rect = Rect(self.parent.rect)
コード例 #25
0
class State(object):
    """ This is a prototype class for States.

    All states should inherit from it. No direct instances of this
    class should be created. Update must be overloaded in the child class.

    Overview of Methods:
       startup       - Called when added to the state stack
       resume        - Called each time state is updated for first time
       update        - Called each frame while state is active
       process_event - Called when there is a new input event
       pause         - Called when state is no longer active
       shutdown      - Called before state is destroyed

    :ivar client: tuxemon.core.session.Client
    :cvar force_draw: If True, state will never be skipped in drawing phase
    :cvar rect: Area of the screen will be drawn on
    """
    __metaclass__ = ABCMeta

    rect = Rect((0, 0), prepare.SCREEN_SIZE)
    transparent = False   # ignore all background/borders
    force_draw = False    # draw even if completely under another state

    def __init__(self, client):
        """ Do not override this unless there is a special need.

        All init for the State, loading of config, images, etc should
        be done in State.startup or State.resume, not here.

        :param tuxemon.core.client.Client client: State Manager / Game Client
        :returns: None
        """
        self.client = client
        self.start_time = 0.0
        self.current_time = 0.0
        self.animations = pygame.sprite.Group()  # only animations and tasks
        self.sprites = SpriteGroup()             # all sprites that draw on the screen

    @property
    def name(self):
        return self.__class__.__name__

    def load_sprite(self, filename, **kwargs):
        """ Load a sprite and add it to this state

        kwargs can be any value used by Rect, or layer

        :param filename: filename, relative to the resources folder
        :type filename: String
        :param kwargs: Keyword arguments to pass to the Rect constructor
        :returns: tuxemon.core.sprite.Sprite
        """
        layer = kwargs.pop('layer', 0)
        sprite = graphics.load_sprite(filename, **kwargs)
        self.sprites.add(sprite, layer=layer)
        return sprite

    def animate(self, *targets, **kwargs):
        """ Animate something in this state

        Animations are processed even while state is inactive

        :param targets: targets of the Animation
        :type targets: any
        :param kwargs: Attributes and their final value
        :returns: tuxemon.core.animation.Animation
        """
        ani = Animation(*targets, **kwargs)
        self.animations.add(ani)
        return ani

    def task(self, *args, **kwargs):
        """ Create a task for this state

        Tasks are processed even while state is inactive
        If you want to pass positional arguments, use functools.partial

        :param args: function to be called
        :param kwargs: kwargs passed to the function
        :returns: tuxemon.core.animation.Task
        """
        task = Task(*args, **kwargs)
        self.animations.add(task)
        return task

    def remove_animations_of(self, target):
        """ Given and object, remove any animations that it is used with

        :param target: any
        :returns: None
        """
        remove_animations_of(target, self.animations)

    def process_event(self, event):
        """ Handles player input events. This function is only called when the
        player provides input such as pressing a key or clicking the mouse.

        Since this is part of a chain of event handlers, the return value
        from this method becomes input for the next one.  Returning None
        signifies that this method has dealt with an event and wants it
        exclusively.  Return the event and others can use it as well.

        You should return None if you have handled input here.

        :type event: tuxemon.core.input.PlayerInput
        :rtype: Optional[core.input.PlayerInput]
        """
        return event

    def update(self, time_delta):
        """ Time update function for state.  Must be overloaded in children.

        :param time_delta: amount of time in fractional seconds since last update
        :type time_delta: Float
        :returns: None
        :rtype: None
        """
        self.animations.update(time_delta)

    def draw(self, surface):
        """ Render the state to the surface passed.  Must be overloaded in children

        Do not change the state of any game entities.  Every draw should be the same
        for a given game time.  Any game changes should be done during update.

        :param surface: Surface to be rendered onto
        :type surface: pygame.Surface
        :returns: None
        :rtype: None
        """
        pass

    def startup(self, **kwargs):
        """ Called when scene is added to State Stack

        This will be called:
        * after state is pushed and before next update
        * just once during the life of a state

        Example uses: loading images, configuration, sounds.

        :param kwargs: Configuration options
        :returns: None
        :rtype: None
        """
        pass

    def resume(self):
        """ Called before update when state is newly in focus

        This will be called:
        * before update after being pushed to the stack
        * before update after state has been paused

        After being called, state will begin to receive player input
        Could be called several times over lifetime of state

        Example uses: starting music, open menu, starting animations, timers, etc

        :returns: None
        :rtype: None
        """
        pass

    def pause(self):
        """ Called when state is pushed back in the stack, allowed to pause

        This will be called:
        * after update when state is pushed back
        * before being shutdown

        After being called, state will no longer receive player input
        Could be called several times over lifetime of state

        Example uses: stopping music, sounds, fading out, making state graphics dim

        :returns: None
        :rtype: None
        """
        pass

    def shutdown(self):
        """ Called when state is removed from stack and will be destroyed

        This will be called:
        * after update when state is popped

        Make sure to release any references to objects that may cause
        cyclical dependencies.

        :returns: None
        :rtype: None
        """
        pass
コード例 #26
0
 def update_image(self):
     rect = Rect((0, 0), self._rect.size)
     surface = pygame.Surface(rect.size, pygame.SRCALPHA)
     self._original_image = surface
     self._image = surface
     self._draw(surface, rect)
コード例 #27
0
ファイル: sprite.py プロジェクト: sradigan/Tuxemon
class SpriteGroup(pygame.sprite.LayeredUpdates):
    """ Sane variation of a pygame sprite group

    Features:
    * Supports Layers
    * Supports Index / Slice
    * Supports skipping sprites without an image
    * Supports sprites with visible flag
    * Get bounding rect of all children

    Variations from standard group:
    * SpriteGroup.add no longer accepts a sequence, use SpriteGroup.extend
    """
    _init_rect = Rect(0, 0, 0, 0)

    def __init__(self, *args, **kwargs):
        self._spritelayers = dict()
        self._spritelist = list()
        pygame.sprite.AbstractGroup.__init__(self)
        self._default_layer = kwargs.get('default_layer', 0)

    def __nonzero__(self):
        return bool(self._spritelist)

    def __getitem__(self, item):
        # patch in indexing / slicing support
        return self._spritelist.__getitem__(item)

    def draw(self, surface):
        spritedict = self.spritedict
        surface_blit = surface.blit
        dirty = self.lostsprites
        self.lostsprites = []
        dirty_append = dirty.append

        for s in self.sprites():
            if getattr(s, "image", None) is None:
                continue

            if not getattr(s, 'visible', True):
                continue

            if isinstance(s.image, PygAnimation):
                s.image.blit(surface, s.rect)
                continue

            r = spritedict[s]
            newrect = surface_blit(s.image, s.rect)
            if r:
                if newrect.colliderect(r):
                    dirty_append(newrect.union(r))
                else:
                    dirty_append(newrect)
                    dirty_append(r)
            else:
                dirty_append(newrect)
            spritedict[s] = newrect
        return dirty

    def extend(self, sprites, **kwargs):
        """ Add a sequence of sprites to the SpriteGroup

        :param sprites: Sequence (list, set, etc)
        :param kwargs:
        :returns: None
        """
        if '_index' in kwargs.keys():
            raise KeyError
        for index, sprite in enumerate(sprites):
            kwargs['_index'] = index
            self.add(sprite, **kwargs)

    def add(self, sprite, **kwargs):
        """ Add a sprite to group.  do not pass a sequence or iterator

        LayeredUpdates.add(*sprites, **kwargs): return None
        If the sprite you add has an attribute _layer, then that layer will be
        used. If **kwarg contains 'layer', then the passed sprites will be
        added to that layer (overriding the sprite._layer attribute). If
        neither the sprite nor **kwarg has a 'layer', then the default layer is
        used to add the sprites.
        """
        layer = kwargs.get('layer')
        if isinstance(sprite, pygame.sprite.Sprite):
            if not self.has_internal(sprite):
                self.add_internal(sprite, layer)
                sprite.add_internal(self)
        else:
            raise TypeError

    def calc_bounding_rect(self):
        """A rect object that contains all sprites of this group
        """
        sprites = self.sprites()
        if not sprites:
            return self.rect
        elif len(sprites) == 1:
            return Rect(sprites[0].rect)
        else:
            return sprites[0].rect.unionall([s.rect for s in sprites[1:]])
コード例 #28
0
ファイル: __init__.py プロジェクト: sradigan/Tuxemon
 def calc_menu_items_rect(self):
     width, height = self.rect.size
     left = width // 2.25
     top = height // 12
     width /= 2
     return Rect(left, top, width, height - top * 2)
コード例 #29
0
def scale_area(area):
    return Rect(tools.scale_sequence(area))
コード例 #30
0
 def get_rect(self):
     # Returns a Rect object for this animation object.
     # The top and left will be set to 0, 0, and the width and height
     # will be set to what is returned by getMaxSize().
     maxWidth, maxHeight = self.getMaxSize()
     return Rect(0, 0, maxWidth, maxHeight)