2

I'm probably overlooking something simple.

I'm looping through a 2D Array assigning values to variables in each object in the array. However when 'j' increments the value assigned to gameArray[1][1].x changes from 100 to 400, while it shouldn't be changed after the initial assignment.

--create tilemap 5x5 array
for i = 1, gridSize.x, 1  do
    gameArray[i] = {}
    for j = 1, gridSize.y, 1  do
        gameArray[i][j] = tileArray[math.random(numTiles)]
        gameArray[i][j].x = (i * 100)
        gameArray[i][j].y = (j * 100)
        debug.debug()
    end
end

tileArray[x] is an object containing 4 integers and a love2D image loaded from a PNG.

--tUD
tileArray[1].u = 1
tileArray[1].r = 0
tileArray[1].d = 1
tileArray[1].l = 0
tileArray[1].img = love.graphics.newImage('tiles/tUD.png')

Below is a copy of the debug console while testing:

lua_debug> print(gameArray[1][1].y)
100
lua_debug> cont
lua_debug> print(gameArray[1][1].y)
100
lua_debug> cont
lua_debug> print(gameArray[1][1].y)
100
lua_debug> cont
lua_debug> print(gameArray[1][1].y)
400
lua_debug>

Any ideas what may be causing this?

0

2 Answers 2

1

Your inner loop is overwriting previously stored values in gameArray[i][j].y. This is because of this line:

gameArray[i][j] = tileArray[math.random(numTiles)]

Here, a random number, presumably from 1 to 25, is used to select a tile. But, it is likely that the same tile will be selected more that once, leading to the first value written to gameArray[i][1].y being overwritten when j is larger. I don't know exactly what functionality you desire here, but one solution is to build an array of indices, and to randomly select an index when selecting a tile, removing the index from the list so that it can not be selected again.

Here is an example of how this might be implemented. I have included some dummy initializations so that the code runs and displays results:

-- Dummy initializations
tileArray = {}
for i = 1, 25 do
   tileArray[i] = {}
end

gameArray = {}
gridSize = {}

-- Initialize gridSize
gridSize.x = 5
gridSize.y = 5

-- List of available tile indices
indices = {}
for i = 1, 25 do
   indices[i] = i
end

-- Create tilemap 5x5 array
for i = 1, gridSize.x do
    gameArray[i] = {}
    for j = 1, gridSize.y do
        k = math.random(#indices)
        index = indices[k]
        table.remove(indices, k) 
        gameArray[i][j] = tileArray[index]
        gameArray[i][j].x = (i * 100)
        gameArray[i][j].y = (j * 100)
    end
end

-- Display results    
for i = 1, gridSize.x do
   for j = 1, gridSize.y do
      fmt = string.format("[%d][%d].x = %d, [%d][%d].y = %d\n",
                          i, j, gameArray[i][j].x, i, j, gameArray[i][j].y)
      io.write(fmt)
   end
end

Program output:

[1][1].x = 100, [1][1].y = 100
[1][2].x = 100, [1][2].y = 200
[1][3].x = 100, [1][3].y = 300
[1][4].x = 100, [1][4].y = 400
[1][5].x = 100, [1][5].y = 500
[2][1].x = 200, [2][1].y = 100
[2][2].x = 200, [2][2].y = 200
[2][3].x = 200, [2][3].y = 300
[2][4].x = 200, [2][4].y = 400
[2][5].x = 200, [2][5].y = 500
[3][1].x = 300, [3][1].y = 100
[3][2].x = 300, [3][2].y = 200
[3][3].x = 300, [3][3].y = 300
[3][4].x = 300, [3][4].y = 400
[3][5].x = 300, [3][5].y = 500
[4][1].x = 400, [4][1].y = 100
[4][2].x = 400, [4][2].y = 200
[4][3].x = 400, [4][3].y = 300
[4][4].x = 400, [4][4].y = 400
[4][5].x = 400, [4][5].y = 500
[5][1].x = 500, [5][1].y = 100
[5][2].x = 500, [5][2].y = 200
[5][3].x = 500, [5][3].y = 300
[5][4].x = 500, [5][4].y = 400
[5][5].x = 500, [5][5].y = 500

UPDATE

Given some more information about the goals of the OP code, it became apparent that you need to be able to use tiles from tileArray more than once. The problem is that by assigning an element from tileArray to gameArray[i][j], and then modifying gameArray[i][j], you are also modifying the original tile element.

The solution is to assign a copy of the tile element to gameArray[i][j]. Lua does not come with a function to copy tables, but you can look at this link to read about ways to copy tables. For a simple table requiring only a shallow copy, the page linked provides a function called shallowcopy(). Here is a modification of the above code that uses shallowcopy():

function shallowcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in pairs(orig) do
            copy[orig_key] = orig_value
        end
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

-- Dummy initializations
numTiles = 5
tileArray = {}
for i = 1, numTiles do
   tileArray[i] = {}
   tileArray[i].tile_type = i
end

gameArray = {}
gridSize = {}

-- Initialize gridSize
gridSize.x = 5
gridSize.y = 5

-- Create tilemap 5x5 array
for i = 1, gridSize.x do
    gameArray[i] = {}
    for j = 1, gridSize.y do
       gameArray[i][j] = shallowcopy(tileArray[math.random(numTiles)])
       gameArray[i][j].x = (i * 100)
       gameArray[i][j].y = (j * 100)
    end
end

-- Display results    
for i = 1, gridSize.x do
   for j = 1, gridSize.y do
      fmt = string.format("[%d][%d].x = %d, [%d][%d].y = %d : type %d\n",
                          i, j, gameArray[i][j].x, i, j, gameArray[i][j].y,
                          gameArray[i][j].tile_type)
      io.write(fmt)
   end
end

Program output:

[1][1].x = 100, [1][1].y = 100 : type 1
[1][2].x = 100, [1][2].y = 200 : type 1
[1][3].x = 100, [1][3].y = 300 : type 5
[1][4].x = 100, [1][4].y = 400 : type 2
[1][5].x = 100, [1][5].y = 500 : type 3
[2][1].x = 200, [2][1].y = 100 : type 5
[2][2].x = 200, [2][2].y = 200 : type 4
[2][3].x = 200, [2][3].y = 300 : type 2
[2][4].x = 200, [2][4].y = 400 : type 4
[2][5].x = 200, [2][5].y = 500 : type 3
[3][1].x = 300, [3][1].y = 100 : type 3
[3][2].x = 300, [3][2].y = 200 : type 5
[3][3].x = 300, [3][3].y = 300 : type 2
[3][4].x = 300, [3][4].y = 400 : type 4
[3][5].x = 300, [3][5].y = 500 : type 3
[4][1].x = 400, [4][1].y = 100 : type 4
[4][2].x = 400, [4][2].y = 200 : type 3
[4][3].x = 400, [4][3].y = 300 : type 5
[4][4].x = 400, [4][4].y = 400 : type 2
[4][5].x = 400, [4][5].y = 500 : type 2
[5][1].x = 500, [5][1].y = 100 : type 5
[5][2].x = 500, [5][2].y = 200 : type 5
[5][3].x = 500, [5][3].y = 300 : type 1
[5][4].x = 500, [5][4].y = 400 : type 5
[5][5].x = 500, [5][5].y = 500 : type 3
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer, it's going to help a lot with fixing this bug, however i'm trying to allow the creation of duplicate tiles. e.g. tile 1-1 and tile 1-5 may be copies of each other. I'll try to find another way around this but thank you very much for the help
I can't really tell you how to create duplicates of your tables, since I don't know their structure, but here is a link about this that may be helpful.
0

While the above answer written by David Bowling works and is beautiful code, it does not fix the original problem as the duplication of tiles is prevented as part of the fix.

The original problem was fixed by using a shallow copy function for the table. Which was borrowed from the following site: http://lua-users.org/wiki/CopyTable

Changing the line

gameArray[i][j] = tileArray[math.random(numTiles)]

to

gameArray[i][j] = shallowcopy(tileArray[math.random(numTiles)])

Adding this is as a second answer for anyone that has a similar problem

1 Comment

You need instead, gameArray[i][j] = shallowcopy(tileArray[math.random(numTiles)]), to assign the copy to gameArray[i][j]. I have updated my answer to show an example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.