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!

Beyond Scripting

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.

Third, there may be other easy integrations available using some of the third party bindings our developer community has built. For example, there is a Javascript package that lets you integrate Myo controls directly into a webpage.

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!

Newsletter

Enter your email address and get all latest content delivered to your inbox every now and then.