15

我问我如何调整一个克隆的形状/尺寸以影响场景视图中的所有其他克隆,并且接受的答案是正确的。它只能克隆一个游戏对象。我尝试进行一些调整,但我想出的唯一解决方案是为其他对象添加重复的方法。这在处理要克隆的多个游戏对象时效果不佳。

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

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

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

4

8 回答 8

1

我不想使用预制件

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],只是不要忘记在运行项目时禁用它。同样,我强烈建议使用预制件。

于 2019-06-30T09:48:30.167 回答
0

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

于 2019-03-13T16:56:54.707 回答
-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;
            }
        }
    }
}

上面是一个简短的例子,给你一个想法,绝不是广泛的,但你应该能够将它应用到你正在尝试做的事情中;例如,如果您想在游戏对象之间复制精灵的颜色,您可以修改otherClonesSprite引用列表,而不是在更新中设置比例,您可以将每个 Sprite 组件的颜色设置为这个对象。

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

于 2018-09-07T12:31:57.367 回答
-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 方法。当您想更改长度时,中心类会发布该消息并将其发送给所有订阅者。

这里的不同之处在于,在我的示例中,中心类需要跟踪发布者/订阅者中的所有克隆,而您不需要。

于 2018-06-29T03:07:30.487 回答
-1

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

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 销毁对象。

于 2018-10-31T10:36:43.620 回答
-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;
    }
}

在这里阅读有关这两个选项的一些重要信息!

于 2018-11-04T20:04:31.737 回答
-1

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

于 2018-06-28T20:00:41.713 回答
-1

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

于 2018-11-01T13:39:29.023 回答