0

Есть участок js кода

function FindEnabledMeshes() 
    {
        var renderers;
        renderers = target.transform.GetComponentsInChildren(MeshFilter);
/...    
}   

всё работало, переделываю на С#, и не знаю какой тип дать renderers, потребовалось привести тип в С#:

 void Method() {
        SimpleMeshCombine target = new SimpleMeshCombine(); // Скрипт SimpleMeshCombine приведен ниже

        var renders; // ?

        renderers =  target.transform.GetComponentsInChildren<MeshFilter>();
         // в target не видит transform, в js видел
    }

Скрипт SimpleMeshCombine

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

[AddComponentMenu("Simple Mesh Combined")]
public class SimpleMeshCombine : MonoBehaviour {

    public   GameObject[] combinedGameOjects;   //Stores gameObjects that has been merged, mesh renderer disabled
    public GameObject combined;                 //Stores the combined mesh gameObject
    public   string meshName = "Combined_Meshes";   //Asset name when saving as prefab
    public   bool _advanced ;                       //Toggles advanced features 
    public   bool _savedPrefab;                     //Used when checking if this mesh has been saved to prefab (saving the same mesh twice generates error)
    public   bool _generateLightmapUV;          //Toggles secondary UV map generation
}

так же в переменной meshFilters, не видит Length в C#

var meshFilters;
        meshFilters = FindEnabledMeshes();
        var combine: CombineInstance[] = new CombineInstance[meshFilters.length];

Спасибо работает, не пойму чего в этой области выдает ошибку при нажатии на кнопку в инспекторе, в дочерних объектах находятся три куба, скрипт висит на пустышке родительском: Ошибка:

NullReferenceException
SimpleMeshCombineEditor.OnInspectorGUI () (at Assets/Simple Mesh Combine/Simple Mesh Combine/Scripts/Editor/SimpleMeshCombineEditor.cs:22)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1240)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

в строке

if(target.transform.childCount > 1) combineMeshes();



    if (!target.combined) {
            target._generateLightmapUV = EditorGUILayout.Toggle("Generate Ligthmap UV's", target._generateLightmapUV);
            GUILayout.Label("Combine all Mesh Renderer enabled meshes");
            if(GUILayout.Button("Combine")) {
                if(target.transform.childCount > 1) combineMeshes();
            } 

Скрипт SimpleMeshCombine

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

    [AddComponentMenu("Simple Mesh Combined")]
    public class SimpleMeshCombine : MonoBehaviour {

        public   GameObject[] combinedGameOjects;   //Stores gameObjects that has been merged, mesh renderer disabled
        public GameObject combined;                 //Stores the combined mesh gameObject
        public   string meshName = "Combined_Meshes";   //Asset name when saving as prefab
        public   bool _advanced ;                       //Toggles advanced features 
        public   bool _savedPrefab;                     //Used when checking if this mesh has been saved to prefab (saving the same mesh twice generates error)
        public   bool _generateLightmapUV;          //Toggles secondary UV map generation
    }

Скрипт SimpleMeshCombineEditor, лежит в папке Editor

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

[CustomEditor(typeof(SimpleMeshCombine))]

public class SimpleMeshCombineEditor : Editor {
    int count;

    public  override void  OnInspectorGUI (){
            //DrawDefaultInspector ();
            GUILayout.Space(10);
            GUILayout.Label("*All meshes must have same material*");    
            GUILayout.Space(10);

        SimpleMeshCombine target = new SimpleMeshCombine ();

        if (!target.combined) {
                target._generateLightmapUV = EditorGUILayout.Toggle("Generate Ligthmap UV's", target._generateLightmapUV);
                GUILayout.Label("Combine all Mesh Renderer enabled meshes");
                if(GUILayout.Button("Combine")) {
                    if(target.transform.childCount > 1) combineMeshes();
                }   
            }else{
                GUILayout.Label("Decombine all previously combined meshes");
                if(GUILayout.Button("Release")) {
                    EnableRenderers(true);
                    target._savedPrefab = false;
                    if(target.combined)
                        DestroyImmediate(target.combined);
                }
            }
            if(target.combined && !target._savedPrefab)
                target._advanced = EditorGUILayout.Toggle("Advanced Features", target._advanced);
            if(target.combined && target._advanced && !target._savedPrefab){
                if(GUILayout.Button("Save Prefab")) {
                    string n = target.meshName;
                    if(System.IO.Directory.Exists("Assets/Simple Mesh Combine/Saved Meshes/")){
                        if(!System.IO.File.Exists("Assets/Simple Mesh Combine/Saved Meshes/"+target.meshName+".asset")){        
                            AssetDatabase.CreateAsset(target.combined.GetComponent<MeshFilter>().sharedMesh, "Assets/Simple Mesh Combine/Saved Meshes/"+n+".asset");
                            target._advanced = false;
                            target._savedPrefab = true;
                            Debug.Log("Saved Assets/Simple Mesh Combine/Saved Meshes/"+n+".asset");
                        }else{
                            Debug.Log(target.meshName+".asset" + " already exists, please change the name");
                        }

                    }else{
                        Debug.Log("Missing Folder: Assets/Simple Mesh Combine/Saved Meshes/");
                    }
                }
                target.meshName = GUILayout.TextField(target.meshName);
            }
            if (GUI.changed){
                EditorUtility.SetDirty(target);
            }
        }

        void  EnableRenderers (bool e ){    

        SimpleMeshCombine target = new SimpleMeshCombine();
        for (int i = 0; i < target.combinedGameOjects.Length; i++){
            target.combinedGameOjects[i].GetComponent<Renderer>().enabled = e;
            }  
        }

    MeshFilter[]  FindEnabledMeshes ()
    {
        SimpleMeshCombine target = new SimpleMeshCombine(); 

        //var renderers = target.transform.GetComponentsInChildren<MeshFilter>();
        MeshFilter[] renderers;
        renderers = target.transform.GetComponentsInChildren<MeshFilter>();


        for (int i = 0; i < renderers.Length; i++)//
            {
            if(renderers[i].GetComponent<MeshRenderer>() && renderers[i].GetComponent<Renderer>().enabled)
                    count++;
            }

        var meshfilters = new MeshFilter[count];
        count = 0;
            for (int ii = 0; ii < renderers.Length; ii++)
            {
                if(renderers[ii].GetComponent<MeshRenderer>() && renderers[ii].GetComponent<MeshRenderer>().enabled){
                    meshfilters[count] = renderers[ii];
                    count++;
                }
            }
            return meshfilters;
        }

        void  combineMeshes (){//Combines meshes

        SimpleMeshCombine target = new SimpleMeshCombine(); 

        GameObject combinedFrags = new GameObject();
            combinedFrags.AddComponent<MeshFilter>();
            combinedFrags.AddComponent<MeshRenderer>();     
        //  int meshFilters ; /// var meshFilters
        var meshFilters =   FindEnabledMeshes();
        //var meshFilters = target.transform.GetComponentsInChildren<MeshFilter>();
        //meshFilters = FindEnabledMeshes();
            CombineInstance[] combine = new CombineInstance[meshFilters.Length];

            Debug.Log("Simple Mesh Combine: Combined " + meshFilters.Length + " Meshes");

            target.combinedGameOjects = new GameObject[meshFilters.Length];      
            for (int i = 0; i < meshFilters.Length; i++)
            {
                combinedFrags.GetComponent<MeshRenderer>().sharedMaterial = meshFilters[i].transform.gameObject.GetComponent<MeshRenderer>().sharedMaterial;
                target.combinedGameOjects[i] = meshFilters[i].gameObject;
                combine[i].mesh = meshFilters[i].transform.GetComponent<MeshFilter>().sharedMesh;
                combine[i].transform = meshFilters[i].transform.localToWorldMatrix;         
            }

            combinedFrags.GetComponent<MeshFilter>().mesh = new Mesh();
            combinedFrags.GetComponent<MeshFilter>().sharedMesh.CombineMeshes(combine);
            if(target._generateLightmapUV){
                Unwrapping.GenerateSecondaryUVSet(combinedFrags.GetComponent<MeshFilter>().sharedMesh);
                combinedFrags.isStatic = true;
            }

            combinedFrags.name = "_Combined Mesh [" + target.name + "]";
            target.combined = combinedFrags.gameObject;
            EnableRenderers(false);
            combinedFrags.transform.parent = target.transform;
        }   

}
GR1995
  • 623
  • 1
  • 4
  • 21
  • 1
    в отличие от js, в C# у массивов свойство называется Length (с большой буквы) а у списков - Count, какое конкретно нужно в твоем случае зависит от того, что возвращает FindEnabledMeshes – Grundy Aug 24 '17 at 12:17
  • Обновил ответ для последнего вопроса – Артём Оконечников Aug 24 '17 at 13:19
  • 3
    Если у вас возник новый вопрос, задавайте его отдельно. Не дело заставлять отвечающих отвечать на много вопросов. Примите ответ здесь и задайте новый вопрос. – VladD Aug 24 '17 at 15:04

2 Answers2

3

Ключевое слово var определяет тип переменной в зависимости от инициализирующего значения. Это ключевое слово нельзя применять в контексте null или определения без инициализации (как в вашем случае). Так-же var нельзя использовать у полей класса/структуры.

Таким образом, для вашего случая, корректный код будет следующий:

var renderers = target.transform.GetComponentsInChildren<MeshFilter>();

Если вам необходимо явно указать тип переменной, то нужно посмотреть на сигнатуру метода GetComponentsInChildren, а именно на возвращаемое значение и явно указать этот тип:

MeshFilter[] renderers = target.transform.GetComponentsInChildren<MeshFilter>();

Тогда вы получите то, что ожидаете:

MeshFilter[] renderers; 
renderers = target.transform.GetComponentsInChildren<MeshFilter>();

if(target.transform.childCount > 1) combineMeshes();

NullReferenceException говорит о том, что вы обращаетесь вместо объекта класса к нулевому значению (null). В вашем случае, либо target либо target.transform содержит null вместо ссылки на объект класса.

Что такое NullReferenceException, и как мне исправить код?

  • А как я могу проинициализировать target, если это экземпляр класса SimpleMeshCombine, а сам скрипт наследуется от Editor, в js скрипте типы приводить не нужно было, просто вызывали target.combine – GR1995 Aug 24 '17 at 14:35
  • Опубликуйте полный код инициализации target и его использования – Артём Оконечников Aug 24 '17 at 14:41
  • Значит, transform у вас null. Посмотрите как его инициализирует SimpleMeshCombine – Артём Оконечников Aug 24 '17 at 14:54
0

target определен в Editor, имеет тип Object, вам надо преобразовать его, обычно делают так <Нужный тип> targ=(<Нужный тип>)target; В вашем случае надо сделать, SimpleMeshCombine targ= (SimpleMeshCombine)target; и все target заменить на targ.

В Js если убрать pragma strict этого делать не надо, поэтому там было просто target и все работало.

У вас несколько функций использует target, поэтому либо targ передавать как аргумент, либо в каждой функции переопределять локальное targ, либо сделать глобальную targ в самом классе и делать проверку if(targ==null) targ= (SimpleMeshCombine)target;

Xumera_hZ
  • 1,610
  • 2
  • 9
  • 13