首页 > 解决方案 > 当我尝试访问实体组件数据时,当我构建到我的 Iphone 时,Unity c# null 引用错误

问题描述

我正在构建一个使用 CodeMonkey 开发的 A* 寻路系统的游戏: https ://www.youtube.com/watch?v=XomlTHitAug&list=PLzDRvYVwl53v55lu_TjC21Iu4CuFGQXVn&index=3

我修改了他提供的文件,使其更加简单。我到了路径查找在编辑器中完美运行的地步。

但是,当我在手机上构建游戏时,我从寻路移动脚本的 Update 方法中收到了一个空引用异常。经过一些调试,我发现convertedEntityHolder.GetEntity() 命令返回Entity.Null,并且convertedEntityHolder.GetEntityManager() 命令返回Null。当然,这会导致空引用异常。我不确定为什么这会在构建到我的 Iphone 时中断。有任何想法吗?

private void Update() 
    {
        if (!transform.Find("Entity"))
        {
            EntityObj = Instantiate(Resources.Load("Prefabs/UnitEntity"), (Vector2)this.transform.position, Quaternion.identity) as GameObject;
            EntityObj.transform.parent = this.transform;
            EntityObj.name = "Entity";
            convertedEntityHolder = EntityObj.GetComponent<ConvertedEntityHolder>();
            target = transform.position;
            if (PathfindingGridSetup.Instance != null && convertedEntityHolder.GetEntityManager() != null)
            {
                //setPathToPoint(transform.position);
            }
        }
        else if (!EntityObj || !convertedEntityHolder)
        {
            EntityObj = transform.Find("Entity").gameObject;
            convertedEntityHolder = EntityObj.GetComponent<ConvertedEntityHolder>();
            target = transform.position;
            if (PathfindingGridSetup.Instance != null && convertedEntityHolder.GetEntityManager() != null)
            {
                //setPathToPoint(transform.position);
            }
        }
        else
        {
            entity = convertedEntityHolder.GetEntity();
            Debug.Log(entity); //prints "Entity.Null"
            entityManager = convertedEntityHolder.GetEntityManager();
            Debug.Log(entityManager); //prints "Null"
            pathFollow = convertedEntityHolder.GetEntityManager().GetComponentData<PathFollow>(entity); 
            // ^^^ returns a null
            ...

Entity 预制件上有四个脚本组件。如果您需要查看他们的代码,请告诉我。他们是:

转换实体.cs

using System;
using System.Collections.Generic;
using Unity.Entities.Conversion;
using UnityEngine;
using UnityObject = UnityEngine.Object;
using static Unity.Debug;

namespace Unity.Entities
{
    [DisallowMultipleComponent]
    [AddComponentMenu("DOTS/Convert To Entity")]
    public class ConvertToEntity : MonoBehaviour
    {
        public enum Mode
        {
            ConvertAndDestroy,
            ConvertAndInjectGameObject
        }

        public Mode ConversionMode;

        void Awake()
        {
            if (World.DefaultGameObjectInjectionWorld != null)
            {
                var system = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<ConvertToEntitySystem>();
                system.AddToBeConverted(World.DefaultGameObjectInjectionWorld, this);
            }
            else
            {
                UnityEngine.Debug.LogWarning($"{nameof(ConvertToEntity)} failed because there is no {nameof(World.DefaultGameObjectInjectionWorld)}", this);
            }
        }
    }

    [UpdateInGroup(typeof(InitializationSystemGroup))]
    public class ConvertToEntitySystem : ComponentSystem
    {
        Dictionary<World, List<ConvertToEntity>> m_ToBeConverted = new Dictionary<World, List<ConvertToEntity>>();

        public BlobAssetStore BlobAssetStore { get; private set; }

        protected override void OnCreate()
        {
            base.OnCreate();
            BlobAssetStore = new BlobAssetStore();
        }

        protected override void OnDestroy()
        {
            base.OnDestroy();
            if (BlobAssetStore != null)
            {
                BlobAssetStore.Dispose();
                BlobAssetStore = null;
            }
        }

        // using `this.World` is a sign of a problem - that World is only needed so that this system will update, but
        // adding entities to it directly is wrong (must be directed via m_ToBeConverted).
        // ReSharper disable once UnusedMember.Local
        new World World => throw new InvalidOperationException($"Do not use `this.World` directly (use {nameof(m_ToBeConverted)})");

        protected override void OnUpdate()
        {
            if (m_ToBeConverted.Count != 0)
                Convert();
        }

        public void AddToBeConverted(World world, ConvertToEntity convertToEntity)
        {
            if (!m_ToBeConverted.TryGetValue(world, out var list))
            {
                list = new List<ConvertToEntity>();
                m_ToBeConverted.Add(world, list);
            }
            list.Add(convertToEntity);
        }

        static bool IsConvertAndInject(GameObject go)
        {
            var mode = go.GetComponent<ConvertToEntity>()?.ConversionMode;
            return mode == ConvertToEntity.Mode.ConvertAndInjectGameObject;
        }

        static void AddRecurse(EntityManager manager, Transform transform, HashSet<Transform> toBeDetached, List<Transform> toBeInjected)
        {
            if (transform.GetComponent<StopConvertToEntity>() != null)
            {
                toBeDetached.Add(transform);
                return;
            }

            GameObjectEntity.AddToEntityManager(manager, transform.gameObject);

            if (IsConvertAndInject(transform.gameObject))
            {
                toBeDetached.Add(transform);
                toBeInjected.Add(transform);
            }
            else
            {
                foreach (Transform child in transform)
                    AddRecurse(manager, child, toBeDetached, toBeInjected);
            }
        }

        static void InjectOriginalComponents(GameObjectConversionMappingSystem mappingSystem, Transform transform)
        {
            var entity = mappingSystem.GetPrimaryEntity(transform.gameObject);
            foreach (var com in transform.GetComponents<Component>())
            {
                if (com is GameObjectEntity || com is ConvertToEntity || com is ComponentDataProxyBase || com is StopConvertToEntity)
                    continue;

                mappingSystem.DstEntityManager.AddComponentObject(entity, com);
            }
        }

        void Convert()
        {
            var toBeDetached = new HashSet<Transform>();
            var conversionRoots = new HashSet<GameObject>();

            try
            {
                var toBeInjected = new List<Transform>();

                foreach (var convertToWorld in m_ToBeConverted)
                {
                    var toBeConverted = convertToWorld.Value;

                    var settings = new GameObjectConversionSettings(
                        convertToWorld.Key,
                        GameObjectConversionUtility.ConversionFlags.AssignName);

                    settings.BlobAssetStore = BlobAssetStore;

                    using (var gameObjectWorld = settings.CreateConversionWorld())
                    {
                        toBeConverted.RemoveAll(convert =>
                        {
                            if (convert.GetComponent<StopConvertToEntity>() != null)
                            {
                                LogWarning(
                                    $"{nameof(ConvertToEntity)} will be ignored because of a {nameof(StopConvertToEntity)} on the same GameObject",
                                    convert.gameObject);
                                return true;
                            }

                            var parent = convert.transform.parent;
                            var remove = parent != null && parent.GetComponentInParent<ConvertToEntity>() != null;
                            if (remove && parent.GetComponentInParent<StopConvertToEntity>() != null)
                            {
                                LogWarning(
                                    $"{nameof(ConvertToEntity)} will be ignored because of a {nameof(StopConvertToEntity)} higher in the hierarchy",
                                    convert.gameObject);
                            }

                            return remove;
                        });

                        foreach (var convert in toBeConverted)
                            AddRecurse(gameObjectWorld.EntityManager, convert.transform, toBeDetached, toBeInjected);

                        foreach (var convert in toBeConverted)
                        {
                            conversionRoots.Add(convert.gameObject);
                            toBeDetached.Remove(convert.transform);
                        }

                        GameObjectConversionUtility.Convert(gameObjectWorld);

                        var mappingSystem = gameObjectWorld.GetExistingSystem<GameObjectConversionMappingSystem>();
                        foreach (var convert in toBeInjected)
                            InjectOriginalComponents(mappingSystem, convert);
                    }

                    toBeInjected.Clear();
                }
            }
            finally
            {
                m_ToBeConverted.Clear();

                foreach (var transform in toBeDetached)
                    transform.parent = null;

                foreach (var go in conversionRoots)
                {
                    if(!IsConvertAndInject(go))
                        UnityObject.DestroyImmediate(go);
                }
            }
        }
    }
}

ConvertedEntityHolder.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

public class ConvertedEntityHolder : MonoBehaviour, IConvertGameObjectToEntity {

    private Entity entity;
    private EntityManager entityManager;

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
        Debug.Log("Converted");
        this.entity = entity;
        this.entityManager = dstManager;
        //Debug.Log(entity);
    }

    public Entity GetEntity() {
        return entity;
    }

    public EntityManager GetEntityManager() {
        return entityManager;
    }

}

PathPositionAuthoring.cs

public class PathPositionAuthoring : MonoBehaviour, IConvertGameObjectToEntity {

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
        dstManager.AddBuffer<PathPosition>(entity);
    }

}

路径跟随.cs

using Unity.Entities;

[GenerateAuthoringComponent]
public struct PathFollow : IComponentData {

    public int pathIndex;

}

将GameObjectToEntitySystem.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityObject = UnityEngine.Object;

namespace Unity.Entities
{
    public interface IConvertGameObjectToEntity
    {
        void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem);
    }

    public interface IDeclareReferencedPrefabs
    {
        void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs);
    }

    [AttributeUsage(AttributeTargets.Class)]
    public class RequiresEntityConversionAttribute : Attribute {  }
}

namespace Unity.Entities.Conversion
{
    class ConvertGameObjectToEntitySystem : GameObjectConversionSystem
    {
        void Convert(Transform transform, List<IConvertGameObjectToEntity> convertibles)
        {
            try
            {
                transform.GetComponents(convertibles);

                foreach (var c in convertibles)
                {
                    var behaviour = c as Behaviour;
                    if (behaviour != null && !behaviour.enabled) continue;

#if UNITY_EDITOR
                    if (!ShouldRunConversionSystem(c.GetType()))
                        continue;
#endif

                    var entity = GetPrimaryEntity((Component)c);
                    c.Convert(entity, DstEntityManager, this); //Calls all convert methods
                }
            }
            catch (Exception x)
            {
                Debug.LogException(x, transform);
            }
        }

        protected override void OnUpdate()
        {
            var convertibles = new List<IConvertGameObjectToEntity>();

            Entities.ForEach((Transform transform) => Convert(transform, convertibles));
            convertibles.Clear();

            //@TODO: Remove this again once we add support for inheritance in queries
            Entities.ForEach((RectTransform transform) => Convert(transform, convertibles));
        }
    }

    [UpdateInGroup(typeof(GameObjectBeforeConversionGroup))]
    class ComponentDataProxyToEntitySystem : GameObjectConversionSystem
    {
        protected override void OnUpdate()
        {
            Entities.ForEach((Transform transform) =>
            {
                GameObjectConversionMappingSystem.CopyComponentDataProxyToEntity(DstEntityManager, transform.gameObject, GetPrimaryEntity(transform));
            });
            //@TODO: Remove this again once KevinM adds support for inheritance in queries
            Entities.ForEach((RectTransform transform) =>
            {
                GameObjectConversionMappingSystem.CopyComponentDataProxyToEntity(DstEntityManager, transform.gameObject, GetPrimaryEntity(transform));
            });
        }
    }
}

标签: c#entity-frameworkunity3dnullreferenceexceptionunity-dots

解决方案


在所有资产的导入设置中,确保您已启用读/写。很多时候它会默认为未选中。

在此处输入图像描述

在此处输入图像描述


推荐阅读