使用FindObjectsOfTypeAll()保存对象

时间:2018-12-02 16:39:59

标签: c# unity3d

我有一个save-Method,可以使用位置,健康状况,旋转等五个特定标签之一保存有关每个块的信息。

我首先要获取所有对象(甚至是不活动的对象),因此我使用FindObjectsOfTypeAll()-Method。

然后,我通过一个foreach循环遍历所有已找到的对象,并检查它们是否具有正确的标签,如果有,我保存它们。

这是我使用的代码:

GameObject[] allObjects = Resources.FindObjectsOfTypeAll(typeof (GameObject)) as GameObject[];

using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
    Debug.Log(allObjects.Length);
    foreach (GameObject block in allObjects)
    {
        bool isActive = block.activeSelf;
        block.SetActive(true);
        if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor")
        {                    
            // SAVE
            write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z);
        }

        block.SetActive(isActive);
    }
write.Close();
}

我对此进行了调试,if (block.tag == "WoodBlock" || ...)行工作正常。

问题是下一行:

write.WriteLine(...);

在这里我得到一个nullReferenceException,它告诉我:

  

NullReferenceException:对象引用未设置为的实例   对象

我不知道为什么吗?!

2 个答案:

答案 0 :(得分:1)

问题很可能是

block.GetComponent<BlockControl>()

为找到的null中的一个返回GameObjects,因为它根本不包含该成分。


您可以使用

Resources.FindObjectsOfTypeAll<BlockCo troll>();

确保在单独的列表中仅包含类型BlockControl的所有组件。


比起列表,您可以更轻松地过滤标记的对象,而不是那些||条件

var searchedTags = new List<string>()
{
    "WoodBlock",
    "WoodSteps",
    "WoodRamp",
    "GlasBlock",
    "WoodDoor"
};

if (searchedTags.Contains(block.gameObject.tag))
{
    ....
}

甚至更简单的使用Linq来获取您感兴趣的对象:

var objectsOfInterest = allObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();

我也只会使用StreamWriter进行实际写操作,而在该using块中什么也不做。

请注意,如果您在StreamWriter块内使用using,则不必使用write.Close(),因为它会自动放置在using块之后完成。


因此,我将使用类似的

var searchedTags = new List<string>()
{
    "WoodBlock",
    "WoodSteps",
    "WoodRamp",
    "GlasBlock",
    "WoodDoor"
};

// This list is used to get all GameObject
// keep track which where active and activate all
var allObjects = Resources.FindObjectsOfTypeAll<GameObject>();

// Here we get all BlockController components
var allBlockObjects = Resources.FindObjectsOfTypeAll<BlockController>();

// finally we only get BlockControllers with the tags we want
var objectsOfInterest = allBlockObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();

Debug.Log("objects total: " + allObjects.Length);
Debug.Log("block objects: " + allBlockObjects.Length);
Debug.Log("objects of interest: " + objectsOfInterest.Length);

// Step 1 keep track which GameObjects where active and activate all

var objectWasNotActive = new List<GameObject>();

foreach (var obj in allObjects)
{
    if(!obj.activeSelf)
    {
        // keep track which objects where not active
        objectWasNotActive.Add(obj);
    }

    // Set all to true
    obj.SetActive(true);
}

// Step 2 save your BlockControllers with searched tags

using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
    foreach (var block in objectsOfInterest)
    {  
        // Here you already have components of type BlockController
        // so you don't need to get them 

        // But GetHealth might also return null so maybe you want to check that too
        // It is up to you whether you want to skip or fill it with default values in such case
        var health = block.GetHealth();
        if(health == null)
        {
            //option 1 skip
            continue;

            // OR option 2 default e.g.
            // Assuming it is Vector2
            health = Vector2.zero;
        }

        // SAVE
        write.WriteLine(
            block.gameObject.tag + "," 
            + block.transform.position.x + "," 
            + block.transform.position.y + "," 
            + block.transform.position.z + "," 
            + health.x + "," 
            + health.y + "," 
            + block.transform.rotation.x + "," 
            + block.transform.rotation.y + "," 
            + block.transform.rotation.z
        );        
    }
}

// Step 3 disable those GameObjects again that where not active before
foreach(var obj in objectWasNotActive)
{
    obj.SetActive(false);
}

答案 1 :(得分:0)

现在,很难在不看代码的情况下调试它,但是请先检查一下。

  • 检查 input:focus::-webkit-input-placeholder { /* Chrome/Opera/Safari */ color: transparent !important; } input:focus::-moz-placeholder { /* Firefox 19+ */ color: transparent !important; } input:focus:-ms-input-placeholder { /* IE 10+ */ color: transparent !important; } input:focus:-moz-placeholder { /* Firefox 18- */ color: transparent !important; } 是否已正确初始化且没有错误,有时会无提示地失败。
  • 您确定所有带有这些标记的对象上都带有组件write吗?

尝试将您的代码更新为此,只是检查它到底在哪里失败

BlockControl

通过这种方式,您可以找出导致问题的if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor") { Debug.Log(block.name); Debug.Log(block.GetComponent<BlockControl>()); Debug.Log(block.GetComponent<BlockControl>().GetHealth()); // SAVE write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z); } ,以及问题出在组件或block函数上。