0

3D 配列またはテーブルのサイズを動的に変更することを目的とした関数がありますが、範囲外であるため値 nil を返すと言って中断し続けます。そのコードは次のとおりです。

function resize()       
    temp = { }
    for h=1, height do
        table.insert( temp , { } )
        for y=1, length do
            table.insert ( temp[h], { } )
            for x=1, width do
                num = 16                
                if #blocks <= height then
                    if #blocks[h] <= length then
                        if #blocks[h][y] <= width then
                            num = blocks[h][y][x]
                        end
                    end
                end         
                table.insert( temp[h][y] , num )
            end
        end
    end 
    blocks = temp
end

あまりコメントされていないことは知っていますが、ディメンションが変更された新しいテーブルを作成し、ブロックのデータを新しいテーブルに重ね合わせ、最後にブロックを新しい一時テーブルで上書きするという考えです。

長さ、幅、高さは、1 ずつ増加または減少しますが、一度に 1 つだけ変更されます。

十分に明確に説明したかどうかわかりませんが、そうでない場合はお知らせください。詳しく説明します。

ありがとう、ジェームズ

4

3 に答える 3

1

あなたの特定のエラー(おそらく)

nil 値に対してテストしません。初期化されていないテーブル (= この場合は配列) のメンバーはすべてnil、定義によるものです。また、数値と比較するnilとエラーが発生します。

lua: attempt to compare nil with number

ただし、実際のエラー メッセージを提供できないようですので、これは推測に過ぎません。これらはあなたのコードのエラーだと誤解しないでください。とにかく、何が起こるかを示すために、コードとともにいくつかのコメントがあります

if #blocks <= height then              -- say #blocks is 3, height is 4
    if #blocks[h] <= length then       -- E: in iteration 4 blocks[h] is nil
        if #blocks[h][y] <= width then -- E: in it. 3,4 blocks[h][y] is nil
            num = blocks[h][y][x]
        end
    end
end

次のように、最初にすべてのレベルで nil に対してテストする必要があります

if blocks[h] and blocks[h][y] and blocks[h][y][x] and
       #blocks[h]<=height and #blocks[h][y]<=height and #blocks[h][y][x]<=height
    num = blocks[h][y][x]
end

一般的なプログラミングの間違い

blockslengthwidthおよびheightは関数のパラメーターのようですが、ヘッダーにはありません。関数を呼び出す前に外部で設定したと思いますか? これは確かに良い習慣ではありません。

tempnum宣言する必要がありますlocal

たとえば、3D配列をフラット化されたテーブルに入れて、__callこのようなメタメソッドを追加すると、データ構造をよりインテリジェントにすることができます

function newMdArray(X, Y, Z)
    local MT = { __call = function(t, x, y, z, v)
        if x>X or y>Y or z>Z or x<1 or y<1 or z<1 then return nil end
        local k = x + X*(y-1) + X*Y*(z-1);
        if v ~= nil then t[k] = v; end
        return t[k]
    end };
    return setmetatable({}, MT);
end

次に、サイズ変更されたコピーを作成するために必要なことは次のとおりです。

function resizeMdArray(array, X, Y, Z)
    local r = newMdArray(X, Y, Z);
    for x=1, X do
        for y=1, Y do
            for z=1, Z do
                r(x, y, z, array(x, y, z) or 16);
            end
        end
    end
    return r;
end

おまけとして、このデータ構造は 3D 配列を 1D 配列にフラット化するため、データをコピーするだけの場合は、テーブルとしてアクセスして各要素をコピーするだけでコピーできます。

for i=1, X*Y*Z do
    new[i] = old[i]
end

もちろん、バックグラウンドで「実際の」(隠された) 3 次元配列を使用してまったく同じことを行い、算術計算を節約することもできますが、nil エラーを防ぐために常に空の値をテストする必要があります。

于 2013-06-05T14:15:33.207 に答える
1

バグは if ステートメントにあると思います。高さ、長さ、幅ではなく、h、y、x に対するブロックのサイズを指定する必要があります。

補足として、temp[h] = {} で置き換えることができる場合は、table.insert を使用しないでください。それはより速いです。また、一時ストレージには locals を使用してみてください。

于 2013-06-04T20:59:01.490 に答える
0

これが最善の方法かどうかはわかりませんが、うまくいきます。

function resize()       
temp = { } -- temp table

-- inserting all the height levels
for h=1, height do table.insert( temp , { } ) end

-- inserting all the lengths
for h=1, height do
    for l=1, length do table.insert( temp[h], { } ) end
end

-- inserting all the width and defaulting them to 0
for h=1, height do
    for l=1, length do
        for w=1, width do table.insert( temp[h][l] , 0 ) end
    end
end

-- if the canvas size is increasing
if #blocks <= height then
    if #blocks[1] <= length then
        if #blocks[1][1] <= width then
            for h=1, #blocks do
                for l=1, #blocks[1] do
                    for w=1, #blocks[1][1] do
                        -- fill in data from blocks
                        temp[h][l][w] = blocks[h][l][w]
                    end
                end
            end
        end
    end
end

--if the canvas size is decreasing
if #blocks >= height then
    if #blocks[1] >= length then
        if #blocks[1][1] >= width then
            for h=1, #temp do
                for l=1, #temp[1] do
                    for w=1, #temp[1][1] do
                        -- fill in data from blocks but not the last value
                        temp[h][l][w] = blocks[h][l][w]
                    end
                end
            end
        end
    end
end

-- overwrite blocks with the new dimensions
blocks = temp
于 2013-06-05T06:02:40.453 に答える