Part Six: Beyond Scripting
Hello again. This is the last part of our advanced Myo Script tutorial on orientation and gestures. You can find parts one, two, three, four and five here. Today, I’ll leave you with the final Race The Sun script as well as some thoughts on when you might want to use something other than Myo Script to Myo-enable a game or app.
But first, the final script:
scriptId = 'com.thalmic.examples.racethesun' scriptTitle = "Race The Sun" scriptDetailsUrl = "https://market.myo.com/app/5478fb74e4b05772f1d76920" description = [[ Race the Sun From the Steam description: You are a solar craft. The sun is your death timer. Hurtle towards the sunset at breakneck speed in a futile race against time. Delay the inevitable by catching energy boosts which reverse the setting sun - if only for a moment. Problems? Talk to us (@thalmicdev) Demo here: http://www.kongregate.com/games/flippfly/race-the-sun ]] link = [[http://store.steampowered.com/app/253030/]] controls = [[ Controls: - Hold wave out enable/disable mouse control - Wave in to click - Fist to center your yaw/roll, and then yaw left/right to fly left/right - Fist also hits "enter" on menus - Wave up/down to jump if you get a jump pickup - Fingers spread to hit escape and pause or back up in the menus ]] knownIssues = [[ - None ]] centreYaw = 0 centreRoll = 0 deltaRoll = 0 YAW_DEADZONE = .1 ROLL_DEADZONE = .2 MOUSE_CONTROL_TOGGLE_DURATION = 1000 PI = 3.1416 TWOPI = PI * 2 flyingLeft = false flyingRight = false togglingMouseControl = 0 mouseEnabled = true printCount = 0 function onForegroundWindowChange(app, title) --myo.debug("onForegroundWindowChange: " .. app .. ", " .. title) local titleMatch = string.match(title, "Play Race The Sun, a free online game on Kongregate") ~= nil or platform == "MacOS" and app == "unity.Flippfly.RaceTheSun" or platform == "Windows" and app == "RaceTheSun.exe" myo.controlMouse(titleMatch and mouseEnabled); if (titleMatch) then myo.setLockingPolicy("none") end return titleMatch; end function onPoseEdge(pose, edge) --myo.debug("onPoseEdge: " .. pose .. ", " .. edge) if (edge == "on") then if (pose == "fist") then centre() if (mouseEnabled) then toggleMouseControl() end elseif (pose == "fingersSpread") then escape(); elseif (pose == "waveIn" or pose == "waveOut") then if (math.abs(deltaRoll) > ROLL_DEADZONE) then jump() elseif (pose == "waveIn") then leftClick() else if (mouseEnabled) then toggleMouseControl(); else togglingMouseControl = myo.getTimeMilliseconds(); end end end else togglingMouseControl = 0 end end function activeAppName() return "Race The Sun" end function centre() --myo.debug("Centred") centreYaw = myo.getYaw() centreRoll = myo.getRoll() myo.controlMouse(false); myo.vibrate("short") myo.keyboard("return", "press") end function onPeriodic() if (togglingMouseControl > 0 and myo.getTimeMilliseconds() > (togglingMouseControl + MOUSE_CONTROL_TOGGLE_DURATION)) then togglingMouseControl = 0 toggleMouseControl() end if (centreYaw == 0) then return end local currentYaw = myo.getYaw() local currentRoll = myo.getRoll() local deltaYaw = calculateDeltaRadians(currentYaw, centreYaw) deltaRoll = calculateDeltaRadians(currentRoll, centreRoll); printCount = printCount + 1 if printCount >= 200 then --myo.debug("deltaYaw = " .. deltaYaw .. ", centreYaw = " .. centreYaw .. ", currentYaw = " .. currentYaw) --myo.debug("deltaRoll = " .. deltaRoll .. " currentRoll = " .. currentRoll) printCount = 0 end if (deltaYaw < -YAW_DEADZONE) then flyLeft() elseif (deltaYaw > YAW_DEADZONE) then flyRight() else flyNeutral() end end function flyLeft() if (flyingRight) then --myo.debug("Not flying right"); myo.keyboard("right_arrow","up") flyingRight = false end if (not flyingLeft) then --myo.debug("Flying left"); myo.keyboard("left_arrow","down") flyingLeft = true; end end function flyRight() if (flyingLeft) then --myo.debug("Not flying left"); myo.keyboard("left_arrow","up") flyingLeft = false end if (not flyingRight) then --myo.debug("Flying right"); myo.keyboard("right_arrow","down") flyingRight = true end end function jump() --myo.debug("Jump!") myo.keyboard("space","press") end function flyNeutral() if (flyingLeft) then --myo.debug("Not flying left"); myo.keyboard("left_arrow","up") flyingLeft = false end if (flyingRight) then --myo.debug("Not flying right"); myo.keyboard("right_arrow","up") flyingRight = false end end function calculateDeltaRadians(currentYaw, centreYaw) local deltaYaw = currentYaw - centreYaw if (deltaYaw > PI) then deltaYaw = deltaYaw - TWOPI elseif(deltaYaw < -PI) then deltaYaw = deltaYaw + TWOPI end return deltaYaw end function toggleMouseControl() mouseEnabled = not mouseEnabled myo.vibrate("medium") if (mouseEnabled) then --myo.debug("Mouse control enabled") centreYaw = 0 flyNeutral() else --myo.debug("Mouse control disabled") end myo.controlMouse(mouseEnabled); end function leftClick() --myo.debug("Left click!") myo.mouse("left", "click") end function escape() --myo.debug("Escape!") centreYaw = 0 myo.keyboard("escape","press") end
Note that it has a scriptDetailsUrl link now. That’s because you can actually go and download this script in the Myo Market. Make sure you remember to update that property as you are submitting your script!
That’s all for Myo Script! Quite easy and powerful, no? We haven’t talked about the gyroscope and accelerometer support, or the MIDI support, but that’s basically it. We’ll have to leave those for another tutorial.
You may be wondering at this point why you would ever use any of the actual SDKs. First, if you want to target a mobile platform, scripting is not available. You’ll have to use the full Android or iOS SDK.
Second, if you actually control the application’s source, asking the user to install a script may be a needless extra hassle.
But finally, there is a whole suite of problems you can run into by not knowing the state of the app you are targeting. We almost hit this in Race The Sun. How do we know if the user is in the menu or not? We solved that with a gesture to let the user enable/disable the mouse, but wouldn’t it be better if mouse control just automatically turned on and off at the right time? What if we wanted to have several sets of totally different controls for different stages or minigames? Myo enabled quicktime events?
What if the window title is not a useful identifier?
Clearly, though Myo Scripts are a great way to Myo-enable existing apps, rapidly prototype experiments, and give users the power to use their Myo armband to control the things they want, there are still times when a full SDK is the way to go.
If you're hungry for more, check out #MyoCraft, an ongoing series full of Myo developer tips, including a bunch of more sophisticated Myo Script techniques. If you ever get stuck or have any questions, don’t forget you can always jump on Developer Forums! Follow the official @ThalmicDev Twitter account and sign up for our newsletter to stay up to date with all the latest Myo development news. And of course, stay tuned to this blog (RSS).
Good luck, and happy coding!