Ответы пользователя по тегу Unity
  • Как сделать так, чтобы коллайдер объекта не вращался вслед за объектом?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Проще всего оставить коллайдер на объекте, а весь визуал перенести внутрь по иерархии в дочерний, и вращать уже дочерний.
    Ответ написан
    Комментировать
  • Как исправить ошибку NullReferenceException: Object reference not set to an instance of an object?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Ошибка заключается в том, что в этой строке:
    hit.collider.transform.parent.GetComponent<DoorScript>().count_v();

    Вы пытаетесь вызвать родительский объект у объекта, который не имеет родительского объекта. В таком случае получаете null. Если вы хотите обратиться к корневому объекту, используйте свойство root. Типа:
    hit.collider.transform.root.GetComponent<DoorScript>().count_v();

    Что, к слову, можно сократить до
    hit.transform.root.GetComponent<DoorScript>().count_v();


    Если же у вас есть вероятность, что скрипта DoorScript вообще не будет на объекте с данным тегом, то от него проще отказаться:
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class user : MonoBehaviour {
    
    	public float Distens = 0f;
    
    	void Update() {
    		if (Input.GetKeyDown(KeyCode.E)) {
    			Ray ray = new Ray (transform.position, transform.forward);
    			RaycastHit hit;
    			if (Physics.Raycast(ray, out hit, Distens))
    				if (hit.transform.root.TryGetComponent(out DoorScript door))
    					door.count_v();
    		}
    	}
    }
    Ответ написан
    Комментировать
  • Как изменить слой текста в юнити?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если вы имеете ввиду приоритет отрисовки среди элементов интерфейса, то их определяет порядок иерархии. Например, если вы расположите сначала текст, а потом картинку, то картинка будет рисоваться после текста, и, следовательно, его закроет.
    Если данная проблема наблюдается со всем канвасом в сравнении с другими элементами сцены, то имеет смысл создать отдельный Sorting Layer типа UI, расположить его ниже других (чтобы приоритет был выше) и установить его канвасу.
    Если вы имели ввиду текст типа TextMeshPro, то у него есть собственный order in layer, находящийся в меню Extra Settings.
    Если вы имели ввиду что-то другое, ответьте с более детальным описанием проблемы и скриншотами.
    Ответ написан
    Комментировать
  • Как установить ссылку на объект в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Есть такое понятие как контекст. Если переменная создана внутри одного блока кода, она не будет видима нигде, кроме этого и дочерних ему блоков кода, коими являются как методы, так и конструкции типа if. В вашем коде есть два фрагмента:
    if (!oneApple) {
    	if (Input.GetKeyUp(KeyCode.Q)) {
    		createApple();
    		GameObject apple = GameObject.Find("apple");
    		oneApple = true;
    	}
    }
    
    if (oneApple) {
    	apple.transform.position -= new Vector3(0, 0, 5 * Time.deltaTime);
    	if (apple.transform.position.z < -15) {
    		Destroy(apple);
    		oneApple =false;
    	}
    }

    Не понятно, идут они вместе или в разных методах, но даже на этом уровне видно, что контекст переменной apple находится исключительно внутри блока первого фрагмента кода. Решается это путём создания переменной класса. Если таковая уже есть, тогда из первого фрагмента удалите GameObject, чтобы получилось.
    if (!oneApple) {
    	if (Input.GetKeyUp(KeyCode.Q)) {
    		createApple();
    		apple = GameObject.Find("apple");
    		oneApple = true;
    	}
    }

    И, на будущее, вставляйте скрипты внутрь соответствующего тега.
    Пара непрошенных советов
    // Данный код
    GameObject createApple() {
    	GameObject result = new GameObject("apple");
    	GameObject apple = null;
    	apple = apllePrefab;
    	Vector3 applePos = transform.position + new Vector3 (1, 0.5f,1);
    	if (apple != null) {
    		GameObject go = Instantiate(apllePrefab, applePos,Quaternion.identity);
    	}
    	return result;
    }
    // Можно заменить на такой без потери смысла
    GameObject сreateApple() {
    	var applePos = transform.position + new Vector3(1, 0.5f, 1);
    	return Instantiate(apllePrefab, applePos, Quaternion.identity);
    }
    // Далее в этом фрагменте вы сначала помещаете объект на сцену, а затем пытаетесь его найти
    if (!oneApple) {
    	if (Input.GetKeyUp(KeyCode.Q)) {
    		createApple();
    		apple = GameObject.Find("apple");
    		oneApple = true;
    	}
    }
    // Не то чтобы метод GameObject.Find вообще не стоило
    // никогда использовать, но обычно есть более практичные
    // способы это сделать. Например передать прямую ссылку:
    if (!oneApple) {
    	if (Input.GetKeyUp(KeyCode.Q)) {
    		apple = сreateApple();
    		oneApple = true;
    	}
    }
    Ответ написан
    Комментировать
  • Как исправить ошибки билда в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Попробуйте сбилдить проект, сменив бекенд на моно:
    Edit >> Project Settings >> Player >> Other Settings >> Configuration >> Scripting Backend
    Если не помогло, то у вас, скорее всего 2022 юнити. Если да, перенесите проект на 2021, там должно всё работать.
    Ответ написан
  • Можно ли переместить центр объекта?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Вам нужен якорь - не специальный компонент, а, скорее дополнительная точка в пространстве.

    Если под прямоугольником вы имели ввиду некий 2D/3D-объект, то вам нужно создать якорь (Create Empty) и расположить ваш объект так, чтобы якорь находился в нужном месте, после чего совершать нужные действия по трансформу уже не с объектом, а с якорем. Только не забудьте расположить объект по иерархии внутри якоря.

    Если вы хотите хотите через сцену управлять объектом с точкой-якорем, переключитеcь с соответствующий режим. Где-то сверху есть вот такой переключатель:
    6384907bc4a6c292064992.png
    Переключите левый в режим Pivot

    В случае Unity UI всё немного проще, т.к. там используется модифицированный компонент Rect Transform, имеющий свойство Pivot.
    Ответ написан
    2 комментария
  • Как в юнити сделать сохранение большого числа переменных?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Попробуйте JSON-сериализацию https://docs.unity3d.com/2020.1/Documentation/Manu... с сохранением данных в playerprefs https://docs.unity3d.com/ScriptReference/PlayerPre... или непосредственно на устройство - https://docs.unity3d.com/ScriptReference/Applicati.... В общем случае этого достаточно. Но, судя по количеству полей данных, вам придётся как-то гарантировать их констистентность и способ восстановления. Если я не ошибся, попробуйте поработать с бд SQLite.
    Если вам нужно хранить в облаке, используйте Firebase или Playfab.
    Ответ написан
    Комментировать
  • Какие курсы/видеоуроки по UNITY вы посоветуете?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Для начинающего - тупо любые популярные. На раннем этапе там напортачить сложно, потому просто смотрите, чтобы подача материала была вам комфортна. Начало это интерфейс, инструменты, основные вкладки, основы физики и освещения. Дойдя до этого этапа, вы уже сами будете легче понимать, какой именно источник информации вам более комфортен - его дальше и смотрите/читайте.
    Ответ написан
    Комментировать
  • Как проверить есть ли префаб на сцене?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    1) По тегу. Метод FindGameObjectsWithTag возвращает массив объектов типа GameObject, характеризующихся указанным тегом. Если у вас сложный объект (состоящих из родительского и дочерних), то помечайте тегом только родительский. Минус данного подхода в том, что он относительно медленный, но ощутить его медленность у вас получится на действительно огромных сценах (несколько тысяч/десятков тысяч объектов).

    Вот так будет выглядеть код, если вы пометите рут-объект врагов тегом Enemy:
    var enemies = GameObject.FindGameObjectsWithTag("Enemy");
    if (enemies.Length > 0) {
    	// действие
    }


    2. По специфическому скрипту. Проблема тут та же, что и в прошлом пункте, поскольку под капотом они работают почти одинаково.

    Скорее всего, для врага у вас есть специальный скрипт-контроллер, который называется, например, Enemy. Тогда код будет таким:
    var enemies = FindObjectsOfType<Enemy>();
    if (enemies.Length > 0) {
    	// действие
    }


    3. Список врагов. Спавня врага, вы добавляете его в список. А перед уничтожеием удаляете из него.
    Создание - скрипт спаунера:
    public List<Enemy> enemies = new List<Enemy>();
    // ...
    var enemy = Instantiate(...);
    enemies.Add(enemy);
    // чтобы скрипт врага мог общаться с контроллером, передадим туда ссылку
    enemy.spawner = this;
    // и метод логики удаления
    public void Remove(Enemy e) {
        enemies.Remove(e);
        if (enemies.Count > 0) {
            // действие
        }
    }

    Уничтожение, скрипт врага:
    public Spawner spawner;
    // ...
    if (health <= 0) {
        spawner.Remove(this); // удаляем этого врага из списка спаунера
        Destroy(gameObject); // уничтожаем его объект
    }

    Третий способ самый выгодный с точки зрения производительности, так как вы имеете список, где есть только враги.
    Ответ написан
    Комментировать
  • Как лучше/правильнее реализовать архитектуру проекта игры в юнити?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Норм архитектура. Касательно ссылок, простейший, лёгкий и неплохой способ - паттерн синглтон.
    Ответ написан
    Комментировать
  • Как сделать чтобы каждая кнопка выводила свой текст на unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    У текстового поля как объекта есть два поля для имени/номера - имя объекта и видимое текстовое поле. Забегая вперёд скажу, что вы не можете удалить из консоли одно выбранное сообщение, а лишь всё скопом, что наталкивает на мысль, что вы подразумевали сделать кнопку-переключатель видимости вложенного текста.
    Если я прав, то вам достаточно привязать к кнопке что-то типа:
    public GameObject text; // ссылка на внутреннее текстовое поле
    // ...
    public void OnClick() { // привязать к кнопке
    	text.SetActive(!text.activeSelf); // переключает видимость
    }
    Ответ написан
    Комментировать
  • Как проверять столкновение по слою?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Суть - будь то столкновение типа Collision или ControllerColliderHit, у обоих можно достать свойство gameObject, к которому и отосится искомое вами свойство.
    private void OnCollisionEnter(Collision c) {
    	if (c.gameObject.layer == 6) { // порядковый номер искомого слоя
    		// do anything
    	}
    }
    Ответ написан
    Комментировать
  • Как сделать ограничение на прыжок?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Чтобы сделать ограничение на прыжки, они сначала вообще должны быть. У вас есть доступный извне метод Move(), создайте аналогичный Jump(). Что-то типо такого:

    public void Jump() {
    	rb2d.AddForce(Vector2.up * jumpPower);
    }


    Говоря об ограничении, полагаю, вы подразумеваете количество прыжков? Если да, вам нужно хранить число возможных и совершённых прыжков в качестве полей класса, увеличивать последнее при прыжке и перед попыткой его совершения сравнивать их.

    public int jumpsLimit;
    public int jumpsDone;
    public void Jump() {
    	if (jumpsDone < jumpsLimit) {
    		rb2d.AddForce(Vector2.up * jumpPower);
    		jumpsDone++;
    	}
    }


    Осталось лишь в момент столкновения с землёй и всем, от чего можно отпрыгивать, сбрасывать jumpsDone до 0.
    Ответ написан
    1 комментарий
  • Почему при взаимодействии с UI в OnMessage вебсокет закрывает соединение?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если коротко, то всё из-за того, что вебсокет работает в ином, нежели юнити, потоке. Поток юнити обслуживает покадровую систему и имеет закрытую структуру. Вместо прямого запуска кода сделайте очередь команд, в которую помещайте то, что вам нужно запустить. Выглядеть это будет как-то так:

    // очередь команд
    private readonly ConcurrentQueue<Action> _Actions = new ConcurrentQueue<Action>();
    
    // получаете сообщение - ставите в очередь
    private void OnMessage(object sender, MessageEventArgs e) {
    	_Actions.Enqueue(() => ReadResponse(e.Data));
    }
    
    // каждое обновление экрана запускаем всю очередь
    private void Update() {
    	while (_Actions.Count > 0)
    		if (_Actions.TryDequeue(out var action))
    			action?.Invoke();
    }
    
    // вот тут вы уже можете влиять на тот же текст
    private void ReadResponse(string data) {
    	// ваш код
    }
    Ответ написан
    1 комментарий
  • Как пульнуть обекь в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Возможно, вы так и задумывали, но если нет, то в строке:
    num = Random.Range(0, 4);
    У вас генерируются числа от 0 до 3 включительно, но число 0 не обрабатывается методом спавна.

    Затем удалите следующие три строки:
    num = (int) num;
    yield return new WaitForSeconds(0.001f);
    num = 0;


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

    Если не помогло - пишите в коменты, будем разбираться дальше.
    Ответ написан
  • Как сделать чтобы сфера шла всегда вперед и крутилась?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Существует, два разных направления вперёд:
    * transform.forward - направление вперёд объекта, зависящее от его поворота (обычно, ещё бывает берут transform.right и другие);
    * Vector3.forward - глобальное направление вперёд.

    Проблема вашего вопроса в том, что объект, двигаясь вперёд и кручась при этом будет либо вращаться на месте, либо описывать круг вокруг некоторого центра (в зависимости от настроек скорости движения и вращения.

    Полагаю, вы хотите двигать объект вперёд по глобальной оси. В таком случае, достаточно просто тянуть его вперёд по глобальной оси и при этом спокойно вращать любым известным вам способом.
    Ответ написан
  • Как не дать коллайдеру внутри объекта проникнуть в другой коллайдер?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Сам по себе CharacterController имеет внутренний капсуль-коллайдер, который так-то не должен застревать внутри других объектов. Такое может происходить в случае неправильного использования (скрипты). Например, толкать персонажа внутрь коллайдера со слишком большой силой. Сделай вы так со стандартной связкой коллайдера и твёрдого тела, последний бы просто улетел от накопившихся внутренних напряжений. CharacterController же, в свою очередь, не то чтобы сдвинуть, даже телепортировать извне никак нельзя без его отключения.

    Также такой баг теоретически может возникнуть при движении с использованием свойства velocity, словно это rigidbody. Если вы вдруг так делайте - используйте метод Move(Vector3).

    Кроме того, ваш контроллер сам по себе не знаком с гравитацией. Есть также ненулевая вероятность, что стоя краешком на обрыве персонаж всё ещё считает себя стоящим на земле, и у вас не срабатывает код гравитации (если он вообще есть).

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

    Примерно вот так выглядит обычный скрипт персонажа с таким контроллером:
    скрипт

    using UnityEngine;
    
    [RequireComponent(typeof(CharacterController))]
    public class PlayerMove3D : MonoBehaviour {
    
    	CharacterController controller;
    
    	Vector3 input, velocity;
    
    	public float moveSpeed = 10f;
    	public float jumpPower = 10f;
    	public float gravity = 20f;
    
    	public Transform groundCheckPoint;
    	public float groundCheckRadius;
    	public LayerMask groundLayer;
    
    	private void Start() => controller = GetComponent<CharacterController>();
    
    	private void Update() {
    		input.x = Input.GetAxis("Horizontal");
    		input.z = Input.GetAxis("Vertical");
    		input = input.normalized;
    
    		bool grounded = Physics.CheckSphere(groundCheckPoint.position, groundCheckRadius, groundLayer);
    
    		if (grounded && velocity.y < 0)
    			velocity.y = -2f;
    
    		if (Input.GetKeyDown(KeyCode.Space) && grounded) {
    			Jump(Mathf.Sqrt(2f * gravity * jumpPower));
    		}
    	}
    
    	private void FixedUpdate() {
    		Vector3 moveVector = transform.right * input.x + transform.forward * input.z;
    		controller.Move(moveVector * moveSpeed * Time.fixedDeltaTime);
    
    		velocity.y -= gravity * Time.fixedDeltaTime;
    		controller.Move(velocity * Time.fixedDeltaTime);
    	}
    
    	private void OnControllerColliderHit(ControllerColliderHit hit) {
    		// TODO collisions
    	}
    }

    Ответ написан
    1 комментарий
  • Как сделать чтобы камера не поворачивалась?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Камера переворачивается потому, что вы поместили её в иерархии внутрь персонажа.
    Решается это так: делаете объект камеры независимым по иерархии от игрока и делаете скрипт. который к текущим координатам игрока прибавляет начальные координаты камеры на момент старта. Таким образом она всегда будет на нужном месте относительно игрока.
    Ответ написан
  • Как сделать пределы для камеры?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если вы не поместите камеру внутрь персонажа по иерархии, то задача упрощается простой проверкой вхождения координат в некоторую область. Если область имеет неправильную геометрическую форму, то лучше воспользоваться другим ответом freeExec на этот вопрос. Если же у вас простой прямоугольник, можете сделать как-то так:
    using UnityEngine;
    
    public class CameraFollow2D : MonoBehaviour {
    
    	public Transform target;
    
    	public float minX, maxX;
    	public float minY, maxY;
    
    	private void LateUpdate() {
    		Vector3 nextPosition = transform.position;
    		nextPosition.x = Mathf.Clamp(target.position.x, minX, maxX);
    		nextPosition.y = Mathf.Clamp(target.position.y, minY, maxY);
    		transform.position = nextPosition;
    	}
    }
    Ответ написан
    Комментировать
  • Почему не отображаются буквы ошибок в консоли?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если это не нехватка физической/оперативной памяти или неправильная дата, то проблема должна решиться после обновления винды в центре обновлений и перезагрузки редактора.
    Ответ написан
    Комментировать