コード例 #1
0
ファイル: OpieTorso.cs プロジェクト: AmyGibson/OpieMemoryGame
    // Update is called once per frame
    void Update()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        if (!Opie.instance().update())
        {
            Debug.Log("ERROR: Opie failed to update\n");
        }
#endif
    }
コード例 #2
0
    private void LoadAndPlayBack(AudioClip ac)
    {
        StartCoroutine(LoadOneSound(ac));
#if UNITY_ANDROID && !UNITY_EDITOR
        //Opie is HAPPY to listern to the playback
        StartCoroutine(TransientEmotion(EyeType.ATTENTIVE));
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
    }
コード例 #3
0
    void Start()
    {
        logInfo = GameObject.Find("ProfileInfo").GetComponent <LogInfo>();

#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
        Opie.instance().head().set_eye_type(EyeType.ATTENTIVE, Opie.Head.instant_action());
#endif
    }
コード例 #4
0
    // Use this for initialization
    void Start()
    {
        //When entering this scene, stop the idle motion so that Opie stops
        //scanning the environment with its eyes
#if UNITY_ANDROID
        Opie.instance().behaviours("idle_motion").stop(Opie.Behaviour.instant_action());
#endif
        game_info         = GameObject.Find("GameInfo").GetComponent <GameInfo>();
        currentLevel.text = game_info.CurrentLevelToString();
    }
コード例 #5
0
    // Use this for initialization
    void Start()
    {
        //When entering this scene, stop the idle motion so that Opie stops
        //scanning the environment with its eyes
#if UNITY_ANDROID
        Opie.instance().behaviours("idle_motion").stop(Opie.Behaviour.instant_action());
#endif
        //Find the object containing profile information
        game_info = GameObject.Find("GameInfo").GetComponent <GameInfo>();
    }
コード例 #6
0
ファイル: LogInfo.cs プロジェクト: AmyGibson/OpieMemoryGame
    void Start()
    {
        //Create the file that logs the information
        Filename = GetLatestFilename();
#if UNITY_ANDROID && !UNITY_EDITOR
        //When the file is created, set the eyes to look straight up and set their emotion to ATTENTIVE
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
        Opie.instance().head().set_eye_type(EyeType.ATTENTIVE, Opie.Head.instant_action());
#endif
    }
コード例 #7
0
    private IEnumerator TransientEmotion(EyeType emote)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_eye_type(emote, Opie.Head.instant_action());
#endif
        yield return(new WaitForSeconds(2));        //2

#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
#endif
    }
コード例 #8
0
    // Use this for initialization
    void Start()
    {
        //When entering this scene, stop the idle motion so that Opie stops scanning the environment with its eyes
#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().behaviours("idle_motion").stop(Opie.Behaviour.instant_action());
#endif
        //Find the object containing profile information
        logInfo = GameObject.Find("ProfileInfo").GetComponent <LogInfo>();

        //Write the username on screen (for verification purpose)
        UsernameText.text = logInfo.PlayerName;
    }
コード例 #9
0
    //If quitting the game at that stge, go back to login screen
    public void QuitApp()
    {
        quitButton.interactable = false;
        quitPressed             = true;
#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
        logInfo.Reset();
        extRes.Reset();

        StartCoroutine(QuitAppCo());
    }
コード例 #10
0
    // Use this for initialization
    void Start()
    {
        //Find the objects containing the game data and the profile information
        gameData   = GameObject.Find("GameData").GetComponent <GameDataScript>();
        logInfo    = GameObject.Find("ProfileInfo").GetComponent <LogInfo>();
        extRes     = GameObject.Find("LoadExternalResources").GetComponent <LoadExternalResources>();
        quitButton = GameObject.Find("QuitButton").GetComponent <Button>();
        //goButton = GameObject.Find("GoButton").GetComponent<Button>();
        restartBtn = GameObject.Find("RestartButton").GetComponent <Button>();

        // move the loading resources to here to hide loading time
        // only load if not loaded
        if (!extRes.IsLoaded())
        {
            resourcesLoaded = false;
            startTime       = Time.realtimeSinceStartup;
            extRes.LoadMemoryGameResources();
            restartBtn.interactable = false;
            goButton.interactable   = false;
        }
        else
        {
            goButton.interactable   = true;
            restartBtn.interactable = true;
        }



        //Quit the application if the player has reached the last level
        if (gameData.Iteration > gameData.TotalLevel)
        {
            QuitApp();
        }


        if (gameData.Iteration == 1)
        {
            restartBtn.gameObject.SetActive(false);
        }
        else
        {
            restartBtn.gameObject.SetActive(true);
        }

        //Display the name of the user
        TextWritten.text = logInfo.PlayerName;
#if UNITY_ANDROID && !UNITY_EDITOR
        //Get Opie to look down at its tummy to observe progress
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.0f, Opie.Head.transition_action());
#endif
    }
コード例 #11
0
    void Update()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        foreach (Vector2 pos in GetTouchOrMouseInteractions())
        {
            // Get the origin of the tap
            Vector2 origin = Camera.main.ScreenToWorldPoint(pos);
            float   Xeye   = 0.5f + origin.x / (22.5f - 2f * origin.y);

            Opie.instance().head().set_linked_pose_and_eye_position(Xeye, 0.0f, Opie.Head.transition_action());
        }
#endif
    }
コード例 #12
0
    void Start()
    {
        //Find all the necessary the Game Objects
        gameData     = GameObject.Find("GameData").GetComponent <GameDataScript>();
        logInfo      = GameObject.Find("ProfileInfo").GetComponent <LogInfo>();
        originalCard = GameObject.Find("Memory Card").GetComponent <MemoryCardRecall>();
        originalStar = GameObject.Find("Star").GetComponent <Star>();
        extRes       = GameObject.Find("LoadExternalResources").GetComponent <LoadExternalResources>();
        rps          = GameObject.Find("RecallPlaySound").GetComponent <RecallPlaySound>();
        quitButton   = GameObject.Find("QuitButton").GetComponent <Button>();
        mainLog      = GameObject.Find("MainLogging").GetComponent <MainLogging>();


#if UNITY_ANDROID && !UNITY_EDITOR
        //Opie looks up with NEUTRAL emotion
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif

        //Retrieve ordering of the images, all the resources should have already been loaded
        ordering = gameData.Ordering;

        images   = extRes.MemoryImages;
        sounds   = extRes.MemorySounds;
        words    = extRes.MemoryWords;
        noOfCard = gameData.NRows * gameData.NCols / 2;

        //Shuffle the order of the cards to be Question
        questions = Enumerable.Range(0, noOfCard).ToArray();

        Shuffle(questions);

        answers = new int[noOfCard];
        for (int i = 0; i < noOfCard; i++)
        {
            answers[i] = ordering[questions[i]];
        }

        CardsSetup();

        //Initializing the vectors of correct and incorrect answers
        correct        = new List <string>();
        incorrect      = new List <string>();
        oneShotCorrect = new List <string>();
        //mcbn.GetComponent<Button>().interactable = false;

        DeactivateAllCards();
        //Present the first word (sound + transcription)
        NextQuestion();
    }
コード例 #13
0
    void Update()
    {
        //React to user touches
        foreach (Vector2 pos in getTouchOrMouseInteractions())
        {
            // Get the origin of the tap
            Vector2 origin = Camera.main.ScreenToWorldPoint(pos);
            float   Xeye   = 0.5f + origin.x / (22.5f - 2f * origin.y);

            //Get Opie to look where the touch happened
#if UNITY_ANDROID
            Opie.instance().head().set_linked_pose_and_eye_position(Xeye, 0.0f, Opie.Head.transition_action());
#endif
        }
    }
コード例 #14
0
    // Use this for initialization
    void Start()
    {
#if UNITY_ANDROID
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
        //When entering this scene, stop the idle motion so that Opie stops scanning
        //the environment with its eyes
//#if UNITY_ANDROID
//        Opie.instance().behaviours ("idle_motion").stop (Opie.Behaviour.instant_action ());
//#endif
        //Find the object containing profile information
        gameInfo = GameObject.Find("GameInfo").GetComponent <GameInfo>();
        gameData = GameObject.Find("GameData").GetComponent <GameDataScript>();
    }
コード例 #15
0
    //Check if the cards match
    private IEnumerator CheckMatch()
    {
        //If the cards match
        if (_firstRevealed.id == _secondRevealed.id)
        {
#if UNITY_ANDROID
            StartCoroutine(transientEmotion(EyeType.ATTENTIVE));
            Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
            current_score++;

            // prevent overlapping of sound, so far the only condition is if it is playing the quit sound
            if (!mps.SoundSource.isPlaying)
            {
                mps.PlayCardMatchSound();
            }

            //Debug.Log ("Scored in state " + state_machine.state.name);
            Scored();

            //If the score reaches the maximum, then go to next
            if (current_score == winning_score)
            {
                go_to_next();
                //StartCoroutine(go_to_next());
            }
        }
        else
        {
            //If the cards don't match, Opie looks sad
#if UNITY_ANDROID
            StartCoroutine(transientEmotion(EyeType.SAD));
            Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
            mps.PlayCardMismatchSound();
            yield return(new WaitForSeconds(.5f));

            Finish();

            //If the cards don't match, unreveal them
            _firstRevealed.Unreveal();
            _secondRevealed.Unreveal();
        }

        //Reinitialize the variables containing the values of the selected cards
        _firstRevealed  = null;
        _secondRevealed = null;
    }
コード例 #16
0
    public void NextQuestion()
    {
        NextBtn.interactable   = false;
        ImageDisplay.sprite    = extRes.MemoryImages[questions[questionNo]];
        targetSound            = extRes.MemorySounds[questions[questionNo]];
        targetText             = extRes.MemoryWords[questions[questionNo]];
        TranscriptionText.text = targetText;
        RecordText.text        = "";
#if UNITY_ANDROID && !UNITY_EDITOR
        // Opie looks down at the belly
        //Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.0f, Opie.Head.transition_action());
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
#endif
        if (!quitPressed)
        {
            StartCoroutine(PlayTargetSound());
        }
    }
コード例 #17
0
    void Start()
    {
#if UNITY_ANDROID
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif

        //Find all the necessary the Game Objects
        gameData      = GameObject.Find("GameData").GetComponent <GameDataScript>();
        gameInfo      = GameObject.Find("GameInfo").GetComponent <GameInfo>();
        recallResults = GameObject.Find("RecallResults").GetComponent <RecallResults>();
        recallResults.Reset();

        originalCard = GameObject.Find("Memory Card").GetComponent <MemoryCardRecall>();
        //originalStar = GameObject.Find("Star").GetComponent<Star>();

        rps        = GameObject.Find("RecallPlaySound").GetComponent <RecallPlaySound>();
        quitButton = GameObject.Find("QuitButton").GetComponent <Button>();

        //Retrieve ordering of the images, all the resources should have already been loaded
        ordering = gameData.Ordering;

        images     = gameInfo.Images;
        sounds     = gameInfo.Sounds;
        words      = gameInfo.Words;
        no_of_card = gameData.N_rows * gameData.N_cols / 2;

        //Shuffle the order of the cards to be Question
        questions = Enumerable.Range(0, no_of_card).ToArray();

        Shuffle(questions);

        answers = new int[no_of_card];
        for (int i = 0; i < no_of_card; i++)
        {
            answers[i] = ordering[questions[i]];
        }

        CardsSetup();

        DeactivateAllCards();
        //Present the first word (sound + transcription)
        NextQuestion();
    }
コード例 #18
0
    // Update is called once per frame
    void Update()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        //React to user touches
        foreach (Vector2 pos in GetTouchOrMouseInteractions())
        {
            // Get the origin of the tap
            Vector2 origin = Camera.main.ScreenToWorldPoint(pos);
            float   Xeye   = 0.5f + origin.x / (22.5f - 2f * origin.y);

            // log every tap?? what is the point of logging the position

            /*
             *          StreamWriter w;
             *          w = new StreamWriter(Application.persistentDataPath + "/" + logInfo.PlayerName + '/'
             + logInfo.Filename, true);
             +          w.WriteLine(DateTime.Now.ToString() + "\t" + origin.x.ToString() + "\t" + origin.y.ToString() + "\n");
             +          w.Close();
             */
            //using auto closes streamwrite
            //prevents problems if w.close() is not executed
            using (StreamWriter w = logInfo.LogFileInfo.AppendText())
            {
                w.WriteLine(DateTime.Now.ToString() + "\t" + origin.x.ToString() + "\t" + origin.y.ToString());
            }

            //Get opie to look where the touch occured
            Opie.instance().head().set_linked_pose_and_eye_position(Xeye, 0.0f,
                                                                    Opie.Head.transition_action());
        }
#endif

        // if we are waiting for some resources to be loaded
        if (resourceLoading)
        {
            if (extRes.AreStoryResourcesReady())
            {
                resourceLoading  = false;
                LoadingText.text = "";
                Debug.Log("Load next page time" + (Time.realtimeSinceStartup - startTime).ToString());
            }
        }
    }
コード例 #19
0
    //Called when a story sequence is finished (target found)
    private IEnumerator FinishedSequence()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        //Opie looks up
        Opie.instance().head().set_eye_type(EyeType.ATTENTIVE, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.0f, Opie.Head.transition_action());
#endif
        // no more clicking
        mask.gameObject.SetActive(false);

        //Target has been found, so the text of the sequence is read
        sps.PlayStorySound(currentSound);

        //Wait for sound to be finished
        yield return(new WaitWhile(() => sps.SoundSource.isPlaying));

        if (quitPressed)
        {
            yield break; // stop the coroutine entirely
        }

        //Move to next level (or quit if last level is reached)
        level++;
        if (level > totalLevels)
        {
            QuitApp();
            yield break;
        }


        // in case the next page is still loading for some reason
        if (resourceLoading)
        {
            LoadingText.text = "loading next page";
        }
        // wait for the loading to finish
        yield return(new WaitWhile(() => resourceLoading));


        // if not quited not finished, move to next page
        SetupNextPage();
    }
コード例 #20
0
    //If quitting the game at that stge, go back to login screen
    public void quit_app()
    {
        // the only way for quitPressed to be true here is when the game has started progressing to
        // next stage, so should not quit. this is an extra safeguard in case the disabling the button
        // doesnt happen fast enough. Unity doesnt always update the UI immediately
        if (quitPressed)
        {
            return;
        }

        quitPressed = true;
#if UNITY_ANDROID
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
        gameData.Reset();
        quitButton.interactable = false;

        UnityEngine.SceneManagement.SceneManager.LoadScene("language_selection");
        //StartCoroutine(QuitAppCo());
    }
コード例 #21
0
    void Start()
    {
        //Find the objects containing Game Data and Profile Info
        gameData = GameObject.Find("GameData").GetComponent <GameDataScript>();

        //Retrieve ordering of the images
        ordering = gameData.Ordering;
#if UNITY_ANDROID && !UNITY_EDITOR
        //Opie looks up with NEUTRAL emotion
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
        StateMachineInit();
        CardsSetup();
        mps = GameObject.Find("MemoryPlaySound").GetComponent <MemoryPlaySound>();



        //UnityEngine.SceneManagement.SceneManager.LoadScene("Recall");
    }
コード例 #22
0
    private void SetupNextPage()
    {
        //Set the background and mask to the next level (already loaded)
        background.sprite = extRes.StoryNextImage;
        mask.sprite       = extRes.StoryNextMask;
        currentSound      = extRes.StoryNextSound;
        mask.gameObject.SetActive(true);

#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_eye_type(EyeType.NEUTRAL, Opie.Head.instant_action());
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif

        // preload the page after in the background and the user is playing with the current
        // page
        if (level + 1 <= totalLevels)
        {
            resourceLoading = true;
            startTime       = Time.realtimeSinceStartup;
            extRes.LoadStoryNextPage(level + 1);
        }
    }
コード例 #23
0
    public void QuitApp()
    {
        // the only way for quitPressed to be true here is when the game has started progressing to
        // next stage, so should not quit. this is an extra safeguard in case the disabling the button
        // doesnt happen fast enough. Unity doesnt always update the UI immediately
        if (quitPressed)
        {
            return;
        }
        DeactivateAllCards();
        quitPressed = true;
#if UNITY_ANDROID && !UNITY_EDITOR
        Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
        gameData.Reset();
        logInfo.Reset();
        extRes.Reset();

        quitButton.interactable = false;

        StartCoroutine(QuitAppCo());
    }
コード例 #24
0
    void Update()
    {
        // scene transition here so that if the app is quitted half way through recording the
        // mic is stopped and audio is discarded to prevent errors/junk data
        // "recordingDone" should only be true after recording and it is safe to SavWav
        if (recordingDone)
        {
            GoToNext();
        }

#if UNITY_ANDROID && !UNITY_EDITOR
        //React to user touches
        foreach (Vector2 pos in GetTouchOrMouseInteractions())
        {
            // Get the origin of the tap
            Vector2 origin = Camera.main.ScreenToWorldPoint(pos);
            float   Xeye   = 0.5f + origin.x / (22.5f - 2f * origin.y);

            //Get Opie to look where the touch happened
            Opie.instance().head().set_linked_pose_and_eye_position(Xeye, 0.0f, Opie.Head.transition_action());
        }
#endif
    }
コード例 #25
0
    void Update()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        //Define what happens when the user touches
        foreach (Vector2 pos in GetTouchOrMouseInteractions())
        {
            // Get the origin of the tap
            Vector2 origin = Camera.main.ScreenToWorldPoint(pos);
            float   Xeye   = 0.5f + origin.x / (22.5f - 2f * origin.y);

            //Get Opie to look at the position where the touch occurred
            Opie.instance().head().set_linked_pose_and_eye_position(Xeye, 0.0f, Opie.Head.transition_action());
        }
#endif
        //For debugging only (keyboard)
        if (Input.GetKey("escape"))
        {
            StopAllCoroutines();
            Application.Quit();
        }

        //Update the state machine
        state_machine.update();
    }
コード例 #26
0
    private IEnumerator CheckMatch(int idClicked)
    {
        /*
         * // below is to control the game flow
         * // if at soon as the game is loaded, someone press an image
         * // it will 1. cut off the instruction 2. still play the current word
         * // before going to the next word
         * //
         * // I have changed my mind later, all cards are deactivated initially
         * // so the below code doesnt do anything
         * if (questionNo == 0)
         * {
         *  rps.SoundSource.Stop(); //to cut off the instruction
         *
         *  yield return new WaitWhile(() => rps.SoundSource.isPlaying);
         *  // for some reason it doesnt stop immediately
         *
         *  yield return new WaitWhile(() => rps.SoundSource.isPlaying);
         *  // this is to make sure the target word is played in full
         * }
         */

        attempts++;

        //If there is a match
        if (idClicked == answers[questionNo])
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            //Opie is HAPPY if the guess is right
            StartCoroutine(TransientEmotion(EyeType.ATTENTIVE));
            Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
            correctScore++;

            stars[questionNo].Setfilled();

            rps.PlayCardMatchSound();
            yield return(new WaitWhile(() => rps.SoundSource.isPlaying));


            //Add the trasncripton of the word to the list of correctly recognized words (for teacher feedback)
            correct.Add(targetTranscription);

            if (noOfCard > 1 && attempts == 1)
            {
                oneShotCorrect.Add(targetTranscription);
            }

            attempts = 0;
            //if trying mode
            if (!CheckIfDone())
            {
                //Increment the question number
                questionNo++;
                NextQuestion();
            }
        }
        else
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            //Opie is SAD if the guess is wrong
            StartCoroutine(TransientEmotion(EyeType.SAD));
            Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.5f, Opie.Head.transition_action());
#endif
            rps.PlayCardMismatchSound();
            yield return(new WaitWhile(() => rps.SoundSource.isPlaying));

            //Add the transcirption of the word to the list of incorrectly recognized words (for teacher feedback)
            incorrect.Add(targetTranscription);

            // if trying mode
            StartCoroutine(BlockPlayWord(questionNo));
        }


        // if testing mode

        /* if (!CheckIfDone())
         * {
         *   //Increment the question number
         *   questionNo++;
         *   NextQuestion();
         * }*/
    }
コード例 #27
0
    private void StateMachineInit()
    {
        //Defining the State machine defining the game states
        state_machine = new StateMachine(
            new Transition[] {
            new Transition {
                from = STATE_NONE_SELECTED, ev = EVENT_CLICK, to = STATE_FIRST_FLIPPING
            },
            new Transition {
                from = STATE_FIRST_FLIPPING, ev = EVENT_FINISHED, to = STATE_FIRST_PLAYING
            },
            new Transition {
                from = STATE_FIRST_PLAYING, ev = EVENT_FINISHED, to = STATE_FIRST_SELECTED
            },
            new Transition {
                from = STATE_FIRST_SELECTED, ev = EVENT_CLICK, to = STATE_SECOND_FLIPPING
            },
            new Transition {
                from = STATE_SECOND_FLIPPING, ev = EVENT_FINISHED, to = STATE_SECOND_PLAYING
            },
            new Transition {
                from = STATE_SECOND_PLAYING, ev = EVENT_FINISHED, to = STATE_MATCHING
            },
            new Transition {
                from = STATE_MATCHING, ev = EVENT_FINISHED, to = STATE_FIRST_FLIPPING_BACK
            },
            new Transition {
                from = STATE_MATCHING, ev = EVENT_SCORED, to = STATE_NONE_SELECTED
            },
            new Transition {
                from = STATE_FIRST_FLIPPING_BACK, ev = EVENT_FINISHED, to = STATE_SECOND_FLIPPING_BACK
            },
            new Transition {
                from = STATE_SECOND_FLIPPING_BACK, ev = EVENT_FINISHED, to = STATE_NONE_SELECTED
            }
        }
            );

        state_machine.onTransition = (Transition transition) => {
            // Debug.Log("transition: " + transition.from.name + ": " + transition.ev.name + " -> " + transition.to.name);
        };

        //State reached when the first card has been selected
        STATE_FIRST_FLIPPING.onEnter = (State state, Event ev) => {
            current_card.StartFlipAndPlay();
        };

        //State reached when the second card has been selected
        STATE_SECOND_FLIPPING.onEnter = (State state, Event ev) => {
            current_card.StartFlipAndPlay();
        };

        //Once both cards are selected, check if they match
        STATE_MATCHING.onEnter = (State state, Event ev) => {
            StartCheckMatch();
        };

        //Once the cards are checked, go back to the "default" state with no cards selected.
        STATE_NONE_SELECTED.onEnter = (State state, Event ev) => {
            //Opie looks down at its tummy to invite the user to tap the cards
#if UNITY_ANDROID
            Opie.instance().head().set_linked_pose_and_eye_position(0.5f, 0.0f, Opie.Head.transition_action());
#endif
        };


        //State machine initialization
        state_machine.init(STATE_NONE_SELECTED);
    }