как использовать словарь, чтобы сделать код аккуратным в C # для сценариев Unity

#c# #unity3d

#c# #unity3d

Вопрос:

Это мой код для контроллера animator в unity, который работает нормально, но показал, что он просто повторяется снова и снова для изменения некоторых переменных. Мой вопрос в том, есть ли способ создать словарь на C #, чтобы сделать его менее повторяющимся. Я полагаю, что должен быть способ, но поскольку я новичок в c #, я был бы благодарен за помощь

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

public class anim : MonoBehaviour
{
    [SerializeField] private Animator animator = null;


    private static readonly int hashHappy = Animator.StringToHash("happy");
    private static readonly int hashSad = Animator.StringToHash("sad");

    
    void Update()
     {
         if(Input.GetKey(KeyCode.H))
         {

             animator.SetBool(hashHappy, true);
             animator.SetBool(hashSad, false);

         } else if (Input.GetKeyUp(KeyCode.H))
         {
             Invoke("finishHappy", 5f);
           
         }

         if(Input.GetKey(KeyCode.S)){

             animator.SetBool(hashHappy, false);
             animator.SetBool(hashSad, true);

         } else if (Input.GetKeyUp(KeyCode.S))
         {
             Invoke("finishSad", 5f);
           
         }





        

     }

     public void finishHappy()=>animator.SetBool(hashHappy, false);
     public void finishSad()=>animator.SetBool(hashSad, false);

 
        
   


}
 

Ответ №1:

Честно говоря, я понятия не имею, имеет ли смысл то, что вы делаете, поскольку у меня ограниченные знания Unity.

Однако структура данных, которую я бы использовал, была бы List<T> . Это позволит вам перебирать хэши и переключать анимацию.

Учитывая

 public static class SomeClass
{
   private static readonly int hashHappy = Animator.StringToHash("happy");
   private static readonly int hashClap = Animator.StringToHash("clap");
   private static readonly int hashSad = Animator.StringToHash("sad");
   private static readonly int hashAngry = Animator.StringToHash("angry");
   private static readonly int hashDance = Animator.StringToHash("dance");
   private static readonly int hashDie = Animator.StringToHash("die");

   privatestatic List<int> _hashes;

   static SomeClass()
   {
      _hashes = new List<int>() {hashHappy, hashClap, hashSad, hashAngry, hashDance, hashDie};
   }

   public static void Set(Animator animator, int hash)
   {
      foreach (var item in _hashes)
         animator.SetBool(hash, item == hash);
   }
}
 

использование

 if(Input.GetKey(KeyCode.H))
   SomeClass.Set(animator, hashHappy);
if(Input.GetKey(KeyCode.C)) 
   SomeClass.Set(animator, hashClap);
 

Ответ №2:

Я, вероятно, был бы склонен использовать словарь, как вы сначала подумали. А затем соедините это с некоторыми перечислениями для ваших выражений. Конечный результат будет выглядеть примерно так:

 public enum ExpressionType
{
    None,
    Happy,
    Sad,
    Angry,
    // etc. etc.
}

public class anim : MonoBehaviour
{
    [SerializeField] private Animator animator = null;

    private static Dictionary<ExpressionType, int> expressions = new Dictionary<ExpressionType, int> ( )
    {
        [ ExpressionType.Happy ] = Animator.StringToHash ( "happy" ),
        [ ExpressionType.Sad ] = Animator.StringToHash ( "sad" ),
        [ ExpressionType.Angry ] = Animator.StringToHash ( "angry" ),
    };

    private static anim _instance;
    private void Awake ( )
    {
        _instance = this;
    }

    public static bool Set ( ExpressionType e = ExpressionType.None )
    {
        if ( _instance ) return false;
        foreach ( var kv in expressions )
            _instance.animator.SetBool ( kv.Value, kv.Key == e );
        return true;
    }

    void Update ( )
    {
        if ( Input.GetKeyDown ( KeyCode.H ) )
            Set ( ExpressionType.Happy );
        else if ( Input.GetKeyUp ( KeyCode.H ) )
            Invoke ( "Set", 5f );

        if ( Input.GetKey ( KeyCode.S ) )
            Set ( ExpressionType.Sad );
        else if ( Input.GetKeyUp ( KeyCode.S ) )
            Invoke ( "Set", 5f );
    }
}
 

Передача без аргумента статическому Set методу приведет к тому, что все значения bool будут установлены в false , и именно поэтому Invoke("Set", 5f) можно использовать вызов, вместо того, чтобы пытаться точно указать, какое логическое значение animator установить в false .

Вы могли бы добавить отдельный Reset метод, если хотите сэкономить пару ненужных вызовов аниматора, но это ничего не сломает, если оставить все как есть.

Обратите внимание, что это действительно полезно только в том случае, если вы используете значение bool animator . Установка триггера или передача значений потребуют Set выполнения некоторых дополнительных проверок типов данных. И последнее замечание, чтобы сказать, что я написал, но не тестировал код. Похоже, это должно сработать.

Комментарии:

1. спасибо за объяснение и код, у меня все работает нормально