Circles of Confusion (game)

Here is a simple game based on code I had in another discussion. Instructions are in the game, or you can read them at the bottom of the program if you don’t want to load it.


supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
    limit=5
    init()
    instruct=true
end

function init()
    path=0
    moveit=false
    gameOver=false
    circleCollision=false
    complete={}
    speed=2
    tab1={}
    offset = {}
    mx = {}
    my = {}
    dx = {}
    dy = {}
    move = {}
    ex={}
    ey={}
    hit=0
    selected=0
    coll=vec2(0,0)
    dist=WIDTH/(limit+1)
    for z = 1, limit do
        tab1[z] = {}
        move[z] = false
        offset[z] = 1
        dx[z] = 0
        dy[z] = 0
        mx[z] = z*dist
        my[z] = 100
        complete[z]=false
        createEnd(z)
    end
end

function createEnd(ep)
    count=0
    if ep==1 then
        ex[ep]=math.random(50,WIDTH-50)
        ey[ep]=math.random(HEIGHT/2,HEIGHT-50) 
    else
        while 1 do
            xx=0
            hx=math.random(50,WIDTH-50)
            hy=math.random(HEIGHT/2,HEIGHT-50)
            for z=1,ep-1 do
                v1=vec2(hx,hy)
                v2=vec2(ex[z],ey[z])
                d=v1:dist(v2)
                if d < 100 then
                   xx=1 
                end
            end
            if xx==0 then
                ex[ep]=hx
                ey[ep]=hy
                return
            end
            count = count + 1
            if count>1000 then
                return
            end
        end
    end
end

function draw()
    background(70,70,60)
    if instruct then
        instructions()
        return
    end
    for d = 1, limit do
        fill(255, 255, 255)
        for z=offset[d]+1,#tab1[d] do
            stroke(255, 255, 255, 255)
            strokeWidth(3)
            ellipse(tab1[d][z-1].x,tab1[d][z-1].y,3)
        end 
        if move[d] and moveit then
            a=math.sqrt(dx[d]*dx[d]+dy[d]*dy[d])
            b=speed/a
            mx[d] = mx[d] + dx[d]*b
            my[d] = my[d] + dy[d]*b
            moveCircle(d)
        end 
        if complete[d] then
            fill(0,255,0) 
        end
        ellipse(ex[d],ey[d],40,40)
        if move[d] then
            fill(0,255,0)
        end       
        if coll.x==d or coll.y==d then
            fill(255,0,0)
        end 
        ellipse(mx[d],my[d],40,40)
        fill(0)
        text(d,mx[d],my[d])
        text(d,ex[d],ey[d])
    end
    if hit==limit then
        nextLevelScreen()
    elseif circleCollision then
        circleCollisionScreen()
    elseif selected==limit and not moveit then
        fontSize(40)
        fill(0,0,255)
        text("Double tap the screen to continue",WIDTH/2,HEIGHT/2)
        fontSize(17)
    end  
    who()  
end

function who()
    fill(255,255,255,30)
    fontSize(17)
    text("dave1707 (C)",WIDTH-70,20)
end

function nextLevelScreen()
    fontSize(40)
    fill(0,0,255)
    text("You made it.",WIDTH/2,HEIGHT/2-100)
    text("Double tap the screen for the next level",WIDTH/2,HEIGHT/2-200)
    fontSize(17)
end

function circleCollisionScreen()
    fontSize(40)
    fill(0,0,255)
    text("Sorry, you had a collision.",WIDTH/2,HEIGHT/2)
    text("Double tap the screen to retry level",WIDTH/2,HEIGHT/2-100)
    fontSize(17)
end

function calcDist(hx,hy)
    pp=#tab1[path]
    if pp>1 then
        a=hx-tab1[path][pp].x
        b=hy-tab1[path][pp].y
        if a*a+b*b>400 then
            return true
        end
        return false
    end
    return true
end

function touched(t)
    if t.state==BEGAN then
        if t.tapCount==2 then
            if instruct then
                instruct=false
                init()
                return
            end
            if hit==limit then
                limit = limit + 1
                init()
                return
            end
            if gameOver then
                init()
                return
            end
            if selected==limit then
                moveit=true
                nextLevel=false
                return
            end
        end
        path=0
        for s = 1, limit do
            if (t.y-my[s])^2/20^2+(t.x-mx[s])^2/20^2 <= 1 and not move[s] then
                path=s
            end       
        end
    elseif t.state==MOVING and path>0 then 
        if calcDist(t.x,t.y) then
            table.insert(tab1[path],vec2(t.x,t.y))
        end
    elseif t.state==ENDED and path>0 then
            table.insert(tab1[path],vec2(ex[path],ey[path]))
            move[path]=true
            selected = selected + 1
            dx[path]=(tab1[path][offset[path]].x-mx[path])
            dy[path]=(tab1[path][offset[path]].y-my[path])  
    end
end

function checkCollision(cc)
    v1=vec2(mx[cc],my[cc])
    for z=1,limit do
        if cc~=z then
            v2=vec2(mx[z],my[z])
            if v1:dist(v2)<38 then
                moveit=false
                gameOver=true
                coll=vec2(z,cc)
                circleCollision=true
                return true
            end
        end
    end
    return false
end

function checkMatch(cm)
    v1=vec2(mx[cm],my[cm])
    v2=vec2(ex[cm],ey[cm])
    if v1:dist(v2)<5 then
        mx[cm]=ex[cm]
        my[cm]=ey[cm]
        move[cm]=false
        offset[cm]=#tab1[cm]
        hit = hit + 1
        complete[cm]=true
        return true
    end
    return false
end

function moveCircle(mc)
    if move[mc] then
        if offset[mc]>#tab1[mc] then
            tab1[mc]={}
            offset[mc]=1
            dx[mc]=0
            dy[mc]=0
            move[mc]=false
            return
        end
        if checkCollision(mc) then
            return
        end
        if checkMatch(mc) then
            return
        end
        a=math.abs(tab1[mc][offset[mc]].x-mx[mc])
        b=math.abs(tab1[mc][offset[mc]].y-my[mc])
        ab=math.sqrt(a*a+b*b)
        if ab<5 then
            offset[mc] = offset[mc] + 1
            dx[mc]=tab1[mc][offset[mc]].x-mx[mc]
            dy[mc]=tab1[mc][offset[mc]].y-my[mc]
        end
    end
end

function instructions()
    w=WIDTH/2
    fontSize(25)
    fill(214, 157, 46, 255)
    text("Circles of Confusion",w,700)
    fill(255)
    text("The object is to move the lower circles to the",w,650)
    text("matching circles above them. To move the circles, use",w,600)
    text("your finger to drag a path from the lower circle to",w,550)
    text("the upper circle. Once you lift your finger, the path",w,500)
    text("will end and you can't re-draw it. If you don't draw",w,450)
    text("a path far enough, the circle will still find it's",w,400)
    text("way to it's matching circle. The paths can overlap,",w,350)
    text("but if any circle collides with another, the game",w,300)
    text("stops and you re-play that level. If you get all of",w,250)
    text("the circles to their matching circle, you go to the",w,200)
    text("next level which adds one more circle.",w,150)
    fill(255,0,0)
    text("Double tap the screen to start",w,100)
end

Very nice and smooth game. Thanks for sharing. A tap on a starting circle should cancel the cicle path if it exists (i linked 5 to 6 by error and could not correct it). A great addition would be a time constraint with a visible countdown.

@Jmv38 Thanks for the comments. I probably could add a cancel easy enough, but I’m not sure if it’s worth it. Even though you were able to link the starting 5 circle to the ending 6 circle, when the 5 circle reached the ending 6 circle, it would then start moving to the ending 5 circle. If circle 6 was delayed enough and nothing got in circle 5’s way, it would have gotten there safely. I’m not sure what incentive a timer would add. If the timer ran out, would I start the level over or would I force them back to the very beginning ( 5 circles ). I’m not into games that much, so I pretty much just do games bare bones, no frills, or bells and whistles. I wasn’t planning this game, it was just the result of something I did in another post and it was easy enough to do with little thought or time. The main point was just to give others an example, maybe not a good one since it isn’t structured very well. This doesn’t have any comments either because there’s a limit to how big the post can be without having to split it up.

-@dave1707 ok, no problem. However i think youR bare program has really the potential to become a hit if a little bit o salt is added to it. Would you allow me to use your code and try modify it into something more spicy? (i am not sure i’ll do anything soon, cause i am focusing on 3d right now, but i’ll keep it somewhere in my head for later…)

@Jmv38 If you want to try to spice it up, it’s OK with me. I don’t think it’s that interesting of a game. There isn’t much of a challenge after a while and once you reach a high number of circles it’s probably impossible. It was mostly written as a code example more than a game.

I like it. I hit the instruction limit at nine circles, though.

(A solution always exists, by the way, at least until there are so many circles that the size of the circles becomes significant)

@Andrew_Stacey I changed the limit to 20 and tried the game, but I had a collision soon after the circles started to move. Once the limit gets high, it takes longer to draw the paths then the circles move. I think as the limit gets higher, the interest in playing the game gets lower.

I also hit the instruction limit. What is it btw?

I’ve never seen the instruction limit. I always have to close Codea to get out of a looping program.

@Jmv38 @Andrew_Stacey I played around with setInstructionLimit() and it seems that every time you use setInstructionLimit(), it resets the count and starts over to what’s set. So putting setInstructionLimit(value) with some value in draw() would probably prevent a program from stopping.

Even with setInstructionLimit(0) in setup, do you still keep hitting the wall?

.@Mark i’ve put the instruction before setup, i haven’t had and instruction limit error. Thanks for the tip. This function should be documented.