1
\$\begingroup\$
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class MouthSpeechController : MonoBehaviour
{
    public TMP_Text[] texts;
    public bool startTalking = false;
    public float talkTime;
    public float duration;
    [Range(0, 100)]
    public float valueRange;
    private SkinnedMeshRenderer bodySkinnedMeshRenderer;
    private bool isTalking = true;

    // Start is called before the first frame update
    void Start()
    {
        bodySkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
    }

    // Update is called once per frame
    void Update()
    {
        if (startTalking && isTalking)
        {
            StartCoroutine(AnimateMouth());
            StartCoroutine(TalkTime());

            isTalking = false;
        }

        if (startTalking == false && isTalking == false)
        {
            isTalking = true;
        }
    }

    //Lerp between startValue and endValue over 'duration' seconds
    private IEnumerator LerpShape(float startValue, float endValue, float duration)
    {
        float elapsed = 0;
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float value = Mathf.Lerp(startValue, endValue, elapsed / duration);
            bodySkinnedMeshRenderer.SetBlendShapeWeight(0, value);
            yield return null;
        }
    }

    //animate open and closed, then repeat
    public IEnumerator AnimateMouth()
    {
        while (startTalking == true)
        {
            yield return StartCoroutine(LerpShape(0, valueRange, duration));
            yield return StartCoroutine(LerpShape(valueRange, 0, duration));
        }
    }

    public IEnumerator TalkTime()
    {
        yield return new WaitForSeconds(talkTime);

        startTalking = false;
    }
}

The script is working but to get it working from other scripts I need first to make a reference for example :

public PlayerMouthSpeechController playermouthspeechcontroller;

Then somewhere for example in the Start to set the time :

private void Start()
    {
        playermouthspeechcontroller.talkTime = 10;
    }

Then in somewhere else and it's all in the same script I need to make it start talking :

playermouthspeechcontroller.startTalking = true;

Instead maybe to make an option using maybe a public static method that all I will need to do is to type something like this in every script I want it to talk :

MouthSpeechController.StartTalking(10f);

One line and it will start talking for 10 seconds. To leave also the other options if I want to set the time in someplace and start in other place but also to make something public static I think it's good logic to start the talking with one line.

I tried this. Added instance static variable init the instance in the Awake and added the static method at the bottom of the script. At the Start, I tried to test it but it does nothing.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class MouthSpeechController : MonoBehaviour
{
    public TMP_Text[] texts;
    public bool startTalking = false;
    public float talkTime;
    public float duration;
    [Range(0, 100)]
    public float valueRange;
    private SkinnedMeshRenderer bodySkinnedMeshRenderer;
    private bool isTalking = true;
    private static MouthSpeechController instance;

    private void Awake()
    {
        instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        bodySkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();

        StartTalking(10f);
    }

    // Update is called once per frame
    void Update()
    {
        if (startTalking && isTalking)
        {
            StartCoroutine(AnimateMouth());
            StartCoroutine(TalkTime(talkTime));

            isTalking = false;
        }

        if (startTalking == false && isTalking == false)
        {
            isTalking = true;
        }
    }

    //Lerp between startValue and endValue over 'duration' seconds
    private IEnumerator LerpShape(float startValue, float endValue, float duration)
    {
        float elapsed = 0;
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float value = Mathf.Lerp(startValue, endValue, elapsed / duration);
            bodySkinnedMeshRenderer.SetBlendShapeWeight(0, value);
            yield return null;
        }
    }

    //animate open and closed, then repeat
    public IEnumerator AnimateMouth()
    {
        while (startTalking == true)
        {
            yield return StartCoroutine(LerpShape(0, valueRange, duration));
            yield return StartCoroutine(LerpShape(valueRange, 0, duration));
        }
    }

    public IEnumerator TalkTime(float TalkTime)
    {
        yield return new WaitForSeconds(TalkTime);

        startTalking = false;
    }

    public static void StartTalking(float TalkingTime)
    {
        instance.StartCoroutine(instance.AnimateMouth());
        instance.StartCoroutine(instance.TalkTime(TalkingTime));
    }
}
\$\endgroup\$
6
  • 3
    \$\begingroup\$ What problems have you encountered adding a method that encapsulates the steps you've listed? \$\endgroup\$ – Pikalek May 21 at 20:11
  • \$\begingroup\$ @Pikalek The problem is that you can't StartCoroutine inside static method. \$\endgroup\$ – Shitrit Lehava May 21 at 21:03
  • \$\begingroup\$ @Pikalek I updated my question with what I tried using instance variable for the static problem/s and try to test it in the Start but it's not working nothing happens. \$\endgroup\$ – Shitrit Lehava May 21 at 21:12
  • \$\begingroup\$ Ok, it's working now. Using instance public static method and also had to set the two flags in the static method. and it's working perfectly. \$\endgroup\$ – Shitrit Lehava May 21 at 22:46
  • 1
    \$\begingroup\$ I don't understand why you're trying to use a static method at all. playermouthspeechcontroller is an instance variable & all the stuff you listed involves manipulating that instance. \$\endgroup\$ – Pikalek May 21 at 22:49
0
\$\begingroup\$
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class MouthSpeechController : MonoBehaviour
{
    public TMP_Text[] texts;
    public static bool startTalking = false;
    public float talkTime;
    public float duration;
    [Range(0, 100)]
    public float valueRange;
    private SkinnedMeshRenderer bodySkinnedMeshRenderer;
    private static bool isTalking = true;
    private static MouthSpeechController instance;

    private void Awake()
    {
        instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        bodySkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();

        StartTalking(10f);
    }

    // Update is called once per frame
    void Update()
    {
        if (startTalking && isTalking)
        {
            StartCoroutine(AnimateMouth());
            StartCoroutine(TalkTime(talkTime));

            isTalking = false;
        }

        if (startTalking == false && isTalking == false)
        {
            isTalking = true;
        }
    }

    //Lerp between startValue and endValue over 'duration' seconds
    private IEnumerator LerpShape(float startValue, float endValue, float duration)
    {
        float elapsed = 0;
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float value = Mathf.Lerp(startValue, endValue, elapsed / duration);
            bodySkinnedMeshRenderer.SetBlendShapeWeight(0, value);
            yield return null;
        }
    }

    //animate open and closed, then repeat
    public IEnumerator AnimateMouth()
    {
        while (startTalking == true)
        {
            yield return StartCoroutine(LerpShape(0, valueRange, duration));
            yield return StartCoroutine(LerpShape(valueRange, 0, duration));
        }
    }

    public IEnumerator TalkTime(float TalkTime)
    {
        yield return new WaitForSeconds(TalkTime);

        startTalking = false;
    }

    public static void StartTalking(float TalkingTime)
    {
        isTalking = false;
        startTalking = true;

        instance.StartCoroutine(instance.AnimateMouth());
        instance.StartCoroutine(instance.TalkTime(TalkingTime));
    }
}

This line should be removed from the Start it's only for testing :

StartTalking(10f);

now you can call it from any script and start the talking with a single simple line this way :

MouthSpeechController.StartTalking(10f);
\$\endgroup\$
1
  • \$\begingroup\$ This is similar to the approach I would recommend for this situation as well, but you could explain it a lot better. It is difficult to see for anyone who reads your question and answer that you added the static keyword at a few selected places in this very long script. And someone who is not yet that familiar with the C# programming language might not even know what that keyword means. A better answer would use a more concise use-case and would explain better what the Singleton pattern is in general. \$\endgroup\$ – Philipp Jun 21 at 15:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.