def _new_block_from_factory(self, sprite_list, x, y, copy_block=None): self.svg = SVG() self.svg.set_scale(self.scale) self.svg.set_innie([False]) self.svg.set_outie(False) self.svg.set_tab(True) self.svg.set_slot(True) if copy_block is not None: self._left = copy_block._left self._top = copy_block._top self._right = copy_block._right self._bottom = copy_block._bottom self.dx = copy_block.dx self.ex = copy_block.ex self.ey = copy_block.ey self.width = copy_block.width self.height = copy_block.height self.shapes[0] = copy_block.shapes[0] if sprite_list is not None: self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0]) self.spr._margins = copy_block.spr._margins[:] if len(copy_block.shapes) > 1: self.shapes[1] = copy_block.shapes[1] self.docks = copy_block.docks[:] else: if self.expandable() and self.type == 'block': self.svg.set_show(True) self._make_block(self.svg) if sprite_list is not None: self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0]) self._set_margins() self._set_label_attributes() if (self.name == 'number' or self.name == 'string') and \ len(self.values) > 0: for i, v in enumerate(self.values): if v is not None: if self.name == 'number': self._set_labels( i, str(v).replace('.', self.block_list.decimal_point)) else: self._set_labels(i, str(v)) elif self.type == 'block' and self.name in CONSTANTS: self._set_labels(0, block_names[self.name][0] + ' = ' + \ str(CONSTANTS[self.name])) elif self.name in block_names: for i, n in enumerate(block_names[self.name]): self._set_labels(i, n) if copy_block is None and self.spr is not None: if self.spr.label_width() > self.spr.label_safe_width(): self.resize()
def make_sprites(self): sprites = pg.sprite.Group() layer = self.tmx_renderer.get_layer('sprites') for obj in layer: if obj.name == "wanderer": sprite = s.Wanderer('player_f', obj.x, obj.y, obj.properties['direction']) sprites.add(sprite) if obj.name == 'mover': sprite = s.Mover('uncle', obj.x, obj.y) sprites.add(sprite) if obj.name == 'chicken': if self.inventory['chickens']['catch']: if obj.id not in self.inventory['catched_chickens']: sprite = s.Chicken(obj.x, obj.y, obj.properties['direction'], obj.id) sprites.add(sprite) else: sprite = s.Chicken(obj.x, obj.y, obj.properties['direction']) sprites.add(sprite) if obj.name == 'chicken_lost': if self.inventory['chickens']['rescue']: if obj.id not in self.inventory['found_items']: sprite = s.Chicken(obj.x, obj.y, obj.properties['direction'], obj.id, obj.properties['color']) sprites.add(sprite) if obj.name == 'uncle': sprite = s.Sprite(obj.name, obj.x, obj.y) sprites.add(sprite) if 'chicken_rescue' not in self.game_data['active_quests']: if obj.name == 'uncle_out': sprite = s.Sprite('uncle', obj.x, obj.y) sprites.add(sprite) if obj.name == 'chicken_rgb': sprite = s.Chicken(obj.x, obj.y, obj.properties['direction'], obj.id, obj.properties['color']) sprites.add(sprite) else: if obj.name == 'uncle_in': sprite = s.Sprite('uncle', obj.x, obj.y) sprites.add(sprite) if obj.name == 'boat_player': sprite = s.Boat(obj.name, obj.x, obj.y, 'right') sprites.add(sprite) return sprites
def __init__(self,filename=None): self.initialize_metadata() self.initialize_waves() self.initialize_sfx() self.initialize_code() self.initialize_gfx() if filename: self.initialize_waves(True) self.initialize_sfx(True) with open(filename,"r") as f: lines = [l.rstrip() for l in f] stage=0 tag = "" for line in lines: if not line: continue # skip empty lines if stage==0: if line.startswith("-- "): parts=line[3:].split(": ",2) self.metadata[parts[0]]=parts[1] else: stage=1 if stage==1: if not line.startswith("-- <"): self.code[0]+="{}\n".format(line) else: stage=2 if stage==2: match = re.search(r"-- <(.+)>",line) if not match: raise Exception("Invalid line for stage 2") if match.group(1) not in ["TILES","WAVES","SFX","PALETTE"]+["CODE"+str(i) for i in range(8)]: raise Exception("Invalid tag!") tag = match.group(1) if tag.startswith("CODE"): self.code[int(tag[-1])]="" stage = 3 elif stage==3: if line=="-- </{}>".format(tag): stage = 2 else: if tag.startswith("CODE"): self.code[int(tag[-1])]+="{}\n".format(line) continue if tag=="TILES": # Sprite class is implemented! self.sprites.append(sprites.Sprite(line[3:])) elif tag=="PALETTE": self.palette = sprites.Palette(line[3:]) elif tag=="WAVES": self.waves.append(line[3:]) elif tag=="SFX": self.sfx.append(line[3:])
def load_sprites(self, level): # load sprites self.overlays = pygame.sprite.RenderUpdates() # create sprite groups block_list = pygame.sprite.Group() all_sprites_list = pygame.sprite.Group() # get sprites for pos, tile in self.level.sprites.items(): tile = int(tile[0]), int(tile[1]) thing = sprites.Sprite(pos, tile) block_list.add(thing) all_sprites_list.add(thing) # get player sprite tile = [self.level.player['tile'][0], self.level.player['tile'][1]] tile = int(tile[0]), int(tile[1]) pos = (self.level.player['pos'][0], self.level.player['pos'][1]) pos = int(pos[0]), int(pos[1]) player = pc.Player(pos, tile) all_sprites_list.add(player) # return sprite groups and player return block_list, all_sprites_list, player
MAP_CACHE = tileset.TileCache(MAP_TILE_WIDTH, MAP_TILE_HEIGHT) # load level level = Level() level.load_file(arguments['--input']) # load sprites overlays = pygame.sprite.RenderUpdates() things = pygame.sprite.RenderUpdates() block_list = pygame.sprite.Group() all_sprites_list = pygame.sprite.Group() for pos, tile in level.sprites.items(): tile = int(tile[0]), int(tile[1]) thing = sprites.Sprite(pos, tile) block_list.add(thing) all_sprites_list.add(thing) # set up player tile = [level.player['tile'][0], level.player['tile'][1]] tile = int(tile[0]), int(tile[1]) pos = (level.player['pos'][0], level.player['pos'][1]) pos = int(pos[0]), int(pos[1]) player = player.Player(pos, tile) all_sprites_list.add(player) # set up game clock clock = pygame.time.Clock() # render level
def start_element(self, name, attributes): if name == 'map': self.columns = int(attributes.get('width', None)) self.lines = int(attributes.get('height', None)) self.tile_width = int(attributes.get('tilewidth', None)) self.tile_height = int(attributes.get('tileheight', None)) elif name == 'image': # criar um tileset # É possível usar mais de um conjunto de peças, mas eles devem ter tamanhos e peças idênticos. # chaves de cores transparentes. source = attributes.get('source', None) transp = attributes.get('trans', None) if self.tileset is None: self.tileset = Tileset(self.tile_width, self.tile_height) self.tileset.add_set(source, ("0x" + str(transp))) elif name == 'property': # armazena propriedades adicionais. # adicionar às propriedades do item ou da camada, dependendo da tag pai em que estamos if self.in_item: self.items[-1].properties[attributes.get( 'name', None)] = attributes.get('value', None) else: self.properties[self.layers][attributes.get( 'name', None)] = attributes.get('value', None) elif name == 'layer': # começando a contagem self.line = 0 self.column = 0 self.layers += 1 self.properties.append({}) self.in_item = False elif name == 'tile': # obter informações de cada bloco e colocar no mapa # ID do arquivo para fazer referência ao conjunto de blocos gid = int(attributes.get('gid', None)) - 1 if gid < 0: gid = 0 self.cur_row.append(self.tileset.tiles[gid]) self.column += 1 if self.column >= self.columns: self.line += 1 self.column = 0 self.cur_layer.append(self.cur_row) self.cur_row = [] if self.line >= self.lines: self.image.append(self.cur_layer) self.cur_layer = [] elif name == 'object': # áreas de objetos podem ser pintadas em azulejo ou especificadas manualmente, como no mapa de amostra self.in_item = True x = int(attributes.get('x', None)) / self.tile_width y = int(attributes.get('y', None)) / self.tile_height if attributes.get( 'type', None ) == 'block': # impede que itens entrem em quadrados contidos width = int(attributes.get('width', None)) / self.tile_width height = int(attributes.get('height', None)) / self.tile_height self.blocking.append(Rect(x, y, width, height)) if attributes.get('type', None) == 'boulder': # empurrável self.items.append( item.Item( sprites.Sprite('sprites/rock.png', 32, 64, (0, 198, 198)), Rect(x, y, 1, 1), 'boulder')) if attributes.get('type', None) == 'girl': self.items.append( item.Item( sprites.Sprite('sprites/girl.png', 32, 64, (0, 198, 198)), Rect(x, y, 1, 1), 'person')) if attributes.get('type', None) == 'boy': self.items.append( item.Item( sprites.Sprite('sprites/boy.png', 32, 64, (0, 198, 198)), Rect(x, y, 1, 1), 'person'))
def __init__(self, sw, name, x, y, w, h): # create sprite from svg file self.spr = sprites.Sprite( sw.sprites, x, y, self.load_image(sw.path, name, w * sw.scale, h * sw.scale))
def main(self): global player # Estes assumem valores de 0, -1 ou 1, dependendo se os blocos estão deslizando nesse momento # direção. Isso é diferente de se mover, pois leva em consideração a janela que se fecha pelas bordas. x_tile_sliding, y_tile_sliding = 0, 0 # Tudo funciona mesmo com um número par de linhas/colunas visíveis. O jogador simplesmente não está # centralizado na superfície da tela. mid_x, mid_y = (config.tiles_visible_x - 1) / 2, (config.tiles_visible_y - 1) / 2 # Manuseio especial para objetos ativos no mundo do jogo. Todas as pessoas devem ter uma propriedade de caminho. for i in self.tmxhandler.items: # Construa o caminho da lista de propriedades analisadas para o mapa if i.type == 'person': i.path = [int(n) for n in i.properties['path'].split(',')] # Estes parâmetros de conjuntos de peças regulares são especificados nos arquivos mundiais XML, mas não há # arquivos XML para sprites # player para que eles tenham que ser codificados em algum lugar. player = item.Item( sprites.Sprite('sprites/boy.png', 32, 64, (0, 198, 198)), Rect(3, 3, 1, 1), 'player') # Adicione o player à lista de itens para que ele colide corretamente e seja pintado como parte do primeiro plano. self.tmxhandler.items.append(player) # Calcular quais blocos devem ficar visíveis ao redor do player. A visão fixa garante que a câmera não # go fora das fronteiras do mundo. viewport = Rect(player.position.left - mid_x, player.position.top - mid_y, config.tiles_visible_x, config.tiles_visible_y) clamped = viewport.clamp(self.map_edges) # A posição do jogador determina quais peças serão sorteadas. Além disso, se o jogador ainda estiver # moving, a linha / coluna à direita uma unidade atrás dele também deve ser desenhada. for row in range( 0 - (y_tile_sliding and player.facing[1] == 1), config.tiles_visible_y + (y_tile_sliding and player.facing[1] == -1)): for column in range( 0 - (x_tile_sliding and player.facing[0] == 1), config.tiles_visible_x + (x_tile_sliding and player.facing[0] == -1)): # Blit a área apropriada de uma determinada camada da representação interna do # game world no buffer da superfície da tela. self.screen.blit( self.tmxhandler.image[layer][row + clamped.top][column + clamped.left], (column * config.tiles_size + (x_tile_sliding * player.sliding * player.facing[0]), row * config.tiles_size + (y_tile_sliding * player.sliding * player.facing[1]) - 16)) pg.init() pg.display.set_caption("Pykemon - Demo") # Usamos a biblioteca sax para analisar mapas, caminhos e metadados de blocos dos arquivos XML do mundo do jogo. parser = sax.make_parser() parser.setContentHandler(self.tmxhandler) # moving representa a tecla de direção pressionada agora # Se você quiser saber se o jogador está se movendo, player.facing e player.sliding devem ser # usado em vez disso, porque a tecla de direção pode ser liberada ou alterada durante o movimento. moving = 0, 0 player.facing = 0, 1 # Mapas constantes do teclado para vetores de movimento moves = { K_UP: (0, -1), K_DOWN: (0, 1), K_LEFT: (-1, 0), K_RIGHT: (1, 0) } # O limitador de quadros está desativado no momento? turbo = 0 # Há um único quadro para ficar parado. Ao deslizar, o item alterna entre a posição imóvel # frame e a estrutura de marcha atual (que é alternada a cada passo para que as pernas se alternem) animation_cutoffs = (config.tiles_size / 2) clock = pg.time.Clock() # Estamos gravando atualmente? recording = False frame = 0 capture_run = 0 # Loop principal do jogo while True: self.screen.fill(255, 0, 255) for event in pg.event.get(): if event.type == QUIT: terminate() if event.type == KEYDOWN: if event.key in moves.keys(): moving = moves[event.key] if event.key is K_SPACE: # Segure espaço para desativar o limitador de quadros turbo = True if event.key is K_r: # Segure r para gravar a saída da tela em muitos PNGs recording = True elif event.type == KEYUP: # Não queremos parar se o jogador pressionar e soltar uma tecla de movimento enquanto estiver # movendo em uma direção diferente, para que a direção do movimento seja verificada na tecla # pressionada if event.key in moves.keys() and moves[ event.key] == moving: moving = 0, 0 if event.key is K_SPACE: # Restaura o limitador de quadros quando o espaço é liberado turbo = False if event.key is K_r: recording = False capture_run += 1 # Observe que o movimento do jogador está sendo tratado aqui e não abaixo com o restante dos itens. if player.sliding == 0 and moving != (0, 0): # Isso retornará falso se o jogador encontrar um obstáculo. if player.move(moving): # Mover a janela de visualização com o player viewport.move_ip(moving) # Mova a janela de visualização de volta ao mundo do jogo, se ela acabou de sair. clamped = viewport.clamp(self.map_edges) # Estes cálculos determinam se o jogador deve se mover livremente perto das fronteiras ou deve # ser fixado em o centro de um plano de fundo de rolagem quando distante das bordas. Observe que, # por exemplo, o player pode estar perto do topo do mundo e capaz de se mover livremente na # vertical, mas ainda assim estar fixo no direção horizontal. x_tile_sliding, y_tile_sliding = 0, 0 if viewport.left == clamped.left and viewport.move( -1 * moving[0], 0).left == viewport.move( -1 * moving[0], 0).clamp(self.map_edges).left: x_tile_sliding = 1 if viewport.top == clamped.top and viewport.move( 0, -1 * moving[1]).top == viewport.move( 0, -1 * moving[1]).clamp(self.map_edges).top: y_tile_sliding = 1 # Manipula o movimento de todas as pessoas em todos os quadros, alterando a direção conforme necessário # para corresponder ao caminho no arquivo XML. for i in self.tmxhandler.items: if i.type == 'person': # Observe que os pedregulhos nunca são chamados para go(), apenas bump_notify() i.go() # Primeiro, precisamos escolher todas as camadas não marcadas como oclusivas e desenhá-las em ordem. # Isso cria o background em que itens se movem. occluding = [] for layer in range(0, self.tmxhandler.layers): if 'occlude' in self.tmxhandler.properties[ layer + 1]: # + 1 porque 0 é o suporte do mapa occluding.append(layer) else: self.main( ) # Muitas e muitas variáveis gratuitas passam por aqui # Agora, desenhe cada item (incluindo o player), dependendo de estar visível na janela de exibição da # câmera. for i in self.tmxhandler.items: # O deslizamento de um item é definido como tiles_size toda vez que ele se move e diminui em 4 pixels # por quadro até it atinge 0 e, nesse ponto, alcançou sua nova posição. Observe que o valor de # deslizamento do jogador não é changed até que a camada de oclusão tenha sido desenhada. Isso é # necessário porque se a viewport for alterada b Antes de os itens serem desenhados, # eles retrocederão 4 pixels no final do movimento deslizante. if i is not player and i.sliding > 0: i.sliding -= 4 # Verifique se o item está visível dentro de três blocos ao redor da janela de visualização e, # se estiver, desenhe-o. A visualização deve ser expandida por três peças devido ao pior caso: # enquanto um item está deslizando para a direita do jogador, o jogador Move-se para a esquerda. No # futuro, posso adicionar uma verificação que permita inflar apenas 2 peças e um inflável direcional # dependendo para que lado o jogador está se movendo. if clamped.inflate(3, 3).contains(i.position): self.screen.blit( i.sprite.facing[i.facing] [0 if i.sliding < animation_cutoffs else 1 + i.toggle], ((i.position.left - clamped.left) * config.tiles_size - (i.sliding * i.facing[0]), (i.position.top - clamped.top - 1) * config.tiles_size - (i.sliding * i.facing[1]) + (y_tile_sliding * player.sliding * player.facing[1]) - 16)) # Finalmente, desenhe cada camada de oclusão que foi ignorada anteriormente. Essa camada será desenhada # em cima dos itens. for layer in occluding: self.main() # E agora que as operações de desenho estão concluídas, atualize o valor deslizante do jogador. if player.sliding > 0: player.sliding -= 4 # E agora que as operações de desenho estão concluídas, atualize o valor deslizante do jogador. pg.display.update() if not turbo: clock.tick(30) if recording: # Exporte a superfície da tela para um arquivo png para fazer vídeos. Isso pode consumir muito espaço # em disco se você gravar por mais than alguns segundos. A compactação PNG mata a taxa de quadros, # mas os tamanhos dos arquivos são muito mais gerenciáveis. pg.image.save( self.screen, 'capture/' + 'run' + str(capture_run).zfill(2) + '_f' + str(frame).zfill(5) + '.png') frame += 1