结合单独的水平地图对于纹理瓷砖,墙和&退出Pygame

时间:2015-07-19 20:20:02

标签: python pygame

我正在尝试将两个单独的列表转换为一个平铺图。

  1. 用于放置颜色块或纹理
  2. 用于保持墙壁**和出口点的位置。
  3. 我正在使用两种不同的方法来创建使用字符来表示图块的图块。我可以让两种方法分开工作,但是想要将它们组合使用?

    我希望知道如何将两个结果与两个列表结合起来

    #map of the colors or textured tiles
    level1tile = ["------",
                  "-$$---",
                  "-$^^$-",
                  "------"
        ]
    #level1tile is a simple mapping: char -> colour
    colors = {'X': pygame.color.THECOLORS['blue'],
              '-': pygame.color.THECOLORS['grey'],
              '^': pygame.color.THECOLORS['brown'] ]        
              }
    
    #map of the walls and level exits
    level1wall = ["WWWWWW",
                  "W    E",
                  "W WW W",
                  "WWWWWW"
        ]
    #level1wall is collision detection W = wall, E = exit, P = Player
    
    1. 用于放置颜色块或纹理
    2. 用于保持墙壁**和出口点的位置。
    3. 我将在线下添加隐形物品,所以我想保留两个单独的地图,这样一些标题可以具有与墙壁相同的纹理。

      可能用途的一些示例: 1.你可以通过一些水砖而不是其他水砖 2.流沙,隐形物品或陷阱

      所以在第一张地图中代表水蓝色瓷砖

       colors = {'X': pygame.color.THECOLORS['blue']}
      

      在第二个中,我代表水,W为墙碰撞检测。

      在本例中,我通过使用W作为墙壁进行碰撞检测来阻挡区域,蓝色或水色以及灰色或岩石砖是玩家无法行走的区域。

      Background titles

      在本例中,我通过使用W作为墙壁进行碰撞检测来阻挡区域,蓝色或水和灰色或岩石瓦片是玩家无法行走的区域。但是我希望保留两张地图,以防我想添加隐形区域或者你可以走一些水等等。

      Method 1

      level = ["WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
               "W           WWWWWWWWW WW          EW",
               "W            WWWWWWW               W",
               "W           WW             WWW     W",
               "W          WW             WWWWW    W",
               "W                        WWWWWWW   W",
               "W                        WWWWWW    W",
               "W                        WWWWWWW   W",
               "W                         WWWWWW   W",
               "W                            WW    W",
               "W                                  W",
               "W                W                 W",
               "W               WWW                W",
               "W              WWWWW               W",
               "W              WWWWW               W",
               "W             WWWWW                W",
               "W              WWWWWW              W",
               "W                 WWW              W",
               "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"]
      
      
      # W = wall, E = exit, P = Player
      x = y = 0
      for row in level:
          for col in row:
              if col == "W":
                  Wall((x, y))
              if col == "E":
                  end_rect = pygame.Rect(x, y, 32, 32)
              x += 32
          y += 32
          x = 0
      

      我正在使用一种技术来创建颜色或纹理平铺地图,这是我在这里阅读成员Sloth帖子时学到的。

      levelB = ["------------------------------------",
               "-  $$$$$$$$$--------- --   $ $ $ $E-",
               "- $  $$$$$$$$-------^^^^         $$-",
               "-$ $$$$$$$$ --     ^^^^    XXX    $-",
               "-  $$$$$$$ --  $  ^^^^    XXXXX    -",
               "-    $$$$$$$      ^^^^   XXXXXXX   -",
               "- $$$$$$$$$$      ^^^^   XXXXXX    -",
               "-    $$$$$$$$     ^^^^   XXXXXXX   -",
               "-$$$$$$$$$$$$$$  ^^^^     XXXXXX   -",
               "-     $$$$$$$   ^^^^         XX    -",
               "-  $ $$$       ^^^^        $ $ $ $ -",
               "- $$$$$$     ^^^^-         $$$$$$$$-",
               "-  $$$$$$   ^^^^---      $$$$$ $ $ -",
               "- $$$$$    ^^^^-----        $$$$$$$-",
               "- $$$$$$$  ^^^^-----       $ $ $ $ -",
               "- $$$$$$$ ^^^^-----       $$$$$$ $$-",
               "-  $$$$$$ ^^^^ ------      $ $ $ $ -",
               "- $$$$$$$$  ^^^^  ---            $$-",
               "------------------------------------"]
      #a simple mapping: char -> colour
      colors = {'X': pygame.color.THECOLORS['blue'],
                '-': pygame.color.THECOLORS['grey'],
                '$': pygame.color.THECOLORS['green'],
                '^': pygame.color.THECOLORS['brown'], 
                'E': pygame.color.THECOLORS['black']        
                }
      
      blocksize = 32
      

      我将用纹理贴图交换颜色

      enter image description here

      ####################################### < / p>

      enter image description here

      下面是我尝试按照提供的答案,我仍然只能执行一半检查。

      完整资源

      import os
      import random
      import pygame
      
      #map of the colors or textured tiles
      level1tile = ["------------------------------------",
               "-  $$$$$$$$$--------- --   $ $ $ $E-",
               "- $  $$$$$$$$-------^^^^         $$-",
               "-$ $$$$$$$$ --     ^^^^    XXX    $-",
               "-  $$$$$$$ --  $  ^^^^    XXXXX    -",
               "-    $$$$$$$      ^^^^   XXXXXXX   -",
               "- $$$$$$$$$$      ^^^^   XXXXXX    -",
               "-    $$$$$$$$     ^^^^   XXXXXXX   -",
               "-$$$$$$$$$$$$$$  ^^^^     XXXXXX   -",
               "-     $$$$$$$   ^^^^         XX    -",
               "-  $ $$$       ^^^^        $ $ $ $ -",
               "- $$$$$$     ^^^^-         $$$$$$$$-",
               "-  $$$$$$   ^^^^---      $$$$$ $ $ -",
               "- $$$$$    ^^^^-----        $$$$$$$-",
               "- $$$$$$$  ^^^^-----       $ $ $ $ -",
               "- $$$$$$$ ^^^^-----       $$$$$$ $$-",
               "-  $$$$$$ ^^^^ ------      $ $ $ $ -",
               "- $$$$$$$$  ^^^^  ---            $$-",
               "------------------------------------"]
      #a simple mapping: char -> color
      colors = {'X': pygame.color.THECOLORS['blue'],
                '-': pygame.color.THECOLORS['grey'],
                '$': pygame.color.THECOLORS['green'],
                '^': pygame.color.THECOLORS['brown'], 
                'E': pygame.color.THECOLORS['black']        
                }
      
      blocksize = 32
      #map of the walls and level exits
      level1wall = ["WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
               "W           WWWWWWWWW WW          EW",
               "W            WWWWWWW               W",
               "W           WW             WWW     W",
               "W          WW             WWWWW    W",
               "W                        WWWWWWW   W",
               "W                        WWWWWW    W",
               "W                        WWWWWWW   W",
               "W                         WWWWWW   W",
               "W                            WW    W",
               "W                                  W",
               "W                W                 W",
               "W               WWW                W",
               "W              WWWWW               W",
               "W              WWWWW               W",
               "W             WWWWW                W",
               "W              WWWWWW              W",
               "W                 WWW              W",
               "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"]
      
      
      # Class for the Player object
      class Player(object):
      
          def __init__(self):
              self.rect = pygame.Rect(32, 32, 16, 16)
      
          def move(self, dx, dy):
      
              # Move each axis separately. Note that this checks for collisions both times.
              if dx != 0:
                  self.move_single_axis(dx, 0)
              if dy != 0:
                  self.move_single_axis(0, dy)
      
          def move_single_axis(self, dx, dy):
      
              # Move the rect
              self.rect.x += dx
              self.rect.y += dy
      
              # If you collide with a wall, move out based on velocity
              for wall in walls:
                  if self.rect.colliderect(wall.rect):
                      if dx > 0: # collide right
                          self.rect.right = wall.rect.left
                      if dx < 0: # collide left
                          self.rect.left = wall.rect.right
                      if dy > 0: # collide top
                          self.rect.bottom = wall.rect.top
                      if dy < 0: # collide bottom
                          self.rect.top = wall.rect.bottom
      
      # Nice class to hold a wall rect
      class Wall(object):
      
          def __init__(self, pos):
              walls.append(self)
              self.rect = pygame.Rect(pos[0], pos[1], 32, 32)
      #level1wall is collision detection W = wall, E = exit, P = Player
      
      #Block
      class Block(pygame.sprite.Sprite):
          # Constructor. Pass in the color of the block, and its x and y position
          def __init__(self, color, width, height, x, y):
             # Call the parent class (Sprite) constructor
             pygame.sprite.Sprite.__init__(self)
      
             # Create an image of the block, and fill it with a color.
             # This could also be an image loaded from the disk.
             self.image = pygame.Surface([width, height])
             self.image.fill(color)
      
             # Fetch the rectangle object that has the dimensions of the image
             # Update the position of this object by setting the values of rect.x and rect.y
             self.rect = self.image.get_rect(top=y, left=x)
      
      pygame.init()
      
      
      # Set up the display
      pygame.display.set_caption("Tiles and Walls!")
      screen = pygame.display.set_mode((len(level[0])* blocksize, len(level*blocksize)))
      #screen = pygame.display.set_mode((1150, 600))
      
      clock = pygame.time.Clock()
      walls = [] # List to hold the walls
      player = Player() # Create the player
      
      
      combined_list = []  # initialize a blank list
      for i in range(len(level1tile)):  # build your new list
        combined_list.append(zip(level1tile[i], level1wall[i]))
      
          # Parse the level string above. W = wall, E = exit
      x = y = 0
      for row in level1wall:
          for col in row:
              if col == "W":
                  Wall((x, y))
              if col == "E":
                  end_rect = pygame.Rect(x, y, 32, 32)
              x += 32
          y += 32
          x = 0
      
      running = True
      while running:
      
          clock.tick(60)
      
          for e in pygame.event.get():
              if e.type == pygame.QUIT:
                  running = False
              if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE:
                  running = False
      
          # Move the player if an arrow key is pressed
          key = pygame.key.get_pressed()
          if key[pygame.K_LEFT]:
              player.move(-2, 0)
          if key[pygame.K_RIGHT]:
              player.move(2, 0)
          if key[pygame.K_UP]:
              player.move(0, -2)
          if key[pygame.K_DOWN]:
              player.move(0, 2)
      
          # Just added this to make it slightly fun ;)
          if player.rect.colliderect(end_rect):
              raise SystemExit("Next Level!")
      
          # Draw the scene
          screen.fill((0, 0, 0))
          for wall in walls:
              pygame.draw.rect(screen, (255, 255, 255), wall.rect)
          pygame.draw.rect(screen, (255, 0, 0), end_rect)
          pygame.draw.rect(screen, (255, 200, 0), player.rect)
          pygame.display.flip()
      

2 个答案:

答案 0 :(得分:1)

没有Itertools

我可能会建议在Python中使用zip()函数。基本上它需要两个(或更多)列表作为参数并返回一个列表,其中每个元素是该位置的原始两个列表的值的元组。例如,您可以创建一个新列表,在地图中的每个位置都有一个元组(tile, wall)

combined_list = []  # initialize a blank list
for i in range(len(level1tile)):  # build your new list
  combined_list.append(zip(level1tile[i], level1wall[i]))

,使用您问题中的第一个示例,返回:

combined_list = 
[[('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W')],
 [('-', 'W'), ('$', ' '), ('$', ' '), ('-', ' '), ('-', ' '), ('-', 'E')],
 [('-', 'W'), ('$', ' '), ('^', 'W'), ('^', 'W'), ('$', ' '), ('-', 'W')],
 [('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W'), ('-', 'W')]]

然后,您可以使用以下内容获取地图(x, y)中任何指定位置的图块和墙状态:

(tile, wall) = combined_list[x][y]

然后,您可以分别访问tilewall

>> (tile, wall) = combined_list[1][0]
>> tile
    '-'
>> wall
    'W'

那是否符合您的要求?

将这两个字符串列表与列表推导相结合可能有一种非常聪明的方法,但我无法让它为我工作。

编辑:使用Itertools

使用itertools 是一种聪明的方法!好吧,有点。我无法完全保留您的2D布局,而是设法将所有(tile, wall)元组放入单个1 x n*m长度列表(而不是n x m 2D列表) :

import itertools as it
combined = list(it.izip(it.chain.from_iterable(level1tile), it.chain.from_iterable(level2tile)))

现在,您可以使用以下符号访问位置(tile, wall)的{​​{1}}值

(x, y)

使用(tile, wall) = combined[x + y*n] # where "n" is how many columns you have in your map (或不使用)可能仍然更优雅的方式,但希望这会有所帮助。

答案 1 :(得分:1)

由于您使用字符来表示图块和墙,因此您可以将它们连接成一个字符串以组合这两个列表。组合列表将需要更少的内存,以提供比将它们放入列表或字符元组所需的更快的访问方式。

之后,您可以分别直接使用combined[row][col][0]combined[row][col][1]访问特定位置的拼贴和墙角。

使用itertools.izip()而不是zip()可以减少内存消耗,因为它无需创建临时中间列表。使用xrange()代替range()也是如此。

try:
    from itertools import izip
except ImportError:  # Python3
    izip = zip
    xrange = range

combined = [tuple(tile+wall for tile, wall in zip(level1tile[i], level1wall[i]))
                for i in xrange(len(level1tile))]

from pprint import pprint
print('level1tile and level1wall combined:')
pprint(combined)
print('')

print('combined[1][5] -> {!r}'.format(combined[1][5]))
tile, wall = combined[1][5]
print('after "tile, wall = combined[1][5]:"')
print('  tile, wall -> {!r},{!r}'.format(tile, wall))

输出:

level1tile and level1wall combined:
[('-W', '-W', '-W', '-W', '-W', '-W'),
 ('-W', '$ ', '$ ', '- ', '- ', '-E'),
 ('-W', '$ ', '^W', '^W', '$ ', '-W'),
 ('-W', '-W', '-W', '-W', '-W', '-W')]

combined[1][5] -> '-E'
after "tile, wall = combined[1][5]:"
  tile, wall -> '-','E'