how to initiate a 'touch' event at any point within the view and have it call a function to rotate an object, and fire a bullet.

I currently have a tank that is controlled by a joystick, and a turret that I am trying to get to respond to touch events within the view.

Q1. How do I code my turret to respond (rotate) to touch events within the view?

Q2. How do I code a bullet that will be fired from the turret portion of the tank whenever the user ‘taps’ or ‘drags’ his finger within the view?

My goal is to have the user controlling the speed and direction of the tank via joystick (accomplished) and for the turret, the user would ‘tap’ on various locations and have the turret ‘aim’ in that direction and fire, in addition I would like the user to be able to drag their finger and upon release the tank would fire.

Thanks in advance for any help. :slight_smile:

-Saer [import]uid: 148623 topic_id: 30680 reply_id: 330680[/import]

Hi Saer,

Q1) I would suggest setting up an invisible but touch-sensitive rectangle that spans the entire screen (but make sure your joystick “returns true” so touches in that region don’t transmit through to the sensor rectangle). When the user touches the rectangle in the “began” phase, you calculate the math using an “angle between” function (I wrote one awhile back and there are others if you search). The turret would then rotate to that angle, preferably using a Runtime listener, NOT a transition. This would ensure that the turret locks… and stays locked… on to the touch point even if the touch or the tank moves.

Q2) on the “ended” phase of the touch, create a bullet at the tank’s location and fire it toward the touch release point, again using he proper math and physics to move it there. Why? Because collision detection usually isn’t reliable if you transition an object, and obviously you’ll want the bullet to collide with other things. :wink:

Any further questions, just let me know.
Brent Sorrentino
[import]uid: 9747 topic_id: 30680 reply_id: 122964[/import]

Awesome, thanks for the reply!

I created an invisible touch-sensitive rect, but I’m having trouble with figuring out how to make the joystick “return true” (the terminal shows a touch event has occurred even when I click the joystick.)
Also, I can’t seem to find your “angle between” function…

*Only when I omit line ten does the joystick even register.
Here is some of my code: [lua]–adds a rect to act as a base for touch events relating to the turret
local transRect = display.newRect(0,0, 1024, 768)
transRect:setReferencePoint(display.CenterReferencePoint);
transRect.isVisible = false
transRect.isHitTestable = true

function transRect:touch(e)
if e.phase == “began” then
print( “You touched the object!” );
–return true
end
end

transRect:addEventListener( “touch”, transRect )
–==================================================================================================
–adding the turret that will be controlled by the player
local user_turret = display.newImage(“gameImages/user_turret.png”)
user_turret:setReferencePoint(player.CenterReferencePoint);
user_turret.x = user_tank.x;
user_turret.y = 16;
user_turret.yReference = 18;

–===================================================
–=========

local StickLib = require(“lib_analog_stick”)

local Text = display.newText( " ", _W*.6, _H-20, native.systemFont, 15 )

–Creates analog stick that controls the tank body’s speed and direction
local LeftStick = StickLib.NewStick(
{
x = _W*.1,
y = _H*.85,
thumbSize = 20,
borderSize = 36,
snapBackSpeed = .75,
R = 256,
G = 255,
B = 255
})



local function main( event )

–Sets Left analog to control the tank body.
LeftStick:move(player, 2.0, true)

–SHOW STICK INFO
Text.text = “ANGLE = “…LeftStick:getAngle()…” DISTANCE = “…math.ceil(LeftStick:getDistance())…” PERCENT = “…math.ceil(LeftStick:getPercent()*100)…”%”

end

Runtime:addEventListener( “enterFrame”, main ) [import]uid: 148623 topic_id: 30680 reply_id: 123095[/import]

Hi again,

I’m not sure what’s in the “lib_analog_stick” module, but you’ll need to modify that slightly. In the function that receives the touch events (began, moved, ended), you’ll need to add “return true” at the very end… outside of any conditional if-then clauses. This will ensure that the touch doesn’t transfer “through” the joystick elements to the rectangular touch sensor that you set up.

Also, make sure that the joystick is in a layer above (z-index) the rectangle, or you won’t receive any touches on it. :slight_smile:

Brent
[import]uid: 9747 topic_id: 30680 reply_id: 123096[/import]

Thanks. It seems to be doing what I want.
As far as getting the turret to respond, I still haven’t been able to find the “angle between” function you mentioned above… [import]uid: 148623 topic_id: 30680 reply_id: 123104[/import]

After searching the forums I found a bit of code that allows the user to, by way of clicking the object itself and dragging the object, rotate it. I spent about 3hrs trying to edit the code to run the way I want, but had little success. :\ (I am fairly new to Corona and coding in general)

Any ideas on how to edit this code to achieve my goal?
[lua]local function rotateObj(event)
local t = event.target
local phase = event.phase

if (phase == “began”) then
display.getCurrentStage():setFocus( t )
t.isFocus = true

– Store initial position of finger
t.x1 = event.x
t.y1 = event.y

elseif t.isFocus then
if (phase == “moved”) then
t.x2 = event.x
t.y2 = event.y

angle1 = 180/math.pi * math.atan2(t.y1 - t.y , t.x1 - t.x)
angle2 = 180/math.pi * math.atan2(t.y2 - t.y , t.x2 - t.x)
print("angle1 = "…angle1)
rotationAmt = angle1 - angle2

–rotate it
t.rotation = t.rotation - rotationAmt
print ("t.rotation = "…t.rotation)

t.x1 = t.x2
t.y1 = t.y2

elseif (phase == “ended”) then

display.getCurrentStage():setFocus( nil )
t.isFocus = false
end
end

– Stop further propagation of touch event
return true
end
yourObject:addEventListener(“touch”, rotateObj) [import]uid: 148623 topic_id: 30680 reply_id: 123312[/import]

Hi Saerothir,
Sorry, I meant to reply but it slipped through the cracks. The “angle between” function that I use is printed below. “srcX” and “srcY” are, in this case, your turret X and Y positions (just plug in turret.x or turret.y, or whatever you have named your turret object). “dstX” and “dstY” are the touch location X and Y coordinates… where the user touches/drags on the sensor rectangle.

local math\_deg = math.deg --localize 'math.deg' for better performance  
local math\_atan2 = math.atan2 --localize 'math.atan2' for better performance  
  
local function angleBetween( srcX, srcY, dstX, dstY )  
 local angle = ( math\_deg( math\_atan2( dstY-srcY, dstX-srcX ) )+90 ) --; return angle  
 if ( angle \< 0 ) then angle = angle + 360 end ; return angle % 360  
end  
  
--USAGE:  
local ang = angleBetween( turret.x, turret.y, eventX, eventY )  
turret.rotation = ang  

Try this out a bit and let me know how it goes.

Brent

[import]uid: 9747 topic_id: 30680 reply_id: 123314[/import]

Well, it kinda works :]

When I launch the simulator and then click on a random point within the view the turret immediately rotates to that point, but that’s all it does…?
It doesn’t respond when I attempt to click on a different point on the screen nor does it respond to dragging…

here is my code (I know I’m missing something)

 --adds a rect to act as a base for touch event relating to the turret  
local transRect = display.newRect(0,0, 1024, 768)  
transRect:setReferencePoint(display.CenterReferencePoint);  
transRect.isVisible = false  
transRect.isHitTestable = true  
  
 function transRect:touch(e)  
 if e.phase == "began" then  
 print( "You touched the object!" );  
  
 local math\_deg = math.deg --localize 'math.deg' for better performance  
 local math\_atan2 = math.atan2 --localize 'math.atan2' for better performance  
   
 local function angleBetween( user\_turretx, user\_turrety, transRecx, transRecty )  
 local angle = ( math\_deg( math\_atan2( transRect.y-user\_turret.y, transRect.x-user\_turret.x ) )+90 ) --; return angle  
 if ( angle \< 0 ) then angle = angle + 360 end ; return angle % 360  
 end  
   
 --USAGE:  
 local ang = angleBetween( user\_turret.x, user\_turret.y, event.x, event.y )  
 user\_turret.rotation = ang  
  
  
 end  
end   
 Runtime:addEventListener("touch", transRect)  
 transRect:addEventListener( "touch", transRect )  
  

Edit –
When I click on a point within the view it is registering two touch events, the terminal shows the the string message - line 9 - twice. [import]uid: 148623 topic_id: 30680 reply_id: 123327[/import]

Hi @Saerothir,
It should look more like this. I haven’t actually tested this in the Simulator, but give it a try and let me know if it’s closer to your goals.

local transRect = display.newRect(0,0, 1024, 768)  
transRect:setReferencePoint(display.CenterReferencePoint);  
transRect.isVisible = false  
transRect.isHitTestable = true  
  
--up-reference these here, not within the function!  
local math\_deg = math.deg --localize 'math.deg' for better performance  
local math\_atan2 = math.atan2 --localize 'math.atan2' for better performance  
  
--likewise, this function should reside outside and above the touch function  
local function angleBetween( srcX, srcY, dstX, dstY )  
 local angle = ( math\_deg( math\_atan2( dstY-srcY, dstX-srcX ) )+90 ) --; return angle  
 if ( angle \< 0 ) then angle = angle + 360 end ; return angle % 360  
end  
  
local function transRect( event )  
  
 local ang = angleBetween( user\_turret.x, user\_turret.y, event.x, event.y )  
 user\_turret.rotation = ang --rotate turret on ALL touch/drag conditions  
  
 if e.phase == "began" or e.phase == "moved" then  
 print( "BEGAN/MOVED phase touch" )  
 elseif e.phase == "ended" then  
 print( "FIRE a bullet now!" )  
 end  
  
end  
  
--a touch listener on the sensor rectangle is all you need. So, delete the next line...  
Runtime:addEventListener("touch", transRect) --DELETE this!  
transRect:addEventListener( "touch", transRect )  

[import]uid: 9747 topic_id: 30680 reply_id: 123418[/import]

Hi Saer,

Q1) I would suggest setting up an invisible but touch-sensitive rectangle that spans the entire screen (but make sure your joystick “returns true” so touches in that region don’t transmit through to the sensor rectangle). When the user touches the rectangle in the “began” phase, you calculate the math using an “angle between” function (I wrote one awhile back and there are others if you search). The turret would then rotate to that angle, preferably using a Runtime listener, NOT a transition. This would ensure that the turret locks… and stays locked… on to the touch point even if the touch or the tank moves.

Q2) on the “ended” phase of the touch, create a bullet at the tank’s location and fire it toward the touch release point, again using he proper math and physics to move it there. Why? Because collision detection usually isn’t reliable if you transition an object, and obviously you’ll want the bullet to collide with other things. :wink:

Any further questions, just let me know.
Brent Sorrentino
[import]uid: 9747 topic_id: 30680 reply_id: 122964[/import]

Awesome, thanks for the reply!

I created an invisible touch-sensitive rect, but I’m having trouble with figuring out how to make the joystick “return true” (the terminal shows a touch event has occurred even when I click the joystick.)
Also, I can’t seem to find your “angle between” function…

*Only when I omit line ten does the joystick even register.
Here is some of my code: [lua]–adds a rect to act as a base for touch events relating to the turret
local transRect = display.newRect(0,0, 1024, 768)
transRect:setReferencePoint(display.CenterReferencePoint);
transRect.isVisible = false
transRect.isHitTestable = true

function transRect:touch(e)
if e.phase == “began” then
print( “You touched the object!” );
–return true
end
end

transRect:addEventListener( “touch”, transRect )
–==================================================================================================
–adding the turret that will be controlled by the player
local user_turret = display.newImage(“gameImages/user_turret.png”)
user_turret:setReferencePoint(player.CenterReferencePoint);
user_turret.x = user_tank.x;
user_turret.y = 16;
user_turret.yReference = 18;

–===================================================
–=========

local StickLib = require(“lib_analog_stick”)

local Text = display.newText( " ", _W*.6, _H-20, native.systemFont, 15 )

–Creates analog stick that controls the tank body’s speed and direction
local LeftStick = StickLib.NewStick(
{
x = _W*.1,
y = _H*.85,
thumbSize = 20,
borderSize = 36,
snapBackSpeed = .75,
R = 256,
G = 255,
B = 255
})



local function main( event )

–Sets Left analog to control the tank body.
LeftStick:move(player, 2.0, true)

–SHOW STICK INFO
Text.text = “ANGLE = “…LeftStick:getAngle()…” DISTANCE = “…math.ceil(LeftStick:getDistance())…” PERCENT = “…math.ceil(LeftStick:getPercent()*100)…”%”

end

Runtime:addEventListener( “enterFrame”, main ) [import]uid: 148623 topic_id: 30680 reply_id: 123095[/import]

Hi again,

I’m not sure what’s in the “lib_analog_stick” module, but you’ll need to modify that slightly. In the function that receives the touch events (began, moved, ended), you’ll need to add “return true” at the very end… outside of any conditional if-then clauses. This will ensure that the touch doesn’t transfer “through” the joystick elements to the rectangular touch sensor that you set up.

Also, make sure that the joystick is in a layer above (z-index) the rectangle, or you won’t receive any touches on it. :slight_smile:

Brent
[import]uid: 9747 topic_id: 30680 reply_id: 123096[/import]

Thanks. It seems to be doing what I want.
As far as getting the turret to respond, I still haven’t been able to find the “angle between” function you mentioned above… [import]uid: 148623 topic_id: 30680 reply_id: 123104[/import]

Hey Brent,
Sorry for the delayed response.

I made a video to show the issues I’m having:
http://www.youtube.com/watch?v=vG2rJyDJC-w&feature=youtube_gdata_player

P.S. I hope I was clear enough in explaining. [import]uid: 148623 topic_id: 30680 reply_id: 123604[/import]

Hi Saerothir,
The video is marked as private. Can you make it public for me to view? (and others who might want to comment)

Brent
[import]uid: 9747 topic_id: 30680 reply_id: 123618[/import]

Oh, sorry.
It should work now. [import]uid: 148623 topic_id: 30680 reply_id: 123620[/import]

Thanks for posting the video, it helped clarify some things! A few new things I noticed…

  1. Remove line #2 where you set the reference point of the sensor rectangle. This could be the cause of the touch response giving the wrong values when you move the tank from its starting position in the upper left.

  2. I should have noticed this before (kicking myself)… you have both the rectangle AND the function named “transRect”. This is probably causing some confusion in Lua, which might be why you’re getting the first error. Name the function something different like “senseRect”, along with all references to it, and see if that helps.

Otherwise, if you’re still having problems, please e-mail me the code for “level1.lua”. I couldn’t really see it clearly in the video, even blown up to full screen view. Please send it to bjsorrentino (at) yahoo (dot) com.

Brent [import]uid: 9747 topic_id: 30680 reply_id: 123630[/import]

I emailed you the level1.lua code. [import]uid: 148623 topic_id: 30680 reply_id: 123750[/import]

Hi @Saerothir,
I don’t know what other advice I can give. I pulled out the angle-tracking code, placed it in a new Lua simulation, and it seems to work perfectly. So quite possibly the problem is somewhere in the StickLib module, or something is going wrong in Storyboard. I don’t actually use Storyboard so I won’t pretend I’m an expert on how it all works… I just know the basics of it, and I also know it’s extremely fussy about what things you place in which “phase” of it.

I did remove all of the instances where you changed the reference points of objects (the turret, even the player group itself. You should be very careful about where you use those commands, because they can really muck with the coordinate system, touch coordinates, scaling, etc.

I sense that you want to have the turret rotate by its “base”, not the center, which is why you adjusted its reference point. I actually suggest that you design your turret image as a larger square with its “base” in the center of the image boundaries and transparent space all around. So, instead of adjusting the reference point of it in Corona, you place its base in the center of a square image, and the Corona display object rotates around its center as is default.

Anyway, try this yourself in a NEW Corona simulation, outside of Storyboard. For me it works perfectly, and the turret always tracks the touch position.

Sorry I couldn’t find the problem in your level1.lua code. It must be something within StickLib or elsewhere, and could take awhile to track down. Maybe you can narrow down the problem by looking there, or pulling your app out of Storyboard for the time being.

Best of luck!
Brent

--adding new local group that will represent the tank  
local player = display.newGroup()  
--player.xReference = 25;   
--player.yReference = 23;  
  
--adding the tank that will be controlled by the player  
local user\_tank = display.newImage("gameImages/user\_tank.png");  
  
--adding the turret that will be controlled by the player  
local user\_turret = display.newImage("gameImages/user\_turret.png")  
--user\_turret:setReferencePoint(player.CenterReferencePoint);  
user\_turret.x = 100;  
user\_turret.y = 100;   
--user\_turret.yReference = 18;  
  
--following function is a daisy-chained series of transitions to simulate the turret moving  
local function simulateTankMove()  
 transition.to( user\_turret, { time=6000, x=924 } )  
 transition.to( user\_turret, { delay=6000, time=6000, y=568 } )  
 transition.to( user\_turret, { delay=12000, time=3000, x=462, y=400 } )  
 transition.to( user\_turret, { delay=15000, time=3000, x=100, y=568 } )  
 transition.to( user\_turret, { delay=18000, time=6000, x=100, y=100, onComplete=simulateTankMove } )  
end  
simulateTankMove()  
  
--===============================================================   
--===============================================================   
--===============================================================  
  
--adds a rect to act as a base for touch event relating to the turret  
local transRect = display.newRect(0,0, 1024, 768)  
transRect:setFillColor(255,100,150,40)  
--transRect.isVisible = false  
transRect.isHitTestable = true  
  
local math\_deg = math.deg --localize 'math.deg' for better performance  
local math\_atan2 = math.atan2 --localize 'math.atan2' for better performance  
   
--likewise, this function should reside outside and above the touch function  
local function angleBetween( srcX, srcY, dstX, dstY )  
 local angle = ( math\_deg( math\_atan2( dstY-srcY, dstX-srcX ) )+90 ) --; return angle  
 if ( angle \< 0 ) then angle = angle + 360 end ; return angle % 360  
end  
   
local function touchRect( event )  
   
 local ang = angleBetween( user\_turret.x, user\_turret.y, event.x, event.y )  
 user\_turret.rotation = ang --rotate turret on ALL touch/drag conditions  
 local e = event.phase  
 if e.phase == "began" or e.phase == "moved" then  
 print( "BEGAN/MOVED phase touch" )  
 elseif e.phase == "ended" then  
 print( "FIRE a bullet now!" )  
 end  
   
end  
   
--a touch listener on the sensor rectangle is all you need. So, delete the next line...  
--Runtime:addEventListener("touch", touchRect) --DELETE this!  
transRect:addEventListener( "touch", touchRect )   
  
--===============================================================  
--===============================================================  
  
--adding objects to local group 'player'  
player:insert(user\_tank)  
player:insert(user\_turret)  

[import]uid: 9747 topic_id: 30680 reply_id: 123773[/import]

After searching the forums I found a bit of code that allows the user to, by way of clicking the object itself and dragging the object, rotate it. I spent about 3hrs trying to edit the code to run the way I want, but had little success. :\ (I am fairly new to Corona and coding in general)

Any ideas on how to edit this code to achieve my goal?
[lua]local function rotateObj(event)
local t = event.target
local phase = event.phase

if (phase == “began”) then
display.getCurrentStage():setFocus( t )
t.isFocus = true

– Store initial position of finger
t.x1 = event.x
t.y1 = event.y

elseif t.isFocus then
if (phase == “moved”) then
t.x2 = event.x
t.y2 = event.y

angle1 = 180/math.pi * math.atan2(t.y1 - t.y , t.x1 - t.x)
angle2 = 180/math.pi * math.atan2(t.y2 - t.y , t.x2 - t.x)
print("angle1 = "…angle1)
rotationAmt = angle1 - angle2

–rotate it
t.rotation = t.rotation - rotationAmt
print ("t.rotation = "…t.rotation)

t.x1 = t.x2
t.y1 = t.y2

elseif (phase == “ended”) then

display.getCurrentStage():setFocus( nil )
t.isFocus = false
end
end

– Stop further propagation of touch event
return true
end
yourObject:addEventListener(“touch”, rotateObj) [import]uid: 148623 topic_id: 30680 reply_id: 123312[/import]