Tutorial details

Tutorial 10 - A Simple Dial Class | App Code for Sale | Preview

Tutorial 10 - A Simple Dial Class | iOS Tutorial

How to use Dial Class

Overview PAGE TOP

10.1 Your Personality and a Little Maths

This tutorial is based on some code that we ported from our iPhone App Personality Profile. In this App you use a dial to answer a number of questions and a profile is provided based on your selection. We used a dial because we wanted a touch friendly solution and this seemed like an intuitive approach. The App is FREE on iTunes so download it and compare the functionality of the Objective C version to our Lua implementation. The embedded video above gives you an idea of how it works but the effect is better understood when used on your iDevice.

Screenshot_2012.03.11_09.52.44.png

The trick to working out how to move the dial is a mathematical one. In essence you need to convert the cartesian co-ordinates of your finger on the screen to equivalent polar co-ordinates.

It is about now that you realise that those maths lessons way back weren't completely useless and perhaps you should have paid more attention. Don't panic, all you need to know is that it is possible to convert from a point (x, y) to polar co-ordinates which consist of an angle and a distance. The angle tells you how much to rotate the dial and you can use the distance portion to work out whether a point is within a circle which is handy for detecting if a tap was on the dial.

To make life easy we created a function which does all the hard work. We have reproduced it below but note that you also need the math.hypot() function which isn't available in the Codea version of Lua. Both of these functions (and more) are contained in the Math tab of RSLibrary.

We have made use of the new Codea dependency functionality so if you download the entire tutorial code in one file, then you also need to download RSLibrary and link it as a dependency to DialDemo. See Tutorial 9 if you want to understand dependencies better or see what is in RSLibrary. For this tute you only need the Math and Button tabs but you might as well grab the whole thing.

As an aside, a handy trick which we use in the math.polar function is to assign a default value to a parameter using "or". This works because nil evaluates to false in Lua. See the code below to understand how you can use this to overload functions.

1   function math.polar(x, y, originX, originY)
2    
3      -- Usage: math.polar(x, y) - origin is assumed at (0, 0)
4      --               math.polar(x, y, originX, originY)
5      --
6      -- This function converts from cartesian co-ordinates (x, y) to
7      -- polar co-ordinates (distance, angle) using the two functions:
8      --
9      --    1. distance = hypot(x, y) - the hypotenuse of a right-angle triangle; and
10     --    2. angle = atan2(x, y) - is the arc tangent of y/x in radians.
11     --
12     -- Since nil evaluates to false in Lua, you can use "or" to assign a default value.
13     --
14     -- Reefwing Software (www.reefwing.com.au)
15     -- Version 1.0
16   
17     local oX = originX or 0
18     local oY = originY or 0
19     local dx = x - oX
20     local dy = y - oY
21     local distance = math.hypot(dx, dy)
22     local angleInDegrees = math.deg(math.atan2(dy, dx))
23     -- Functions may return multiple results in Lua.
24     return distance, angleInDegrees
25   
26  end

10.2 The Main Class PAGE TOP

In this instance the Main class is just there to demonstrate the Dial Class. Both Landscape and Portrait orientations are supported using the orientationChanged() function.

1   --# Main
2   -- DialDemo
3   -- Define supported orientations
4   supportedOrientations(ANY)
5   -- Use this function to perform your initial setup
6   
7   function setup()
8   
9      -- Project Metadata
10     version = 1.0
11     saveProjectInfo("Description", "Codea Dial Demonstration")
12     saveProjectInfo("Author", "Reefwing Software")
13     saveProjectInfo("Date", "26th July 2012")
14     saveProjectInfo("Version", version)
15     print("DialDemo v"..version.."\n")
16     -- Keep an eye on Frame Rate (Frames Per Second, FPS) so we can
17     -- compare and contrast different approaches. 
18     FPS = 0
19     watch("FPS")
20     -- Define a new dial = Dial(x, y, angle)
21     --
22     -- Where: (x, y) are the CENTER co-ordinates of the dial. (default alignment is CENTER).
23     --        angle = the current angle (in degrees) of the dial.
24     dial = Dial(WIDTH/2, HEIGHT/2, 0)
25     -- Create a button which will zero the dial
26     -- The Button Class is contained within RSLibrary
27     local rbX = WIDTH/2 - dial.width/2
28     local rbY = HEIGHT/2 - dial.height - 20
29     resetButton = Button("Reset", rbX, rbY, dial.width, 50)
30     resetButton.action = function() resetButtonTapped() end
31    
32  end
33  
34  -- Drawing Functions
35  function draw()
36     -- Update instantaneous FPS
37     FPS = math.round(1/DeltaTime)
38     -- This sets a black background color 
39     background(blackColor)
40     -- Draw the dial and reset button
41     dial:draw()
42     resetButton:draw()
43  end
44  
45  function orientationChanged(newOrientation)
46     -- If the iPad orientation changes we need to 
47     -- adjust object co-ordinates.
48     local rbX = WIDTH/2 - dial.width/2
49     local rbY = HEIGHT/2 - dial.height - 20
50     dial.x, dial.y = WIDTH/2, HEIGHT/2
51     resetButton.x, resetButton.y = rbX, rbY
52  end
53  
54  -- Handle Touches
55  function touched(touch)
56     dial:touched(touch)
57     resetButton:touched(touch)
58  end
59  
60  function resetButtonTapped()
61     dial:reset()
62  end

10.3 The Dial Class PAGE TOP

The Dial Class is where the magic happens. We only have a licence to use the knob and dial images in our App, so you are going to have to draw or obtain your own version. Strictly speaking you only need a knob image (the bit that moves). The class should handle any differences in size to our sprites.

1   --# Dial
2   Dial = class()
3   -- A Dial Class
4   -- Reefwing Software (www.reefwing.com.au)
5   --
6   -- 26 July 2012
7   -- Version 1.0
8   
9   function Dial:init(x, y, angle)
10     
11     -- These parameters are used to customise your Dial
12     self.x = x    -- x screen co-ordinate for the dial
13     self.y = y    -- y screen co-ordinate for the dial
14     self.alignment = CENTER    -- Dial uses CENTER alignment
15     self.visible = true        -- Boolean to indicate whether dial is drawn and touches handled
16     self.currentAngle = angle or 0  -- Current Angle of the dial in degrees (default 0)
17     dialImage = readImage("Dropbox:pDial200px")
18     knobImage = readImage("Dropbox:pKnob147px")
19     radius = knobImage.width/2       -- Radius of knob circle sprite
20     self.width = dialImage.width     -- Defined by the dial sprite width
21     self.height = dialImage.height   -- Defined by the dial sprite height
22     
23  end
24  
25  -- Draw function
26  function Dial:draw()
27      
28     -- Codea does not automatically call this method
29     if self.visible then
30         sprite(dialImage, self.x, self.y)
31         pushMatrix()
32         rotateDialByDegrees(self.x, self.y, self.currentAngle)
33         sprite(knobImage, 0, 0)
34         popMatrix()
35     end
36     
37  end
38  
39  -- Touch Handler
40  function Dial:touched(touch)
41      
42     -- Codea does not automatically call this method
43     --
44     -- The pointInCircle() function determines if the touch was
45     -- on the dial. This function is contained in RSLibrary.
46     --
47     -- math.polar(x, y) converts from cartesian co-ordinates (x, y) to polar
48     -- co-ordinates (distance, angle). We only use the returned angle not the 
49     -- distance. This function is also contained in RSLibrary.
50     
51     if self.visible and pointInCircle(touch.x, touch.y, self.x, self.y, radius) then
52         if touch.state == MOVING then
53             _, self.currentAngle = math.polar(touch.x, touch.y, self.x, self.y)
54         end
55     end
56     
57  end
58  
59  -- Utility Functions
60      
61  function Dial:reset()
62     self.currentAngle = 0
63  end
64  
65  function rotateDialByDegrees(centreX, centreY, angle)
66     translate(centreX, centreY)
67     rotate(angle)
68  end

Reference PAGE TOP

http://codeatuts.blogspot.in/2012/07/tutorial-10-simple-dial-class.html

0 Comments Leave a comment

Please login in order to leave a comment.

Newest first
!

Sign-in to your Chupamobile Account.

The Easiest way to Launch your next App or Game.

Join Chupamobile and get instant access to thousands of ready made App and Game Templates.

Creating an account means you’re okay with Chupamobile’s Terms of Service and Privacy Policy.