BRO_TIGER
@BRO_TIGER
Indie Developer (C#, JS)

Как удалить объект из иерархии с помощью луча?

Доброго времени суток обитатели Тостера! Долгое время не было вопросов на тему Программирования и Разработки игр, думаю пора задать вопрос :)
Решил доделать Систему Строительства при этом избавиться от некоторых ненужных скриптов (Тем самым чуть-чуть оптимизировать саму игру). Вот и зашёл в тупик на Уничтожении объектов внутри Родителя! Я хотел с помощью луча от курсора мыши удалить объект из иерархии, но метод удалял саму иерархию а после можно было спокойно удалять объекты так как они уже не находились в иерархии... Вот сам скрипт, а точнее его части:

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


public class BuildingSystem : MonoBehaviour
{

    public LayerMask detailLayer;
    public bool IsBuilding;

    void Update()
    {
        if (IsBuilding && Input.GetMouseButtonDown(1))
        {
            Destroy();
        }
    }


    public void Destroy()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit, 20, detailLayer))
        {
            Destroy(hit.transform.gameObject);
        }
    }
}


Заранее Спасибо!
  • Вопрос задан
  • 685 просмотров
Решения вопроса 3
MrMureno
@MrMureno Куратор тега Unity
VR for all
толком и не понял в чем собственно вопрос. Как вместо всего родительского объекта удалить только пару детишек внутри??
Тут целая масса вариантов.
1) Отдельные слои/теги для нужных объектов (так же лучом смотрим куда попали, только не первый попавшийся объект. а все кого луч зацепил. RaycastAll метод)
2) по прежнему попав лучом в родительский объект - просто по именам искать (если однотипные или объекты с определенным компонентом. FindChild , GetComponent и тд.
3) Наверно мой любимая вариация варианта номер 2 - на родительские однотипные объекты навесить скрипт(или разные скрипты с наследованием) аля "Инфо о здании" какой нить BuildingComponentRefs.cs ,в котором пару публичных ссылок с подставленными нужными объектами. и возможно даже пару методов для работы с ними, для упрощения себе жизни. всякие аля "Выключить всё" "Включить все" "Пометить красным" и тд и тп. Получаться префабы с уже настроенными/подставленными ссылками. и ничего искать не надо, предполагая что на родительском объекте висит этот "описывающий" скрипт (и так как ссылки подставляются ручками, то не обязательно имена и места/иерархию в префабах прям так строго соблюдать)

Но все вообще сильно упирается в начальную архитектуру приложения и то как вы там что у себя реализовали и что планируете дальше.
Ответ написан
Griboks
@Griboks Куратор тега C#
А почему бы просто не использовать void OnMouseDown() на самой постройке? Вы, по сути, это и делаете, только через костыль. Если, конечно, за экраном нет невидимой стенки.
Ответ написан
BRO_TIGER
@BRO_TIGER Автор вопроса
Indie Developer (C#, JS)
Всем снова привет! Мне понравились несколько вариантов ответов... Это ответ Denis Gaydak и ответ Griboks! И вот как я это сделал - Я переписал старый скрипт и упростил до невозможного! (Спасибо Griboks!)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DestructibleObject : MonoBehaviour
{
    void OnMouseDown()
    {
        Destroy(gameObject);
    }
}


Дальше я добавил булевскую переменную в Скрипт Строительства:

public bool IsRemove;

А потом сделал скрипт с помощью которого я в детали добавлял Твердые Тела (Rigidbody) для работы с методом [OnMouseDown();]:

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

public class AddComponent : MonoBehaviour {

    public GameObject buildingCamera;
    Rigidbody rig;


    void Start()
    {
        buildingCamera = GameObject.FindGameObjectWithTag("MainCamera");
    }


    void Update ()
    {
        BuildingSystem BS = buildingCamera.GetComponent<BuildingSystem>();

        if (BS.IsRemove)
        {
            if (rig == null)
            {
                rig = gameObject.AddComponent<Rigidbody>();
                rig.constraints = RigidbodyConstraints.FreezeAll;
            }
        }

        if (!BS.IsRemove)
        {
            if (rig != null)
                Destroy(rig);
        }               
	}
}


А позже всё соединил с помощью Менеджера Строительства:

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

public class BuildingHUB : MonoBehaviour {

    public GameObject buildingCamera;

    public GameObject currentPreview;

    BuildingSystem buildingSystem;


    void Start()
    {
        buildingSystem = buildingCamera.GetComponent<BuildingSystem>();
    }


    void Update ()
    {
        currentPreview = buildingSystem.currentpreview.gameObject;

        if (buildingSystem.IsBuilding && Input.GetKeyDown(KeyCode.Delete))
        {
            ToRemove();
        }

        if (buildingSystem.IsRemove && Input.GetKeyDown(KeyCode.Escape))
        {
            RemoveToEscape();
        }
    }


    public void ToRemove()
    {
        buildingSystem.IsRemove = true;
        buildingSystem.IsBuilding = false;
        currentPreview.SetActive(false);
    }


    public void RemoveToEscape()
    {
        buildingSystem.IsRemove = false;
        buildingSystem.IsBuilding = true;
        currentPreview.SetActive(true);
    }
}


Всем Спасибо за ответы!)
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
flexer1992
@flexer1992
Unity Developer
Если коллайдер в который попадает рейкас висит на родителе то все верно, он и удалит родителя. Ну и по этому коду достаточно сложно строить какие-то предположения.
Ответ написан
Комментировать
@GreatRash
А почему вы не объявили переменную hit?

public void Destroy() {
  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  RaycastHit hit;

  if (Physics.Raycast(ray, out hit, 20, detailLayer)) {
    // теперь в hit что-то будет
  }
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы