[Solved] 2D Array

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Bondrusiek
Prole
Posts: 23
Joined: Sun Dec 03, 2023 2:49 pm

[Solved] 2D Array

Post by Bondrusiek »

Hi I have no a big experience with Lua. I have a problem with 2d array. I mark by "*" where is a critical points:

Code: Select all

FallingSand = Object:extend()

local WIDTH  = 500
local HEIGHT = 300
local m_size = 5
local m_cols
local m_rows
local m_grid = {}
local m_nextGrid = {}
local m_clicked = false
local m_hueValue = 0

function FallingSand:new()
    m_cols = math.floor(WIDTH / m_size)
    m_rows = math.floor(HEIGHT / m_size)
    for i = 1, m_cols do
        m_grid[i]     = {}
        m_nextGrid[i] = {}
        for j = 1, m_rows do 
            m_grid[i][j] = 0
            m_nextGrid[i][j] = 0
        end
    end
end

function FallingSand:update(dt)
    local mouseX, mouseY
    local mouseCol =  1
    local mouseRow = 1
    local matrix = 5
    local extent = math.floor(matrix / 2)
    if input:down('leftButton') then
        mouseX, mouseY = love.mouse.getPosition()
        mouseCol = math.floor(mouseX / m_size)
        mouseRow = math.floor(mouseY / m_size)
        for i = -extent, extent do
            for j = -extent, extent do
                local randomValue = love.math.random(100)
                if randomValue < 75 then
                    local col = mouseCol + i + 1
                    local row = mouseRow + j + 1
                    if FallingSand:withinCols(col) and FallingSand:withinRows(row) then
                        --*********** here is m_grid[i][j] set to 100
                        m_grid[col][row] = 100 
                    end
                end

            end
        end

    for i = 1, m_cols do
        for j = 1, m_rows do 
            m_nextGrid[i][j] = 0
        end
    end

    for i = 1, m_cols do
        for j = 1, m_rows do
            --  What is the state?
            --*********** state always is set to 0 from m_grid[i][j]
            local state = m_grid[i][j]
            -- Randomly fall left or right
            if state > 0 then 
                local below = m_grid[i][j + 1]
                -- Randomly fall left or right
                local dir = 1
                if love.math.random(100) < 50 then 
                    dir = dir * -1
                end

                --Check below left or right
                local belowA = -1
                local belowB = -1
                if FallingSand:withinCols(i + dir) then 
                    belowA = m_grid[i + dir][j + 1]
                end
                if FallingSand:withinCols(i - dir) then 
                    belowB = m_grid[i - dir][j + 1]
                end
                -- Can it fall below or left or right?
                if below == 0 then 
                    m_nextGrid[i][j + 1] = state
                elseif belowA == 0 then 
                    m_nextGrid[i + dir][j + 1] = state
                elseif belowB == 0 then
                    m_nextGrid[i - dir][j + 1] = state;
                    -- Stay put!
                else 
                    m_nextGrid[i][j] = state;
                end
            end
        end
    end
    m_grid = m_nextGrid

    end
end

function FallingSand:draw()
    love.graphics.print("Falling Sand", 0, 0)
    for i = 1, m_cols do 
        for j = 1, m_rows do 
            if m_grid[i][j] > 0 then 
                love.graphics.setColor(0.5, 1.0, 1.0)
                local x = (i - 1) * m_size
                local y = (j - 1) * m_size
                love.graphics.rectangle('fill', x, y, m_size, m_size)
            end
        end
    end
end

function FallingSand:withinCols(x)
    return x >= 1 and x <= m_cols
end

function FallingSand:withinRows(y)
    return y >= 1 and y <= m_rows
end

I have no idea how solve that. I use print() func to debug value and in input:down() m_grid[][] is set on 100 but lower m_grid[] [] always return 0. Do you have nay tips ?
Last edited by Bondrusiek on Wed May 15, 2024 8:08 am, edited 1 time in total.
User avatar
Bobble68
Party member
Posts: 162
Joined: Wed Nov 30, 2022 9:16 pm
Contact:

Re: 2D Array

Post by Bobble68 »

Currently looking through it, however you haven't given us much to go on in terms of what's actually wrong vs what you want, so it's not easy to pinpoint the issue, especially without the full project.

Edit: Something I have noticed is that at line 44 col and row can be 0 which isn't accounted for at line 51 which starts at 1, however I have no idea if this is intentional or is even related your problem.

Edit 2: I've also noticed that you have a lot of variables with the m_ prefix, which I know is commonly used to show a variable is a member of a class. However (assuming my assuption is correct), this isn't how Lua works - the local variables here will be shared between all instances of the FallingSand object, which may be causing your problems (again, hard to know without context).

In Lua, members of an object are accessed by indexing it, and object functions can access themselves by using the 'self' keyword. Here's what I imagine it should look like:

Code: Select all

FallingSand = Object:extend()

local WIDTH  = 500
local HEIGHT = 300


function FallingSand:new()

    self.size = 5
    self.grid = {}
    self.nextGrid = {}
    self.clicked = false
    self.hueValue = 0
    self.cols = math.floor(WIDTH / self.size)
    self.rows = math.floor(HEIGHT / self.size)
    for i = 1, self.cols do
        self.grid[i]     = {}
        self.nextGrid[i] = {}
        for j = 1, self.rows do 
            self.grid[i][j] = 0
            self.nextGrid[i][j] = 0
        end
    end
end

function FallingSand:update(dt)
    local mouseX, mouseY
    local mouseCol =  1
    local mouseRow = 1
    local matrix = 5
    local extent = math.floor(matrix / 2)
    if input:down('leftButton') then
        mouseX, mouseY = love.mouse.getPosition()
        mouseCol = math.floor(mouseX / self.size)
        mouseRow = math.floor(mouseY / self.size)
        for i = -extent, extent do
            for j = -extent, extent do
                local randomValue = love.math.random(100)
                if randomValue < 75 then
                    local col = mouseCol + i + 1
                    local row = mouseRow + j + 1
                    if FallingSand:withinCols(col) and FallingSand:withinRows(row) then
                        --*********** here is self.grid[i][j] set to 100
                        self.grid[col][row] = 100 
                    end
                end

            end
        end

        for i = 1, self.cols do
            for j = 1, self.rows do 
                self.nextGrid[i][j] = 0
            end
        end

        for i = 1, self.cols do
            for j = 1, self.rows do
                --  What is the state?
                --*********** state always is set to 0 from self.grid[i][j]
                local state = self.grid[i][j]
                -- Randomly fall left or right
                if state > 0 then 
                    local below = self.grid[i][j + 1]
                    -- Randomly fall left or right
                    local dir = 1
                    if love.math.random(100) < 50 then 
                        dir = dir * -1
                    end

                    --Check below left or right
                    local belowA = -1
                    local belowB = -1
                    if FallingSand:withinCols(i + dir) then 
                        belowA = self.grid[i + dir][j + 1]
                    end
                    if FallingSand:withinCols(i - dir) then 
                        belowB = self.grid[i - dir][j + 1]
                    end
                    -- Can it fall below or left or right?
                    if below == 0 then 
                        self.nextGrid[i][j + 1] = state
                    elseif belowA == 0 then 
                        self.nextGrid[i + dir][j + 1] = state
                    elseif belowB == 0 then
                        self.nextGrid[i - dir][j + 1] = state;
                        -- Stay put!
                    else 
                        self.nextGrid[i][j] = state;
                    end
                end
            end
        end
    self.grid = self.nextGrid

    end
end

function FallingSand:draw()
    love.graphics.print("Falling Sand", 0, 0)
    for i = 1, self.cols do 
        for j = 1, self.rows do 
            if self.grid[i][j] > 0 then 
                love.graphics.setColor(0.5, 1.0, 1.0)
                local x = (i - 1) * self.size
                local y = (j - 1) * self.size
                love.graphics.rectangle('fill', x, y, self.size, self.size)
            end
        end
    end
end

function FallingSand:withinCols(x)
    return x >= 1 and x <= self.cols
end

function FallingSand:withinRows(y)
    return y >= 1 and y <= self.rows
end

The variable declarations have been moved inside the :new() function, since they need to be declared for every new object. Hopefully this is your issue, but it's impossible to say.
Last edited by Bobble68 on Wed Apr 03, 2024 6:28 pm, edited 2 times in total.
Dragon
MrFariator
Party member
Posts: 548
Joined: Wed Oct 05, 2016 11:53 am

Re: 2D Array

Post by MrFariator »

Keep in mind that whenever you create a new instance of this FallingSand class, the m_grid variable is essentially reset (ie. the "state" becomes 0 for all entries). You might be creating new instances somewhere else in your code, and this is the source of your woes.

To fix this, you'd need to make sure that each instance of this FallingSand class would have its own m_grid variable. For example, inside the new function you'd do this:

Code: Select all

function FallingSand:new()
    m_cols = math.floor(WIDTH / m_size)
    m_rows = math.floor(HEIGHT / m_size)
    
    -- 'self' refers to the new instance we're creating
    self.m_grid = {}
    for i = 1, m_cols do
        self.m_grid[i] = {}
        for j = 1, m_rows do 
            self.m_grid[i][j] = 0
        end
    end
end
And similarly handle the "m_grid" in other places via the "self". Of course, this is assuming you are using classic.
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: 2D Array

Post by pgimeno »

There's also an indentation problem within FallingSand:update(). This IF statement:

Code: Select all

if input:down('leftButton') then
is closed at the very end of the function, but the indentation suggests that that's not the intention.
Bondrusiek
Prole
Posts: 23
Joined: Sun Dec 03, 2023 2:49 pm

Re: 2D Array

Post by Bondrusiek »

pgimeno MrFariator Boble68 thank you for your suggestion/tips/help!

I also investigate a bit and I found the interesting thing. I would like to point out that I am not an expert in Lua (I am more C++-centric):
I printed two values one is self.grid and second is self.nextGrid:

Code: Select all

    print("grid ", self.grid)
    print("next_grid ", self.nextGrid)
grid table: 0x01033e9970
next_grid table: 0x01033e99b8
If I understand correctly on the right is an address of memory so If I assign

Code: Select all

self.grid = self.nextGrid
self.grid is the same memory address like self.nextGrid. I have to assign only values so I created a for loop:

Code: Select all

        for i = 1, self.cols do
            for j = 1, self.rows do
                if self.grid[i][j] ~= self.nextGrid[i][j] then
                    self.grid[i][j] = self.nextGrid[i][j]
                end
            end
        end
I create a falling sand effect. Here is my Love2D example.
test.png
test.png (19.8 KiB) Viewed 1753 times
PS.
I have a problem with classic module. IE

Code: Select all

FallingSand = Object:extend()

function FallingSand:new()
    self.cols = 5
end

function FallingSand:update(dt)
	print(FallingSand:withinCols(5))
end

function FallingSand:draw()

end

function FallingSand:withinCols(x)
    return x >= 1 and x <= self.cols -- Other func than new/update/draw. In this kind of function all self values are nil ???
end
RNavega
Party member
Posts: 353
Joined: Sun Aug 16, 2020 1:28 pm

Re: 2D Array

Post by RNavega »

Code: Select all

function FallingSand:update(dt)
	print(FallingSand:withinCols(5))
end
Try self:withinCols(5) so the sugar becomes FallingSand.withinCols(self, 5).

The colon syntax is explained in here (the entire PIL e-book is useful btw): https://www.lua.org/pil/16.html
Bondrusiek
Prole
Posts: 23
Joined: Sun Dec 03, 2023 2:49 pm

Re: 2D Array

Post by Bondrusiek »

Try self:withinCols(5) so the sugar becomes FallingSand.withinCols(self, 5).
It works now. Thank you!
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 2 guests