Как изменить логическое значение из другого скрипта C#

#c# #unity3d #boolean

#c# #unity3d #логическое

Вопрос:

У меня есть 2 скрипта, playerMachanics и enemyBehavior. У моего вражеского поведения есть логическое значение, которое, когда логическое значение равно true, удаляется от игрока. Вместо этого я получаю сообщение об ошибке: «ссылка на объект не установлена для экземпляра объекта».

Я уверен, что это означает, что скрипт не может найти компонент, но я не могу понять, что не так.

 public class enemyBehavior : MonoBehaviour
{
    public bool evade = false;
    public GameObject Player;
    public float movementSpeed = 4;

    // Start is called before the first frame update
    void Start()
    {
        Player = GameObject.FindGameObjectWithTag("Player");
    }

    // Update is called once per frame
    void Update()
    {
        transform.LookAt(Player.transform);
        transform.position  = transform.forward * movementSpeed * Time.deltaTime;

        if (evade == true)
        {
            movementSpeed = -4;
        }
    }
}
  
 public class playerMechanics : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {

    }

    void OnCollisionEnter(Collision collision)
    {

        enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
        if (collision.gameObject.name == "coin")
        {
            Destroy(collision.gameObject);
            enemyBehavior script = GetComponent<enemyBehavior>();
            script.evade = script.evade == true;
        }
    }
}
  

Я ожидал, что скорость движения будет равна -4, но теперь я просто получаю сообщение об ошибке.

Комментарии:

1. script.evade = script.evade == true; ничего не делает. Вы пытаетесь изменить значение на противоположное? Если да, измените true на false или просто сделайте: script.evade = !script.evade;

2. Моя основная проблема заключается в ошибке: «ссылка на объект не установлена для экземпляра объекта». Я даже ничего не могу сделать, пока это есть…

3. @RufusL это script.evade = сценарий.уклонение == false;

4. Итак, это означает script есть null . Из документации : «Возвращает компонент типа type, если к игровому объекту прикреплен один, null, если нет». . Кроме того, похоже, что эта строка не нужна: enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();

5. @RufusL да, эта строка не была нужна. Я удалил его, но я все еще не понимаю, что мне нужно сделать, чтобы исправить уклонение. Я изменил его на: script.evade = !script.evade; но я все еще получаю ошибку

Ответ №1:

Вызов GetComponent сам по себе будет искать компонент, прикрепленный к родительскому объекту скрипта, который, я думаю, в данном случае является игроком. Таким образом, он всегда будет возвращать значение null.

Добавить

 Public GameObject enemy;
  

в класс playerMechanics, а затем перейдите в конструктор и перетащите игровой объект, к которому прикреплен скрипт enemyBehavior. Существует несколько проблем с методом OnCollisionEnter. Что-то вроде этого

 void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.name == "coin")
    {
        Destroy(collision.gameObject);
        enemyBehavior script = enemy.GetComponent<enemyBehavior>();
        script.evade = false;
    }
}
  

должно помочь вам двигаться в правильном направлении.

Ответ №2:

Является ли поведение противника объектом player? Смотрите здесь

 enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
  

и здесь

 enemyBehavior script = GetComponent<enemyBehavior>();
  

Вам нужно реализовать способ отслеживания того, какой вражеский экземпляр вы захватываете. Сделайте это, создав переменную для хранения вражеского скрипта или используя синглтон для вражеского скрипта (если есть один враг).
Переменная:

 public enemyBehaviour enemy;
  

Синглтон:
(Поведение врага)

 public static enemyBehaviour instance = null;
private static readonly object padLock = new object();

void Awake(){
  lock(padLock){
    if(instance == null)
      instance = this;
  }
}
  

(проигрыватель)

 enemyBehaviour.instance.evade = false;
  

Посмотрите синглтоны, если хотите узнать больше.

Ответ №3:

Если я прав, я думаю, что ваша игровая механика работает следующим образом: цель игрока — собирать монеты. Когда они соберут его, враг рядом с ним подойдет и ускользнет от игрока.

Если это так, вам следует использовать это:

 public class enemyBehavior : MonoBehaviour
    {
        public bool evade = false;
        public GameObject Player;
        public float movementSpeed = 4;

        void Start()
        {
            Player = GameObject.FindGameObjectWithTag("Player");
        }
        void Update()
        {
            transform.LookAt(Player.transform);
            transform.position  = transform.forward * movementSpeed * Time.deltaTime;

            if (evade)
            {
                movementSpeed = -4;
            }
        }
    }

    public class playerMechanics : MonoBehaviour
    {

        [SerializeField] enemyBehvaior enemy;

        void OnCollisionEnter(Collision collision)
        {
            if (collision.collider.name == "coin")
            {
                Destroy(collision.collider.gameObject);
                enemy.evade = true;
            }
        }
    }
  

В вашем коде вы написали ‘collision.GameObject.’ Это относится к объекту, к которому прикреплен скрипт. Если вы хотите ссылаться на объект, к которому мы обращаемся, используйте ‘collision.collider’.

‘[SerializeField]’ — это атрибут unity, который используется для отображения поля в инспекторе, не делая его общедоступным.

На всякий случай, если вы используете 2D, убедитесь, что метод подписан ‘OnCollisionEnter2D (столкновение Collision2D)’.

Надеюсь, я ответил на ваш вопрос. 🙂