• Ошибка с поворотом камеры в скрипте?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Занятный способ использовать агента. Обычно для движения используют Transform, Rigidbody, CharacterController или WheelCollider. Не видя проекта могу лишь сказать, что вы поместили камеру по иерархии внутрь игрока. И когда игрок поворачивается, камера поворачивается вместе с ним. Обычно для управления камерой пишут отдельный скрипт, что я вам и советую сделать.
    Ответ написан
    Комментировать
  • Как разделить 3D модель на конечности?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Вроде были дополнения для работы с мешами в юнити, но они $15++ стоят, и имеют функционал далёкий от того же бесплатного блендера, который предлагаю вам использовать. Также в блендере легче и приятнее анимировать модели, ведь можно управлять такими вещами, как веса костей, чтобы, например, при подъёме задней ноги не деформировалась геометрия крупа или хвоста.
    Ответ написан
    3 комментария
  • Как сохранить положение слайдера после перезагрузки игры UNITY?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    При запуске сцены загрузите значение из базы в слайдер.
    Ответ написан
    Комментировать
  • Как сделать проверку на землю под ногами(Unity 2d)?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Способов проверить наличие земли много, вопрос в конкретной игре. Самый простой - проверить столкновение коллайдеров.
    иллюстрация1
    63d2302016761335903485.png

    Стандартные скрипты сверху имеют сигнатуру вида
    public class [название] : MonoBehaviour.
    MonoBehaviour - это специальный скрипт, дающий возможность нашему использовать некоторые стандартные методы, например:
    void OnCollisionEnter2D(Collision2D c) {
    	Debug.Log(c.gameObject.name); // выводит в консоль название объекта, с которым владелец скрипта столкнулся
    }

    Минус подхода в том, что ваш объект будет считать столкновениями в том числе и удары головой о потолок, что не очень сходится с задачей. В таком случае поступают иначе - создают в иерархии персонажа пустую точку, затем вокруг неё в коде ищут определённые поверхности. Выглядит обычно как-то так или так:
    иллюстрация2
    63d231f8302fc690248078.png

    Код же будет выглядеть как-то так:
    код
    // поля класса
    public Transform groundCheckPoint;
    public float range;
    public LayerMask groundLayers;
    
    // сама инструкция
    bool isGrounded = Physics2D.OverlapCircle(groundCheckPoint.position, range, groundLayers);
    
    // в вашем коде имеет смысл как-то так сделать
    void Jump() {
    	if(Physics2D.OverlapCircle(groundCheckPoint.position, range, groundLayers))
    		rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
    }


    Пара непрошенных советов для начинающему коллеге по цеху

    Инструкции вида
    [SerializeField] public float speed = 10f;
    [SerializeField] public float jumpForce = 14f;

    Не имеют смысла, так как оператор доступности public и так делает вашу переменную видимой в инспекторе, поэтому использование атрибута избыточно. Хуже не делает, просто бессмысленно. Атрибуты больше нужны, чтобы задать специфическое поведение для удобства редактирования игры. Например, вы не хотите давать другим классам прямой доступ к изменению скорости бега и силы прыжка персонажа - ставите приват, но чтобы в редакторе можно было потестить и выставить нужные значения (вы же не экстрасенс, чтобы с первого раза угадать), добавляют атрибут и получается:
    [SerializeField] private float speed = 10f;
    [SerializeField] private float jumpForce = 14f;


    Второе уже относится больше к здравому смыслу - все запросы ввода лучше делать внутри Update, а обеспечением их доступности для метода FixedUpdate должна заниматься внутренняя переменная класса, типа:
    private float xInput;
    
    private void Update() {
    	xInput = Input.GetAxis("Horizontal");
    	// code
    }
    
    private void FixedUpdate() {
    	rb.velocity = new Vector2(xInput * speed, rb.velocity.y);
    }

    Ответ написан
    Комментировать
  • Не логинится в юнити хаб вообще, даже ничего не открывается, просто не реагирует, что делать?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Чтобы решить проблему, нужно понимать, как именно юнити делает авторизацию.

    Unity Hub посылает в браузер запрос, дальше браузер его обрабатывает, как если вы бы через браузер входили, но вместо демонстрации интерфейса успешного входа, он посылает ответ обратно в хаб.

    Так как у вас при нажатии на кнопку не открывается браузер, значит что-то блокирует этот запрос. Это может быть как антивирус, так и фаерволл вашей ОС. Бывает ещё такое, что сам хаб не посылает запрос вообще, тогда надо его полностью выключить через диспетчер задач - остановить все процессы/снять все задачи, в названии которых как-то упоминается Unity, а затем перезайти и попробовать ещё раз.

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

    @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
    Охотник на пиратов и сборщик монолитов
    На 10 винде он и не работает, а ещё на 8-ке и на exFAT дисках. Попробуйте AOMEI Partition Assistant Professional. Там в списке дисков ПКМ на нужном, субменю Advanced/Change Serial Number, вводите, ОК и слева сверху галочка Apply. Минус в том, что программа платная. Есть Freeware версия, но хз есть ли там нужное.
    Ответ написан
    Комментировать
  • Как лучше/правильнее реализовать архитектуру проекта игры в юнити?

    @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 комментарий