Joystick

Posted by Matthew Pringle, Posted on August 18, 2010, Last updated October 7, 2010

14 votes

Add a joystick to your game, add multiple joysticks if necessary.


Get it here with examples http://www.alienhorde.com/files/joystick_1_0.zip

Create a new file joystick.lua and paste the code chunk at the end of this page in it. Place that file in your project folder, with main.lua.

In your main.lua

Load Joystick Class

1
local joystickClass = require( "joystick" )

Add a new joystick to your application ( zero config version )

1
joystick = joystickClass.newJoystick{}

Simple Usage

1
2
3
4
local function printOutput()
        print( joystick.joyX , joystick.joyY , joystick.joyAngle , joystick.joyVector )
end
Runtime:addEventListener( "enterFrame" , printOutput )

A more advanced version allows you to add images for the inner and outer joystick. Here we have created to png files of circular images "joystickOuter.png" and "joystickInner.png". We also want the elements of the joystick to have transparency and for the actual joystick to fade out when not in use. Also shown is a more advanced way of taking values from the joystick. We can attach a function to the joystick through "onMove = printJoystick2" and then have the function query the event for the outputs of the joystick. This way you can construct a function to control a game character / element and have the joystick power that object. The joystick uses an "enterFrame" listener to power the feedback so you will receive values every frame, even if the joystick is not in use. The joystick will return "false" in such instances. You should check all values for false, e.g. "if joyY and joyY ~= false then" before performing any calculations on the output of the joystick.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
local function printJoystick2( event )
        print( event.joyX , event.joyY , event.joyAngle , event.joyVector )
end
 
local joystick2 = joystickClass.newJoystick{
        outerImage = "joystickOuter.png",               -- Outer Image - Circular - Leave Empty For Default Vector
        outerRadius = "",                                               -- Outer Radius - Size Of Outer Joystick Element - The Limit
        outerAlpha = 0.5,                                               -- Outer Alpha ( 0 - 1 )
        innerImage = "joystickInner.png",               -- Inner Image - Circular - Leave Empty For Default Vector
        innerRadius = "",                                               -- Inner Radius - Size Of Touchable Joystick Element
        innerAlpha = 0.5,                                               -- Inner Alpha ( 0 - 1 )
        backgroundImage = "",                                   -- Background Image
        background_x = 0,                                               -- Background X Offset
        background_y = 0,                                               -- Background Y Offset
        backgroundAlpha = 1,                                    -- Background Alpha ( 0 - 1 )
        position_x = 185,                                               -- X Position Top - From Left Of Screen - Positions Outer Image
        position_y = 345,                                               -- Y Position - From Left Of Screen - Positions Outer Image
        ghost = 0,                                                              -- Set Alpha Of Touch Ghost ( 0 - 255 )
        joystickAlpha = 0.5,                                    -- Joystick Alpha - ( 0 - 1 ) - Sets Alpha Of Entire Joystick Group
        joystickFade = true,                                    -- Fade Effect ( true / false )
        joystickFadeDelay = 2000,                               -- Fade Effect Delay ( In MilliSeconds )
        onMove = printJoystick2                         -- Move Event
}

Paste the code below into main.lua

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
-- Joystick Class
-- joystick.lua
-- Version 1
-- By Matthew Pringle
-- matt@mattpringle.co.uk
-- The software is provided FREE to use and is on an "AS IS" basis.
-- If you are providing images for outerImage and innerImage you do not need to specify
-- outerRadius and innerRadius, they are calculated from the size of the image.
-- outerImage and innerImage should be square images, with an even number of pixels.
-- Example Setup
--              joystick = joystickClass.newJoystick{
--                      outerImage = "joystickOuter.png",                       -- Outer Image - Circular - Leave Empty For Default Vector
--                      outerRadius = "",                                                       -- Outer Radius - Size Of Outer Joystick Element - The Limit
--                      outerAlpha = 0.5,                                                       -- Outer Alpha ( 0 - 1 )
--                      innerImage = "joystickInner.png",                       -- Inner Image - Circular - Leave Empty For Default Vector
--                      innerRadius = "",                                                       -- Inner Radius - Size Of Touchable Joystick Element
--                      innerAlpha = 0.5,                                                       -- Inner Alpha ( 0 - 1 )
--                      backgroundImage = "joystickBackground.png",     -- Background Image
--                      background_x = 0,                                                       -- Background X Offset
--                      background_y = 0,                                                       -- Background Y Offset
--                      backgroundAlpha = 1,                                            -- Background Alpha ( 0 - 1 )
--                      position_x = 15,                                                        -- X Position Top - From Left Of Screen - Positions Outer Image
--                      position_y = 345,                                                       -- Y Position - From Left Of Screen - Positions Outer Image
--                      ghost = 0,                                                                      -- Set Alpha Of Touch Ghost ( 0 - 255 )
--                      joystickAlpha = 0.5,                                            -- Joystick Alpha - ( 0 - 1 ) - Sets Alpha Of Entire Joystick Group
--                      joystickFade = true,                                            -- Fade Effect ( true / false )
--                      joystickFadeDelay = 2000,                                       -- Fade Effect Delay ( In MilliSeconds )
--                      onMove = "class.function"                                       -- Move Event
--              }
-- To stop the joystick from interacting with the user call joystick.joystickStop()
-- To start the joystick call joystick.joystickStart()
-- The joystick passes the following values
-- joyVector ( returns 0 to 1 )
-- joyAngle ( returns full 360 degrees, 0 pointing up and degrees increasing clockwise )
-- joyX ( -1 to 1 )
-- joyY ( -1 to 1 )
-- Remember to check for false before doing any mathematical calculations, false = 0 in terms of position
-- but false has the added value of telling the software the joystick is not being used
------------------------------------------------------------------------------------------------------------------------
module(..., package.seeall)
------------------------------------------------------------------------------------------------------------------------
-- Calculate Joytick Outputs
local function calculateJoystick( this )
        
        -- Setup Values
        local joystickTouch = this.joystickTouch
        local newXPosition = this.joyCentreX
        local newYPosition = this.joyCentreY
        local max = this.joyMax
        local pi = math.pi
        local sqrt = math.sqrt
        local atan2 = math.atan2
        local sin = math.sin
        local cos = math.cos
        
        -- Calculate X and Y
        local xDist = joystickTouch.x - newXPosition
        local yDist = joystickTouch.y - newYPosition
        
        -- Calcualte Distance
        local distance = sqrt ( ( xDist * xDist ) + ( yDist * yDist ) )
        
        -- Set Max Distance
        if distance > max then distance = max end
        
        -- Calculate Angle
        local angle = ( atan2( yDist , xDist ) * ( 180 / pi ) ) + 90
        if angle < 0 then angle = 360 + angle end
        
        -- Calculate X and Y Limited To Outer Circle
        local xFinal = ( sin( angle * pi / 180 ) * distance )
        local yFinal = ( cos( angle * pi / 180 ) * distance )
        
        -- Normalize
        distance = distance / max
        xFinal = xFinal / max
        yFinal = yFinal / max
        
        -- Set New Values
        this.joyVector = distance
        this.joyAngle = angle
        this.joyX = xFinal
        this.joyY = -yFinal
        
end
------------------------------------------------------------------------------------------------------------------------
-- Position Inner Joystick
local function positionJoystickInner( this )
        
        -- Setup Values
        local newXPosition = this.joyCentreX
        local newYPosition = this.joyCentreY
        local max = this.joyMax
        local joyX = this.joyX
        local joyY = this.joyY
        local floor = math.floor
        
        -- Set New Position
        if joyX ~= false and joyY ~= false then
                this.joystickInner.x = floor( newXPosition + ( joyX * max ) )
                this.joystickInner.y = floor( newYPosition + ( joyY * max ) )
        else
                -- Reset Position
                this.joystickInner.x = floor( newXPosition )
                this.joystickInner.y = floor( newYPosition )
        end
        
end
------------------------------------------------------------------------------------------------------------------------
-- Handle Joystick Touch
local function newJoystickHandler( self , event )
        
        -- Setup Values
        local joystick = self.parent
        local this = event.target
        local phase = event.phase
        local onMove = joystick.onMove
        
        -- Event
        if "began" == phase then
                -- Start Focus
                display.getCurrentStage():setFocus( this , event.id )
                this.isFocus = true
                -- Store Initial Position
                this.x0 = event.x - this.x
                this.y0 = event.y - this.y
                -- Show Ghost
                joystick.joystickTouch.alpha = 1
                -- Fade Effect
                if joystick.fadeEffect == true then
                        if joystick.tween then transition.cancel( joystick.tween ) end
                        local tweenTime = ( 1 - joystick.alpha ) * 300
                        joystick.tween = transition.to( joystick, { alpha=1, time=tweenTime, delay=0 } )
                end
        elseif this.isFocus then
                if "moved" == phase then
                        -- Capture Event Position
                        this.x = event.x - this.x0
                        this.y = event.y - this.y0
                        -- Perform Calculations
                        calculateJoystick( joystick )
                        -- Set Position Of Inner Joystick
                        positionJoystickInner( joystick )
                elseif "ended" == phase or "cancelled" == phase then
                        -- End Focus
                        display.getCurrentStage():setFocus( this , nil )
                        this.isFocus = false
                        -- Reset Position To Joystick Centre
                        this.x = joystick.joyCentreX
                        this.y = joystick.joyCentreY
                        -- Set Values To False
                        joystick.joyVector = false
                        joystick.joyAngle = false
                        joystick.joyX = false
                        joystick.joyY = false
                        -- Set Position Of Inner Joystick
                        positionJoystickInner( joystick )
                        -- Hide Ghost
                        joystick.joystickTouch.alpha = 0.01
                        -- Fade Effect
                        if joystick.fadeEffect == true then
                                local tweenTime = ( 1 - joystick.fadeEffectAlpha ) * 500
                                if joystick.tween then transition.cancel( joystick.tween ) end
                                if joystick.alpha < 1 then
                                        joystick.tween = transition.to( joystick , { alpha=joystick.fadeEffectAlpha , time=tweenTime , delay=0 } )
                                else
                                        joystick.tween = transition.to( joystick , { alpha=joystick.fadeEffectAlpha , time=tweenTime , delay=joystick.fadeEffectDelay } )
                                end
                        end
                end
        end
        -- End Event
        return true
        
end
------------------------------------------------------------------------------------------------------------------------
-- Generates A New Joystick
function newJoystick( params )
 
        -- New Joystick Group
        local joystick = display.newGroup()
        
        -- Load Outer Image
        if not params.outerRadius or params.outerRadius == "" then params.outerRadius = 60 end
        if params.outerImage and params.outerImage ~= "" then
                local joystickOuter = display.newImage( params.outerImage )
                joystick:insert( joystickOuter )
                joystick.joystickOuter = joystickOuter
        else
                -- Or Draw Outer Circle
                local joystickOuter = display.newCircle( params.outerRadius , params.outerRadius , params.outerRadius )
                joystickOuter:setFillColor( 255 , 255 , 255 )
                joystick:insert( joystickOuter )
                joystick.joystickOuter = joystickOuter
        end
        if not params.outerAlpha or params.outerAlpha == "" then params.outerAlpha = 1 end
        joystick.joystickOuter.alpha = params.outerAlpha
        
        -- Load Inner Image
        if not params.innerRadius or params.innerRadius == "" then params.innerRadius = 24 end
        if params.innerImage and params.innerImage ~= "" then
                local joystickInner = display.newImage( params.innerImage )
                joystick:insert( joystickInner )
                joystick.joystickInner = joystickInner
        else
                -- Or Draw Inner Circle
                local joystickInner = display.newCircle( params.outerRadius , params.outerRadius , params.innerRadius )
                joystickInner:setFillColor( 0 , 0 , 0 )
                joystick:insert( joystickInner )
                joystick.joystickInner = joystickInner
        end
        if not params.innerAlpha or params.innerAlpha == "" then params.innerAlpha = 1 end
        joystick.joystickInner.alpha = params.innerAlpha
        
        -- Generate Touch Object
        if not params.ghost or params.ghost == "" then params.ghost = 0 end
        joystickTouch = display.newCircle( joystick.joystickOuter.x , joystick.joystickOuter.y , joystick.joystickInner.width / 2 )
        joystickTouch:setFillColor( 255 , 255 , 255 , params.ghost )
        joystickTouch.alpha = 0.01
        joystick:insert( joystickTouch )
        joystick.joystickTouch = joystickTouch
        
        -- Position Joystick
        if not params.position_x or params.position_x == "" then params.position_x = 15 end
        if not params.position_y or params.position_y == "" then params.position_y = display.stageHeight - 15 - joystick.joystickOuter.height end
        joystick.x = params.position_x
        joystick.y = params.position_y
        
        -- Load Background Image
        if params.backgroundImage and params.backgroundImage ~= "" then
                local joystickBackground = display.newImage( params.backgroundImage )
                if not params.background_x then params.background_x = 0 end
                joystickBackground.x = joystick.joystickOuter.x + params.background_x
                if not params.background_y then params.background_y = 0 end
                joystickBackground.y = joystick.joystickOuter.y +  params.background_y
                joystick:insert( 1 , joystickBackground )
                joystick.joystickBackground = joystickBackground
                if not params.backgroundAlpha then params.backgroundAlpha = 1 end
                joystick.joystickBackground.alpha = params.backgroundAlpha
        end
        
        -- Set Joystick Alpha
        if not params.joystickAlpha or params.joystickAlpha == "" then params.joystickAlpha = 1 end
        joystick.alpha = params.joystickAlpha
        
        -- Fade Effect
        if params.joystickFade == true then 
                joystick.fadeEffect = true
                joystick.fadeEffectAlpha = joystick.alpha
                if not params.joystickFadeDelay or params.joystickFadeDelay == "" then
                        params.joystickFadeDelay = 2000
                end
                joystick.fadeEffectDelay = params.joystickFadeDelay
        end
        
        -- Set Default Values
        joystick.joyMax = ( joystick.joystickOuter.width / 2 ) - ( joystick.joystickInner.width / 2 )
        joystick.joyCentreX = joystick.joystickOuter.x
        joystick.joyCentreY = joystick.joystickOuter.y
        joystick.joyVector = false
        joystick.joyAngle = false
        joystick.joyX = false
        joystick.joyY = false
        
        -- On Move Event
        if ( params.onMove and ( type(params.onMove) == "function" ) ) then
                joystick.enterFrame = params.onMove
                Runtime:addEventListener( "enterFrame" , joystick )
        end
 
        -- Set Joystick Listener
        joystick.joystickTouch.touch = newJoystickHandler
        joystick.joystickTouch:addEventListener( "touch", joystick.joystickTouch )
        
        -- Stop Function
        function joystick:joystickStop()
                -- End Focus
                display.getCurrentStage():setFocus( joystick.joystickTouch , nil )
                joystick.joystickTouch.isFocus = false
                -- Reset Position To Joystick Centre
                joystick.joystickTouch.x = joystick.joyCentreX
                joystick.joystickTouch.y = joystick.joyCentreY
                joystick.joystickTouch.alpha = 0.01
                joystick.joystickTouch:removeEventListener( "touch", joystick.joystickTouch )
                joystick.joyVector = false
                joystick.joyAngle = false
                joystick.joyX = false
                joystick.joyY = false
                if joystick.enterFrame then
                        Runtime:removeEventListener( "enterFrame" , joystick )
                        joystick.enterFrame( joystick )
                end
                positionJoystickInner( joystick )
                -- Fade Effect
                if joystick.fadeEffect == true then 
                        if joystick.alpha ~= joystick.fadeEffectAlpha then
                                local tweenTime = ( joystick.alpha - joystick.fadeEffectAlpha ) * 500
                                if joystick.tween then transition.cancel( joystick.tween ) end
                                joystick.tween = transition.to( joystick , { alpha=joystick.fadeEffectAlpha , time=tweenTime } )
                        end
                end
        end
        
        -- Start Function
        function joystick:joystickStart()
                joystick.joyVector = false
                joystick.joyAngle = false
                joystick.joyX = false
                joystick.joyY = false
                if joystick.enterFrame then
                        Runtime:addEventListener( "enterFrame" , joystick )
                end
                joystick.joystickTouch:addEventListener( "touch", joystick.joystickTouch )
        end
        
        -- Position Joystick Inner
        positionJoystickInner( joystick )
        
        -- Return New Joystick
        return joystick
        
end

Compatibility: 
Corona 2.0

Replies

hoplite
User offline. Last seen 1 year 14 weeks ago. Offline
Joined: 27 Dec 2010

This is really helpful stuff, Matthew. Thanks a ton!

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010
hoplite
User offline. Last seen 1 year 14 weeks ago. Offline
Joined: 27 Dec 2010

That remote accelerometer utility is going to be super useful as soon as I can get someone to answer my forum question on pushing game builds to ad hoc devices. :)

Regarding this joystick system, when using it in conjunction with Director, how does one unload the functions called upon joystick move, when shifting away from the screen containing the joystick?

Example:
An instance of the joystick has 'onMove = joyFunction' set. joyFunction updates the object 'avatar' by varying avatar's alpha with the joystick input value, then checks for out of bounds values:

if avatar.alpha < 0.0 then
avatar.alpha = 0.0

When navigating away from this screen, that check continues to run during each frame, loading the terminal window with "attempt to compare nil with number."

How do you typically handle this across scenes?

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

I think I put something in the notes about that. Basically the joystick will return false when it not being used / touched. I could have just returned 0 which would not have then caused your bug but false can provide extra info to the program as 0 can also mean the joystick is in the centre spot but still being touched.

Basically if you check for false before preforming any movement / calculation you shouldn't have any issues.

From the example with the plane you can see im checking for false before trying to move the plane.

1
2
3
4
5
6
7
8
9
-- Move X
if xStrength ~= false then
        plane.x = math.floor( plane.x + ( xStrength * speed ) )
end
        
-- Move Y
if yStrength ~= false then
        plane.y = math.floor( plane.y + ( yStrength * speed ) )
end

florinsivlad
User offline. Last seen 1 year 15 weeks ago. Offline
Joined: 6 Jan 2011

Hey, man, this this is really really useful. And may I say, beautifully accomplished. :) Thanks a lot.
I have however, 2 questions. Well, more like a question and a simple, humble request. :)

First, how do I remove the joystick from the screen? Have you implemented a function for that, or I do this with the removeSelf() Corona function?

And second, I'm struggling for about 3 days now to make a simple program. I want to generate the joystick with a touch event, at the tap coordinates. I've setup the event and the listener, the joystick appears at event.x and event.y coordinates (well, minus the radius, that is :D), but I can't manage the event.phase stuff, and because of that, everything else isn't working. I'd also like the joystick to dissapear from the screen if the phase is "ended" (that's why I need the remove function), and so on... Can you pleaaaase guide me a little with this simple task? :)

Thank you very much!

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

To remove the joystick...

There is probably no need to remove from memory as you will probably want to reuse it in the app. So just stop it and hide it.

call joystick:joystickStop() to stop all the joystick functions and then just hide it using alpha or visibility.

My joystick, if you look at the examples will fade out after touch. You just need to specify final alphas etc...

You can setup a watcher function to reposition the joystick on touch.

florinsivlad
User offline. Last seen 1 year 15 weeks ago. Offline
Joined: 6 Jan 2011

Yes, you're right... Now I'm asking myself why didn't that make sense to me earlier. :D Sorry, I'm rather new to Corona and Lua, for that matter, and... stuff like this tends to happen.

I did what you said, works flawlessly. Thank you for that. But now I have another problem. Once I tap somewhere else, the joystick moves, but how do I tell the program to move the joystick once I move my finger? Because now I have to tap to set the position of the joystick, lift my finger and "grab" the joystick again to move it.
I figured that if the phase is "moved", I should pass focus to the joystick with display.getCurrentStage():setFocus(joystick), but that didn't work. Do I have to set the focus to an element inside the joystick, joystick.joystickOuter? Or how can I do that?

Thanks again, and again sorry for my noob questions. :)

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

The joystick will always move given that method as the phase moved only works until the user lifts their finger and then the phase is ended and focus lost.

Your helper function should either remember the previous position and apply rules before deciding if it should move again. Download the epic citadel demo for a good implementation of a similar joystick.

I cant recall without being in front of the simulator but if you are fading out the joystick after the user lifts their finder you could check the alpha of the joystick and if the alpha == 0 then reposition, if ~= 0 then its not faded out and the user may want to use it again with out it moving.

florinsivlad
User offline. Last seen 1 year 15 weeks ago. Offline
Joined: 6 Jan 2011

Still can't figure out that problem with the focus. My code is this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function onTouch(event)
        local phase = event.phase
        joystick:joystickStop()
        if "began" == phase then
                joystick.x = event.x - 280 --radius of my joystick is 280
                joystick.y = event.y - 280
                joystick:joystickStart()
                joystick.isFocus = true
        elseif joystick.isFocus then
                if "moved" == phase then
                        joystick:joystickStart()
                        -- This is where I should set focus 
                        -- to the joystick's knob
                elseif "ended" == phase or "cancelled" == phase then
                        joystick:joystickStop()
                end
        end
        return true
end
Runtime:addEventListener( "touch", onTouch)

What am I doing wrong? Please, help me, I think I'm going nuts here.

nicke2k
User offline. Last seen 1 year 17 weeks ago. Offline
Joined: 22 Jan 2011

Hi, im trying to implement a "onFinish" option e.g

1
2
3
joystick = joystickClass.newJoystick{
   onFinish = my_method
}

i attemped

...
elseif "ended" == phase or "cancelled" == phase then
...
joystick:onFinish

with not success (complains nil value)

any suggestions?

hoplite
User offline. Last seen 1 year 14 weeks ago. Offline
Joined: 27 Dec 2010

Hi, Matthew,
I've been using your joystick module with great success, but I can't seem to get it to play well with Director. When I try to unload a completed game scene with Director, I believe I have to stop the timers associated with the joystick.

Using:

1
2
3
4
5
6
7
8
9
10
11
12
13
local joystickClass = require( "joystick" )
 
...
 
 
local function unloadGame()
        physics.stop()
        joystickClass.joystickStop()
 
        [or joystickClass:joystickStop() --note colon instead of period]
 
        ....
end

I get the following terminal output:

1
attempt to call field [or method, right? ]  'joystickStop' (a nil value)

What am I doing wrong here with respect to unloadng the joystick funtionality temporarily between game levels?

Thanks! This code and the tile engine example have been very helpful.

Hoplite

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

When you create a joystick it needs to be passed to a variable, you call the stop function on the variable not the class. The class only creates a joystick, it doesnt control them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local joystickClass = require( "joystick" )
 
-- Print Output To Terminal
local function printOutput( event )
        print( event.joyX , event.joyY , event.joyAngle , event.joyVector )
end
 
-- Add A New Joystick
joystick = joystickClass.newJoystick{
        outerImage = "joystickOuter.png",               -- Outer Image - Circular - Leave Empty For Default Vector
        outerAlpha = 0.8,                                               -- Outer Alpha ( 0 - 1 )
        innerImage = "joystickInner.png",               -- Inner Image - Circular - Leave Empty For Default Vector
        innerAlpha = 0.8,                                               -- Inner Alpha ( 0 - 1 )
        position_x = 25,                                                -- X Position Top - From Left Of Screen - Positions Outer Image
        position_y = 335,                                               -- Y Position - From Left Of Screen - Positions Outer Image
        onMove = printOutput                                    -- Move Event
}
 
joystick.joystickStop()

corkyportwine's picture
corkyportwine
User offline. Last seen 16 hours 43 min ago. Offline
Joined: 7 Feb 2011

Hi. This looks really cool. I haven't started playing with it yet (I'm at work) but I have a question. In the game I am working on I have a stationary turret that needs to turn a full 360 degrees (enemies attack from all directions) Is it possible to use the joystick as a way to change the direction an object is facing, rather than moving the object?

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

yeah using event.joyAngle will give you the angle of the touch from the joystick so you can use that to point in a direction.

One of the samples, the tank one, should show you how.

dellagd
User offline. Last seen 25 weeks 20 hours ago. Offline
Joined: 6 Feb 2011

anyone know how I can have the joystick do a certain thing when I release it? (After moving it around and stuff)

m9415253
User offline. Last seen 3 weeks 4 days ago. Offline
Joined: 26 May 2010

Awesome, thanks for sharing Matthew!

corkyportwine's picture
corkyportwine
User offline. Last seen 16 hours 43 min ago. Offline
Joined: 7 Feb 2011

Matthew: I'm trying to follow your advice and I've been struggling with this for a while. I've removed the joystick I don't need (the one that controls the background) so I can just focus on rotating the turret. I'm trying to get the turret to point at the same angle as joystick (instead of rotating in that relative direction). I'm just not sure which file I should be messing with to accomplish this.

Should I be in tank.lua and adjust the "Turret Controller" section? I've done a lot of trial and error and I'm mostly getting error, haha.

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

email me your work to support@coronaremote.com and I will have a quick look

Wazzup
User offline. Last seen 3 weeks 1 day ago. Offline
Joined: 23 Feb 2011

Many thanks for providing this! It looks great, but I'm having a few problems getting it to work.

I'm trying to use this in a platform game I'm creating but I'm struggling to piece together the code required to make my player move.

Just simple up down left right codes are confusing me and I'm getting nowhere.

Is there any chance you could give me a few pointers?

Many thanks

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

I think there is a digital control pad in the code exchange that make make more sense for a platform.

However it should be quite simple with my joystick

event.joyX , event.joyY are the 2 values you want to use

so character.x = character.x + event.joyX would move said character in the x direction

email me your code if you are still struggling

Wazzup
User offline. Last seen 3 weeks 1 day ago. Offline
Joined: 23 Feb 2011

I've tried the d-pad, but I personally feel the joystick would make the gameplay feel a lot more "smoother" - from what I've seen anyway.

I'll give your code a try and see how far it gets me (I'm new to coding ;)).

Thanks for your help!

loghound
User offline. Last seen 17 weeks 2 days ago. Offline
Joined: 26 Mar 2011

Hi Matthew,

This is very nicely done -- I'm especially excited about the nice tile engine.

One question -- How did you generat those textures for the tile engine? They match up very nicely and don't repeat in an obvious way -- I'm been scratching my head over how to do that

Thanks

-John

prnk28
User offline. Last seen 20 weeks 6 days ago. Offline
Joined: 3 Feb 2011

can you tell me how to add an image to the main.lua and then make it move on the movement of the joystick.
---sorry newbit---

xxxfanta's picture
xxxfanta
User offline. Last seen 6 days 50 sec ago. Offline
Joined: 25 Dec 2010

Hey Matthew! Thanks for that Script - it is a really amazing and usefull enhancement for every game that needs a joystick!

I just had a little problem using it with the directorclass, since it was loaded everytime i reloaded my game and I couldn't find a way to actually nil or remove the joystick, so i guess i'll have to make a little workaround ;)

Besides that you did a great job! :)

supercyclone77
User offline. Last seen 45 weeks 3 days ago. Offline
Joined: 19 Apr 2011

I would just like to take the time to say thank you for your outstanding efforts to help the corona community pursue their goals. This code sure is a big help to all us. Not only does it help us with our own projects, it also helps us to grasp inspiration from your efforts.

I just have one question, how do I change the size of the joystick so that it's just a little smaller than the original size? Thanks in advance.

Matthew Pringle
User offline. Last seen 5 weeks 20 hours ago. Offline
Joined: 23 Feb 2010

you can use these settings to control how the joystick is build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
joystick = joystickClass.newJoystick{
--                      outerImage = "joystickOuter.png",                       -- Outer Image - Circular - Leave Empty For Default Vector
--                      outerRadius = "",                                                       -- Outer Radius - Size Of Outer Joystick Element - The Limit
--                      outerAlpha = 0.5,                                                       -- Outer Alpha ( 0 - 1 )
--                      innerImage = "joystickInner.png",                       -- Inner Image - Circular - Leave Empty For Default Vector
--                      innerRadius = "",                                                       -- Inner Radius - Size Of Touchable Joystick Element
--                      innerAlpha = 0.5,                                                       -- Inner Alpha ( 0 - 1 )
--                      backgroundImage = "joystickBackground.png",     -- Background Image
--                      background_x = 0,                                                       -- Background X Offset
--                      background_y = 0,                                                       -- Background Y Offset
--                      backgroundAlpha = 1,                                            -- Background Alpha ( 0 - 1 )
--                      position_x = 15,                                                        -- X Position Top - From Left Of Screen - Positions Outer Image
--                      position_y = 345,                                                       -- Y Position - From Left Of Screen - Positions Outer Image
--                      ghost = 0,                                                                      -- Set Alpha Of Touch Ghost ( 0 - 255 )
--                      joystickAlpha = 0.5,                                            -- Joystick Alpha - ( 0 - 1 ) - Sets Alpha Of Entire Joystick Group
--                      joystickFade = true,                                            -- Fade Effect ( true / false )
--                      joystickFadeDelay = 2000,                                       -- Fade Effect Delay ( In MilliSeconds )
--                      onMove = "class.function"                                       -- Move Event
--              }

If you are using images then the size of the joystick is taken from the image size, vector you need to set outerRadius = and innerRadius =

CELL's picture
CELL
User offline. Last seen 6 days 10 hours ago. Offline
Joined: 23 Jan 2011

Thanks a lot for this Matthew. Now I just need to get the display.group to follow my player and i'm away.

Cheers

kevinjt4
User offline. Last seen 39 weeks 6 days ago. Offline
Joined: 16 Jan 2011

Excellent code! Very cool.

I have a few questions to ask regarding the implementation of this into my code.

I have a lua file called game.lua which prior to the implementing of your joystick
and plane lua code, had its own imbedded onscreen joystick. The code is very
simplistic giving out up/down/left/right coordinates allowing the ship to move as well as
allowing me to record the ships coordinates where bullets would come out.

I was able to integrate your code into the game.lua as module calls and am able to get
program running in the simulator. In lieu of that, here is my question.

1) Prior to "your" code, i had the game.lua file place the bullet for the ship at specified
coordinates in front of the plane that were easily found by the fact that the original
on-screen controller was in the game.lua file. As with the code below:

1
2
3
4
5
6
7
        
                local bullet = display.newImage ("bullet.png")
                        bullet.x = plane.x + 30  --<< orignally:   bullet.x = ship.x + 30
                        bullet.y = plane.y              --<< orignally:   bullet.y = ship.y
                        transition.to (bullet, {time = 1500, x=550})
                physics.addBody (bullet, {bounce=0.6, radius =10})  --bounce was 0.6
                localGroup:insert(bullet)

Now that the plane.lua file is being called in a seperate module, HOW do i return those
same X and Y coordinates back into the game.lua file for me to place the bullets at the
correct coordinates?

currently I have it as:

module
function new()
local plane = require("plane")
local physics
sound
various background stuff
score/health bar
scrolling background
local joystickClass = require ("joystick")
joystick = joystickClass.newJoystick{
outerImage = "",
outerRadius = 60,
outerAlpha = 0,
innerImage = "joystickInner.png",
innerRadius = "",
your variables, etc etc etc...
}

Then later when the fire button is pressed the bullet code above is run placing the bullets at the x,y coordinates. But now I'm unsure on how to get those coordinates.

Any help is greatly appreciated.

diginutscorp's picture
diginutscorp
User offline. Last seen 4 weeks 1 day ago. Offline
Joined: 24 Feb 2011

how do I stop the background from rotating. I just want the tank to move back and forth

b-bond
User offline. Last seen 13 weeks 6 days ago. Offline
Joined: 23 Jan 2012

Hi fellow developers,

I am trying to use this for a 2d platformer, the movement on the x-axis is awesome.

I am trying to implement a ladder, however gravity is a bitch and now I am stuck.

1
2
3
4
5
6
if player.canClimb and event.joyY then
        if event.joyAngle > 335 or event.joyAngle < 25 then
                physics.setGravity( 0, 0 )
                player:setLinearVelocity( 0, -50 )
        end
end

Further down in the code I check if the player collides with the ladder.

The problem with this is that the player keeps moving up and he can't stand still on the ladder.

Any help?

Thanks

b-bond