forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Уроки (http://forum.boolean.name/forumdisplay.php?f=145)
-   -   Unity3d - Простой AI (http://forum.boolean.name/showthread.php?t=12712)

pax 23.06.2010 19:36

Unity3d - Простой AI
 
Данный урок является результатом поставленной задачи в этом посте.

Сначала немного теории.

Прежде всего, чтобы понять, как правильно создавать игровой мир в Unity3d, стоит рассказать о его составляющих.
Первое на что стоит обратить внимание – это объект игры (GameObject). Это основной элемент игрового мира, который содержит в себе компонент по умолчанию Transform, определяющий положение, размер и ориентацию объекта в сцене. Каждый объект игры может содержать любое количество компонентов (можно их назвать скриптами), которые определяют поведение данного объекта в сцене. Некоторые компоненты могут требовать наличие других компонентов для правильной работы. Например, в прошлой статье я приводил пример назначения компонента Rigid Body кубикам, которые уже имели компонент Box Collider. Взаимодействие между данными компонентами позволяло кубику вести себя в сцене как физическому объекту, который может падать и сталкиваться с другими кубиками и другими объектами сцены, имеющими компоненты Collider.

Как я уже говорил, каждый объект игры может иметь компоненты, определяющие его поведение. Поведение может быть не явное, как в приведенном выше примере, а выполнять какие-то действия разово или на протяжении какого-то времени. Например, игровой объект может создавать другие объекты при запуске сцены, играя роль «инициализатора» игрового мира; может выполнять какие-то действия периодически, например, уничтожил ли игрок всех врагов в сцене или нет, и если уничтожил, то выполнить действия по завершению уровня.
Префаб (Prefab) – подготовленный заранее объект игрового мира. Он может содержать в себе любой сложности заготовленную структуру. Создается он очень просто: 1) В сцене создается игровой объект любой сложности; 2) в окне Project создается Prefab так же как и создается любой скрипт; 3) перетаскиванием из окна сцены созданного игрового объекта на созданный в окне Project префаб в сцене этот объект становится экземпляром префаба, а та пустая заготовка ранее созданная в окне Project становится заготовленным объектом.

Здесь следует отметить, что если префабами являются игровые объекты, содержащие в себе компоненты для визуализации моделей (Mesh Filter и Mesh Renderer), то Unity3d автоматически использует технологию инстансинга для визуализации групп одинаковых объектов.
Думаю, данного введения будет достаточно для понимания данного урока, поэтому перейдем к практической части.

Начинаем делать заготовки.
  1. Для начала нам понадобится создать пустой проект, как это было описано в предыдущем уроке.
  2. Создадим в окне Project четыре папки: Scripts, Prefabs, Scenes и Materials.
  3. Создаем в папке Scripts два скрипта с названиями Player, Enemy.
  4. В папке Prefabs создаем два пустых префаба с такими же именами (Player, Enemy).
  5. В папке Materials создадим два материала PlayerMaterial и EnemyMaterial и дадим им зеленый и оранжевый цвет соответственно.
  6. В папку Scenes сохраняем текущую сцену под названием Game.

Должно получиться примерно так, как показано на следующем скриншоте:


Мы сначала реализуем поведение игрока, потом сделаем заготовку для поведения врага.
Итак, переходим в выбранный вами редактор кода (в моем случае Visual Studio) двойным щелчком по скрипту «Player» и помещаем в него следующий код:
PHP код:

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»:
PHP код:

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.forwardplayerDirection);

        
// максимальный угол поворота на текущем кадре
        
float maxAngle turnSpeed Time.deltaTime;

        
// Вычисляем прямой поворот на игрока
        
Quaternion rot Quaternion.LookRotation(_playerTransform.position _thisTransform.position);

        
// поворачиваем врага на игрока с учетом скорости поворота
        
if (maxAngle angle)
        {
            
_thisTransform.rotation Quaternion.Slerp(_thisTransform.rotationrotmaxAngle 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);
    }


Подготавливаем сцену
На данном этапе Вы уже должны понимать, как работают скрипты поведения каждого из трех объектов, назначение каждого из используемых окон среды. Если что-то осталось непонятно, то попробуйте перечитать эту статью или вернуться к предыдущей статье.
  1. Возвращаемся в среду Unity3d и создаем три игровых объекта в сцене: два кубика и план.
  2. У кубиков удаляем Box Collider и добавляем компонент Character Controller, с помощью которого будем управлять игроком и врагами.
  3. Назначаем кубикам материалы перетаскиванием.
  4. Зададим плану масштаб(Scale) (100,1,100) для того, чтобы он принял размеры, требуемые по заданию (по умолчанию он размером 10х10) и поместим его в ноль координат, если он был создан не в нуле. На нем по умолчанию установлен компонент Mesh Collider, который позволит нашим кубикам не проваливаться.
  5. Выбираем первый кубик и добавляем ему компонент Player. Перетаскиваем этот кубик на префаб с названием Player.
  6. Выбираем второй кубик и добавляем ему компонент Enemy. Перетаскиваем этот кубик на префаб с названием Enemy.
  7. Переименовываем объекты в сцене в соответствии с их назначением.
  8. Вы должны уже были заметить, что после создания из объекта префаба – его название в сцене становится синего цвета.
  9. Расставляем наши объекты в сцене, так как нужно, создав заранее еще два экземпляра префаба Enemy просто перетащив его в сцену.
  10. Переименуем врагов так как в задании)).
    У меня получилось примерно так:

  11. Сохраняем сцену и запускаем.

Как всегда результат.

burovalex 15.02.2013 18:36

Ответ: 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 - это берется вектор в прямом направлении?


Ответь Пожалуйста кто на что сможет
БУДУ ОЧЕНЬ БЛАГОДАРЕН

is.SarCasm 15.02.2013 19:28

Ответ: 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, относительно этого объекта

burovalex 15.02.2013 20:41

Ответ: Unity3d - Простой AI
 
СПАСИБО БОЛЬШОЕ!! Хоть чтото прояснилось.

Можете еще ссылку на пример или пример написать
Как можно создать массив и вего поместить какие-нибудь объекты (например кубики) и произвольно со временем удалять объекты.

pax 15.02.2013 21:06

Ответ: 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: тут я приводил пример создания поля из объектов, сохраняя ссылки на них в думерном массиве

burovalex 15.02.2013 22:11

Ответ: 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);       
        }
}


burovalex 15.02.2013 22:13

Ответ: Unity3d - Простой AI
 
И еще вопросик )
А можно в консоле отображать данные - использовать как дебагер, или еще куда-нибудь в другое место печатать?

Я себя чуствую как полный нуб! Не думал что так сложно будет перейти с блитца на с# ...

Andvrok 16.02.2013 01:09

Ответ: Unity3d - Простой AI
 
PHP код:

Debug.Log("text"); 


pax 16.02.2013 10:49

Ответ: Unity3d - Простой AI
 
PHP код:

Rigidbody instancer = (Rigidbody)Instantiate(MeshToInstance); 

Тут необходимо явно привести тип UnityEngine.Object к Rigidbody. Для этого перед выражением ставится название типа в скобках. Но я обычно всегда инстанцирую геймобъекты, а не их компоненты.

PHP код:

void Start()
    {
        
Invoke("Launch",2);    
    } 

Функция Example сама по себе не запустится, запускаются определенные эвенты

Про консоль: Debug.Log(данные); или print(данные);

Цитата:

Сообщение от burovalex (Сообщение 252892)
не думал, но оказывается приколько когда язык известный - можно пользоваться в разных движках, буду учиться )

Это основная причина, по которой я советую изучать C# для скриптов Unity, а не js

burovalex 16.02.2013 18:36

Ответ: Unity3d - Простой AI
 
Начал с нуля всё изучать, т.е. смотреть как типы даных объявляются и заодно для себя начал выкидывать инфу в chm. Как думаете, нужны такие наработки, или уже хватает?
Если да, то подскажите какой адрес надо писать для внутренних гиперссылок
Вот наброски: http://www.sendspace.com/file/j9g31y
Жмём Click here to start download from sendspace

И еще такая тема. Когда пользовался блитцом, при использовании буленовских переменных, для инвертации значения просто писал так:
boole=(1-boole)
НО в с# такое не канает. В нём нет такой конвертации.
Что делать в таких случаях?


ЮХУУУ, уже начинаю потихоньку втягиваться, сам догадался boole=!boole; ))

burovalex 17.02.2013 15:45

Ответ: Unity3d - Простой AI
 
Чёт тишина, так делать справку или нет?

Еще вопросик
Как задавать значения вручную для Vector2,Vector3,Color
Только не так Vector2.x=1; Vector2.y=2;
А типо так Vector2=Vector2(1,2);
Подскажите

pax 17.02.2013 21:20

Ответ: Unity3d - Простой AI
 
Vector2 myVec= new Vector2(1,2);

ЕвГен 15.04.2014 13:11

Ответ: 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"( добавить ему жизни и при столкновение ее вычитать?)?

Randomize 16.04.2014 09:17

Ответ: Unity3d - Простой AI
 
Цитата:

Сообщение от pax (Сообщение 253030)
Vector2 myVec= new Vector2(1,2);

Вот, кстати, почему в Юнитях так принято создавать объекты сотнями? Там это дело хоть как оптимизируется (объектный пул, etc)?
Просто делать new в цикле по 500 раз и так каждый кадр - выглядит довольно страшно. А по инету сорсы гуляют и куда не глянь всюду ехал new через new. Понятно, что структуры копеечные, но если их скапливается достаточно много, то потом GC не охреневает с такого хламушника?

impersonalis 16.04.2014 11:19

Ответ: Unity3d - Простой AI
 
Теперь нам лень изощряться, оптимизировать код,
И интерфейс с дураками мы пишем из году в год,
Свыклись с мощной машиной, отвыкли от всякого риска.


Часовой пояс GMT +4, время: 08:01.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot