コード例 #1
0
    // This is meant to "smooth" the data and make it less noisy by averaging the last NUMFRAMES.
    private AffectiveStates averageState()
    {
        AffectiveStates state = AffectiveStates.None;

        lastFrames[frame] = determineState(); // This gets the state for the current frame.
        frame             = ((frame + 1) % NUMFRAMES);
        int nones = 0;
        int frust = 0;
        int bored = 0;
        int flow  = 0;

        // Count the number of each state we've got on record.
        for (int i = 0; i < NUMFRAMES; i++)
        {
            switch (lastFrames[i])
            {
            case AffectiveStates.Boredom:
                bored++;
                break;

            case AffectiveStates.Flow:
                flow++;
                break;

            case AffectiveStates.Frustration:
                frust++;
                break;

            default:
                nones++;
                break;
            }
        }
        // Most frequent wins.
        if ((frust > bored) && (frust > flow) && (frust > nones))
        {
            state = AffectiveStates.Frustration;
        }
        else if ((bored > flow) && (bored > nones))
        {
            state = AffectiveStates.Boredom;
        }
        else if (flow > nones)
        {
            state = AffectiveStates.Flow;
        }
        // else - we already have none stored in state.
        //Debug.Log((int)state);
        return(state);
    }
コード例 #2
0
    /// <summary>
    /// This is the hard one, where the real work happens. This is where we determine the affective state from the current frame.
    /// Visage gives us the emotion estimations, that's the easy part. The hard part is going from those six measures to our
    /// affective states. Literature, such as Craig et al. (2008), tell us that the affective states will appear as the following:
    /// Boredom: Neutrality, no real emotion showed.
    /// Frustration: High anger, low happiness. May also include disgust, but disgust proved unreliable.
    /// Flow: Surprise/Awe and low sadness. May also appear as neutrality, which can cause confusion when compared to boredom.
    /// Based on those, the measures used below were created to try and detect each of these. Feel free to modify this as
    /// needed, but be aware that even small changes will have a major impact on affective state detection. If you feel that
    /// the states are being detected incorrectly, this is the part to modify.
    /// </summary>
    private AffectiveStates determineState()
    {
        AffectiveStates state = AffectiveStates.None;
        // DETECT BOREDOM: If all estimations are below THRESHOLD, player is showing neutrality.
        bool nonBored = false;

        for (int i = 0; ((i < probs.Length) && (!nonBored)); i++)
        {
            if (probs[i] > THRESHOLD)
            {
                nonBored = true;
            }
        }
        // If player is not bored, they must be something else.
        if (nonBored)
        {
            // DETECT FRUSTRATION: High anger and low happiness is a sign of frustration.
            if ((probs[ANGER] > THRESHOLD) && (probs[HAPPINESS] < THRESHOLD))
            {
                state = AffectiveStates.Frustration;
            }
            // Player is not frustrated, are they in flow?
            else
            {
                // DETECT FLOW: Noticible surprise and low sadness show flow.
                if ((probs[SURPRISE] > THRESHOLD) && (probs[SADDNESS] < THRESHOLD))
                {
                    state = AffectiveStates.Flow;
                }
                // NOTE! No else here. If we get here, all of our measures have failed.
                // This means that the player is in a state we can't recognize, so we return None.
            }
        }
        else
        {
            // Double check that they might be in Flow, as it can look a lot like boredom.
            // DETECT FLOW: If they appear bored and are currently in flow, or just were in flow, they're probably in flow still/again.
            if ((currentState == AffectiveStates.Flow) || (lastState == AffectiveStates.Flow))
            {
                state = AffectiveStates.Flow;
            }
            // Nope, they are truely bored.
            else
            {
                state = AffectiveStates.Boredom;
            }
        }
        return(state);
    }
コード例 #3
0
 // Update is called once per frame
 void Update()
 {
     if (tracking)
     {
         if (gameObject.GetComponent <Tracker>().TrackerStatus != 0)
         {
             ///////////////////////////////////////////////////////////////////////////////////////////////////////
             // Emotions are acqured here! Be extremely careful about making any changes to these two lines!
             // The entire emotion system depends on these working successfully.
             IntPtr nums = VisageTrackerNative._getEmotions();
             // Due to cross language type mangling, we have to marshal the result into something we can use.
             Marshal.Copy(nums, probs, 0, 6);
             ///////////////////////////////////////////////////////////////////////////////////////////////////////
             FileManagement.dump(probs);
             if (probs[0] != -9999) // -9999 is the "error" code from the plugin.
             {
                 for (int i = 0; i < probs.Length; i++)
                 {
                     // Truncate to three places for easier display
                     probs[i] = (float)Math.Truncate(1000 * probs[i]) / 1000;
                 }
                 haveRecentData = true;
             }
             else
             {
                 haveRecentData = false;
                 currentState   = AffectiveStates.None;
             }
         }
         else
         {
             haveRecentData = false;
         }
         // If we have gotten recent data, and are not waiting for the next wave, analyse it.
         if (haveRecentData && !waitForWave)
         {
             analyzeData();
         }
     }
 }
コード例 #4
0
    // Helper to translate affective state.
    private static string getState(AffectiveStates state)
    {
        string print;

        switch (state)
        {
        case AffectiveStates.Boredom:
            print = "Boredom";
            break;

        case AffectiveStates.Flow:
            print = "Flow";
            break;

        case AffectiveStates.Frustration:
            print = "Frustration";
            break;

        default:
            print = "None";
            break;
        }
        return(print);
    }
コード例 #5
0
 // Called when an emotion has been detected long enough for us to make judgements off of it.
 public static void emotionMax(AffectiveStates state)
 {
     print("EMOTION MAX REACHED - The player has been detected in " + getState(state) + " for long enough to consider it their new state.");
 }
コード例 #6
0
 // Called when a new affective state is detected.
 public static void stateChange(AffectiveStates state)
 {
     print("STATE CHANGE - NEW STATE -> " + getState(state));
 }
コード例 #7
0
    // This is where we begin trying to determine the player's affective state.
    private void analyzeData()
    {
        // Are we waiting between changes?
        if (currentDelay > 0)
        {
            currentDelay--;
        }
        else
        {
            // Do we need to update the data?
            if (wasWaiting)
            {
                haveRecentData = false;
                wasWaiting     = false;
                // Reset stored frames to ensure we don't accidentally make judgements off them.
                for (int i = 0; i < lastFrames.Length; i++)
                {
                    lastFrames[i] = AffectiveStates.None;
                }
                FileManagement.delayEnd();
            }
            else
            {
                AffectiveStates update = averageState();
                // Are they still in the same state?
                if (currentState == update)
                {
                    // Only increase this if we are tracking an actual emotion
                    if (currentState != AffectiveStates.None)
                    {
                        currentEmotionDuration++;
                    }
                }
                else
                {
                    // State has changed. Reset everything.
                    currentState           = update;
                    currentEmotionDuration = 0;
                    FileManagement.stateChange(currentState);
                }
                // Have they sustained that emotion long enough to consider it their state?
                if (currentEmotionDuration == EMOTIONMAX)
                {
                    // Reset everything.
                    lastState              = currentState;
                    wasWaiting             = true;
                    currentDelay           = ANALYSISDELAY;
                    currentEmotionDuration = 0;
                    FileManagement.emotionMax(currentState);
                    waitForWave = true;
                    Debug.Log((int)currentState);
                    // Determine how (if at all) we need to modify difficulty.
                    switch (currentState)
                    {
                    case AffectiveStates.Boredom:
                        curDifficulty = stepUp();
                        //setDifficulty(1);
                        Debug.Log("stepUp");
                        break;

                    case AffectiveStates.Frustration:
                        curDifficulty = stepDown();
                        Debug.Log("stepDown");
                        //setDifficulty(1);
                        break;

                    case AffectiveStates.Flow:
                        // If they're in Flow, don't change anything for awhile.
                        currentDelay = ANALYSISDELAY * 3;
                        Debug.Log("Flow");
                        break;
                    }
                    DifficultyManagement.setDifficulty(curDifficulty);
                }
            }
        }
    }