如何防止 renderBlocks() 函数进入无限循环?

问题描述

-- This is minecraft,but 2D,and in Lua.

-- **************************************
-- ID 0: Air
-- ID 1: Stone
-- ID 2 Logs
-- ID 3: Leaves
-- ID 4: Planks
-- ID 5: Crafting Table
-- ID 6: Furnance
-- ID 7: Player position detector block
-- **************************************

blockTable = { -- Stores all the blocks
    {0,0},{0,7,{6,6,6}
}
tableRow = 1 -- Y value for block render pointer
tableColumn = 1 -- X value for block render pointer
runOnce = true -- Run a loop once
tickNum = 0 -- Number of ticks since startup
function renderBlock(X,Y,K) -- Render a block
    if K == 1 then -- if blockID == 1,draw a grey square
        screen.setColor(100,100,100)
        print(X,Y)
        screen.drawRectF(X,8,8)
    end
    if K == 6 then -- If the blockID == draw a grey square
        screen.setColor(100,100)
        screen.drawRectF(X,8)
    end
end

function renderBlocks() -- Render all the blocks (Scans though the blockTable in a raster pattern)
        while runOnce == true -- Run this code once
    do
    while #blockTable >= tableRow
    do
        while #blockTable[tableRow] >= tableColumn
        do
            print("TC " .. tableColumn)
            tableColumn = tableColumn + 1
            
            blockID = blockTable[tableRow][tableColumn]
            renderBlock(tableRow,tableColumn,blockID)
            if tableColumn > #blockTable[tableRow] then tableColumn = 1 end
        end
        runOnce = false
    end
        print("TR " .. tableRow)
        tableRow = tableRow + 1
    end
end

function onTick()
    print("Tick! Tick count: " .. tickNum) -- Print the current tick,as well as say that there has been a tick
    tickNum = tickNum + 1
end

function onDraw()
    while runOnce == true -- Run this code once
    do
    renderBlocks()
    runOnce = false
    end
end

这是我在 IDE 中的框架代码Link

我不知道为什么会这样,我在这里不知所措。

解决方法

在对表进行循环时,使用 for 循环比使用 while 或 repeat 循环要好得多,后者更难理解和修正错误。

如果您想获取索引(表中的数字)和关联的值,请使用 for index,value in ipairs(yourtable) do 或如果您想获取键(通常用作值的键的字符串),请使用 for key,value in pairs(yourtable) do : yourTable["key"] = 0) 以及与之关联的值。

for row,innerTable in ipairs(blockTable) do
        
    for col,value in ipairs(innerTable) do
            
        print("TC " .. col)
            
        blockID = value
        renderBlock(row,col,blockID)
            
    end
        
end

最后一个应该在你的 renderBlocks 函数中完成。但是:

while runOnce == true do

    -- Doing something
    runOnce = false

end

不是很好的东西。如果它只被调用一次,不要把它放入循环中!

此外,更好的代码识别有助于更快地了解正在发生的事情。并在处理不同问题的代码块之间添加一些空间。

编辑:因此您的函数可能如下所示:

function renderBlocks()
    if runOnce then
        runOnce = false
        for row,innerTable in ipairs(blockTable) do
            for col,value in ipairs(innerTable) do
                blockID = value
                renderBlock(row,blockID)
            end
        end
    end
end
,

您的 renderBlocks() 函数中有几个问题

function renderBlocks()
  while runOnce == true do
    while #blockTable >= tableRow do
      while #blockTable[tableRow] >= tableColumn do
        print("TC " .. tableColumn)
        tableColumn = tableColumn + 1

        blockID = blockTable[tableRow][tableColumn]
        renderBlock(tableRow,tableColumn,blockID)
        if tableColumn > #blockTable[tableRow] then 
          tableColumn = 1 
        end
      end
      runOnce = false
    end
    print("TR " .. tableRow)
    tableRow = tableRow + 1
  end
end

首先我们可以看看最里面的循环。这里我们遇到了用于评估循环的悔恨以及它是如何递增的问题。

while #blockTable[tableRow] >= tableColumn do
  print("TC " .. tableColumn)
  tableColumn = tableColumn + 1 -- incremented here

  blockID = blockTable[tableRow][tableColumn]
  renderBlock(tableRow,blockID)
  if tableColumn > #blockTable[tableRow] then 
    tableColumn = 1 -- reset here
  end
end

在循环体中执行 tableColumn = tableColumn + 1 之后在同一个体中执行 if tableColumn > #blockTable[tableRow] then tableColumn = 1 end 所以当 tableColumn 增加到会结束我们重置的循环的值时,这是一个问题它 1 防止循环永远结束。

现在让我们看看下一个循环。这里我们从不增加 tableRow 它是在这个循环结束后增加的,所以循环不可能结束。

while #blockTable >= tableRow do
    while #blockTable[tableRow] >= tableColumn do
        ...
    end
    runOnce = false
end

我相信你是故意的

print("TR " .. tableRow)
tableRow = tableRow + 1

发生在这个循环内而不是在它之外。

,

您在这里遗漏了一些块定义。不要认为这就是将它发送到无限循环的原因,否则您可能看不到结果。

function renderBlock(X,Y,blockID)  --  Render a block
  if blockID == 0 then  --  Air
    --  screen.setColor(10,20,220,0) -- is there an alpha channel?
    screen.setColor(10,220)

  elseif blockID == 1 then  --  Stone
    screen.setColor(100,100,100)

  elseif blockID == 2 then  --  Logs
    screen.setColor(200,50,50)

  elseif blockID == 3 then  --  Leaves
    screen.setColor(20,40)

  elseif blockID == 4 then  --  Planks
    screen.setColor(180,30,10)

  elseif blockID == 5 then  --  Craft Table
    screen.setColor(180,10)

  elseif blockID == 6 then  --  Furnace
    screen.setColor(100,100)

  elseif blockID == 7 then  --  Player detect
    screen.setColor(220,30)
  end

  print(X,Y)
  screen.drawRectF(X,8,8)
end

使用 for 循环很容易。设置初始条件,然后设置最终完成条件,让它运行课程。

function renderBlocks() -- Render all blocks (Scans though blockTable in a raster pattern)
  for row = 1,#blockTable do
    for col = 1,#blockTable[row] do
      print("TC " ..col)
      local blockID = blockTable[row][col]
      renderBlock(row,blockID)
    end
    print("TR " ..row)
  end
end

您可能不需要那个runOnce。如果你发现你做了别的事情,继续,但嵌套 for 循环不应该需要它。

function onDraw()
  renderBlocks()
end

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...