当我尝试访问实体组件数据时构建 Iphone 时出现 Unity c# 空引用错误
Unity c# null reference error when I build to my Iphone when I try to access an entities component data
我正在构建一个使用 CodeMonkey 开发的 A* 寻路系统的游戏:
https://www.youtube.com/watch?v=XomlTHitAug&list=PLzDRvYVwl53v55lu_TjC21Iu4CuFGQXVn&index=3
我修改了他提供的文件,使其更加简单。我到了路径查找在编辑器中完美运行的地步。
但是,当我为我的 phone 构建游戏时,我从路径查找移动脚本的更新方法中收到了一个空引用异常。经过一些调试后,我发现 convertedEntityHolder.GetEntity() 命令 returns Entity.Null 和 convertedEntityHolder.GetEntityManager() 命令 returns 为空。当然,这会导致空引用异常。我不确定为什么这会在构建我的 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
...
实体预制件上有四个脚本组件。如果您需要查看他们的代码,请告诉我。他们是:
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));
});
}
}
}
在所有资产的导入设置中,确保已启用 read/write。很多时候它会默认为未选中。
我将游戏下载到我的 mac 上并从那里构建它。这似乎解决了问题。
我正在构建一个使用 CodeMonkey 开发的 A* 寻路系统的游戏: https://www.youtube.com/watch?v=XomlTHitAug&list=PLzDRvYVwl53v55lu_TjC21Iu4CuFGQXVn&index=3
我修改了他提供的文件,使其更加简单。我到了路径查找在编辑器中完美运行的地步。
但是,当我为我的 phone 构建游戏时,我从路径查找移动脚本的更新方法中收到了一个空引用异常。经过一些调试后,我发现 convertedEntityHolder.GetEntity() 命令 returns Entity.Null 和 convertedEntityHolder.GetEntityManager() 命令 returns 为空。当然,这会导致空引用异常。我不确定为什么这会在构建我的 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
...
实体预制件上有四个脚本组件。如果您需要查看他们的代码,请告诉我。他们是:
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));
});
}
}
}
在所有资产的导入设置中,确保已启用 read/write。很多时候它会默认为未选中。
我将游戏下载到我的 mac 上并从那里构建它。这似乎解决了问题。