I need the player to draw a straight line with limited length

I need the person who is playing to be able to draw a straight line (with limited length) on the screen. Any idea on how I can do that?
Thanks [import]uid: 188277 topic_id: 34907 reply_id: 334907[/import]

Record the X, Y at the start of a touch event. During the ended phase, draw the line. You will probably need to compute the line length using simple right angle triangle math and if it’s going to be too long, do whatever you need to do if it’s too long:

dx = current.x - start.x  
dy = current.y - start.y  
line\_length = math.sqrt(dx\*dx+dy\*dy)  

[import]uid: 199310 topic_id: 34907 reply_id: 138740[/import]

Here is something I used in a project of mine. Hopefully it’s helpful in some way!

[code]local cw = display.contentWidth
local ch = display.contentHeight
local bg = display.newRect(0, 0, cw, ch)
bg:setFillColor(25,25,25)

local lineLengthConstraint = 128

local function checkLineLength(line)
local x = (line.contentBounds.xMax-2) - (line.contentBounds.xMin+2)
local y = (line.contentBounds.yMax-2) - (line.contentBounds.yMin+2)
local length = math.sqrt(x*x + y*y)
return length
end

local function drawLine(event)

if event.phase == “began” then

– inTouch state.

inTouch = true

– X/Y Coordinates of initial touch.

initialX = event.x
initialY = event.y

– Create Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Create Line #2, using the length and rotation of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8
line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “moved” and inTouch then

– Remove old Line #1.

display.remove(line1)
line1 = nil

– Create new Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Recreate Line #2, in the case that Line #1 is shorter than the length constraint.

if checkLineLength(line1) <= lineLengthConstraint then

– Remove old Line #2.

display.remove(line2)
line2 = nil

– Create new Line #2, using the length of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8

end

– Set rotation of Line #2.

line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “ended” and inTouch then

– inTouch state.

inTouch = false

– Custom code here?

– ???
– ???
– ???

– Remove all lines.

display.remove(line1)
line1 = nil

display.remove(line2)
line2 = nil

end

end

Runtime:addEventListener(“touch”, drawLine)[/code] [import]uid: 12217 topic_id: 34907 reply_id: 138795[/import]

Though I don’t normally like being spoon-fed code, it’s nice to see something like this every now and then. This is very helpful! Thanks! [import]uid: 188277 topic_id: 34907 reply_id: 138849[/import]

Well, I fixed most of the problems, but when the program starts, I am unable to draw lines. Everything else seems to be fine, though.

[code]
local physics = require(“physics”)
physics.start()

physics.setScale( 60 )

physics.setGravity(0, 10)

display.setStatusBar( display.HiddenStatusBar )

local background = display.newImage( “images/clouds.png”, true )

– Create player and set location
local player = display.newImage(“images/fred.png”)
player.x = display.contentWidth / 2
player.y = display.contentHeight / 3

– Turn player into physics body
physics.addBody(player)

– Create walls on the left and right
local leftWall = display.newRect (0, 0, 1, display.contentHeight);
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight);

– Add physics to the walls. (static)
physics.addBody (leftWall, “static”, { bounce = 0.1 } );
physics.addBody (rightWall, “static”, { bounce = 0.1 } );

local cw = display.contentWidth
local ch = display.contentHeight
local lineLengthConstraint = 128

local function checkLineLength(line)
local x = (line.contentBounds.xMax-2) - (line.contentBounds.xMin+2)
local y = (line.contentBounds.yMax-2) - (line.contentBounds.yMin+2)
local length = math.sqrt(x*x + y*y)
return length
end
local function drawLine(event)

Runtime:addEventListener(“touch”, drawLine)

if event.phase == “began” then

– inTouch state.

inTouch = true

– X/Y Coordinates of initial touch.

initialX = event.x
initialY = event.y

– Create Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Create Line #2, using the length and rotation of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8
line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “moved” and inTouch then

– Remove old Line #1.

display.remove(line1)
line1 = nil

– Create new Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Recreate Line #2, in the case that Line #1 is shorter than the length constraint.

if checkLineLength(line1) <= lineLengthConstraint then

– Remove old Line #2.

display.remove(line2)
line2 = nil

– Create new Line #2, using the length of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8

end

– Set rotation of Line #2.

line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “ended” and inTouch then

– inTouch state.

inTouch = false

– Remove all lines.

display.remove(line1)
line1 = nil

display.remove(line2)
line2 = nil

end

end [import]uid: 188277 topic_id: 34907 reply_id: 138925[/import]

On line 40 you’ve placed the runtime listener for the drawLine function inside of the drawLine function, when it should actually be below it. If you cut and paste line 40 to line 120 you will be able to draw lines again! :slight_smile: [import]uid: 12217 topic_id: 34907 reply_id: 138936[/import]

It works! :slight_smile: Thanks for all your help! [import]uid: 188277 topic_id: 34907 reply_id: 138940[/import]

Actually, I have one more problem: I notice that as the line is drawn, once the “colored” part of the line is past its limited length, there is still a thin, grayish line that does not have a limited length. At first it was no problem, but when I set the draw mode to hybrid, I saw two things:

  1. The area that the character can collide with is actually not limited; I think this is because of that grayish line. (as I’m looking at it more, I don’t think that’s the case)

  2. If I draw the line diagonally, the area for collision is… uh… it’s not very easy to explain this… here’s a picture:

http://imgur.com/LPdje [import]uid: 188277 topic_id: 34907 reply_id: 138945[/import]

Can you post the latest version of your code so I can take a look? [import]uid: 12217 topic_id: 34907 reply_id: 138948[/import]

[code]
local physics = require(“physics”)
physics.start()

– physics.setDrawMode(“hybrid”)

physics.setScale( 60 )

physics.setGravity(0, 10)

display.setStatusBar( display.HiddenStatusBar )

local background = display.newImage( “images/clouds.png”, true )

– Create player and set location
local player = display.newImage(“images/fred.png”)
player.x = display.contentWidth / 2
player.y = display.contentHeight / 3

– Turn player into physics body
physics.addBody(player, { radius = 30 } );

– Create walls on the left and right
local leftWall = display.newRect (0, 0, 1, display.contentHeight);
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight);

– Add physics to the walls. They will not move so they will be static
physics.addBody (leftWall, “static”, { bounce = 0.1 } );
physics.addBody (rightWall, “static”, { bounce = 0.1 } );

local cw = display.contentWidth
local ch = display.contentHeight
local lineLengthConstraint = 128

local function checkLineLength(line)
local x = (line.contentBounds.xMax-2) - (line.contentBounds.xMin+2)
local y = (line.contentBounds.yMax-2) - (line.contentBounds.yMin+2)
local length = math.sqrt(x*x + y*y)
return length
end
local function drawLine(event)

if event.phase == “began” then

– inTouch state.

inTouch = true

– X/Y Coordinates of initial touch.

initialX = event.x
initialY = event.y

– Create Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Create Line #2, using the length and rotation of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8
line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “moved” and inTouch then

– Remove old Line #1.

display.remove(line1)
line1 = nil

– Create new Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Recreate Line #2, in the case that Line #1 is shorter than the length constraint.

if checkLineLength(line1) <= lineLengthConstraint then

– Remove old Line #2.

display.remove(line2)
line2 = nil

– Create new Line #2, using the length of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8

end

– Set rotation of Line #2.

line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “ended” and inTouch then

– inTouch state.

inTouch = false

– Custom code here?

physics.addBody(line1, “static”, { bounce = 1.0 } );
physics.addBody(line2, “static”, { bounce = 1.0 } );

– Remove all lines.

end

end
Runtime:addEventListener(“touch”, drawLine) [import]uid: 188277 topic_id: 34907 reply_id: 138949[/import]

Ok, I’ve fixed the problems, and improved the code at the same time (I realized there’s no need for the thin gray line at all).

The problem with the physics body being offset from the limited length line was fixed by creating a custom physics shape using the width and length of the line.

Also, if you want the physics body to be added to the line while it’s being drawn, uncomment lines 83 and 84 and comment lines 100 and 101.

Here is the updated code:

[code]local physics = require(“physics”)
physics.start()

physics.setDrawMode(“hybrid”)

physics.setScale( 60 )

physics.setGravity(0, 10)

display.setStatusBar( display.HiddenStatusBar )

local background = display.newImage( “images/clouds.png”, true )

– Create player and set location
local player = display.newImage(“images/fred.png”)
player.x = display.contentWidth / 2
player.y = display.contentHeight / 3

– Turn player into physics body
physics.addBody(player, { radius = 30 } );

– Create walls on the left and right
local leftWall = display.newRect (0, 0, 1, display.contentHeight);
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight);

– Add physics to the walls. They will not move so they will be static
physics.addBody (leftWall, “static”, { bounce = 0.1 } );
physics.addBody (rightWall, “static”, { bounce = 0.1 } );

local lineLengthConstraint = 128
local lines = {}

local function getLength(x1, x2, y1, y2)
local x = x1 - x2
local y = y1 - y2
local length = math.sqrt(x*x + y*y)
return length
end

local function drawLine(event)

if event.phase == “began” then

– inTouch state.

inTouch = true

– X/Y Coordinates of initial touch.

initialX = event.x
initialY = event.y

– Create our line.

ourLine = display.newLine(initialX, initialY, initialX, initialY+getLength(initialX, event.x, initialY, event.y))
ourLine:setColor(0,255,0)
ourLine.width = 8
ourLine.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “moved” and inTouch then

– Recreate our line, in the case that it is shorter than the length constraint.

if getLength(initialX, event.x, initialY, event.y) <= lineLengthConstraint then

– Remove old version of our line.

display.remove(ourLine)
ourLine = nil

– Create new version of our line.

ourLine = display.newLine(initialX, initialY, initialX, initialY+getLength(initialX, event.x, initialY, event.y))
ourLine:setColor(0,255,0)
ourLine.width = 8

– Store limited line length.

limitedLineLength = getLength(initialX, event.x, initialY, event.y)

– Physics

–local physShape = { (ourLine.width/2),0, (ourLine.width/2),limitedLineLength, -(ourLine.width/2),limitedLineLength, -(ourLine.width/2),0 }
–physics.addBody(ourLine, “static”, {bounce=1.0, shape=physShape})

end

– Set rotation of our line.

ourLine.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “ended” and inTouch then

– inTouch state.

inTouch = false

– Physics

local physShape = { (ourLine.width/2),0, (ourLine.width/2),limitedLineLength, -(ourLine.width/2),limitedLineLength, -(ourLine.width/2),0 }
physics.addBody(ourLine, “static”, {bounce=1.0, shape=physShape})

– Store our line in a table, just in case we need to reference or remove it later.

lines[#lines+1] = ourLine

end

end

Runtime:addEventListener(“touch”, drawLine)[/code]

I hope this helps! [import]uid: 12217 topic_id: 34907 reply_id: 138953[/import]

I’m not home yet, but I will get back to it shortly. Thanks! In the mean time, I have one more question: how can I make it so that only one line can be on the screen at a time?
Thanks! [import]uid: 188277 topic_id: 34907 reply_id: 139051[/import]

[Double post, sorry] [import]uid: 188277 topic_id: 34907 reply_id: 139052[/import]

Well, I was trying to make it so that only one appears at a time, but it wasn’t working. I was using group.numChildren() method. I’m stuck:

[code]
– table
lines[#lines+1] = ourLine

– insert ourLine into a new group that I created
local group = display.newGroup()
group:insert( ourLine )
– find number of lines and store it in count
local count = group.numChildren()
– if there is more than one line, remove that extra line
if (count > 1) then
display.remove(ourLine)
ourLine = nil
else
– do nothing
end [import]uid: 188277 topic_id: 34907 reply_id: 139115[/import]

No need for a group! :slight_smile: I suspected that you might want to reference / remove the lines at some point, which is why I added the table in the last version of the code. Here is some code which will remove the line if the player draws more than one:

[code]-- Remove line from the screen when there’s one or more stored in the table.

if #lines >= 1 then
for i=1,#lines do
display.remove(lines[i])
lines[i] = nil
end
end

– Store our line in a table.

lines[#lines+1] = ourLine[/code]

Replace line 105 in the last code block I posted with this new code. Hope that helps! [import]uid: 12217 topic_id: 34907 reply_id: 139120[/import]

That’s perfect! Thanks for all your help. I really appreciate it! That’s all the help I need. Thank you! :slight_smile: [import]uid: 188277 topic_id: 34907 reply_id: 139160[/import]

No problem. I’m glad I was able to assist! :slight_smile: [import]uid: 12217 topic_id: 34907 reply_id: 139171[/import]

Record the X, Y at the start of a touch event. During the ended phase, draw the line. You will probably need to compute the line length using simple right angle triangle math and if it’s going to be too long, do whatever you need to do if it’s too long:

dx = current.x - start.x  
dy = current.y - start.y  
line\_length = math.sqrt(dx\*dx+dy\*dy)  

[import]uid: 199310 topic_id: 34907 reply_id: 138740[/import]

Here is something I used in a project of mine. Hopefully it’s helpful in some way!

[code]local cw = display.contentWidth
local ch = display.contentHeight
local bg = display.newRect(0, 0, cw, ch)
bg:setFillColor(25,25,25)

local lineLengthConstraint = 128

local function checkLineLength(line)
local x = (line.contentBounds.xMax-2) - (line.contentBounds.xMin+2)
local y = (line.contentBounds.yMax-2) - (line.contentBounds.yMin+2)
local length = math.sqrt(x*x + y*y)
return length
end

local function drawLine(event)

if event.phase == “began” then

– inTouch state.

inTouch = true

– X/Y Coordinates of initial touch.

initialX = event.x
initialY = event.y

– Create Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Create Line #2, using the length and rotation of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8
line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “moved” and inTouch then

– Remove old Line #1.

display.remove(line1)
line1 = nil

– Create new Line #1.

line1 = display.newLine(initialX, initialY, event.x, event.y)
line1.width = 1
line1.alpha = 0.25
–line1.isVisible = false

– Recreate Line #2, in the case that Line #1 is shorter than the length constraint.

if checkLineLength(line1) <= lineLengthConstraint then

– Remove old Line #2.

display.remove(line2)
line2 = nil

– Create new Line #2, using the length of Line #1.

line2 = display.newLine(initialX, initialY, initialX, initialY+checkLineLength(line1))
line2:setColor(0,255,0)
line2.width = 8

end

– Set rotation of Line #2.

line2.rotation = math.deg(math.atan2(event.y - initialY, event.x - initialX)) - 90

elseif event.phase == “ended” and inTouch then

– inTouch state.

inTouch = false

– Custom code here?

– ???
– ???
– ???

– Remove all lines.

display.remove(line1)
line1 = nil

display.remove(line2)
line2 = nil

end

end

Runtime:addEventListener(“touch”, drawLine)[/code] [import]uid: 12217 topic_id: 34907 reply_id: 138795[/import]

Though I don’t normally like being spoon-fed code, it’s nice to see something like this every now and then. This is very helpful! Thanks! [import]uid: 188277 topic_id: 34907 reply_id: 138849[/import]