We now have physical events being passed in a very understandable format. We have a little bit of work left to do to translate these events (which are still specifically about the physical condition of the device) into commands for the player.
The math in this section is almost as abstract as the previous task, because the design specifies that the ship's acceleration is going to be based on how strongly the device's tilt aligns with the ship's facing direction, and the speed with which it turns will be based on how much the direction of tilt runs across the ship's facing.
Save any other open files and open game.lua
.
pythagorean
distance module is loaded; we'll need it in this file as well:local scene = storyboard.newScene()
require "math.pythagorean"
local physics = require "physics"
Tilt
events will be translated into Thrust
and Yaw
events on the game scene, before the event handlers:local physics = require "physics" function scene:Tilt(event) end function scene:createScene( event )
math.sin
, then we'll determine the angle and length of the 2D vector they create using familiar methods.function scene:Tilt(event) local lateral, vertical = math.sin(event.lateral), math.sin(event.vertical) local theta, r = -math.atan2(lateral, -vertical), math.pythagorean(lateral, vertical) end
local theta, r = -math.atan2(lateral, -vertical), math.pythagorean(lateral, vertical) theta = theta - math.rad(self.Player.rotation) lateral, vertical = math.sin(theta) * r, math.cos(theta) * r end
local threshold = 1/6 function scene:Tilt(event) local lateral, vertical = math.sin(event.lateral), math.sin(event.vertical) local theta, r = -math.atan2(lateral, -vertical), math.pythagorean(lateral, vertical) theta = theta - math.rad(self.Player.rotation) lateral, vertical = math.sin(theta) * r, math.cos(theta) * r if math.abs(lateral) < threshold then lateral = 0 end if math.abs(vertical) < threshold then vertical = 0 end end
Thrust
and Yaw
as events for the player object to catch:if math.abs(vertical) < threshold then vertical = 0 end self:dispatchEvent{name='Thrust'; value = vertical * 1/3} self:dispatchEvent{name='Yaw'; value = lateral * 64} end
Tilt
events whenever the scene is fully loaded, and stop receiving them when the scene leaves the foreground:function scene:enterScene( event ) physics.start() Runtime:addEventListener('Tilt', self) end function scene:exitScene( event ) Runtime:removeEventListener('Tilt', self) end
There are two challenges with running game objects directly off of the enterFrame
event sent to Runtime
:
enterFrame
events of Runtime
, then if you want to do something like pause the game, you have to find each of these objects individually and disengage them, or build each listener to check some kind of common isPaused
value.We'll use a custom event, clock
, to solve both of these things. The listener for this event will track the time of consecutive enterFrames
to include the elapsed duration between them. Because any objects that need to know about time passing in the game will listen to the game scene itself for these clock events, the game scene itself can be responsible for turning them off by disconnecting itself from the Runtime
events that drive them. We can turn only one listener on and off instead of an indefinite number.
The player
object is already programmed to listen for these events, so we need to create the bridge that will send them.
enterFrame
events when it's listening to them:local physics = require "physics" local clock, previous = 0, system.getTimer() function scene:enterFrame(event) end local threshold = 1/6
function scene:enterFrame(event)
local elapsed = event.time - previous
end
function scene:enterFrame(event)
local elapsed = event.time - previous
clock, previous = clock + elapsed, event.time
end
clock, previous = clock + elapsed, event.time
self:dispatchEvent{name = "clock"; clock = self, delta = elapsed, time = clock}
end
enterFrame
events:self:dispatchEvent{name = "clock"; clock = self, delta = elapsed, time = clock} end function scene:Start() previous = system.getTimer() Runtime:addEventListener('enterFrame', self) end local threshold = 1/6
Runtime:addEventListener('enterFrame', self) end function scene:Stop() local elapsed = system.getTimer() - previous self:dispatchEvent{name = "clock"; clock = self, delta = elapsed, time = clock} Runtime:removeEventListener('enterFrame', self) end local threshold = 1/6
Runtime:removeEventListener('enterFrame', self) end scene:addEventListener('clock', scene) function scene:clock(event) if self.view then self.World:dispatchEvent(event) end end local threshold = 1 / 6
function scene:enterScene( event ) physics.start() Runtime:addEventListener('Tilt', self) self:Start() end -- Called when scene is about to move offscreen: function scene:exitScene( event ) Runtime:removeEventListener('Tilt', self) self:Stop() end
This task has been about interpreting the intended meaning of fundamental events; converting the angle of the device into instructions for the player object, and controlling how the passage of time for the device's clock controls the passage of time for the game.
At this point, you should be able to build the project for the device and test how the player ship moves as you tilt the device in various directions.
18.118.186.202