2016-08-18 65 views
1

這裏是我的所有代碼:如何使對象在按鍵上通過一組對象移動?

import random as random 

import pygame as pygame 

pygame.init() # initialize 
clock = pygame.time.Clock() # framerate limit 
Screen = pygame.display.set_mode([1000, 1000]) # Create screen object and Window Size 
Done = False 
MapSize = 25 

TileWidth = 20 
TileHeight = 20 
TileMargin = 4 

BLACK = (0, 0, 0) 
WHITE = (255, 255, 255) 
GREEN = (0, 255, 0) 
RED = (255, 0, 0) 
BLUE = (0, 0, 255) 


class MapTile(object): 
    def __init__(self, Name, xlocation, ylocation): 
     self.Name = Name 
     self.xlocation = xlocation 
     self.ylocation = ylocation 


class Character(object): 
    def __init__(self, Name, HP, Allegiance, xlocation, ylocation): 
     self.Name = Name 
     self.HP = HP 
     self.Allegiance = Allegiance 
     self.xlocation = xlocation 
     self.ylocation = ylocation 

    def Move(self, Direction): 
     if Direction == "UP": 
      self.ylocation += 1 

     elif Direction == "LEFT": 
      self.xlocation -= 1 

     elif Direction == "RIGHT": 
      self.xlocation += 1 

     elif Direction == "DOWN": 
      self.ylocation -= 1 

     self.Location() 

    def Location(self): 
     print("Coordinates: " + str(self.xlocation) + ", " + str(self.ylocation)) 




class Map(object): 
    Grid = [] 
    global MapSize 

    for Row in range(MapSize): # Creating grid 
     Grid.append([]) 
     for Column in range(MapSize): 
      Grid[Row].append([]) 

    for Row in range(MapSize):  #Filling grid with grass 
     for Column in range(MapSize): 
      TempTile = MapTile("Grass", Row, Column) 
      Grid[Row][Column].append(TempTile) 

    for Row in range(MapSize):  #Rocks 
     for Column in range(MapSize): 
      TempTile = MapTile("Rock", Row, Column) 
      if Row == 1: 
       Grid[Row][Column].append(TempTile) 

    for i in range(10):  #Random trees 
     RandomRow = random.randint(0, MapSize - 1) 
     RandomColumn = random.randint(0, MapSize - 1) 
     TempTile = MapTile("Tree", Row, Column) 
     Grid[RandomRow][RandomColumn].append(TempTile) 



    def update(self): 
     for Row in range(MapSize): 
      for Column in range(MapSize): 
       for i in range(len(Map.Grid[Row][Column])): 
        if Map.Grid[Row][Column][i].xlocation != Column: 
         print("BOOP") 
         Map.Grid[Row][Map.Grid[Row][Column][i].xlocation].append(Map.Grid[Row][Column][i]) 
         Map.Grid.remove(Map.Grid[Row][Column][i]) 

        if Map.Grid[Row][Column][i].ylocation != Row: 
         print("BOOP") 
         Map.Grid[Row][Map.Grid[Row][Column][i].xlocation].append(Map.Grid[Row][Column][i]) 

        else: 
         break 

    RandomRow = random.randint(0, MapSize - 1) 
    RandomColumn = random.randint(0, MapSize - 1) 
    Hero = Character("boop", 10, "Friendly", RandomRow, RandomColumn) 
    Grid[RandomRow][RandomColumn].append(Hero) 


Map = Map() 

while not Done: 

    for event in pygame.event.get(): 
     if event.type == pygame.QUIT: 

      Done = True 

     elif event.type == pygame.MOUSEBUTTONDOWN: 
      Pos = pygame.mouse.get_pos() 
      Column = Pos[0] // (TileWidth + TileMargin) 
      Row = Pos[1] // (TileHeight + TileMargin) 
      print(str(Row) + ", " + str(Column)) 

      for i in range(len(Map.Grid[Row][Column])): 
       print(str(Map.Grid[Row][Column][i].Name)) 

     elif event.type == pygame.KEYDOWN: 
      if event.key == pygame.K_LEFT: 
       Map.Hero.Move("LEFT") 
      if event.key == pygame.K_RIGHT: 
       Map.Hero.Move("RIGHT") 
      if event.key == pygame.K_UP: 
       Map.Hero.Move("UP") 
      if event.key == pygame.K_DOWN: 
       Map.Hero.Move("DOWN") 

      Map.update() 


    Screen.fill(BLACK) 

    for Row in range(MapSize): # Drawing grid 
     for Column in range(MapSize): 
      Color = WHITE 
      if len(Map.Grid[Row][Column]) == 2: 
       Color = RED 
      for i in range(0, len(Map.Grid[Row][Column])): 
       if Map.Grid[Row][Column][i].Name == "boop": 
        Color = GREEN 
       if Map.Grid[Row][Column][i].Name == "MoveTile": 
        Color = BLUE 

      pygame.draw.rect(Screen, Color, [(TileMargin + TileWidth) * Column + TileMargin, 
              (TileMargin + TileHeight) * Row + TileMargin, 
              TileWidth, 
              TileHeight]) 

    clock.tick(60) 

    pygame.display.flip() 

pygame.quit() 

和相關的位:

elif event.type == pygame.KEYDOWN: 
      if event.key == pygame.K_LEFT: 
       Map.Hero.Move("LEFT") 
      if event.key == pygame.K_RIGHT: 
       Map.Hero.Move("RIGHT") 
      if event.key == pygame.K_UP: 
       Map.Hero.Move("UP") 
      if event.key == pygame.K_DOWN: 
       Map.Hero.Move("DOWN") 

      Map.update() 

移動功能:

def Move(self, Direction): 
      if Direction == "UP": 
       self.ylocation += 1 

      elif Direction == "LEFT": 
       self.xlocation -= 1 

      elif Direction == "RIGHT": 
       self.xlocation += 1 

      elif Direction == "DOWN": 
       self.ylocation -= 1 

而且更新功能,問題所在:

def update(self): 
      for Row in range(MapSize): 
       for Column in range(MapSize): 
        for i in range(len(Map.Grid[Row][Column])): 
         if Map.Grid[Row][Column][i].xlocation != Column: 
          print("BOOP") 
          Map.Grid[Row][Map.Grid[Row][Column][i].xlocation].append(Map.Grid[Row][Column][i]) 
          Map.Grid.remove(Map.Grid[Row][Column][i]) 

         if Map.Grid[Row][Column][i].ylocation != Row: 
          print("BOOP") 
          Map.Grid[Row][Map.Grid[Row][Column][i].xlocation].append(Map.Grid[Row][Column][i]) 

         else: 
          break 

更新函數的預期行爲是檢查網格中的每個對象並查看它是否已經移動(如果對象的內部座標與其在網格上的當前位置之間存在差異),並將其替換爲網格中的它的正確位置。它通過在新位置追加新版本的對象並刪除舊對象來實現此目的。

我得到的錯誤是:

Traceback (most recent call last): 
    File "/Users/kosay.jabre/Desktop/Monster.py", line 136, in <module> 
    Map.update() 
    File "/Users/kosay.jabre/Desktop/Monster.py", line 93, in update 
    Map.Grid.remove(Map.Grid[Row][Column][i]) 
ValueError: list.remove(x): x not in list 

我如何能最好的達到預期的行爲?

+0

你得到的錯誤是因爲'Map.Grid.remove()'只查找在列表中,只包含代表第二個維度其他列表的第一個維度的價值 - 所以它永遠不會找到引用相應的MapTile實例。你需要遍歷每個子列表,然後'try'去除目標(如果你這樣做,就退出循環)。 – martineau

+0

你能幫我一下這樣做的語法嗎?另外,我不想刪除MapTile,而是刪除Hero。我想通過將他追加到新位置並移除舊實例來移動英雄。 – Kos

回答

1

感謝您取消刪除您的問題,以便我可以發佈答案。對不起,我花了這麼長的時間才能回到你身邊 - 希望能夠幫到你也不晚。

下面是你的問題中的代碼大量修改(但工作)版本。其中一個讓我放慢速度的原因是你沒有遵循PEP 8 - Style Guide for Python Code的建議,這使得你的代碼版本難以閱讀和理解。普遍缺乏解釋發生了什麼的評論,特別是在某些部分,並沒有讓它變得更容易。

Map.update()方法是我實現的東西,有點像我在我的評論中描述的那樣,在你的問題中關於如何修復ValueError問題。

import pygame as pygame 
import random as random 
import sys 

GRASS_NAME = "Grass" 
HERO_NAME = "Hero" 
MOVETILE_NAME = "MoveTile" 
ROCK_NAME = "Rock" 
TREE_NAME = "Tree" 
MAP_SIZE = 25 
TILE_WIDTH = 20 
TILE_HEIGHT = 20 
TILE_MARGIN = 4 
TILE_SIZE = TILE_WIDTH+TILE_MARGIN 
BLACK = 0, 0, 0 
WHITE = 255, 255, 255 
GREEN = 0, 255, 0 
RED = 255, 0, 0 
BLUE = 0, 0, 255 
YELLOW = 255, 255, 0 
BROWN = 128, 128, 0 
UP, DOWN, LEFT, RIGHT = 0, 1, 2, 3 
MOVEMENTS = {UP: (-1, 0), DOWN: (1, 0), LEFT: (0, -1,), RIGHT: (0, 1)} 
MOVEMENT_KEYS = {pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN} 

def quit_game(): 
    pygame.quit() 
    sys.exit() 

class MapTile(object): 
    def __init__(self, name, xloc, yloc): 
     self.name = name 
     self.xloc = xloc 
     self.yloc = yloc 

class Character(object): 
    def __init__(self, name, hp, allegiance, xloc, yloc): 
     self.name = name 
     self.hp = hp 
     self.allegiance = allegiance 
     self.xloc = xloc 
     self.yloc = yloc 

    def move(self, direction): 
     dy, dx = MOVEMENTS[direction] 
     self.yloc += dy 
     self.xloc += dx 

     # Enforce boundaries 
     if self.xloc < 0: 
      self.xloc = 0 
     elif self.xloc > MAP_SIZE-1: 
      self.xloc = MAP_SIZE-1 

     if self.yloc < 0: 
      self.yloc = 0 
     elif self.yloc > MAP_SIZE-1: 
      self.yloc = MAP_SIZE-1 

     self.location() 

    def location(self): 
     print("{} coordinates: ({}, {})".format(self.name, self.xloc, self.yloc)) 

class Map(object): 
    # Initialize grid 
    grid = [[[] for column in range(MAP_SIZE)] for row in range(MAP_SIZE)] 

    for row in range(MAP_SIZE):  # Completely fill grid with grass 
     for column in range(MAP_SIZE): 
      grid[row][column].append(MapTile(GRASS_NAME, column, row)) 

    # Add row of rocks near top 
    row = 1 
    for column in range(MAP_SIZE): 
     grid[row][column].append(MapTile(ROCK_NAME, column, row)) 

    for _ in range(10): # Add some random trees 
     row, column = random.randint(0, MAP_SIZE-1), random.randint(0, MAP_SIZE-1) 
     grid[row][column].append(MapTile(TREE_NAME, column, row)) 

    # Put hero character in random location 
    row, column = random.randint(0, MAP_SIZE-1), random.randint(0, MAP_SIZE-1) 
    hero = Character(HERO_NAME, 10, "Friendly", column, row) 
    grid[row][column].append(hero) 

    del row, column # clean up class context 

    def update(self): 
     """Check every object in the grid and see if it has moved (if there is a 
     discrepancy between the object's internal coordinates and its current 
     position on the grid), and if so put it in its proper place by deleting 
     it from its old list and appending it to the one for the proper location. 
     """ 
     for row in range(MAP_SIZE): 
      for column in range(MAP_SIZE): 
       for i, object in enumerate(map.grid[row][column]): 
        if object.xloc != column or object.yloc != row: # wrong spot? 
         #print("BOOP") 
         map.grid[row][column].pop(i) 
         map.grid[object.yloc][object.xloc].append(object) 

pygame.init() 
clock = pygame.time.Clock() # to limit framerate 
screen = pygame.display.set_mode([1000, 1000]) 
map = Map() 

while True: 
    for event in pygame.event.get(): 
     if event.type == pygame.QUIT: 
      quit_game() 
     elif(event.type == pygame.MOUSEBUTTONDOWN 
      and pygame.mouse.get_pressed()[0]): # button1 pressed? 
      xpos, ypos = pygame.mouse.get_pos() 
      column, row = xpos // TILE_SIZE, ypos // TILE_SIZE 
      if 0 <= column < MAP_SIZE and 0 <= row < MAP_SIZE: # on map? 
       print(str(row) + ", " + str(column)) 
       for i in range(len(map.grid[row][column])): 
        print(str(map.grid[row][column][i].name)) 
     elif event.type == pygame.KEYDOWN: 
      if event.key in MOVEMENT_KEYS: 
       if event.key == pygame.K_LEFT: 
        map.hero.move(LEFT) 
       elif event.key == pygame.K_RIGHT: 
        map.hero.move(RIGHT) 
       elif event.key == pygame.K_UP: 
        map.hero.move(UP) 
       else: 
        map.hero.move(DOWN) 
       map.update() 
      elif event.key == pygame.K_ESCAPE: 
       quit_game() 

    screen.fill(BLACK) 

    # Draw grid 
    for row in range(MAP_SIZE): 
     for column in range(MAP_SIZE): 
      # Determine color based on objects in this spot 
      names = {object.name for object in map.grid[row][column]} 
      color = WHITE # default color (Grass) 
      if HERO_NAME in names: 
       color = YELLOW 
      elif MOVETILE_NAME in names: 
       color = BLUE 
      elif TREE_NAME in names: 
       color = GREEN 
      elif ROCK_NAME in names: 
       color = RED 

      pygame.draw.rect(screen, color, 
          [TILE_SIZE*column + TILE_MARGIN, 
           TILE_SIZE*row + TILE_MARGIN, 
           TILE_WIDTH, 
           TILE_HEIGHT]) 

    clock.tick(60) 
    pygame.display.flip() 

pygame.quit()