Перейти к содержанию
Технологии манипуляции СМИ

Активность

Лента обновляется автоматически     

  1. Последняя неделя
  2. Константин Орлов

    Полезные ссылки для Unity (видеоуроки и скачка)

    Принципы работы с префабами: Вы можете перенести любой объект из сцены в окно ассетов, таким образом создастся префаб. Теперь можно из ассетов переносить любое количество раз этот объект обратно на сцену, и будут создаваться копии. При редактировании префаба все копии автоматически подстроятся под измененный префаб. Редактировать префаб частично можно в инспекторе, но нередко нужно достать его на сцену, внести коррективы и нажать Apply, чтобы изменения применились к префабу, и как следствие ко всем его экземплярам. Также можно отредактировать любой экземпляр префаба на сцене, нажать Apply, и изменения примут все копии (что по сути аналогично предыдущему действию). В префаба может содержаться другой префаб. Как при этом работает редактирование и применение изменений я так и не разобрался. У меня 3 моба из 3 разных префабов, в каждом есть по 1 экземпляру префаба LivingInfoBar, но в двух мобах префаб LivingInfoBar берет данные из исходника, а у одного моба как бы создается свой префаб LivingInfoBar и он ни на какие изменения не влияет, и сам не принимает никаких изменений.
  3. Константин Орлов

    Unity и С#: Что такое делегаты простыми словами

    Вы можете посмотреть урок по делегатам в 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.
  4. Как на C# в Unity получить доступ к переменным другого скрипта? Если в видео вам не понятно, то разжую на пальцах. Для примера у вас на GameObject (так называют любой объект на сцене) висит 2 скрипта, вам нужно, чтобы один скрипт у другого мог вызывать его функции или менять переменные. Получить доступ к скрипту на том же объекте Синтаксис получения. Сначала вам в первом скрипте необходимо создать переменную, которая будет ссылаться на второй скрипт вашего GameObject. Потом положить в эту переменную ссылку на второй скрипт, далее использовать переменную для работы с переменными и функциями второго скрипта. И все. Очень просто, теперь как это делается. Весь код делается в первом скрипте, сначала мы создаем переменную, в методе Awake или Start приписываем ей ссылку, и далее уже в нужных местах (Start или Update) будем через нее обращаться к "членам" (функциям и переменным) второго скрипта. Вы должны знать имя второго скрипта, это имя (название скрипта, оно же является классом) будет "типом переменной". Официальная терминология очень умная и непонятная, поэтому скажу проще - создаете переменную, как обычно, вроде "private int X", только вместо типа int используете название вашего скрипта (оно же класс). Например, "private HealthSystem ImyaPeremennoi", таким образом вы создали переменную, в которую можно положить ссылку на скрипт, который называется HealthSystem (в вашем случае название скрипта другое). Название переменной может быть любым, а тип переменной должен быть таким же, как название второго скрипта, с которым вы хотите работать из первого. Итак, вы создали переменную, тип которой совпадает с названием второго скрипта, а имя переменной может быть любым. Теперь в эту переменную нужно положить ссылку на второй скрипт, так как мы создали лишь пустой "контейнер", и задали его "тип", но еще не указали, какой конкретно экземпляр этого скрипта будет находиться в переменной. А экземпляров может быть несколько, если у вас один и тот же (второй) скрипт прикреплен к нескольким объектам. Поэтому после строчки "private HealthSystem ImyaPeremennoi;" в методе Awake/Start нам надо сделать следующее ""ImyaPeremennoi = GetComponent<HealthSystem>();". То есть до этого мы создали переменную и решили, какого она будет типа. А сейчас мы засунули в нее скрипт с названием HealthSystem (это второй скрипт), который должен находиться на том же объекте, что и первый скрипт, где мы пишем все эти строчки. Конструкция "ImyaPeremennoi = GetComponent..." значит, что в эту переменную мы поместим ссылку на какой-то компонент, который есть у нас на объекте. Это может быть Rigitbody, Collider, Transform (который автоматически есть у всех объектов) - все это компоненты. Скрипты тоже компоненты, ведь они находятся в инспекторе, и добавить их можно с помощью кнопки Add Component. В данном случае в переменную с типом (то есть с видом или "породой") "HealthSystem" мы можем поместить только скрипт HealthSystem. Итак, еще раз: мы создали переменную с определенным типом "private HealthSystem ImyaPeremennoi;", чтобы туда засунуть ссылку на скрипт. Все это делалось в одном скрипте (имя его может быть любым, главное, чтобы он был на объекте), а доступ будем получать к другому скрипту, который в нашем примере называется HealthSystem (тут как будто бы все переменные и функции, отвечающие за ХП игрока). Потом мы засунули в переменную ImyaPeremennoi ссылку на скрипт HealthSystem, написав следующее: "ImyaPeremennoi = GetComponent<HealthSystem>();". Теперь используя переменную ImyaPeremennoi мы можем через нее обращаться к переменным и функциям скрипта HealthSystem. Например, скрипте HealthSystem есть публичная переменная Zdorovie (public int Zdorovie = 100;) , отвечающая за здоровье игрока, попробуем в нашем первом скрипте изменить ее. Пишем "ImyaPeremennoi.Zdorovie = 50;" теперь наш первый скрипт напрямую меняет переменную у второго скрипта. Также первый скрипт может вызывать функции из второго скрипта, например, во втором скрипте прописана функция Jump();, вызов которой заставляет игрока подпрыгнуть. Ее можно взывать так "ImyaPeremennoi.Jump();" Как получить доступ к скрипту другого объекта Тут принципы те же, с той лишь разницей, что добавляется еще одно действие. В первом примере, когда мы писали "ImyaPeremennoi = GetComponent<HealthSystem>();", мы имели в виду следующее "ImyaPeremennoi = _у_этого_объекта_ GetComponent<HealthSystem>();", то есть компонент брали у того же объекта, на котором висит первый скрипт с этим кодом. Поэтому по умолчанию, когда вызывался GetComponent он знал, с какого объекта брать компонент. По сути мы писали в скрипте "команду", какой нужно получить компонент, но не указывали у кого мы его берем, так как подразумевается, что с себя. Сейчас же надо просто указать пальцем, у кого берем компонент. Для этого надо создать еще одну переменную, куда мы поместим ссылку на другой объект. Пишется это так "public GameObject DrugoiObiekt" - мы создаем публичную переменную (public) с названием DrugoiObiekt, и поместить в нее можно будет что-то, у чего тип GameObject. А GameObject - это "базовый" тип любого объекта на сцене. Итак, как и в первый раз мы сначала создали переменную "контейнер", которая предназначена для хранения любого GameObject'а, теперь нужно засунуть в нее конкретный объект, с которым мы будем работать. Так как мы сделали ее публичного типа (public), то вы можете в инспекторе перетащить из иерархии сцены любой объект в нее. Для этого вам нужно зайти в инспектор того объекта, на котором висит ваш первый скрипт (где мы писали весь этот код), и там появится специально поле с названием DrugoiObiekt. Когда вы туда перетяните объект, то скрипт будет знать, какой именно объект подразумеваете в переменной DrugoiObiekt. Ссылку на объект мы теперь получили, она после перетягивания хранится в DrugoiObiekt, но теперь нужно получить ссылку на скрипт, который висит на этом другом объекте. А чтобы получить ссылку на скрипт нам нужна переменная, которая ее будет хранить. А чтобы переменная хранила ссылку на скрипт, она должна быть быть таким же типом, как и название скрипта. В нашем случае у DrugoiObiekt скрипт также называется, как и раньше - это HealthSystem. Поэтому мы можем создать переменную типа HealthSystem, например, так: "private HealthSystem HealthSDrygogoObiekta;". Теперь в эту переменную-ссылку нужно "положить скрипт" с другого объекта. Делается это так "HealthSDrygogoObiekta = DrugoiObiekt.GetComponent<HealthSystem>();". Мы это уже делали, только тут всего два отличия. Первое это другое имя переменной, если раньше она называлась ImyaPeremennoi, то теперь HealthSDrygogoObiekta, а тип у этих переменных одинаковый, так как они обе предназначены для хранения ссылки на скрипт HealthSystem. Второе отличие, что теперь мы указываем у кого мы берем компонент. Если первый раз достаточно было написать "GetComponent<HealthSystem>();", и было понятно, что компонент HealthSystem мы берем с того объекта, на котором висят эти строчки кода, то теперь явно указываем объект - DrugoiObiekt. Как вы помните в переменной DrugoiObiekt у нас хранится ссылка на другой объект, который вы перетянули в инспекторе. В итоге у нас переменная HealthSDrygogoObiekta содержит ссылку на скрипт другого (внешнего, так сказать) объекта. Теперь мы можем у него менять переменные и использовать функции, которые есть в его скрипте HealthSystem. Например, "HealthSDrygogoObiekta.Zdorovie = 55;" или "HealthSDrygogoObiekta.Jump();", если у скрипте HealthSystem есть функция Jump();
  5. Ещё раньше
  6. Скрипт, который является базовым классом, от которого вы можете наследовать другие классы (скрипты). Смысл в том, что создавая скрипт, и вешая его на GameObject (например, NPC или моба, а может и игрока), вы можете унаследовать его от этого, и тогда получите функции, описанные в самом скрипте в комментариях в начале. Это может понадобиться, если у вас много видом мобов или NPC, и у них планируются свои разновидности (еще дочерние классы), и вы хотите всем задать одни и те же особенности. Например, у всех должно быть хп, максимум хп, и здоровье должно восстанавливаться. Если вы их будете наследовать от этого базового класса (либо от других классов, которые наследуются от этого), то все они будут иметь свойства описанные в скрипте. В тексте скрипта все описано, единственное на что стоит уделить особое внимание - в вашем классе-наследнике в методе Start должен содержаться вызов ХП-регена, иначе ХП не будет восстанавливаться со временем: void Start() { StartCoroutine(HPRegen()); } Сам скрипт (класс), от которого нужно наследоваться:
  7. Константин Орлов

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

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

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

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

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

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

    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"), тогда лампочка выключается.
  11. Константин Орлов

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

    Перемещение объектов Вместо Object4Mouving подставляйте имя переменной, которая в вашем скрипте ссылает на нужный объект: Object4Mouving.transform.position = new Vector3(1, 2, 3);//перемещение объекта Object4Mouving в указанные координаты по X,Y,Z
  12. Константин Орлов

    Unity: Преследование персонажа мобом

    Тут придется напрячься. Так как это скорее напоминалка для тех, кто разбирается в 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); //если ниже указанного, тогда выключаем анимацию движения } } }
  13. Константин Орлов

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

    Кроме того, что Unity может создавать игры под самые популярные платформы (Windows, Android, Xbox, PS) и для этого не требуется ничего особого, достаточно просто скомпилировать игру в нужный формат. Еще изучая этот движок для создания игр вы научитесь: делать игры, это сейчас самый популярный движок делать приложения для Android, например, не составит труда написать интерфейсную программу, если вы знаете хорошо Unity выучите язык программирования C#, который пригодится не только для написания скриптов для игры, но еще и для программирования в целом научитесь 3D моделированию, например, если вам нужно будет поработать с 3D объектами для создания видео или картинки можно выучить английский язык, если постоянно смотреть в переводчике, что значат встречающиеся в настройках редактора слова, а также если самому называть свои объекты не Svet, а Light, очень эффективно, так как вы постоянно с ними работаете и запоминаете значение. Произношение также можно запоминать, в Яндекс Переводчике есть озвучка. Таким образом можно решать сразу несколько задач, многие из них понадобятся в современном мире всем, например, изучение английского языка. Некоторые почти всем - язык программирования, умение создать приложение для телефона.
  14. Константин Орлов

    Unity шейдер для нормального масштаба текстур

    Изначально текстуры в Unity привязываются к размеру объекта, на который наложены. В итоге мы получаем либо слишком размытую текстуру (при большом объекте), либо слишком мелкую, если объект маленький. Инструкция, как поставить нормальный размер текстур в Unity: Добавляем шейдер в проект, выбираем в шейдере Rain GS, и теперь текстуры будут без привязки к размеру объекта (всегда нормальный масштаб, без увеличения или уменьшения). В настройках шейдера в инспекторе есть параметр Tiling, отвечающий за масштаб текстуры. Можно скачать с поста uvfreecheck(shader4Unity).rar, либо по ссылке https://yadi.sk/d/liK7Xqfrsbngc
  15. Продолжаем изучать технологии манипуляции людьми, на этот раз о технологиях манипуляции игроком в компьютерных играх. Что такое манипуляция https://orkons.ru/stati/manipulyatsiya-eto-skrytoe-upravlenie/ Нечто подобное используют и в фильмах. Например, в фильме "Берегись автомобиля" (разбор https://youtu.be/d-7jeeM3Fd8) для привлечения внимания к сигаретам персонажи любили ими жестикулировать. Сигареты и так в кадре, и уже влияют на подсознание, но чем больше они притягивают внимания, тем эффективней пропаганда. Но и перебарщивать не нужно.
  16. Константин Орлов

    Unity скрипт: генератор объектов с импульсом

    Не забудьте назвать файл скрипта таким же именем, либо переименовать класс в тексте скрипта 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; } } }
  17. Константин Орлов

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

    Полезные для новичков скрипты c# для Unity. Тут как отдельные "команды" (что-то вроде записной книжки, чтобы не заучивать синтаксис), так и небольшие кусочки кода, которые помогут лучше понять принципы работы. Как из скрипта включить/выключить другой скрипт Указываете вместо ActivateScript имя своего метода, а вместо NameScript имя скрипта, который прикреплен к объекту. Оставляете gameObject, если этот код будет отключать другой скрипт, который прикреплен на этом же объекте. Если нужно, чтобы этот код был на одном объекте, а выключал он скрипт у другого объекта, тогда необходимо создать публичную переменную типа GameObject и в инспекторе поместить в нее нужный объект, на котором включаем/выключаем скрипт. Для выключения скрипта в коде замените true на false. //активирует скрипт (если таковой есть) https://gcup.ru/forum/59-41557-1 public void ActivateScript () { gameObject.GetComponent<NameScript>().enabled = true; } Поиск объектов Unity Поиск по тегу Присваивает переменной ссылку на игрока, находя его по тегу: GameObject PlayerFound = GameObject.FindGameObjectWithTag("Player"); Поиск по имени в редакторе GameObject foundObject = GameObject.Find("NameObjectFromHierarhy"); Создает переменную типа GameObject под названием foundObject ("найденный объект"), и помещает туда объект, который найдется на сцене (в иерархии юнити) с именем NameObjectFromHierarhy.
  18. Константин Орлов

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

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

    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/, также там про добавление компонентов с помощью скриптов.
  20. Константин Орлов

    Недостатки системы образования (школа, ВУЗы)

    До чего доводит обучение в школах и ВУЗах, где значительную часть времени в 21 веке люди занимаются переписыванием услышанного. Уже давно можно раздавать материалы на бумаге, чтобы ученикам не требовалось работать переписчиками, и достаточно давно есть электронные способы передачи информации, что позволяет копировать ее бесконечное количество раз, но все еще "надо записывать". Итак, тут человек советует записывать, что он сказал на видео, чтобы потом можно было вернуться к материалу и повторить. А еще он посоветовал записывать программы. Дожили https://youtu.be/o48YZOdhWFI?t=45s Чтобы его зрителям не нужно было ничего записывать, достаточно выложить под видео текст с его текстового документа, который он показывает на экране.
  21. Если в консоли Юнити появилась ошибка "TerrainData is missing splat texture 5(***), make sure it is marked for read/write in the importer.", то ее можно исправить найдя нужную текстуру (в скобочках указана в вашем сообщении), и установив там режим для чтения и записи. У меня это возникло после перестановки Unity и распаковки архива с проектом.
  22. Константин Орлов

    Полезные ссылки для Unity (видеоуроки и скачка)

    Rigitbody https://youtu.be/ON4styauqp8?t=18m30s Универсальная система способностей(спеллов) часть I http://www.unity3d.ru/distribution/viewtopic.php?f=11&t=29346
  23. Константин Орлов

    Unity: Создание объектов через метод Instantiate

    Для начала объявляем переменную, которая будет хранить в себе создаваемый объект, например: [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" из кода, тогда положение создаваемого объекта будет таким, каким было на момент создания префаба. Т.е. инфа по положении берется из префаба. Можно раскоментировать последнюю строчку, тогда объект при создании будет получать импульс вверх относительно объекта, к которому прикреплен скрипт (например, игрока), то есть будет выстреливать. При этом если игрок наклонится, то верх будет тоже под наклоном. Этот код нужен лишь для примера, чтобы понять принципы работы скриптов. Он неоптимизирован, в крупных проектах такой подход не стоит использовать.
  24. Константин Орлов

    Полезные ссылки для Unity (видеоуроки и скачка)

    Полезные советы Еще одно решение: Иногда при загрузке сцены из LoadLevel пропадает глобальное освещение и тени становятся черными. Чтобы исправить, надо отключить Baked GI, снять галочку с Continuous baking и нажать build. Теперь сцена будет загружаться нормально Что-то умное: Надоело писать PropertyDrawer в Unity? Есть способ лучше https://itnan.ru/post.php?c=1&p=340536 Если на GameObject повесить скрипт, и сделать из GameObject префаб, то публичные переменные (числовые точно) можно менять в префабе, и они поменяются у всех GameObject, сделанных из этого префаба. Есть исключение - если сделать публичную переменную типа Transform ("public Transform OtherGameObject;"), и перетащить в инспекторе туда другой объект, то при создании из такого объекта префаба, префаб не сохранит значение. Но если туда перетащить сам GameObject, на котором скрипт, то он запомнит это.
  25. Константин Орлов

    Полезные ссылки для Unity (видеоуроки и скачка)

    Ресурсы для Unity Модели, исходники, скрипты .3ds файлы для Unity http://www.3ds-models.org/tag/3ds/ Еще модели https://p3dm.ru Исходники игр http://u3d.at.ua/load/iskhodniki_igr/3-1 Исходники игр и модели http://unity3ddd.ru/ 105 Гигабайт текстур (torrent-файл): CGTextures_Big_Collection_2018_torrent.torrent Лучшие скрипты для Unity с null-code.ru Простая 2D книга / разбивка текста Система подсказок для 2D, 3D и UI с локализацией Взлом замков как в Skyrim Продвинутый инвентарь персонажа Создаем большую карту уровня / местности [UI] Интерактивные панели на базе UI [FPS] Вывод потерянных хит поинтов на экран Меню привязки клавиш + сохранение Область поиска предмета для FPS / TPS Перемещение объектов в шутере Мозаика / нарезка изображения Смена дня и ночи Динамический список [UI] Очередной клон тетриса на Unity Делаем журнал сообщений Простой пример генерации уровня Указатель пути Игрушка «крестики-нолики» Скрипт гравипушки наподобие как в Half-Life Фоновая загрузка сцены / уровня 3 способа сохранения данных игры
  26. Константин Орлов

    Unity: Как сделать всплывающую подсказку, как в Windows

    При наведении курсора на объект (как из 3D мира, так и в UI-интерфейсе) появляется всплывающая подсказка, похожая на обычную из интерфейса Windows. Пример работы всплывающей подсказки на игровом движке Unity Есть 3 скрипта. Один необходимо повесить на Canvas, и два других на объекты, с которых хотите получать всплывающие подсказки. Если это обычный 3D объект, то вешаем на него TooltipText, если это UI-объект, то TooltipTextUI. После чего в инспекторе конкретного объекта в компоненте скрипта указываем текст подсказки. Как установить всплывающие подсказки в Unity3d Создаем Canvas; удаляем компонент Graphic Raycaster, так как нам не нужно взаимодействие курсора с Tooltip-ом (нет картинки этого действия); вешаем на него скрипт Tooltip: Внутри него создаем 3 объекта: 1) Картинка фона (GameObject > UI > Image); 2) Картинка стрелочки-уголочка; 3) Элемент UI-текст. Скачиваем картинки в пакете со сценой примером (23кб всего), импортируем в проект, берем из папки Sprite картинки: на фон выставляем картинку Box, на стрелочку Arrow. Делаем дочерними от фоновой картинки (Box) картинку со стрелочкой и UI-текст. Выравниваем элементы в инспекторе: для стрелочки и фона bottom/left, для текста stretch/stretch; В инспекторе Canvas за счет прикрепления скрипта появились настройки, переносим в соответствующие поля созданные нами GameObject'ы: в поле Box - картинку фона, в Arrow - стрелочку, в Box Text - UI-элемент текста; Теперь можно на любой объект на сцене, который имеет коллайдер, повесить скрипт TooltipText, и в инспекторе объекта задать текст подсказки. Если это объект UI, то вешаем скрипт TooltipTextUI. Настройки шрифта задаются в инспекторе Canvas, на котором весит скрипт Tooltip. Вы можете использовать свои картинки для фона, но для начала советую попробовать с этими, чтобы быть уверенными, что ничего не съезжает из-за других картинок. Насколько скрипт грамотно написан и оптимизирован не знаю, я пока недостаточно разбираюсь, но я его поставил - работает. Задавать все объекты обязательно (фон, стрелочку), иначе работать не будет. Я пробовал без стрелочки, ибо не нужна она мне особо, но тогда видимо нарушается логика скрипта. Если подсказка очень короткая, например, 4 буквы "Стол" или "Стена", то стрелочка отображаться будет немного криво, поэтому мне пришлось увеличить текст, например, до "Это стол" или "Это стена". Источник: взято отсюда. Вы можете скачать скрипты и картинки (+демо сцена) отсюда UnityTooltip.unitypackage, либо с источника. Также скрипты выложены ниже: Скрипт Tooltip для Canvas Скрипт TooltipText для любого объекта на сцене (имеющего коллайдер) Скрипт TooltipTextUI для объектов UI (им колайдер не требуется) Картинки тоже можно скачать прямо с поста (но не факт, что заработают эти, возможно нужно именно из файлов брать): Arrow: Box:
  27. Константин Орлов

    Полезные ссылки для Unity (видеоуроки и скачка)

    Наиболее полезные видеоуроки Unity3d с ютуба Unity C# уроки / #6 - Корутины (Coroutines) Unity и создание 2D эффектов для игр на Андроид и ПК / Урок Unity3D без C# Изучение языка C# для начинающих Изучение C# в одном видео уроке за час! Вода в Unity: WaterPro — настройка, принцип работы, типичные ошибки при использовании 15 советов, которые могут ускорить вашу работу в редакторе Unity и часть 2 Как сделать игру на Unity 5 #14 звуки в игре + короткое видео по конкретным параметрам настроек аудио Как за час создать игру на Unity3D. Как сделать игру на Unity 5 #2 создание мира (программное создание мира через скрипты + создание мира в редакторе) Как сделать игру на Unity 5 #28 Стартовое меню в игре (+статические переменные для передачи данных из сцены в сцену) Обзор Timeline в Unity 2017.1 + гайд с вариантами использования (создание смены дня и ночи) Unity 2017.1 Cinemachine — основы, принцип работы, интеграция с Timeline Unity 5: Как получить и обработать клик по объекту на сцене с помощью Event System Unity изменение переменной другого скрипта (создание хп банки и выстрел по врагу) Unity 3D - Создание миникарты с метками, работа со слоями Мини - Карта [СОЗДАНИЕ MiniMap] | Unity 5 Как сделать паузу в Unity 3D | Unity 5 Создаем и настраиваем сцены в Unity3d как PRO Unity3d Скриптинг. Урок 8. Доступ к компонентам с помощью GetComponent Атрибуты Уроки по Unity3d #12 - Система событий (EventSystem) логово маньяка Unity и C#: обращение к переменным другого скрипта или объекта Обзор плагина PlayMaker для Unity 3D Level Design в Unity с нуля #2 - прототипирование [ENG SUBS] Unity3D UI: Урок 5 - События. EventSystem, EventTrigger Модуль 40. Делегаты. Видеокурс по C# Добавляем танку полоску здоровья в Unity3d (метка на экране не уменьшающаяся и видная через препятствия) Каналы и плейлисты с уроками по Юнити Официальные уроки Unity Юнити на русском Deatrocker Плейлист: Разработка игр на Unity Плейлист C# с канала Byte++
  1. Загрузить ещё активность
  • Newsletter

    Want to keep up to date with all our latest news and information?

    Sign Up
×