Как сделать врага в unity 2d
Перейти к содержимому

Как сделать врага в unity 2d

  • автор:

Как сделать движение условного врага к игроку в юнити (RigidBody2d)

Я много где искал ответ и находил то что мне не совсем нужно. У меня есть игра видом Сверху, в ней расположен игрок и враг, враг должен преследовать игрока. Внимание, не через Transform а через RigidBody2D , т.е как видно враг должен преследовать игрока и просто долбиться в него. Мне не нужно ничего лишнего. Я пытался написать ИИ для врага используя уже написанный заранее скрипт передвижения игрока но таки не разобрался с направлением. Вот код движения игрока по которому я хотел сделать ИИ врагу. Цель: Сделать движение врага к игроку без использования Transform .

 public class PlayerMove : MonoBehaviour < private Vector2 MoveObject; private Rigidbody2D PhysicalMove; private int PlayerSpeed = 10; void Start() < PhysicalMove = GetComponent(); > void Update() < Vector2 InputData = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); MoveObject = InputData.normalized * PlayerSpeed; >private void FixedUpdate() < PhysicalMove.MovePosition(PhysicalMove.position + MoveObject * Time.fixedDeltaTime); >> 

Отслеживать

задан 9 апр 2022 в 13:45

462 4 4 серебряных знака 16 16 бронзовых знаков

Как сделать врага в unity 2d

Текущее время: 15 фев 2024, 13:59

Делаем простого врага.

Научился сам? Помоги начинающему.
Сообщений: 5 • Страница 1 из 1

Делаем простого врага.

gogogo3 24 ноя 2014, 11:14

Здравствуйте, сейчас я поделюсь информацией — как сделать простого врага?
У меня версия Unity3D 4.6.0 Beta
В уроке всего 7 шагов.
1. Создаём новый объект GameObject > 3D Object > Cube. Переместите его в нужное место.
2. Создадим скрипт на C# и назовём его Enemy. ВНИМАНИЕ! Если вы его назовёте по-другому, то скрипт может не работать! Особенно у тех, кто пишет с ошибками.
3. Откроем скрипт и сотрите всё, что в нём есть, и скопируйте и вставьте вот этот код:

Синтаксис:
Синтаксис: [ Показать ]
Используется csharp

using UnityEngine ;
using System.Collections ;

public class Enemy : MonoBehaviour {

public Transform player ;
public float move_speed ;
public float rotation_speed ;
public Transform enemy ;
void Update ( )
{
var look_dir = player. position — enemy. position ;
look_dir. y = 0 ;
enemy. rotation = Quaternion. Slerp ( enemy. rotation ,Quaternion. LookRotation ( look_dir ) ,rotation_speed * Time. deltaTime ) ;
enemy. position += enemy. forward * move_speed * Time. deltaTime ;
}
} 

4. После этого сохраните скрипт.
5. Повесьте(прикрепите) скрипт к врагу, которому мы создавали, то есть к объекту.
Там в настройках скрипта после прикрепления, мы видим 4 поля: Player, Move_speed, Rotation_speed, Enemy.
6. В поле Player скидываем нашего персонажа которым мы будем управлять. Это может быть First Person Controller или если вы делаете для мобильных устройств, то заходите в First Person Controls потом снова First Person Controls и вы увидите Player вот и скидываете его.
В поле Move_speed указываем скорость передвижения врага, в моём случае это будет 3.
В поле Move_speed указываем скорость поворотов врага, в моём случае это будет 5.
В поле Enemy скидываем самого врага(объекта).
7. В настройке мы всё сделали, теперь создаём новый компонент RigidBody к врагу. Ничего не меняйте в настройках компонента!
Вот и всё, враг создан, теперь можете запустить игру и проверить Враг будет просто за вами ходить.
Если будут вопросы, пишите в эту тему. Кто не зарегистрирован на этом форуме, зарегистрируйтесь, если хотите задать вопрос
До встречи, приятного программирования и создания игры!

gogogo3 UNITрон Сообщения: 189 Зарегистрирован: 24 ноя 2014, 10:45

Re: Делаем простого врага.

lawson 24 ноя 2014, 12:42

Как сделать движения врага в Unity 2D?

65424409e08aa084924523.png

Так что бы враг двигался в верх — в низ

  • Вопрос задан 01 нояб. 2023
  • 33 просмотра

1 комментарий

Простой 1 комментарий

TosterModerator

Модератор @TosterModerator

На вопрос «как сделать» отвечает документация и поиск в интернет.

Тут отвечают на вопросы «почему я сделал, как в документации, а оно не работает. Поискал в интернет, вот запросы, в ответах не нашел. Что я делаю не так?»

Покажите, как вы пробовали решить проблему, приведите код попытки (пусть неудачной), опишите, как запускали, что ожидали и что получилось.
За готовыми решениями — на фриланс. В текущем виде это не вопрос, а задание. Нарушен п.5.12 Регламента.

Разные типы врагов Unity3D

Как правильно делаются разные типы врагов в Unity3D? У врагов должна быть разный массив спрайтов, разная анимация, и разное поведение.
Я сделал скрипт:

using UnityEngine; using System.Collections; [ExecuteInEditMode] [RequireComponent(typeof(SpriteRenderer))] [RequireComponent(typeof(Animator))] [RequireComponent(typeof(BoxCollider2D))] [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(ChangerLayer))] public class EmenyScript : MonoBehaviour < private SpriteRenderer spriteRenderer; private Animator animator; private BoxCollider2D collider; private Rigidbody2D rigidBody; private ChangerLayer changerLayer; void Awake() < spriteRenderer = GetComponent(); animator = GetComponent(); collider = GetComponent(); rigidBody = GetComponent(); changerLayer = GetComponent(); rigidBody.isKinematic = true; > >

Этот скрипт натягиваю на каждый GameObject врага, потом ручками создаю анимацию, добавляю AnimatorController в Animator, создаю конкретный скрипт конкретного врага и натягиваю на этот GameObject. Потом создаю префаб.

Так это делается? Или есть более лучший способ создание разных врагов?

#1
11:22, 10 авг 2017

bretbas
> Так это делается? Или есть более лучший способ создание разных врагов?

> создаю конкретный скрипт конкретного врага и натягиваю на этот GameObject
если с наследованием от базового класса поведения, то да

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

#2
14:23, 10 авг 2017

Chupakaber, Код, который я написал выше, уместно использовать для определения общих компонентов всех врагов?
Я не сильно Вас понял. Вы написали:

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

Но зачем делать общий интерфейс, и где его делать, если:
1. Все враги — это GameObject, и я могу использовать их в одной коллекции соответственно
2. От GameObject наследовать нельзя, поэтому как я сделаю общий интерфейс, как вы написали?

Опять же спрашиваю, если я просто добавлю на каждого врага тот скрипт, который описал выше, и потом уже буду каждого настраивать ручками, добавлять конкретизированные скрипты для того или иного врага и тд, будет ли этот подход правильный? Да, и потом все это в префабы запихну

#3
14:48, 10 авг 2017

bretbas
> 1. Все враги — это GameObject, и я могу использовать их в одной коллекции
> соответственно
> 2. От GameObject наследовать нельзя, поэтому как я сделаю общий интерфейс, как
> вы написали?
Я хз, как в юнити, но суть в чём. Есть интерфейс «враг» со всеми ресурсами, есть наследники, которые эти ресурсы устанавливают и логику описывают.

#4
15:10, 10 авг 2017

bretbas
> Но зачем делать общий интерфейс, и где его делать, если:

> 2. От GameObject наследовать нельзя, поэтому как я сделаю общий интерфейс, как
> вы написали?
наследоваться можно от «MonoBehaviour» , это любой компонент GameObject’а. и в нем есть ссылка на сам GameObject

> 1. Все враги — это GameObject, и я могу использовать их в одной коллекции
> соответственно
если будешь проходиться по коллекции и вызывать поведенческие методы циклические, то придется брать компонент поведения (скрипт/класс) при помощи GetComponent(), не самый эффективный способ
если есть скрипт «EmenyScript» (что бы это ни значило, полагаю буквы местами перепутаны просто), то логичнее именно эти классы в коллекции хранить, и внутри них уже ссылки на GameObject (по умолчанию есть) и графический компонент, который универсален (полагаю что так) для всех врагов

допустим есть враги — 1. лучник, 2. мечник, 3. лекарь, у них есть в поведении одинаковые детали — если нужно дойти до определенной точки маршрута — они пойдут все одинаково
и есть отличающиеся — когда атакует лучник — он начнет это делать с расстояния, и будет стараться держать дистанцию, а мечник будет бегать за врагом, лекарь же сперва проверит. ненадо ли кого полечить. а если нет друзей тогда уже будет отбиваться сам

таким образом часть поведения — общая, другая часть — уникальная
общую часть можно наследовать от базового класса поведения (EnemyBehavior), а уникальную уже переопределять (override для virtual методов) в результирующих классов (ArcherBehavior : EnemyBehavior, SwordsmanBehavior : EnemyBehavior)

либо не наследовать, а использовать интерфейсы, т.е. не будет базового класса как такового и даже абстрактного класса не будет, будут только «правила», определяющие что у этих классов есть общее, а именно — должны быть методы: 1. движения по маршруту, 2. атаки, 3. убегания, 4. всякие реакции на события и т.д.
и коллекция будет уже не по классу а по интерфейсу, это немного не так удобно, но тоже допустимо, и в некоторых случаях более гибко

есть ещё вариант — на все возможные события в игре подписываться каждым уникальным классом, тогда никакого наследования и интерфейсов, никаких коллекций и вообще никаких узких мест, всё супер гибко, но супер-запутано будет думаю, в общем дело вкуса, подпиской на события тоже надо уметь пользоваться

ещё нюанс — вязать отображение (графику — спрайты, модели, материалы) и поведение в один класс не стоит, потеря гибкости и лапшекод нечитаемый. так что с этим всё верно — игровой объект это один класс (компонент Monobehaviour), а поведение — другой

Dimich
> Я хз, как в юнити, но суть в чём. Есть интерфейс «враг» со всеми ресурсами,
> есть наследники, которые эти ресурсы устанавливают и логику описывают.
в юнити всё довольно гибко, можно сделать по человечески, как ты описываешь
главное не зацикливаться на том, что есть уже готовый функционал и не думать что нужно пользоваться только им. его конечно нужно расширять и игнорировать то, что тебе мешает сделать нормально (:

#5
16:22, 10 авг 2017

Chupakaber, Все что ты написал, я понимаю:) Мне просто не привычно наследоваться от компонент, а не от GameObject. В своем движке, когда я писал его, я сделал так, чтобы можно было наследоваться от GameObject и определить в нем заранее нужные для этого GameObject’а компоненты. Плюс я определял нужные данные в этом же наследнике, чтобы не вызывать долгие методы, аля GetComponent<> и тд. Выглядело это примерно так:
GameObject -> Vehicle -> Tank -> Tank1, Tank2, Tank3

Вообщем теперь нужно немного по другому думать. Допустим у меня есть определенное движение у каждого врага, уникальное у каждого — кто-то прыгает, кто-то ходит по зигзагу, кто-то просто идет прямо и тд. Но все они в любом случае перемещаются по одной оси.

Следовательно общий скрипт перемещения по оси будет один. Назовем его MovingEnemyScript.
Также у каждого врага должны быть по любому следующие стандартные компоненты: SpriteRenderer, Animator, BoxCollider2D, RigidBody2D ну и еще может быть какие-то.

Я должен определить базовый класс EnemyController, который будет добавлять(если нет) все компоненты, которые я описал выше: SpriteRenderer, Animator, BoxCollider2D, RigidBody2D, MovingEnemyScript.
Получаем такой код соответственно:

using UnityEngine; using System.Collections; [ExecuteInEditMode] [RequireComponent(typeof(SpriteRenderer))] [RequireComponent(typeof(Animator))] [RequireComponent(typeof(BoxCollider2D))] [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(ChangerLayer))] [RequireComponent(typeof(MovingEnemyScript))] public class EmenyScript : MonoBehaviour < private SpriteRenderer spriteRenderer; private Animator animator; private BoxCollider2D collider; private Rigidbody2D rigidBody; private ChangerLayer changerLayer; private MovingEnemyScript moveEnemy; void Awake() < spriteRenderer = GetComponent(); animator = GetComponent(); collider = GetComponent(); rigidBody = GetComponent(); changerLayer = GetComponent(); moveEnemy = GetComponent(); rigidBody.isKinematic = true; > >

Затем наследуем от него, и делаем у каждого врага поведения движения(прыжок, ход по зигзагу и тд).

Можно и по другому сделать.
Можно выделить просто базовый класс хотьбы:

using UnityEngine; using System.Collections; public class EmenyMoveScript : MonoBehaviour

И от него уже наследовать движения (прыжок, ход по зигзагу и тд).
А вот этот скрипт уже отдельно на каждый GameObject врага пихать:

using UnityEngine; using System.Collections; [ExecuteInEditMode] [RequireComponent(typeof(SpriteRenderer))] [RequireComponent(typeof(Animator))] [RequireComponent(typeof(BoxCollider2D))] [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(ChangerLayer))] [RequireComponent(typeof(MovingEnemyScript))] public class EmenyScript : MonoBehaviour < private SpriteRenderer spriteRenderer; private Animator animator; private BoxCollider2D collider; private Rigidbody2D rigidBody; private ChangerLayer changerLayer; private MovingEnemyScript moveEnemy; void Awake() < spriteRenderer = GetComponent(); animator = GetComponent(); collider = GetComponent(); rigidBody = GetComponent(); changerLayer = GetComponent(); moveEnemy = GetComponent(); rigidBody.isKinematic = true; > >

#6
17:09, 10 авг 2017

moveEnemy = GetComponent();

если ты префаб собираешь всё равно — сделай свойство публичным и ручками накидай

тогда ты сможешь от MovingEnemyScript отнаследоваться в EmenyMoveScript, Emeny2MoveScript и т.д. и этот компонент ручками перетянутый в свойство moveEnemy подцепится по базовому классу MovingEnemyScript

в юнити управление кодом не всегда лучше «визуального программирования» (: хоть там и паблик свойства будут лишние, но тебе я думаю от них хуже не будет, тем более гибче сможешь в ним обращаться из соседних компонентов через основной, если обратные ссылки проставишь (а они думаю понадобятся если не усеешь всё событийно-ориентированным подходом)

UPD: короче, возми просто и отбрось названия классов юнитевские, и воспринимай MonoBehaviour класс как GameObject , а GameObject просто как посредник, просто компонент основного твоего класса «врага»
т.е. представь зависимости GameObject и класса отнаследованного от MonoBehaviour в зеркальном виде, и всё встанет на свои места

#7
17:40, 10 авг 2017

в юнити управление кодом не всегда лучше «визуального программирования»

Вот, в точку! Я из-за этого и путаюсь. На самом деле, я все это дело вижу так:

1. Делаем скрипт, который добавляет автоматически нужные компоненты для врага( чтобы я ручками каждый раз не собирал его )

тогда ты сможешь от MovingEnemyScript отнаследоваться в EmenyMoveScript, Emeny2MoveScript и т.д. и этот компонент ручками перетянутый в свойство moveEnemy подцепится по базовому классу MovingEnemyScript

2. Зачем тогда вообще наследование?:) Просто делаем разные скрипты для разных поведений врагов. Создаем разных врагов из пункта 1, и перетягиваем на каждый конкретный ему скрипт. Все. Зачем наследование и тд и тп?

3. С графикой аналогично. Так как мы добавили в пункте 1 компоненты SpriteRenderer и Animator, то просто опять для каждого врага настраиваем их определенным образом.

4. Запихиваем все это в префабы.

5. Пишем генератор для создания случайно выбранных врагов из определенной точки.

6. Запускаем и радуемся

#8
19:35, 10 авг 2017

bretbas
> 1. Делаем скрипт, который добавляет автоматически нужные компоненты для врага(
> чтобы я ручками каждый раз не собирал его )
ручками компоненты собираются один раз для префаба, а дальше можешь его клонировать и вносить тока мелкие изменения по параметрам например

bretbas
> 2. Зачем тогда вообще наследование?:) Просто делаем разные скрипты для разных
> поведений врагов. Создаем разных врагов из пункта 1, и перетягиваем на каждый
> конкретный ему скрипт. Все. Зачем наследование и тд и тп?
чтобы в том скрипте, в котором у тебя будет коллекция всех игровых объектов, ты не делал для каждого GetComponent да ещё как-то по тегу или названию выбирая какой класс тебе нужен
наследуешься от базового, в котором есть полный набор виртуальных методов, и обращаешься к каждому объекту в коллекции как к базовому классу
а поведение будет уже у них разное, как в переопределенных наследных классах

bretbas
> 3. С графикой аналогично. Так как мы добавили в пункте 1 компоненты
> SpriteRenderer и Animator, то просто опять для каждого врага настраиваем их
> определенным образом.
графику конечно придется визуально мышкой настраивать, кодом коротко и удобно не будет, кодом только для особых нестандартных случаев стоит графикой морочиться

и дальше да, генератор по хорошему должен быть из одной строчки:

public LinkedList objects = new LinkedList(); public CreateEnemy(string prefabName, Vector3 position, Quaternion rotation) < objects.AddLast(Instantiate(Resources.Load("Prefabs/Enemies/" + prefabName), position, rotation).GetComponent()); >

префабы должны при этом лежать в папке Assets/Resources/Prefabs/Enemies/
prefabName — название префаба
position — точка размещения нового врага в мире
rotation — понятно думаю, его вращение, куда он смотрит
objects — коллекция всех врагов с компонентом в наличии — базовым классом EnemyScript, или любым другим от него отнаследованным
из коллекции ты будешь сразу получать класс EnemyScript, а не GameObject, с которым лишние GetComponent нужны

всю настройку самих себя эти твои враги должны сделать сами в своем методе Start()

#9
19:53, 10 авг 2017

чтобы в том скрипте, в котором у тебя будет коллекция всех игровых объектов, ты не делал для каждого GetComponent да ещё как-то по тегу или названию выбирая какой класс тебе нужен

В каком скрипте у меня должна быть коллекция игровых объектов? Я этого не говорил. Я говорил, что просто хочу реализовать разное поведение у врагов и все. Но чтобы они полиморфно где-то лежали. я этого не сказал.
У каждого уникального скрипта поведения врага, есть Update(), так пусть он и выполняется для этого врага. Но в кучу собирать всех врагов, пока что мне не нужно:)

и дальше да, генератор по хорошему должен быть из одной строчки

Я вот такой написал:

void Update () < accumulator += Time.deltaTime; if( accumulator >= interval ) < BoxCollider2D componentCollider = areaEnemyAppear.GetComponent(); float halfHeightArea = componentCollider.size.y / 2; float halfWidthArea = componentCollider.size.x / 2; Vector3 positionArea = areaEnemyAppear.transform.position; foreach( var enemyObject in enemyObjects ) < Vector3 position = new Vector3( Random.Range( positionArea.x - halfWidthArea, positionArea.x + halfWidthArea ), Random.Range( positionArea.y - halfHeightArea, positionArea.y + halfHeightArea ) ); Instantiate( enemyObject, position, Quaternion.identity ); >accumulator = 0; > >

Где enemyObjects — массив врагов, которые передаются через инспектор. Я думаю так удобно, так как я могу быстренько убрать для генерации того или иного врага.
areaEnemyAppear — GameObject, у которого есть BoxCollider2D. Он служит площадкой, внутри которой будут генерироваться враги.
interval — генератор служит как бы таймером для генерации, поэтому это время, когда таймер должен сработать. Задается также через инспектор. Можно в принципе разделить таймер и генератор на два скрипта.

#10
20:46, 10 авг 2017

bretbas
> Но чтобы они полиморфно где-то лежали.
ну пусть они полиморфно нигде не лежат
но полиморфно взаимодействовать они же будут? например какие-то базовые параметры у них общие, элементы поведения, рассчет атаки/ущерба там
это же нужно? или будет отдельный компонент без наследования эти общие для всех штуки содержащий?

#11
21:13, 10 авг 2017

ну пусть они полиморфно нигде не лежат
но полиморфно взаимодействовать они же будут? например какие-то базовые параметры у них общие, элементы поведения, рассчет атаки/ущерба там
это же нужно? или будет отдельный компонент без наследования эти общие для всех штуки содержащий?

Ладно, это уже пошло угадывание:) Враги умирают с одного выстрела, сами они атаки не имеют. Вообщем, если разобраться, а я уже в принципе разобрался. у них общее только набор компонентов, больше ничего в них общего то и нет.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *