假设我有MapTile类的两个对象:
class MapTile(object): #The main class for stationary things that inhabit the grid ... grass, trees, rocks and stuff.
def __init__(self, name, internal_column, internal_row, visible):
self.name = name
self.internal_column = internal_column
self.internal_row = internal_row
self.visible = visible
它们位于二维数组中,它们各自的internal_column和internal_row属性表示它们在数组中的坐标。
我想写一个函数,返回两个这样的对象之间的距离。以下是我目前所拥有的:
def return_distance(self, pointA, pointB):
distance = math.sqrt((pointA.internal_column - pointB.internal_column)**2 + (pointA.internal_row - pointB.internal_row)**2)
return distance
其中,点A和点B将是两个对象。
当我尝试它时,我得到了这个错误:
Traceback (most recent call last):
File "/Users/kosay.jabre/Desktop/Monster.py", line 380, in <module>
Map.update()
File "/Users/kosay.jabre/Desktop/Monster.py", line 297, in update
if Map.return_distance(Map.Grid[column][row], character) <= character.visionrange:
File "/Users/kosay.jabre/Desktop/Monster.py", line 245, in return_distance
distance = math.sqrt((pointA.internal_column - pointB.internal_column)**2 + (pointA.internal_row - pointB.internal_row)**2)
AttributeError: 'list' object has no attribute 'internal_column'
我这样调用距离函数:
for character in Map.everyone:
for column in range(MAPSIZE):
for row in range(MAPSIZE):
if Map.return_distance(Map.Grid[column][row], character) <= character.visionrange:
Map.Grid[column][row].visible = True
我该怎么办?如何在"Map.Grid[column][row]"中访问对象的属性,而不是将"Map.Grad[column][row]"本身作为列表访问?以下是创建Map.Grid的方法:
MAPSIZE = 25
class Map(object): #The main class; where the action happens
global MAPSIZE
Grid = []
friendlies = []
enemies = []
everyone = [friendlies + enemies]
visible = []
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", column, row, False)
Grid[column][row].append(TempTile)
我直接把东西添加到地图上。每个人都是这样的:
for column in range(MAPSIZE):
for row in range(MAPSIZE):
for i in range(len(Map.Grid[column][row])):
if Map.Grid[column][row][i].__class__.__name__ == "Character":
Map.everyone.append(Map.Grid[column][row][i])
这是我运行时的完整代码:
import random
import math
import pygame
pygame.init()
Clock = pygame.time.Clock()
Screen = pygame.display.set_mode([650, 650])
DONE = False
MAPSIZE = 25 #how many tiles
TURN = 0
TILEWIDTH = 20 #pixel size of tile
TILEHEIGHT = 20
TILEMARGIN = 4
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
BROWN = (123, 123, 0)
MOVECOLOR = (150, 250, 150)
KeyLookup = {
pygame.K_LEFT: "W",
pygame.K_RIGHT: "E",
pygame.K_DOWN: "S",
pygame.K_UP: "N"
}
class MapTile(object): #The main class for stationary things that inhabit the grid ... grass, trees, rocks and stuff.
def __init__(self, name, internal_column, internal_row, visible):
self.name = name
self.internal_column = internal_column
self.internal_row = internal_row
self.visible = visible
class Character(object): #can move around and do cool stuff
def __init__(self, name, HP, internal_column, internal_row, damage, allegiance):
self.name = name
self.HP = HP
self.internal_column = internal_column
self.internal_row = internal_row
self.damage = damage
self.allegiance = allegiance
visionrange = 10
moves_left = 15
direction = "N"
def move(self, direction): #how characters move around
if self.collision_check(direction):
print("Collision")
return
if self.moves_left == 0:
print("No more moves left")
return
elif direction == "N":
self.internal_row -= 1
self.direction = "N"
elif direction == "W":
self.internal_column -= 1
self.direction = "W"
elif direction == "E":
self.internal_column += 1
self.direction = "E"
elif direction == "S":
self.internal_row += 1
self.direction = "S"
self.moves_left = self.moves_left - 1
def collision_check(self, direction):
if direction == "N":
if self.internal_row == 0:
return True
if len(Map.Grid[self.internal_column][(self.internal_row)-1]) > 1:
return True
elif direction == "W":
if self.internal_column == 0:
return True
if len(Map.Grid[self.internal_column-1][(self.internal_row)]) > 1:
return True
elif direction == "E":
if self.internal_column == MAPSIZE-1:
return True
if len(Map.Grid[self.internal_column+1][(self.internal_row)]) > 1:
return True
elif direction == "S":
if self.internal_row == MAPSIZE-1:
return True
if len(Map.Grid[self.internal_column][(self.internal_row)+1]) > 1:
return True
return False
def attack(self, direction):
if self.collision_check(direction):
print("Attack attempt.")
if self.direction == "N":
for i in range(0, len(Map.Grid[self.internal_column][self.internal_row-1])):
if Map.Grid[int(self.internal_column)][int(self.internal_row-1)][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column][self.internal_row-1][i].HP -= self.damage
print(str(self.damage) + " damage")
elif self.direction == "E":
for i in range(0, len(Map.Grid[self.internal_column+1][self.internal_row])):
if Map.Grid[self.internal_column+1][self.internal_row][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column+1][self.internal_row][i].HP -= self.damage
print(str(self.damage) + " damage")
elif self.direction == "W":
for i in range(0, len(Map.Grid[self.internal_column-1][self.internal_row])):
if Map.Grid[self.internal_column-1][self.internal_row][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column-1][self.internal_row][i].HP -= self.damage
print(str(self.damage) + " damage")
elif self.direction == "S":
for i in range(0, len(Map.Grid[self.internal_column][self.internal_row+1])):
if Map.Grid[self.internal_column][self.internal_row+1][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column][self.internal_row+1][i].HP -= self.damage
print(str(self.damage) + " damage")
self.moves_left = self.moves_left - 1
def ranged_attack(self, direction):
if self.direction == "S":
for k in range(1, (MAPSIZE - self.internal_row)):
for i in range(0, len(Map.Grid[self.internal_column][self.internal_row + k])):
if Map.Grid[self.internal_column][self.internal_row + k][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column][self.internal_row + k][i].HP -= self.damage
print(str(self.damage) + " damage")
self.moves_left = self.moves_left - 1
if self.direction == "N":
for k in range(1, self.internal_row):
for i in range(0, len(Map.Grid[self.internal_column][self.internal_row - k])):
if Map.Grid[self.internal_column][self.internal_row - k][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column][self.internal_row - k][i].HP -= self.damage
print(str(self.damage) + " damage")
self.moves_left = self.moves_left - 1
if self.direction == "W":
for k in range(1, self.internal_column):
for i in range(0, len(Map.Grid[self.internal_column - k][self.internal_row])):
if Map.Grid[self.internal_column - k][self.internal_row][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column - k][self.internal_row][i].HP -= self.damage
print(str(self.damage) + " damage")
self.moves_left = self.moves_left - 1
if self.direction == "E":
for k in range(1, (MAPSIZE - self.internal_column)):
for i in range(0, len(Map.Grid[self.internal_column + k][self.internal_row])):
if Map.Grid[self.internal_column + k][self.internal_row][i].__class__.__name__ == "Character":
Map.Grid[self.internal_column + k][self.internal_row][i].HP -= self.damage
print(str(self.damage) + " damage")
self.moves_left = self.moves_left - 1
else:
return
class Goblin(Character):
def __init__(self):
Character.__init__(self, "Goblin", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1), 10, random.randint(0,1))
def random_move(self):
i = random.randint(0,3)
if i == 0:
self.move("N")
elif i == 1:
self.move("S")
elif i == 2:
self.move("W")
elif i == 3:
self.move("E")
self.moves_left = 10
class Archer(Character):
def __init__(self):
Character.__init__(self, "Archer", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))
class Warrior(Character):
def __init__(self):
Character.__init__(self, "Warrior", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))
class Scout(Character):
def __init__(self):
Character.__init__(self, "Scout", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))
class Rogue(Character):
def __init__(self):
Character.__init__(self, "Rogue", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))
class Wizard(Character):
def __init__(self):
Character.__init__(self, "Wizard", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))
class Map(object): #The main class; where the action happens
global MAPSIZE
wild_characters = []
can_move = []
no_moves = []
Grid = []
friendlies = []
enemies = []
everyone = [friendlies + enemies]
visible = []
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", column, row, False)
Grid[column][row].append(TempTile)
for row in range(MAPSIZE): #Putting some rocks near the top
for column in range(MAPSIZE):
TempTile = MapTile("Rock", column, row, False)
if row == 1:
Grid[column][row].append(TempTile)
for i in range(10): #Trees in random places
random_row = random.randint(0, MAPSIZE - 1)
random_column = random.randint(0, MAPSIZE - 1)
TempTile = MapTile("Tree", random_column, random_row, False)
Grid[random_column][random_row].append(TempTile)
def generate_hero(self): #Generate a character and place it randomly
temp_hero = Character("Hero", 30, random.randint(0, MAPSIZE - 1), random.randint(0, MAPSIZE - 1) , 10, random.randint(0,1))
self.Grid[temp_hero.internal_column][temp_hero.internal_row].append(temp_hero)
self.can_move.append(temp_hero)
if temp_hero.allegiance == 0:
self.friendlies.append(temp_hero)
elif temp_hero.allegiance == 1:
self.enemies.append(temp_hero)
def return_distance(self, pointA, pointB):
distance = math.sqrt((pointA.internal_column - pointB.internal_column)**2 + (pointA.internal_row - pointB.internal_row)**2)
return distance
def generate_goblin(self): #Generate a character and place it randomly
random_row = random.randint(0, MAPSIZE - 1)
random_column = random.randint(0, MAPSIZE - 1)
temp_goblin = Goblin()
self.Grid[random_column][random_row].append(temp_goblin)
Map.wild_characters.append(temp_goblin)
def update(self):
for column in range(MAPSIZE): #These nested loops go through entire grid
for row in range(MAPSIZE): #They check if any objects internal coordinates
for i in range(len(Map.Grid[column][row])): #disagree with its place on the grid and update it accordingly
if Map.Grid[column][row][i].internal_column != column:
TempChar = Map.Grid[column][row][i]
Map.Grid[column][row].remove(Map.Grid[column][row][i])
Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)
elif Map.Grid[column][row][i].internal_row != row:
TempChar = Map.Grid[column][row][i]
Map.Grid[column][row].remove(Map.Grid[column][row][i])
Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)
temparr = Map.no_moves[:]
for characterobject in temparr: #This moves any characters with moves to the can move list
if len(temparr) > 0:
if characterobject.moves_left > 0:
Map.can_move.append(characterobject)
Map.no_moves.remove(characterobject)
if characterobject.HP <= 0:
Map.no_moves.remove(characterobject)
arr = Map.can_move[:] # copy
for item in arr:
if item.moves_left == 0:
Map.can_move.remove(item)
Map.no_moves.append(item)
if item.HP <= 0:
Map.can_move.remove(item)
for column in range(MAPSIZE):
for row in range(MAPSIZE):
for i in range(len(Map.Grid[column][row])):
if Map.Grid[column][row][i].__class__.__name__ == "Character":
if Map.Grid[column][row][i].HP <= 0:
Map.Grid[column][row].remove(Map.Grid[column][row][i])
print("Character died")
for column in range(MAPSIZE):
for row in range(MAPSIZE):
for i in range(len(Map.Grid[column][row])):
if Map.Grid[column][row][i].__class__.__name__ == "Character":
Map.everyone.append(Map.Grid[column][row][i])
for character in Map.everyone:
for column in range(MAPSIZE):
for row in range(MAPSIZE):
if Map.return_distance(Map.Grid[column][row][0], character ) <= 15:
Map.Grid[column][row].visible = True
def listofcharacters(self):
for column in range(MAPSIZE):
for row in range(MAPSIZE):
for i in range(len(Map.Grid[column][row])):
if Map.Grid[column][row][i].__class__.__name__ == "Character":
print("Column: ", Map.Grid[column][row][i].internal_column, ", Row: ", Map.Grid[column][row][i].internal_row, ", Allegiance: ", Map.Grid[column][row][i].allegiance)
Map = Map()
Map.generate_hero()
while not DONE: #Main pygame loop
for event in pygame.event.get(): #catching events
if event.type == pygame.QUIT:
DONE = True
elif event.type == pygame.MOUSEBUTTONDOWN:
Pos = pygame.mouse.get_pos()
column = Pos[0] // (TILEWIDTH + TILEMARGIN) #Translating the position of the mouse into rows and columns
row = Pos[1] // (TILEHEIGHT + TILEMARGIN)
print(str(row) + ", " + str(column))
for i in range(len(Map.Grid[column][row])):
print(str(Map.Grid[column][row][i].name)) #print stuff that inhabits that square
elif event.type == pygame.KEYDOWN:
wild_char_arr = Map.wild_characters[:]
for wildcharacter in wild_char_arr:
if wildcharacter.name == "Goblin":
wildcharacter.random_move()
if event.key == 97: # Keypress: a
print("New turn.")
temparr = Map.no_moves[:]
for item in temparr:
if item.moves_left == 0:
item.moves_left = 15
TURN = TURN + 1
print("Turn: ", TURN)
elif event.key == 115: # Keypress: s
print("Generated hero.")
Map.generate_hero()
elif event.key == 113: # Keypress: q
print("ranged attack")
Map.can_move[0].ranged_attack(Map.can_move[0].direction)
elif event.key == 119: # Keypress: w
print("Generated hero.")
Map.generate_hero()
elif event.key == 101: # Keypress: e
print("Generated hero.")
Map.generate_hero()
elif event.key == 114: # Keypress: r
print("Generated hero.")
Map.generate_hero()
elif event.key == 116: # Keypress: t
print("Generated hero.")
Map.generate_hero()
elif event.key == 100: # Keypress: d
Map.generate_goblin()
print("Generated goblin.")
elif event.key == 102: # Keypress: f
Map.can_move[0].attack(Map.can_move[0].direction)
elif len(Map.can_move) > 0:
Map.can_move[0].move(KeyLookup[event.key])
else:
print("invalid")
Map.update()
Screen.fill(BLACK)
for row in range(MAPSIZE): # Drawing grid
for column in range(MAPSIZE):
for i in range(0, len(Map.Grid[column][row])):
Color = WHITE
if len(Map.can_move) > 0: # Creating colored area around character showing his move range
if (math.sqrt((Map.can_move[0].internal_column - column)**2 + (Map.can_move[0].internal_row - row)**2)) <= Map.can_move[0].moves_left:
Color = MOVECOLOR
if len(Map.Grid[column][row]) > 1:
Color = RED
if Map.Grid[column][row][i].name == "Tree":
Color = GREEN
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
Color = BROWN
pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,
TILEWIDTH,
TILEHEIGHT])
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
if Map.Grid[column][row][i].direction == "N":
Color = RED
pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,
TILEWIDTH/4,
TILEHEIGHT/4])
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
if Map.Grid[column][row][i].direction == "S":
Color = RED
pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 1 ,
TILEWIDTH/4,
TILEHEIGHT/4])
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
if Map.Grid[column][row][i].direction == "E":
Color = RED
pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 15,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8,
TILEWIDTH/4,
TILEHEIGHT/4])
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
if Map.Grid[column][row][i].direction == "W":
Color = RED
pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN
,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8 ,
TILEWIDTH/4,
TILEHEIGHT/4])
Clock.tick(60)
pygame.display.flip()
pygame.quit()
在Map
:中
friendlies = []
enemies = []
everyone = [friendlies + enemies]
这意味着everyone
被定义为空列表的列表:[ [] + [] ]
==[ [] ]
。这反过来意味着:
for character in Map.everyone:
character
是导致错误的空列表[]
。
此外,由于在分配时只计算一次,因此以后修改friendlies
和enemies
时,不会更改everyone
的值。
当您只需要一个列表列表时,您似乎正在创建一个列表的列表列表。row
列表可以直接包含您的MapTile
;不需要用更多的列表来填充它。
试试这个:
for row in range(MAPSIZE): # Creating grid
Grid.append([])
for row in range(MAPSIZE): #Filling grid with grass
for column in range(MAPSIZE):
TempTile = MapTile("Grass", column, row, False)
Grid[row].append(TempTile)
这样,网格只是一个行列表,每一行都是一个平铺列表,每列一个平铺。