Marco simple para el desarrollo de problemas de Unity.

En el proceso de desarrollo normal, generalmente se encuentra con una gran cantidad de desarrollo de preguntas, las más comunes incluyen preguntas de opción múltiple, preguntas para completar espacios en blanco, preguntas y respuestas, etc. Por supuesto, el desarrollo de estas funciones es muy sencillo, pero si no existe un marco universal para la gestión, sino que se escribe un conjunto de códigos para cada o cada tipo de pregunta, las iteraciones y el mantenimiento posteriores se verán muy afectados. Para resolver este problema, en mi tiempo libre, creé un marco de preguntas simple que puede respaldar y ampliar todos los tipos de preguntas mencionados anteriormente.

Primero, definí una interfaz IQuestion. Todas las preguntas posteriores se heredarán de esta interfaz. El contenido de la interfaz es el siguiente

public interface IQuestion
{
    /// <summary>
    /// quesItem列表
    /// </summary>
    List<IQuesItem> questionItemList { get; set; }
    /// <summary>
    /// quesItem的数量
    /// </summary>
    int quesItemCount { get; }
    /// <summary>
    /// 增加一个QuesItem
    /// </summary>
    /// <param name="item"></param>
    void AddQuesItem(IQuesItem item);
    /// <summary>
    /// 移除一个QuesItem
    /// </summary>
    /// <param name="item"></param>
    void RemoveQuesItem(IQuesItem item);
    /// <summary>
    /// 清空所有QuesItem
    /// </summary>
    /// <param name="item"></param>
    void ClearQuesItem();
    /// <summary>
    /// 提交
    /// </summary>
    /// <returns></returns>
    bool Submit();
    /// <summary>
    /// 是否回答正确
    /// </summary>
    /// <returns></returns>
    bool IsRight();
    /// <summary>
    /// 根据索引获取QuesItem
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    IQuesItem GetQuesItem(int id);
}

Luego se introduce una nueva interfaz IQuesItem en la interfaz IQuestion anterior.
¿Qué es IQuesItem?
De hecho, en resumen, tome una pregunta de opción múltiple como ejemplo. Cada opción A/B/C/D es un QuesItem. Si es una pregunta para completar espacios en blanco, entonces cada espacio en blanco que debe ingresarse es un QuesItem.
¿Por qué introducir la interfaz IQuesItem?
Porque considerando que la visualización, el efecto y el método de operación de cada unidad de operación pueden ser diferentes en la etapa posterior, en este momento, todas estas situaciones posibles son muy adecuadas para el procesamiento polimórfico, y luego cada unidad de operación en la etapa posterior será un individuo independiente. , mejora la flexibilidad de la unidad operativa

/// <summary>
/// 操作单元
/// </summary>
public interface IQuesItem
{
    /// <summary>
    /// 目标结果
    /// </summary>
    object targetAnswer { get;}
    /// <summary>
    /// 实际当前结果
    /// </summary>
    object curAnswer { get; }
    /// <summary>
    /// 实际当前结果改变
    /// </summary>
    /// <param name="value">改变之后</param>
    void OnChanged(object value);
    /// <summary>
    /// 是否回答正确
    /// </summary>
    /// <returns></returns>
    bool IsRight();
    /// <summary>
    /// 回答正确之后的反应
    /// </summary>
    void OnRight();
    /// <summary>
    /// 回答错误之后的反应
    /// </summary>
    void OnError();
}

De hecho, la estructura básica se ha determinado al momento de escribir este artículo. Posteriormente, el objeto de pregunta hereda IQuestion, y todas las unidades de operación heredan IQuesItem, y luego se realiza el polimorfismo en los objetos específicos.
Pero en ese momento descubrimos que debido a que la interfaz no podía implementar métodos específicos, para mejorar la velocidad de desarrollo, hice otra encapsulación entre el objeto real y la interfaz del tema.

public abstract class Question : MonoBehaviour,IQuestion
{
    private IQuestion iquestion=>this;
    List<IQuesItem> IQuestion.questionItemList { get; set; }
    public int quesItemCount => iquestion?.questionItemList == null ? 0 : iquestion.questionItemList.Count;

    protected virtual void Awake()
    {
        IQuesItem[] items = transform.GetComponentsInChildren<IQuesItem>();
        if (items!=null&&items.Length>0)
            for (int i = 0; i < items.Length; i++)AddQuesItem(items[i]);
    }

    public IQuesItem GetQuesItem(int id)
    {
        if (id>=quesItemCount) return null;
        return iquestion.questionItemList[id];
    }

    /// <summary>
    /// 提交答案
    /// </summary>
    /// <returns>返回正误</returns>
    public virtual void OnSubmit()
    {
        bool isRight = iquestion.Submit();
        SubmitResult(isRight);
    }

    protected abstract void SubmitResult(bool isRight);

    /// <summary>
    /// 添加一个QuesItem
    /// </summary>
    /// <param name="item"></param>
    public void AddQuesItem(IQuesItem item)
    {
        if (iquestion.questionItemList==null)iquestion.questionItemList=new List<IQuesItem>();
        iquestion.questionItemList.Add(item);
    }

    /// <summary>
    /// 移除一个QuesItem
    /// </summary>
    /// <param name="item"></param>
    public void RemoveQuesItem(IQuesItem item)
    {
        if (quesItemCount==0) return;
        iquestion.questionItemList.Remove(item);
    }

    /// <summary>
    /// 清空所有QuesItem
    /// </summary>
    public void ClearQuesItem()
    {
        if (iquestion.questionItemList!=null)iquestion.questionItemList.Clear();
    }

    /// <summary>
    /// 当前回答是否正确
    /// </summary>
    /// <returns>返回正误</returns>
    public bool IsRight()
    {
        if (quesItemCount==0) return false;
        bool isRight = true;
        for (int i = 0; i < quesItemCount; i++)
        {
            if (!GetQuesItem(i).IsRight())
            {
                isRight = false;
                break;
            }
        }
        return isRight;
    }

    #region 私有
    bool IQuestion.Submit()
    {
        if (quesItemCount == 0) return false;
        IQuesItem curItem = null;
        bool isRight = true;
        for (int i = 0; i < quesItemCount; i++)
        {
            curItem = GetQuesItem(i);
            if (curItem.IsRight())curItem.OnRight();
            else
            {
                isRight = false;
                curItem.OnError();
            }
        }
        return isRight;
    }

    #endregion
    
}

Luego puede ver que el objeto Question hereda de MonoBehaviour y la interfaz IQuestion. Primero, hereda de MonoBehaviour para simplificar la configuración de los datos iniciales. Hereda la interfaz IQuestion para realizar las funciones básicas de la pregunta. Además, Question es un objeto abstracto con el propósito de evitar el uso directo de Question y modificar los datos y la lógica internos durante el desarrollo del programa para garantizar la unidad de este objeto.
Por lo tanto, podemos heredar todos los objetos de pregunta de la interfaz Question en lugar de IQuestion.

De hecho, está terminado cuando lo escribo, pero si no te dejo ver el efecto, siempre parece que falta algo.
¡Mo Fang! Hagamos una prueba sencilla con preguntas de opción múltiple.
Luego llamé al objeto de pregunta de opción múltiple ChooseQues y, por supuesto, tengo que heredar Question.

/// <summary>
/// 选择题
/// </summary>
public class ChooseQues : Question
{
    [SerializeField]
    private Text tipText;
    [SerializeField]
    private Button submitBtn;

    private void Start()
    {
        submitBtn.onClick.AddListener(OnSubmit);
    }

    protected override void SubmitResult(bool isRight)
    {
        tipText.text = isRight ? "回答正确" : "回答错误";
    }

}

¿Qué tal? El objeto de pregunta de opción múltiple solo necesita escribir dicho código para realizar las funciones de envío y aviso. . . . .
¿Falta algo?
Así es, falta cada objeto de unidad de operación (opción), así que llamo a cada unidad de operación ToggleItem, porque uso Toggle para crear cada opción, por supuesto, también puedes usar otros métodos.

public class ToggleItem : MonoBehaviour,IQuesItem
{
    [SerializeField]
    private bool answer;
    public object targetAnswer => answer;
    public object curAnswer => toggle.isOn;
    private Toggle toggle;
    private Text effectText;

    private void Start()
    {
        toggle = GetComponent<Toggle>();
        toggle.onValueChanged.AddListener(isSelect=>OnChanged(isSelect));
        effectText = transform.Find("EffectText")?.GetComponent<Text>();
    }

    public void OnChanged(object value)
    {
        Debug.Log(transform.name+": 变为:"+(bool)value);
    }

    public bool IsRight()
    {
        return (bool) curAnswer == (bool) targetAnswer;
    }

    public void OnRight()
    {
        if (effectText)effectText.text = "选择正确";
    }

    public void OnError()
    {
        if (effectText)effectText.text = "选择错误";
    }
}

Realmente terminé de escribir esta vez. .
Puedes ver que este objeto tiene un campo targetAnswer, que es la respuesta objetivo (se puede configurar en el panel). La interfaz es de tipo objeto, porque su tipo de datos no se puede arreglar más adelante. Por ejemplo, se puede usar el valor bool. como la respuesta objetivo aquí.
También hay un campo llamado curAnswer, que es la respuesta ingresada actualmente, por lo que obviamente solo necesitamos juzgar si los resultados de los dos son sinérgicos en IsRight ().
effectText crea un efecto simple (mensaje de texto, ¿es correcto este bloque de operación?). Por supuesto, también puedes crear efectos geniales en él. Escríbelos directamente en OnRight() [el efecto después de responder correctamente] y OnError() [El efecto después de responder incorrectamente] estará bien.
Las representaciones son las siguientes:

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Finalmente, se adjunta el enlace del código fuente, que también implementa los tipos de preguntas para completar espacios en blanco y rompecabezas de cuadrícula de nueve cuadrados.
Código fuente

Supongo que te gusta

Origin blog.csdn.net/weixin_42498461/article/details/123550925
Recomendado
Clasificación