Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Advise me, please. zLevel does odd things.

in Questions Posts: 1,089

I have a function that draws a bunch of objects. Looks like this:

function DungeonContentsCollection:draw()
    pushMatrix()
    pushStyle()
    for tile,entries in pairs(self:drawingOrder()) do
        if tile:isVisible() then
            local gc = tile:graphicCenter()
            for i,object in ipairs(entries) do
                zLevel(5) -- breaks visibility??
                spriteMode(CENTER)
                object:draw(false, gc)
            end
        end
    end
    popStyle()
    popMatrix()
end

When the zLevel is in there, objects drawn in the loop sometimes show up and sometimes do not, depending on how the Player moves around near them. There is no obvious pattern, but it seems that if it ever appears while player is on a given tile, it will always appear, and vice versa. So it's not random with moves, but dependent on where you move.

There is no other call to zLevel in the whole program.

I can do without the call, because I am (finally) drawing in increasing z-level order, but what the heck could possibly be going on that could do this? Unless zLevel is well and truly borked?

Ideas solicited. Thanks!

Comments

  • Posts: 1,285

    @RonJeffries okay I'm a little bit majorly out of my depth here, but I do know that the draw() function has some pecadilloes when it comes to combining 2D concepts and 3D concepts, and if I remember correctly it actually renders one before the other, so if you call something that requires 3D rendering (which I guess would be mesh rendering?) at the wrong time, it won't interact properly with your 2D renders. Maybe partial and badly-remembered information is worse than no information at all, but at least it may be a hint that the anatomy of a draw cycle is not as straightforward as it might seem....

  • Posts: 1,089

    this is all 2d, sprites mostly.

  • Posts: 1,089

    i don't see how it could be. i think zlevel is screwy somehow

  • Posts: 172

    maybe try putting your pop and push inside the for loop

  • dave1707dave1707 Mod
    Posts: 9,432

    @RonJeffries Is this something like what you’re running into. Move the ship slider so the space ship overlays the other objects. The ship has the yellow square around it covering up the other 2. If you slide the others one around, those don’t have the square background.

    Then uncomment the second setup and draw code. I reversed the ship and ufo. Now the ufo has the square background covering the others as you slide the parameter and the others don’t. So I’m not sure what’s causing this.

    function setup()
        img = {}
        img[1] = readImage(asset.builtin.Space_Art.Red_Ship)
        img[2] = readImage(asset.builtin.Space_Art.Asteroid_Large)
        img[3] = readImage(asset.builtin.Space_Art.UFO)
        parameter.integer("ship", -10, 10, -3)
        parameter.integer("asteroid", -10, 10, 0)
        parameter.integer("ufo", -10, 10, 3)
        rectMode(CENTER)
    end
    
    function draw()
        background(255, 230, 0,0)
        translate(WIDTH/2, HEIGHT/2)
        zLevel(0)
        z = 0 -- Keep track of z level
        fill(37, 235, 22)
        imgZ = {ship, asteroid, ufo}
        scale(3, 3)
        for i = 1, #img do
            local dz = imgZ[i] - z
            zLevel(dz)
            z = z + dz -- Keep track of z level
            sprite(img[i], i * 20 - 40, 0)
        end
    end
    
    --[[
    function setup()
        img = {}
        img[1] = readImage(asset.builtin.Space_Art.UFO)
        img[2] = readImage(asset.builtin.Space_Art.Asteroid_Large)
        img[3] = readImage(asset.builtin.Space_Art.Red_Ship)
        parameter.integer("ufo", -10, 10, -3)
        parameter.integer("asteroid", -10, 10, 0)
        parameter.integer("ship", -10, 10, 3)
        rectMode(CENTER)
    end
    
    function draw()
        background(255, 230, 0,0)
        translate(WIDTH/2, HEIGHT/2)
        zLevel(0)
        z = 0 -- Keep track of z level
        fill(37, 235, 22)
        imgZ = {ufo, asteroid, ship}
        scale(3, 3)
        for i = 1, #img do
            local dz = imgZ[i] - z
            zLevel(dz)
            z = z + dz -- Keep track of z level
            sprite(img[i], i * 20 - 40, 0)
        end
    end
    --]]
    
  • Posts: 1,089

    hi dave ... mine is not a coverage thing. objects disappear when there's nothing near them. and it's the only zlevel call anywhere.

  • Posts: 1,089

    @skar can't hurt, might try it.

  • Posts: 1,089

    @skar push pop changes it but weirdly. i find that setting zlevel in lots of places an make it work, but so does setting it nowhere,

    @Simeon are you sure zlevel is saved / restored properly by push/popmatrix? this almost looks like it's sticky, or additive or something.

    not urgent: i'm just curious to figure out how a single zlevel call could make things appear/disappear when nothing else is near them.

  • edited June 10 Posts: 2,363
    Hi all,
    Off the wall a bit but could this be related to blending mode, something in the depths of my cranium says I've seen something similar - but, as usual I can't find it.
  • Posts: 1,089

    not doing anything with blending mode.

  • dave1707dave1707 Mod
    Posts: 9,432

    @RonJeffries I was playing around with the below code similar to yours above. What I see is that zLevel looks like it’s additive. Each time thru the loop, the value for zLevel gets added to itself. Once the zLevel is above 10 or below -10, anything drawn at the level disappears. Slide the level slider and watch the tot value that is displayed. When a tot value corresponding to a zLevel vale exceeds 10 or below -10 that draw doesn’t show.

    function setup()
        fill(255)
        parameter.integer("level",-11,11,0)
        tab={   asset.builtin.Space_Art.UFO,
                asset.builtin.Space_Art.Red_Ship,
                asset.builtin.Space_Art.Asteroid_Large,
                asset.builtin.Space_Art.Icon
            }
    end
    
    function draw()
        background(0)
        tot=0
        for a,b in pairs(tab) do
            zLevel(level)
            sprite(b,WIDTH/2+a*50,HEIGHT/2)
            tot=tot+level
            text(tot,WIDTH/2,HEIGHT-100-a*20)
        end
    end
    
  • dave1707dave1707 Mod
    edited June 10 Posts: 9,432

    @RonJeffries Apparently you can control the zLevel by subtracting the value in the loop.
    So you can subtract values to keep sprites from disappearing.

    function setup()
        fill(255)
        parameter.integer("level",-11,11,0)
        tab={   asset.builtin.Space_Art.UFO,
            asset.builtin.Space_Art.Red_Ship,
            asset.builtin.Space_Art.Asteroid_Large,
            asset.builtin.Space_Art.Icon
        }
    end
    
    function draw()
        background(0)
        for a,b in pairs(tab) do
            zLevel(level)
            sprite(b,WIDTH/2+a*50,HEIGHT/2)
            zLevel(-level)
        end
    end
    
  • edited June 10 Posts: 1,089

    You're right, zLevel adds rather than setting. i think this version of your demo shows it better.

    @Simeon i think this is a clear bug: subsequent calls to zLevel add to the level rather than replace it.

    well spotted, @dave1707 !

    function setup()
        fill(255)
        parameter.integer("level",-11,11,0)
        tab={   asset.builtin.Space_Art.UFO,
            asset.builtin.Space_Art.Red_Ship,
            asset.builtin.Space_Art.Asteroid_Large,
            asset.builtin.Space_Art.Icon
        }
    end
    
    function draw()
        background(0)
        tot=0
        pushMatrix()
        for a,b in pairs(tab) do
            zLevel(level)
            --sprite(b,WIDTH/2+a*50,HEIGHT/2)
            text(""..a, WIDTH/2+a*50, HEIGHT/2)
            tot=tot+level
            text(tot,WIDTH/2,HEIGHT-100-a*20)
        end
        popMatrix()
    end
    
    
    
  • Posts: 1,089

    yes, the subtract should work. still a bug.

  • Posts: 1,089

    i can imagine concern that fixing this bug would break things, but i think that's unlikely. if i were to use it now i'd be like:

    zLevel(n)
    draw ...
    zLevel(-n)
    zLevel(0)
    

    that should work, and would survive the correction.

  • edited June 11 Posts: 2,363
    @RonJeffries @Simeon - wouldn't it be better to make it more explicit by adding z-level to the sprite command. Are vector drawings also z-level dependent, if so you could retain z-level as a command to specify it. Also, if you can specify z-level you could add it to setContext() call to restrict output.
  • dave1707dave1707 Mod
    Posts: 9,432

    @RonJeffries The zLevel(0) you show above doesn’t do anything. It just adds 0 to whatever value zLevel currently is. It seems like zLevel is 0 when draw starts and changes by whatever value you set zLevel to until you exit draw. That means any functions called from within draw that use zLevel will add to or subtract from the zLevel value.

  • dave1707dave1707 Mod
    Posts: 9,432

    @RonJeffries You can use a function like the one below to set your zlevel values. Put currZlevel=0 at the beginning of draw() and then call setZlevel(zLevel) any time you want to change the zLevel. It determines what value it needs to add or subtract so you get the correct zLevel. I haven’t tried it, but I think it should work.

    function setZlevel(z)
        zLevel(z-currZlevel)
        currZlevel=z
    end
    
  • dave1707dave1707 Mod
    Posts: 9,432

    @RonJeffries Heres an example using the above function. One thing I saw when using it was anytime a zLevel used a negative value, the background of the current sprite would show over the next sprite. I was able to solve that problem by putting the desired zLevel in a table with the image and sorting on zLevel so the images were drawn from low to high.

    viewer.mode=FULLSCREEN
    
    function setup()
        fill(255)
        tab={
            {img=asset.builtin.Space_Art.UFO,lev=10},
            {img=asset.builtin.SpaceCute.Health_Heart,lev=-3},
            {img=asset.builtin.Space_Art.Asteroid_Large,lev=7},
            {img=asset.builtin.Space_Art.Red_Ship,lev=4},
            {img=asset.builtin.Planet_Cute.Character_Horn_Girl,lev=-5},
            }
        sort(tab)
    end
    
    function draw()
        background(92, 89, 32)
        currZlevel=0
        for z=1,#tab do
            setZlevel(tab[z].lev)
            text(currZlevel,WIDTH/6+100*z,HEIGHT/2+150)
            sprite(tab[z].img,WIDTH/6+100*z,HEIGHT/2,200)
        end
    end
    
    function setZlevel(z)
        zLevel(z-currZlevel)
        currZlevel=z
    end
    
    function sort(tbl) 
        table.sort(tbl,
        function(a,b)
            if a.lev<b.lev then
                return true
            end
            return false
        end)
    end
    
  • Posts: 1,089

    The reason for the zLevel(0) is that the code works if the bug gets fixed, guaranteeing that zLevel is always 0 after use.

    Yes, sorting in z order works, that's what I'm currently doing.

    Thanks!

Sign In or Register to comment.