|
23.06.2010, 19:36
|
#1
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Unity3d - Простой AI
Данный урок является результатом поставленной задачи в этом посте.
Сначала немного теории.
Прежде всего, чтобы понять, как правильно создавать игровой мир в Unity3d, стоит рассказать о его составляющих.
Первое на что стоит обратить внимание – это объект игры (GameObject). Это основной элемент игрового мира, который содержит в себе компонент по умолчанию Transform, определяющий положение, размер и ориентацию объекта в сцене. Каждый объект игры может содержать любое количество компонентов (можно их назвать скриптами), которые определяют поведение данного объекта в сцене. Некоторые компоненты могут требовать наличие других компонентов для правильной работы. Например, в прошлой статье я приводил пример назначения компонента Rigid Body кубикам, которые уже имели компонент Box Collider. Взаимодействие между данными компонентами позволяло кубику вести себя в сцене как физическому объекту, который может падать и сталкиваться с другими кубиками и другими объектами сцены, имеющими компоненты Collider.
Как я уже говорил, каждый объект игры может иметь компоненты, определяющие его поведение. Поведение может быть не явное, как в приведенном выше примере, а выполнять какие-то действия разово или на протяжении какого-то времени. Например, игровой объект может создавать другие объекты при запуске сцены, играя роль «инициализатора» игрового мира; может выполнять какие-то действия периодически, например, уничтожил ли игрок всех врагов в сцене или нет, и если уничтожил, то выполнить действия по завершению уровня.
Префаб (Prefab) – подготовленный заранее объект игрового мира. Он может содержать в себе любой сложности заготовленную структуру. Создается он очень просто: 1) В сцене создается игровой объект любой сложности; 2) в окне Project создается Prefab так же как и создается любой скрипт; 3) перетаскиванием из окна сцены созданного игрового объекта на созданный в окне Project префаб в сцене этот объект становится экземпляром префаба, а та пустая заготовка ранее созданная в окне Project становится заготовленным объектом.
Здесь следует отметить, что если префабами являются игровые объекты, содержащие в себе компоненты для визуализации моделей (Mesh Filter и Mesh Renderer), то Unity3d автоматически использует технологию инстансинга для визуализации групп одинаковых объектов.
Думаю, данного введения будет достаточно для понимания данного урока, поэтому перейдем к практической части.
Начинаем делать заготовки.
- Для начала нам понадобится создать пустой проект, как это было описано в предыдущем уроке.
- Создадим в окне Project четыре папки: Scripts, Prefabs, Scenes и Materials.
- Создаем в папке Scripts два скрипта с названиями Player, Enemy.
- В папке Prefabs создаем два пустых префаба с такими же именами (Player, Enemy).
- В папке Materials создадим два материала PlayerMaterial и EnemyMaterial и дадим им зеленый и оранжевый цвет соответственно.
- В папку Scenes сохраняем текущую сцену под названием Game.
Должно получиться примерно так, как показано на следующем скриншоте:
Мы сначала реализуем поведение игрока, потом сделаем заготовку для поведения врага.
Итак, переходим в выбранный вами редактор кода (в моем случае Visual Studio) двойным щелчком по скрипту «Player» и помещаем в него следующий код:
using UnityEngine;
public class Player : MonoBehaviour { // скорость ходьбы и скорость поворота в секунду public float moveSpeed = 2; public float turnSpeed = 90;
private CharacterController _controller; private Transform _thisTransform;
public void Start() { // Получаем контроллер _controller = GetComponent<CharacterController>();
// Получаем компонент трансформации объекта, к которому привязан данный компонент _thisTransform = transform; }
public void FixedUpdate() { // Рассчитываем позицию _controller.Move(_thisTransform.forward * moveSpeed * Time.deltaTime * Input.GetAxis("Vertical") + Vector3.down * 10.0f * Time.deltaTime);
// Рассчитываем поворот Quaternion rot = Quaternion.AngleAxis( turnSpeed * Time.deltaTime * Input.GetAxis("Horizontal"), Vector3.up); _thisTransform.rotation *= rot; } }
То же самое делаем со скриптом «Enemy»:
using UnityEngine;
public class Enemy : MonoBehaviour { // скорость ходьбы и скорость поворота в секунду public float moveSpeed = 2; public float turnSpeed = 90;
private CharacterController _controller; private Transform _thisTransform; private Transform _playerTransform;
public void Start() { // Получаем контроллер _controller = GetComponent<CharacterController>();
// Получаем компонент трансформации объекта, к которому привязан данный компонент _thisTransform = transform;
// Получаем компонент трансформации игрока Player player = (Player)FindObjectOfType(typeof(Player)); _playerTransform = player.transform; }
// Все что связано с физикой выполняем в FixedUpdate public void FixedUpdate() { // направление на игрока Vector3 playerDirection = (_playerTransform.position - _thisTransform.position).normalized;
// угол поворота на игрока float angle = Vector3.Angle(_thisTransform.forward, playerDirection);
// максимальный угол поворота на текущем кадре float maxAngle = turnSpeed * Time.deltaTime;
// Вычисляем прямой поворот на игрока Quaternion rot = Quaternion.LookRotation(_playerTransform.position - _thisTransform.position);
// поворачиваем врага на игрока с учетом скорости поворота if (maxAngle < angle) { _thisTransform.rotation = Quaternion.Slerp(_thisTransform.rotation, rot, maxAngle / angle); } else { _thisTransform.rotation = rot; }
// если дистанция до игрока больше трех метров if (Vector3.Distance(_playerTransform.position, _thisTransform.position) > 3.0f) { // двигаемся к игроку _controller.Move(_thisTransform.forward * moveSpeed * Time.deltaTime); } else // если меньше или равна трем метрам { // здесь например стреляем в игрока }
// гравитация _controller.Move(Vector3.down * 10.0f * Time.deltaTime); } }
Подготавливаем сцену
На данном этапе Вы уже должны понимать, как работают скрипты поведения каждого из трех объектов, назначение каждого из используемых окон среды. Если что-то осталось непонятно, то попробуйте перечитать эту статью или вернуться к предыдущей статье. - Возвращаемся в среду Unity3d и создаем три игровых объекта в сцене: два кубика и план.
- У кубиков удаляем Box Collider и добавляем компонент Character Controller, с помощью которого будем управлять игроком и врагами.
- Назначаем кубикам материалы перетаскиванием.
- Зададим плану масштаб(Scale) (100,1,100) для того, чтобы он принял размеры, требуемые по заданию (по умолчанию он размером 10х10) и поместим его в ноль координат, если он был создан не в нуле. На нем по умолчанию установлен компонент Mesh Collider, который позволит нашим кубикам не проваливаться.
- Выбираем первый кубик и добавляем ему компонент Player. Перетаскиваем этот кубик на префаб с названием Player.
- Выбираем второй кубик и добавляем ему компонент Enemy. Перетаскиваем этот кубик на префаб с названием Enemy.
- Переименовываем объекты в сцене в соответствии с их назначением.
- Вы должны уже были заметить, что после создания из объекта префаба – его название в сцене становится синего цвета.
- Расставляем наши объекты в сцене, так как нужно, создав заранее еще два экземпляра префаба Enemy просто перетащив его в сцену.
- Переименуем врагов так как в задании)).
У меня получилось примерно так:
- Сохраняем сцену и запускаем.
Как всегда результат.
Последний раз редактировалось pax, 16.02.2013 в 11:24.
|
(Offline)
|
|
Эти 14 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
|
Amatsu (16.02.2013), ARA (13.08.2010), baton4ik (05.08.2010), burovalex (15.02.2013), den (20.07.2010), Dream (23.06.2010), Fatalix3d (23.06.2010), jfkkk (23.06.2010), mauNgerS (15.02.2013), maxturbo (22.10.2010), Nex (24.06.2010), Nuprahtor (23.06.2010), Radnk (17.07.2012), SaM_ (16.06.2011)
|
15.02.2013, 18:36
|
#2
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
Помогите пожайлуста разобраться с синтаксисом, тяжело, я с блитца перехожу..
Пойду прямо по примеру.
private Transform _thisTransform;
private CharacterController _controller;
Так объявляются компоненты объектов?
_controller = GetComponent<CharacterController>();
Вот здесь вообще не понял, почему не в скобках, а рядом с ними и в треугольных. Нельзя както так писать _controller = This.GetComponent(CharacterController) ??
_thisTransform = transform;
переменной присвается трансформация понятно, но чья? самого себя?
Т.е. можно написать _thisTransform = This.transform
Player player = (Player)FindObjectOfType(typeof(Player));
Здесь вообще не понял,
1-й Player что означает, это чтото типа CharacterController или что??
2-й player (понятно что переменная)!
3-й (Player) тоже не понял, почему он в скобках?
4-й typeof(Player) это что значит, под типом подразумевается объект к которому скрипт с названием Player прикреплён ??
float angle = Vector3.Angle(_thisTransform.forward, playerDirection);
Vector3 означает взять 3-й компонент вектора чтоли? т.е. z или как??
_thisTransform.forward - это берется вектор в прямом направлении?
Ответь Пожалуйста кто на что сможет
БУДУ ОЧЕНЬ БЛАГОДАРЕН
__________________
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
15.02.2013, 19:28
|
#3
|
Бывалый
Регистрация: 17.05.2009
Адрес: Днепропетровск
Сообщений: 672
Написано 180 полезных сообщений (для 428 пользователей)
|
Ответ: Unity3d - Простой AI
Так объявляются компоненты объектов?
|
Так вообще объявляются объекты. Точно также как в блице Field int x; или как там.
Вот здесь вообще не понял, почему не в скобках, а рядом с ними и в треугольных. Нельзя както так писать _controller = This.GetComponent(CharacterController) ??
|
Можно написать This.GetComponent("CharacterController") , но это не круто. Смотри справку.
1-й Player что означает, это чтото типа CharacterController или что??
|
Это , похоже, заранее определенный класс.
3-й (Player) тоже не понял, почему он в скобках?
|
Это тоже самое что написать "as Player". То есть найденный объект переводится в Player (это как из float в int, например) или из найденного объекта берется компонент "Player"
4-й typeof(Player) это что значит, под типом подразумевается объект к которому скрипт с названием Player прикреплён ??
|
Смотри справку
Vector3 означает взять 3-й компонент вектора чтоли? т.е. z или как??
|
Это класс, такой же как string, gameObject или transform. По сути это класс состоящий из трех float'ов x,y,z и статических функций. Опять справка: http://docs.unity3d.com/Documentatio...e/Vector3.html
_thisTransform.forward - это берется вектор в прямом направлении?
|
Вектор вперед по Z, относительно этого объекта
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо is.SarCasm за это полезное сообщение:
|
|
15.02.2013, 20:41
|
#4
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
СПАСИБО БОЛЬШОЕ!! Хоть чтото прояснилось.
Можете еще ссылку на пример или пример написать
Как можно создать массив и вего поместить какие-нибудь объекты (например кубики) и произвольно со временем удалять объекты.
__________________
|
(Offline)
|
|
15.02.2013, 21:06
|
#5
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - Простой AI
Тоже прокомментирую
1. В данном случае поля класса объявляются синтаксисом: модификатор тип имя_переменной. private значит не публичное поле класса, Transform или CharacterController это типы, _thisTransform и _controller имена переменных. Подробнее тут, потом можно почитать тут, но уже сложнее.
2. Метод GetComponent<CharacterController>(); шаблонный. Подробнее тут. В угловых скобках указывается тип (в данном случае тип компонента, который надо найти на объекте).
3. _thisTransform = transform; тоже самое что и _thisTransform = this.transform; Т.е. переменной присваивается значение свойства transform. Это свойство, хоть и выглядит как переменная, выполняет действие подобное описанному в пункте 2 - получает с объекта компонент типа Transform. Т.е. запись _thisTransform = GetComponent<Transform>(). Подробнее о свойствах тут. Какие свойства есть у скрипта тут.
4. Player player = (Player)FindObjectOfType(typeof(Player));
Все что перед "равно" это объявление переменной player типа Player. Справа выполняется функция поиска объекта типа Player в сцене (скрипт на каком-либо объекте сцены). Но так как функция возвращает тип UnityEngine.Object от которого наследуются все объекты Unity (в том числе и скрипты - MonoBehaviour унаследован от Component, Component от UnityEngine.Object) - чтобы присвоить полученное значение переменной типа Player, полученное значение нужно привести к типу Player - это как раз (Player). Подробнее об этом тут. C# это строго типизированный язык. Все переменные должны иметь тип и могут содержать экземпляры данных, соответствующие этим типам. Еще почитать.
5. float angle = Vector3.Angle(_thisTransform.forward, playerDirection);
дословно: посчитать угол между двумя векторами _thisTransform.forward и playerDirection.
UPD: тут я приводил пример создания поля из объектов, сохраняя ссылки на них в думерном массиве
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
|
|
15.02.2013, 22:11
|
#6
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
Спасибо за помощь! не думал, но оказывается приколько когда язык известный - можно пользоваться в разных движках, буду учиться )
Поможете разобраться с примером, взял с Юнити, писал своими словами, но смысл тот же. Но почему то ругается что я пытаюсь конвертировать UnityEngine.Object в UnityEngine.Rigidbody. Я понимаю что это компонент объекта, а не объект.
Но подскажите плиз, как сделать чтоб не ругался.
Как я понял в примере должны появляться копии каждые две секунды в рандомных позициях
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public Rigidbody MeshToInstance;
// Update is called once per frame
void Launch() {
Rigidbody instancer = Instantiate(MeshToInstance);
instancer.velocity = Random.insideUnitSphere;
}
void Example()
{
Invoke("Launch",2);
}
}
__________________
|
(Offline)
|
|
15.02.2013, 22:13
|
#7
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
И еще вопросик )
А можно в консоле отображать данные - использовать как дебагер, или еще куда-нибудь в другое место печатать?
Я себя чуствую как полный нуб! Не думал что так сложно будет перейти с блитца на с# ...
__________________
|
(Offline)
|
|
16.02.2013, 01:09
|
#8
|
Бывалый
Регистрация: 26.07.2009
Сообщений: 785
Написано 362 полезных сообщений (для 995 пользователей)
|
Ответ: Unity3d - Простой AI
|
(Offline)
|
|
16.02.2013, 10:49
|
#9
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - Простой AI
Rigidbody instancer = (Rigidbody)Instantiate(MeshToInstance);
Тут необходимо явно привести тип UnityEngine.Object к Rigidbody. Для этого перед выражением ставится название типа в скобках. Но я обычно всегда инстанцирую геймобъекты, а не их компоненты.
void Start() { Invoke("Launch",2); }
Функция Example сама по себе не запустится, запускаются определенные эвенты
Про консоль: Debug.Log(данные); или print(данные);
Сообщение от burovalex
не думал, но оказывается приколько когда язык известный - можно пользоваться в разных движках, буду учиться )
|
Это основная причина, по которой я советую изучать C# для скриптов Unity, а не js
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
16.02.2013, 18:36
|
#10
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
Начал с нуля всё изучать, т.е. смотреть как типы даных объявляются и заодно для себя начал выкидывать инфу в chm. Как думаете, нужны такие наработки, или уже хватает?
Если да, то подскажите какой адрес надо писать для внутренних гиперссылок
Вот наброски: http://www.sendspace.com/file/j9g31y
Жмём Click here to start download from sendspace
И еще такая тема. Когда пользовался блитцом, при использовании буленовских переменных, для инвертации значения просто писал так:
boole=(1-boole)
НО в с# такое не канает. В нём нет такой конвертации.
Что делать в таких случаях?
ЮХУУУ, уже начинаю потихоньку втягиваться, сам догадался boole=!boole; ))
__________________
Последний раз редактировалось burovalex, 16.02.2013 в 23:03.
|
(Offline)
|
|
17.02.2013, 15:45
|
#11
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Unity3d - Простой AI
Чёт тишина, так делать справку или нет?
Еще вопросик
Как задавать значения вручную для Vector2,Vector3,Color
Только не так Vector2.x=1; Vector2.y=2;
А типо так Vector2=Vector2(1,2);
Подскажите
__________________
|
(Offline)
|
|
17.02.2013, 21:20
|
#12
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - Простой AI
Vector2 myVec= new Vector2(1,2);
|
(Offline)
|
|
15.04.2014, 13:11
|
#13
|
AnyKey`щик
Регистрация: 31.01.2013
Сообщений: 10
Написано 6 полезных сообщений (для 34 пользователей)
|
Ответ: Unity3d - Простой AI
Привет всем! Хочу сделать не большой проект в жанре FPS на Unity. До этого я не программировал, занимался только моделированием. Сейчас в сцене у меня Player у которого стандартный FPS_Controller и Enamy(Модель бота с анимацией, он может следовать за Player'ом с помощью NavMeshAgent и ему присвоен тэг "Enamy"), также есть перфаб Bullet(Игрок может стрелять физическими сферами) у Bullet есть скрипт:
void OnCollisionEnter(Collision collision){
if(collision.gameObject.tag=="Enamy" ){
Destroy(collision.gameObject);
Destroy(gameObject);
}
}
Т.Е. Игрок "выпускает" пулю и если она сталкивается с объектом у которого есть тэг "Enamy", тогда пуля и объект очищается.
Вопрос:
Как мне реализовать смерть "Enamy"( добавить ему жизни и при столкновение ее вычитать?)?
|
(Offline)
|
|
16.04.2014, 09:17
|
#14
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,361
Написано 2,473 полезных сообщений (для 6,856 пользователей)
|
Ответ: Unity3d - Простой AI
Сообщение от pax
Vector2 myVec= new Vector2(1,2);
|
Вот, кстати, почему в Юнитях так принято создавать объекты сотнями? Там это дело хоть как оптимизируется (объектный пул, etc)?
Просто делать new в цикле по 500 раз и так каждый кадр - выглядит довольно страшно. А по инету сорсы гуляют и куда не глянь всюду ехал new через new. Понятно, что структуры копеечные, но если их скапливается достаточно много, то потом GC не охреневает с такого хламушника?
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 4090 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
16.04.2014, 11:19
|
#15
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: Unity3d - Простой AI
Теперь нам лень изощряться, оптимизировать код,
И интерфейс с дураками мы пишем из году в год,
Свыклись с мощной машиной, отвыкли от всякого риска.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо impersonalis за это полезное сообщение:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 14:28.
|