Portal 2D project

@Ignatz I did search the forums and got nothing on what I wanted.

From draw, just execute a function based on a value that draws a page that has what you want on it.

function setup()
    lev={level1,level2,level3}
    lv=1
end

function draw()
    lev[lv]()    
end

function touched(t)
    if t.state==BEGAN then
        lv=lv+1
        if lv>#lev then
            lv=1
        end
    end
end

function level1()
    background(255, 0, 0)
    fill(255)
    text("level 1",WIDTH/2,HEIGHT/2)
    text("tap screen for next level",WIDTH/2,HEIGHT-50)
end

function level2()
    background(0, 159, 255)
    fill(255)
    text("level 2",WIDTH/2,HEIGHT/2)
    text("tap screen for next level",WIDTH/2,HEIGHT-50)
end

function level3()
    background(242, 0, 255)
    fill(255)
    text("level 3",WIDTH/2,HEIGHT/2)
    text("tap screen for next level",WIDTH/2,HEIGHT-50)
end

@Chell I modified one of my above programs to show different levels if I understand what you’re after.

EDIT: Changed program to use tables and allow for multiple levels and multiple portals per levels.

displayMode(FULLSCREEN)

function setup()
    lev={level1,level2,level3,level4}
    lv=1
    portals={}
    portals[1]={vec4(300,400,2,1)}  -- x,y,next level,next portal
    portals[2]={vec4(400,700,1,1),vec4(500,500,3,1)}
    portals[3]={vec4(100,100,2,2),vec4(200,300,2,1),vec4(500,300,4,2)}
    portals[4]={vec4(200,300,2,1),vec4(300,400,1,1),vec4(400,100,3,2),vec4(600,500,2,2)}
    sx,sy=200,380
end

function draw()
    lev[lv]()
    sprite("Planet Cute:Character Horn Girl",sx,sy,100)
    if not moved then
        for z=1,#portals[lv] do
            port=portals[lv][z]
            if sx>port.x-20 and sx<port.x+20 and sy>port.y-20 and sy<port.y+20 then
                moved=true
                moved1=true                
                lv=port.z
                sx=portals[port.z][port.w].x
                sy=portals[port.z][port.w].y
                inX=sx
                inY=sy
                break
            end
        end
    elseif sx<inX-20 or sx>inX+20 or sy<inY-20 or sy>inY+20 then
            moved1=false
            moved=false
    end    
end

function level1()
    background(50,130,130)
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    for z=1,#portals[1] do
        ellipse(portals[1][z].x,portals[1][z].y,60,120)
    end
    text("level1",WIDTH/2,HEIGHT/2)
end
    
function level2()   
    background(130,130,50)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    for z=1,#portals[2] do
        ellipse(portals[2][z].x,portals[2][z].y,60,120)
    end
    text("level2",WIDTH/2,HEIGHT/2)
end

function level3()   
    background(211, 223, 156, 255)
    fill(231, 108, 87, 255)
    stroke(249, 0, 255, 255)
    strokeWidth(2)
    for z=1,#portals[3] do
        ellipse(portals[3][z].x,portals[3][z].y,60,120)
    end
    text("level3",WIDTH/2,HEIGHT/2)
end

function level4()   
    background(154, 223, 169, 255)
    fill(224, 126, 174, 255)
    stroke(230, 197, 90, 255)
    strokeWidth(2)
    for z=1,#portals[4] do
        ellipse(portals[4][z].x,portals[4][z].y,60,120)
    end
    text("level4",WIDTH/2,HEIGHT/2)
end

function touched(t)
    if t.state==MOVING and not moved1 then
        if t.x>sx-30 and t.x<sx+30 and t.y>sy-30 and t.y<sy+30 then
            sx=t.x
            sy=t.y   
        end     
    end
    if t.state==ENDED then
        moved1=false
    end    
end

Thank you for all your help. That answers all my questions for now.

Modified the above program to use tables to allow multiple levels with multiple portals per level.

Okay, but that’s not exactly what I’m trying to do. I want to place a portal in front of me, place a portal somewhere else to get to the exit of the level, and when you get to the exit you go to the next level automaticlly. But I’ve been trying my best to work towards that.

@Chell That’s OK. I had fun writing the code and I’m sure someone else might find a use for it to create some kind of a game.

I actually started a code to do just that out of all the examples and a little of my code. But I can’t get the level changing down. Here’s the code:


-- My Little Portal Beta Mode

-- Use this function to perform your initial setup
function setup()
    lev={level1,level2,level3,level4}
    lv=1
    et,tc=0,0
    px,py=300,400
    hx,hy= 700,300
    sx,sy=200,435

end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    bodies = {}
    
    -- Create some static boxes (not effected by gravity or collisions)
    local left = makeBox(WIDTH/4, HEIGHT/2, WIDTH/3, 10, 0)
    left.type = STATIC
    
    local right = makeBox(WIDTH - WIDTH/4, HEIGHT/2, WIDTH/3, 10, 0)
    right.type = STATIC
    
    table.insert(bodies, left)
    table.insert(bodies, right)
    
    
    for k,body in pairs(bodies) do
        drawBody(body)
    end
    
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    ellipse(px,py,60,120)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    ellipse(hx,hy,60,120)
    if ElapsedTime-et>.2 and tc>0 then
        if tc==2 then
            hx=tx
            hy=ty
        elseif tc==3 then
            px=tx
            py=ty
        end
        tc=0
    end
       sprite("Documents:Chell",sx,sy,100)
       if not moved then
        if px>sx-20 and px<sx+20 and py>sy-20 and py<sy+20 then
            sx = hx
            sy = hy
            moved=true
            moved1=true
        elseif hx>sx-20 and hx<sx+20 and hy>sy-20 and hy<sy+20 then
            sx = px
            sy = py
            moved=true
            moved1=true
        end
    end
    if moved then
        if px>sx-20 and px<sx+20 and py>sy-20 and py<sy+20 then
            return
        end
        if hx>sx-20 and hx<sx+20 and hy>sy-20 and hy<sy+20 then
            return
        end
        moved1=false
        moved=false
    end
end

    function touched(t)
    if t.state==BEGAN then
        et=ElapsedTime
        tc=t.tapCount
        tx=t.x
        ty=t.y
    end
    if t.x>sx-30 and t.x<sx+30 and t.y>sy-30 and t.y<sy+30 then
        if t.state==MOVING then
            sx=t.x
            sy=t.y   
        end     
    end
    if t.state==ENDED then
        moved1=false
    end    
end

    -- Do your drawing here
    function makeBox(x,y,w,h,r)
    -- Points are defined in counter-clockwise order
    local body = physics.body(POLYGON,vec2(-w/2, h/2),
    vec2(-w/2, -h/2), vec2(w/2, -h/2), vec2(w/2, h/2))
    
    -- Set the body's transform (position, angle)
    body.x = x
    body.y = y
    body.angle = r
    
    -- Make movement smoother regardless of framerate
    body.interpolate = true
    
    return body
end

-- Helper function to draw a physics body
function drawBody(body)
    -- Push style and transform matrix so we can restore them after
    pushStyle()
    pushMatrix()
    
    strokeWidth(5)
    stroke(255, 255, 255, 255)
    translate(body.x, body.y)
    rotate(body.angle)
    
    -- Draw body based on shape type
    if body.shapeType == POLYGON then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points do
            a = points[j]
            b = points[(j % #points)+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CHAIN or body.shapeType == EDGE then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points-1 do
            a = points[j]
            b = points[j+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CIRCLE then
        strokeWidth(3.0)
        line(0,0,body.radius-3,0)
        ellipse(0,0,body.radius*2)
    end
    
    -- Restore style and transform
    popMatrix()
    popStyle()
    
function level1()
    background(50,130,130)
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)

end

function level2()   
    background(50, 61, 130, 255)
    end

function level3()   
    background(66, 78, 120, 255)
    end

function level4()   
    background(154, 169, 223, 255)
    end


end

@Chell When you post code, put 3~'s on a line above and below your code to format it correctly.

Okay, but can you help with the level problem? I can create levels now but I can’t get to them. I want to create a door that leads to the next level.

I added some code. You can compare this code to yours.

-- My Little Portal Beta Mode

function setup()
    lev={level1,level2,level3,level4}
    lv=1
    et,tc=0,0
    px,py=300,400
    hx,hy= 700,300
    sx,sy=200,435
end

function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    bodies = {}

    -- Create some static boxes (not effected by gravity or collisions)
    local left = makeBox(WIDTH/4, HEIGHT/2, WIDTH/3, 10, 0)
    left.type = STATIC

    local right = makeBox(WIDTH - WIDTH/4, HEIGHT/2, WIDTH/3, 10, 0)
    right.type = STATIC

    table.insert(bodies, left)
    table.insert(bodies, right)

    for k,body in pairs(bodies) do
        drawBody(body)
    end
    
    lev[lv]()  -- added
      
    if ElapsedTime-et>.2 and tc>0 then
        if tc==2 then
            hx=tx
            hy=ty
        elseif tc==3 then
            px=tx
            py=ty
        end
        tc=0
    end
    sprite("Planet Cute:Character Boy",sx,sy,100)
    if not moved then
        if px>sx-20 and px<sx+20 and py>sy-20 and py<sy+20 then
            sx = hx
            sy = hy
            moved=true
            moved1=true
        elseif hx>sx-20 and hx<sx+20 and hy>sy-20 and hy<sy+20 then
            sx = px
            sy = py
            moved=true
            moved1=true
            lv=lv+1
            if lv>#lev then
                lv=1
            end
        end
    end
    if moved then
        if px>sx-20 and px<sx+20 and py>sy-20 and py<sy+20 then
            return
        end
        if hx>sx-20 and hx<sx+20 and hy>sy-20 and hy<sy+20 then
            return
        end
        moved1=false
        moved=false
    end
end

function touched(t)
    if t.state==BEGAN then
        et=ElapsedTime
        tc=t.tapCount
        tx=t.x
        ty=t.y
    end
    if t.x>sx-30 and t.x<sx+30 and t.y>sy-30 and t.y<sy+30 then
        if t.state==MOVING then
            sx=t.x
            sy=t.y   
        end     
    end
    if t.state==ENDED then
        moved1=false
    end    
end

function makeBox(x,y,w,h,r)
    -- Points are defined in counter-clockwise order
    local body = physics.body(POLYGON,vec2(-w/2, h/2),
    vec2(-w/2, -h/2), vec2(w/2, -h/2), vec2(w/2, h/2))

    -- Set the body's transform (position, angle)
    body.x = x
    body.y = y
    body.angle = r

    -- Make movement smoother regardless of framerate
    body.interpolate = true
    return body
end

function drawBody(body)
    -- Push style and transform matrix so we can restore them after
    pushStyle()
    pushMatrix()

    strokeWidth(5)
    stroke(255, 255, 255, 255)
    translate(body.x, body.y)
    rotate(body.angle)

    -- Draw body based on shape type
    if body.shapeType == POLYGON then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points do
            a = points[j]
            b = points[(j % #points)+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CHAIN or body.shapeType == EDGE then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points-1 do
            a = points[j]
            b = points[j+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CIRCLE then
        strokeWidth(3.0)
        line(0,0,body.radius-3,0)
        ellipse(0,0,body.radius*2)
    end

    -- Restore style and transform
    popMatrix()
    popStyle()
end

function level1()
    background(50,130,130)        
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    ellipse(px,py,60,120)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    ellipse(hx,hy,60,120)        
end

function level2()   
    background(50, 61, 130, 255)
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    ellipse(px,py,60,120)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    ellipse(hx,hy,60,120)        
end

function level3()   
    background(66, 78, 120, 255)
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    ellipse(px,py,60,120)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    ellipse(hx,hy,60,120)
end

function level4()   
    background(154, 169, 223, 255)
    fill(181, 141, 64, 255)
    stroke(255, 105, 0, 255)
    strokeWidth(2)
    ellipse(px,py,60,120)
    fill(64, 76, 181, 255)
    stroke(0, 17, 255, 255)
    strokeWidth(2)
    ellipse(hx,hy,60,120)        
end

@Chell Why did you define the levels inside your drawbody? I wrote the following program to see what would happen:

-- FunctionScope

-- Use this function to perform your initial setup
function setup()
    outerScope(false)
    outerScope(true)
    innerScope()
end


function outerScope (call)
    print("outerScope")
    function innerScope()
        print("innerScope")
    end
    if call==true then
        innerScope()
    end
end

I’m used to compiled languages with scoping rules, but defining a new function wherever you want seems to work. I would argue that it does make your program hard to read.

I’ve read chapter 6 of the LUA 5.1spec a couple of times to try to get my head around function calls. I slowly getting it … and Dave has worked some magic with functions as first class values with the code

-- from setup
    lev={level1,level2,level3,level4}
    lv=1

--from draw
    lev[lv]()

Thanks for your question. Dave is answering for two :)>-

@nfgdayton I believe that was an error on @Chell part. When I updated his code, i had to take the levels out of drawbody. In your code above, function innerScope doesn’t exits unless function outerScope is executed. Comment out the 2 calls to outerScope in setup and see what happens.

Thanks, I can see how that’s tied to functions as first class values. I defined a string in outerScope and it printed as nil if I didn’t call outerScope. Light is getting a little brighter.

@dave1707
I’ve added a little more to your example to fit the door I was looking for. But I want to know how to have the rectangles positioned in a different angle in each level.
@nfgdayton
Maybe you could join my team. There’s more than one person working on this project and we’re open to new members. I just handle the coding, which explains why I need help all the time.

@Chell Where did the rectangles come from and what are they used for. Below is an example of rectangles at a different angle.

function setup()
end

function draw()
    background(40, 40, 50)
    
    pushMatrix()
    fill(232, 49, 49, 255)
    translate(100,200)
    rotate(45)
    rect(0,0,100,50)
    popMatrix()

    pushMatrix()
    fill(49, 56, 231, 255)
    translate(400,300)
    rotate(75)
    rect(0,0,100,50)
    popMatrix()
    
    pushMatrix()
    fill(49, 231, 128, 255)
    translate(600,500)
    rotate(130)
    rect(0,0,100,50)
    popMatrix()
end

The rectangles are meant to be like platforms that you can teleport to, and a large round circle acts as a gateway to the next level.

@Chell feel free to send me a message.

Progress with me will be a lot slower than with Dave. I have learned a lot from your questions, but the draw section this program is getting pretty complex. (I.E. 1. Box Code, 2. Level Code (One call - cleanest part of the routine), 3. Portal movement Code, 4. Sprite movement Code. ) I could help you isolate these functions so we could create smaller sample programs for asking for help from Dave or Ignatz to answer.

I’ve started learning .GIT, so I would be excited in trying out what I know in a team environment.

@nfgdayton
Cool, at least production can move faster,

I’m currently working on level 2, but I have a problem. I need to create an interactive box that can be pushed by a player. I checked all the examples I thought would have the answer but found not