#c# #unity3d
#c# #unity3d
Вопрос:
Я работаю над проектом Unity, в котором 3D-объекты, такие как куб, Сфера и цилиндр, появляются в центре экрана при выборе из выпадающего списка кнопок. Сценарий создания экземпляра работает нормально, но все 3 объекта появляются и сливаются друг с другом. Ожидается, что при создании экземпляра одного из них будут уничтожены 2 других. Проблема, с которой я сталкиваюсь, заключается в том, что созданный объект является клоном, и я не могу заставить его быть уничтоженным. Я новичок в Unity и пытаюсь учиться. Я вставил приведенный ниже код, я создал 3 из них для каждой кнопки и изменил параметры в соответствии с объектом.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Cube_Inst : MonoBehaviour
{
public GameObject box;
public Transform pos;
public bool trigger;
public Button yourButton;
public GameObject Sphere_Destroy;
public GameObject Cylinder_Destroy;
void Start()
{
Button btn = yourButton.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
trigger = true;
Destroy(Sphere_Destroy);
Destroy(Cylinder_Destroy);
}
public void Update()
{
if (trigger == true)
{
Instantiate(box, pos.position, pos.rotation);
trigger = false;
}
}
}
Ответ №1:
Вы должны скорее реализовать все централизованно («Шаблон единой ответственности»).
Не позволяйте отдельным кнопкам иметь отдельные скрипты с множеством перекрестных ссылок между ними.
Лучше иметь один компонент центрального контроллера и позволять кнопкам передавать разные параметры в общий метод создания.
Также вы должны делать это на основе событий — вы уже знаете момент нажатия кнопки — вместо опроса, проверяющего флаг в Update
методе. Я бы использовал что-то вроде
// Put this on ONE object that is always active in the Scene
public class SpawnController : MonoBehaviour
{
private GameObject _currentClone;
private GameObject _currentPrefab;
public void SetInstance(GameObject prefab, Vector3 position, Quaternion rotation)
{
// Was the same prefab passed again? -> Ignore
if(prefab == _currentPrefab) return;
_currentPrefab = prefab;
// Already exists a clone? -> Destroy it
if(_currentClone) Destroy(_currentClone);
// Create and store the new clone
_currentClone = Instantiate (prefab, position, rotation);
}
}
Поэтому, если SetInstance
вызывается, он автоматически уничтожает любой уже существующий экземпляр.
А затем иметь один и тот же компонент на каждой кнопке, но только настраивать их соответствующим образом
public class SpawnButton : MonoBehaviour
{
// Already reference this via the Inspector if possible
// If not we will get it on runtime as fallback
[SerializeField] private Button _button;
// For each different button reference a different prefab
[SerializeField] private GameObject _prefab;
// Reference the spawn point
[SerializeField] private Transform _spawnPoint;
// Here drag in the SpawnController from the scene if possible
// if not, we will find it on runtime as fallback
[SerializeField] private SpawnController _spawnController;
private void Awake()
{
if(!_button) _button = Get component<Button>();
_button.onClick.AddListener(DoSpawn());
if(!_spawnController) _spawnController = FindObjectOfType<SpawnController>();
}
private void DoSpawn()
{
// Only tell the SpawnController to do its thing
// This button doesn't have to know or care what that means for the Scene
_spawnController.SetInstance(_prefab, _spawnPoint.position, _spawnPoint.rotation);
}
}
Вы могли бы даже сделать шаг дальше и вообще не сообщать кнопкам о SpawnController
и его секретном SetInstance
методе, а скорее сделать что-то вроде
public class SpawnController : MonoBehaviour
{
private GameObject _currentClone;
private Button _lastClickedButton;
private void Awake()
{
SpawnButton.OnSpawnButtonClicked = SetInstance;
}
private void SetInstance(Button button, GameObject prefab, Vector3 position, Quaternion rotation)
{
// Was the same button pressed again? -> Ignore
if(button == _lastClickedButton) return;
_lastClickedButton = button;
// Already exists a clone? -> Destroy it
if(_currentClone) Destroy(_currentClone);
// Create and store the new clone
_currentClone = Instantiate (prefab, position, rotation);
}
}
и затем
public class SpawnButton : MonoBehaviour
{
public static event Action<Button, GameObject, Vector3, Quaternion> OnSpawnButtonClicked;
// Already reference this via the Inspector if possible
// If not we will get it on runtime as fallback
[SerializeField] private Button _button;
// For each different button reference a different prefab
[SerializeField] private GameObject _prefab;
// Reference the spawn point
[SerializeField] private Transform _spawnPoint;
private void Awake()
{
if(!_button) _button = Get component<Button>();
_button.onClick.AddListener(DoSpawn());
}
private void DoSpawn()
{
// Only Invoke the event
// You don't care if or who is listening
OnSpawnButtonClicked?.Invoke(this, _prefab, _spawnPoint.position, _spawnPoint.rotation);
}
}
Комментарии:
1. Большое вам спасибо за это. Действительно ценится