8.1 A Skinned Directional Pad (dPad) Class
In Interlude 9 we looked at moving an object on the screen using 4 buttons. This is such a common requirement for games that the directional pad evolved and is now a ubiquitous part of any console controller. While this is not always the best control mechanism for touch screen device it has the advantage of being intuitive and simple.
We have used the earlier moveShip program to demonstrate this new dPad class. The program includes the optional standard Codea function orientationChanged(newOrientation), to demonstrate how the dPad can be automatically positioned based on the iPad orientation (i.e. landscape or portrait).
To see the dPad in action, you can download the entire moveShip code including the dPad class or just download the individual classes as required.
Because we are using sprites for the dPad skin you will need to add at least one of the following images to your linked dropbox account. The dimensions of the skins vary from 200 x 200 pixels to 250 x 250 pixels to match up with the four underlying directional buttons (up, down, left and right). If you want to create you own skins, you will need to play with the dimensions to best match the button orientation.
The first three skins have transparent sections which allow the button glow to show through when the directional buttons are pressed.
We would suggest not using the PS3 or Xbox inspired versions if you plan submitting the associated App to Apple for approval!
We will now look at the complete Directional Pad Class code.
--# DirectionalPad DirectionalPad = class() -- DirectionalPad Class -- Reefwing Software (www.reefwing.com.au) -- -- 21 July 2012 -- Version 1.0 -- -- Requires the modified @Vega Mesh Button Class v1.2 function DirectionalPad:init(x, y) -- These parameters are used to customise your dPad
The dPad class uses (x, y) to define the centre location on the screen for the dPad. The width and height is a constant in this version (250 x 250 pixels). The sprite skin may be less than this depending on the design. At the moment, only CENTER alignment is available but we will update this to handle CORNER alignment in a future version.
The four directional buttons are then defined. You can access the button parameters via the dPad class (e.g. dPad.upButton.status is valid).
Finally there are two booleans, visible which is used to determine whether to draw the dPad and tapped which is true if the last touch was on the dPad.
self.x = x self.y = y self.width = 250 self.height = 250 self.alignment = CENTER self.upButton = Button("", x - 25, y + 35, 50, 50) self.downButton = Button("", x - 25, y - 85, 50, 50) self.leftButton = Button("", x - 80, y - 25, 50, 50) self.rightButton = Button("", x + 35, y - 25, 50, 50) self.visible = true self.tapped = false end function DirectionalPad:draw() -- Codea does not automatically call this method -- The buttons are drawn under the sprite "skin" if self.visible then self.upButton:draw() self.downButton:draw() self.leftButton:draw() self.rightButton:draw()
After drawing the four directional buttons we overlay the sprite skin. Change the sprite name to change the "skin".
sprite("Dropbox:dPadLight250x250", self.x, self.y) end end function DirectionalPad:moveBy(offset) -- This function is used to move the position of the -- dPad if the iPad orientation changes. This ensures -- that it is always visible.
This function is not called automatically. Have a look at the main class to see how to use this capability. You need to implement the orientationChanged(newOrientation) function and then define your offset (e.g. local offset = dPad.x - (WIDTH - dPad.width/2 - 20)) and apply it using dPad: moveBy(offset).
self.x = self.x - offset self.upButton.x = self.upButton.x - offset self.rightButton.x = self.rightButton.x - offset self.leftButton.x = self.leftButton.x - offset self.downButton.x = self.downButton.x - offset end function DirectionalPad:touched(touch) -- Codea does not automatically call this method -- You need to pass through the touches to the -- Button class. -- -- The tapped boolean keeps track of whether the tap -- was on the dPad (true) or elsewhere (false). self.tapped = false -- Note that the pointInRect() function and the Button class in general -- assume a CORNER alignment but the DirectionalPad uses CENTER (because -- it is easier with sprites) so we need to translate between the two. local x = self.x - self.width/2 local y = self.y - self.height/2 if self.visible and pointInRect(touch.x, touch.y, x, y, self.width, self.height) then self.tapped = true self.upButton:touched(touch) self.downButton:touched(touch) self.leftButton:touched(touch) self.rightButton:touched(touch) end end