Ejemplo n.º 1
0
class PrTracks:
    """
        PrTracks
        ========

        provides object which manage track instruction groups

        1. Container instruction group for canvas
        2. List of PrTracks
        3. show/hide tracks
        4. z-order handling
        
    """
    def __init__(self):
        self.container = InstructionGroup()
        self.tracks = {}

    def get(self, idx):
        if idx in self.tracks:
            return self.tracks[idx]

    def add(self, idx, track):
        self.tracks[idx] = track
        self.container.add(track.canvas)

    def remove(self, idx):
        self.container.remove(self.tracks[idx].canvas)
        self.tracks[idx] = None

    def show(self, idx):
        track = self.tracks[idx]
        if track:
            if self.tracks[idx].visible == False:
                # self.container.add(track.canvas)
                # track.visible = True
                track.show()

    def hide(self, idx):
        track = self.tracks[idx]
        if track:
            if self.tracks[idx].visible:
                # self.container.remove(track.canvas)
                # track.visible = False
                track.hide()

    def draw(self):
        self.container.clear()
        for key in self.tracks:
            self.container.add(self.tracks[key].canvas)
        return self.container
Ejemplo n.º 2
0
class LetterGrid(Widget):
    """An instance is a grid of letter boxes. 
    
    While letter boxes are arranged in a grid, not all grids must have a
    letter box.  This allows us to represent a seven-cross.
    
    Instance Attributes:
        cols: number of columns in the grid [int > 0]
        rows: number of rows in the grid [int > 0]
        foreground: the foreground color [4 element list of floats]
        background: the background color [4 element list of floats]
        textcolor: the text color [4 element list of floats]
        font_size: the size of the font [int > 0]
        bold: whether the font is bolded [boolean]
        italic: whether the font is in italics [boolean]
        border: the border size in pixels [odd, positive integer]
        
        _labels: the collection of all letter boxes [map of tuples to LetterBox]
        _back: drawing layer for unpressed boxes
        _front: drawing layer for pressed boxes
    """
    # Computed propery
    @property
    def cellsize(self):
        """A 2-element tuple with the cellsize in pixels."""
        if self._resized:
            width  = self.size[0]/float(self.cols)
            height = self.size[1]/float(self.rows)
            self._cellsize = (width, height)
            self._resized = False
        return self._cellsize
    
    # Kivy style properties for KV sheets
    cols = NumericProperty(1)
    rows = NumericProperty(1)
    border    = NumericProperty(3)
    font_size = NumericProperty(36)
    bold   = BooleanProperty(True)
    italic = BooleanProperty(False)
    foreground = ListProperty([0,0,0,1])
    background = ListProperty([1,1,1,1])
    textcolor  = ListProperty([1,0,0,1])
    
    def __init__(self, **kw):
        """**Constructor**: Create a new letter box
        
            :param keywords: dictionary of keyword arguments 
            **Precondition**: See below.
        
        To use the constructor for this class, you should provide
        it with a list of keyword arguments that initialize various
        attributes.  For example, to initialize a 2x3 grid, use
        the constructor call
        
            GObject(rows=2,cols=3)
        
        You do not need to provide the keywords as a dictionary.
        The ** in the parameter `keywords` does that automatically.
        
        Any attribute of this class may be used as a keyword.  The
        argument must satisfy the invariants of that attribute.  See
        the list of attributes of this class for more information."""
        Widget.__init__(self,**kw)
        self._resized = True
        self._labels = dict()
        self._set_properties(kw)
        self.bind(pos=self._reposition)
        
        # Create a layer for proper state control.
        self._back  = InstructionGroup()
        self._front = InstructionGroup()
        self.canvas.add(self._back)
        self.canvas.add(self._front)
        
        # Bind kivy attributes to methods
        self.bind(size=self._resize)
        self.bind(cols=self._resize)
        self.bind(rows=self._resize)
        self.bind(border=self._set_border)
        self.bind(font_size=self._set_font_size)
        self.bind(bold=self._set_bold)
        self.bind(italic=self._set_italic)
        self.bind(foreground=self._set_foreground)
        self.bind(background=self._set_background)
        self.bind(textcolor=self._set_textcolor)
    
    def clear(self):
        """Reset the entire letter grid, eliminating all letter boxes."""
        self._labels = dict()
       
        self.canvas.clear()
        self.canvas.add(Color(0,0,0,1))
        self.canvas.add(Rectangle(pos=self.pos,size=self.size))
        
        self._back  = InstructionGroup()
        self._front = InstructionGroup()
        self.canvas.add(self._back)
        self.canvas.add(self._front)
    
    def _set_properties(self,kw):
        """Sets the letter box attributes according to kw
        
        If an attribute is not in kw, the attribute is set to a default.
        
            :param keywords: dictionary of keyword arguments 
            **Precondition**: Same as __init__"""
        if 'cols' in kw:
            self.cols = kw['cols']
        
        if 'rows' in kw:
            self.rows = kw['rows']
        
        if 'background' in kw:
            self.background = kw['background']
        
        if 'foreground' in kw:
            self.foreground = kw['foreground']
        
        if 'textcolor' in kw:
            self.textcolor = kw['textcolor']
        
        if 'border' in kw:
            self.border =kw['border']
    
        if 'font_size' in kw:
            self.fontsize =kw['font_size']
        
        if 'bold' in kw:
            self.bold =kw['bold']
        
        if 'italic' in kw:
            self.italic =kw['italic']
    
    # Methods to update the letter grid
    def add_cell(self, s, col, row):
        """Adds a new cell to the letter grid.
        
        The letter grid has s as its initial text.
        
        If the cell already exists, it replaces the text with s.
        
        Precondition: row and col are valid indices in the grid.  s is a string."""
        assert row >= 0 and row < self.rows, 'Row '+`row`+' is out of range [0,'+`self.rows`+']'
        assert col >= 0 and col < self.cols, 'Row '+`col`+' is out of range [0,'+`self.cols`+']'
        if (col,row) in self._labels:
            self._labels[(col,row)].text = s
            return
        
        label = LetterBox(text=s, fontsize=self.font_size, color=self.textcolor)
        label.bold   = self.bold
        label.italic = self.italic
        label.size   = self.cellsize
        x = self.pos[0] + col*self.cellsize[0]
        y = self.pos[1] + row*self.cellsize[1]
        label.pos = [x,y]
        self._labels[(col,row)] = label
        self._back.add(label.canvas)
    
    def delete_cell(self, col, row):
        """Deletes the LetterBox at col and row.
        
        If there is no LetterBox at that position, this method does nothing.
        
        Precondition: row and col are valid indices in the grid."""
        if not (col, row) in self._labels:
            return
        
        label = self._labels[(col,row)]
        self._back.remove(label.canvas)
        del self._labels[(col,row)]
    
    def get_cell(self, col, row):
        """Returns the LetterBox at col and row.
        
        If there is no LetterBox at that position, it returns None.
        
        Precondition: row and col are valid indices in the grid."""
        assert row >= 0 and row < self.rows, 'Row '+`row`+' is out of range [0,'+`self.rows`+']'
        assert col >= 0 and col < self.cols, 'Row '+`col`+' is out of range [0,'+`self.cols`+']'

        if not (col, row) in self._labels:
            return None
            
        return self._labels[(col,row)]
    
    def toggle_cell(self, col, row):
        """Toggles the state of the LetterBox at col and row.
        
        If there is no LetterBox at that position, it does nothing.
        
        Precondition: row and col are valid indices in the grid."""
        if not (col, row) in self._labels:
            return
        
        label = self._labels[(col,row)]
        label.state = not label.state
        tmp = label.foreground
        label.foreground = label.background
        label.background = tmp
        tmp = label.textcolor
        tmp = map(lambda x: 1-x, tmp[:-1])+tmp[-1:]
        label.textcolor = tmp
        if label.state:
            self._front.add(label.canvas)
            return True
        
        self._front.remove(label.canvas)
        return False

    # Call Back Methods
    def _reposition(self,obj,value):
        """Repositions the graphics object.
        
        This function is called by Kivy services, so it passes the
        object and new position as an argument."""
        for pos in self._labels:
            self._labels[pos].pos[0] = self.pos[0]+self.cellsize[0]*pos[0]
            self._labels[pos].pos[1] = self.pos[1]+self.cellsize[1]*pos[1]
    
    def _resize(self,obj,value):
        """Resizes the graphics object.
        
        This function is called by Kivy services, so it passes the
        object and new size as an argument."""
        self._resized = True
        for pos in self._labels:
            self._labels[pos].size = self.cellsize
            self._labels[pos].pos[0] = self.pos[0]+self.cellsize[0]*pos[0]
            self._labels[pos].pos[1] = self.pos[1]+self.cellsize[1]*pos[1]
    
    def _set_border(self,obj,value):
        """Updates the border attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].border = value
    
    def _set_font_size(self,obj,value):
        """Updates the font size attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].fontsize = value
    
    def _set_bold(self,obj,value):
        """Updates the bold attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].bold = value
    
    def _set_italic(self,obj,value):
        """Updates the italic attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].italic = value
    
    def _set_foreground(self,obj,value):
        """Updates the foreground attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].foreground = list(value)
    
    def _set_background(self,obj,value):
        """Updates the background attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].background = list(value)
    
    def _set_textcolor(self,obj,value):
        """Updates the text color attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].textcolor = list(value)
Ejemplo n.º 3
0
class LetterGrid(Widget):
    """An instance is a grid of letter boxes. 
    
    While letter boxes are arranged in a grid, not all grids must have a
    letter box.  This allows us to represent a seven-cross.
    
    Instance Attributes:
        cols: number of columns in the grid [int > 0]
        rows: number of rows in the grid [int > 0]
        foreground: the foreground color [4 element list of floats]
        background: the background color [4 element list of floats]
        textcolor: the text color [4 element list of floats]
        font_size: the size of the font [int > 0]
        bold: whether the font is bolded [boolean]
        italic: whether the font is in italics [boolean]
        border: the border size in pixels [odd, positive integer]
        
        _labels: the collection of all letter boxes [map of tuples to LetterBox]
        _back: drawing layer for unpressed boxes
        _front: drawing layer for pressed boxes
    """
    # Computed propery
    @property
    def cellsize(self):
        """A 2-element tuple with the cellsize in pixels."""
        if self._resized:
            width = self.size[0] / float(self.cols)
            height = self.size[1] / float(self.rows)
            self._cellsize = (width, height)
            self._resized = False
        return self._cellsize

    # Kivy style properties for KV sheets
    cols = NumericProperty(1)
    rows = NumericProperty(1)
    border = NumericProperty(3)
    font_size = NumericProperty(36)
    bold = BooleanProperty(True)
    italic = BooleanProperty(False)
    foreground = ListProperty([0, 0, 0, 1])
    background = ListProperty([1, 1, 1, 1])
    textcolor = ListProperty([1, 0, 0, 1])

    def __init__(self, **kw):
        """**Constructor**: Create a new letter box
        
            :param keywords: dictionary of keyword arguments 
            **Precondition**: See below.
        
        To use the constructor for this class, you should provide
        it with a list of keyword arguments that initialize various
        attributes.  For example, to initialize a 2x3 grid, use
        the constructor call
        
            GObject(rows=2,cols=3)
        
        You do not need to provide the keywords as a dictionary.
        The ** in the parameter `keywords` does that automatically.
        
        Any attribute of this class may be used as a keyword.  The
        argument must satisfy the invariants of that attribute.  See
        the list of attributes of this class for more information."""
        Widget.__init__(self, **kw)
        self._resized = True
        self._labels = dict()
        self._set_properties(kw)
        self.bind(pos=self._reposition)

        # Create a layer for proper state control.
        self._back = InstructionGroup()
        self._front = InstructionGroup()
        self.canvas.add(self._back)
        self.canvas.add(self._front)

        # Bind kivy attributes to methods
        self.bind(size=self._resize)
        self.bind(cols=self._resize)
        self.bind(rows=self._resize)
        self.bind(border=self._set_border)
        self.bind(font_size=self._set_font_size)
        self.bind(bold=self._set_bold)
        self.bind(italic=self._set_italic)
        self.bind(foreground=self._set_foreground)
        self.bind(background=self._set_background)
        self.bind(textcolor=self._set_textcolor)

    def clear(self):
        """Reset the entire letter grid, eliminating all letter boxes."""
        self._labels = dict()

        self.canvas.clear()
        self.canvas.add(Color(0, 0, 0, 1))
        self.canvas.add(Rectangle(pos=self.pos, size=self.size))

        self._back = InstructionGroup()
        self._front = InstructionGroup()
        self.canvas.add(self._back)
        self.canvas.add(self._front)

    def _set_properties(self, kw):
        """Sets the letter box attributes according to kw
        
        If an attribute is not in kw, the attribute is set to a default.
        
            :param keywords: dictionary of keyword arguments 
            **Precondition**: Same as __init__"""
        if 'cols' in kw:
            self.cols = kw['cols']

        if 'rows' in kw:
            self.rows = kw['rows']

        if 'background' in kw:
            self.background = kw['background']

        if 'foreground' in kw:
            self.foreground = kw['foreground']

        if 'textcolor' in kw:
            self.textcolor = kw['textcolor']

        if 'border' in kw:
            self.border = kw['border']

        if 'font_size' in kw:
            self.fontsize = kw['font_size']

        if 'bold' in kw:
            self.bold = kw['bold']

        if 'italic' in kw:
            self.italic = kw['italic']

    # Methods to update the letter grid
    def add_cell(self, s, col, row):
        """Adds a new cell to the letter grid.
        
        The letter grid has s as its initial text.
        
        If the cell already exists, it replaces the text with s.
        
        Precondition: row and col are valid indices in the grid.  s is a string."""
        assert row >= 0 and row < self.rows, 'Row ' + ` row ` + ' is out of range [0,' + ` self.rows ` + ']'
        assert col >= 0 and col < self.cols, 'Row ' + ` col ` + ' is out of range [0,' + ` self.cols ` + ']'
        if (col, row) in self._labels:
            self._labels[(col, row)].text = s
            return

        label = LetterBox(text=s,
                          fontsize=self.font_size,
                          color=self.textcolor)
        label.bold = self.bold
        label.italic = self.italic
        label.size = self.cellsize
        x = self.pos[0] + col * self.cellsize[0]
        y = self.pos[1] + row * self.cellsize[1]
        label.pos = [x, y]
        self._labels[(col, row)] = label
        self._back.add(label.canvas)

    def delete_cell(self, col, row):
        """Deletes the LetterBox at col and row.
        
        If there is no LetterBox at that position, this method does nothing.
        
        Precondition: row and col are valid indices in the grid."""
        if not (col, row) in self._labels:
            return

        label = self._labels[(col, row)]
        self._back.remove(label.canvas)
        del self._labels[(col, row)]

    def get_cell(self, col, row):
        """Returns the LetterBox at col and row.
        
        If there is no LetterBox at that position, it returns None.
        
        Precondition: row and col are valid indices in the grid."""
        assert row >= 0 and row < self.rows, 'Row ' + ` row ` + ' is out of range [0,' + ` self.rows ` + ']'
        assert col >= 0 and col < self.cols, 'Row ' + ` col ` + ' is out of range [0,' + ` self.cols ` + ']'

        if not (col, row) in self._labels:
            return None

        return self._labels[(col, row)]

    def toggle_cell(self, col, row):
        """Toggles the state of the LetterBox at col and row.
        
        If there is no LetterBox at that position, it does nothing.
        
        Precondition: row and col are valid indices in the grid."""
        if not (col, row) in self._labels:
            return

        label = self._labels[(col, row)]
        label.state = not label.state
        tmp = label.foreground
        label.foreground = label.background
        label.background = tmp
        tmp = label.textcolor
        tmp = map(lambda x: 1 - x, tmp[:-1]) + tmp[-1:]
        label.textcolor = tmp
        if label.state:
            self._front.add(label.canvas)
            return True

        self._front.remove(label.canvas)
        return False

    # Call Back Methods
    def _reposition(self, obj, value):
        """Repositions the graphics object.
        
        This function is called by Kivy services, so it passes the
        object and new position as an argument."""
        for pos in self._labels:
            self._labels[pos].pos[0] = self.pos[0] + self.cellsize[0] * pos[0]
            self._labels[pos].pos[1] = self.pos[1] + self.cellsize[1] * pos[1]

    def _resize(self, obj, value):
        """Resizes the graphics object.
        
        This function is called by Kivy services, so it passes the
        object and new size as an argument."""
        self._resized = True
        for pos in self._labels:
            self._labels[pos].size = self.cellsize
            self._labels[pos].pos[0] = self.pos[0] + self.cellsize[0] * pos[0]
            self._labels[pos].pos[1] = self.pos[1] + self.cellsize[1] * pos[1]

    def _set_border(self, obj, value):
        """Updates the border attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].border = value

    def _set_font_size(self, obj, value):
        """Updates the font size attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].fontsize = value

    def _set_bold(self, obj, value):
        """Updates the bold attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].bold = value

    def _set_italic(self, obj, value):
        """Updates the italic attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].italic = value

    def _set_foreground(self, obj, value):
        """Updates the foreground attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].foreground = list(value)

    def _set_background(self, obj, value):
        """Updates the background attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].background = list(value)

    def _set_textcolor(self, obj, value):
        """Updates the text color attribute.
        
        This method propagates its value across all LetterBoxes in the grid.
        
        This function is called by Kivy services, so it passes the object and
        new attribute value as an argument."""
        for pos in self._labels:
            self._labels[pos].textcolor = list(value)
Ejemplo n.º 4
0
class World:
    RADIUS_WIDTH = 2
    RADIUS_HEIGHT = 2
    LOAD_RADIUS = 1

    def __init__(self, pos: Tuple[float, float]):
        self.world_group = InstructionGroup()
        self.top_group = InstructionGroup()

        chunk_pos = World.get_chunk_coords_from_pos(pos)

        self.loaded_center = chunk_pos
        self.seed = random.randint(0, 2**32 - 1)
        self.chunks = dict()

        self.loaded_chunks = [[
            None
            for _ in World.get_loaded_range(chunk_pos[0], World.RADIUS_WIDTH)
        ] for _ in World.get_loaded_range(chunk_pos[1], World.RADIUS_HEIGHT)]

        size = Chunk.SIZE, Chunk.SIZE
        self.terrain_instructions = [[
            Sprite(None, (0, 0), size)
            for _ in World.get_loaded_range(chunk_pos[0], World.RADIUS_WIDTH)
        ] for _ in World.get_loaded_range(chunk_pos[1], World.RADIUS_HEIGHT)]

        self.features_chunk_instructions = [[
            InstructionGroup()
            for _ in World.get_loaded_range(chunk_pos[0], World.RADIUS_WIDTH)
        ] for _ in World.get_loaded_range(chunk_pos[1], World.RADIUS_HEIGHT)]

        self.top_features_chunk_instructions = [[
            InstructionGroup()
            for _ in World.get_loaded_range(chunk_pos[0], World.RADIUS_WIDTH)
        ] for _ in World.get_loaded_range(chunk_pos[1], World.RADIUS_HEIGHT)]

        for row in self.features_chunk_instructions:
            for instruction in row:
                self.world_group.add(instruction)

        self.load_area(self.loaded_center)

    def get_chunk_from_coords(self, pos):
        coords = self.get_chunk_coords_from_pos(pos)
        return self.chunks[coords[1]][coords[0]]

    def get_chunk_in_range(self, rng: int):
        for y in World.get_loaded_range(World.RADIUS_HEIGHT, rng):
            for x in World.get_loaded_range(World.RADIUS_WIDTH, rng):
                yield self.loaded_chunks[y][x]

    def update(self, pos: Tuple[float, float]):
        x, y = pos

        x, y = World.get_chunk_coords_from_pos((x, y))
        lx, ly = self.loaded_center

        if x + World.LOAD_RADIUS == lx or x - World.LOAD_RADIUS == lx or x == lx:
            if y + World.LOAD_RADIUS == ly or y - World.LOAD_RADIUS == ly or y == ly:
                return

        self.loaded_center = x, y
        self.load_area(self.loaded_center)

    def draw(self, canvas: RenderContext):
        for row in self.terrain_instructions:
            for terrain in row:
                terrain.draw(canvas)

        canvas.add(self.world_group)

    def draw_top(self, canvas: RenderContext):
        canvas.add(self.top_group)

    def render_chunk_at(self, x: int, y: int):
        instruction_group = self.features_chunk_instructions[y][x]
        self.world_group.remove(instruction_group)
        top_instruction_group = self.top_features_chunk_instructions[y][x]
        self.top_group.remove(top_instruction_group)

        instruction_group = InstructionGroup()
        self.features_chunk_instructions[y][x] = instruction_group
        self.world_group.add(instruction_group)

        top_instruction_group = InstructionGroup()
        self.top_features_chunk_instructions[y][x] = top_instruction_group
        self.top_group.add(top_instruction_group)
        self.loaded_chunks[y][x].draw_features(instruction_group,
                                               top_instruction_group)

    def render_chunk(self, chunk):
        for y in range(len(self.loaded_chunks)):
            for x in range(len(self.loaded_chunks[y])):
                if chunk == self.loaded_chunks[y][x]:
                    self.render_chunk_at(x, y)
                    return

    def load_area(self, pos: Tuple[int, int]):
        for index_y, y in enumerate(
                World.get_loaded_range(pos[1], World.RADIUS_HEIGHT)):
            if y not in self.chunks:
                self.chunks[y] = dict()

            row_chunks = self.chunks[y]
            for index_x, x in enumerate(
                    World.get_loaded_range(pos[0], World.RADIUS_WIDTH)):
                if x not in row_chunks:
                    row_chunks[x] = Chunk((x * Chunk.SIZE, y * Chunk.SIZE),
                                          self.seed)

                terrain_instruction = self.terrain_instructions[index_y][
                    index_x]
                self.loaded_chunks[index_y][index_x] = row_chunks[x]
                self.loaded_chunks[index_y][index_x].draw(terrain_instruction)
                self.render_chunk_at(index_x, index_y)

    @staticmethod
    def get_loaded_range(x: int, rng: int):
        return range(x - rng, x + rng + 1)

    @staticmethod
    def get_chunk_coords_from_pos(pos: Tuple[float, float]) -> Tuple[int, int]:
        x, y = pos
        if x < 0:
            x -= Chunk.SIZE
        if y < 0:
            y -= Chunk.SIZE

        return int(x / Chunk.SIZE), int(y / Chunk.SIZE)
Ejemplo n.º 5
0
class SelectAttackState(TurnAction):
    def __init__(self, target, **kwargs):
        super(SelectAttackState, self).__init__(target, **kwargs)
        self.amount = self.target.map.tile_width
        self.moving = False
        self.velocity = [0, 0]
        self.layer = self.target.map.layers.by_name['below']
        self.foreshadowed = self.layer.get_at(*target.center)
        self.move_keys = [Keyboard.keycodes['left'], Keyboard.keycodes['right'],
                          Keyboard.keycodes['up'], Keyboard.keycodes['down'], Keyboard.keycodes['enter']]
        self.travelled = set()
        self.checked = set()
        self.index = {}
        self.instructions = InstructionGroup()
        self.layer = self.target.map.layers.by_name['below']
        self.confirmed = False
        self.effect = MeleeDamage
        tile = self.layer.get_at(*self.target.pos)
        self.cursor = Sprite(pos=[tile.px, tile.py],
                             size=self.target.size, texture=images['cursor'], opacity=0.5)
        self.current_tile = self.target.get_current_cell()
        self.target.game.layer_widgets['sprite_layer'].add_widget(self.cursor)
        self.get_tiles_in_range(tile, 0)
        self.selected = None
        self.last_touched = None
        self.highlight_tiles()

    def highlight_tiles(self):
        for tile in self.travelled:
            self.instructions.add(Color(rgba=[1, .4, .3, .3]))
            self.instructions.add(Rectangle(pos=(tile.px, tile.py), size=(tile.px_width, tile.px_height)))
        self.target.game.layer_widgets['below'].canvas.add(self.instructions)
        # print(self.travelled, self.foreshadowed)

    @memoized
    def get_tiles_in_range(self, tile, moved):
        self.travelled.add(tile)
        if moved < 2:
            for neighbor in self.layer.get_neighbor_cells(tile):
                # if not self.target.map.layers['objects'].collide(Rect(*neighbor.center + (8, 8)), 'wall'):
                self.get_tiles_in_range(neighbor, moved + 1)

    def touch(self, touch, *args):
        print('touch!', touch)
        pos = self.target.map.pixel_from_screen(*touch.pos)
        cell = self.target.map.layers.by_name['below'].get_at(*pos)
        print('at {}.  Found?  {}'.format(pos, cell))
        if cell is not None and cell in self.travelled:
            print('cell not none, found in travels')
            self.cursor.pos = (cell.px, cell.py)
            if cell is self.last_touched:
                if self.get_selected():
                    self.confirm()
            else:
                self.last_touched = cell
                self.highlight_selected(cell)

    def highlight_selected(self, tile):
            if self.selected:
                for s in self.selected:
                    self.instructions.remove(s)
            self.selected = [Color(rgba=[6, .3, .2, .6]),
                             Rectangle(pos=(tile.px, tile.py), size=(tile.px_width, tile.px_height))]
            for a in self.selected:
                self.instructions.add(a)

    def get_selected(self):
        self.selected_targets = []
        for battler in self.target.game.entities:
            # TODO - figure out why this code is selecting both characters...
            print('checks say:', battler is not self.target, not battler.incapacitated,
                  self.cursor.collide_point(*battler.center))
            if battler is not self.target and not battler.incapacitated and self.cursor.collide_point(*battler.center):
                self.selected_targets.append(battler)
        print('selected targets:', self.selected_targets)
        return self.selected_targets

    def update(self, dt):
        if not self.confirmed:
            if not self.moving:
                self.velocity = [0, 0]
                if keys.get(Keyboard.keycodes['left']):
                    self.velocity = self.velocity_dict['left']
                elif keys.get(Keyboard.keycodes['right']):
                    self.velocity = self.velocity_dict['right']
                elif keys.get(Keyboard.keycodes['up']):
                    self.velocity = self.velocity_dict['up']
                elif keys.get(Keyboard.keycodes['down']):
                    self.velocity = self.velocity_dict['down']
                elif keys.get(Keyboard.keycodes['enter']):
                    print('battle_entities currently:', self.target.game.entities)
                    if self.get_selected():
                        self.confirm()
                    else:
                        pass
                elif keys.get(Keyboard.keycodes['backspace']):
                    print('pressed backspace')
                    self.end()
                else:
                    return
                new_x = self.current_tile.x + self.velocity[0]
                new_y = self.current_tile.y + self.velocity[1]
                # print('new not none')
                new_target = self.layer.get_tile(new_x, new_y)
                if new_target and new_target.tile.is_passable() and not new_target.occupied:
                    # print('starting to move!')
                    self.foreshadowed = new_target
                if self.foreshadowed in self.travelled:
                    self.start_moving()

            else:
                self.move(dt)
        else:
            if not self.current_effect.finished:
                self.current_effect.update(dt)
            else:
                self.ready_next_effect()

    def move(self, dt):
        # because we are moving a cursor Sprite and there's a dependency mess, we are pasting here for now
        x, y = self.foreshadowed.px, self.foreshadowed.py
        delta_x = self.cursor.x - x
        delta_y = self.cursor.y - y
        distance = Vector(*self.cursor.pos).distance((x, y))
        if distance >= 0.5:
            delta_x = (delta_x / distance) * (dt * 50)
            delta_y = (delta_y / distance) * (dt * 50)
            new_x, new_y = self.cursor.pos
            new_x += -delta_x
            new_y += -delta_y
            self.cursor.pos = [new_x, new_y]
            distance = Vector(*self.cursor.pos).distance((x, y))
        if distance <= 0.5:
            self.done_moving()
        else:
            return False

    def done_moving(self, *args):
        self.cursor.pos = [self.foreshadowed.px, self.foreshadowed.py]
        self.current_tile = self.foreshadowed
        self.moving = False

    def start_moving(self, *args):
        self.moving = True

    def end(self):
        super(SelectAttackState, self).end()
        self.target.state = BattleMenuState(self.target)
        self.target.game.layer_widgets['below'].canvas.remove(self.instructions)
        self.target.anim_delay = -1
        self.target.reload()  # reset animation
        self.cursor.parent.remove_widget(self.cursor)
Ejemplo n.º 6
0
class SelectMoveState(State):
    def __init__(self, target, **kwargs):
        super(SelectMoveState, self).__init__(target, **kwargs)
        self.amount = self.target.map.tile_width
        self.moving = False
        self.velocity = [0, 0]
        self.layer = self.target.map.layers.by_name['below']
        self.foreshadowed = self.layer.get_at(*target.center)
        self.current_tile = self.target.get_current_cell()
        self.move_keys = [Keyboard.keycodes['left'], Keyboard.keycodes['right'],
                          Keyboard.keycodes['up'], Keyboard.keycodes['down'], Keyboard.keycodes['enter']]
        self.travelled = set()
        self.checked = set()
        self.index = {}
        self.instructions = InstructionGroup()
        self.layer = self.target.map.layers.by_name['below']
        tile = self.layer.get_at(*self.target.pos)
        self.get_tiles_in_range(tile, 0)
        self.last_touched = None
        self.selected = []
        self.highlight_tiles()

    def touch(self, touch, *args):
        print('touch!', touch)
        pos = self.target.map.pixel_from_screen(*touch.pos)
        cell = self.target.map.layers.by_name['below'].get_at(*pos)
        print('at {}.  Found?  {}'.format(pos, cell))
        if cell is not None and cell in self.travelled:
            print('cell not none, found in travels')
            if cell is self.last_touched:
                self.target.set_position(cell.px, cell.py)
                self.end()
            else:
                self.last_touched = cell
                self.highlight_selected(cell)

    def highlight_selected(self, tile):
            if self.selected:
                for s in self.selected:
                    self.instructions.remove(s)
            self.selected = [Color(rgba=[6, .3, .2, .6]),
                             Rectangle(pos=(tile.px, tile.py), size=(tile.px_width, tile.px_height))]
            for a in self.selected:
                self.instructions.add(a)

    def highlight_tiles(self):
        for tile in self.travelled:
            self.instructions.add(Color(rgba=[.3, .5, .8, .5]))
            self.instructions.add(Rectangle(pos=(tile.px, tile.py), size=(tile.px_width, tile.px_height)))
        self.target.game.layer_widgets['below'].canvas.add(self.instructions)

    @memoized
    def get_tiles_in_range(self, tile, moved):
        self.travelled.add(tile)
        # did this to keep smallest range possible to reach selected tile, for calculating cost at end of move state
        self.index[tile] = min(self.index.get(tile, 1000), moved)
        if moved < self.target.move_range():
            for neighbor in self.layer.get_neighbor_cells(tile):
                self.get_tiles_in_range(neighbor, moved + 1)

    def update(self, dt):
        if not self.moving:
            pressed = [key for key in self.move_keys if keys.get(key)]
            if pressed:
                self.velocity = [0, 0]
                if Keyboard.keycodes['left'] in pressed:
                    self.target.set_face('left')
                    self.velocity = self.velocity_dict['left']
                elif Keyboard.keycodes['right'] in pressed:
                    self.target.set_face('right')
                    self.velocity = self.velocity_dict['right']
                elif Keyboard.keycodes['up'] in pressed:
                    self.target.set_face('up')
                    self.velocity = self.velocity_dict['up']
                elif Keyboard.keycodes['down'] in pressed:
                    self.target.set_face('down')
                    self.velocity = self.velocity_dict['down']
                elif keys.get(Keyboard.keycodes['enter']):
                    self.end()
                    return
                self.current_tile = self.target.get_current_cell()
                new_x = self.current_tile.x + self.velocity[0]
                new_y = self.current_tile.y + self.velocity[1]
                # print('new not none')
                new_target = self.layer.get_tile(new_x, new_y)
                if new_target and new_target.tile.is_passable() and not new_target.occupied:
                    # print('starting to move!')
                    self.foreshadowed = new_target
                if self.foreshadowed in self.travelled:
                    self.start_moving()
            else:
                if self.target.anim_delay > 0:
                    self.target.reload()  # reset animation
                self.target.anim_delay = -1
        else:
            self.move(dt)

    def move(self, dt):
        done = move(dt, self.target, self.foreshadowed.px, self.foreshadowed.py)
        if done:
            self.done_moving()

    def done_moving(self, *args):
        self.target.set_position(self.foreshadowed.px, self.foreshadowed.py)
        self.moving = False

    def start_moving(self, *args):
        self.moving = True

    def end(self):
        current = self.layer.get_at(*self.target.center)
        self.target.spend_moves(self.index[self.layer.get_at(*self.target.center)])
        self.target.game.layer_widgets['below'].canvas.remove(self.instructions)
        self.target.anim_delay = -1
        self.target.reload()  # reset animation
        self.target.set_position(current.px, current.py)
        self.target.state = BattleMenuState(self.target)
Ejemplo n.º 7
0
class SelectAttackState(TurnAction):
    def __init__(self, target, **kwargs):
        super(SelectAttackState, self).__init__(target, **kwargs)
        self.amount = self.target.map.tile_width
        self.moving = False
        self.velocity = [0, 0]
        self.layer = self.target.map.layers.by_name['below']
        self.foreshadowed = self.layer.get_at(*target.center)
        self.move_keys = [
            Keyboard.keycodes['left'], Keyboard.keycodes['right'],
            Keyboard.keycodes['up'], Keyboard.keycodes['down'],
            Keyboard.keycodes['enter']
        ]
        self.travelled = set()
        self.checked = set()
        self.index = {}
        self.instructions = InstructionGroup()
        self.layer = self.target.map.layers.by_name['below']
        self.confirmed = False
        self.effect = MeleeDamage
        tile = self.layer.get_at(*self.target.pos)
        self.cursor = Sprite(pos=[tile.px, tile.py],
                             size=self.target.size,
                             texture=images['cursor'],
                             opacity=0.5)
        self.current_tile = self.target.get_current_cell()
        self.target.game.layer_widgets['sprite_layer'].add_widget(self.cursor)
        self.get_tiles_in_range(tile, 0)
        self.selected = None
        self.last_touched = None
        self.highlight_tiles()

    def highlight_tiles(self):
        for tile in self.travelled:
            self.instructions.add(Color(rgba=[1, .4, .3, .3]))
            self.instructions.add(
                Rectangle(pos=(tile.px, tile.py),
                          size=(tile.px_width, tile.px_height)))
        self.target.game.layer_widgets['below'].canvas.add(self.instructions)
        # print(self.travelled, self.foreshadowed)

    @memoized
    def get_tiles_in_range(self, tile, moved):
        self.travelled.add(tile)
        if moved < 2:
            for neighbor in self.layer.get_neighbor_cells(tile):
                # if not self.target.map.layers['objects'].collide(Rect(*neighbor.center + (8, 8)), 'wall'):
                self.get_tiles_in_range(neighbor, moved + 1)

    def touch(self, touch, *args):
        print('touch!', touch)
        pos = self.target.map.pixel_from_screen(*touch.pos)
        cell = self.target.map.layers.by_name['below'].get_at(*pos)
        print('at {}.  Found?  {}'.format(pos, cell))
        if cell is not None and cell in self.travelled:
            print('cell not none, found in travels')
            self.cursor.pos = (cell.px, cell.py)
            if cell is self.last_touched:
                if self.get_selected():
                    self.confirm()
            else:
                self.last_touched = cell
                self.highlight_selected(cell)

    def highlight_selected(self, tile):
        if self.selected:
            for s in self.selected:
                self.instructions.remove(s)
        self.selected = [
            Color(rgba=[6, .3, .2, .6]),
            Rectangle(pos=(tile.px, tile.py),
                      size=(tile.px_width, tile.px_height))
        ]
        for a in self.selected:
            self.instructions.add(a)

    def get_selected(self):
        self.selected_targets = []
        for battler in self.target.game.entities:
            # TODO - figure out why this code is selecting both characters...
            print('checks say:', battler is not self.target,
                  not battler.incapacitated,
                  self.cursor.collide_point(*battler.center))
            if battler is not self.target and not battler.incapacitated and self.cursor.collide_point(
                    *battler.center):
                self.selected_targets.append(battler)
        print('selected targets:', self.selected_targets)
        return self.selected_targets

    def update(self, dt):
        if not self.confirmed:
            if not self.moving:
                self.velocity = [0, 0]
                if keys.get(Keyboard.keycodes['left']):
                    self.velocity = self.velocity_dict['left']
                elif keys.get(Keyboard.keycodes['right']):
                    self.velocity = self.velocity_dict['right']
                elif keys.get(Keyboard.keycodes['up']):
                    self.velocity = self.velocity_dict['up']
                elif keys.get(Keyboard.keycodes['down']):
                    self.velocity = self.velocity_dict['down']
                elif keys.get(Keyboard.keycodes['enter']):
                    print('battle_entities currently:',
                          self.target.game.entities)
                    if self.get_selected():
                        self.confirm()
                    else:
                        pass
                elif keys.get(Keyboard.keycodes['backspace']):
                    print('pressed backspace')
                    self.end()
                else:
                    return
                new_x = self.current_tile.x + self.velocity[0]
                new_y = self.current_tile.y + self.velocity[1]
                # print('new not none')
                new_target = self.layer.get_tile(new_x, new_y)
                if new_target and new_target.tile.is_passable(
                ) and not new_target.occupied:
                    # print('starting to move!')
                    self.foreshadowed = new_target
                if self.foreshadowed in self.travelled:
                    self.start_moving()

            else:
                self.move(dt)
        else:
            if not self.current_effect.finished:
                self.current_effect.update(dt)
            else:
                self.ready_next_effect()

    def move(self, dt):
        # because we are moving a cursor Sprite and there's a dependency mess, we are pasting here for now
        x, y = self.foreshadowed.px, self.foreshadowed.py
        delta_x = self.cursor.x - x
        delta_y = self.cursor.y - y
        distance = Vector(*self.cursor.pos).distance((x, y))
        if distance >= 0.5:
            delta_x = (delta_x / distance) * (dt * 50)
            delta_y = (delta_y / distance) * (dt * 50)
            new_x, new_y = self.cursor.pos
            new_x += -delta_x
            new_y += -delta_y
            self.cursor.pos = [new_x, new_y]
            distance = Vector(*self.cursor.pos).distance((x, y))
        if distance <= 0.5:
            self.done_moving()
        else:
            return False

    def done_moving(self, *args):
        self.cursor.pos = [self.foreshadowed.px, self.foreshadowed.py]
        self.current_tile = self.foreshadowed
        self.moving = False

    def start_moving(self, *args):
        self.moving = True

    def end(self):
        super(SelectAttackState, self).end()
        self.target.state = BattleMenuState(self.target)
        self.target.game.layer_widgets['below'].canvas.remove(
            self.instructions)
        self.target.anim_delay = -1
        self.target.reload()  # reset animation
        self.cursor.parent.remove_widget(self.cursor)
Ejemplo n.º 8
0
class SelectMoveState(State):
    def __init__(self, target, **kwargs):
        super(SelectMoveState, self).__init__(target, **kwargs)
        self.amount = self.target.map.tile_width
        self.moving = False
        self.velocity = [0, 0]
        self.layer = self.target.map.layers.by_name['below']
        self.foreshadowed = self.layer.get_at(*target.center)
        self.current_tile = self.target.get_current_cell()
        self.move_keys = [
            Keyboard.keycodes['left'], Keyboard.keycodes['right'],
            Keyboard.keycodes['up'], Keyboard.keycodes['down'],
            Keyboard.keycodes['enter']
        ]
        self.travelled = set()
        self.checked = set()
        self.index = {}
        self.instructions = InstructionGroup()
        self.layer = self.target.map.layers.by_name['below']
        tile = self.layer.get_at(*self.target.pos)
        self.get_tiles_in_range(tile, 0)
        self.last_touched = None
        self.selected = []
        self.highlight_tiles()

    def touch(self, touch, *args):
        print('touch!', touch)
        pos = self.target.map.pixel_from_screen(*touch.pos)
        cell = self.target.map.layers.by_name['below'].get_at(*pos)
        print('at {}.  Found?  {}'.format(pos, cell))
        if cell is not None and cell in self.travelled:
            print('cell not none, found in travels')
            if cell is self.last_touched:
                self.target.set_position(cell.px, cell.py)
                self.end()
            else:
                self.last_touched = cell
                self.highlight_selected(cell)

    def highlight_selected(self, tile):
        if self.selected:
            for s in self.selected:
                self.instructions.remove(s)
        self.selected = [
            Color(rgba=[6, .3, .2, .6]),
            Rectangle(pos=(tile.px, tile.py),
                      size=(tile.px_width, tile.px_height))
        ]
        for a in self.selected:
            self.instructions.add(a)

    def highlight_tiles(self):
        for tile in self.travelled:
            self.instructions.add(Color(rgba=[.3, .5, .8, .5]))
            self.instructions.add(
                Rectangle(pos=(tile.px, tile.py),
                          size=(tile.px_width, tile.px_height)))
        self.target.game.layer_widgets['below'].canvas.add(self.instructions)

    @memoized
    def get_tiles_in_range(self, tile, moved):
        self.travelled.add(tile)
        # did this to keep smallest range possible to reach selected tile, for calculating cost at end of move state
        self.index[tile] = min(self.index.get(tile, 1000), moved)
        if moved < self.target.move_range():
            for neighbor in self.layer.get_neighbor_cells(tile):
                self.get_tiles_in_range(neighbor, moved + 1)

    def update(self, dt):
        if not self.moving:
            pressed = [key for key in self.move_keys if keys.get(key)]
            if pressed:
                self.velocity = [0, 0]
                if Keyboard.keycodes['left'] in pressed:
                    self.target.set_face('left')
                    self.velocity = self.velocity_dict['left']
                elif Keyboard.keycodes['right'] in pressed:
                    self.target.set_face('right')
                    self.velocity = self.velocity_dict['right']
                elif Keyboard.keycodes['up'] in pressed:
                    self.target.set_face('up')
                    self.velocity = self.velocity_dict['up']
                elif Keyboard.keycodes['down'] in pressed:
                    self.target.set_face('down')
                    self.velocity = self.velocity_dict['down']
                elif keys.get(Keyboard.keycodes['enter']):
                    self.end()
                    return
                self.current_tile = self.target.get_current_cell()
                new_x = self.current_tile.x + self.velocity[0]
                new_y = self.current_tile.y + self.velocity[1]
                # print('new not none')
                new_target = self.layer.get_tile(new_x, new_y)
                if new_target and new_target.tile.is_passable(
                ) and not new_target.occupied:
                    # print('starting to move!')
                    self.foreshadowed = new_target
                if self.foreshadowed in self.travelled:
                    self.start_moving()
            else:
                if self.target.anim_delay > 0:
                    self.target.reload()  # reset animation
                self.target.anim_delay = -1
        else:
            self.move(dt)

    def move(self, dt):
        done = move(dt, self.target, self.foreshadowed.px,
                    self.foreshadowed.py)
        if done:
            self.done_moving()

    def done_moving(self, *args):
        self.target.set_position(self.foreshadowed.px, self.foreshadowed.py)
        self.moving = False

    def start_moving(self, *args):
        self.moving = True

    def end(self):
        current = self.layer.get_at(*self.target.center)
        self.target.spend_moves(
            self.index[self.layer.get_at(*self.target.center)])
        self.target.game.layer_widgets['below'].canvas.remove(
            self.instructions)
        self.target.anim_delay = -1
        self.target.reload()  # reset animation
        self.target.set_position(current.px, current.py)
        self.target.state = BattleMenuState(self.target)