当我尝试访问实体组件数据时,当我构建到我的 Iphone 时,Unity c# null 引用错误

Unity c# null reference error when I build to my Iphone when I try to access an entities component data

提问人:Christian Jones 提问时间:6/5/2020 最后编辑:Christian Jones 更新时间:6/9/2020 访问量:1201

问:

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

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

但是,当我在手机上构建游戏时,我从我的路径查找移动脚本的 Update 方法中收到了 null 引用异常。经过一些调试,我发现 convertedEntityHolder.GetEntity() 命令返回 Entity.Null,而 convertedEntityHolder.GetEntityManager() 命令返回 Null。当然,这会导致 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
            ...

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

转换到实体.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);
                }
            }
        }
    }
}

转换实体持有人.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;
    }

}

路径位置创作.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;

}

转换游戏对象到实体系统.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# 实体框架 unity-game-engine nullreferenceexception unity-dots

评论

0赞 DoragonSoruja 6/5/2020
这听起来很愚蠢,但只是为了确保,您是否根据您的手机类型正确构建?我知道这几乎从来都不是解决方案,但请检查您是否没有
0赞 Christian Jones 6/5/2020
我有一部 Iphone 8。我在 Unity 中为 ios 构建。在 xcode 中...我想我正在为 ios 10.0 构建。让我打开版本,看看会发生什么。
0赞 Christian Jones 6/5/2020
将其更改为 13.4,仍然得到相同的结果。
0赞 DoragonSoruja 6/5/2020
如果这没有帮助,那么您能否显示“CovertedEntityHolder.cs”
0赞 Christian Jones 6/5/2020
@DoragonSoruja 见上文。

答:

0赞 vasmos 6/5/2020 #1

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

enter image description here

enter image description here

评论

0赞 Christian Jones 6/5/2020
在哪里可以找到这些导入设置?我单击“项目”文件夹中的脚本,它显示“ScriptName 导入设置”,但我没有看到读/写选项。
0赞 vasmos 6/5/2020
它不会出现在脚本上,但应该出现在大多数/所有模型上,尤其是当它们有装备或动画时
0赞 Christian Jones 6/5/2020
这是一款2D游戏。所以我没有任何模型。只是精灵、工作表和动画。
0赞 vasmos 6/5/2020
它将出现在您的所有精灵上,它位于导入设置的中间
0赞 Christian Jones 6/5/2020
好的,我做了改变。明天必须进行测试,看看这是否解决了问题。谢谢!
0赞 Christian Jones 6/9/2020 #2

我将游戏下载到我的 Mac 上并从那里构建它。这似乎解决了这个问题。