Python / Pygame: список перезаписывается сам по себе - PullRequest
1 голос
/ 14 октября 2019

Итак, я недавно начал с python и сейчас работаю над простой игрой в стиле 2D-майнкрафта. Я пытался нарисовать некоторые изображения на поверхности, используя Pygame, но с (2D) массивом, в котором хранятся все блоки в мире, происходит что-то странное. Я еще не делал никаких случайных вещей для генерации ландшафта, поэтому использую это для создания полностью плоского мира:


class World:
    def __init__(self, width, height, blockSprites):
        self.width = width
        self.height = height
        self.blockSprites = blockSprites

    def generate(self):
        temp = [self.air] * self.width
        self.map = [temp] * self.height
        for y in range(self.height):
            for x in range(self.width):
                if(y < 50):
                    self.map[y][x] = self.dirt

Это класс Block и класс Camera:

class Block:
    def __init__(self, blockid, textureX, textureY):
        self.textureX = textureX
        self.textureY = textureY
        self.solid = True
        self.id = blockid


from math import floor
class Camera:
    def __init__(self, worldWidth, worldHeight):
        self.x = 0
        self.xB = floor(self.x/64)
        self.y = 55*64 #test value for initial camera position
        self.yB = floor(self.y/64)
        self.zoom = 1
        self.baseWidth = 960
        self.baseWidthB = 15 #in blocks (1block = 64px)
        self.baseHeight = 640
        self.baseHeightB = 10

А вот и функция World.draw, которая вызывается каждый кадр:

   def draw(self, canvas, camera):
        #canvas is the pygame surface which I draw on
        canvas.fill(pygame.Color(143, 218, 239))
        for y in range(camera.baseHeightB):
            for x in range(camera.baseWidthB):
                #id=0 means"air"
                if(not self.map[camera.yB + y][camera.xB + x].id == 0):
                    canvas.blit(self.blockSprites, (x*64, camera.baseHeight - (y+1)*64), (self.map[camera.yB + y][camera.xB + x].textureX, self.map[camera. yB + y][camera.xB + x].textureY, 64, 64))
        return canvas

Проблема в том, что world.map - это не половина блоков грязи и половина воздушных блоков, когда я вызываю world.draw ()... это все грязные блоки ... Я пытался добавить

else:
    self.map[y][x] = self.air

в конец world.generate, и все превратилось в воздушные блоки ... Может кто-нибудь сказать мне, почему это так?

1 Ответ

1 голос
/ 14 октября 2019

Допустим, у вас есть класс Item и 2 экземпляра o из Item:

class Item:
   def  __init__(self, c):
        self.c = c

o = Item('o')
w, h = 3, 3

Выход

for r in map: print([c.c for c in r])

равен

['o', 'o', 'o']
['o', 'o', 'o']
['o', 'o', 'o']

Оператор temp = [o] * w создает список ссылок на тот же элемент o, а оператор map = [temp] * h создает список ссылок на тот же объект списка temp.

temp = [o] * w
map = [temp] * h

В конце каждый элемент map ссылается на один-единственный список temp, а каждый элемент temp ссылается на один-единственный объект o. Если содержимое одного внутреннего элемента карты изменяется, то магическим образом кажется, что весь объект меняется. Причина в том, что существует только один объект o, и все элементы карты ссылаются на один и тот же объект.

Таким образом, вывод:

map[1][1].c = '_'
for r in map: print([c.c for c in r])

равен

['_', '_', '_']
['_', '_', '_']
['_', '_', '_']

Если создается новый экземпляр x из Item и изменяется один элемент map

x = Item('x')
map[1][1] = x 
for r in map: print([c.c for c in r])

Тогда все элементы в строкеменять. Обратите внимание, что каждый элемент ссылается на один и тот же список temp. Строк не много, есть только один объект temp. Если элемент temp изменяется, то это, кажется, изменения в каждой строке:

['_', 'x', '_']
['_', 'x', '_']
['_', 'x', '_']

Вы должны создать карту, где каждый элемент карты являетсяотдельный экземпляр Item:

map = [[Item('o') for i in range(w)] for j in range(h)]

Обратите внимание, Item('o') создает новый экземпляр Item.
Теперь содержимое элемента можно изменить или назначить новый объектвнутренний элемент, потому что для каждого объекта в каждой строке есть один отдельный объект:

map[1][1].c = 'X'
map[1][0] = Item('x')
for r in map: print([c.c for c in r])
['o', 'o', 'o']
['x', 'X', 'o']
['o', 'o', 'o']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...