Как я могу создать информационный массив или список всех объектов дверей? - PullRequest
0 голосов
/ 14 февраля 2020
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectsReplace : MonoBehaviour
{
    public class TransformInfo
    {
        public Vector3 pos;
        public Quaternion rot;
        public Vector3 scale;
    }

    public void GetDoors()
    {
        var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
        var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");


        TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length];

        for (int i = 0; i < trnfrm.Length; i++)
        {
            trnfrm[i] = new TransformInfo();

            trnfrm[i].pos = DoorsLeft[i].transform.position;
            trnfrm[i].rot = DoorsLeft[i].transform.rotation;
            trnfrm[i].scale = DoorsLeft[i].transform.localScale;
        }
    }
}

Это нормально работает для DoorsLeft, но я хочу, чтобы trnfrm включал также информацию об объектах из DoorsRight, поэтому структура массива или списка trnfrm будет выглядеть примерно так:

DoorLeft 0...info inside
DoorLeft 1...info inside
.
.
.
DoorRight 0...info inside
DoorRight 1...info inside

Вот как выглядит массив теперь:

Doors array

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

DoorLeft 0...info inside
DoorLeft 1...info inside
.
.
.
DoorRight 0...info inside
DoorRight 1...info inside

А как прочитать информацию обратно в GameObjects?

Основная цель - создать префаб в позициях дверей, с одинаковыми поворотами и масштабированием дверей. ,

Так вот что я сделал:

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

public class ObjectsReplace : MonoBehaviour
{
    public struct TransformInfo
    {
        public string ID;
        public Transform Transform;

        public Vector3 pos;
        public Quaternion rot;
        public Vector3 scale;

        public TransformInfo(Transform transform, string id)
        {
            Transform = transform;
            ID = id;
            // For this kind of stuff I always prefer working on the local values
            pos = transform.localPosition;
            rot = transform.localRotation;
            scale = transform.localScale;
        }

        public void Apply()
        {
            Transform.localPosition = pos;
            Transform.localRotation = rot;
            Transform.localScale = scale;
        }

        public void Apply(Transform transform)
        {
            transform.localPosition = pos;
            transform.localRotation = rot;
            transform.localScale = scale;
        }
    }

    public GameObject prefabToInit;

    // Note your method should probably return something
    public TransformInfo[] GetDoors()
    {
        var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
        var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");

        TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length * 2];

        int trnfrmIndex = 0;
        for (int i = 0; i < DoorsLeft.Length; i++)
        {
            trnfrm[trnfrmIndex] = new TransformInfo(DoorsLeft[i].transform, $"{i}_L");
            trnfrm[trnfrmIndex + 1] = new TransformInfo(DoorsRight[i].transform, $"{i}_R");

            trnfrmIndex += 2;
        }

        return trnfrm;
    }

    public void ApplyDoors()
    {
        foreach (var info in GetDoors())
        {
            info.Apply(Instantiate(prefabToInit.transform));
        }
    }
}

И вызов этого ApplyDoors из сценария редактора:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[CustomEditor(typeof(ObjectsReplace))]
public class ObjectsReplaceEditor : Editor
{
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        ObjectsReplace myScript = (ObjectsReplace)target;

        if (GUILayout.Button("Add"))
        {
            myScript.ApplyDoors();
        }
    }
}

Проблема в том, что он многократно создает префаб в главном узле иерархии, а не как двери, как дочерние, поэтому он помещает все сборные в одну и ту же область вместо того, где двери:

Prefabs after Instantiated

Но теперь я вижу, что он меняет исходный сборный ресурс источника на куб:

Prefab changed to cube scaled to 1,1,1

Но исходное масштабирование сборного ресурса источника было:

Original prefab

Не уверен, почему он изменил префаб сам масштабирования до 1,1,1

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

Двери зеленого цвета справа - это двери слева и справа, которые я вручную добавьте префаб DoorShieldFXLocked Variant. И так должны выглядеть все точки после создания префаба DoorShieldFXLocked.

Example door with the prefab on Door_Left and on Door_Right

Каждая дверь построена с помощью Door_Left и Door_Right и на каждой двери она должен быть Instantiating DoorShieldFXLocked, но вместо этого он меняет масштаб DoorShieldFXLocked на 1,1,1 и помещает все Instantiated DoorShieldFXLocked в другую область почти в том же месте.

И это скриншот в Иерархии примера как строится дверь структура двери:

Каждая дверь - дитя сборного дома. Это просто префаб, я не смог уместить его на скриншоте, но помимо всего этого есть префаб. Поэтому мне интересно, есть ли способ также применить сборные конструкции каждой двери? Но это пример конструкции двери:

Door structure

1 Ответ

1 голос
/ 14 февраля 2020

Окей, раньше не было понятно, что вы хотели, поэтому вот обновленный ответ:

Проблема была в том, что

  1. Это применило бы точно такой же локальный вращение, положение и масштаб для объектов DoorShieldFX ... это не то, что вам нужно, поскольку эти положения и повороты будут относиться к его родителям. Так что да, в этом случае вы скорее хотели глобальные преобразования.

  2. Вы все их выводите на сцену root, а не как дети соответствующих дверей.

В этом случае вы скорее всего хотите сделать:

public struct TransformInfo
{
    public Transform Transform;

    public Vector3 pos;
    public Quaternion rot;
    public Vector3 scale;

    public TransformInfo(Transform transform)
    {
        Transform = transform;

        pos = transform.position;
        rot = transform.rotation;
        scale = transform.scale;
    }

    public void Apply(Transform transform)
    {
        // First of all it is important that
        // this new FX is a child of the according door so
        transform.SetParent(Transform, false);

        // Then you can put it in position if it is still needed
        // since actually SetParent with worldPositionStays = false
        // should actually already do that anyway.
        transform.position = pos;
        transform.rotation = rot;
        // Not sure about the scale since it would be relative to the door
        // depends on your case
    }
}

Затем, чтобы получить информацию из обоих списков, вы можете просто сделать, например, (предполагая, что сумма равна для левого и правого)

// Note your method should probably return something
public TransformInfo[] GetDoors()
{
    var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
    var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");

    TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length * 2];

    trnfrmIndex = 0;
    for (int i = 0; i < DoorsLeft.Length; i++)
    {
        trnfrm[trnfrmIndex] = new TransformInfo(DoorsLeft[i]);
        trnfrm[trnfrmIndex+1] = new TransformInfo(DoorsRight[i]);

        trnfrmIndex += 2;
    }

    return trnfrm;
}

Затем для повторного применения ко всем дверям вы можете сделать

foreach(var info in transformInfos)
{
    info.Apply(Instantiate (prefabToInit).transform);
}

Идентификационный номер больше не нужен.


Однако

Ну, на самом деле весь сценарий не нужен для вашей цели, поскольку вы также можете просто перебрать два массива, например

public void ApplyDoors()
{
    var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
    var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");

    foreach(var door in DoorsLeft)
    {
        Instantiate(prefabToInit, door.transform.position, door.transform.rotation, door.transform);
    }

    foreach(var door in DoorsRight)
    {
        Instantiate(prefabToInit, door.transform.position, door.transform.rotation, door.transform);
    }
}

, без необходимости какого-либо промежуточного класса!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...