【问题标题】:Hierarchy issue Unity层次结构问题 Unity
【发布时间】:2019-11-04 20:46:43
【问题描述】:

我在 Unity 3d 中制作一个简单的游戏,基本上你有一个背景对象,上面有更多游戏对象,你要做的就是将这些游戏对象拖到一些垃圾桶中,只要你用正确的对象说对象被删除,游戏的理念是当您将所有对象放入正确的罐中时,您就赢得了游戏

我已经完成了所有的拖拽和验收,但我不知道如何制作脚本,这样当没有更多对象时,你就赢了。

我一直试图在一个空的游戏对象上使用层次结构,它是你必须销毁的对象的父对象,但我不知道如何实际删除对象以便代码可以注册它,有什么帮助吗?

拖拽代码和我用于垃圾桶的代码:

using UnityEngine;
using UnityEngine.EventSystems;

public class arrastrar : MonoBehaviour, IDragHandler
{
    public float z = 0.0f;
    public void OnDrag(PointerEventData eventData)
    {
        Vector3 mousePosition = Input.mousePosition;
        mousePosition.z = z;
        transform.position = Camera.main.ScreenToWorldPoint(mousePosition);
    }
}

还有垃圾桶里的代码

using System.Collections;
using UnityEngine;
using System.Collections.Generic;

public class botarBasura: MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.name == "cubo")
            Destroy(other.gameObject);
    } else if (other.gameObject.name == "escombros")
    {
    other.gameObject.transform.position = new Vector3(-1, 2.5f, -2); //If its not the correct trash can it returns the object to the starting position
    }
    } else if ( other.gameObject.name == "botellas")
    {
    other.gameObject.transform.position = new Vector3(0, 2.5f, -2);
    }
  }
}

【问题讨论】:

  • 所有游戏对象都有一个继承的.Destroy() 方法,您可以使用它来销毁它们。不过,我建议禁用它们。一般来说,最好将您的对象池化并在不活动时隐藏它们,将它们返回到池中。您希望尽可能避免在游戏过程中实例化。一些实例化/销毁在性能方面并不明显,但是当您开始处理数百或数千个游戏对象并且您的垃圾收集器正在拉加超时时,性能可能会变得相当粗糙。最好尽早习惯池化的概念,因为它不太复杂
  • 可拖动对象上是否有某种只有它们才有的组件/脚本/标签?
  • 是的@Ruzihm 他们有,他们有一个 Drag 脚本,好吧,顾名思义就是用来拖动对象的,我把它附在下面
  • @DetectivePikachu 除非你有数百个对象,否则池是多余的,这里可能只是不必要的复杂性

标签: c# unity3d


【解决方案1】:

您可以使用可编写脚本的对象来跟踪您的对象。对象只需要在其 OnEnable() 和 OnDisable() 回调中将自己添加和删除到可编写脚本对象的列表中。当一个对象自行移除时,您可以通过代码检查是否没有更多对象,并触发一个事件,您的场景中的某些东西会对此做出反应。

(可拖动对象)

public class DragableObject : MonoBehaviour{

//reference to the scriptable object
public DragableObjectSet RuntimeSet;

void OnEnable(){
    RuntimeSet.Add(this);
}

void OnDisable(){
    RuntimeSet.Remove(this);

    //you can put code checking if the runtime set is empty here
    //or you can put it in the DragableObjectSet Remove method
}

}

可编写脚本的对象示例代码

public DragableObjectSet : ScriptableObject
{
    public List<DragableObject> RuntimeSet = new List<DragableObject>();


    public void Add(DragableObject obj){
        RuntimeSet.Add(obj);
    }

    public void Remove(DragableObject obj){
        RuntimeSet.Remove(obj);
        if(RuntimeSet.Count() == 0)
           //some code here raising an event (if desired)
    }
}

这种类型的对象称为运行时集,在 40 分钟左右的演讲中进行了详细介绍。

https://www.youtube.com/watch?v=raQ3iHhE_Kk

【讨论】:

【解决方案2】:

解决方案可能是使用单例:

创建一个新的空游戏对象并添加以下代码:

using UnityEngine;

public class TrashCounter : MonoBehaviour {
    public static TrashCounter instance = null;    
    public int counter = 0;

    void Awake(){ instance = this; }
}

现在,无论您在何处创建对象(或在任何对象代码的 Start() 方法中),您只需执行 TrashCounter.instance.counter++ 即可获得垃圾计数。

之后,您只需在每次删除对象时通过执行TrashCounter.instance.counter-- 和询问if(TrashCounter.instance.counter == 0) WinGame() 来更新此计数器。

【讨论】:

  • 我要去查一下,因为我不知道什么是单例,不过请给小费!
【解决方案3】:

您可以使用Object.FindObjectsOfType&lt;ComponentType&gt;(); 获取所有活动和尚未销毁的游戏对象的数组,其中包含一些启用的组件。一旦你有了它,你就可以查看该数组的长度。

因此,您可以在销毁/停用可拖动游戏对象的代码中执行以下操作:

GameObject otherObject = /* get draggable object to possibly destroy */;

if ( /* test to remove otherObject */ )
{
    // deactivate the draggable object
    otherObject.setActive = false;

    // get all other draggable objects
    DraggableObject[] remainingDraggableObjects = Object.FindObjectsOfType<DraggableObject>();

    if (remainingDraggableObjects.Length == 0)
    {
        // there are no more active gameobjects with enabled DraggableObject component
        // handle win condition here.
    }   
}

在您的具体示例中,它可能如下所示:

void OnCollisionEnter(Collision other)
{
    if (other.gameObject.name == "cubo")
    {
        other.gameObject.setActive = false; // better than destroying in most cases

        // get all other draggable objects
        arrastrar[] remainingObjects = Object.FindObjectsOfType<arrastrar>();

        if (remainingObjects.Length == 0)
        {
            // there are no more active gameobjects with enabled arrastrar component
            // handle win condition here.
        }  
    }

    // ...

【讨论】:

  • 我将附上我一直用来将我的对象拖到垃圾桶附近的代码。使用 UnityEngine;使用 UnityEngine.EventSystems;公共类 arrastrar : MonoBehaviour, IDragHandler { public float z = 0.0f; public void OnDrag(PointerEventData eventData) { Vector3 mousePosition = Input.mousePosition;鼠标位置.z = z; transform.position = Camera.main.ScreenToWorldPoint(mousePosition); } }
  • 哦,还有一件事我不知道它是否理想,我有一个脚本可以删除每种类型的垃圾桶中的对象,该脚本在碰撞时搜索对象的名称,如果所述对象的名称是正确的,它会删除该对象,所以如果我使用这种方法,我会将数组和这个脚本本身放在哪里?
  • @PanmoRamirez 请edit the question 包含该代码。
  • @PanmoRamirez 正如我回答中的 cmets 所建议的那样,无论您在哪里测试以删除另一个对象,都可以。如果没有看到您正在使用的代码,我真的不能再详细了。
  • @PanmoRamirez 我编辑了我的答案以显示它在您的代码中的外观
猜你喜欢
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
相关资源
最近更新 更多