Как я могу создать экземпляр моей границы вокруг «бронзы», когда она самая близкая, и уничтожить границу, когда она больше не самая близкая? - PullRequest
0 голосов
/ 07 августа 2020

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

Я готов полностью перезапустите мой бронзовый сценарий, если это означает, что я могу сделать это проще.

Заранее спасибо!

Найти ближайший бронзовый сценарий

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

public class FindBronze : MonoBehaviour
{
    void Update()
    {
        FindClosestBronze();
    }
    void FindClosestBronze()
    {
        float distanceToClosestBronze = Mathf.Infinity;
        Bronze closestBronze = null;
        Bronze[] allBronze = GameObject.FindObjectsOfType<Bronze>();

        foreach (Bronze currentBronze in allBronze)
        {
            float distanceToBronze = (currentBronze.transform.position - this.transform.position).sqrMagnitude;
            if (distanceToBronze < distanceToClosestBronze)
            {
                distanceToClosestBronze = distanceToBronze;
                closestBronze = currentBronze;
            }
            if (distanceToBronze > distanceToClosestBronze)
            {
                closestBronze.GetComponent<Bronze>().notSelected();
                
            }

            closestBronze.GetComponent<Bronze>().Selected();
        }
    }
}

Бронзовый сценарий (включая контур)

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

public class Bronze : MonoBehaviour
{
    public bool isSelected = false;
    public Animator anim;
    [SerializeField]
    public GameObject selectedBox;
    public GameObject bronzeBase;
    private GameObject clone;
    // Update is called once per frame
    void Awake()
    {
        clone = (GameObject)Instantiate(selectedBox, bronzeBase.transform);

    }
    public void Selected()
    {
        if (!isSelected)
        {

           clone = (GameObject)Instantiate(selectedBox, bronzeBase.transform);
            isSelected = true;

        }
        
        else
        {
            Destroy(clone);
            isSelected = false;
        }
    }
    public void notSelected()
    {
       
        Destroy(selectedBox);
    }   

}

1 Ответ

1 голос
/ 07 августа 2020

В Bronze в notSelected вы уничтожаете префаб selectBox!

Вы, вероятно, хотели бы уничтожить экземпляр clone.

В любом случае, я бы предложил несколько вещей, которые я бы сделал по-другому.

  • Вместо Instantiate и Destroy все время лучше используйте только SetActive
  • Вместо используя FindObjectOfType в Update, сохраните их в событии HashSet: каждый экземпляр Bronze регистрирует и отменяет регистрацию
  • Зависит от личного вкуса, но я бы использовал Linq, чтобы найти ближайший экземпляр

Это может выглядеть как

public class Bronze : MonoBehaviour
{
    // Every instance of this component registers and unregisters itself here
    public static readonly HashSet<Bronze> Instances = new HashSet<Bronze>();

    [Header("References")]
    public Animator anim;
    [SerializeField] private GameObject selectedBox;
    [SerializeField] private GameObject bronzeBase;

    [Header("Debugging")]
    [SerializeField] bool _isSelected = false;

    private GameObject clone;

    // Have a property for the selection
    public bool IsSelected
    {
        // when something reads this property return _isSelected
        get => _isSelected;
        // This is executed everytime someone changes the value of IsSelected
        set
        {
            if(_isSelected == value) return;

            _isSelected = value;

            clone.SetActive(_isSelected);
        }
    }

    // Update is called once per frame
    void Awake()
    {
        // Instantiate already returns the type of the given prefab
        clone = Instantiate(selectedBox, bronzeBase.transform);

        // Register yourself to the alive instances
        Instances.Add(this);
    }

    private void OnDestroy ()
    {
        // Remove yourself from the Instances
        Instances.Remove(this);
    }
}

А затем использовать

using System.Linq;

public class FindBronze : MonoBehaviour
{
    private Bronze currentSelected;

    private void Update()
    {
        UpdateClosestBronze();
    }

    void UpdateClosestBronze()
    {
        if(Bronze.Instances.Count ==0) return;

        // This takes the instances
        // orders them by distance ascending using the sqrMagnitude
        // of the vector between the Instance and you
        // sqrMagnitude is more efficient than Vector3.Distance when you only need to compare instead of the actual distance
        // then finally it takes the first item 
        var newClosest = Bronze.Instances.OrderBy(b => (b.transform.position - transform.position).sqrMagnitude).First();

        // skip if the result is the same as last time
        if(newClosest == currentSelected) return;

        // otherwise first deselect the current selection if there is one
        if(currentSelected)
        {
            currentSelected.IsSelected = false;
        }
   
        // Then set the new selection     
        currentSelected = newSelected;
        currentSelected.IsSelected = true;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...