A proof of concept on how to draw a line and have it act as a physical body. I owe MichaelAssadi a huge debt of gratitude for posting his example, it was what got me started.
The problem with other examples is that it basically draws a box at the intersection of each segment which I couldn't come up with a way of making it smooth. Also, as the move event fires (it looks like) every frame when drawing if you're swiping across the screen fast there are large gaps which objects may fall through (easy to do in Michael's example.)
I took inspiration from that and from the fact that you can use custom polygons to create physical bodies on a displayObject and am just laying a polygon on each segment. I think this should perform fairly well (would think as well as the boxes as it's just a 3-sided poly per segment and it gives 100% smooth coverage along the line. The one possible point of failure is that it is literally a flat poly, the poly is just (from line segment perspective) x1,y1 -> x2, y2 -> x1, y1. I can't imagine any cases where that would break but it's the biggest question about it in my mind. You could also have a problem if you have a fat line with the poly being it the middle. The interacting object won't "touch" until the center of the line (to see what I'm talking about set line_width = 25 or something. Could probably cheat this by doing radius on the ball's physics body but haven't played with it.
One way I'd like to try improving this if I get time to spend is to apply the smoothCurve (catmull splines) code that's being used in the Flight Path example. Anybody? Anybody? ; )
I'm not a neophyte developer but am new to Lua and Corona and did this very sloppy so forgive the lack of comments (should be fairly understandable though). Also, if anybody sees anything desperately wrong or has any style/code/design suggestions please let me know (you know, like mixing snake and camel case ; ).
NOTES:
There are two boxes on the bottom, the box on the left will drop a new ball (not collecting balls, so potential memory leak of seriously abused), and the box on the right will clear all lines.
The colors are the way they are because my 4 y/o daughter started playing with it on my iPad and I did that as a little treat for her.
It does seem to chug along pretty seriously at like the bottom of a U type curve and I haven't been able to figure that one out at all, any suggestions would be greatly appreciated. Set DrawMode to hybrid to see it clearly.
Thanks to all for sharing your code gems here and for any feedback and/or improvements!
Gerald
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | require("physics") physics.start() physics.setDrawMode("normal") local HEIGHT = display.contentHeight local WIDTH = display.contentWidth local lines = {} local line_number = 1 local line_width = 5 local prev_x, prev_y, ball local function draw_line(e) if e.phase == "began" then prev_x = e.x prev_y = e.y elseif e.phase == "moved" then lines[line_number] = display.newLine(prev_x, prev_y, e.x, e.y) lines[line_number]:setColor(math.random(255), math.random(255), math.random(255)) lines[line_number].width = line_width dist_x = e.x - prev_x dist_y = e.y - prev_y -- Add a physics body that's a flat polygon that follows each segment of the line physics.addBody(lines[line_number], "static", { density = 1, friction = 0.5, bounce = 0, shape = {0, 0, dist_x, dist_y, 0, 0} } ) prev_x = e.x prev_y = e.y line_number = line_number + 1 elseif e.phase == "ended" then end end new_ball_button = display.newRect(10, HEIGHT - 75, 150, 75) delete_lines_button = display.newRect(WIDTH - 150, HEIGHT - 75, 150, 75) -- Create a new ball function new_ball_button:touch(e) if e.phase == "ended" then ball = display.newCircle(50, 50, 25) physics.addBody(ball, {density = 5000, friction = 0.5, bounce = 0.1, radius = 25} ) ball:setFillColor(math.random(255), math.random(255), math.random(255)) end end -- Delete all existing lines function delete_lines_button:touch(e) if e.phase == "ended" then for i = #lines, 1, -1 do if (lines[i]) then lines[i].parent:remove(lines[i]) lines[i] = nil end end lines = {} line_number = 1 end end Runtime:addEventListener("touch", draw_line) new_ball_button:addEventListener("touch", new_ball_button) delete_lines_button:addEventListener("touch", delete_lines_button) |
Very impressive! You don't need to thank me, this was all you. Great job! You did far better ;)
I noticed the ball won't chug along if you are quick to draw out the line, if you cause little ripples then ya it chugs along.
I think the way I understand it is that every pixel of the line becomes a physics body or something. I know that's the case for a tool called "Svg level editor" by Karnakgames. He says if you free hand draw something in the svg inkscape program and it parses out the data, it will treat each pixel of the free hand drawing as it's own physics body.
I just noticed, bumping line_width from 5 to 100, it's "crosses" (best way I can describe it lol) that are close together being drawn across the screen, with a line going through the intersection.....interesting. I wish I had talent like this to do these amazing things!
ng
How would I remove the ball?
I don't quite understand the whole nil thing, so I know it's a function I create and to remove the ball.
Let's say I draw a line in a half circle and the ball is stuck, and I want to delete the ball along with the lines, how would that be done?
I was thinking about adding something to the
delete_lines_button but not entirely sure how to code that. That's due to being a noob though :)
Either case, my 2 week old boy likes the rainbow lines, ESPECIALLY WHEN I MAKE THEM 1 INCH THICK. lol.
ng
Ok, so I may not be able to write my OWN code to figure things out, but I was able to use the "Bridge" example to figure out how to insert it into this code.
Basically, an event listener is now on the ball so you can remove the ball. I suppose now that I think about it I should have added a button that removes the ball in case the ball falls out of sight (for memory I suppose). I'll let someone else handle that piece though :)
At least I can contribute something, even though I simply copied and pasted into the correct areas....that counts for something right :)?
ng
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | local physics = require("physics") local physics = require("physics") physics.start() physics.setPositionIterations(32) --"hybrid" "debug" "normal" physics.setDrawMode("hybrid") local HEIGHT = display.contentHeight local WIDTH = display.contentWidth local lines = {} local line_number = 1 local line_width = 10 local prev_x, prev_y, ball local function draw_line(e) if e.phase == "began" then prev_x = e.x prev_y = e.y elseif e.phase == "moved" then lines[line_number] = display.newLine(prev_x, prev_y, e.x, e.y) lines[line_number]:setColor(math.random(255), math.random(255), math.random(255)) lines[line_number].width = line_width dist_x = e.x - prev_x dist_y = e.y - prev_y -- Add a physics body that's a flat polygon that follows each segment of the line physics.addBody(lines[line_number], "static", { density = 1, friction = 0.1, bounce = 0, shape = {0, 0, dist_x, dist_y, 0, 0} } ) prev_x = e.x prev_y = e.y line_number = line_number + 1 elseif e.phase == "ended" then end end new_ball_button = display.newRect(10, HEIGHT - 75, 150, 75) delete_lines_button = display.newRect(WIDTH - 150, HEIGHT - 75, 150, 75) local removeBody = function( event ) local t = event.target local phase = event.phase if "began" == phase then t:removeSelf() -- destroy object end -- Stop further propagation of touch event return true end -- Create a new ball function new_ball_button:touch(e) if e.phase == "ended" then ball = display.newCircle(50, 300, 25) --ball = display.newImage ("blueball.png") physics.addBody(ball, {density = 5, friction = 100, bounce = 0.1, radius = 25} ) ball:setFillColor(math.random(255), math.random(255), math.random(255)) ball.IsBullet = true end ---+++++ ---CODE TO REMOVE BALL YAY!!!!! ball:addEventListener( "touch", removeBody ) -- assign touch listener to rock end -- Delete all existing lines function delete_lines_button:touch(e) if e.phase == "ended" then for i = #lines, 1, -1 do if (lines[i]) then lines[i].parent:remove(lines[i]) lines[i] = nil end end lines = {} line_number = 1 end end Runtime:addEventListener("touch", draw_line) new_ball_button:addEventListener("touch", new_ball_button) delete_lines_button:addEventListener("touch", delete_lines_button) |
I had to laugh while reading your comment :)
Finally as u did.. thats coding... just bring the right pieces together.. haha.
thats the way I create programs since 25 years /big smile/
all the best
greets chris
Very pretty lines, quick look at memory:
started at 84ish, rose to 360 after 10 seconds of drawing (yes I timed ;) ) and when lines were erased went down to 115, so yes. memory leak