Reputation: 21
So I've recently started with python and I'm working on a simple 2D-minecraft-like game right now. I was trying to draw some images on a Surface using Pygame but something weird keeps happening to the (2D) Array that stores all the blocks in the world. I haven't done any random terrain generation stuff yet so I'm using this to make a completely flat world:
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
This is the Block class and the Camera class:
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
And here is the World.draw function which gets called every frame:
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
The Problem is that world.map isn't half dirt blocks and half air blocks when I call world.draw()... It's all dirt blocks... I've tried adding
else:
self.map[y][x] = self.air
to the end of world.generate and everything turned into air blocks... Can someone tell me why this is?
Upvotes: 1
Views: 87
Reputation: 210998
Lets assume you've a class Item
and 2 instances o
of Item
:
class Item:
def __init__(self, c):
self.c = c
o = Item('o')
w, h = 3, 3
The output of
for r in map: print([c.c for c in r])
is
['o', 'o', 'o'] ['o', 'o', 'o'] ['o', 'o', 'o']
The statement temp = [o] * w
create a list o f references to the same item o
and the statement map = [temp] * h
creates a list of references to the same list object temp
.
temp = [o] * w
map = [temp] * h
At the end each element of map
refers to the one and only list temp
and each element of temp
refers to the one and only object o
.
If the content of one inner element of the map is changed then magically all object seems to change. The reason is there is just one object o
and all elements from map refer to the same object.
So the output of:
map[1][1].c = '_'
for r in map: print([c.c for c in r])
is
['_', '_', '_'] ['_', '_', '_'] ['_', '_', '_']
If a new instance of x
of Item
is created and a single element of map
is changed
x = Item('x')
map[1][1] = x
for r in map: print([c.c for c in r])
Then all the items of on row seems to change. Note, each element refers to the same list temp
. There are not multiple rows, there is just one row object temp
.
If an element of temp
is changed, then this appears to be changes in each row:
['_', 'x', '_'] ['_', 'x', '_'] ['_', 'x', '_']
You've to create a map where each element of the map is a separate instance of Item
:
map = [[Item('o') for i in range(w)] for j in range(h)]
Note, Item('o')
creates a new instance of Item
.
Now the content of an element can be changed or a new object can be assigned to an inner element, because there is one separate object for each object in each row:
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']
Upvotes: 1