как клонировать несколько игровых объектов таким образом, чтобы свойства клона одного можно было скорректировать, чтобы соответствовать всем остальным в сцене

Я спросил, как я могу настроить форму/размеры одного клона, чтобы повлиять на все другие клоны в представлении сцены, и принятый ответ был точным. Он мог клонировать только один игровой объект. Я попытался внести некоторые коррективы, но единственное решение, которое я нашел, это добавление дублирующих методов для дополнительных объектов. Это плохо работает при работе с несколькими игровыми объектами, которые нужно клонировать.

Как я могу клонировать несколько уникальных игровых объектов, чтобы настройка компонентов/свойств одного клона повлияла на все другие клоны этого объекта в виде сцены?

Обратите внимание, что я не хочу достигать этого во время выполнения, и я не хочу использовать префабы. Я использую это, чтобы помочь в создании сложных уровней, так что живое обновление настраиваемых клонов очень важно.

Кроме того, мне также нужен способ отключить эту повторяющуюся репликацию свойства/компонента для каждого клона, предпочтительно с помощью кнопки.

Ответ 1

Вы должны использовать ScriptableObject в качестве контейнера данных и присоединить его к игровому объекту, все клоны будут использовать один и тот же синхронизированный ScriptableObject.

Ответ 2

Я не хочу использовать префабы

Новая сборная система в 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] к классу, в котором он находится, просто не забудьте отключить его при запуске проекта. Опять же, я настоятельно рекомендую вместо этого использовать префабы.

Ответ 4

Похоже, у вас есть объект, который имеет несколько клонов. Вы хотите, чтобы изменение формы или размеров любого из этих объектов влияло на другие?

Чтобы это произошло, каждый объект должен знать о других. Вы можете сделать это децентрализованным (каждый объект содержит ссылку друг на друга) или централизованным (один объект управляет остальными).

Централизованный подход более прост, поэтому я приведу простой пример.

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. Когда вы хотите изменить длину, центральный класс публикует это сообщение, и оно отправляется всем подписчикам.

Разница здесь в том, что в моем примере центральный класс должен отслеживать все клоны, а в издателе/​​подписчике вы этого не делаете.

Ответ 5

Это только для редактирования объектов в редакторе? Если так, то это звучит так, как будто готовые сборные - это путь; Вы можете напрямую редактировать префаб, и все его "клоны" в сцене будут иметь все изменения, включая все монобиевы, трансформации и тому подобное, реплицированные на префаб.

Если вам нужно, чтобы это работало во время выполнения, вам, вероятно, понадобится некоторый код, чтобы сделать это за вас. Вы не совсем предоставили достаточно разъяснений относительно того, что именно вы хотите сделать, поэтому в приведенном ниже примере я предполагаю, что у вас есть игровой объект с компонентом сетки или спрайта, и вы хотите, чтобы его размер/масштаб изменялись вместе со всеми его " клоны ";

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 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 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 на что этого объекта.

Если вам нужна эта функциональность только в редакторе, а не во время выполнения, я настоятельно рекомендую использовать первый вариант с использованием префабов, поскольку он предоставит вам гораздо больше функциональности при меньших затратах и производительности.

Ответ 6

Создайте скрипт 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 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 через специальную функцию.

Ответ 7

сделайте все элементы, которые нуждаются в масштабировании дочерних элементов пустого WorldObjects затем масштабируйте объект мира, он соответствующим образом масштабирует все его дочерние элементы. затем вы можете вручную или с помощью сценария удалить родительский объект, чтобы сделать объекты независимыми. лучший способ без префабов...

Ответ 8

использовать одноэлементный класс. добавьте этот сценарий ко всем объектам, затем вы можете позвонить одному из них, и он все настроит.

Вы также можете сделать это со статическим классом, но одноэлементный подход чище и дает вам больше возможностей.

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;
    }
}

Читайте здесь для получения отличной информации об обоих вариантах!