Path drawing

I want to make a game where player can control the characters by touch them and draw the path for them to follow. But I don’t know how to start. Can anyone suggest me or give me example?

Thank you

Hi @wave, May be this link could help you: http://twolivesleft.com/Codea/Talk/discussion/comment/13802#Comment_13802

@wave

Is this what you’re after. Just drag your finger on the screen to leave a trail. Once you lift your finger, the circle will follow the trail. After the circle stops, draw another trail somewhere on the screen and the circle will find the start of the trail and then follow it. I don’t like the way this works, but I don’t have the time to make it better right now, but this might give you a starting point.
If the points on the trail are close together, the circle gets kind of jerky, so the faster you draw the trail, the smoother it moves.


displayMode(FULLSCREEN)
function setup()
    mx=0
    my=0
    init()
end

function init()
    tab1={}    -- table for points
    offset=1
    dx=0
    dy=0
    move=false
end

function draw()
    background(40, 40, 50)
    for z=2,#tab1-1 do
        stroke(255)
        strokeWidth(3)
        line(tab1[z-1].x,tab1[z-1].y,tab1[z].x,tab1[z].y)
    end    
    if move then    -- try to move at constant speed
        a=math.sqrt(dx*dx+dy*dy)
        b=5/a
        mx = mx + dx*b
        my = my + dy*b
    end    
    fill(255)
    ellipse(mx,my,20,20)
    moveCircle()
end

function touched(t)
    if t.state==BEGAN and not en then
        if mx==0 and my==0 then
            mx=t.x
            my=t.y
        end
    elseif t.state==MOVING then
        table.insert(tab1,vec2(t.x,t.y))    -- insert points in table
    elseif t.state==ENDED then
        dx=(tab1[offset].x-mx)
        dy=(tab1[offset].y-my)
        move=true
    end
end

function moveCircle()
    if move then
        if offset==#tab1 then
            init()
            return
        end
        a=math.abs(tab1[offset].x-mx)    -- calc new x,y direction
        b=math.abs(tab1[offset].y-my)
        ab=math.sqrt(a*a+b*b)
        if a<1 and b<1 or ab<5 then
            offset = offset + 1
            dx=tab1[offset].x-mx
            dy=tab1[offset].y-my
        end
    end
end

@dave1707

Thank you, this really help me getting start. But can you explain a moveCircle function? I’m quite confused. Thanks again for the help.

@wave

I added more comments to moveCircle(). Here is what’s happening. The circle moves from one position in the table to the next. When I reach a point in the table, I get the x,y difference to the next point. Based on that difference, I know how far I need to move in the x direction and the y direction. As the circle moves, I check if it reaches the next point, that’s the check a<1 and b<1. I also add code if the x,y distance is within 5 of the next point, that’s the ab<5. The circle didn’t always get within 1 of the next point and would leave the trail. Actually, you don’t need the a<1and b<1check, just the ab<5. Up in the draw function, I calculate the distance the circle needs to travel and try to move it at a constant speed. I hope that explains things better. Like I said earlier, I’m not satisfied with the way all this is working, but it works. I’m sure someone will come up with a better routine.


function moveCircle()
    if move then  -- if the circle is moving, then execute the following code

        if offset==#tab1 then  -- circle reached end of trail, start over
            init()
            return
        end

        a=math.abs(tab1[offset].x-mx)  -- difference between circle x and table x position
        b=math.abs(tab1[offset].y-my)  -- difference between circle y and table y position

        ab=math.sqrt(a*a+b*b) -- distance between circle x,y and table x,y position
  
        -- check if the circle reached the next point in the table
        if a<1 and b<1 or ab<5 then -- if x,y difference less 1 or distance less than 5

            offset = offset + 1  -- offset for the next position in the table

            -- get the difference of where the circle is and where it needs to go
            dx=tab1[offset].x-mx  -- difference between circle x and table x position
            dy=tab1[offset].y-my  -- difference between circle y and table y position

        end
    end
end

@wave

Here is another version. I limit the number of points in the table. If you drag your finger slow, I won’t insert a point unless it’s more than 20 away from the previous point. I also remove the trail as the circle moves along. And I removed the a<1 and the b< 1 from moveCircle. Still not very good, but better.


displayMode(FULLSCREEN)
function setup()
    mx=0
    my=0
    init()
end

function init()
    tab1={}    -- table for points
    offset=1
    dx=0
    dy=0
    move=false
end

function draw()
    local a; local b
    local line=line
    background(40, 40, 50)
    for z=offset+1,#tab1-1 do
        stroke(255)
        strokeWidth(3)
        line(tab1[z-1].x,tab1[z-1].y,tab1[z].x,tab1[z].y)
    end    
    if move then    -- try to move at constant speed
        a=math.sqrt(dx*dx+dy*dy)
        b=5/a
        mx = mx + dx*b
        my = my + dy*b
    end    
    fill(255)
    ellipse(mx,my,20,20)
    moveCircle()
end

function calcDist()-- don't draw points within 20 of the previous point
    local t=#tab1
    local a; local b
    if t>1 then
        a=hx-tab1[t].x
        b=hy-tab1[t].y
        if a*a+b*b>400 then
            return true
        end
        return false
    end
    return true
end

function touched(t)
    if t.state==BEGAN and not en then
        if mx==0 and my==0 then
            mx=t.x
            my=t.y
        end
    elseif t.state==MOVING then
        hx=t.x
        hy=t.y       
        if calcDist() then -- limit points in the table
            table.insert(tab1,vec2(t.x,t.y))    -- insert points in table
        end
    elseif t.state==ENDED then
        dx=(tab1[offset].x-mx)
        dy=(tab1[offset].y-my)
        move=true
    end
end

function moveCircle()
    local a; local b; local ab
    if move then
        if offset==#tab1 then
            init()
            return
        end
        a=math.abs(tab1[offset].x-mx)    -- calc new x,y direction
        b=math.abs(tab1[offset].y-my)
        ab=math.sqrt(a*a+b*b)
        if ab<5 then
            offset = offset + 1
            dx=tab1[offset].x-mx
            dy=tab1[offset].y-my
        end
    end
end

@dave1707

Thank you again. Your explanation help me understand much better.

(By the way, there is a crash when press a finger and lift it without moving)

.@dave1707
Thanks for your permanent help to us, I want to add a background image to this code in order to enable delineation of figures from it and to save them.

  1. How to add a background image into this code ( sprite , setContext, …)

  2. How to close this trail and fill the inside with a transparent color by playing on its alpha to verify that the region delineated is accurate.

Great thanks for your previous help to .@letaief

Hi @letaief

  1. You want a sprite as the background. 2) You want to drag your finger to close an area and fill it with a transparent color. How close is this. This isn’t the greatest, but I’m not exactly sure what you’re trying to do. Drag your finger in a large circle on the sprite.

displayMode(FULLSCREEN)
function setup()
    count=0
    tab={}
    mtab={}
    m=mesh()
end

function draw()
    background(40, 40, 50)
    sprite("Cargo Bot:Codea Icon",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
    m.vertices=mtab
    m:setColors(0,0,0,75)  -- transparent color
    m.draw(m)
end

function touched(t)
    if t.state==MOVING then
        count = count + 1
        table.insert(tab,t)
        if count>1 then
            table.insert(mtab,(vec2(tab[1].x,tab[1].y)))
            table.insert(mtab,(vec2(tab[count-1].x,tab[count-1].y)))
            table.insert(mtab,(vec2(tab[count].x,tab[count].y)))
        end
    end
end



Hi @wave

The crash doesn’t surprise me. I don’t like the way the code is working, so eventually I’m going to re-write it and make it better. Glad the explanation helped.

@dave1707
I added my own code a bit to change the line to dot and make player to have to draw from the circle for it to follow. I also fix the crash too, it happens because when you touch and lift your finger, it won’t call the t.state == moving so no insert table. But later on the code calls that nil thing so it crash.

Here’s my version I would be very glad if you have anything to suggest about it.

displayMode(FULLSCREEN)
function setup()
    mx=0
    my=0
    init()
end

function init()
    tab1={}    -- table for points
    offset=1
    dx=0
    dy=0
    move=false
    mx1 = 0
    my1 = 0
    insert = false
end

function draw()
    local a; local b
    local line=line
    background(0, 0, 0, 255)
    for z=offset+1,#tab1-1 do
        stroke(255, 255, 255, 255)
        strokeWidth(3)
        --line(tab1[z-1].x,tab1[z-1].y,tab1[z].x,tab1[z].y)
        if math.abs(tab1[1].x - mx1) < 30 and math.abs(tab1[1].y - my1) < 30 then
            ellipse(tab1[z-1].x,tab1[z-1].y,3)
        end
    end    
    if move then    -- try to move at constant speed
        a=math.sqrt(dx*dx+dy*dy)
        b=5/a
        mx = mx + dx*b
        my = my + dy*b
    end    
    fill(255, 255, 255, 255)
    ellipse(mx,my,40,40)
    moveCircle()
end

function calcDist()-- don't draw points within 20 of the previous point
    local t=#tab1
    local a; local b
    if t>1 then
        a=hx-tab1[t].x
        b=hy-tab1[t].y
        if a*a+b*b>400 then
            return true
        end
        return false
    end
    return true
end

function touched(t)
    if t.state==BEGAN and not en then
        mx1=t.x
        my1=t.y
        if mx==0 and my==0 then
            mx=t.x
            my=t.y
        end
        
    elseif t.state==MOVING then  
        hx=t.x
        hy=t.y 
        if calcDist() then -- limit points in the table
            table.insert(tab1,vec2(t.x,t.y))    -- insert points in table
            insert = true
        end
 
    elseif t.state==ENDED then
        if insert then        
            if math.abs(tab1[1].x - mx) < 30 and math.abs(tab1[1].y - my) < 30 then
                move=true
                dx=(tab1[offset].x-mx)
                dy=(tab1[offset].y-my)
        
            else
                init()
                return
            end
        end
    end
end

function moveCircle()
    local a; local b; local ab
    if move then
        if offset==#tab1 then
            init()
            return
        end
        a=math.abs(tab1[offset].x-mx)    -- calc new x,y direction
        b=math.abs(tab1[offset].y-my)
        ab=math.sqrt(a*a+b*b)
        if ab<5 then
            offset = offset + 1
            dx=tab1[offset].x-mx
            dy=tab1[offset].y-my
        end
    end
end

(Now I’m trying to make multiple circles and draw path for them individually. I think it will be done soon but again, any advice would be nice)

@wave

In order to have multiple circles and paths for them to follow, you’ll have to change the code to add tables to keep track of the circle/dot values for each one and the calculations. For example, tab1 will have to be a multiple table. Instead of tab1[z], it will have to be tab1[nbr][z] where nbr will be the number for the different circles. Each time you touch the screen to draw the points, nbr will have to be incremented. Will the circles start moving as soon as you lift your finger, or will you draw multiple paths and then start the circles. Post if you have questions.

You should also look at using a tween library for smooth motion or clean the code up by writing a function.

Hi @aciolino

What or where is the tween library. A google search didn’t show anything useful, and it’s not mentioned in Codea. All of my coding is done on the iPad, so if it’s not in Codea, I can’t use it.

It will be in 1.5 release of Codea.

To .@dave1707

http://www.pcastuces.com/pratique/multimedia/photoshop/lasso.htm

The image pedro.bmp! Explains what I intend to do with this code.

I want to Draw any shape from anatomical images, from scintigraphic images or any other medical imaging file.

Thanks @Jmv38

Guess I should have skipped the Google search and did a forum search instead.

To @letaief

I guess you’re talking about a lasso tool that’s found in a lot of photo editors. Do you want something like that written in Codea or could you just download one of the free photo editors to do what you want.

I want it in Codea, if you remember I wrote in a previous post about ROI (region of interest) and you posted a code that I tried and worked but not as I needed, I let that in stand by and when I saw this post on path drawing I returned to this idea. I thought that the lasso is a French term thats why I didn’t use it. sorry for my bad English.

I can’t do multitouch and the code is not quite work. Can you help me fix it?


displayMode(FULLSCREEN)
function setup()   
    init()
end

function init()
    tab1={}
    offset = {}
    mx = {}
    my = {}
    dx = {}
    dy = {}
    move = {}
    mxi = {}
    myi = {}
    ptouch = {}
    insert = {}
    touches = {}
    for w = 1, 8 do
        tab1[w] = {}
        mxi[w] = 0
        myi[w] = 0
        move[w] = false
        offset[w] = 1
        dx[w] = 0
        dy[w] = 0
        ptouch[w] = false
        mx[w] = 50*w*2
        my[w] = 125
        insert[w] = false
    end
end

function draw()
    background(0, 0, 0, 255)
    fill(255, 255, 255, 255)
    for w = 1, 8 do
        local a; local b
        for z=offset[w]+1,#tab1[w] - 1 do
            stroke(255, 255, 255, 255)
            strokeWidth(3)
            if math.abs(tab1[w][1].x - mxi[w]) < 30 and math.abs(tab1[w][1].y - myi[w]) < 30 then
                ellipse(tab1[w][z-1].x,tab1[w][z-1].y,3)
            end
        end    
        if move[w] then -- try to move at constant speed
            a=math.sqrt(dx[w]*dx[w]+dy[w]*dy[w])
            b=5/a
            mx[w] = mx[w] + dx[w]*b
            my[w] = my[w] + dy[w]*b
            moveCircle(w)
        end     
        ellipse(mx[w],my[w],40,40)
    end
end

function calcDist() -- don't draw points within 20 of the previous point
    for w = 1,8 do
        local t=#tab1[w]
        local a; local b
        if t>1 then
            a=hx-tab1[w][t].x
            b=hy-tab1[w][t].y
            if a*a+b*b>400 then
                return true
            end
            return false
        end
    end
    return true
end

function touched(touch)
    if touch.state==BEGAN then
       -- touches[touch.id] = touch
        for w = 1, 8 do
            if touch.x > (mx[w] - 40) and touch.x < (mx[w] + 40) and
               touch.y > (my[w] - 40) and touch.y < (my[w] + 40) then
                    mxi[w] = touch.x
                    myi[w] = touch.y
                    ptouch[w] = true
            else ptouch[w] = false end       
        end
        
    elseif touch.state==MOVING then 
       -- touches[touch.id] = touch
        hx=touch.x
        hy=touch.y 
        if calcDist() then -- limit points in the table
            for w = 1, 8 do
                if ptouch[w] then
                    table.insert(tab1[w],vec2(touch.x,touch.y))    -- insert points in table
                    insert[w] = true
                end
            end
        end
 
    elseif touch.state==ENDED then
     --   touches[touch.id] = nil
        for w = 1, 8 do
            if insert[w] == true then        
                if math.abs(tab1[w][1].x - mx[w]) < 30 and 
                   math.abs(tab1[w][1].y - my[w]) < 30 then
                    move[w]=true
                    dx[w]=(tab1[w][offset[w]].x-mx[w])
                    dy[w]=(tab1[w][offset[w]].y-my[w])          
                else
                    return
                end
            end
        end
    end
end

function moveCircle(w)
    local a; local b; local ab
    if move[w] then
        if offset[w]==#tab1[w] then
            tab1[w] = {}
            offset[w]=1
            dx[w]=0
            dy[w]=0
            move[w]=false
            mxi[w] = 0
            myi[w] = 0
            insert[w] = false
            ptouch[w] = false
            return
        end
            a=math.abs(tab1[w][offset[w]].x-mx[w])
            b=math.abs(tab1[w][offset[w]].y-my[w])
            ab=math.sqrt(a*a+b*b)
        if ab<5 then
            offset[w] = offset[w] + 1
            dx[w]=tab1[w][offset[w]].x-mx[w]
            dy[w]=tab1[w][offset[w]].y-my[w]
        end
    end
end