Now that the game displays a level correctly, we need to start adding the ability to communicate with it.
We imported a pre-packaged interface.lua
file from version 1
, but it doesn't do anything. Actually, it does one thing: it returns a blank group, which fills in the space that the rest of the game needs occupied to work, but doesn't actually send or respond to any events.
Open the interface.lua
file and remove the starting placeholder that says:
return display.newGroup()
We'll expand the interface group with the required behaviors:
display
group, so we'll break it out into a variable so that we can add to it before we return it:return function(game) local self = display.newGroup() return self end
0
:local self = display.newGroup() local counter = display.newText(self, "0", 10, 10, native.systemFont, 24) counter:setReferencePoint(display.CenterLeftReferencePoint) return self end
Move
event happens on the game
object, this count needs to be updated. The following pattern to adjust the text and keep it aligned should be familiar:counter:setReferencePoint(display.CenterLeftReferencePoint) function counter:Move(event) if event.count then local x, y = self.x, self.y self.text = event.count self:setReferencePoint( display.CenterLeftReferencePoint) self.x, self.y = x, y end end game:addEventListener('Move', counter) return self
In other words, the counter listens for the Move
events on the game; if the event has an associated count of moves taken, the counter updates itself to display that count.
Runtime
, that creates problems when the scene stops being active (we'll discuss that problem in more detail in a later project). The interface will collect all its touch
and tap
events from the scene's associated group, which collects all touches on its children (such as the world
scene) that aren't handled by those children.return function(game)
local self = display.newGroup()
local target = game.view
local counter = display.newText(self, "0", 10, 10, native.systemFont, 24)
local fade = {delay = 5000, time = 750; alpha = 0}
return function(game)
touch
handler becomes fairly easy to write at this point; we need to track the transition for the fade
event, so it can be cancelled, which is easily done as a property of the text object:self.x, self.y = x, y end end function counter:touch(event) if self.Fade then transition.cancel(self.Fade) end self.alpha = 1.0 self.isVisible = true self.Fade = transition.to(self, fade) end target:addEventListener('touch', counter) game:addEventListener('Move', counter)
self.Fade = transition.to(self, fade)
end
counter:touch()
target:addEventListener('touch', counter)
The last element of the interface is not complicated code, but it takes some real math to design properly. We need to identify taps as being in one of the four compass directions compared to the screen. To reduce user mishaps, we will discard taps that happen too near a boundary between one direction and another.
We have two challenges here: recognizing whether a touch is in one of the active zones or not, and "snapping" the directions being output to the exact compass points. We can get the angle of the touch with the math.atan2
function, but the tough part is the east quadrant. The polar axis, the point where the zero angle lies on graphs, is right in the middle of it. Angles that should be registered for the eastern direction range from 0-π/8 (Lua's trigonometric functions all return results in radians), but also from 15π/8-0. While this problem could be solved with a long if/elseif
statement, we can solve the whole problem fairly simply by just adding π/8 (one-sixteenth of a circle), moving the angles under consideration to line up with the zero line.
At this point, solving both questions becomes much easier. We can slice the circle into eight wedges, and determine which wedge the specified angle falls into by dividing the angle by one-eighth of a circle, π/4. You can clip the fractional part of the wedge off with math.floor()
and normalize it into a range (eliminating negative angles or angles over a full circle) by taking the result modulus 8
(that is, dividing by eight and keeping only the remainder).
In this way, a fractional number from 0 to 2π is converted into an integer from zero to seven. Because we're only interested in the wedges zero, two, four, and six, we can compare the wedge index modulus 2
to 0
to determine if it's a valid touch, and then multiply the wedge number by an eighth of a circle, π/4, to obtain the final direction, pointing straight right, down, left, or up.
local function checkMove(self, event) local direction = math.atan2(event.y - display.contentCenterY, event.x - display.contentCenterX) + math.pi / 8 direction = math.floor(direction * 4 / math.pi) % 8 if direction % 2 == 0 then self:dispatchEvent{name = 'Move'; action = 'attempt', direction = direction * math.pi / 4 } end return true end return function(game) local self = display.newGroup()
This new function just has to be attached to the interface to handle touches on the target using the following code:
local target = game.view self.tap = checkMove target:addEventListener('tap', self) local counter = display.newText(self, "0", 10, 10, native.systemFont, 24)
The dispatchEvent
call triggers an event targeted on the interface that indicates that the player tried to move in a particular direction. This event has no clue about whether the attempted move is legal or will produce any results. It only says that the player tried to move, and which way.
18.226.4.239