rotating a graphic using a finger movement (touch event)

I am trying to create a simple demo that will rotate an image by detecting a finger being moved across the screen. I have created this code, but it seems messy, long winded and doesn’t work 100% ie. when the user moves up and down before removing their finger. The idea of the code is that it finds out the x,y location where the finger starts the touch and then works out if it is going up or down the screen. Depending on the direction the graphic is rotated in that direction. I have linked this code to an event listener for the background image rather than the image as I thought that this would give me more flexibility.

-----
oldY = 0
newY = 0

function fingerMove(event)
 if event.phase == "began" then
 oldY=event.yStart
 print("Started" .. newY)
 end
 if event.phase =="moved" then 
 newY=event.y
 print ("Moved oldY=" .. oldY .. " newY="..newY)
 if newY\>oldY+10 then
 --move down
 print("down")
 cannonRotation = cannonRotation + 1
 if (cannonRotation \>= rotateMax) then
 cannonRotation = rotateMax
 end 
 cannonBarrel.rotation = cannonRotation
 fireButton.rotation = cannonRotation
 elseif newY<oldy then> --move up<br> print("up")<br> cannonRotation = cannonRotation - 1<br> if (cannonRotation &lt;= rotateMin) then<br> cannonRotation = rotateMin<br> end<br> cannonBarrel.rotation = cannonRotation<br> fireButton.rotation = cannonRotation<br> end<br>	end	<br>	if event.phase == "ended" or event.phase == "cancelled" then<br> print("ended")<br> oldY=newY<br>	end<br>end<br>-----------<br></oldy>

Any suggestions or improvements appreciated. A simple solution would be nice as I’m still a newby and so need to understand what is happening in the code.
:slight_smile: [import]uid: 116086 topic_id: 35374 reply_id: 335374[/import]

–Goto the sample code and run DRAGME or DRAGMEMULTITOUCH or copy the code given below to main.lua
system.activate( “multitouch” )

local arguments =
{
{ x=50, y=110, w=50, h=50, r=10, red=255, green=0, blue=128 },
{ x=10, y=150, w=75, h=50, r=10, red=0, green=128, blue=255 },
{ x=90, y=190, w=100, h=50, r=10, red=255, green=255, blue=0 }
}

local eventInfoText1 = display.newText(" “, 100,300, native.systemFont, 12)
eventInfoText1:setTextColor(100,255,255)
local eventInfoText2 = display.newText(” ", 100,320, native.systemFont, 12)
eventInfoText2:setTextColor(100,255,255)

local function printTouch( event )
if event.target then
local bounds = event.target.contentBounds
print( “event(” … event.phase … “) (”…event.x…","…event.y…") bounds: “…bounds.xMin…”,"…bounds.yMin…","…bounds.xMax…","…bounds.yMax )
eventInfoText1.x = event.x
eventInfoText1.y = bounds.yMin - 30
eventInfoText1.text = “event(” … event.phase … “) (”…event.x…","…event.y…")"
eventInfoText2.x = event.x
eventInfoText2.y = bounds.yMin - 10
eventInfoText2.text = “bounds: “…bounds.xMin…”,”…bounds.yMin…","…bounds.xMax…","…bounds.yMax
end
end

local function onTouch( event )
local t = event.target

– Print info about the event. For actual production code, you should
– not call this function because it wastes CPU resources.
printTouch(event)

local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t, event.id )

– Spurious events can be sent to the target, e.g. the user presses
– elsewhere on the screen and then moves the finger over the target.
– To prevent this, we add this flag. Only when it’s true will “move”
– events be sent to the target.
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
elseif t.isFocus then
if “moved” == phase then
– Make object move (we subtract t.x0,t.y0 so that moves are
– relative to initial grab point, rather than object “snapping”).
t.x = event.x - t.x0
t.y = event.y - t.y0
elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( t, nil )
t.isFocus = false
end
end

– Important to return true. This tells the system that the event
– should not be propagated to listeners of any objects underneath.
return true
end

– Iterate through arguments array and create rounded rects (vector objects) for each item
for _,item in ipairs( arguments ) do
local button = display.newRoundedRect( item.x, item.y, item.w, item.h, item.r )
button:setFillColor( item.red, item.green, item.blue )
button.strokeWidth = 6
button:setStrokeColor( 200,200,200,255 )

– Make the button instance respond to touch events
button:addEventListener( “touch”, onTouch )
end

– listener used by Runtime object. This gets called if no other display object
– intercepts the event.
local function printTouch2( event )
print( “event(” … event.phase … “) (”…event.x…","…event.y…")" )
eventInfoText1.x = event.x
eventInfoText1.y = event.y
eventInfoText1.text = “event(” … event.phase … “) (”…event.x…","…event.y…")"
eventInfoText2.text = " "
end

Runtime:addEventListener( “touch”, printTouch2 )
[import]uid: 108129 topic_id: 35374 reply_id: 140598[/import]

Hello Robert,
If you don’t need to (or don’t want to) implement multi-touch, you can just build a simple rotation function that works by detecting the touch position on the stage. As the touch begins or moves around the stage, you call a simple “angle between” function between the object you want to rotate and the touch position, as follows:

local function angleBetween( srcX, srcY, dstX, dstY )  
 local angle = ( math.deg( math.atan2( dstY-srcY, dstX-srcX ) )+90 )  
 if ( angle \< 0 ) then angle = angle + 360 end  
 return angle % 360  
end  

With the four arguments being the source object X and Y, and the destination (touch) position X and Y. With this angle, you set the object’s rotation using object.rotation = angle.

This is, of course, the most basic implementation sample. You’d likely need to expand on it with touch voiding or “focus” capture to not interfere with other touchable objects; you might need to smoothly rotate the object to the new angle on the “began” phase (instead of snapping to that angle), etc.

Does this help?
Brent
[import]uid: 200026 topic_id: 35374 reply_id: 140640[/import]

I like the angle version as can understand it and even expalin it to someone else - now can I get it to work.

Thanks for both as your replies were fast and in depth. Since we mainly use the simulator multi-touch is difficult to implement. [import]uid: 116086 topic_id: 35374 reply_id: 140660[/import]

–Goto the sample code and run DRAGME or DRAGMEMULTITOUCH or copy the code given below to main.lua
system.activate( “multitouch” )

local arguments =
{
{ x=50, y=110, w=50, h=50, r=10, red=255, green=0, blue=128 },
{ x=10, y=150, w=75, h=50, r=10, red=0, green=128, blue=255 },
{ x=90, y=190, w=100, h=50, r=10, red=255, green=255, blue=0 }
}

local eventInfoText1 = display.newText(" “, 100,300, native.systemFont, 12)
eventInfoText1:setTextColor(100,255,255)
local eventInfoText2 = display.newText(” ", 100,320, native.systemFont, 12)
eventInfoText2:setTextColor(100,255,255)

local function printTouch( event )
if event.target then
local bounds = event.target.contentBounds
print( “event(” … event.phase … “) (”…event.x…","…event.y…") bounds: “…bounds.xMin…”,"…bounds.yMin…","…bounds.xMax…","…bounds.yMax )
eventInfoText1.x = event.x
eventInfoText1.y = bounds.yMin - 30
eventInfoText1.text = “event(” … event.phase … “) (”…event.x…","…event.y…")"
eventInfoText2.x = event.x
eventInfoText2.y = bounds.yMin - 10
eventInfoText2.text = “bounds: “…bounds.xMin…”,”…bounds.yMin…","…bounds.xMax…","…bounds.yMax
end
end

local function onTouch( event )
local t = event.target

– Print info about the event. For actual production code, you should
– not call this function because it wastes CPU resources.
printTouch(event)

local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t, event.id )

– Spurious events can be sent to the target, e.g. the user presses
– elsewhere on the screen and then moves the finger over the target.
– To prevent this, we add this flag. Only when it’s true will “move”
– events be sent to the target.
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
elseif t.isFocus then
if “moved” == phase then
– Make object move (we subtract t.x0,t.y0 so that moves are
– relative to initial grab point, rather than object “snapping”).
t.x = event.x - t.x0
t.y = event.y - t.y0
elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( t, nil )
t.isFocus = false
end
end

– Important to return true. This tells the system that the event
– should not be propagated to listeners of any objects underneath.
return true
end

– Iterate through arguments array and create rounded rects (vector objects) for each item
for _,item in ipairs( arguments ) do
local button = display.newRoundedRect( item.x, item.y, item.w, item.h, item.r )
button:setFillColor( item.red, item.green, item.blue )
button.strokeWidth = 6
button:setStrokeColor( 200,200,200,255 )

– Make the button instance respond to touch events
button:addEventListener( “touch”, onTouch )
end

– listener used by Runtime object. This gets called if no other display object
– intercepts the event.
local function printTouch2( event )
print( “event(” … event.phase … “) (”…event.x…","…event.y…")" )
eventInfoText1.x = event.x
eventInfoText1.y = event.y
eventInfoText1.text = “event(” … event.phase … “) (”…event.x…","…event.y…")"
eventInfoText2.text = " "
end

Runtime:addEventListener( “touch”, printTouch2 )
[import]uid: 108129 topic_id: 35374 reply_id: 140598[/import]

Hello Robert,
If you don’t need to (or don’t want to) implement multi-touch, you can just build a simple rotation function that works by detecting the touch position on the stage. As the touch begins or moves around the stage, you call a simple “angle between” function between the object you want to rotate and the touch position, as follows:

local function angleBetween( srcX, srcY, dstX, dstY )  
 local angle = ( math.deg( math.atan2( dstY-srcY, dstX-srcX ) )+90 )  
 if ( angle \< 0 ) then angle = angle + 360 end  
 return angle % 360  
end  

With the four arguments being the source object X and Y, and the destination (touch) position X and Y. With this angle, you set the object’s rotation using object.rotation = angle.

This is, of course, the most basic implementation sample. You’d likely need to expand on it with touch voiding or “focus” capture to not interfere with other touchable objects; you might need to smoothly rotate the object to the new angle on the “began” phase (instead of snapping to that angle), etc.

Does this help?
Brent
[import]uid: 200026 topic_id: 35374 reply_id: 140640[/import]

I like the angle version as can understand it and even expalin it to someone else - now can I get it to work.

Thanks for both as your replies were fast and in depth. Since we mainly use the simulator multi-touch is difficult to implement. [import]uid: 116086 topic_id: 35374 reply_id: 140660[/import]

Hey Sir,
How do I rotate image in clock and anticlock directions based on touch ??

Hey Sir,
How do I rotate image in clock and anticlock directions based on touch ??