• Почему изображение не скачивается?

    @Ezekiel4 Автор вопроса
    Охотник на пиратов и сборщик монолитов
    Ответили в другом месте, суть в том, чтобы при попытках получения удалённого ресурса проверять статус запроса:
    public IEnumerator GetRemoteTexture(string url, Action<Texture2D> response) {
    	UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
    	yield return request.SendWebRequest();
    	if (request.result != UnityWebRequest.Result.Success){
    		response(null);
    	} else {
    		response(DownloadHandlerTexture.GetContent(request));
    	}
    }
    Ответ написан
    Комментировать
  • Как сделать бесскочнный звук с кнопками?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Как-то так:
    using UnityEngine;
    
    public class MusicDemo : MonoBehaviour {
    
    	public AudioSource audio; // в инспекторе сюда перетащите источник звука
    
    	public void OnPressed() { // привяжите к кнопке этот метод
    		if (audio.isPlaying) // если аудио играет
    			audio.Pause(); // поставить на паузу
    		else // иначе
    			audio.UnPause(); // снять с паузы
    	}
    }

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

    @Ezekiel4 Автор вопроса
    Охотник на пиратов и сборщик монолитов
    Мб кому пригодится, мне помогло решение:

    // ...
    using System.Collections.Concurrent;
    // ...
    private readonly ConcurrentQueue<Action> _Actions = new ConcurrentQueue<Action>();
    // ...
    // Когда вам нужно что-то запустить из другого потока, вызываете тут
    _Actions.Enqueue(() => {
    	// Ваш код
    });
    // ...
    private void Update() {
    	while (_Actions.Count > 0)
    		if (_Actions.TryDequeue(out var action))
    			action?.Invoke();
    // ...
    }
    Ответ написан
    Комментировать
  • Как настроить тригер?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Суть в том, что на цели должен быть проходимый коллайдер (включена галочка isTrigger), в таком случае у вас появляется доступ к событиям OnTriggerEnter2D, OnTriggerExit2D и OnTriggerStay2D, которые вызываются при вхождении, выходе и нахождении постороннего коллайдера внутри этого. Далее проверяете что именно вошло в коллайдер (например, по тегу, который есть только на игроке) и делаете SetActive(true) на кнопке.
    Как-то так:
    using UnityEngine;
    
    public class SimpleTrigger : MonoBehaviour {
    
    	public GameObject button;
    
    	private void OnTriggerEnter2D(Collider2D c) {
    		if (c.gameObject.tag == "Player")
    			button.SetActive(true);
    	}
    }
    Ответ написан
    Комментировать
  • Почему персонаж проваливается под террейн?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Персонаж проваливается потому, что нет коллизии между ним и рельефом. Возможные причины:
    1) Нет коллайдера на персонаже (или CharacterController-а) и/или на рельефе нет коллайдера;
    2) Один (или оба) из коллайдеров обозначен как проходимый (isTrigger=true);
    3) Вы пытались поставить игрока на землю на глаз и случайно "провалили" нижний кусочек коллайдера игрока сквозь границу рельефа;
    4) В настройках физики вы отключили коллизию между слоями игрока и рельефа (Edit > Project Settings, вкладка Physics, в самом низу будет схема с галочками);
    5) На персонаже висит Rigidbody, и вы даёте ему слишком большой имульс движения вниз, а в Collision Detection стоит не Continuous.
    Если ничего не помогло, заскриньте компоненты физики и движения в инспекторе персонажа и пришлите в ответ.
    Ответ написан
  • Unity Почему не обрабатываются нажатия?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Ввод не обрабатывается по одной из 4 причин:
    1) Отсутствует Event System;
    2) Требуемый компонент перекрывается иным компонентом или канвасом, у которого включено свойство Raycast Target;
    3) Ваш канвас типа World Space / Screen Space - Camera, но камера не указана;
    4) На объекте с Event Trigger отсутствует компонент, способный быть целью для взаимодействий с UI (галочка Raycast Target, например Image, который можно сделать прозрачным или Text, у которого можно удалить отображаемую надпись).
    Ответ написан
    Комментировать
  • Как проверить во что врезался рейкаст?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Переменная hit из вашего примера имеет тип RaycastHit (ссылочка на документацию), у которого есть свойство collider. Сам же метод Raycast возвращает логическое значение, определяющее, было ли касание в указанном направлении и расстоянии. Выглядеть это должно как-то так:
    if (Physics.Raycast(transform.position, _direction, out hit, 10f)) {
    	if (hit.collider == yourCollider) {
    		// some logic
    	}
    }

    Также это всегда можно совместить с TryGetComponent, если логика должна зависеть от определённого компонента, который может быть на цели (ссылочка). Как-то так:
    private MyComponent GetTarget() {
    	if (Physics.Raycast(transform.position, _direction, out hit, 10f))
    		if (hit.transform.TryGetComponent(out MyComponent m))
    			return m;
    	return null;
    }
    Ответ написан
    2 комментария
  • Как сделать перемещение пола с игроком на нем?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    В простейшем варианте должно быть что-то такое: когда игрок становится на платформу, мы делаем платформу его родительским объектом (свойство transform.parent), когда игрок спрыгивает с платформы, в transform.parent передаём null. Таким образом игрок будет двигаться сам по себе на платформе, будучи привязанным к ней до тех пор, пока не спрыгнет.

    Выглядеть это будет как-то так:
    using UnityEngine;
    
    public class PlatformMove : MonoBehaviour {
    
    	// movement
    
    	private void OnCollisionEnter2D(Collision2D c) {
    		if (c.gameObject.tag == "Player")
    			c.transform.parent = transform;
    	}
    
    	private void OnCollisionExit2D(Collision2D c) {
    		if (c.gameObject.tag == "Player")
    			c.transform.parent = null;
    	}
    }
    Ответ написан
    Комментировать
  • Как получить ответ из WebSocket?

    @Ezekiel4 Автор вопроса
    Охотник на пиратов и сборщик монолитов
    Итак, если у вас появилась аналогичная проблема и вы перепробовали всё возможное, проверьте, не должно ли в адресе сервиса быть "wss://...", а не "ws://..." В моём случае это помогло.
    Ответ написан
    Комментировать
  • Как реализовать комнату в unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Вам на сервере нужен пул (список объектов) комнат. Когда игрок будет создавать комнату, она добавится в список, когда будет искать, список будет перебираться. Когда игра начнётся, комната скроется, когда закончится - удалится из списка.
    Ответ написан
    Комментировать
  • Как в телеграме чат-боту узнать кто в группе?

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

    Тут есть проблема, ведь способ не отработает события входа тех, кто уже в чате. Можно решить, слушая события сообщений (отправка/редакт/удаление) и проверяя наличие данных пользователей в наборе.

    Напишите, если способ не сработает.
    Ответ написан
  • Как загрузить изображение из приложения на телефон?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Определитесь с форматом изображения для сохранения. Обычно используют формат *.png, но и для других есть готовые решения. В качестве папки для сохранения можете использовать persistentDataPath или выбрать что-то своё. По итогу получится:
    // imageTitle - имя файла, например, time stamp
    string pathToFile = Application.persistentDataPath + "/" + imageTitle + ".png";

    Далее выберите изображение, которое вам нужно, представив его как тип Texture2D (напишите, если вам нужно что-то другое). И используйте метод типа:
    using System.IO;
    
    // ...
    
    public bool SavePNG(Texture2D texture, string pathToFile) {
    	if (!File.Exists(pathToFile)) {
    		byte[] bytes = texture.EncodeToPNG();
    		File.WriteAllBytes(pathToFile, bytes);
    		return true;
    	}
    	return false;
    }

    Если же потом прямо из приложения нужно прочитать внешнюю картинку, то:
    public static Texture2D LoadPNG(string pathToFile) {
    	Texture2D texture = null;
    	if (File.Exists(pathToFile)) {
    		byte[] fileData = File.ReadAllBytes(pathToFile);
    		texture = new Texture2D(2, 2);
    		texture.LoadImage(fileData);
    	}
    	return texture;
    }
    Ответ написан
  • Как переместить курсор мыши по середине экрана?

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

    Способ 1
    В классе Cursor наличествует свойство lockState, определяющее поведение и видимость курсора. Сохранив в него значение CursorLockMode.Locked, вы переместите курсор в центр ОКНА ИГРЫ и скроете. Затем туда нужно сохранить значение Cursor.lockState = CursorLockMode.None, что разблокирует курсор и сделает видимым. Есть только одна проблема - эта операция работает не мгновенно, потому применить их последовательно не получится. Выглядеть код будет как-то так

    using UnityEngine;
    
    public class MouseCenteringExample : MonoBehaviour {
    
    	private void Start() {
    		Cursor.lockState = CursorLockMode.Locked;
    		Invoke("UnlockCursor", 0.05f);
    	}
    
    	private void UnlockCursor() => Cursor.lockState = CursorLockMode.None;	
    
    }


    Способ 2
    Если вы используете New Input System, то вам доступна опция InputState.Change, которую, в контексте вашей задачи, можно использовать так:

    using UnityEngine;
    
    public class MouseCenteringExample : MonoBehaviour {
    
    	private void Start() {
    		var center = Screen.safeArea.center;
    		Mouse.current.WarpCursorPosition(center);
    		InputState.Change(Mouse.current.position, center);
    	}
    
    }


    Способ 3
    Можно воспользоваться поддержкой нативных библиотек ОС. Правда, тут придётся подключить платформозависимую компиляцию. Например, для Windows:

    using System.Runtime.InteropServices;
    using UnityEngine;
    
    public class MouseCenteringExample : MonoBehaviour {
    
    #if UNITY_STANDALONE_WIN
    
    	[DllImport("user32.dll")]
    	static extern bool SetCursorPos(int X, int Y);
    
    	private void Start() {
    		var center = Screen.safeArea.center;
    		SetCursorPos((int)center.x, (int)center.y);
    	}
    
    #endif
    
    }
    Ответ написан
    2 комментария
  • Можно ли защитить Unity-игру от вскрытия ассетов через всякие assetRipper и тд?

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

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

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

    Если же вам нужна рекомендация, которая сделает ваши приложения безопасней - никогда не храните в PlayerPrefs чувствительные данные.
    Ответ написан
    1 комментарий
  • Из-за чего ошибка при сохранении в unity эффектов?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Вам нужно установить URP или UDRP. Для этого зайдите в Package Manager, выберите Unity Registry и один из вышеперечисленных.
    Если они у вас уже есть, перейдите в меню Edit/Project Settings, слева раздел Graphics. В самом верху будет поле "Scriptable Render Pipeline Settings". Там нужно указать ассет пайплайна, который вы используете.
    Ответ написан
  • Как использовать JWT в Unity?

    @Ezekiel4 Автор вопроса
    Охотник на пиратов и сборщик монолитов
    Задал тот же вопрос ещё в паре мест, посоветовали установить Postman и полазить по внутренностям сайта через F12.
    Как оказалось, токен надо отправить в заголовок, а перед самим токеном поставить "JWT ". Надеюсь, это кому-то поможет.
    Ответ написан
    Комментировать
  • Что не так с Input Field-TMP в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    TextMeshProUGUI и есть текст, это не поле ввода. Поле ввода - это TMP_InputField. Попробуйте:

    using TMPro;
    using UnityEditor;
    using UnityEngine;
    
    public class Calc : MonoBehaviour {
    
    	[SerializeField] private TMP_InputField m_inputField;
    	[SerializeField] private TextMeshProUGUI m_text;
    
    	public void OnCalculate() {
            ExpressionEvaluator.Evaluate(m_inputField.text, out int result);
            m_text.text = result.ToString();
    	}
    }
    Ответ написан
    1 комментарий
  • Как избежать зависания во время выполнения огромного цикла for?

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

    Если данные варианты вам не подходят и вы хотите обойтись прогрессбаром, то разбейте задачу на шаги, в вашем случае шаги итерации, и после завершения каждого добавляйте +1/к-во шагов к величине прогресса, просто вызывая это в конце блока цикла.
    Ответ написан
    Комментировать
  • С чего начать путь в gameDev с помощью Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Алгоритм изучения юнити примерно таков:
    1) Интерфейс - что где куда, минимум понимание смысла основных вкладок, которые вы видите со старта нового проекта;
    2) Манипулирование объектами на сцене - движение, вращение, масштабирование, покраска, скрытие, иерархия;
    3) Физика - минимум, коллайдеры, твёрдые тела и физические материалы;
    4) Освещение - какое бывает и как работает, тени;
    5) Звук - как проигрывать, как слушать, что с ним можно делать;
    6) Графический интерфейс - какие компоненты есть и зачем они нужны;
    7) Анимации - создание, воспроизведение, управление;
    8) Частицы - создание и правка.

    Учёба без практики не имеет смысла, но перечисленные выше инструменты вам в любом случае нужны будут. Весь остальной инструментарий ситуативен. Разбираться дальше реально лучше прямо в работе над очередным проектом.
    Если говорить в общем, то дальше можно просто открыть package manager (раздел unity registry) и тупо по порядку сверху вниз посмотреть какие есть стандартные дополнения + подсказки можно также в вакансиях на Unity Developer искать.

    Также вам будет очень полезна официальная документация:
    https://docs.unity3d.com/ScriptReference/
    Официальная документация по c#:
    https://docs.microsoft.com/en-us/dotnet/csharp/
    И полезный сайт по c# на русском:
    https://metanit.com/sharp/tutorial/
    Ответ написан
  • Как сделать физическое перемещение персонажа по локальным осям?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если хотите взаимодействовать в движении с коллайдерами, то про перемещения через transform можете забыть, используйте rigidbody или character controller, смотря что больше подходит.
    По поводу осей. Глобальные оси вызываются через Vector3, например Vector3.up - это вектор (0;1;0). В случае Vector2 всё тоже самое, только без z.
    Оси же самого объекта вызываются через его transform: та же ось вперёд - transform.forward в стандартном 3д или transform.up в стандартном 2д.

    Движение же будет выглядеть как-то так:
    // z is vertical axis (3d; y for 2d), x is horizontal axis
    rigidBody.velocity = transform.forward * z + transform.right * x;
    Ответ написан
    Комментировать