Need help creating a vertical parallax starfield

Hi all,

Taking my first baby steps in writing a game. I’ve never coded anything other than stuff that attaches to a database and gets used in an office, so it’s a little daunting. Please bear with (or just ignore) the potential barrage of early questions…

So my project to help me learn will be a simple vertical shooter and I’d really like a scrolling parallax starfield as the background.

Problem is, I have no clue where to even start, could someone help me along the way?

Something a bit like this…

https://youtu.be/x01V2hO1FBk

@RaggedTooth - funnily enough I have just been looking at starfields. Not the vertical type more the Star Trek 3D type. I’ll check through to see if I have any examples for you - the ones I have may work for you - you just need to change the direction and maintain the star size.

Thank you. I see some posts mentioning an example game Bit Invader as a starting point and the wiki mentions it as a built in example.

But unless I’m missing something I can!t see it in the latest version or find it on the web…

@RaggedTooth Here’s something I just threw together.

displayMode(FULLSCREEN)

function setup()
    tab={}
    for z=1,300 do  -- number of stars
        x=math.random(WIDTH)
        y=math.random(HEIGHT)
        s=math.random(8)    -- size
        sp=math.random(3)   -- speed
        c=color(math.random(255),math.random(255),math.random(255))
        table.insert(tab,{x=x,y=y,s=s,sp=sp,c=c})
    end   
end

function draw()
    background(0)
    for a,b in pairs(tab) do
        fill(b.c)
        ellipse(b.x,b.y,b.s)
        b.y=b.y-b.sp
        if b.y<-10 then
            b.y=HEIGHT+20
        end
    end
end

@Bri_G Can you use this.

displayMode(FULLSCREEN)

function setup()
    col={color(0, 12, 255, 255),        color(107, 145, 171, 255),
         color(255, 243, 0, 255),       color(168, 169, 97, 255),
         color(255, 255, 255, 255),     color(255, 150, 0, 255),
         color(255, 0, 13, 255)}
    nbrStars=300
    st={}
    for z=1,nbrStars do
        c=math.random(7)    -- colored stars
        --c=5 -- white stars
        table.insert(st,vec4(math.random(WIDTH),math.random(HEIGHT),1,c))
    end
    speed=75
end

function draw()
    background(40, 40, 50)
    for a,b in pairs(st) do
        fill(col[b.w])
        ellipse(b.x,b.y,b.z)
        xd=WIDTH/2-b.x
        if xd<.02 and xd>-.02 then
            xd=.1
        end
        yd=HEIGHT/2-b.y
        if yd<.05 and yd>-.05 then
            yd=.1
        end
        b.x=b.x-xd/speed
        b.y=b.y-yd/speed    
        b.z=b.z+.1
        if b.x<0 or b.x>WIDTH or b.y<0 or b.y>HEIGHT then
            st[a].x=math.random(WIDTH)
            st[a].y=math.random(HEIGHT)
            st[a].z=1
        end
    end
end

@RaggedTooth oh, here’s the Bit Invader example code

You should be able to open the zip straight in Codea and choose to import the project

Wow, thank you. That’s a great start.

I clearly need to learn about tables, I can see what the For loop in the draw is doing, but don’t understand the pairs syntax for the loop declaration.

@dave1707 - thanks for the code, better than the code I was working on more adaptable to what I’m trying to do. Update later. Thanks.

@RaggedTooth Do you mean the “for a,b in pairs(st) do”-part?
If so, you have two variables a and b. Let’s say you have a table that stores 5 values:

myTable = {0, 3, 5, 7, 9}

The variable “a” is a count variable. So doing:

for a, b in pairs(myTable) do print(a) end

Will give you the values from 1 to 5. In the first iteration of the loop, “a” takes on the value 1. In the second one, “a” will be equal to 2 and so on.

The other variable, “b”, takes on what is stored in the table at that specific position in the table. So when you type in:

for a, b in pairs(myTable) do print(b) end

It will print out the values 0, 3, 5, 7 and 9. So in the first iteration of the loop, b takes on the value 0. In the second iteration, it will be 3 and so on.

The code-snippets above store a vec4 in the table. So e.g. the line ellipse(b.x,b.y,b.z) means that you take the x, y and z values of the vec4 that is currently stored in b.
I hope that was helpful :slight_smile:

Can I participate?

displayMode(FULLSCREEN)

function setup()
    stars = {}
    --speed = 10
    
    bg = mesh()
    bg.shader = shader("Filters:Radial Blur")
    bg.shader.sampleDist = 1
    bg.shader.sampleStrength = 2.2
    
    r = bg:addRect(0, 0, 0, 0)
    
    img = image(WIDTH, HEIGHT)
    parameter.number("speed", 1, 10, 5)
    
    for i = 1, 100 do
        table.insert(stars, star())
    end
end

function draw()
    --background(0)
    updateImage()
    bg.texture = img
    bg:setRect(r, WIDTH*.5, HEIGHT*.5, WIDTH, HEIGHT)
    bg:draw()
    --sprite(img, WIDTH*.5, HEIGHT*.5)
end

function updateImage()
    setContext(img)
    background(33, 33, 52, 255)
    
    local remove = {}
    for i, s in ipairs(stars) do
        
        local m = (s.y - HEIGHT*.5) / (s.x - WIDTH*.5)
        local d = math.sqrt( (s.y - HEIGHT*.5) ^ 2 + (s.x - WIDTH*.5) ^ 2 )
        local isBug = d < 10 or math.abs(s.y - HEIGHT*.5) < 10 or math.abs(s.x - WIDTH*.5) < 10
        
        local newX = s.x + speed * sign(s.y - HEIGHT*.5) * sign (m) * (d / 100) / s.distance
        local newY = s.y + m * speed * sign(s.y - HEIGHT*.5) * sign (m) * (d / 100) / s.distance
        
        if not isBug then
            stroke(s.color.r, s.color.g, s.color.b, s.alpha / s.distance)
            --ellipse(s.x, s.y, 5)
            strokeWidth(6 - s.distance + d / 250)
            
            line(s.x, s.y, newX, newY)
            
            s.x = newX
            s.y = newY
            s.alpha = math.min(255, s.alpha + speed * 2)
        end
        
        if s.x < 0 or s.y < 0 or s.x > WIDTH or s.y > HEIGHT or isBug then
            table.insert(remove, i)
        end
    end
    
    if #remove > 0 then
        for i = 1, #remove do
            table.remove(stars, remove[i] - i + 1)
        end
        
        for i = 1, #remove do
            table.insert(stars, star())
        end
    end
    setContext()
end

function sign(n)
    if n < 0 then
        return -1
    end
    return 1
end

function star()
    return {
        x = math.random(1, WIDTH),
        y = math.random(1, HEIGHT),
        alpha = 0,
        color = color(math.random(255)/50+150, math.random(255)/50+150, math.random(255)/50+150),
        distance = math.random(1, 5)
    }
end

@Anatoly - neat, like the use of the shader. Gives the impression of speed. I’ll try to fit that into my code.

@Anatoly cool effect, nice use of the radial blur

@Leon thank you for that. Most helpful.

@Simeon thanks for the example, again very helpful once I finally worked out how to import it from the file rather than from inside Codea which seemed the most logical way!

Much to learn…