flicker drawing large images - any advice?

So - I’m kinda stumped, and am hoping that someone has seen and solved this problem.

I’m trying to make a scrolling starfield for a space game I’m working on - to give the impression of movement, your ship stays centered on the screen (top-down view), and the stars scroll by as you move.

My initial implementation of this is to make a screen-sized image, fill it with a few hundred random white dots, and do 4 sprite() calls to tile it on the screen based on the player’s x,y coordinates. I hope that explanation makes sense.

Problem is, when I do that I get very dim, flickery stars - they’re nice and steady if you are stopped, but moving, they fade to practically nothing.

I’ve tried removing the “background(0,0,0,0)” call at the beginning of the draw() loop, if anything it makes it worse.

I’ve also tried one big image, or even small - still dim, so it doesn’t appear to be time drawing sprites (which I didn’t expect anyway).

I have yet to experiment with mesh() or modifying the page switching; I can’t believe mesh will be much faster than one image() draw, even a big one (it seems to run at a fine frame rate, but I’ve not measured it), and I kinda don’t want to mess with page switching because I suspect it’ll mess with the stuff I want to draw on top of the starfield…

Open to suggestions and sample code if anyone has got a scrolling background working… (It may be a side effect of teensy white dots on a largely black screen, to be frank… I’ll experiment with larger dots next…)

if I double the size of the stars (2x2 pixels), they retain their brightness, but blur. It’s not what I was hoping for (I’m trying for a nice rock-steady scroll), but I think it’ll work for the project.

I think 1 pixel stars will appear to flicker due to the LCD. The old windows stars screensaver has the same effect.

The 2x2 pixel stars blur? Even with noSmooth()? Is this just an effect of the screen or is it actually a problem when paused?

I think I posted this for you before. The flicker here is deliberate.



function setup()
    stars = {}
    numstars = 1000
    local x,y
    for i = 1,numstars do
        x = math.random(-WIDTH,2*WIDTH)
        y = math.random(-HEIGHT,2*HEIGHT)
        z = math.random(10,100)
        table.insert(stars,{x,y,z})
    end
    v = vec2(0,0)
    l = 30
    p = vec2(l,0)
    o = vec2(WIDTH/2,HEIGHT/2)
    tolerence = 25
    M = 100
    dM = 5
    G = 100000
    mu = 0
    ds = 0
end

function draw()
    background(0, 0, 0)
    noStroke()
    fill(255, 255, 255, 255)
    rectMode(CENTER)
    translate(o.x,o.y)
    if CurrentTouch then
        local pp = vec2(-p.y,p.x)/p:len()
        local d = vec2(CurrentTouch.x,CurrentTouch.y)
        d = d - o
        debuga = math.atan2(d.x,d.y)
        local dd = vec2(CurrentTouch.deltaX,CurrentTouch.deltaY)
        if dd:lenSqr() < tolerence and CurrentTouch.state ~= ENDED then
            ds = ds + DeltaTime
        else
            ds = ds - DeltaTime
        end
        if d:lenSqr() > tolerence then
            local a = G * M * d:dot(pp) / (d - p):len()^3
            
            a = a - mu * v:len() * v:dot(pp)
            v = v + a * DeltaTime * pp
            p = p + v * DeltaTime
            p = p/p:len() * l
        end
    end
    for i=1,numstars do
        stars[i][1] = (stars[i][1] - math.exp(ds)*p.x/stars[i][3] + WIDTH)%(3*WIDTH) - WIDTH
        stars[i][2] = (stars[i][2] - math.exp(ds)*p.y/stars[i][3] + HEIGHT)%(3*HEIGHT) - HEIGHT
        local r = math.random(1,3)
        rect(stars[i][1],stars[i][2],r,r)
    end
    local ang = math.atan2(p.x,p.y)
    debug = ang
    rotate(180-ang/math.pi * 180)
    spriteMode(CENTER)
    sprite("Tyrian Remastered:Boss D")
end

Oh yeah i just found this in my projects, its awesome.

@Simeon - No - the 2x2 ones look better. And - the single pixel ones look fine if the background isn’t in motion. As soon as I move it, they get very dim, and blur or stretch in the direction of motion.

it’s almost like a single pixel has to be there longer than the time between calls to draw() to fully “power up” - and I’m moving them every frame. Hmm. I should try moving things every 2 or 3 frames, see if it looks different.

Perhaps later. The 2x2 stars still look good, for now. What I really want is to import a nice photo image of stars, but one big enough to look good tiled is big, and there’s no good way to get it in other than to hack it in, and this is something I’m hoping to share. We really need some way to import and share graphics assets. I might eventually do something procedural that looks nice, but not enough time right now (I’m hoping to have something for the Codea Player, but between this and my work schedule, I’m not likely to have something showable in a week…)

I spent a few minutes writing a bit of code to draw a reasonably nice star field. Hopefully you find this useful. I think it could be tweaked a lot, as this was the first time I played the project after writing the code.

supportedOrientations(LANDSCAPE_ANY)

-- You could move these to their own utility file
function starImage(s)
    local s2 = s/2    
    local i = image(s,s)
    
    setContext(i)
    
    pushStyle()
    
    for i = 1,6 do
        fill( 240, 245, 255, i*10 )
        ellipse( s2, s2, (s-1) / i )
    end

    fill(255)
    ellipse( s2, s2, 3 )
    
    popStyle()
    
    setContext()
    
    return i
end
    
function blend(c1, c2, a)
    return color(c1.r * a + c2.r * (1-a),
                 c1.g * a + c2.g * (1-a),
                 c1.b * a + c2.b * (1-a),
                 c1.a)
end

-- Use this function to perform your initial setup
function setup()
    local gradSize = 32
    grad = image(gradSize,gradSize)
    
    local toColor = color(29, 27, 38, 255)
    local fromColor = color(39, 58, 103, 255)
    
    -- Make a gradient
    local c = nil
    for i = 1,gradSize do
        for x = 1,gradSize do
            local a = i/gradSize            
            c = blend( fromColor, toColor, a )
            
            grad:set(x, i, c)
        end
    end
    
    starMesh = mesh()
    starMesh.texture = starImage(32)
    
    for i = 1,100 do
        local x = math.random(WIDTH)
        local y = math.random(HEIGHT)
        local s = math.random(8, 32)
        local idx = starMesh:addRect(x, y, s, s)
        local o = math.random(40,255)
        starMesh:setRectColor( idx, color(255,255,255,o) )
    end
end

-- This function gets called once every frame
function draw()
    smooth()
    
    -- Gradient background
    sprite( grad, WIDTH/2, HEIGHT/2, 
                  WIDTH+20, HEIGHT+20 )

    -- Do your drawing here
    starMesh:draw()    
end

Stars

Edit: Just tried Andrew’s. His is awesome.

Just realized I missed a good question…

@Simeon - yes, it is even dim paused. So - it can’t be a “too fast” kind of thing. When Codea is paused, is it still flipping pages?

Thank you both for the code - I’ll try them out.