Draw a line with physics

Does anyone know how to draw a curved line with physics. The only function I can find is here
http://developer.coronalabs.com/code/draw-line
But its not perfect because if the user draws the line too fast their will be gaping holes where objects will fall through. I have seen it done in a Corona game “Where’s my cheese” https://itunes.apple.com/us/app/wheres-my-cheese/id541582329?mt=8

And it seems to work perfect in this game can someone please help me achieve drawing the perfect line with physics?

Thank you
Russell [import]uid: 75779 topic_id: 32281 reply_id: 332281[/import]

Hi Russell,
This is tricky but not impossible. I think the way “Where’s my Cheese” accomplished it is by using a Corona “drawing method” (Runtime listener of plotting points as the user drags a finger around). Then, those points are used to lay down a whole series of physics objects (probably just little circles).

So, you can use a similar drawing method to plot a series of points, adding a new point as the user moves his/her finger around… and each point would be added to a table for later reference. BUT (important!) don’t plot a new point unless it’s sufficiently far enough from the previous point. If you simply plot points using a Runtime listener, you’ll end up with hundreds of overlapping points, and adding a physical object for each point would be both unnecessary and a performance killer.

You’re probably aware of this already, but Corona physics (Box2D, actually) can’t draw concave “lines” or shapes as physics objects. That’s why you need to plot your lines as a series of individual objects, and space them far enough apart to simulate a line, but not so far apart that other objects fall through the “line”.

Does this help?
Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128435[/import]

Yes thank you, I am using a similar method to what you speak: Runtime listener of plotting points as the user drags a finger around. My points are little rectangles. The problem is when the user swipes their finger very fast across the screen the Runtime listener will not catch the points in time and they will be spread out. You can see how it looks when you run the physics(hybrid) on it. I’m befuddled how “Where’s my Cheese” accomplished this as I have tried to make it not work on their game using super fast swipes, and it worked fine.

Perhaps you can alter this code (plug-and-play), try drawing a fast line and see how the dots spread out when looking at the physics(hybrid)

Thank you
[lua]–(Copy paste friendly)

– Try swiping mouse over simulator to produce random colored lines

– Starts physics

local physics = require (“physics”)
physics.start(true)
physics.setGravity(10, 0)
physics.setDrawMode(‘hybrid’)

– Ball rolls on Line

local ball = display.newCircle( 0, 0, 25)
ball:setFillColor(0, 255, 0)
ball.x = display.contentHeight/12
ball.y = display.contentWidth/4

physics.addBody(ball, {bounce=0.3, radius = 25, friction=0.5})

– Draw a line

local i = 1
local tempLine
local ractgangle_hit = {}
local prevX , prevY
local function runTouch(event)
if(event.phase==“began”) then
if(tempLine==nil) then
tempLine=display.newLine(event.x, event.y, event.x, event.y)

– Random Colors for line

r = math.random (0, 255)
g = math.random ( 0, 255)
b = math.random (0, 255 )
tempLine:setColor(r,g, b)

prevX = event.x
prevY = event.y
end
elseif(event.phase==“moved”) then
tempLine:append(event.x,event.y-2)
tempLine.width=tempLine.width+0.9
ractgangle_hit[i] = display.newLine(prevX, prevY, event.x, event.y)
ractgangle_hit[i]:setColor(r,g, b)
ractgangle_hit[i].width = 5

– Creates physic joints for line (Turn on draw mode to see the effects)

local Width = ractgangle_hit[i].width * 0.6
local Height = ractgangle_hit[i].height * 0.2

– Physic body for the line shape

local lineShape = {-Width,-Height,Width,-Height,Width,Height,-Width,Height}

physics.addBody(ractgangle_hit[i], “static”, { bounce = -1, density=0.3, friction=0.7, shape = lineShape})
prevX = event.x
prevY = event.y
i = i + 1
elseif(event.phase==“ended”) then
tempLine.parent.remove(tempLine)
tempLine=nil
end
end
Runtime:addEventListener(“touch”, runTouch)
[import]uid: 75779 topic_id: 32281 reply_id: 128447[/import]

Hi Russell,
Good point, I didn’t consider the fast swipe issue. I think I have a better idea though, somewhat related. You could use the “point reduction code” algorithm written by Carlos (formerly of Corona Labs) and then plot your points along the series of simplified points. In addition to automatically reducing the number of points along your screen-painted path (so you wouldn’t need to do it on the fly), it theoretically creates a smoother curve too.

I haven’t actually tried this or experimented with the code, I’ve only watched the video. Might be worth a shot!

http://www.coronalabs.com/blog/2010/12/29/corona-sdk-tutorial-polygon-point-reduction-with-curve-fitting/
http://developer.coronalabs.com/code/point-reduction-code-0

Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128539[/import]

Hi Russell,
This is tricky but not impossible. I think the way “Where’s my Cheese” accomplished it is by using a Corona “drawing method” (Runtime listener of plotting points as the user drags a finger around). Then, those points are used to lay down a whole series of physics objects (probably just little circles).

So, you can use a similar drawing method to plot a series of points, adding a new point as the user moves his/her finger around… and each point would be added to a table for later reference. BUT (important!) don’t plot a new point unless it’s sufficiently far enough from the previous point. If you simply plot points using a Runtime listener, you’ll end up with hundreds of overlapping points, and adding a physical object for each point would be both unnecessary and a performance killer.

You’re probably aware of this already, but Corona physics (Box2D, actually) can’t draw concave “lines” or shapes as physics objects. That’s why you need to plot your lines as a series of individual objects, and space them far enough apart to simulate a line, but not so far apart that other objects fall through the “line”.

Does this help?
Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128435[/import]

Yes thank you, I am using a similar method to what you speak: Runtime listener of plotting points as the user drags a finger around. My points are little rectangles. The problem is when the user swipes their finger very fast across the screen the Runtime listener will not catch the points in time and they will be spread out. You can see how it looks when you run the physics(hybrid) on it. I’m befuddled how “Where’s my Cheese” accomplished this as I have tried to make it not work on their game using super fast swipes, and it worked fine.

Perhaps you can alter this code (plug-and-play), try drawing a fast line and see how the dots spread out when looking at the physics(hybrid)

Thank you
[lua]–(Copy paste friendly)

– Try swiping mouse over simulator to produce random colored lines

– Starts physics

local physics = require (“physics”)
physics.start(true)
physics.setGravity(10, 0)
physics.setDrawMode(‘hybrid’)

– Ball rolls on Line

local ball = display.newCircle( 0, 0, 25)
ball:setFillColor(0, 255, 0)
ball.x = display.contentHeight/12
ball.y = display.contentWidth/4

physics.addBody(ball, {bounce=0.3, radius = 25, friction=0.5})

– Draw a line

local i = 1
local tempLine
local ractgangle_hit = {}
local prevX , prevY
local function runTouch(event)
if(event.phase==“began”) then
if(tempLine==nil) then
tempLine=display.newLine(event.x, event.y, event.x, event.y)

– Random Colors for line

r = math.random (0, 255)
g = math.random ( 0, 255)
b = math.random (0, 255 )
tempLine:setColor(r,g, b)

prevX = event.x
prevY = event.y
end
elseif(event.phase==“moved”) then
tempLine:append(event.x,event.y-2)
tempLine.width=tempLine.width+0.9
ractgangle_hit[i] = display.newLine(prevX, prevY, event.x, event.y)
ractgangle_hit[i]:setColor(r,g, b)
ractgangle_hit[i].width = 5

– Creates physic joints for line (Turn on draw mode to see the effects)

local Width = ractgangle_hit[i].width * 0.6
local Height = ractgangle_hit[i].height * 0.2

– Physic body for the line shape

local lineShape = {-Width,-Height,Width,-Height,Width,Height,-Width,Height}

physics.addBody(ractgangle_hit[i], “static”, { bounce = -1, density=0.3, friction=0.7, shape = lineShape})
prevX = event.x
prevY = event.y
i = i + 1
elseif(event.phase==“ended”) then
tempLine.parent.remove(tempLine)
tempLine=nil
end
end
Runtime:addEventListener(“touch”, runTouch)
[import]uid: 75779 topic_id: 32281 reply_id: 128447[/import]

Hi.

I’ve run into this with (UI) grids, too. What I do there is snap the end points each to a cell and then do a Bresenham line between those two cells.

See for example

Grid (Touch function)
Iterators (LineIter)

That code is pretty framework-heavy, but maybe you can get an idea from it. Anyhow, that might be a way to get some initial points (and then process them with Brent’s suggestion). Just assume some imaginary grid to fit against. [import]uid: 27791 topic_id: 32281 reply_id: 128564[/import]

Hi Russell,
Good point, I didn’t consider the fast swipe issue. I think I have a better idea though, somewhat related. You could use the “point reduction code” algorithm written by Carlos (formerly of Corona Labs) and then plot your points along the series of simplified points. In addition to automatically reducing the number of points along your screen-painted path (so you wouldn’t need to do it on the fly), it theoretically creates a smoother curve too.

I haven’t actually tried this or experimented with the code, I’ve only watched the video. Might be worth a shot!

http://www.coronalabs.com/blog/2010/12/29/corona-sdk-tutorial-polygon-point-reduction-with-curve-fitting/
http://developer.coronalabs.com/code/point-reduction-code-0

Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128539[/import]

@Brent Sorrentino @StarCrunch
Thank you for assistance I looked over your recommendations and unfortunateley I have no idea how to implement these codes or where to start if I wanted to change them. I tried adding physics to the point-reduction-code, and having less point equals less physics points

I’m suprised this has been so difficult to figure out. I’ve asked this question three times over the past month and you two have been the only ones to reply. The sad part is I know it can be done because I have seen it.

Thanks again for taking the time to help me.

Russell [import]uid: 75779 topic_id: 32281 reply_id: 128626[/import]

Hi Russell,

This might not help much, but if your curves don’t need to be “perfect”, you could just manually span the gap between two far-apart points with a calculated number of tween-points, and add bodies to them like the others.

For example, if the user quickly swipes the finger across and the Runtime listener picks up two points that are (for example) 2 inches apart on the screen, that’s obviously going to cause problems in your scenario. But you could inspect those two points, in code, and determine that they’re a certain distance apart by using a distance calculation that I can provide to you, if you don’t have one already.

With those two points known, you could then add in 4-5 (or 10-15, whatever) NEW points between them in a straight line. It wouldn’t be as perfect as a gradually-bending curve, but it might be all you need.

Brent [import]uid: 9747 topic_id: 32281 reply_id: 128653[/import]

Hi.

I’ve run into this with (UI) grids, too. What I do there is snap the end points each to a cell and then do a Bresenham line between those two cells.

See for example

Grid (Touch function)
Iterators (LineIter)

That code is pretty framework-heavy, but maybe you can get an idea from it. Anyhow, that might be a way to get some initial points (and then process them with Brent’s suggestion). Just assume some imaginary grid to fit against. [import]uid: 27791 topic_id: 32281 reply_id: 128564[/import]

@Brent Sorrentino @StarCrunch
Thank you for assistance I looked over your recommendations and unfortunateley I have no idea how to implement these codes or where to start if I wanted to change them. I tried adding physics to the point-reduction-code, and having less point equals less physics points

I’m suprised this has been so difficult to figure out. I’ve asked this question three times over the past month and you two have been the only ones to reply. The sad part is I know it can be done because I have seen it.

Thanks again for taking the time to help me.

Russell [import]uid: 75779 topic_id: 32281 reply_id: 128626[/import]

Hi Russell,

This might not help much, but if your curves don’t need to be “perfect”, you could just manually span the gap between two far-apart points with a calculated number of tween-points, and add bodies to them like the others.

For example, if the user quickly swipes the finger across and the Runtime listener picks up two points that are (for example) 2 inches apart on the screen, that’s obviously going to cause problems in your scenario. But you could inspect those two points, in code, and determine that they’re a certain distance apart by using a distance calculation that I can provide to you, if you don’t have one already.

With those two points known, you could then add in 4-5 (or 10-15, whatever) NEW points between them in a straight line. It wouldn’t be as perfect as a gradually-bending curve, but it might be all you need.

Brent [import]uid: 9747 topic_id: 32281 reply_id: 128653[/import]

Interesting I just looked at “Where’s my cheese” https://itunes.apple.com/us/app/wheres-my-cheese/id541582329?mt=8 and it looks like they use the same method of connecting a line to two dots points that are spread out over an area.
So we would need a function that measures the two dot points and then connects a “static line” to the points. Any ideas how to add that to above stated function? [import]uid: 75779 topic_id: 32281 reply_id: 128877[/import]

This is a valid point… instead of filling the “large gap” with several little rectangles, it makes much more sense (from a performance standpoint, and ease of coding) to just span the gap with one long rectangle.

Here’s how I would approach this scenario:

  1. on the touch “began” phase, you plot your first point and store it as a set of coordinates in a “holding table”
  2. as the touch “moved” phase goes, you constantly compare the touch location to the previous coordinate… always the LAST coordinate set in the table, so easy to reference
  3. ONLY if the touch is sufficiently far enough from the previous point (to avoid an absurd amount of overlap), you plot the next point AND add that coordinate to the holding table.
  4. when the line is complete, on phase “ended”, you then go through to add your physics bodies AND fill in the big gaps with rectangles.
  5. to accomplish that, you just loop through the table and compare two coordinate sets at a time in regards to their distance.
  6. if you find that two points are too far apart (big gap), you then use those two points to create a long rectangle that spans the gap. How? Let’s say you have a coordinate pair of 10,10 and 100,100…
local function distAngle( point1x, point1y, point2x, point2y )  
 local xFactor = point2x-point1x ; local yFactor = point2y-point1y  
 local dist = math.sqrt((xFactor\*xFactor) + (yFactor\*yFactor))  
 local angle = ( math.deg( math.atan2( yFactor, xFactor ) )+90 )  
 if ( angle \< 0 ) then angle = angle + 360 end ; angle = angle % 360  
 return dist,angle  
end  
  
--get distance and angle between the two points  
local thisDist,thisAngle = distAngle( 10,10,100,100 )  
if thisDist \>= ( 200 ) then --you must tweak this number!  
 --create a rectangle of size "thisDist" and whatever height you need  
 --MOVE the rectangle to the X/Y location BETWEEN the two points, using simple geometry  
 --ROTATE the rectangle to the "thisAngle" value, so it positions between the two points  
else  
 --just put a little square as a "point", since distance is acceptable  
end  

And basically, you just loop through the series of coordinates in this fashion. I hacked these functions together pretty fast using code from some of my current apps, and so they might need testing and adjustment, but I hope you see the basic method here.

Of course, it’s not the ONLY method, it’s just the way I’d tackle this scenario.

Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128880[/import]

Brent, that sounds promising! So what we want to do is have a function that finds any 2 points that are say “greater than” 1inch apart.

“With those two points known, you could then add in 4-5 (or 10-15, whatever) NEW points between them in a straight line. It wouldn’t be as perfect as a gradually-bending curve, but it might be all you need.”
–It doesnt need to be perfect at all, actually a line connecting the dots would work perfect because a ball will be rolling on it and it will look fine. As long as that line doesn’t let an object fall through.

So with that said I am unsure how to create a function that find any two points within the “draw a line” function I copied. Please take a look where the points are created
[lua]
– Draw a line

local i = 1
local tempLine
local ractgangle_hit = {}
local prevX , prevY
local function runTouch(event)

if(event.phase==“began”) then
if(tempLine==nil) then
tempLine=display.newLine(event.x, event.y, event.x, event.y)
prevX = event.x
prevY = event.y
end
elseif(event.phase==“moved”) then
tempLine:append(event.x,event.y-2)
tempLine.width=tempLine.width+0.9
ractgangle_hit[i] = display.newLine(prevX, prevY, event.x, event.y)
ractgangle_hit[i].width = 5

– Creates physic joints for line (Turn on draw mode to see the effects)

local Width = ractgangle_hit[i].width * 0.6
local Height = ractgangle_hit[i].height * 0.2

– Physic body for the line shape

local lineShape = {-Width,-Height,Width,-Height,Width,Height,-Width,Height}
physics.addBody(ractgangle_hit[i], “static”, { bounce = -1, density=0.3, friction=0.7, shape = lineShape})
prevX = event.x
prevY = event.y
i = i + 1

elseif(event.phase==“ended”) then
tempLine.parent.remove(tempLine)
tempLine=nil
end
end
Runtime:addEventListener(“touch”, runTouch)[/lua]

Thanks for the help!

Russell [import]uid: 75779 topic_id: 32281 reply_id: 128755[/import]

Thanks for the assistance i understand your logic, but I don’t understand how the function works so I have no idea how to implement it into the “draw a line” function I am using. So basically I need to add your function to this function:

[lua]-- Draw a line

local i = 1
local tempLine
local ractgangle_hit = {}
local prevX , prevY
local function runTouch(event)

if(event.phase==“began”) then
if(tempLine==nil) then
tempLine=display.newLine(event.x, event.y, event.x, event.y)
prevX = event.x
prevY = event.y
end

elseif(event.phase==“moved”) then
tempLine:append(event.x,event.y-2)
tempLine.width=tempLine.width+0.9
ractgangle_hit[i] = display.newLine(prevX, prevY, event.x, event.y)
ractgangle_hit[i].width = 5

– Creates physic joints for line (Turn on draw mode to see the effects)

local Width = ractgangle_hit[i].width * 0.6
local Height = ractgangle_hit[i].height * 0.2

– Physic body for the line shape

local lineShape = {-Width,-Height,Width,-Height,Width,Height,-Width,Height}
physics.addBody(ractgangle_hit[i], “static”, { bounce = -1, density=0.3, friction=0.7, shape = lineShape})
prevX = event.x
prevY = event.y
i = i + 1

elseif(event.phase==“ended”) then
tempLine.parent.remove(tempLine)
tempLine=nil
end
end
Runtime:addEventListener(“touch”, runTouch)[/lua]

Any assistance on how to combine these two functions into 1 working function will be much appreciated! [import]uid: 75779 topic_id: 32281 reply_id: 128953[/import]

Interesting I just looked at “Where’s my cheese” https://itunes.apple.com/us/app/wheres-my-cheese/id541582329?mt=8 and it looks like they use the same method of connecting a line to two dots points that are spread out over an area.
So we would need a function that measures the two dot points and then connects a “static line” to the points. Any ideas how to add that to above stated function? [import]uid: 75779 topic_id: 32281 reply_id: 128877[/import]

This is a valid point… instead of filling the “large gap” with several little rectangles, it makes much more sense (from a performance standpoint, and ease of coding) to just span the gap with one long rectangle.

Here’s how I would approach this scenario:

  1. on the touch “began” phase, you plot your first point and store it as a set of coordinates in a “holding table”
  2. as the touch “moved” phase goes, you constantly compare the touch location to the previous coordinate… always the LAST coordinate set in the table, so easy to reference
  3. ONLY if the touch is sufficiently far enough from the previous point (to avoid an absurd amount of overlap), you plot the next point AND add that coordinate to the holding table.
  4. when the line is complete, on phase “ended”, you then go through to add your physics bodies AND fill in the big gaps with rectangles.
  5. to accomplish that, you just loop through the table and compare two coordinate sets at a time in regards to their distance.
  6. if you find that two points are too far apart (big gap), you then use those two points to create a long rectangle that spans the gap. How? Let’s say you have a coordinate pair of 10,10 and 100,100…
local function distAngle( point1x, point1y, point2x, point2y )  
 local xFactor = point2x-point1x ; local yFactor = point2y-point1y  
 local dist = math.sqrt((xFactor\*xFactor) + (yFactor\*yFactor))  
 local angle = ( math.deg( math.atan2( yFactor, xFactor ) )+90 )  
 if ( angle \< 0 ) then angle = angle + 360 end ; angle = angle % 360  
 return dist,angle  
end  
  
--get distance and angle between the two points  
local thisDist,thisAngle = distAngle( 10,10,100,100 )  
if thisDist \>= ( 200 ) then --you must tweak this number!  
 --create a rectangle of size "thisDist" and whatever height you need  
 --MOVE the rectangle to the X/Y location BETWEEN the two points, using simple geometry  
 --ROTATE the rectangle to the "thisAngle" value, so it positions between the two points  
else  
 --just put a little square as a "point", since distance is acceptable  
end  

And basically, you just loop through the series of coordinates in this fashion. I hacked these functions together pretty fast using code from some of my current apps, and so they might need testing and adjustment, but I hope you see the basic method here.

Of course, it’s not the ONLY method, it’s just the way I’d tackle this scenario.

Brent
[import]uid: 9747 topic_id: 32281 reply_id: 128880[/import]

Brent, that sounds promising! So what we want to do is have a function that finds any 2 points that are say “greater than” 1inch apart.

“With those two points known, you could then add in 4-5 (or 10-15, whatever) NEW points between them in a straight line. It wouldn’t be as perfect as a gradually-bending curve, but it might be all you need.”
–It doesnt need to be perfect at all, actually a line connecting the dots would work perfect because a ball will be rolling on it and it will look fine. As long as that line doesn’t let an object fall through.

So with that said I am unsure how to create a function that find any two points within the “draw a line” function I copied. Please take a look where the points are created
[lua]
– Draw a line

local i = 1
local tempLine
local ractgangle_hit = {}
local prevX , prevY
local function runTouch(event)

if(event.phase==“began”) then
if(tempLine==nil) then
tempLine=display.newLine(event.x, event.y, event.x, event.y)
prevX = event.x
prevY = event.y
end
elseif(event.phase==“moved”) then
tempLine:append(event.x,event.y-2)
tempLine.width=tempLine.width+0.9
ractgangle_hit[i] = display.newLine(prevX, prevY, event.x, event.y)
ractgangle_hit[i].width = 5

– Creates physic joints for line (Turn on draw mode to see the effects)

local Width = ractgangle_hit[i].width * 0.6
local Height = ractgangle_hit[i].height * 0.2

– Physic body for the line shape

local lineShape = {-Width,-Height,Width,-Height,Width,Height,-Width,Height}
physics.addBody(ractgangle_hit[i], “static”, { bounce = -1, density=0.3, friction=0.7, shape = lineShape})
prevX = event.x
prevY = event.y
i = i + 1

elseif(event.phase==“ended”) then
tempLine.parent.remove(tempLine)
tempLine=nil
end
end
Runtime:addEventListener(“touch”, runTouch)[/lua]

Thanks for the help!

Russell [import]uid: 75779 topic_id: 32281 reply_id: 128755[/import]