简体   繁体   中英

Python - variable is getting set to 0 and can't figure out why

Okay, so I'm making a little game with pygame and building the map by generating tiles to a multidimensional array. In order to do that I'm using two for loops.

def create(this, t):

    if t == "grasslands":
        for j in range(0, this.numRows):
            for i in range(0, this.numColumns):
                this.column.append(this.Tile("grass", j * this.tileWidth, i * this.tileHeight))
            this.row.append(this.column)

The value for j * this.tileWidth is getting passed into the Tile initialization correctly. After though the column[whatever].x value is still 0. The y value gets set just fine, and if I use i or any other value instead of j things work just fine. Is this something I'm doing wrong or something wonky with Python?

mapgen.py

import pygame
from sprite import *
from assets import *

class mapG:

def __init__(this, resw, resh):
    this.numRows = 3
    this.numcolumns = 3
    this.tileWidth = 128
    this.tileHeight = 128

    this.row = []
    this.column = []
    this.width = this.numRows * this.tileWidth
    this.height = this.numcolumns * this.tileHeight


def create(this, t):

    if t == "grasslands":
        for j in range(0, this.numRows):
            for i in range(0, this.numcolumns):
                this.column.append(this.Tile("grass", j * this.tileWidth, i * this.tileHeight))
            this.row.append(this.column)


def tileAt(this, x, y):
    pass

def moveRight(this):
    for j in range(0,this.numRows):
        for i in range(0, this.numcolumns):
            this.row[j][i].incX(1)

def Update(this, src):
    for j in range(0,this.numRows):
        for i in range(0, this.numcolumns):
            this.row[j][i].Update(src)
            print(this.row[j][i].y, this.row[j][i].x)

class Tile:

    def __init__(this, name, xpos, ypos):
        this.y = ypos
        this.x = xpos
        this.image = assets.tile[name + ".png"]
        this.sprite = sprite(this.image, this.x, this.y, 100, 100)

    def incX(this, amount):
        this.sprite.IncX(amount)

    def decX(this, amount):
        this.sprite.DecX(amount)

    def incY(this, amount):
        this.sprite.IncY(amount)

    def decY(this, amount):
        this.sprite.DecY(amount)

    def Update(this, src = None):
        if src != None:
            this.sprite.Update(src)

sprite.py

import pygame
import assets

class sprite:

def __init__(this, image, xpos, ypos, width = None, height = None):

    this.image = image
    this.x = xpos
    this.y = ypos
    this.width = width
    this.height = height

    if this.width != None and this.height != None:
        this.image = pygame.transform.scale(image, (this.width,this.height))

def GetPos(this):
    return (this.x, this.y)

def IncX(this, amount):
    this.x += amount

def IncY(this, amount):
    this.y += amount

def DecX(this, amount):
    this.x -= amount

def DecY(this, amount):
    this.y -= amount

def Update(this, src = None):
    if src != None:
        src.blit(this.image, this.GetPos())

I believe the issue you have comes from your use of the this.column variable in the create method.

You're only creating one column list (in __init__ ) and then reusing it for all the columns of your map. This won't work.

Your this.row list ends up having multiple references to the same column list, which ends up containing all of the Tile objects you create. You only see some of them later, since your iteration code uses predefined dimensions, rather than actually iterating over the whole of the lists.

To understand this, try to imagine how the iteration progresses for a 2x2 grid (ignoring the tile dimensions). I'm putting each i and j value on it's own line to show how it progresses, and giving the values of row and columns after each step side:

j=0:
   i=0:
      column.append(Tile(i, j))
      # column is [Tile(0, 0)]
      # row is []

   i=1:
      column.append(Tile(i, j))
      # column is [Tile(0, 0), Tile(0, 1)]
      # row is []

   row.append(column)
   # column is [Tile(0, 0), Tile(0, 1)]
   # row is [[Tile(0, 0), Tile(0, 1)]]

j=1: # column is not reset!
   i=0:
      column.append(Tile(i, j))
      # column is [Tile(0, 0), Tile(0, 1), Tile(1, 0)]
      # row is [[Tile(0, 0), Tile(0, 1), Tile(1, 0)]]

   i=1:
      column.append(Tile(i, j))
      # column is [Tile(0, 0), Tile(0, 1), Tile(1, 0), Tile(1, 1)]
      # row is [[Tile(0, 0), Tile(0, 1), Tile(1, 0), Tile(1, 1)]]

   row.append(column)
   # column is [Tile(0, 0), Tile(0, 1), Tile(1, 0), Tile(1, 1)]
   # row is [[Tile(0, 0), Tile(0, 1), Tile(1, 0), Tile(1, 1)],
   #          [Tile(0, 0), Tile(0, 1), Tile(1, 0), Tile(1, 1)]]

The row list contains two references to the same column list of four tiles. Your code had intended to add the first two Tile(0, 0) and Tile(0,1) to the first column, then the last two tiles Tile(1, 0) and Tile(1, 1) to the second column. But because the same list was used both times, you end up with all the values together, and then the whole bunch repeated. When you iterate, you're only seeing the repeated values on the left part of the diagram above.

Here's how to fix it:

def create(this, t):
    if t == "grasslands":
        for j in range(0, this.numRows):

            column = [] # Create a new list! This is the key!

            for i in range(0, this.numColumns):
                column.append(this.Tile("grass",
                              j * this.tileWidth,
                              i * this.tileHeight))
            this.row.append(column)

You can get rid of the line in the constructor that initializes self.column too. It's only needed temporarily, so there's no need to use an instance variable.

You don't end up creating rows of width 3 ( numColumns ). You end up with rows of width 9 (rows*cols) since you don't create a new row each time through the loop.

Your loop should look like this:

for j in range(0, this.numRows):
    row=[]
    for i in range(0, this.numColumns):
        row.append(this.Tile("grass", j * this.tileWidth, i * this.tileHeight))
    this.rows.append(row)

And then you probably ended up looking at the wrong data when you were debugging it, not realizing the row was longer than you expected. (Also the names are a bit confusing, so I changed them a bit.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM