Sprite Sheet help

I was forum digging and I discovered two ways to use sprite sheets that work but not with every sprite sheet.

https://www.gamefromscratch.com/post/2014/10/26/Guide-to-Creating-a-Game-on-an-iPad-Our-First-Project-Adding-Spritesheet-support-to-Codea.aspx

https://codea.io/talk/discussion/comment/13909#Comment_13909

I can get the caveman sprite sheet to work both ways but not the Wizard.

Just wondering what I’m doing wrong.
The wizard image is 2000x200
Each frame is 200x200
10 frames in total

For Main

function setup()
   local img = readImage(asset.documents.Dropbox["Photo Apr 09, 7 51 25 PM.png"])
    wizard = Spritesheet(img,WIDTH,HEIGHT/2,10,1,200,200,0,10)
end
 
function draw() 
   background(40, 40, 50)
    wizard:draw()
end
 
function touched(touch)
    wizard:touched(touch)
end

Spritesheet class

Spritesheet = class()
 
function Spritesheet:init(img,x,y,rows,cols,frameWidth,frameHeight,frame,totalFrames)
   self.x = x
   self.y = y
   self.frame = frame
   self.totalFrames=totalFrames
 
   self.frameWidth = frameWidth
   self.frameHeight = frameHeight
   self.frameRows = rows
   self.frameCols = cols
   self.frameSize = vec2(self.frameWidth,self.frameHeight)
 
   self.counter = 0
 
   self.mesh = mesh()
   --self.texture = img
   self.mesh.texture = img -- self.texture
   self.mesh:addRect(0,0,self.frameWidth,self.frameHeight)
end
 
function Spritesheet:draw()
 
   self.counter = self.counter + DeltaTime
   if self.counter > 1/30 then
 
   self.frame = self.frame + 1 
   if self.frame > self.totalFrames then
       self.frame=0
   end
 
   self.x = self.x -1
 
 
   colUnit = 1/self.frameCols
   rowUnit = 1/self.frameRows
 
   row = math.floor(self.frame / self.frameRows)
   col = math.floor(self.frame % self.frameCols)
 
   self.mesh:setRectTex(1,
   col * colUnit,
  ( 1-rowUnit) - row * rowUnit,
   colUnit,
rowUnit)
 
       self.mesh:setRect(1,self.x,self.y,self.frameWidth,self.frameHeight)
 
    self.counter = 0
    end
 
   self.mesh:draw()
end
 
function Spritesheet:touched(touch)
 
end

Here is way 2 working with caveman but I can’t get to work with wizard.
Caveman download above

function setup()
    
--load up the sprite sheet into a mesh
-- in this case the sprite sheet contains 5 by 5 sprites, each 32 by 32 pixels
-- the file is available from
--http://db.tt/eMJa1tsS
zombie=mesh()
-- you may need to change this to the location where you save the file
img=readImage(asset.documents.Dropbox["Photo Apr 09, 2 42 26 PM.jpg"])
zombie.texture=img
rows=4 --number of rows in the sprite sheet
cols=4 -- number of columns in the sprite sheet
sizex=32 -- width of the sprite image to display on screen - note this does not need to be the original pixel size
sizey=32 -- height of the sprite image
--set up some constants
walkleft=0
walkright=1
turnlefttoright=2
turnrighttoleft=3

--set up some arrays to hold the animations
animdelay=0
animdelaymax=3
animx={}
animy={}
movex={}
movey={}
--define the animation frames
--starting from bottom left as 0,0, enter the column (animx) and row (animy) of the frame you want
--walking left
animx[0]={0,1,2,3,4,0,1,2} 
animy[0]={4,4,4,4,4,3,3,3}
movex[0]={-1,-1,-1,-1,-1,-1,-1,-1}
movey[0]={0,0,0,0,0,0,0,0}
--walking right
animx[1]={0,1,2,3,4,0,1,2}
animy[1]={2,2,2,2,2,1,1,1}
movex[1]={1,1,1,1,1,1,1,1}
movey[1]={0,0,0,0,0,0,0,0}
--turning left to right
animx[2]={3,4,3}
animy[2]={3,3,1}
movex[2]={0,0,0}
movey[2]={0,0,0}
--turning right to left
animx[3]={3,4,3}
animy[3]={1,3,3}
movex[3]={0,0,0}
movey[3]={0,0,0}

x=150  --initial  x coordinate of the sprite
y=HEIGHT/2  -- initial y coordinate of the sprite
state=walkleft -- initial state of the sprite
curFrame=1 -- the initial frame of the animation in terms of the position in the animx and animy arrays
speed=3 -- a factor by which to speed up the movement (alternatively change the values in movex but this provides greater flexibilty
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    --clear the mesh
    zombie:clear()


--cycle through the animation
--add a delay to solw the animation down
animdelay = animdelay + 1
if animdelay>animdelaymax then
    --move to the next frame in the animation
    curFrame = curFrame + 1
    --check to see if this frame is past the end of the animation array for the current state and if so, reset
    if curFrame>#animx[state] and state==turnlefttoright then
        state=walkright
        curFrame=1
    elseif curFrame>#animx[state] and state==turnrighttoleft then
        state=walkleft
        curFrame=1
    elseif curFrame>#animx[state] then
        curFrame=1
    end

    --reset the animation delay counter
    animdelay=0
end
    --adjust the position according to the values in the movement arrays
    x = x + movex[state][curFrame]*speed
    y = y + movey[state][curFrame]*speed -- not needed in this demo as there is no vertical movement
--check to see if the edges of the screen have been met
if x>WIDTH-100 and state~=turnrighttoleft then
    state=turnrighttoleft
    curFrame=1 -- reset the animation
elseif x<100 and state~=turnlefttoright then
    state=turnlefttoright
    curFrame=1
end
    -- Do your drawing here
     local idx=zombie:addRect(x,y,sizex,sizey)
    zombie:setRectTex(idx,(animx[state][curFrame])/cols,(animy[state][curFrame])/rows,1/cols,1/rows)   
    
    --draw the mesh
    zombie:draw()
end

@Jarc Here’s a version that works with both. Enter the number of images wide and high (4,4 for caveman and 10,1 for wizzard) then press extract. You can slide the scale to increase or decrease the size and slide your finger on the screen to move the image around.

displayMode(STANDARD)

function setup()
    tab={}
    delay=0
    i=1
    img=readImage(asset.documents.Dropbox.wizzard)
    iw=img.width
    ih=img.height
    dx,dy=0,HEIGHT/2
    sizeX=iw
    sizeY=ih    
    spriteMode(CORNER)
    parameter.text("wide")
    parameter.text("high")
    parameter.action("extract",extract)
    parameter.integer("scale",1,500,ih)
    img1=image(iw,ih)    
    setContext(img1)
    background(255)
    sprite(img,0,0)
    setContext()    
    w=img1.width
    h=img1.height
end

function extract()
    tab={}
    dx,dy=WIDTH/2,HEIGHT/2
    if wide=="" or high=="" then
        return
    end
    stepX=iw//wide
    stepY=ih//high
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img1:copy(x,y,stepX,stepY))
        end
    end
end

function draw()
    background(255)
    delay=delay+1    
    if #tab>0 then
        if delay>10 then
            delay=1
            i=i+1
        end
        if i>#tab then
            i=1
        end
        sprite(tab[i],dx,dy,scale)
    else
        sprite(img1,dx,dy,400)
    end
end

function touched(t)
    if t.state==MOVING then
        dx=dx+t.deltaX
        dy=dy+t.deltaY 
    end   
end

@dave1707 Your version works the best and I’ve been digging through the forums all day. Thanks!

@Jarc It only works if the sprite sheet is created right and not every sprite sheet is.

@dave1707 is it possible to change animation by touching a specific point on the screen. Meaning if I have a on-screen D-Pad or joystick if I touch Down the code will run sprite sheet row 2, 1-8.
Example sprite-sheet attached.

Maybe a better example with a visual. Basically I’m trying to link the sprite sheet rows to each direction of the joystick or Dpad controller.

displayMode(FULLSCREEN)

function setup()
    pic=readImage(asset.documents.Dropbox["Photo Apr 10, 8 33 09 PM.png"])
    cx,cy=0,0
    sx,sy=WIDTH/2,HEIGHT/2
    dx,dy=0,0
    
    tab={}
    delay=0
    i=1
    img=readImage(asset.documents.Dropbox["Photo Apr 10, 8 33 09 PM.png"])
    iw=img.width
    ih=img.height
    dx,dy=0,HEIGHT/2
    sizeX=iw
    sizeY=ih    
    spriteMode(CORNER)
    parameter.text("wide")
    parameter.text("high")
    parameter.action("extract",extract)
    parameter.integer("scale",1,500,ih)
    img1=image(iw,ih)    
    setContext(img1)
    background(255)
    sprite(img,0,0)
    setContext()    
    w=img1.width
    h=img1.height

end

function extract()
    tab={}
    dx,dy=WIDTH/2,HEIGHT/2
    if wide=="" or high=="" then
        return
    end
    stepX=iw//wide
    stepY=ih//high
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img1:copy(x,y,stepX,stepY))
        end
    end
end


function draw()
    background(40, 40, 50)
    if cx>0 and cy>0 then
        drawCirc()
    end
    sx=sx+dx
    sy=sy+dy
    sprite(pic,sx,sy)
    
    delay=delay+1    
    if #tab>0 then
        if delay>10 then
            delay=1
            i=i+1
        end
        if i>#tab then
            i=1
        end
        sprite(tab[i],dx,dy,scale)
    else
        sprite(img1,dx,dy,400)
    end
    
end

function touched(t)
    
        if t.state==MOVING then
        dx=dx+t.deltaX
        dy=dy+t.deltaY 
    end   
   
    if t.state==BEGAN then
        cx,cy=t.x,t.y      
    end
    if t.state==MOVING then
        if insideCircle(t.x,t.y) then
            dx=(t.x-cx)/10
            dy=(t.y-cy)/10
        else
            cx,cy=0,0
            dx,dy=0,0
        end
    end
    if t.state==ENDED then
        cc,cy=0,0
        dx,dy=0,0
    end
end

function insideCircle(x,y)
    -- check if touch is inside of circle or ellipse
    a,b=100,100 -- radius of circle or a,b of ellipse
    if (x-cx)^2/a^2+(y-cy)^2/b^2 <= 1 then 
        return true
    end
    return false
end

function drawCirc()
    fill(255, 255, 255, 50)
    ellipse(cx,cy,8) -- draw circle center
    fontSize(15)
    fill(233, 80, 133)
    text("Up",cx,cy+80)
    text("Down",cx,cy-80)
    text("Right",cx+80,cy)
    text("Left",cx-80,cy)
    fontSize(10)
    text("DTL",cx-60,cy+60)
    text("DTR",cx+60,cy+60)
    text("DBL",cx-60,cy-60)
    text("DBR",cx+60,cy-60)
    noFill()
    stroke(255,255,255,50)
    strokeWidth(4)
    ellipse(cx,cy,200) -- draw outer circle     
end

The function extract creates a table of each image. You just need to loop thru each section of the table corresponding on the direction your going. For example, if your going down, loop thru table positions 9 thru16, if up then 49 thru 56.

@dave1707 So loop through the table with a if-then statement in touch function?

It’s not going to be as easy as it sounds. The circle might show the eight directions, but the joystick does every direction, so an if statement in touch isn’t going to do it. I’ll look into it more tomorrow.

@Jarc Here’s a hacked up version. Change the img name to the name you have for the person sprite sheet. The joystick is now eight squares that you touch to change direction. Changes can be made from this hacked code.

displayMode(FULLSCREEN)

function setup()
    img=readImage(asset.documents.Dropbox.rty)
    
    rectMode(CENTER)
    x=WIDTH/2
    y=100
    dir=1
    i=1
    bTab={}
    table.insert(bTab,button(x-50,y+50,17))
    table.insert(bTab,button(x,y+50,9))
    table.insert(bTab,button(x+50,y+50,1))
    table.insert(bTab,button(x-50,y,33))
    table.insert(bTab,button(x+50,y,25))
    table.insert(bTab,button(x-50,y-50,57))
    table.insert(bTab,button(x,y-50,49))
    table.insert(bTab,button(x+50,y-50,41))
    delay=0
    iw=img.width
    ih=img.height
    sizeX=iw
    sizeY=ih    
    spriteMode(CORNER)
    img1=image(iw,ih)    
    setContext(img1)
    background(255)
    sprite(img,0,0)
    setContext()   
    wide=8
    high=8 
    extract()
end

function extract()
    tab={}
    dx,dy=WIDTH/2,HEIGHT/2
    stepX=iw//wide
    stepY=ih//high
    sizeY=stepY*high
    sizeX=stepX*wide
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img1:copy(x,y,stepX,stepY))
        end
    end
end

function draw()
    background(255)
    for a,b in pairs(bTab) do
        b:draw()
    end
    if #tab>0 then
        delay=delay+1   
        if delay>15 then
            delay=1
            i=i+1
            if i>dir+7 then
                i=dir
            end
        end
        sprite(tab[i],dx-50,dy,100)
    end
end

function touched(t)
    if t.state==BEGAN then
        for a,b in pairs(bTab) do
            b:touched(t)
        end
    end
end

button=class()

function button:init(x,y,d)
    self.x=x
    self.y=y
    self.dir=d
end

function button:draw()
    rect(self.x,self.y,50,50)
end

function button:touched(t)
    if t.x>self.x-25 and t.x<self.x+25 and t.y>self.y-25 and t.y<self.y+25 then
        dir=self.dir
        i=dir
    end
end

@dave1707 Awesome, thanks. Great code to start with. I’ll be making changes and working on this tonight.

@dave1707 I got the Up,Down,Left and Right to work but I need help with the diagonals.

displayMode(FULLSCREEN)

function setup()
    img=readImage(asset.documents.Dropbox["Photo Apr 10, 8 33 09 PM.png"])

    rectMode(CENTER)
    x=WIDTH/2
    y=100
    dir=1
    i=1
    bTab={}
    table.insert(bTab,button(x-50,y+50,17))
    table.insert(bTab,button(x,y+50,9))
    table.insert(bTab,button(x+50,y+50,1))
    table.insert(bTab,button(x-50,y,33))
    table.insert(bTab,button(x+50,y,25))
    table.insert(bTab,button(x-50,y-50,57))
    table.insert(bTab,button(x,y-50,49))
    table.insert(bTab,button(x+50,y-50,41))
    delay=0
    iw=img.width
    ih=img.height
    sizeX=iw
    sizeY=ih    
    spriteMode(CORNER)
    img1=image(iw,ih)    
    setContext(img1)
    background(255)
    sprite(img,0,0)
    setContext()   
    wide=8
    high=8 
    extract()
    xs=0
    xs2=0
    b1=vec4(WIDTH/2-50,100,50,50)
    b2=vec4(WIDTH/2+50,100,50,50)
    b3=vec4(WIDTH/2,150,50,50)
    b4=vec4(WIDTH/2,50,50,50)
       
end

function extract()
    tab={}
    dx,dy=WIDTH/2,HEIGHT/2
    stepX=iw//wide
    stepY=ih//high
    sizeY=stepY*high
    sizeX=stepX*wide
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img1:copy(x,y,stepX,stepY))
        end
    end
end

function draw()
    background(255)
    for a,b in pairs(bTab) do
        b:draw()
    end
    if #tab>0 then
        delay=delay+1   
        if delay>15 then
            delay=1
            i=i+1
            if i>dir+7 then
                i=dir
            end
        end
        
         --sprite position and scale size
        sprite(tab[i],dx-50,dy,100)
        dx=dx+xs
        dy=dy+xs2
     
    pushStyle()   
    fill(255, 0, 0)
    rect(b1.x,b1.y,b1.z,b1.w)   -- button 1 left
    rect(b2.x,b2.y,b2.z,b2.w)   -- button 2 right
    rect(b3.x,b3.y,b3.z,b3.w)   -- button 3 top
    rect(b4.x,b4.y,b4.z,b4.w)   -- button 4 bottom
    popStyle()    
        
    pushStyle()
    fill(248)
    fontSize(15)
    text("Left",b1.x,b1.y)
    text("Right",b2.x,b2.y)
    text("Top",b3.x,b3.y)
    text("Bottom",b4.x,b4.y)   
    popStyle()    
    end
end

--touch controls,directions
function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        xs=0
        if t.x>b1.x-b1.z/2 and t.x<b1.x+b1.z/2 and
            t.y>b1.y-b1.w/2 and t.y<b1.y+b1.z/2 then
                xs=-2.2
        end
     if t.x>b2.x-b2.z/2 and t.x<b2.x+b2.z/2 and
            t.y>b2.y-b2.w/2 and t.y<b2.y+b1.z/2 then
                xs=2.2
        end
        if t.x>b3.x-b3.z/2 and t.x<b3.x+b3.z/2 and
            t.y>b3.y-b3.w/2 and t.y<b3.y+b1.z/2 then
                xs2=2.2
        end
        if t.x>b4.x-b4.z/2 and t.x<b4.x+b4.z/2 and
            t.y>b4.y-b4.w/2 and t.y<b4.y+b1.z/2 then
                xs2=-2.2
        end

        for a,b in pairs(bTab) do
            b:touched(t)
        end
    end
    if t.state==ENDED then
        xs=0
        xs2=0
    end
end

--class for dpad
button=class()

function button:init(x,y,d)
    self.x=x
    self.y=y
    self.dir=d
end

--drawing pad
function button:draw()
    rect(self.x,self.y,50,50)
end

--touch for dpad
function button:touched(t)
    if t.x>self.x-25 and t.x<self.x+25 and t.y>self.y-25 and t.y<self.y+25 then
        dir=self.dir
        i=dir
    end
    end

@Jarc Here’s another version to work from.

Code removed and updated below

@dave1707 This is how I’m modifying to fit specific backgrounds and how I’m increasing character speed. Is this the easiest way with this code?
Background example attached.

On a side note, anyway to go diagonal using vec4? I used it to go Up, Down, Left and Right but can’t figure out diagonals that way.

displayMode(FULLSCREEN)

function setup()
    img=readImage(asset.documents.Dropbox["Photo Apr 10, 8 24 31 PM.png"])
    rectMode(CENTER)
    dir,i=1,1
    delay,xs,ys=0,0,0
    dx,dy=WIDTH/2,HEIGHT/2
    createButtons()
    extractSprites()
end    

function createButtons()
    x,y=WIDTH/2,100
    bTab={}
    table.insert(bTab,button(x-50,y+50,17,-1,1,"u-l"))
    table.insert(bTab,button(x,y+50,9,0,1,"up"))
    table.insert(bTab,button(x+50,y+50,1,1,1,"u-r"))
    table.insert(bTab,button(x-50,y,33,-1,0,"left"))
    table.insert(bTab,button(x+50,y,25,1,0,"right"))
    table.insert(bTab,button(x-50,y-50,57,-1,-1,"d-l"))
    table.insert(bTab,button(x,y-50,49,0,-1,"down"))
    table.insert(bTab,button(x+50,y-50,41,1,-1,"d-r"))
end

function extractSprites()   
    tab={}
    stepX=img.width//8
    stepY=img.height//8
    sizeX=stepX*8
    sizeY=stepY*8
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img:copy(x,y,stepX,stepY))
        end
    end
end

function draw()
    background(255)
    drawGround()
    checkButtons()   
    drawPerson()
end

function drawGround()
    dx=dx+xs*4
    dy=dy+ys*4
    for x=-20,20 do
        for y=-20,20 do
            sprite(asset.documents.Dropbox["Photo Apr 09, 7 31 15 PM.png"],x*64-dx,y*64-dy)
        end
    end   
end

function checkButtons()
    for a,b in pairs(bTab) do
        b:draw()
    end
end

function drawPerson()    
    delay=delay+1   
    if delay>15 then
        delay=1
        if xs~=0 or ys~=0 then
            i=i+1
            if i>dir+7 then
                i=dir
            end
        end
    end
    sprite(tab[i],WIDTH/2,HEIGHT/2,100)
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        for a,b in pairs(bTab) do
            b:touched(t)
        end
    elseif t.state==ENDED then
        xs=0
        ys=0
    end
end

button=class()

function button:init(x,y,d,xs,ys,n)
    self.x=x    -- x position   
    self.y=y    -- y position
    self.dir=d  -- person direction
    self.xs=xs  -- person speed x
    self.ys=ys  -- person speed y
    self.name=n -- button name
end

function button:draw()
    fill(255,0,0)
    rect(self.x,self.y,50,50)
    fill(255)
    text(self.name,self.x,self.y)
end

function button:touched(t)
    if t.x>self.x-25 and t.x<self.x+25 and t.y>self.y-25 and t.y<self.y+25 then
        dir=self.dir
        i=dir
        xs=self.xs
        ys=self.ys
    end
end

@dave1707 Amazing! As always, thank you for the help.

@Jarc Here’s a new version. I stripped all the unnecessary code out and created separate functions for routines. This might be easier to modify.

displayMode(FULLSCREEN)

function setup()
    img=readImage(asset.documents.Dropbox.rty)
    rectMode(CENTER)
    dir,i=1,1
    delay,xs,ys=0,0,0
    dx,dy=WIDTH/2,HEIGHT/2
    createButtons()
    extractSprites()
end    
    
function createButtons()
    x,y=WIDTH/2,100
    bTab={}
    table.insert(bTab,button(x-50,y+50,17,-1,1,"u-l"))
    table.insert(bTab,button(x,y+50,9,0,1,"up"))
    table.insert(bTab,button(x+50,y+50,1,1,1,"u-r"))
    table.insert(bTab,button(x-50,y,33,-1,0,"left"))
    table.insert(bTab,button(x+50,y,25,1,0,"right"))
    table.insert(bTab,button(x-50,y-50,57,-1,-1,"d-l"))
    table.insert(bTab,button(x,y-50,49,0,-1,"down"))
    table.insert(bTab,button(x+50,y-50,41,1,-1,"d-r"))
end

function extractSprites()   
    tab={}
    stepX=img.width//8
    stepY=img.height//8
    sizeX=stepX*8
    sizeY=stepY*8
    for y=1,sizeY,stepY do
        for x=1,sizeX,stepX do
            table.insert(tab,img:copy(x,y,stepX,stepY))
        end
    end
end

function draw()
    background(255)
    drawGround()
    checkButtons()   
    drawPerson()
end

function drawGround()
    dx=dx+xs
    dy=dy+ys
    for x=-20,20 do
        for y=-20,20 do
            sprite(asset.builtin.Blocks.Gravel_Stone,x*128-dx,y*128-dy)
        end
    end   
end

function checkButtons()
    for a,b in pairs(bTab) do
        b:draw()
    end
end

function drawPerson()    
    delay=delay+1   
    if delay>15 then
        delay=1
        if xs~=0 or ys~=0 then
            i=i+1
            if i>dir+7 then
                i=dir
            end
        end
    end
    sprite(tab[i],WIDTH/2,HEIGHT/2,100)
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        for a,b in pairs(bTab) do
            b:touched(t)
        end
    elseif t.state==ENDED then
        xs=0
        ys=0
    end
end

button=class()

function button:init(x,y,d,xs,ys,n)
    self.x=x    -- x position   
    self.y=y    -- y position
    self.dir=d  -- person direction
    self.xs=xs  -- person speed x
    self.ys=ys  -- person speed y
    self.name=n -- button name
end

function button:draw()
    fill(255,0,0)
    rect(self.x,self.y,50,50)
    fill(255)
    text(self.name,self.x,self.y)
end

function button:touched(t)
    if t.x>self.x-25 and t.x<self.x+25 and t.y>self.y-25 and t.y<self.y+25 then
        dir=self.dir
        i=dir
        xs=self.xs
        ys=self.ys
    end
end

@dave1707 in the code above I only made changes here.


function drawGround()
    dx=dx+xs*4
    dy=dy+ys*4
    for x=-20,20 do
        for y=-20,20 do
            sprite(asset.documents.Dropbox["Photo Apr 09, 7 31 15 PM.png"],x*64-dx,y*64-dy)
        end
    end   
end

@Jarc You can add whatever background you want. You can add a table that has different values in it and depending on the table value you can insert different sections in the ground. You can then avoid them as the person walks around.

Why do you want to add a vec4 for movement. The movement is working in all directions now.

@Jarc Here’s an example of a background I have in some other program I created. The player can collect the stars by running into them. They can’t go up on a black area, but they can fall thru a black area. They also can’t go thru a brick area.