0

I am building a game which uses an A* path finding system developed by CodeMonkey here: https://www.youtube.com/watch?v=XomlTHitAug&list=PLzDRvYVwl53v55lu_TjC21Iu4CuFGQXVn&index=3

I modified the files he provided to be much more bare bones. I got to the point where the path finding was working perfectly in the editor.

However, when I built the game to my phone, I received a null reference exception from within the Update method of the my path finding movement script. After some debugging I discovered that the convertedEntityHolder.GetEntity() command returns Entity.Null and the convertedEntityHolder.GetEntityManager() command returns Null. This, of course, results in a null reference exception. I am not sure why this would break on upon building to my Iphone. Any ideas?

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
            ...

The Entity prefab has four script components on it. Let me know if you need to see their code. They are:

ConvertToEntity.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);
    }

}

PathFollow.cs

using Unity.Entities;

[GenerateAuthoringComponent]
public struct PathFollow : IComponentData {

    public int pathIndex;

}

ConvertGameObjectToEntitySystem.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));
            });
        }
    }
}

9
  • This sounds dumb but just to make sure, did you build correctly according to your type of phone? I understand that it's pretty much never the solution but just check if you haven't Commented Jun 4, 2020 at 20:46
  • I have an Iphone 8. I built for ios in unity. In xcode... I guess I was building for ios 10.0. let me up the version and see what happens. Commented Jun 4, 2020 at 20:51
  • Changed it to 13.4 still getting the same results. Commented Jun 4, 2020 at 20:56
  • If that doesn't help then could you please display "CovertedEntityHolder.cs" Commented Jun 4, 2020 at 20:56
  • @DoragonSoruja See above. Commented Jun 4, 2020 at 21:02

2 Answers 2

0

On the import settings of all your assets make sure you have read/write enabled. Many of times it will default to being unchecked.

enter image description here

enter image description here

Sign up to request clarification or add additional context in comments.

7 Comments

Where do I find those import settings? I click on the script in the Project folder and it shows "ScriptName Import Settings" but I do not see read/write as an option.
It won't be on scripts but it should be on most/all of your models, especially if they have a rig or animation
Its a 2d game. So I don't have any models. Just sprites sheets and animations.
It will be on all of your sprites, its in the middleish of the import settings
Ok, I made the change. will have to test to see if that fixed the issue tomorrow. Thanks!
|
0

I downloaded the game onto my mac and built it from there. that seemed to fix the issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.