9

I have a problem similar to this one: LUA and Corona error: Attempt To Call Method ' ' (A Nil Value) - Driving Me Crazy I have a TCell class:

local TCell={};
local cell_mt = { __index=TCell };
function TCell.new(_contents_name,_x,_y)
    ...
    local ncell=
    {
        ...
    };
    function ncell:setup()
        ...
    end
    ncell:setup();
    return setmetatable(ncell,cell_mt);
end
return TCell;

I have 2d array of TCell references called cells. When I assign

cells[ind1][ind2]=cells[ind3][ind4]

cells[ind1][ind2] begins to lose some properties. If I understood the link above correctly it's caused by losing the metatable association. Do I need to use setmetatable another time? How can I do it if the assignment is not done in the TCell body?

upd.

reset_metatable=function(target)
    return setmetatable(target,cell_mt);
end;
cells[ind1][ind2]=cells[ind3][ind4];
cells[ind1][ind2]=cells[ind1][ind2]:reset_metatable();

isn't really helpful. upd2: deleted all code not connected with camera. Camera and TCell have no enterframe. The problem seems to be in metatables. Output gives NOW 6 1 width i 50 and after it START NOW 6 1 width is nil

-----------------------------------------------------------------------------------------
--
-- Main Cycle
--
-----------------------------------------------------------------------------------------

local storyboard = require( "storyboard" )
local scene = storyboard.newScene()
-- include Corona's "physics" library
local physics = require "physics"
--control_circle=display.newImageRect(C.INTERFACE_DIR..C.INTERFACE_CONTROL_CIRCLE or C.EMPTY_IMAGE,C.CARS_W,C.CARS_W,true);
local events_added=false;

stage_frames=0;
physics.start(); physics.pause()
physics.setGravity( 0,0);

local PCar=require("TCar")
local PBiped=require("TBiped");
local PCell=require("TCell");

local control_circle_len;

local cells={};
local cells_w,cells_h;
local wshift,hshift=-(C.SCREEN_THEORETICAL_W-C.SCREEN_W)/2,-(C.SCREEN_THEORETICAL_H-C.SCREEN_H)/2;


--------------------------------------------

-- forward declarations and other locals


-----------------------------------------------------------------------------------------
-- BEGINNING OF YOUR IMPLEMENTATION
-- 
-- NOTE: Code outside of listener functions (below) will only be executed once,
--       unless storyboard.removeScene() is called.
-- 
-----------------------------------------------------------------------------------------
local wsells,hcells=(C.SCREEN_W-C.SCREEN_W%C.LANDSCAPE_CELL_W)/C.LANDSCAPE_CELL_W+1,(C.SCREEN_H-C.SCREEN_H%C.LANDSCAPE_CELL_H)/C.LANDSCAPE_CELL_H+1;

local dfd=false;
local function manage_cells(cmx,cmy)
    --print("#",cmx,cmy);
    if((cmx==0 and cmy==0) or dfd)
    then
        return;
    end
    local cells_shift_w,cells_shift_h=0,0;
    if(cmx>=0)
    then
        for i=cells_w,1,-1
        do
            if(cells[i][1]:out_of_borders_w()==true)
            then
                cells_shift_w=cells_shift_w+1;
            else
                break;
            end
        end
    else
        for i=1,cells_w,1
        do
            if(cells[i][1]:out_of_borders_w()==true)
            then
                cells_shift_w=cells_shift_w-1;
            else
                break;
            end
        end
    end
    if(cmy>=0)
    then
        for i=cells_h,1,-1
        do
            if(cells[1][i]:out_of_borders_h()==true)
            then
                --[[cells[1][i].contents.rotation=45;
                dfd=true;]]
                cells_shift_h=cells_shift_h+1;
            else
                break;
            end
        end
        --return;
    else
        for i=1,cells_h,1
        do
            if(cells[1][i]:out_of_borders_h()==true)
            then
                cells_shift_h=cells_shift_h-1;
            else
                break;
            end
        end
    end
    --print("~",cells_shift_w,cells_shift_h);
    local stx,finx,sty,finy=1,cells_shift_w,1,cells_shift_h;
    if(cmx<0)
    then
        stx=cells_w+cells_shift_w;
        finx=cells_w;
    end
    if(cmy<0)
    then
        sty=cells_h+cells_shift_h;
        finy=cells_h;
    end
    for i=stx,finx,1
    do
        for j=1,cells_h,1
        do
            if(cells[i][j])
            then
                cells[i][j]:destroy();
                cells[i][j]=nil;
            end
        end
    end
    for i=1,cells_w,1
    do
        for j=sty,finy,1
        do
            if(cells[i][j])
            then
                cells[i][j]:destroy();
                cells[i][j]=nil;
            end
        end
    end
    stx,finx,sty,finy=cells_w-cells_shift_w-1,1,cells_h-cells_shift_h-1,1;
    local itx,ity=-1,-1;
    if(cmx>=0)
    then
        stx=cells_shift_w+1;
        finx=cells_w;
        itx=1;
        print(stx,finx);
    end
    if(cmy>=0)
    then
        sty=cells_shift_h+1;
        finy=cells_h;
        ity=1;
    end


    for i=stx,finx,itx
    do
        for j=1,cells_h,1
        do
            if(cells_shift_w~=0)
            then

                if(j==1)
                then
                    print(i,1,"to",i-cells_shift_w,1);
                end
                cells[i-cells_shift_w][j]=cells[i][j];
                cells[i-cells_shift_w][j]=cells[i-cells_shift_w][j].reset_metatable(cells[i][j]);
                print("++",cells[i-cells_shift_w][j].contents.width);
                cells[i][j]:destroy();
                cells[i][j]=nil;
                if(j==1)
                then
                    print(i-cells_shift_w,1,"width is",cells[i-cells_shift_w][1].contents.width);
                    if(i==7)
                    then
                        cells[6][1].debug=true;
                        print("debug is set");
                    end
                end
            end
        end
    end
    for i=1,cells_w,1
    do
        for j=sty,finy,ity
        do
            if(cells_shift_h~=0)
            then
                print("?this?",i,j);
                cells[i][j-cells_shift_h]=cells[i][j];
                cells[i][j]:destroy();
                cells[i][j]=nil;
            end
        end
    end
    for i=1,cells_w,1
    do
        for j=1,cells_h,1
        do
            if(cells[i][j]==nil)
            then
                print("*new",i,j);
                cells[i][j]=PCell.new(C.LANDSCAPE_DICTIONARY(nil,1),(i-1)*C.LANDSCAPE_CELL_W+C.LANDSCAPE_CELL_W/2-wshift-camera:getX(),(j-1)*C.LANDSCAPE_CELL_H+C.LANDSCAPE_CELL_H/2-hshift-camera:getY());
            end
        end
    end

end
local function stage_main_frame()
    print("START NOW",6,1,"width is",cells[6][1].contents.width);
    local old_camera_x,old_camera_y=camera._view.x,camera._view.y;
    if(dfd==false)
    then
        --print("&");
        camera._view.x=camera._view.x-stage_frames;
    end
    local cmx,cmy=-(camera:getX()-old_camera_x),-(camera:getY()-old_camera_y);
    manage_cells(cmx,cmy);


    stage_frames=stage_frames+1;
    print("NOW",6,1,"width is",cells[6][1].contents.width);
    return function(event)
    end

end
-- Called when the scene's view does not exist:
function scene:createScene( event )
    local group = self.view
end

-- Called immediately after scene has moved onscreen:
function control_player(event)
    car1:get_touch(event);
end
function scene:enterScene( event )
    camera:newLayer("land",1);
    camera:newLayer("bipeds",1);
    camera:newLayer("cars",1);

    i=1;
    while((i-1)*C.LANDSCAPE_CELL_W-C.LANDSCAPE_CELL_W/2-wshift<=C.SCREEN_W)
    do
        j=1;
        cells[i]={};
        while((j-1)*C.LANDSCAPE_CELL_H-C.LANDSCAPE_CELL_H/2-hshift<=C.SCREEN_H)
        do
            cells[i][j]=PCell.new(C.LANDSCAPE_DICTIONARY(nil,1),(i-1)*C.LANDSCAPE_CELL_W+C.LANDSCAPE_CELL_W/2-wshift-camera:getX(),(j-1)*C.LANDSCAPE_CELL_H+C.LANDSCAPE_CELL_H/2-hshift-camera:getY());
            j=j+1;
        end
        i=i+1;
    end
    cells_w,cells_h=#cells,#cells[1];
    local group = self.view
    physics.start();
    physics.setPositionIterations( 1 )
    if(events_added==false)
    then
        events_added=true;
        Runtime:addEventListener("touch",control_player);
        Runtime:addEventListener("enterFrame",stage_main_frame);
    end
end

-- Called when scene is about to move offscreen:
function scene:exitScene( event )
    local group = self.view

    physics.stop()

end

-- If scene's view is removed, scene:destroyScene() will be called just prior to:
function scene:destroyScene( event )
    local group = self.view

    package.loaded[physics] = nil
    physics = nil
end

-----------------------------------------------------------------------------------------
-- END OF YOUR IMPLEMENTATION
-----------------------------------------------------------------------------------------

-- "createScene" event is dispatched if scene's view does not exist
scene:addEventListener( "createScene", scene )

-- "enterScene" event is dispatched whenever scene transition has finished
scene:addEventListener( "enterScene", scene )

-- "exitScene" event is dispatched whenever before next scene's transition begins
scene:addEventListener( "exitScene", scene )

-- "destroyScene" event is dispatched before view is unloaded, which can be
-- automatically unloaded in low memory situations, or explicitly via a call to
-- storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( "destroyScene", scene )

-----------------------------------------------------------------------------------------

return scene

.

local TCell={};
local cell_mt = { __index=TCell };
function TCell.new(_contents_name,_x,_y)
    --print(camera.x);
    if(_x==nil)
    then
        _x=0;
    end
    if(_y==nil)
    then
        _y=0;
    end
    camera:newLayer( "abacaba", 1 );
    local ncell=
    {
        contents_name=_contents_name;
        contents;
        sequence_data;
        sheet_data;

        debug=false;
        --[[main_frame;
        main_frame_handler=function(self)
            main_frame=function(event)
                if(self.contents.x+self.contents.width/2<0 or self.contents.y+self.contents.height/2<0 or self.contents.x-self.contents.width/2>C.SCREEN_W or self.contents.y-self.contents.height/2>C.SCREEN_H)
                then
                    --self:destroy();
                end
            end
            return main_frame;
        end;]]
        clear=function(self)
            if(self.debug==true)
            then
                print("CLEAR!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n\n\n");
            end
            --print(self.contents);
            self.contents:removeSelf();
            camera:removeObject("land",self.contents);
        end;
        show=function(self,_contents_name,__x,__y)
            if(self.debug==true)
            then
                print("SHOW!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n\n\n");
            end
            self.contents_name=_contents_name;
            if(self.contents_name~=C.EMPTY_IMAGE)
            then
                self:set_sequence_data();
            end
            if(self.contents_name~=C.EMPTY_IMAGE)
            then
                self.sheet_data=graphics.newImageSheet(self.contents_name,C.LANDSCAPE_SHEET_DATA);
                self.contents=display.newSprite(self.sheet_data,self.sequence_data);
            else
                self.contents=display.newImageRect(C.EMPTY_IMAGE,C.LANDSCAPE_CELL_W,C.LANDSCAPE_CELL_H,true);
                self.sequence_data=nil;
            end
            self.contents.x=__x;
            self.contents.y=__y;
            camera:addObject("land",self.contents);
        end;
        out_of_borders_w=function(self)
            --print(self.contents.width);
            return self.contents.x+self.contents.width/2-camera:getX()<C.LANDSCAPE_CELLS_LEFT_BORDER-C.LANDSCAPE_CELL_W or 
                self.contents.x-self.contents.width/2-camera:getX()>C.LANDSCAPE_CELLS_RIGHT_BORDER+C.LANDSCAPE_CELL_W;
        end;
        out_of_borders_h=function(self)
            return self.contents.y+self.contents.height/2-camera:getY()<C.LANDSCAPE_CELLS_UPPER_BORDER-C.LANDSCAPE_CELL_H or 
                self.contents.y-self.contents.height/2-camera:getY()>C.LANDSCAPE_CELLS_LOWER_BORDER+C.LANDSCAPE_CELL_H;
        end;
        reset_metatable=function(target)
            return setmetatable(target,cell_mt);
        end;
        set_sequence_data=function(self)
            local px=math.floor(((_x)%C.LANDSCAPE_SHEET_DATA.sheetContentWidth)/C.LANDSCAPE_SHEET_DATA.width)+1;
            local py=math.floor(((_y)%C.LANDSCAPE_SHEET_DATA.sheetContentHeight)/C.LANDSCAPE_SHEET_DATA.height)+1;
            self.sequence_data=
            {
                { name = "only", start=C.LANDSCAPE_SHEET_DATA.sheetContentWidth/C.LANDSCAPE_SHEET_DATA.width*(py-1)+px, count=1 }
            };
        end;

        destroy=function(self)
            --Runtime:removeEventListener("enterFrame",self.main_frame);
            --Runtime:removeEventListener("enterFrame",self.main_frame_handler);

            self:clear();
            if(index~=nil)
            then
                --destroy_cell(index);
            end
        end
    };
    function ncell:setup()
        self:show(self.contents_name,_x,_y);
    end
    ncell:setup();
    return setmetatable(ncell,cell_mt);
end
return TCell;
Community
  • 1
  • 1
user2136963
  • 2,310
  • 2
  • 18
  • 38
  • 2
    There is mismatched `[` – hjpotter92 Mar 30 '13 at 11:18
  • Corrected. It's an example. The code looks like: cells[i-cells_shift_w][j]=cells[i][j]; – user2136963 Mar 30 '13 at 12:45
  • Are you sure that `i-cells_shift_w`, `i` and `j` always point to valid keys? – Martin Ender Mar 30 '13 at 15:14
  • @m.buettner When I test cells_shift_w is 1. When I track cells[6][1], cells[6][1].contents.width is 50 at the end of enterframe. At the beginnig of the next enterframe cells[6][1].contents.width is nil but cells[6][1].contents is not nil. I don't know what happens between because I write in Programmers Notepad. – user2136963 Mar 30 '13 at 15:21
  • Then how do you know it's the assignment that messes things up? – Martin Ender Mar 30 '13 at 15:45
  • @m.buettner Because assignment in this way messes things up: http://stackoverflow.com/questions/15560813/lua-and-corona-error-attempt-to-call-method-a-nil-value-driving-me-craz Probably, I'd better find a debugger to prevent other bugs. – user2136963 Mar 30 '13 at 15:59
  • @user2136963 that's a different case. in that question the value that is assigned is a new table, which doesn't have the same metatable. in your case you are assigning `TCell`s to `TCell`s, all of which have a metatable (at least if you create them with your `new` function). It's not like the metatable is generally lost in assignments. – Martin Ender Mar 30 '13 at 16:03
  • @m.buettner cells[ind1][ind2] is made nil before this. Is there a solution if the problem is in loosing metatable? – user2136963 Mar 30 '13 at 17:20
  • @user2136963 I think you should provide some more code in the question. Just a single line where you think the problem might be makes it hard to actually analyse the problem. You could also try commenting out different lines to see what actually causes the loss the metatable. (btw are you sure, that the metatable is actually lost? "... begins to lose some properties" is all pretty vague – Martin Ender Mar 30 '13 at 17:24
  • `cells[ind1][ind2]=cells[ind1][ind2]:reset_metatable();` you are setting it to `setmetatable` return value. Was that the intent? – Bartek Banachewicz Apr 11 '13 at 12:14
  • can you point at which line you get the error ? – Doğancan Arabacı Apr 12 '13 at 07:37
  • (TCell reference (cells[ind1][ind2]) ).contents.width becomes nil after assignment. Added everything to http://www.filedropper.com/zzz – user2136963 Apr 13 '13 at 14:12

1 Answers1

1

I believe you may misunderstanding variable assignment in Lua. All variables are actually references/pointers to objects. When you write:

cells[ind1][ind2]=cells[ind3][ind4]

you are throwing away (removing a reference to) the object that was pointed to by cells[ind1][ind2], and you create a second reference to the object pointed to by cells[ind3][ind4].

If you put some stuff (like the properties you think are disappearing) in cells[ind1][ind2] before the assignment, it won't be there after the assignment because that variable is now pointing at a different object.

Doub
  • 1,152
  • 1
  • 7
  • 13