Как создать систему мнений между символами

#c# #unity3d

#c# #unity3d

Вопрос:

Допустим, у меня есть скриптовый объект ‘Characters’, и я создаю три символа этого скриптового объекта. Теперь я хочу, чтобы у трех символов было мнение (значение int) о двух других символах. Например, символ 1 имеет 30 мнений о символе 2, а символ 1 имеет -30 мнений о символе 2.

Я думаю, что самый простой способ — создать два целых числа в объекте Characters Scriptable, но если бы у меня было 1000 символов, должен ли я создавать 1000 целых чисел? Есть идеи о том, как создать эту систему?

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

1. Вам нужен контейнер, в этом случае может подойти словарь, поэтому словарь, который связывает ‘Character’ с целым. Например, Character1.opinions(character2) и значением будет ваш рейтинг мнений. Затем вам просто нужен сценарий запуска для динамического заполнения этих словарей для каждого символа в начале

2. Мне 14 лет, и я не совсем новичок в UNITY. Можете ли вы показать мне код для этого?

3. tutorialsteacher.com/csharp/csharp-dictionary может быть, это хорошее место для начала.

4. Если у вас 1000 символов, то вам придется хранить n * (n - 1) = 999000 мнения, где n — количество символов. Т.е. у каждого символа ( n ) есть мнение для всех остальных ( n - 1 ) символов.

5. Могу ли я задать любой объект в словаре. Как класс символов. Что-то вроде IDictionary<Символ, int> dict = новый словарь<символ, int>();

Ответ №1:

Я только что получил блестящий ответ в Unity Answers на этот вопрос. Проверьте это, если хотите.

Вот как это сделать:

  1. Создайте новый класс, наследующий от ScriptableObject
  2. В этом классе объявите 2D-массив, содержащий мнения, и массив, содержащий ваши символы
  3. Создайте пользовательский инспектор для отображения этой сетки

Character.cs

  using UnityEngine;

 [CreateAssetMenu()]
 public class Character : ScriptableObject
 {
     public string Name;
 }
  

OpinionsTable.cs

 using UnityEngine;


 [CreateAssetMenu()]
 public class OpinionsTable : ScriptableObject
 {
     [SerializeField]
     private Character[] characters;

     [SerializeField]
     private int[] opinions;
     public int GetOpinion( Character character1, Character character2 )
     {
         for( int i = 0 ; i < characters.Length ;   i )
         {
             if( character1 == characters[i] )
             {
                 for( int j = 0 ; j < characters.Length ;   j )
                 {
                     if( character2 == characters[j] )
                         return opinions[i * characters.Length   j];;
                 }
                 Debug.LogError( "Character2 not found" );
             }
         }
         Debug.LogError( "Character1 not found" );
         return -1;
     }
     public void SetOpinion( Character character1, Character character2, int opinion )
     {
         for( int i = 0 ; i < characters.Length ;   i )
         {
             if( character1 == characters[i] )
             {
                 for( int j = 0 ; j < characters.Length ;   j )
                 {
                     if( character2 == characters[j] )
                     {
                         opinions[i * characters.Length   j] = opinion;
                         return ;
                     }
                 }
                 Debug.LogError( "Character2 not found" );
             }
         }
         Debug.LogError( "Character1 not found" );
     }
 }
  

В папке под названием ‘Editor’

OpinionsTableEditor.cs

  using UnityEngine;
 using UnityEditor;

 [CustomEditor( typeof( OpinionsTable ) )]
 public class OpinionsTableEditor : Editor
 {
     const float opinionsLabelWidth = 50;
     const float opinionCellSize = 25;
     SerializedProperty characters;
     SerializedProperty opinions;
     int opinionsTableWidth = 0;
     Rect opinionsTableRect;

     void OnEnable()
     {
         // Retrieve the serialized properties
         characters = serializedObject.FindProperty( "characters" );
         opinions = serializedObject.FindProperty( "opinions" );
     }

     public override void OnInspectorGUI()
     {
         serializedObject.Update();

         // Check if the number of characters has been changed
         // If so, resize the opinions
         EditorGUI.BeginChangeCheck();
         EditorGUILayout.PropertyField( characters, true );
         if( EditorGUI.EndChangeCheck() )
         {
             opinions.arraySize = characters.arraySize * characters.arraySize;
         }

         // Draw opinions if there is more than one character
         if ( opinions.arraySize > 1 )
             DrawOpinions( opinions, characters );
         else
             EditorGUILayout.LabelField( "Not enough characters to draw opinions matrix" );

         serializedObject.ApplyModifiedProperties();
     }

     private void DrawOpinions( SerializedProperty opinions, SerializedProperty characters )
     {
         int charactersCount = characters.arraySize;
         if ( Event.current.type == EventType.Layout )
             opinionsTableWidth = Mathf.FloorToInt( EditorGUIUtility.currentViewWidth );

         // Get the rect of the whole matric, labels included
         Rect rect = GUILayoutUtility.GetRect(opinionsTableWidth, opinionsTableWidth, EditorStyles.inspectorDefaultMargins);

         if ( opinionsTableWidth > 0 amp;amp; Event.current.type == EventType.Repaint )
             opinionsTableRect = rect;

         // Draw matrix and labels only if the rect has been computed
         if( opinionsTableRect.width > 0 )
         {
             // Compute size of opinion cell
             float cellWidth     = Mathf.Min( (opinionsTableRect.width - opinionsLabelWidth) / charactersCount, opinionCellSize );
             Rect opinionCell    = new Rect( opinionsTableRect.x   opinionsLabelWidth, opinionsTableRect.y   opinionsLabelWidth, cellWidth, cellWidth );
             Matrix4x4 guiMatrix = GUI.matrix;

             // Draw vertical labels
             for ( int i = 1 ; i <= charactersCount ;   i )
             {
                 Rect verticalLabelRect = new Rect( opinionsTableRect.x   opinionsLabelWidth   i * opinionCell.width, opinionsTableRect.y, opinionsLabelWidth, opinionsLabelWidth );
                 Character character = characters.GetArrayElementAtIndex( i - 1 ).objectReferenceValue as Character;
                 EditorGUIUtility.RotateAroundPivot( 90f, new Vector2( verticalLabelRect.x, verticalLabelRect.y ) );
                 EditorGUI.LabelField( verticalLabelRect, character == null ? "???" : character.Name );
                 GUI.matrix = guiMatrix;
             }            

             // Draw matrix
             for ( int i = 0 ; i < charactersCount ;   i )
             {
                 // Draw horizontal labels
                 SerializedProperty characterProperty = characters.GetArrayElementAtIndex( i );
                 Character character = characterProperty == null ? null : characters.GetArrayElementAtIndex( i ).objectReferenceValue as Character;
                 EditorGUI.LabelField( new Rect( opinionsTableRect.x, opinionCell.y, opinionsLabelWidth, opinionCell.height ), character == null ? "???" : character.Name ) ;

                 for ( int j = 0 ; j < charactersCount ;   j )
                 {
                     opinionCell.x = opinionsTableRect.x   opinionsLabelWidth   j * cellWidth;
                     if ( j > i )
                     {
                         SerializedProperty opinion = opinions.GetArrayElementAtIndex( i * charactersCount   j );
                         opinion.intValue = EditorGUI.IntField( opinionCell, opinion.intValue );
                     }
                     else // Put grey box because the matrix is symmetrical
                     {
                         EditorGUI.DrawRect( opinionCell, Color.grey );
                     }
                 }
                 opinionCell.y  = cellWidth; 
             }
         }
     }
 }
  

введите описание изображения здесь

Примечание

Если вы хотите расширить свой код еще немного, например, символ A будет иметь мнение о символе B. Но у персонажа B также будет мнение о персонаже A. Затем внесите следующие изменения в OpinionsTableEditor.cs

Измените это

  for ( int j = 0 ; j < charactersCount ;   j )
              {
                  opinionCell.x = opinionsTableRect.x   opinionsLabelWidth   j * cellWidth;
                  if ( j > i )
                  {
                      SerializedProperty opinion = opinions.GetArrayElementAtIndex( i * charactersCount   j );
                      opinion.intValue = EditorGUI.IntField( opinionCell, opinion.intValue );
                  }
                  else // Put grey box because the matrix is symmetrical
                  {
                      EditorGUI.DrawRect( opinionCell, Color.grey );
                  }
              }
  

К этому

  for ( int j = 0 ; j < charactersCount ;   j )
              {
                  opinionCell.x = opinionsTableRect.x   opinionsLabelWidth   j * cellWidth;
                  SerializedProperty opinion = opinions.GetArrayElementAtIndex( i * charactersCount   j );
                  opinion.intValue = EditorGUI.IntField( opinionCell, opinion.intValue );
              }