如何以可以调整一个游戏对象的克隆属性以使其与场景视图中的所有其他游戏对象匹配的方式来克隆多个游戏对象

时间:2018-06-28 18:11:03

标签: unity3d unity-editor

我问How can I adjust shape/dimensions of one clone to affect all other clones in the scene view,当场就接受了答案。它只能克隆一个游戏对象。我尝试进行一些调整,但是我想到的唯一解决方案是为其他对象添加重复方法。当处理几个要克隆的游戏对象时,这不能很好地工作。

如何克隆几个唯一的游戏对象,以便调整一个克隆的组件/属性将影响场景视图中该对象的所有其他克隆?

请注意,我不想在运行时实现此目的,也不想使用预制件。我正在使用它来帮助创建复杂的级别,因此实时调整正在克隆的克隆非常重要。

此外,我还需要一种方法来关闭每个克隆上重复的属性/组件复制,最好使用按钮。

8 个答案:

答案 0 :(得分:0)

您应该使用ScriptableObject作为数据容器,并将其附加到游戏对象,所有克隆都将使用相同的同步ScriptableObject。

答案 1 :(得分:0)

  

我不想使用预制件

Unity中的新预制系统正是您所需要的。它符合您的所有要求:

  • Clone several unique game objects

    预制系统用于克隆独特的游戏对象。它甚至支持预制嵌套。

  • I don't want to achieve this at runtime

    很好,预制件仅在单击编辑器中的覆盖按钮时才全局更新。

  • I need a way to turn off the this repeated property/component replication on each clone

    这相当于解压缩对象(断开连接)。

如果有充分的理由避免使用预制件,则始终可以编写一个自定义脚本来跟踪要共享的属性中的更改,并立即更新所有其他对象。通过将[ExecuteInEditMode]属性添加到其所在的类中,可以使该脚本在编辑模式下运行,只是不要忘记在运行项目时将其禁用。再次,我强烈建议改为使用预制件。

答案 2 :(得分:-1)

您应该使用事件。 Unity3d教程有一个很好的简单解释:https://unity3d.com/learn/tutorials/topics/scripting/events

答案 3 :(得分:-1)

听起来您有一个具有多个克隆的对象。您要更改任何一个对象的形状或尺寸以影响其他对象吗?

为此,每个对象都需要了解其他对象。您可以分散(每个对象都包含一个相互引用)或集中式(一个对象管理其余对象)来执行此操作。

集中式方法更简单,所以我举一个简单的例子。

public class Shape
{
    public int length;
}

public class ShapeCentral
{
    public List<Shape> shapes = new List<Shape>();

    public void CloneShape()
    {
        //instantiate new shape
        shapes.Add(new Shape());
    }

    public void SetCloneLength(int l)
    {
        shapes.ForEach(x => x.length = l);
    }
}

如您所见,一个对象可以一次控制所有克隆。诀窍是不要使用其他方法创建克隆,否则会遇到麻烦。

如果您想加强变量访问权限(我建议这样做是一个很好的练习),则可以使用发布者/订阅者模式。在这种情况下,当实例化一个新的克隆时,它将订阅SetCloneLength方法。当您想要更改长度时,中央类将发布该消息,并将其发送给所有订阅者。

这里的区别在于,在我的示例中,中央类需要跟踪所有克隆,而在发布者/订阅者中则不需要。

答案 4 :(得分:-1)

这仅用于在编辑器中编辑对象吗?如果是这样,那么听起来就像是预制件要走的路。您可以直接编辑预制件,并且场景中的所有“克隆”都将发生所有更改,包括所有单行为,变换以及未复制到预制件的任何行为。

如果您需要在运行时使用它,则可能需要一些代码才能为您执行此操作。您尚未完全了解要执行的操作,因此,在下面的示例中,我假设您的游戏对象带有网格或精灵组件,并且希望其尺寸/比例与所有“克隆”;

using UnityEngine;
using System.Collections.Generic;

public class ShapeClone : MonoBehaviour
{
    //This will hold references to the other "clone" gameobjects.
    public List<GameObject> otherClones = new List<GameObject>();

    //All the "clones" in the list otherClones will have their scale matched to this gameobject's scale
    public bool leader;


    private void Update()
    {
        if (leader) //Only change other clones' scales if marked as leader, to avoid every single clone
                    //overriding each other's scale every single frame, which could be rather chaotic
        {
            for (int i = 0; i < otherClones.Count; i++)
            {
                //setting each of the other clones' scale to that of this object.
                otherClones[i].transform.localScale = this.transform.localScale;
            }
        }
    }
}

以上是一个简短的示例,旨在为您提供一个想法,并且绝不详尽,但是您应该可以将其应用于您要尝试的操作;例如,如果您想跨游戏对象复制精灵的颜色,则可以将otherClones修改为Sprite引用的列表,并且可以将{每个Sprite组件的颜色都与此对象的颜色相同。

但是,如果您仅在编辑器中需要此功能,而在运行时则不需要-我强烈建议您使用预制件来选择第一个选项,因为它可以为您提供更多的功能,而成本却只是性能的一小部分。

答案 5 :(得分:-1)

创建脚本CopycatManager,该脚本将容纳一个领导者,然后使用专用的setter复制具有相同类型的其他对象属性。如果某个属性是默认属性,则可能需要在脚本中设置该属性的代理,或者使用触发器。我建议代理。像这样:

class CopycatManager {

    public GameObject leader;

    SomeAttributeType attributeToCopyFromLeader {get; private set}

    void Start () {
        // The first CopycatManager to start is the leader
        List<CopycatManager> allCMs = parent.GetComponentsInChildren();
        CopycatManager foundLeader = allCMs.Find(o => o.leader == o);
        if (foundLeader == null) {
            // There's no leader yet, set yourself a leader
            leader = this;
        } else {
            // Found a leader, accept
            leader = foundLeader;
        }
    }

    public void SetAttribute (SomeAttributeType newVal) {
        // If we're setting the attribute of the leader - we should set this attribute for all children
        if (leader == gameObject) {
            // Find all copycat manager scripts attached to children of current parent
            // Meaning siblings
            // WARNING: It will include children of siblings and the leader itself
            // WARNING: It will not include parents of the Copycat Manager type, add if required
            List<CopycatManager> allCMs = parent.GetComponentsInChildren();
            foreach (CopycatManager manager in allCMs) {
                SetAttributeFromLeader (newVal);
            }
        } else {
            // Non-leader is attempting to change attribute - call leader
            leader.SetAttribute(newVal);
        }
    }

    // Called by leader to each child
    public void SetAttributeFromLeader (SomeAttributeType newVal) {
        attributeToCopyFromLeader = newVal;
    }
}

如果旧领导者被摧毁,请确保分配新的领导者。仅通过专用功能使用CopycatManager销毁对象。

答案 6 :(得分:-1)

将所有需要缩放子项的项目都称为WorldObjects,然后缩放世界对象,它将相应地缩放其所有子项。然后,您可以手动或通过脚本删除父对象以使对象独立。没有预制件的最佳方法...

答案 7 :(得分:-1)

使用单例类。将脚本添加到所有对象,然后您可以调用其中一个,它将调整所有对象。

您也可以使用静态类来执行此操作,但是单例方法更加简洁,并为您提供了更多选择。

public class MySingleton
{

    private static MySingleton fetch; // keep the static reference private

    public bool myBool = false;

    // and expose static members through properties
    // this way, you have a lot more control over what is actually being sent out.
    public static bool MyBool { get { return fetch ? fetch.myBool : false; } }

    void Awake()
    {
        fetch = this;
    }
}

阅读here,以获得有关这两个选项的一些重要信息!