Jump to content

Константин Орлов

Administrators
  • Content Count

    1177
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by Константин Орлов

  1. Константин Орлов

    Unity динамически сменить день на ночь

    Unity динамически сменить день на ночь! Мощный пак Unity3d для смены суток с большим количеством настроек. Динамическая смена дня и ночи позволяет видеть закаты и рассветы, появляются звезды. Небесные тела и объекты движутся согласно реальному поведению - облака плывут по небу по ветру, Солнце и Луна двигаются, как должны, звезды также вращаются по небосклону. Можно задать продолжительность суток, изменение освещенности со временем. Включить и выключить Солнце или Луну. Unity-пак для динамической смены дня и ночи. Особенности: дневное небо плавно сменяется на ночное расчет продолжительности дня, положения солнца и луны в зависимости от часа, дня и года движущиеся облака, звезды, Луна и Солнце настройки всего и вся осадки и атмосферные явления (вроде, я не тестил пока) вы можете сохранить и загрузить настройки через файл .xml Скачать пак Time of Day - Dynamic Sky Dome v3.0.0: https://yadi.sk/d/rcGt4Tkb3Y69ph или зеркало. Сокращенный перевод официальной инструкции с моими дополнениями: Time of Day - Dynamic Sky Dome v3.0.0 Unity3d-пакет для визуализации реалистичных динамических куполов неба с дневным и ночным циклом, реалистичными объектами на небе, динамическими (движущимися) облаками и атмосферным рассеянием. Какие-то понты: Как установить динамическую смену дня и ночи в unity3d Сделайте бекап вашего проекта на всякий случай. Распакуйте ассет-пак в ваш проект Unity, при запросе API Update Required нажмите "I Made a Backup, Go Ahead!". Отключите свой Directional light в иерархии, уберите skybox из вкладки Windows>Lightning>Settings>Scene>Skybox Material (выберите none). Перетащите prefab "Time of Day/Prefabs/Sky Dome" в сцену. Выставите масштаб и позицию префаба так, чтобы он охватывал всю сцену (т.е. поместите сцену в шар-неба). Добавьте скрипт Time of Day Camera в свою основную камеру (Add Component - > Time of Day - > Camera Main Script) По желанию добавьте любой из дополнительных скриптов к основной камере (Add Component - > Time of Day - > ). Можно включить или отключить любые дочерние объекты на сцене в префабе Sky dome (там солнце, луна, облака и прочее) В родительском объекте Sky Dome на сцене куча настроек, теребонькайте их, пока не получите нужный результат!
  2. Константин Орлов

    Unity динамически сменить день на ночь

    Unity3d настройка Дня и Ночи через UI Скачать префаб ассет AdminTV для настроек погоды через UI https://yadi.sk/d/7ApOu1Ea3Y9ReK Этот ассет работает вместе с Time of Day - Dynamic Sky Dome v3.0.0, он позволяет настраивать параметры погоды через монитор, находящийся на игровой сцене. Для установки необходимо вытащить на сцену префаб AdminTV, в его переменных указать ссылки на Sky Dome, и некоторые его внутренние объекты в иерархии. Превью скрипта (но одного скрипта мало, в префабе куча кнопочек и слайдеров):
  3. Константин Орлов

    Photoshop 2017 (взломанный, русифицированный)

    Еще одна версия фотошопа http://gig-torrent.com/load/soft/adobe_photoshop_cc_2017_18_0_2016_pc/7-1-0-20039 Также можете воспользоваться этой Adobe Photoshop CC 2018 http://n-torrents.ru/load/programms/grafika/adobe_photoshop_cc_2018_v19_0_x86_x64_plugins_2017_pc_russkij_portable_by_punsh/38-1-0-62841 (уже вылечена, достаточно просто распаковать, русифицирована).
  4. Константин Орлов

    Unity смена дня и ночи скриптом

    Для смены дня и ночи в Unity3d через скрипт сменим текстуру неба, силу и цвет окружающего освещения (ambient), уберем солнце, зададим настройки тумана. Несколько ночных скайбоксов Night Skyboxes Pack 2.unitypackage https://yadi.sk/d/Ds8DWMmK3XwSiD пак качественных скайбоксов под разные времена суток Skyboxes MegaPack 1.unitypackage https://yadi.sk/d/x7n1t3Kw3XwTKU Создайте файл с названием DayNightChange.cs, и скопируйте в него: using System.Collections; using System.Collections.Generic; using UnityEngine; public class DayNightChange : MonoBehaviour { // скрипт для сменя дня и ночи. Запоминает ваши настройки неба и освещения, и меняет их на ночные // после чего вы можете опять вызывать его функцию смены, чтобы он восстановил прежние настройки // не забудьте установить на камере "Clear Flags - Skybox" // переменные для запоминания изначальных настроек в методе Start Material oldSkyBox; // настройки текстуры неба Color oldAmbientColor; // цвет и яркость окружающего освещения float oldSunSize; // размер солнца или как-то так Color oldFogColor; // яркость и цвет тумана float oldFogDensity; // плотность тумана bool oldFogEnabled; // включен ли туман Color oldDirLightValue; // основное освещение [Header("Задайте новые настройки")] [Tooltip("Задайте текстуру скайбокса")] public Material newSkyBox; // материал скайбокса (картинка неба) [Tooltip("Цвет окружающего освещения")] public Color newAmbientColor; // окружающее освещение https://unity3d.com/ru/learn/tutorials/topics/graphics/ambient-lighting [Tooltip("Цвет тумана")] public Color newFogColor; // цвет тумана [Tooltip("Плотность тумана")] [Range(0, 1)] public float newFogDensity; // плотность тумана [Tooltip("Размер солнца или что-то вроде того")] public float newSunSize; // размер солнца [Tooltip("Включен ли туман?")] public bool newFogEnabled; [Tooltip("Перетащите сюда основное освещение")] public Light directionLight; // Direction Light, чтобы менять ему силу освещения [Tooltip("Яркость нового основного освещения (Direction Light)")] public Color newDirLightValue; void Start() { // сначала запоминаем изначальные настройки oldSkyBox = RenderSettings.skybox; // настройки текстуры неба oldAmbientColor = RenderSettings.ambientLight; // цвет и яркость окружающего освещения oldSunSize = RenderSettings.flareStrength; // размер солнца или как-то так oldFogColor = RenderSettings.fogColor; // яркость и цвет тумана oldFogDensity = RenderSettings.fogDensity; // плотность тумана oldFogEnabled = RenderSettings.fog; // включен ли туман oldDirLightValue = directionLight.color; // основное освещение } void Update() { } bool isNewSetting = false; // показывает, включены новые настройки или старые public void ChangeDayNight() { if (isNewSetting == false) // если новые настройки не включены { Debug.Log("DayNightChange: Настройки из инспектора включены"); // то активируем настройки из инспектора RenderSettings.skybox = newSkyBox; // настройки текстуры неба RenderSettings.ambientLight = newAmbientColor; // цвет и яркость окружающего освещения RenderSettings.flareStrength = newSunSize; // размер солнца или как-то так RenderSettings.fogColor = newFogColor; // яркость и цвет тумана RenderSettings.fogDensity = newFogDensity; // плотность тумана RenderSettings.fog = newFogEnabled; // включен ли туман directionLight.color = newDirLightValue; // яркость основного освещения isNewSetting = true; // переключатель в "новые настройки включены" } else // если новые настройки уже активны { Debug.Log("DayNightChange: Настройки изначальные включены"); // то устанавливаем старые настройки RenderSettings.skybox = oldSkyBox; // настройки текстуры неба RenderSettings.ambientLight = oldAmbientColor; // цвет и яркость окружающего освещения RenderSettings.flareStrength = oldSunSize; // размер солнца или как-то так RenderSettings.fogColor = oldFogColor; // яркость и цвет тумана RenderSettings.fogDensity = oldFogDensity; // плотность тумана RenderSettings.fog = oldFogEnabled; // включен ли туман directionLight.color = oldDirLightValue; // яркость основного освещения isNewSetting = false; // переключатель в "новые настройки включены" } } }
  5. Unity Как разбить лампочку - сделаем разбивающуюся лампочку, которая проигрывает случайный вариант звука поломки. Не забудьте переименовать скрипт в Lamp.cs using System.Collections; using System.Collections.Generic; using UnityEngine; // скрипт отвечает за разбитие лампочки public class Lamp : MonoBehaviour { // Ссылка на видеоурок по пользованию скриптом http://q32.pw/bpUZ // Скачать демосцену Lamp.unitypackage http://q32.pw/bpVa // игровые объекты, которые мы будем включать (выключать) при разбитии лампочки [Header("ГО для вкл/выкл при разбитии")] [Tooltip("Источник света для отключения при разбитии")] public GameObject lightLampGO; // источник света [Tooltip("Искры для включения при разбитии")] public GameObject sparksGO; // партикл искры [Tooltip("Звук искр")] public GameObject soundSparkingGO; // звук искрения [Tooltip("Звук разбивающейся лампочки")] public GameObject soundLampCrashGO; // звук бьющейся лампочки [Tooltip("Звук упавшего на землю стекла (установите источник звука (GameObject) на уровне пола")] public GameObject soundLampFallingGO; // звук упавшего на землю стекла // вышеописанные объекты будут иметь звуковой файл в AudioSource по умолчанию, если хотим // сделать несколько вариантов одного звука, проигрываемого рандомно, то используем массивы: [Header("Массивы с вариациями звука")] [Tooltip("Звук падающего стекла (несколько вариантов)")] public AudioClip[] soundLampFallingArray; [Tooltip("Звук искрения (несколько вариантов)")] public AudioClip[] soundSparkingArray; // массивы в инспекторе можно не задавать вообще, тогда будут проигрываться одни и те же // звуки по умолчанию без рандома private bool lampIsAlive = true; // информирует, цела ли лампа void Start() { // проверяем подключены ли переменные GameObject'ов в инспекторе if (lightLampGO == null) Debug.LogAssertion("Потерян объект - источник света"); if (sparksGO == null) Debug.LogAssertion("Потерян объект - партикл искры"); if (soundSparkingGO == null) Debug.LogAssertion("Потерян объект - звук искрения"); if (soundLampCrashGO == null) Debug.LogAssertion("Потерян объект - звук бьющейся лампочки"); if (soundLampFallingGO == null) Debug.LogAssertion("Потерян объект - звук упавшего на землю стекла"); // проверяем есть ли звуки "по-умолчанию" в объектах со звуками if (soundSparkingGO.GetComponent<AudioSource>().clip == null) Debug.LogAssertion("Установите в компоненте AudioSource у soundSparking аудиофайл"); if (soundLampCrashGO.GetComponent<AudioSource>().clip == null) Debug.LogAssertion("Установите в компоненте AudioSource у soundLampCrash аудиофайл"); if (soundLampFallingGO.GetComponent<AudioSource>().clip == null) Debug.LogAssertion("Установите в компоненте AudioSource у soundLampFalling аудиофайл"); // проверка, не удалили ли коллайдер if (GetComponent<Collider>() == null) Debug.LogAssertion("Не обнаружен компонент коллайдер"); // проверка есть ли на коллайдере галочка "триггер" if (GetComponent<Collider>().isTrigger == false) Debug.LogAssertion("В коллайдере не стоит галочка isTrigger, мы не сможем обработать OnTriggerEnter (лампочка не разобьется)"); } // когда какой-либо предмет попадает в лампочку private void OnTriggerEnter(Collider other) { if (lampIsAlive == true) // если лампа цела, то разбиваем ее, если уже разбита, то ничего не делаем { lampIsAlive = false; // помечаем, как разбитую lightLampGO.SetActive(false); // выкл свет sparksGO.SetActive(true); // вкл искры soundLampCrashGO.SetActive(true); // вкл звук бьющейся лампочки // выбираем из массива случайным образом звук искрения и проигрываем его PlayRandomSound(soundSparkingArray, soundSparkingGO); Invoke("LampFallingDelay", 0.5f); // задержка перед проигрыванием звука упавшего стекла } } // звук упавшего стекла void LampFallingDelay() { // выбираем из массива случайным образом звук падающего стекла и проигрываем его PlayRandomSound(soundLampFallingArray, soundLampFallingGO); } // Проигрываем случайный звук из массива void PlayRandomSound(AudioClip[] arraySound, GameObject audioSourceGO) // принимаем массив звуков и объект, откуда прозвучит { if (arraySound.Length > 0) // если массив имеет элементы в инспекторе (пусть и пустые) { // выбираем случайный элемент-аудиофайл звука из массива AudioClip randomSoundFromArray = arraySound[Random.Range(0, arraySound.Length)]; if (randomSoundFromArray != null) // если аудиофайл не null { // присваиваем источнику звука новый аудиофайл audioSourceGO.GetComponent<AudioSource>().clip = randomSoundFromArray; //Debug.Log(gameObject.name + " - звук из массива успешно проигран: " + audioSourceGO.GetComponent<AudioSource>().clip); } else Debug.LogWarning("в массиве звуков в инспекторе есть пустые поля - (None (Audio Clip)), " + "мы не можем проиграть пустое поле, поэтому проигран звук по умолчанию в самом Audio Source. " + "Возможно, вы не заполнили массив звуков, либо удалили файлы с диска."); } else Debug.Log(arraySound + "В массиве нет ни одного элемента звуков для рандома, проигрывается звук по умолчанию из самого GameObject"); audioSourceGO.SetActive(true); // вкл объект со звуком (проигрывание звука) } } // Советы - следите чтобы источник звука упавшего стекла был на уровне пола // Звуки должны быть настроены к проигрыванию по Awake, партикл искр тоже + партикл должен сам удаляться или отключаться (т.е. не быть Loop)
  6. Константин Орлов

    Как надо делать видеоуроки по Юнити

    После 2 месяцев изучения Unity по видеоурокам на Ютубе, и просмотра более сотни роликов я вывел общие правила: Здороваться нужно либо "всем привет", либо "здравствуйте, дорогие друзья". "Всем привет" - обязательно надо говорить, чтобы часть зрителей не подумала, что "привет" только избранным. Ведь часто так и бывает, в видео говорят "Привет только дяде Васе и тете Феде", и остальные остаются без привета. "Здравствуйте, дорогие друзья" - еще одна традиция. Открывая видеоурок, будьте уверены с 50% вероятностью ваш ждет либо всемпривет, либо здравствуйтедорогиедрузья. Всем очень интересно, как ты печатаешь, поэтому не вырезай эти моменты. Нельзя сначала написать, а потом объяснить, что написано, ведь урок станет раза в 2 короче, и тебе достанется в 2 раза меньше внимания. Для такого красавца это несправедливо. Ускорять видео во время печатания тоже не стоит, у всех зрителей по умолчанию времени вагон и им интересно, как буковки по одной появляются на экране. Даешь своеобразный "прямой эфир"! Затупы вырезать тоже не стоит, всем очень интересно, как ты сначала ошибся, а потом сделал правильно. Настоящие урокеры никогда не выкладывают ссылки на скрипты, все их зрители должны руками набирать смотря на экран. При этом по традиции в комментах появляется одаренный, который на вопли толпы "где ссылка на скрипт" расскажет, что они нубы и не понимают жизнь, ведь набирать надо ручками. Причем именно ручками, а не руками. Если все-таки выкладываешь скрипт, то делать это надо в своей группе вконтакте. И на многочисленные комменты "где скрипт" каждый раз отвечать "в группе ВК". После чего тебя обязательно спросят, где ссылка на группу? Ссылку на саму группу в описании под видео тоже давать не надо, надо написать "смотрите в описании канала". Обязательно надо причмокивать во время урока, хотя бы 2-3 раза за видео. Ведь твой урок так вкусен. Английские слова надо произносить либо совсем неправильно, например, obj (сокращение от object) надо так и называть ОБэЖэ, как школьный предмет. Либо во всю косить под англичанина, неправильно имитируя акцент, чтобы все поняли, что ты не абы кто. Если все-таки решил выкладывать скрипты, то делай их без комментариев. Надо делать только те уроки, которые уже есть на Ютубе. Например, уже штук 10 кривых нубо-реализаций убогого инвентаря? Сделай 11-ю кривую реализацию, такую же убогую и забагованную. Чем больше УГ, тем лучше. Ни в коем случае не делай урок с грамотно оптимизированным и реализованным кодом. Кому вообще такой бред нужен? Этому никто не хочет научиться. В начале видео обязательно скажи о чем видео - ведь зритель нажав на видео с названием "Как сделать инвентарь на Unity" не знает о чем видео. Поэтому используй формулировку "Всем привет (здравствуйте дорогие друзья), сегодня мы будем делать инветарь на Unity". Слово "сегодня" использовать обязательно, даже если у тебя выход видео никак не каждодневный. Хорошим тоном считается первые 10-20% хронометража видео рассказывать информацию не по сути дела. Расскажи, что тебя долго просили сделать видео по такой-то теме, что тебе написали в комментариях, и поэтому ты сейчас записываешь видео... В общем перед зрителем нужно оправдаться, почему ты снимаешь урок, нельзя просто начать рассказывать, как сделать что-то! Делая уроки по C# по этикету нужно либо вообще не объяснять зачем нужна сложная штука, реализацию которой ты объясняешь (например, делегаты), либо делать это под конец видео. Ведь зрителю так интересно смотреть все видео и нихрена не понимать, зачем это надо. В идеале ты сам должен не иметь четкого представления, где реально это используется, но не подавать виду. Задача урока по C# максимально точно в терминах формулировать мысли, чем больше новичку придется пересмотреть твое видео, чтобы уловить мысль, тем лучше. В конце концов видеоуроки делаются для профессоров по программированию, которые оценивают правильность применения терминов, а не для новичков, чтобы они с первого раза уловили суть. Есть и другая сторона медали - если объясняешь какую-то сложную штуку, то просто повторяй по 2 раза одно и то же теми же словами, ведь в 2018 году у зрителя нет возможности на Ютубе перемотать и еще раз переслушать, если не дошло. В идеале можно повторить то же самое, но медленнее, вкручивая каждое слово - так лучше объясняется. Не стоит заходить с другой стороны и объяснять другими словами.
  7. Константин Орлов

    Unity: ходьба NPC (скрипт передвижения)

    Простой скрипт, чтобы заставить NPC (моба или монстра) ходить в Unity по вейпоинтам в случайном порядке. Идеально подходит для новичков, так как делается быстро и требует минимум знаний. Скачать скрипт передвижения NPC для Unity3d: ObjectsNavigation.cs или https://yadi.sk/i/kColXBvj3XqdxA В прошлом уроке "Unity ходьба NPC (скрипт передвижения)" мы пользовались этим скриптом, тут посмотрим, как он работает изнутри.
  8. Константин Орлов

    Unity: Camera Filter Pack v12 (эффекты для камеры, пост процессинг)

    Стоит знать, что в новой версии Юнити из стандартных ассетов убрали post processing, и теперь его нужно качать отдельно с ассет стор. Для версии 5.5 и выше https://assetstore.unity.com/packages/essentials/post-processing-stack-83912. + Видеоурок Для более старой версии https://assetstore.unity.com/packages/essentials/legacy-image-effects-83913 (хотя работает и на Unity 2018)
  9. Эффекты для камеры в Unity. Просто вешаете на любую камеру один из скриптов, и наслаждаетесь эффектом. Скачать Camera Filter Pack: https://yadi.sk/d/CyxaZotl3Wsgaw или Camera Filter Pack v12.unitypackage Несколько примеров. Некоторые эффекты камеры для Unity3d с анимацией, некоторые статичны. Скрины (80 шт) https://yadi.sk/d/3o4WH39V3WsnAQ
  10. Константин Орлов

    Unity: скрипт на инвентарь от Stream

    Версия скрипта с крафтом Скачать InventoryStream.unitypackage или https://yadi.sk/d/yTDKPHpz3WrsGL
  11. Вы можете посмотреть урок по делегатам в c#, но если там недостаточно хорошо разжевано, то вот более понятное описание. Возможно, это не полное описание, и не до конца точное, но мы тут не диссертацию пишем, а пытаемся понять суть явления, пусть и с некоторыми огрехами, поэтому поехали. Что такое делегаты в c#? Если простыми словами, то представьте, что вы написали код программы (класса), где в случае каких-либо действий на консоль выводятся сообщения. Действий и ситуаций, которые приводят к выводу много, соответственно, везде вы прописали например: "Debug.Log ("текст" + какаятопеременная);". И теперь вы можете использовать этот класс, как подпрограмму в основной программе. Но в одним момент поняли, что теперь у вас приложение будет не в консоль выводить текст, а на файл или на экран, как это сделать, не меняя код уже готового класса? Очень просто, когда вы пишете класс, то расставляете в нем как бы "метки" или "маячки" - это такие "команды" (операторы), которые изменят свой функционал в зависимости от того, что вы определите во внешней программе. Во внешнем коде вы определяет функцию, которая будет выводить текст в файл, и говорите коду, что теперь эти "маячки" или "метки" приравниваются к этой функции. И теперь, когда будет проходить выполнение класса, то программа эти метки и маячки заменит на ту функцию, которую вы описали во внешнем коде. Это упрощенное понимание делегатов в c#, и функционал у них больше, но для начала стоит понять хотя бы это. Как же теперь будет работать наша программа? Если раньше она выводила какие-либо переменные на консоль, то теперь она это может делать в файл, либо на печать, либо еще куда-то. И как именно это будет решает уже внешний код, вызывающий класс. Другими словами, когда мы разбрасывали по программе метки и маячки (то есть делегаты), то мы создавали "пустые" функции, которые потом можно подменить конкретными. Но только с определенной сигнатурой, например, у нашем примере они принимают переменную типа string, а возвращают void. Теперь все маячки и метки, у которых одинаковое имя, мы можем подменить функцией, определенной во внешнем коде, главное, чтобы она также принимала string и возвращала void. Это упрощенное представление, которое позволяет буквально за 2 минуты вникнуть в том, о чем "умалчивают" в видеоуроках по 10 минут. Ведь чаще всего очень долго рассказывается, как работать с делегатами, но не рассказывается, зачем они нужно и что из себя представляют. После этого вы можете смотреть видео. Только учтите, что упрощенное объяснение всегда неверно в терминах, поэтому не используйте мои термины, используйте "официальные". Детали реализации делегатов в c# Делегат должен иметь заданную сигнатуру, то есть тип и количество принимаемых параметров, а также тип возвращаемого параметра. Внутри кода вашего класса необходимо не только оставить сами экземпляры делегатов ("пустые функции") , но еще и: создать тип (как бы класс) делегата. То есть в коде вы определяете, что существует тип делегатов с такой-то сигнатурой, например, delegate void TypeMyDelegat(); (сигнатура у него - не принимает параметров, и не возвращает ничего). А потом вам нужно создать экземпляры делегатов, которые будут иметь имя и находиться там, где нужно будет подставить вместо них другую функцию. Экземпляр делегата создается так TypeMyDelegat EkzemplyarName;, то есть этим кодом мы создали экземпляр делегата с именем EkzemplyarName и типом TypeMyDelegat. Мы можем создать несколько экземпляров с разными именами, которые будут иметь один и тот же тип (и сигнатуру, соответственно). В коде вызывать (использовать, "ставить") экземпляры делегатов можно неограниченное число раз, точно также, как можно любое количество раз вызывать какую-либо функцию. Ведь по сути экземпляр делегата в c# это ссылка на функцию. Зачем может понадобиться несколько экземпляров? У каждого есть свое имя, мы сможем расставить их по коду так, чтобы каждый вызывал свою функцию. При этом все они могут быть одного типа, а тип задает только лишь принимаемые аргументы и возвращаемое значение. Соответственно, и типов может быть несколько. Когда мы написали TypeMyDelegat EkzemplyarName;, то создали экземпляр делегата, но мы ему еще не присвоили, на какую функцию он будет ссылаться. Если мы расставим по коду этот экземпляр, то при выполнении получим ошибку, ведь он по факту null, то есть не содержит ссылку на какую-либо функцию. Расставить в коде экземпляр мы можем так EkzemplyarName(); то есть это выглядит как вызов обычной функции. Чтобы этот экземпляр делегата вызывал конкретную функцию, необходимо засунуть в него ссылку на нее. Делается это так EkzemplyarName = KarayatoFunkciya;. У вас в коде должна быть определена void KarayatoFunkciya (), чтобы она смогла впихнуться в делегат, так как тип у делегата такой, что не принимает параметров и возвращает void. Создадим делегат с другим типом, например, delegate void TypeMyDelegatForMessage (string soobshenie), он не возвращает ничего, но принимает string-переменную, в нашем случае для вывода сообщения логов. Допустим у нас в классе, где создан тип делегата с его экземплярами, есть функция void SohranitLogi(string soobshenie);, эта функция будет принимать от кода одну переменную типа string и как-то ее обрабатывать, например, выводить на консоль. Мы хотим, чтобы теперь расставленные по коду делегаты выполняли эту функцию. Пишем EkzemplyarNameForMessage = SohranitLogi;, теперь когда в коде встретится "команда" EkzemplyarNameForMessage (infa);, то будет вызвана функция void SohranitLogi(string soobshenie), в которую передается переменная infa. Итого, все вышенаписанное может выглядеть так: delegate void TypeMyDelegat(); // создаем тип (вид, породу) делегата, который ничего не принимает и не возвращает TypeMyDelegat EkzemplyarName; //создаем экземпляр (объект) делегата, и даем ему имя EkzemplyarName, но мы к нему не приписали ссылку на какую-либо фукнцию, поэтому при попытке его вызвать будет Null и ошибка //EkzemplyarName(); - такой код вызвал бы ошибку delegate void TypeMyDelegatForMessage (string soobshenie); // создаем новый тип делегата, который может принимать string TypeMyDelegatForMessage EkzemplyarNameForMessage; //создаем объект (экземпляр) делегата, вышеописанного типа, но еще без ссылки на функцию void SohranitLogi(string soobshenie) //фукнция, которую будем вызывать через делегат { //... тут какой-то код, выводящий сообщение куда-то } EkzemplyarNameForMessage = SohranitLogi; // теперь экземпляр делегата EkzemplyarNameForMessage (у которогот тип TypeMyDelegatForMessage) будет содержать ссылку на функцию SohranitLogi EkzemplyarNameForMessage (dannie); // эта конструкция передаст в фукнцию SohranitLogi переменную dannie. Тут мы используем экземпляр делегата, который ссылается на функцию. Как передать делегат внутрь класса Вернемся к нашему самому первому примеру про класс. Во внешнем коде мы определяем тип делегата (то есть пишем это "delegate void TypeMyDelegatForMessage (string soobshenie)") , а уже внутри класса должен быть создан внутренний экземпляр этого типа делегата, который мы раскидаем по коду в местах, где потребуется вызывать внешнюю функцию. Но как вы помните, у нас в первом примере был класс, который должен от внешнего кода получить информацию, какую именно функцию вызывать экземплярами делегата. Значит, в коде нашего класса должна быть функция, которая пропишет экземпляру делегата его "значение" (ссылку на внешнюю функцию), и это значение мы должны получить из вне класса. Выглядит это так, пишем внутри класса функцию: public void ZapihatbVdelegat (TypeMyDelegatForMessage 4toZapihat) { EkzemplyarNameForMessage = 4toZapihat; //пихаем во внутренний экземпляр делегата (по имени EkzemplyarNameForMessage) ссылку на функцию, которую нам передаст внешний экземпляр делегата через переменную 4toZapihat } Это функция внутри класса, которую можно вызывать из внешнего кода, и передать ей в качестве параметра через переменную экземпляр делегата с типом TypeMyDelegatForMessage. Данная функция, получив с внешней стороны ссылку на внешнюю функцию, запихает ее в свой внутренний экземпляр делегата. Это значит, что во внешнем коде мы должны будем иметь функцию, и также во внешнем коде мы должны создать экземпляр делегата, и назначить ему эту внешнюю функцию. И только после этого мы вызовем ZapihatbVdelegat и передадим ей наш экземпляр делегата с внешнего кода. И один важный момент, теперь необходимо объявлять тип делегата (то есть писать это "delegate void TypeMyDelegatForMessage (string soobshenie)") во внешнем коде. Ведь мы там сначала создадим экземпляр делегата этого типа, там же в него запихнем нашу внешнюю функцию, и после этого уже передадим его в внутренний код класса через через функцию ZapihatbVdelegat.
  12. Скрипт, который является базовым классом, от которого вы можете наследовать другие классы (скрипты). Смысл в том, что создавая скрипт, и вешая его на GameObject (например, NPC или моба, а может и игрока), вы можете унаследовать его от этого, и тогда получите функции, описанные в самом скрипте в комментариях в начале. Это может понадобиться, если у вас много видом мобов или NPC, и у них планируются свои разновидности (еще дочерние классы), и вы хотите всем задать одни и те же особенности. Например, у всех должно быть хп, максимум хп, и здоровье должно восстанавливаться. Если вы их будете наследовать от этого базового класса (либо от других классов, которые наследуются от этого), то все они будут иметь свойства описанные в скрипте. В тексте скрипта все описано, единственное на что стоит уделить особое внимание - в вашем классе-наследнике в методе Start должен содержаться вызов ХП-регена, иначе ХП не будет восстанавливаться со временем: void Start() { StartCoroutine(HPRegen()); } Сам скрипт (класс), от которого нужно наследоваться:
  13. Константин Орлов

    Unity: полезные скрипты (команды)

    Прибавляет к переменной примерно +1 в секунду CurrHP += Time.deltaTime;
  14. Константин Орлов

    Unity: полезные скрипты (команды)

    Как узнать скорость во время движения объекта? https://toster.ru/q/280308 Движение объекта. Ограничение по скорости и остановка. https://gcup.ru/forum/59-34062-1
  15. Константин Орлов

    Unity как зациклить анимацию?

    Когда только начинаете разбираться с таким инструментом, как Animator, то можно попасть в тупик - анимация проигрывается только один раз, и непонятно где искать настройку, чтобы зациклить анимацию в Unity. Чтобы анимация повторялась надо взять сам кусок анимации (как правило он в префабе объекта), и в инспекторе выбрать Edit на вкладке Animation. Далее нажать Loop Time, и применить изменения (Apply в самом низу инспектора) Можно посмотреть, как настроить повторение анимации, по скрину.
  16. Константин Орлов

    Unity: полезные скрипты (команды)

    Полезные кусочки кода скриптов Небольшие фрагменты, которые можно использовать, как заготовки Перемещение по нажатию на кнопку По нажатию на Q создает ГеймОбжект с именем Object4Mouving и приписывает туда ссылку на объект из иерархии с названием TireNearLike. Название ставьте свое, выбирайте имя того объекта, которое необходимо найти на сцене. Далее объект переносится в указанные координаты. //изменение позиции объекта(тест поиска объекта для изменения его позиции по его имени) if (Input.GetKeyUp(KeyCode.Q)) //будет срабатывать по нажатию Q { Debug.Log("Сработало перемещение объекта по Q"); //выводит инфу в консоль GameObject Object4Mouving = GameObject.Find("TireNearLike"); //поиск объекта по названию в иерархии юнити Object4Mouving.transform.position = new Vector3(1, 2, 3);//перемещение этого объекта в указанные координаты по X,Y,Z } Создание (инициализация, спавн) объектов в Unity Создает объект из указанного в инспекторе экземпляра. Координаты созданного объекта будут такими же, как координаты объекта, на котором висит скрипт. Можно перетянуть в публичную переменную, как префаб, так любой объект из окна иерархии. //инициализирует какой-либо объект public GameObject gameObject4Spawn; //создаем публичную переменную gameObject4Spawn (игровой объект для спавна), сюда нужно переместить в инспекторе объект, который вы хотите создать в игре (из префаба или сцены) public void GenerateGameObject()//создаем функцию, вызвав которую создастся этот объект { Instantiate(gameObject4Spawn);//создание объекта } //теперь в коде этого скрипта (в Start, Update и т.п.) вызывайте функцию "GenerateGameObject();" и в игре появится объект. Как вычислить дистанцию до объекта (монитор дистанции) Например, мы хотим, чтобы лампочка загоралась, когда игрок приближается к ней на определенное расстояние. Можно это сделать через OnTriggerEnter, то есть создать триггерный коллайдер, и когда игрок в него входит, то включается лампочка, но для теста сделаем, чтобы высчитывалось именно расстояние до лампочки. Придется это писать в метод Update, что мало полезно для оптимизации, но опять же - тут лишь тест для понимания принципов работы кода. Скрипт необходимо повесить на объект, относительно которого будем высчитывать расстояние до игрока (в нашем случае это лампочка). В самом скрипте объявляем переменные (не в Update), и в инспекторе перетаскиваем в них нужные объекты: [Tooltip("лампочка, включающаяся при приближении")] public GameObject light4Load; [Tooltip("объект, относительно которого задается расстояние для определения при каком приближении включать подсветку двери")] public Transform monitorDistance; В Update пишем: //если игрок подходит к двери на определенное растояние, то срабатывает подсветка, если уходит, то выключается if (Vector3.Distance(transform.position, monitorDistance.position) < 6.0f) //если дистанция меньше 6 { light4Load.SetActive(true); //активируем лампочку Debug.Log("Монитор дистанции для вкл/выкл лампы сработал");//сообщаем в консоли, что сработало } else //если расстояние не меньше 6 light4Load.SetActive(false);//выключаем лампочку Логика скрипта Сначала создаем переменную типа GameObject под названием light4Load (свет для включения), туда в инспекторе помещаем лампочку, которую нужно включать при приближении игрока. Потом создаем переменную типа Transform с именем monitorDistance, куда помещаем игрока. Так как это тип переменной Transform, то там будут храниться координаты игрока (я так понимаю). Далее будем вычислять расстояние от monitorDistance до объекта, на котором висит этот скрипт. Vector3.Distance это метод, который высчитывает расстояние от одного объекта до другого. Мы туда передаем два параметра: это позиция объекта, на котором скрипт - это "transform.position" и позиция игрока - это "monitorDistance.position". В операторе if идет проверка, если Vector3.Distance возвращает число меньше 6.0f (т.е. расстояние между этими двумя объектами меньше 6 юнитивских метров), тогда активируется лампочка "light4Load.SetActive(true);" (изначально должна быть выключена в инспекторе). Плюс в консоль идет инфа, что лампа включилась. Если расстояние не меньше 6 метров (оператор "else"), тогда лампочка выключается.
  17. Константин Орлов

    Unity: полезные скрипты (команды)

    Перемещение объектов Вместо Object4Mouving подставляйте имя переменной, которая в вашем скрипте ссылает на нужный объект: Object4Mouving.transform.position = new Vector3(1, 2, 3);//перемещение объекта Object4Mouving в указанные координаты по X,Y,Z
  18. Тут придется напрячься. Так как это скорее напоминалка для тех, кто разбирается в Unity и скриптах, а не урок для новичков. Ибо новичку трудно будет вникнуть, что тут происходит по причинам описанным в самом скрипте. Сделано по уроку: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class Spider : MonoBehaviour { //сделано по уроку https://www.youtube.com/watch?v=ANuDASeE-Oc (https://www.youtube.com/watch?v=dgEfHvsi6Zo) //Этот мануал по скриту будет довольно трудно понять новичку, так как я тут изменял названия некоторых методов и переменных под себя //поэтому просто скопировать не получится (+скрипт игрока с ХП нужен, а это скрипт лишь для паука). //Но и чисто по видео сделать тоже не получится без проблем, так как автор изменил код между 1 и 2 частью видео //но не сообщил об этом. Поэтому придется вам посмотреть видео, повторить все за автором, а потом вникнуть в то, что написано ниже, чтобы //заставить заработать код из видео. //Итак, если вы будете делать по этому видео уроку, то учтите, что автор во второй части видео немного передалал код из первой части видео //но это не попало в урок, и он не объяснил, что изменил. Поэтому после полного написания скрипта, чтобы паук ходил по точкам //необходимо его немного изменить. А для этого нужно в начале второй части видео посмотреть старый код из первой части, и переделать его. //А именно: в 34 (относительно моего скрипта) строчке автор сменил тег на GroupPoint, и добавил новую 35 строчку "points = new Transform[temp.childCount];", где //изменил подход - теперь точки пути для паука ищутся сразу всей кучей через родительский объект, у которого должен быть тег GroupPoint //(раньше искалась каждая точка по тегу). Поэтому в родительский объект в иерархии точек вам нужно добавить тег GroupPoint, иначе паук //не будет патрулировать территорию. //Самс скрипт: const float damage = -0.2f; //сила урона паука (у меня минусовое значение из-за особенностей скрипта на ХП, у вас, скорее всего, нужно положительное значение) NavMeshAgent agent; Animator animator; GameObject player; //ссылка на игрока, которого мы найдем позже по тегу Player HpPlayer; // float visible = 8f; //радиус видимости паука, если игрок подойдет ближе указанного значения, то паук начнет преследовать игрока Transform[] points; //массив точек (waypoints), по которым будет ходить паук, когда рядом не видит игрока (типо патрулирует) int path = 0; //переменная выбор пути, используется в скрипте, чтобы указывать на какую из точек в массиве сейчас идти (выбирается случайным образом) float minDistance = 1f; //минимальная дистанция до точки, когда паук посчитает, что дошел до нее. В видео уроки стоит 0.01, //но тогда паук не всегда ее может достичь, если она прямо на полу. // Use this for initialization void Start () { animator = GetComponent<Animator>(); //получаем в переменную аниматор паука agent = GetComponent<NavMeshAgent>(); //получаем в переменную навигационный меш паука player = GameObject.FindGameObjectWithTag("Player"); //ищем игрока по тегу, и помещаем ссылку на него в переменную if (player != null) //если игрок найден (если не Null) { HpPlayer = player.GetComponent<Player>(); //помещаем в переменную скипт, который прикреплен к игроку, и в котором прописана переменная его HP } Transform temp = GameObject.FindGameObjectWithTag("GroupPoint").transform; //создайте в иерархии пустой объект, добавьте ему тег GroupPoint и поместите туда пустые объекты, которые будут точками пути для паука, тогда эта строчка найдет этот объект и поместить в переменную temp points = new Transform[temp.childCount]; //помещает в массив пустые объекты, которые дочерни относительно объекта с тегом GroupPoint (видимо нужно, чтобы определить размер массива) int i = 0; foreach (Transform t in temp) //помещает в массив координаты точек (или что-то вроде того, яхз) { points[i++] = t; } } // Update is called once per frame void Update () { if (player != null) //если игрок найден по тегу (т.е. если не Null) { float distance = Vector3.Distance(transform.position, player.transform.position); //определяем дистанцию между пауком и игроком, и помещаем в переменную if (distance < 1f) //если дистанция меньше указанного значения { //animator.SetBool("attack", true); //тут я поставил, чтобы проигрывалась анимация атаки, но она проигрывается 1 раз без зацикливания, поэтому выключил Player.SetHPPlayer(damage); //тогда наносим дамаг игроку, вызывая фукнцию в его скрипте (должен быть прикреплен к нему на инспекторе), название функции можете прописать свое, главное сделайте ее в скрипте игрока } else if (distance < visible) //если дистанция до игрока меньше радиуса видимости { //animator.SetBool("attack", false);//тогда выключаем анимацию атаки (если была включена), добавил я от себя agent.destination = player.transform.position; //и передаем агенту навигации координаты игрока, чтобы идти к нему } else { float distanceToPoint = Vector3.Distance(transform.position, points[path].transform.position); //иначе (если игрока нет в зоне видимости), тогда определеем координаты точки для патрулирования if (distanceToPoint <= minDistance) //если дистанция до точки меньше минимальной, то точка считается достигнутой { path = Random.Range(0, points.Length); //передаем в переменную случайное число от нуля до длинны нашего массива, содержащего все точки. Нужно, чтобы выбрать случайным образом, к какой точке идти дальше } agent.destination = points[path].transform.position; //направляем нашего агента к случайной точке, выбарнной выше } } if (agent.velocity.magnitude > 2f) //если скорость агента (или как-то так) выше указанного { animator.SetBool("walk", true); //тогда включаем анимацию движения } else { animator.SetBool("walk", false); //если ниже указанного, тогда выключаем анимацию движения } } }
  19. Константин Орлов

    Unity: В чем преимущества игрового движка

    Кроме того, что Unity может создавать игры под самые популярные платформы (Windows, Android, Xbox, PS) и для этого не требуется ничего особого, достаточно просто скомпилировать игру в нужный формат. Еще изучая этот движок для создания игр вы научитесь: делать игры, это сейчас самый популярный движок делать приложения для Android, например, не составит труда написать интерфейсную программу, если вы знаете хорошо Unity выучите язык программирования C#, который пригодится не только для написания скриптов для игры, но еще и для программирования в целом научитесь 3D моделированию, например, если вам нужно будет поработать с 3D объектами для создания видео или картинки можно выучить английский язык, если постоянно смотреть в переводчике, что значат встречающиеся в настройках редактора слова, а также если самому называть свои объекты не Svet, а Light, очень эффективно, так как вы постоянно с ними работаете и запоминаете значение. Произношение также можно запоминать, в Яндекс Переводчике есть озвучка. Таким образом можно решать сразу несколько задач, многие из них понадобятся в современном мире всем, например, изучение английского языка. Некоторые почти всем - язык программирования, умение создать приложение для телефона.
  20. Изначально текстуры в Unity привязываются к размеру объекта, на который наложены. В итоге мы получаем либо слишком размытую текстуру (при большом объекте), либо слишком мелкую, если объект маленький. Инструкция, как поставить нормальный размер текстур в Unity: Добавляем шейдер в проект, выбираем в шейдере Rain GS, и теперь текстуры будут без привязки к размеру объекта (всегда нормальный масштаб, без увеличения или уменьшения). В настройках шейдера в инспекторе есть параметр Tiling, отвечающий за масштаб текстуры. Можно скачать с поста uvfreecheck(shader4Unity).rar, либо по ссылке https://yadi.sk/d/liK7Xqfrsbngc
  21. Не забудьте назвать файл скрипта таким же именем, либо переименовать класс в тексте скрипта using System.Collections; using System.Collections.Generic; using UnityEngine; public class SphereGenerator : MonoBehaviour { //скрипт генерирует объекты и выпуливает их в случаных направлениях в заданом радиусе public GameObject sphere; //сюда передаем префаб private GameObject sphereJump; private float genTime, genTimer = 0.5f; //задаем частоту генерации в секундах // Use this for initialization void Start () { } // Update is called once per frame void Update () { genTime += Time.deltaTime; if (genTime > genTimer) { sphereJump = Instantiate(sphere) as GameObject; //создает объект int forceX = Random.Range(-50, 50); //кординаты создания (в заданом диапазоне) int forceY = Random.Range(90, 550); int forceZ = Random.Range(-50, 50); sphereJump.GetComponent<Rigidbody>().AddForce(new Vector3 (forceX, forceY, forceZ)); //придаем импульс при создании объекта, можно перез закрывающей скобочкой добавить множитель, например *2 genTime = 0; } } }
  22. Константин Орлов

    Unity: коллайдеры через скрипты

    Вот пример кода, когда при инициализации скрипта создается коллайдер в масштабе х2, добавляет галочка Is Trigger. При желании можно раскоментировать код про дестрой объекта, тогда он сразу же удалится: void Start () { gameObject.AddComponent<BoxCollider>().size = new Vector3(2, 2, 2); gameObject.GetComponent<BoxCollider>().isTrigger = true; //Destroy(gameObject.GetComponent<BoxCollider>()); }
  23. Константин Орлов

    Unity: коллайдеры через скрипты

    Как создать BoxCollider или SphereCollider на объекте через скрипт C# в Unity? Может пригодится, если у вас объекты создаются не в редакторе игрового движка, а генерируются из скриптов. Добавление коллайдера Как добавить коллайдер к объекту через скрипт? В скрипте, который прикреплен к GameObject в методе Start пишете gameObject.AddComponent<BoxCollider>(); Это добавит во время старта игры BoxCollier через скрипт любому объекту, к которому будет прикреплен скрипт. Включение галочки Is Trigger Если нужно добавить объекту галочку Is Trigger, то после предыдущей строчки пишем следующее: gameObject.GetComponent<BoxCollider>().isTrigger = true; Уничтожение коллайдера Если необходимо удалить (уничтожить) коллайдер с объекта, то в его скрипте пишем: Destroy(gameObject.GetComponent<BoxCollider>()); Destroy(gameObject.GetComponent<BoxCollider>()); Установка размера Если добавить к строчке ".size = new Vector3(2, 2, 2);", то создаваемый коллайдер будет иметь масштаб (scale) 2 по всем осям: gameObject.AddComponent<BoxCollider>().size = new Vector3(2, 2, 2); Например, при добавлении такого коллайдера на модельку, у меня размер коллайдера стал в 2 раза больше, чем был бы изначально, исходя из размера модельки. Остальное Про определение столкновения коллайдера-триггера с объектами можно прочитать тут https://habr.com/post/149721/, также там про добавление компонентов с помощью скриптов.
  24. Если в консоли Юнити появилась ошибка "TerrainData is missing splat texture 5(***), make sure it is marked for read/write in the importer.", то ее можно исправить найдя нужную текстуру (в скобочках указана в вашем сообщении), и установив там режим для чтения и записи. У меня это возникло после перестановки Unity и распаковки архива с проектом.
  25. Для начала объявляем переменную, которая будет хранить в себе создаваемый объект, например: [Tooltip("создаем объект переменную для генерации объекта с помощью клавиши Y")] public GameObject GenerateObjectAtKeyY; Создаем скрипт с любыми именем, перетаскиваем его на любой активный объект на сцене, в скрипте в методе Update пишем: if (Input.GetKeyUp(KeyCode.Y)) { Debug.Log("Сработала генерация"); GameObject MyGenObject = Instantiate(GenerateObjectAtKeyY, transform.position, transform.rotation); //MyGenObject.GetComponent<Rigidbody>().AddForce(transform.up * 2500); } Теперь перетаскиваем префаб объекта, который нужно создать, в поле переменной скрипта, которое находится в инспекторе объекта, на который мы повесили скрипт. Таким образом при нажатии на Y будет сначала выводиться в консоль информация, что сработала генерация, потом создается объект. Положение созданного объекта будет таким же, как и положение объекта, на котором скрипт. Если повесить скрипт на игрока, то прямо в игроке создастся нужный объект из префаба. Можно удалить ", transform.position, transform.rotation" из кода, тогда положение создаваемого объекта будет таким, каким было на момент создания префаба. Т.е. инфа по положении берется из префаба. Можно раскоментировать последнюю строчку, тогда объект при создании будет получать импульс вверх относительно объекта, к которому прикреплен скрипт (например, игрока), то есть будет выстреливать. При этом если игрок наклонится, то верх будет тоже под наклоном. Этот код нужен лишь для примера, чтобы понять принципы работы скриптов. Он неоптимизирован, в крупных проектах такой подход не стоит использовать.

Powered by Invision Community
Поддержка Invision Community в России