Множественные утверждения True if для нескольких действий с одним и тем же GameObject?

Я создаю небольшой игровой проект (впервые изучаю С#, поэтому кодирование довольно ужасное).

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

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

Синий скрипт на кубе (работает)

    public bool bluetopurple = false;
// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {
    Renderer render = GetComponent<Renderer>();
    render.material.color = Color.blue;

    if (Input.GetMouseButtonDown (0)) {
        bluetopurple = true;

    }

Зеленый сценарий (работает)

public class greenscript : MonoBehaviour {
    public GameObject yellow;
    public yellowscript yellow1;
    public GameObject blue;
    public bluescript blue1;
    public bool green;


// Use this for initialization
void Start () {
    blue1 = GameObject.Find("blue").GetComponent<bluescript> ();
    blue1.bluetopurple = false;

    yellow1 = GameObject.Find("yellow").GetComponent<yellowscript> ();
    yellow1.yellowchange = false; 
    green = false;

}

// Update is called once per frame
void Update () {
    if (yellow1.yellowchange == true) {
        if (blue1.bluetopurple == true) {
            if (Input.GetMouseButtonDown (0)) {
                green = true; 
            }
            if (green == true) {
                Renderer render = GetComponent<Renderer> ();
                render.material.color = Color.green;
                Destroy ((blue), 0.0f);
            }

Фиолетовый скрипт (не работает, переменные изменены правильно, в отладчике не отображаются коды ошибок):

public class purplescript : MonoBehaviour {
public GameObject red;
public redscript red1;
public GameObject blue;
public bluescript blue1;
public bool purple;


// Use this for initialization
void Start () {
    blue1 = GameObject.Find("blue").GetComponent<bluescript> ();
    blue1.bluetopurple = false;

    red1 = GameObject.Find("red").GetComponent<redscript> ();
    red1.redtopurple = false;
    purple = false;

}

// Update is called once per frame
void Update () {
    if (red1.redtopurple == true) {
        if (blue1.bluetopurple == true) {
            if (Input.GetMouseButtonDown (0)) {
                purple = true; 
            }
            if (purple == true) {
                Renderer render = GetComponent<Renderer> ();
                render.material.color = Color.magenta;
                Destroy ((red), 0.0f);
            }

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
160
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

у вас не должно быть 3 класса для каждого куба... У вас должен быть класс, прикрепленный ко всем кубам, и переменная, которая устанавливает инспектору, какой цвет у куба, и логическая активация. Затем создайте основной класс, содержащий массив со всеми кубами. И вам нужен абстрактный класс, у которого есть абстрактный метод Activate, каждый куб расширяет абстрактный класс. В основном классе при клике на куб берем из него абстрактный класс и вызываем метод Activate.

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

George 14.06.2019 08:43

Спасибо за вклад, Джордж, я попытаюсь сжать их в два сценария, когда узнаю больше.

user3211493 17.06.2019 22:18
Ответ принят как подходящий

Прежде всего вместо

GameObject.Find("blue").GetComponent<bluescript>();

скорее использовать

FindObjectOfType<bluescript>();

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


Я не совсем понял, чего вы пытаетесь достичь, но обратите внимание, что Input.GetMouseButtonDown(0) есть true на каждый GameObject.. не только тот, на который вы сейчас наводите указатель мыши!

Если вы хотите реализовать что-то, что должно происходить, когда вы нажимаете на определенный GameObject (с Collider или GUIElement), то лучше используйте OnMouseDown. Кроме того, вы делаете много ненужных вещей в Update, которые называются каждым кадром, поэтому могут быть некоторые проблемы.

Тогда в вашем коде много мелких проблем

  1. для вашего синего сценария

    Renderer render = GetComponent<Renderer>();
    render.material.color = Color.blue;
    

    Наличие этого в вашем методе Update не имеет смысла, потому что

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

    так что, вероятно, это должно выглядеть так

    public class bluescript : MonoBehaviour
    {
        public bool bluetopurple = false;
    
        // Use this for initialization
        private void Start () 
        {
            Renderer render = GetComponent<Renderer>();
            render.material.color = Color.blue;
        } 
    
        // Catch the mousedown
        private void OnMouseDown()
        {
            bluetopurple = true;
        }
    }
    
  2. аналогичные проблемы также встречаются в greenscript. Вы вызываете один и тот же код снова и снова для каждого кадра в Update, blue может быть не установлен, поэтому он может не уничтожиться, а выдать ошибку. Также

    Destroy(blue, 0.0f);
    

    Здесь вы уничтожаете Компонент, а не GameObject! Я думаю, вы хотели сделать Destroy(blue.gameObject); .. также прохождение 0.0f можно пропустить, потому что оно 0 в любом случае по умолчанию.

    public class greenscript : MonoBehaviour 
    {
        // If possible set these already in the Inspector and don't use
        // Find and GetComponent at all
        public yellowscript yellow;
        public bluescript blue;
        public Renderer render;
    
        public bool green;
    
        // Use this for initialization
        private void Start () 
        {
            Renderer render = GetComponent<Renderer>();
    
            blue = FindObjectOfType<bluescript>();
            blue.bluetopurple = false;
    
            yellow = FindObjectOfType<yellowscript> ();
            yellow.yellowchange = false; 
    
            green = false;
        }
    
        private void OnMouseDown()
        {
            if (!yellow.yellowchange) return;
    
            // if you destroyed the blue GameObject already
            // checking this again would throw an error so catch that case
            if (!blue) return;
    
            if (!blue.bluetopurple) return;
    
            green = true;
    
            render.material.color = Color.green;
    
            Destroy(blue.gameObject);
        }
    }
    
  3. И, наконец, фиолетовый скрипт

    public class purplescript : MonoBehaviour 
    {
        public redscript red;
        public bluescript blue;
        public Renderer render;
    
        public bool purple;
    
        // Use this for initialization
        void Start() 
        {
            Renderer render = GetComponent<Renderer>();
    
            blue = FindObjectOfType<bluescript>();
            blue.bluetopurple = false;
    
            red = FindObjectOfType<redscript>();
            red.redtopurple = false;
    
            purple = false;
        }
    
        private void OnMouseDown()
        {
            // here again check if the object still exists first
            if (!red) return;
    
            if (!red.redtopurple) return;
            if (!blue.bluetopurple) return;
    
            purple = true;
    
            render.material.color = Color.magenta;
    
            Destroy(red.gameObject);
        }
    }
    

Вы не показали код для redscript и yellowscript. В greenscript вы Destroy(blue), но в purplescript вы полагаетесь на blue.bluetopurple .. это не кажется правильным.


Альтернативное и лучшее масштабируемое/обслуживаемое решение

Из сценариев, которые я вижу здесь, вы можете значительно упростить это, используя только сценарии 2 сингла a:

  • ScriptA: не полагается на какой-либо другой скрипт, а только меняет свой цвет и логическое значение при нажатии.
  • ScriptB: делает то же самое, но щелкает только тогда, когда значения двух других скриптов верны, меняет свой цвет, уничтожает GameObject одного из других скриптов.

Все остальные, такие как Какие значения проверять, к какому цвету я обращаюсь, какой объект я уничтожаю, вы можете установить с помощью параметров в Инспекторе. Таким образом, вы бы только

public class ScriptA : MonoBehaviour
{
    [Header("Base-Components")]
    public Renderer renderer;

    [Header("Base-Settings")]
    // start with this color
    public Color InitialColor = Color.white;
    // turn to this after being clicked
    public Color TargetColor = Color.white;

    [Header("Values")]
    public bool WasClicked;

    private void Awake()
    {
        SetUp();
    }

    private void SetUp()
    {
        if (!renderer) renderer = GetComponent<Renderer>();
        renderer.material.color = InitialColor;

        WasClicked = false;
    }

    private void OnMouseDown()
    {
        HandleClick();
    }

    // make this virtual so we can extend/overwrite it in child classes
    protected virtual void HandleClick()
    {
        WasClicked = true;
        renderer.material.color = TargetColor;
    }
}

Так как второй скрипт очень похож, но только расширяет поведение, унаследованное от ScriptA. Это означает, что он будет иметь все уже реализованные свойства и методы, но теперь вы можете расширить те, которые реализованы как virtual:

public class ScriptB : MonoBehaviour
{
    // What does this script have, ScriptA didn't?
    [Header("Additional Components")]
    // The two components you want to check the bool for
    public ScriptA FirstToCheck;
    public ScriptA SecondToCheck;
    [Space]
    // The component you want to destroy
    public ScriptA ToDestroy;

    // Overwrite/Extend the behaviour of HandleClick
    protected virtual void HandleClick()
    {
        // One of the references doesn't exist 
        // so object was probably already destroyed
        if (!ToDestroy || !FirstToCheck || !SecondToCheck) return;

        // One of the objects wasn't clicked yet
        if (!FirstToCheck.WasClicked || !SecondToCheck.WasClicked) return;

        // Do what the parent implemented
        // in this case set my bool and change my color
        base.HandleClick();

        Destroy(ToDestroy.gameObject);
    }
}

Поместите ScriptA на куб(ы), который не зависит от других, чтобы активироваться. И ScriptB на кубиках, которые сначала проверяют два других кубика. Затем настройте все параметры в Инспекторе и уже установите ссылки между всеми теми объектами.

Спасибо за помощь DerHugo, я внесу все изменения, которые вы рекомендовали, а я даже не знал о виртуальном классе.

user3211493 17.06.2019 22:17

Другие вопросы по теме