problem with angle and a line

hi,

I would like to direct a line according to event.

The problem is that in specific directions the angle is 180 ° opposite

you have an idea on the right mathematical formula ?

except put full conditions like :

if event.y > line.y then

angle-90
else

angle+90

end

I do not see how else

function getAngle(x1,y1,x2,y2) local PI = 3.14159265358 local deltaY = y2 - y1 local deltaX = x2 - x1 local angleInDegrees = (((math.atan2(deltaY, deltaX) \* 180)/ PI)+360)%360 local mult = 10^0 return math.floor(angleInDegrees \* mult + 0.5) / mult end local line = display.newRect(0,0,20,500) line:setFillColor(1,0,0) line.x = display.contentWidth/2 line.y = display.contentHeight/2 line.anchorY=1 Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local angle = getAngle(c.x,c.y,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

Hey espace3d,

I’m not sure where the mistake in your code is, “math.atan2” should work fine for getting the angle?

I used this code and I get pretty accurate angles:

function getAngle(x1,y1,x2,y2) local radAngle = math.atan2(y2 - y1, x2 - x1) return math.deg(radAngle) end

I’m not sure what the rest of your function is for (math.floor, mult etc.).

Is it possible, that the c.x, c.y and event.x, event.y are not in the same content space?

Maybe you could convert the values with “localToContent” first?

hi thanks ,

Your soluce works with math.atan and it’s more simple than mult… :slight_smile:

But the problem is what you have mentionned with localToContent.

I try this but that don’t works…still the problem of the opposite direction :

--in my game c.body is from --local player={} --local player\_mt = {\_\_index =player } --function player.draw(group,posx,posy,radius) --local c = {} --c.body=display.newCircle(group,posx,posy,radius) -- .... Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then xt,yt=c.body:localToContent(c.body.x,c.body.y) local angle = getAngle(xt,yt,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

i don’t understand really the usage of localToContent …

Hey,

would you try this:

 xt,yt = c.body:localToContent(0,0)

hi,

It’s the same.

maybe this explanation could help you :

The first time while my players is moving the function works always but after 3 or 5 times the direction is opposite

@espace3d

What does the line indicate?

I tried this, with it anchored on the player:

function getAngle(x1,y1,x2,y2) local PI = 3.14159265358 local deltaY = y2 - y1 local deltaX = x2 - x1 local angleInDegrees = (((math.atan2(deltaY, deltaX) \* 180)/ PI)+360)%360 local mult = 10^0 return math.floor(angleInDegrees \* mult + 0.5) / mult end local c = display.newCircle(240, 80, 20) -- "player" at some position local line = display.newRect(0,0,20,500) line:setFillColor(1,0,0) line.x = c.x--display.contentWidth/2 line.y = c.y--display.contentHeight/2 line.anchorY=1 Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = c:localToContent(0, 0) local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

Seems like reasonable behavior to me.

If you do a

line.x, line.y = xt, yt

when setting line.rotation , does it look right?

hi both,

i have re-tested with a simpliest example and the same structure of my game and …it works perfectly in this case.

i have an error in my file and it will be hard to find where the error lies because my file is very big :slight_smile:

here the simpliest snippet :

--background.lua local background={} local background\_mt = { \_\_index = background } --set metatable -------------------------------------------------------------------------------- -- public function -------------------------------------------------------------------------------- function background.draw( posx,posy,x,y ) local e={} --e for backgroundlua e.body=display.newRect(posx,posy,x,y) e.body:setFillColor(1,0,0) return setmetatable ( e,background\_mt ) end return background -------------------------------------------------------------------- --player.lua local player={} local player\_mt = { \_\_index = player } --set metatable -------------------------------------------------------------------------------- -- public function -------------------------------------------------------------------------------- function player.draw( posx,posy,radius ) local e={} --e for playerlua e.body=display.newCircle(posx,posy,radius) line=display.newRect(50,50,2,200) line:setFillColor(1,1,1) line.anchorY=1 function playerInMovement() xposMov=math.random(0,400) yposMov=math.random(0,400) transition.to(e.body, {time=900,x=xposMov,y=yposMov}) transition.to(e.body, {delay=900,time=400,x=50,y=50}) end timer.performWithDelay(1800,playerInMovement,-1) function getAngle(x1,y1,x2,y2) local Angle= math.atan2(y2 - y1, x2 - x1) return math.deg(Angle) end Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = e.body:localToContent(0, 0) line.x=cx line.y=cy local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end) return setmetatable ( e,player\_mt ) end return player -------------------------------------------------------------------- --main.lua local player=require("player") local background=require("background") local players={} backgrounds=background.draw(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight) players= player.draw(200,200,15) --------------------------------------------------------------------------------------------------------------

hi,

I isolated the function causing the problem but i don’t understand why this function +getangle() don’t work …have you an idea ?

 e.touch=function(ev) if ev.phase == "began" then previousTime=ev.time myTimer=timer.performWithDelay(2000, e.energy, -1) e.indicate(ev) elseif ev.phase=="moved" then timeMiddle = ev.time-previousTime elseif ev.phase == "ended" then line.alpha=0 timer.cancel(myTimer) timePassed=ev.time-previousTime if timePassed \> 200 then lineardamping=30-timePassed/40 force=timePassed\*10000000000 else lineardamping=0 end e.body.linearDamping=lineardamping e.body:applyForce(((ev.x - e.body.x )\*force), ((ev.y-e.body.y)\*force),e.body.x,e.body.y) end e.body:applyForce(((ev.x - e.body.x )\*50), ((ev.y-e.body.y)\*50),e.body.x,e.body.y) end

What happens if you add a

return true 

at the end of the function? I guess it’s superfluous for a Runtime listener, but if your object, e , doesn’t trap the touch, the catch-all one will also fire. I don’t know if this will lead to the problem you’re seeing, but it’s worth a try.

no it’s the same and it’s worse at the angle of interpretation by GetAngle :unsure:

yes !

It becomes clearer. When i comment the function (e.indicate) in the snippet below.

e.touch=function(ev) if ev.phase == "began" then previousTime=ev.time myTimer=timer.performWithDelay(2000, e.energy, -1) --e.indicate(ev) elseif ev.phase=="moved" then timeMiddle = ev.time-previousTime elseif ev.phase == "ended" then line.alpha=0 timer.cancel(myTimer) timePassed=ev.time-previousTime if timePassed \> 200 then lineardamping=30-timePassed/40 force=timePassed\*10000000000 else lineardamping=0 end e.body.linearDamping=lineardamping e.body:applyForce(((ev.x - e.body.x )\*force), ((ev.y-e.body.y)\*force),e.body.x,e.body.y) end end

It work perfectly !

What i don’t understand is why this function prevents my code run ? have you an idea about that ?

Thanks

 e.indicate=function(ev) line.alpha=0 lineY=ev.y value=lineY-line.y transition.to(line, {time=500,yScale=value,alpha=.5}) end

here is an example that you could test at home

i would in effect scale a line according to the position of event and orientate the line according to the event.

the problem i when i add these line, my function getAngle don’t work properly…could you tell me why

line.yScale=event.y-cy

the snippet :

--main.lua local player={} player.body=display.newCircle(200,200,10) line=display.newRect(50,50,2,2) --line who the begin is the player and the end is the event line:setFillColor(1,1,1) line.anchorY=1 function playerInMovement() xposMov=math.random(0,400) yposMov=math.random(0,400) transition.to(player.body, {time=900,x=xposMov,y=yposMov}) transition.to(player.body, {delay=900,time=400,x=50,y=50}) end timer.performWithDelay(1800,playerInMovement,-1) function getAngle(x1,y1,x2,y2) local Angle= math.atan2(y2 - y1, x2 - x1) return math.deg(Angle) end Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = player.body:localToContent(0, 0) line.x=cx line.y=cy line.yScale=event.y-cy local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

Finded ! if this could help somebody :slight_smile:

this was simple…yScale could be positive or negative depending of event !

local player={} player.body=display.newCircle(200,200,10) line=display.newRect(50,50,2,2) line:setFillColor(1,1,1) line.anchorY=1 function playerInMovement() xposMov=math.random(0,400) yposMov=math.random(0,400) transition.to(player.body, {time=900,x=xposMov,y=yposMov}) transition.to(player.body, {delay=900,time=400,x=50,y=50}) end timer.performWithDelay(1800,playerInMovement,-1) function getAngle(x1,y1,x2,y2) local Angle= math.atan2(y2 - y1, x2 - x1) return math.deg(Angle) end Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = player.body:localToContent(0, 0) local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 line.x=cx line.y=cy if event.y \> line.y then line.yScale=event.y-cy else line.yScale=cy-event.y end elseif event.phase == "ended" then end end)

Hey espace3d,

I’m not sure where the mistake in your code is, “math.atan2” should work fine for getting the angle?

I used this code and I get pretty accurate angles:

function getAngle(x1,y1,x2,y2) local radAngle = math.atan2(y2 - y1, x2 - x1) return math.deg(radAngle) end

I’m not sure what the rest of your function is for (math.floor, mult etc.).

Is it possible, that the c.x, c.y and event.x, event.y are not in the same content space?

Maybe you could convert the values with “localToContent” first?

hi thanks ,

Your soluce works with math.atan and it’s more simple than mult… :slight_smile:

But the problem is what you have mentionned with localToContent.

I try this but that don’t works…still the problem of the opposite direction :

--in my game c.body is from --local player={} --local player\_mt = {\_\_index =player } --function player.draw(group,posx,posy,radius) --local c = {} --c.body=display.newCircle(group,posx,posy,radius) -- .... Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then xt,yt=c.body:localToContent(c.body.x,c.body.y) local angle = getAngle(xt,yt,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

i don’t understand really the usage of localToContent …

Hey,

would you try this:

 xt,yt = c.body:localToContent(0,0)

hi,

It’s the same.

maybe this explanation could help you :

The first time while my players is moving the function works always but after 3 or 5 times the direction is opposite

@espace3d

What does the line indicate?

I tried this, with it anchored on the player:

function getAngle(x1,y1,x2,y2) local PI = 3.14159265358 local deltaY = y2 - y1 local deltaX = x2 - x1 local angleInDegrees = (((math.atan2(deltaY, deltaX) \* 180)/ PI)+360)%360 local mult = 10^0 return math.floor(angleInDegrees \* mult + 0.5) / mult end local c = display.newCircle(240, 80, 20) -- "player" at some position local line = display.newRect(0,0,20,500) line:setFillColor(1,0,0) line.x = c.x--display.contentWidth/2 line.y = c.y--display.contentHeight/2 line.anchorY=1 Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = c:localToContent(0, 0) local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end)

Seems like reasonable behavior to me.

If you do a

line.x, line.y = xt, yt

when setting line.rotation , does it look right?

hi both,

i have re-tested with a simpliest example and the same structure of my game and …it works perfectly in this case.

i have an error in my file and it will be hard to find where the error lies because my file is very big :slight_smile:

here the simpliest snippet :

--background.lua local background={} local background\_mt = { \_\_index = background } --set metatable -------------------------------------------------------------------------------- -- public function -------------------------------------------------------------------------------- function background.draw( posx,posy,x,y ) local e={} --e for backgroundlua e.body=display.newRect(posx,posy,x,y) e.body:setFillColor(1,0,0) return setmetatable ( e,background\_mt ) end return background -------------------------------------------------------------------- --player.lua local player={} local player\_mt = { \_\_index = player } --set metatable -------------------------------------------------------------------------------- -- public function -------------------------------------------------------------------------------- function player.draw( posx,posy,radius ) local e={} --e for playerlua e.body=display.newCircle(posx,posy,radius) line=display.newRect(50,50,2,200) line:setFillColor(1,1,1) line.anchorY=1 function playerInMovement() xposMov=math.random(0,400) yposMov=math.random(0,400) transition.to(e.body, {time=900,x=xposMov,y=yposMov}) transition.to(e.body, {delay=900,time=400,x=50,y=50}) end timer.performWithDelay(1800,playerInMovement,-1) function getAngle(x1,y1,x2,y2) local Angle= math.atan2(y2 - y1, x2 - x1) return math.deg(Angle) end Runtime:addEventListener("touch",function(event) if event.phase == "began" then elseif event.phase == "moved" then local cx, cy = e.body:localToContent(0, 0) line.x=cx line.y=cy local angle = getAngle(cx,cy,event.x,event.y) line.rotation = angle+90 elseif event.phase == "ended" then end end) return setmetatable ( e,player\_mt ) end return player -------------------------------------------------------------------- --main.lua local player=require("player") local background=require("background") local players={} backgrounds=background.draw(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight) players= player.draw(200,200,15) --------------------------------------------------------------------------------------------------------------

hi,

I isolated the function causing the problem but i don’t understand why this function +getangle() don’t work …have you an idea ?

 e.touch=function(ev) if ev.phase == "began" then previousTime=ev.time myTimer=timer.performWithDelay(2000, e.energy, -1) e.indicate(ev) elseif ev.phase=="moved" then timeMiddle = ev.time-previousTime elseif ev.phase == "ended" then line.alpha=0 timer.cancel(myTimer) timePassed=ev.time-previousTime if timePassed \> 200 then lineardamping=30-timePassed/40 force=timePassed\*10000000000 else lineardamping=0 end e.body.linearDamping=lineardamping e.body:applyForce(((ev.x - e.body.x )\*force), ((ev.y-e.body.y)\*force),e.body.x,e.body.y) end e.body:applyForce(((ev.x - e.body.x )\*50), ((ev.y-e.body.y)\*50),e.body.x,e.body.y) end