• Как в юнити оптимально отображать часто меняющийся текст?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Проблема 100% в коде, которого нет, поэтому я вдамся в гипотезы. Начну с самого хардкорного и закончу тем, что по лайтовее.

    1. Авторазмер
    Возможно, у вас есть скрипт, который при каждом изменении текста пытается отмасштабировать не шрифт, а границы самой компоненты. Проблема в том, что при любом изменении элементов интерфейса юнити перерисовывает вообще весь затронутый канвас. Речь не о свойствах типа цвет, а о перемещении и изменении границ.
    Если у вас такая проблема, то стоит оставить текст в покое и изначально сделать задел по размеру текста на будущее.
    Сюда же можно отнести перерисовку других элементов для ScrollView или использование UI Layouts.

    2. GetComponent
    Возможно, вы используете GetComponent. И делаете это довольно часто. Что-то типа такого:
    public void SetupText(string textToDisplay) {
    	GetComponent<TextMeshPro>().text = textToDisplay;
    }

    Парни с ютуба часто советуют такой треш. Под капотом этот метод довольно тяжёлый и будет тем тяжелее, чем больше компонент на объекте и чем больше раз за единицу времени вызывается.
    Если это ваша проблема, то рекомендую заранее кешировать. Например, сделать это на старте:
    private void Start() {
    	someTextComponent = GetComponent<TextMeshPro>();
    }

    А ещё лучше просто создать видимое инспектором поле и руками туда передать ссылку.
    [SerializeField] TextMeshPro someTextComponent;

    3. Частота вызова
    Ещё один треш, которому учат в интернете - менять что-то или проверять не тогда, когда это нужно, а просто в том же Update. Проблема здесь кроется в множестве "холостых" вызовов.
    Если у вас обновление текста происходит всегда, а не только при необходимости, то стоит подумать лучше над архитектурой.

    4. Размер текста
    Особенность компонент пакета TMPro ещё в том, что метод SetText или аксессор .text не только просто берёт и вставляет, а ещё проводит довольно большую работу под капотом. Если у вас большой текст, вы реально увидите просадку даже на компе, не говоря уже о мобилках. Такая проблема очень актуальна. Например, если вы скриптом или твинами делаете постепенно появляющийся большой объём текста для диалога в игре.
    Решением в данном случае будет либо анимация, либо написание своей реализации нужной компоненты.

    Если среди проблем вашей нет, приложите код. Желательно весь, но в контексте задачи интересна цепочка вызовов от события к присвоению текста.

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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Не знаю, поможет ли это в вашем случае, но вы можете попробовать:
    1. Внутри объекта по иерархии создаёте пустышку. вешаете ей коллайдер и твёрдое тело
    2. Твёрдому телу ставите Body Type = Kinematic (для 2д) или Is Kinematic = true (для 3д)
    3. Выставляете объект так, чтобы пуля ударилась сперва о его коллайдер.

    Как бонус, вы можете сделать несколько таких объектов (для рук, ног, головы, тела) и передавать скрипту игрока разные коэффициенты урона. Типа, например, попадание в руку 20%, а в голову 150%.
    Ответ написан
    Комментировать
  • Как правильно двигать объекты по нарисованным линиям?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Я не знаю, будет ли работать нормально сам код движения, но ваша проблема связана больше с логикой вызова кода движения. Сами посудите, сначала вызывается Update (каждый раз, когда обновляется экран), затем в нём вызывается метод Drive. Напоминаю, каждое обновление экрана, т.е. много раз в секунду.
    Сам же метод сходу берёт и обнуляет прогресс движения:
    targetPointIndex = 1;
    Всё, что ниже, уже просто не имеет смысла.

    Лично я рекомендую вам воспользоваться принципом SRP и делегировать функционал движения отдельному классу. Что-то типа такого:
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class LineRendererFollower : MonoBehaviour {
    
    	public LineRenderer lineRenderer;
    	public float speed;
    	public int nextPointIndex;
    
    	Vector3[] positions;
    
    	void Start() {
    		positions = new Vector3[lineRenderer.positionCount];
    		lineRenderer.GetPositions(positions);
    	}
    
    	void FixedUpdate() {
    		if (Vector3.Distance(transform.position, positions[nextPointIndex]) > 0) {
    			transform.position = Vector3.MoveTowards(transform.position, positions[nextPointIndex], speed * Time.fixedDeltaTime);
    		} else if (nextPointIndex + 1 < positions.Length) {
    			nextPointIndex++;
    			transform.right = (positions[nextPointIndex] - transform.position);
    		} else {
    			// то, что должно случится в конце пути
    		}
    	}
    }
    Ответ написан
    Комментировать
  • Как найти Image в Unity3D?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Учитывая, что
    .GetComponent<Image>();
    Может вернуть null без уведомлений, но не сработает, если объект найден не будет, у вас может быть одно из:
    а) Объект не найден вообще и ошибка на эту строку указывает;
    б) Не найден компонент;
    в) Компонент был удалён в промежутке между созданием объекта и вызовом метода столкновения.

    Рекомендую вам взять на вооружение замечательную функцию вкладки Inspector: режим Debug.
    Пример, компонент Image

    64177f43a8eb0086475123.png


    Сперва проверьте, получается ли полем crosshairImage ссылка на Image. Затем удостоверьтесь, что она остаётся на месте до и в момент столкновения. Если она не находится, то одно из двух:
    а) у вас есть несколько объектов с указанным тегом и первым находится объект без Image
    б) она создаётся после попытки её найти, пример: другой класс в Start её создаёт, но этот старт вызывается раньше. В настройках проекта это можно исправить (порядок выполнения скриптов).

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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Для начала, наведайтесь в меню "Edit / Project Settings... / Quality". И установите значение Anti Aliasing на Disabled. Оно бывает иногда нужно в 2д играх, но в вашей сейчас точно будет только мешать. Затем нужно создать спрайт атлас.
    Во вкладке Project создайте новый файл, в меню создания выберите "2D / Sprite Atlas". Затем выделите его, чтобы видеть его свойства в инспекторе. Внизу будет список, подписанный как Objects for Packing. Перетащите туда не отдельные картинки, а весь импортированный файл.
    В редакторе линии могут остаться, но при запуске и в билде их точно не должно быть.
    Если не сработало или не понятно объяснил - пишите в комменты.
    Ответ написан
  • Как войти в Unity Hub?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Процесс следующий. Unity Hub отправляет браузеру по умолчанию запрос, тот заходит на сайте в аккаунт и возвращает из браузера в хаб обратно ответ.
    Если не открылся браузер - у вас слишком суровные настройки антивируса или брандмауэра, а может браузера вообще нет/не настроен (но как вы бы тогда хаб скачали?). Если открылся, но хаб не отреагировал, возможно, хаб не до конца инициализирован. Такое бывает в Windows с процессами время от времени. Зайдите в диспетчер задач и уберите тупо все процессы, связанные с Unity, после чего перезапустите и попробуйте снова.
    Если не помогло, пишите в комменты версию Unity Hub, название браузера и название+версия ОС, подумаем ещё.
    Ответ написан
    3 комментария
  • Как реализовать движение по диагональной лестнице 2d?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    1) Почему нахождение на лестнице не вызывает остановку анимации падения?
    Вангую на персонаже висит скругленный коллайдер - это от него. Прикол в том, что даже если вам кажется, что персонаж не движется, в Rigidbody2D со скруглённым коллайдером при условии, что вы стоите скруглённой частью на острие или другом круге, то постоянно возникает небольшое ускорение вниз, которое фейлит ваше условие:
    if (rb.velocity.y < 0f && !onGround)
    {
    	animator.SetBool("isFall", true);
    }
    
    if (rb.velocity.y == 0) // вот это вот условие
    {
    	animator.SetBool("isFall", false);
    }

    По идее, должно хватить условия "onGround":
    animator.SetBool("isFall", !onGround);

    2) Почему прыжок с лестницы выше, чем с земли?
    Высота разная, потому что вы применяете к персонажу именно силу, ведь она напрямую учитывается в пересчётах. Более того, высота может быть другой, если вы будете прыгать ещё от углов, стоя на месте или скользя вниз или вверх.
    Есть много решений, вот два рандомных:
    1. Обнулить вертикальную часть вектора velocity перед применением силы:
    void Jump() {
    	if (Input.GetKeyDown(KeyCode.Space) && onGround && !jumpLock) {
    		rb.velocity = new Vector2(rb.velocity.x, 0);
    		rb.AddForce(new Vector2(0f, jumpForce));
    	}
    }

    2. Вообще заменить силу на мгновенное изменение скорости:
    void Jump() {
    	if (Input.GetKeyDown(KeyCode.Space) && onGround && !jumpLock) {
    		rb.velocity = new Vector2(rb.velocity.x, jumpForce);
    	}
    }


    3) Почему персонаж скатывается с угла?
    Потому что стоит скругленной частью на угле. Замените коллайдер. Можете взять квадрат и слегка скруглить края, чтобы при горизонтальном движении не ударялся о стыки текстур (если такая проблема у вас вдруг вообще возникнет).
    Типа такого
    641258084edd0441102905.png
    Ответ написан
  • При нажатии на UI.Button сделать так, чтобы была возможность управления камерой, кто знает???

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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Трясётся потому, что у вас камера внутри иерархии игрока и она считайте дважды пересчитывается, сначала иерархией, потом скриптом. Попробуйте сделать так - создайте пустую точку на месте, где должна была бы крепиться камера и сделайте в LateUpdate привязку координат камер к этому якорю. А поворот через вектор transform.forward.
    Ответ написан
  • Почему у персонажа в Unity при столкновении с врагом не отнимается последняя жизнь?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    На курсах обычно дают один из двух вариантов:

    1) Из текущего здоровья отнимают дельту и затем проверяют, не упало ли здоровье в условие:
    public int healthCurrent;
    
    public void OnHealthChanged(int healthDelta)
    	healthCurrent -= healthDelta;
    	// update health bar
    	if (healthCurrent <= 0) {
    		// death
    	}
    }

    В этом варианте у вас может быть ошибка в условии. Например в примере ниже реально можно попасть в ситуацию, когда персонаж стал бессмертным:
    public int healthCurrent;
    
    public void OnHealthChanged(int healthDelta)
    	if (healthCurrent > 0) {
    		healthCurrent -= healthDelta;
    		// update health bar
    		if (healthCurrent < 0) {
    			// death
    		}
    	}
    }

    2) Через Mathf.Clamp:
    public int healthCurrent;
    public int healthMaximum;
    
    public void OnHealthChanged(int healthDelta)
    	healthCurrent = Mathf.Clamp(healthCurrent - healthDelta, 0, healthMaximum);
    	// update health bar
    	if (healthCurrent == 0) {
    		// death
    	}
    }


    В этом варианте помимо неправильного условия также можно случайно ошибиться в аргументах функции Clamp и вместо 0 указать 1, а проверять будет именно 0.
    Ответ написан
  • Как сделать, чтобы при запуске игры не было видно курсор?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Сам Unity не убирает курсор, а просто его прячет. Если вы резко двинете мышью, то можете заметить, как выделяются элементы под курсором за пределами окна сцены и Unity вообще. А если вы будете транслировать экран через Zoom или Google Meet, то заметите, что курсор на трансляции виден.

    Эту проблему можно решить, написав дополнительное расширение редактора, но обычно с этим не парятся, так как в игре всё работает как часы. Будет это работать примерно следующим образом:
    1) Используя EditorApplication.playModeStateChanged вы можете отследить момент входа в PlayMode
    2) Используя Cursor вы можете узнать координаты курсора, а затем скрыть указатель и залочить его позицию
    А при выходе из PlayMode показать и разблокировать. Чтобы разделить функционал можно использовать платформо-зависимую компиляцию, типа:
    public void HideCursor() {
    
    #if UNITY_EDITOR
    
    	// hide & lock using Cursor class
    
    #else
    
    	Cursor.lockState = CursorLockMode.Locked;
    
    #endif
    
    }
    Ответ написан
    Комментировать
  • Как отзеркалить 2D персонажа?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Обычно для этого достаточно развернуть рут объект игрока по oY. Типа такого:
    public class PlayerController : MonoBehaviour {
    
    	// ...
    
    	private void Update() {
    		float xInput = Input.GetAxisRaw("Horizontal");
    
    		if (xInput != 0)
    			transform.localEulerAngles = new Vector3(0, xInput > 0 ? 0 : 180, 0);
    
    		// ...
    	}
    
    	// ...
    
    }


    PS. С этим у вас может возникнуть новая проблема - если вы следите камерой за игроком, вложив её по иерархии, тогда камеру тоже развернёт и визуально ничего не поменяется. Если у вас такое будет - вынесите её из иерархии игрока и напишите скрипт, который будет синхронизировать oX/oY координаты игрока с камерой.
    Ответ написан
    Комментировать
  • Как заставить так чтобы камера двигалась сама в UNITY при параллакс эффекте?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Вам так или иначе нужно какое-то событие, например, "игрок сместился" или "прошёл один кадр" или что-то ещё. Если у вас игра типа террарии, где параллакс опирается на движение игрока, то вместо слушания клавиш можете сделать как-то так:
    1) Запоминаем где игрок
    2) Смотрим, насколько далеко он сместился от этой точки
    3) Смещаем слои фона на эквивалентные величины

    Если же эффект автоматический, как в раннерах, то всё ещё проще:
    1) Отсчитываем паузу (таймер, обновление экрана или что-то ещё)
    2) Смещаем слои фона на величины их скорости движения
    Ответ написан
    Комментировать
  • Почему соотношение сторон в юнити неправильное после билда игры?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    В канвасе есть компонент Canvas Scaler. Настройте его следующим образом:
    6405e02a8224d397628725.png
    Ответ написан
    1 комментарий
  • Почему низкий фпс при большом количестве CharacterController?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Почему - потому что много объектов. В юнити потребление ресурсов никогда не росло линейно к количеству объектов. Одно накладывается на другое. Столь большое количество активных объектов нестандартная ситуация, потому тут нет шаблонного эффективного решения. На ум приходит попытаться оптимизировать код или написать свой контроллер, но при таких числах оно вам даст едва ли 20 фпс.

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

    Другой вопрос, а будет ли в игре реально тысяча объектов? Это такой стресс-тест? Или это усреднённое значение и реально их может быть и полторы? Я это к тому, что если тысяча не предел, то, возможно, придётся писать что-то ещё более сложное, чем система выше.
    Ответ написан
    2 комментария
  • Как сделать Хватание предметов как в People Playground на Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Есть как минимум два способа это сделать - через иерархию и через суставы. Вы даже без кода можете попробовать руками дать персонажу вещь, сделав её дочерней к ладони и покрутить рукой. Фокус в том, что дочерние объекты повторяют все модификации местоположения и поворота родительского. Нечто похожее делают и суставы, но плюс суставов в том, что их можно разбить, т.е. как бы выбить вещь из руки при достаточном внешнем усилии (отстрелить нож из руки в шутере, например).
    Можно ещё тупо поместить все возможные вещи в руки прямо со старта, в редакторе, а затем их просто выключить и включать как объекты при необходимости, но, надеюсь, вы так делать не будете, потому что это кринж, что бы парни с ютуба вам об этом не говорили.

    Среди первых видосов на ютубе по вашему запросу вот два примера:
    1) Как можно сделать: https://www.youtube.com/watch?v=pzaxC-P3sgs
    2) Как делать не нужно: https://www.youtube.com/watch?v=zEfahR66Pa8

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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Сначала удостоверьтесь, что браузер по-умолчанию имеет активную сессию на сайте юнити. Затем через диспетчер задач остановите все процессы, которые хоть как-то связаны с Unity. Перезапустите хаб и попробуйте ещё раз нажать кнопку входа и подождите пару секунд. Если всё равно глухо, проверьте настройки брандмауэра и антивируса. Они умеют блокировать такие действия. Глухо всё равно - пишите в коменты, подумаем ещё.
    Ответ написан
    Комментировать
  • Хватит ли моего компьютера для разработки игр?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Требования различаются от версии к версии, также зависят от разрабатываемого проекта и уровня его оптимизации. У меня есть ноут 2011 года, там видеокарта интегрированная в проц, сам проц i5 3 поколения (2 ядра, 4 потока), озу 6 гб. На версии 2020* ноута с головой хватает на разработку гиперказуалок, 2д платформеров, шутеров и песочниц. 3д тянет не очень. На этом же ноуте чистая версия 2021 лагает даже до начала разработки проекта.

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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Ну тут есть два варианта - либо вы удаляете компоненту AudioListener с камеры всех, кто удовлетворяет условию:
    using Photon.Pun;
    using UnityEngine;
    
    public class FixAudioListener : MonoBehaviour {
    
    	// заполнить ссылки в инспекторе до старта игры
    	public AudioListener listener;
    	public PhotonView photonView;
    
    	private void Start() {
    		if (!photonView.IsMine)
    			Destroy(listener); // удалить компоненту с камеры
    	}
    }


    Или вы руками его удаляете до старта игры, а на старте помещаете на камеру игрока:
    using Photon.Pun;
    using UnityEngine;
    
    public class FixAudioListener : MonoBehaviour {
    
    	// заполнить ссылку в инспекторе до старта игры
    	public PhotonView photonView;
    
    	private void Start() {
    		if (photonView.IsMine)
    			AddComponent<AudioListener>(); // добавить компоненту на камеру
    	}
    }


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

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    В AudioSource есть свойство Spatial Blend, которое определяет пространственное распространение.
    Крайнее левое положение - это чистый 2D звук. Такой звук играет одинаково по всей сцене. Идеально для фоновой музыки в играх и интерфейса.
    Крайнее правое, в свою очередь, чистый 3D звук, дальность распространения которого вы и определили.
    Промежуточные состояния, это нечто среднее (зависит от зелёной полосы на графике в разделе 3D Sound Settings).

    Вам нужно поставить в крайнее правое положение.
    63f268e6e4ebe824615264.png
    Ответ написан
    Комментировать