Let's say I have two objects of the MapTile class:
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
Which inhabit a 2-dimensional array, their respective internal_column and internal_row attributes representing their coordinates in the array.
I want to write a function that returns the distance between two such objects. Here is what I have so far:
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
Where pointA and pointB would be the two objects.
When I try it out, I get this error:
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'
I am calling the distance function like this:
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
What should I do? How can I access the attributes of the object in "Map.Grid[column][row]" instead of "Map.Grid[column][row]" itself as a list? Here is how Map.Grid is created:
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)
And I add things directly to Map.everyone like this:
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])
Here is the full, full code as I'm running it:
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()
In Map
:
friendlies = []
enemies = []
everyone = [friendlies + enemies]
This means everyone
is defined as as a list of an empty list: [ [] + [] ]
== [ [] ]
. This in turn means:
for character in Map.everyone:
character
is the empty list []
, which causes your error.
Also, because this is evaluated once at the time of the assignment, when you later modify friendlies
and enemies
it does not change the value of everyone
.