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

от admin

2D игра на Unity. Подробное руководство. Часть 3

Снаряд – объект, которым мы будем пользоваться очень часто. В игре будет несколько сцен, в которых игрок будет стрелять. Что мы должны использовать в этом случае? Префаб (Prefab), конечно же! Для этого проделайте следующие действия:

  1. Импортируйте текстуру
  2. Создайте новый спрайт в сцене
  3. Установите изображение на спрайт.
  4. Добавьте «Rigidbody 2D» с равныим нулю значениями «Gravity Scale» и «Fixed Angles».
  5. Добавьте «Box Collider 2D» размером (1, 1) .

Сделайте масштаб таким (0,75, 0,75, 1) для лучшего отображения. Теперь, нам нужно установить новый параметр в «Инспекторе» (Inspector). для этого в «Box Collider 2D» поставьте галочку напротив свойства «IsTrigger». Триггер коллайдера создает событие при столкновении, но не используется при моделирования физики. Это значит, что выстрел пройдет сквозь объект при соприкосновении — никакого «реального» взаимодействия не будет. А вот у другого коллайдера это спровоцирует событие «OnTriggerEnter2D».

Та-дам! У нас появился выстрел. Теперь настало время немного поскриптить. Создайте скрипт, назвав его «ShotScript»:

Прикрепите «ShotScript» к спрайту. Также добавьте «MoveScript», т.к. ваши снимки будут двигаться. Теперь перетащите объект выстрел в панель «Проект» для создания Префаба. Он нам совсем скоро понадобится. Вы должны иметь следующую конфигурацию:

Конфигурация Выстрел 1

Если вы запустите игру с помощью кнопки «Play», вы увидите, что выстрел движется.

Столкновения и повреждения

Тем не менее, выстрел (пока) не наносит повреждений. Ничего удивительного, ведь мы не сделали скрипт обработки повреждений. Создадим его, назвав «HealthScript»:

Добавьте «HealthScript» на префаб спрута.

Убедитесь, что выстрел и спрут находятся на одной линии, чтобы проверить столкновение. Напоминаю, что 2D движок ничего не знает про ось Z, поэтому ваши 2D коллайдеры всегда будут в той же плоскости. А теперь, запустите нашу сцену. Вы должны увидеть следующее:

Здоровье врага превосходит урон от выстрела, поэтому он выживет. Попробуйте изменить значение hp в «HealthScript» врага:

Стрельба

Удалите выстрел из сцены. Теперь, когда мы с ним закончили, ему нечего там делать. Нам нужен новый скрипт для стрельбы. Создайте его под именем «WeaponScript». Этот скрипт мы будем использовать везде (игроки, враги и т.д.) Его цель заключается в to instantiate снаряда перед игровым объектом, к которому он привязан. Вот полный код, больше, чем обычно. Объяснения ниже:

Прикрепите этот скрипт к игроку. Скрипт делится на три части:

Переменные во вкладке «Inspector»

Здесь у нас есть два члена: shotPrefab и shootingRate .

Первый необходим для установки выстрела, который будет использоваться с этим оружием.

Выберите игрока в сцене «Hierarchy». В компоненте «WeaponScript», вы можете увидеть свойство «Shot Prefab» со значением «None». Перетащите префаб «Shot» на это место:

Использование префаба

Unity автоматически дополнит скрипт это информацией. Удобно, не так ли?

Переменная shootingRate имеет значение по умолчанию, установленное в коде. Мы не будем менять его на данный момент. Но вы можете начать игру и экспериментировать с ним, чтобы узнать на что она влияет.

Оружие обладает определенной частотой выстрелов. Без этого параметра можно было бы выпускать неограниченное количество патронов в каждом кадре.

Поэтому нам нужен простой механизм охлаждения. Если его значение превышает 0 , мы просто не можем стрелять. Мы вычитаем прошедшее время из каждого кадра.

3. Публичный метод создания атаки

Главная цель этого скрипта – активироваться через другой скрипт. Поэтому для создания снаряда мы используем публичный метод.

Создав екземпляр снаряда, мы извлекаем скрипты объекта выстрела и оверрайдим некоторые переменные.

Внимание: С помощью метода GetComponent<TypeOfComponent>() можно создать точный компонент (а значит, и скрипт, потому что скрипт – тоже компонент) объекта. Используйте generic ( <TypeOfComponent> ) для обозначения конкретного компонента, который вам нужен.
Кроме того, у нас есть GetComponents<TypeOfComponent>() , вызывающий список вместо первого и т.д.

Использование оружия с классом игрока

Если вы запустите сейчас игру, то увидите, что ничего не изменилось. Мы создали оружие, но оно совершенно бесполезно.

В самом деле, если «WeaponScript» был бы привязан к классу, мы никогда не смогли бы использовать метод Attack(bool) .

Давайте вернемся к нашему «PlayerScript».

В функции Update() добавьте этот кусочек кода:

На данном этапе неважно, поставите вы его перед или после движения.

  1. Мы определяем нажатие кнопки стрельбы ( click или ctrl по умолчанию).
  2. Извлекаем скрипт объекта.
  3. Мы запускаем Attack(false) .

Запустите игру с помощью кнопки «Play». Вот что вы должны получить:

Пули летят слишком медленно? Поэкспериментируйте с префабом «Shot» чтобы выбрать ортимальное значение. Попробуйте также добавить вращение игроку: (0, 0, 45) . Пули двигаються под углом 45 градусов, даже если вращение спрайта выстрела является некорректным – а ведь мы его не изменили.

Shooting rotation

Итак, у нас уже есть нечто похожее на шутер! Теперь вы умеете создавать оружие, которое может стрелять и уничтожить другие объекты. Давайте двигаться дальше. Мы хотим чтобы враги тоже могли стрелять.

Вражеский снаряд

Мы создадим новый снаряд с помощью этого спрайта:

Вражеский снаряд

Если вы так же ленивы, как я, продублируйте префаб «PlayerShot», переименуйте его в «EnemyShot1» и измените спрайт, как описано выше.

Для дублирования создайте экземпляр, перетащив его на сцену, переименовав созданный игровой объект и, наконец, сохранив его как `Prefab’.

Правильный масштаб — (0.35, 0.35, 1) .

Вот, что у вас должно получиться.

настойки для вражеского снаряда

При нажатии «Play» произойдет выстрел, который потенциально может уничтожить врага. Это из-за свойств «ShotScript» (которые по умолчанию плохо совместимы с Poulpi).

Не изменяйте ничего. Помните наш «WeaponScript»? Он то и установит правильные значения.

У нас есть префаб «EnemyShot1». Удалите экземпляры со сцены, если они есть.

Также, как мы делали для игрока, также нам нужно добавить оружие и врагу, а потом вызывать Attack() чтобы выстрелить. Вот, что нам надо сделать:

  1. Добавьте «WeaponScript» врагу.
  2. Перетащите префаб «EnemyShot1» в переменную «Shot Prefab» скрипта.
  3. Создайте новый скрипт под названием «EnemyScript». Он просто будет запускать стрельбу в каждом кадре. Что-то вроде автострельбы.

Прикрепите этот скрипт к осьминогу. У вас должно получиться следующее (заметьте, что частота стрельбы немного звеличилась до 0.75 ):

Настойка осьминога с оружием

Замечание: Если вы модифицируете игровой объект в сцене, не забудьте сохранить все изменения в префабе , использовав кнопку «Применить» справа сверху от панели «Инспектор».

Попробуйте сыграть и посмотреть!

Итак, мы сделали то, что хотели и теперь и по нам тоже стреляют.

Если повернуть врага, вы можете сделать его стреляющим в его слева, но, хм. спрайт повернулся вверх ногами, а нам это не нужно.

Перевернутый спрут

Давайте исправим это недоразумение.

Стрельба в любом направлении.

«WeaponScript» был написан особым образом: вы можете выбрать направление стрельбы, просто вращая прикрепленный игровой объект. Мы уже видели это раньше, когда вращали спрайт врага. Суть в том, чтобы создать пустой игровой объект как ребенка префаба врага. Итак, нам нужно:

  1. Создать пустой игровой объект. Назовем его «WeaponObject».
  2. Удалим «WeaponScript», прикрепленный к префабу врага.
  3. Добавим «WeaponScript» к «WeaponObject» и установить свойства префба выстрела как мы это делали раньше.
  4. Повернем «WeaponObject» вот так (0, 0, 180) .

Если вы проделали это все на игровом объекте, а не на префабе, то не забудьте нажать на кнопку «Применить» для сохранения изменений. Вот, что у нас получилось:

Enemy with a new object

However, we have a small change to make on the «EnemyScript» script.

В своем нынешнем состоянии вызов GetComponent<WeaponScript>() в «EnemyScript» возвращает null. В самом деле, «WeaponScript» больше не привязан к одному объекту игры.

К счастью, в Unity также доступен метод, использующий детскую иерархию игрового объекта, который называется GetComponentInChildren<Type>() .

На самом деле, просто для удовольствия, мы также добавили возможность управления несколькими видами оружия. Мы просто манипулируем списком вместо одного экземпляра компонента. Взгляните на весь «EnemyScript»:

Наконец, нужно обновить скорость выстрела путем настройки публичной пременной «MoveScript» из префаба «EnemyShot1». Скорость выстрела должна быть больше скорости движения спрута:

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

Стрельба а двух направлениях

Эта задача реализуеся всего в пару кликов. Для этого не нужны никакие скрипты:

  1. Добавьте другое оружие врагу (дублируя первый «WeaponObject»).
  2. Измените угол поворота второго «WeaponObject».

Враг должен сейчас стрелять в двух направлениях. Возможный результат:

Это хороший пример правильной работы в Unity: создавая независимые скрипты вроде этого и делая публичными некоторые полезные переменные, можно значительно уменшить количество кода. Меньше кода — меньше ошибок.

Нанесение урона игроку

Наши осьминоги внушают ужас? Как бы не так! Да, они могут стрелять, но это не наносит повреждения игроку. Может, у них холостые патроны? Давайте разбираться.

Просто добавьте «HealthScript» на игрока. Убедитесь, что сняли галку с поля «IsEnemy».

Конфигурация скрипта, отвечающего за здоровье игрока

Запустите игру и почувствуйте разницу:

Бонус

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

Солкновения игрока с врагом

Давайте посмотрим, как мы можем обработать столкновения между игроком и врагом, поскольку сейчас они сталкиваются друг с другом без последствий. Столкновение — это результат пересечения двух не-триггерных 2D коллайдеров. Нам просто нужно обрабатывать событие OnCollisionEnter2D в PlayerScript :

При столкновении мы наносим урон как врагу, так и игроку благодаря наличию компонента HealthScript . К нему привязано все, что относится к здоровью/урону.

Массив снарядов

Когда вы играете, вы можете наблюдать ва вкладке «Иерархия» (Hierarchy), что игровые объекты создаются и удаляются только через 20 секунд (если они не сталкиваются с игроком или врагом).

Если ваша цель создание огневой завесы для которой требуется МНОГО пуль, эта техника вряд ли подойдет.

Один из способов увеличить количество пуль – использовать массив. По сути, это набор пуль ограниченного размера. Когда массив заполнен, удалите старый объект и замените его на новый.

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

Кроме того, можно сократить время жизни пули и тогда она исчезнет быстрее.

Поведение пули

В хорошем шутере должны быть запоминающиеся боевые сцены.

Некоторые библиотеки вроде BulletML значительно упрощают определение сложных и зрелищных bullet patterns.

BulletML для Unity

Если вы хотите сделать полную версию игры в жанре Shoot’Em Up, ознакомьтесь с нашим плагином BulletML for Unity

Задержка выстрела

Добавьте несколько вооруженных противников в сцену и запустите игру. Вы увидете как синхронны все враги.

Можно просто добавить в оружие задержку: поставьте охлаждение на любое значение выше 0. Вы можете использовать алгоритм или просто поставить случайную цифру.

Скорость врагов также может определяться случайной величиной.

Еще раз, это зависит от вас. Все зависит исключительно от того, чего вы хотите достичь с вашим геймплеем.

В следующем уроке

Мы только что узнали, как дать оружие нашим врагам. Мы также увидели как повторно использовать некоторые скрипты для улучшения геймплея.

Результат

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

Create a player and its enemies

Pixelnest StudioPixelnest 18 nov. 2013

In the previous chapter, we have added a background and some props to our scene. It is time to add some useful game elements, like the player!

Creating the player

Creating a player controllable entity needs some elements : a sprite, a way to control it and a way to let it interact with the world.

We will explore this process step by step.

Let’s begin with the sprite.

Add a sprite

Here is the image that we will use:

Player Sprite

(Right click to save the image)

Copy the player image to the “Textures” folder.

Create a new Sprite . Name it “Player”.

Select the sprite to display in the “Sprite” property of the “Sprite Renderer” component.

If you have any trouble, refer to the previous part. We did exactly the same procedure for the background and props.

Select the “Player” sprite layer.

Place the player in the “Foreground” object.

Change its scale. (0.2, 0.2, 1) should be fine.

A word about components

We have just talked about a “Sprite Renderer” component. If you haven’t remarked, a game object is composed of a few components, visibles in the “Inspector” pane.

By default, an empty game object looks like:

Empty game object components

This object has only one component: a “Transform”. This component is required and cannot be disabled or removed from an object.

You can add as many components as you want on an object. A script is added as a component, for example. Most of the components can be enabled or disabled during the lifetime of the object.

Enable a game object component

(You can click on the checkbox to disabled it. You can right-click on a component to reset it, remove it, etc.)

Note: components can interact with other components. If an object has a component that requires another component of an object to work with, you can just drag the whole object inside this component and it will find the correct one in the object.

A “Sprite Renderer” is a component that is able to display a sprite texture.

Now that we have learned about the concept of component, let’s add one to the player!

Add a Box Collider

Click on the “Add Component” button of the player object. Choose a “Box Collider 2D”.

This will represent the player hitbox.

You can see the collider in the editor “Scene” view and tweak its size in the “Inspector” with the “Size” property.

Tip: There is another way to edit a box collider. Select a game object with a box collider and enable the “Edit Collider” toggle in the component. You can observe that the box collider (the green rectangle) is now showing four small handles onto. Drag one of them to change the shape of the box.

Be careful, the blue rectangle represents the Transform component of your game object, not the collider.

We will set the size of the collider to (10, 10) .

It’s way too large for a real shmup but it’s still smaller than the sprite:

Player hitbox

For the time being, it will be enough.

Tip: if you plan to make a shmup, spend a lot of time tweaking your hitboxes. In general, it should fit perfectly a small element inside the player sprite. What about the ship window here? You could also change the collider shape — with a “Circle Collider 2D” for example. It changes nothing to the behavior thanks to Unity, but it will slightly improve the gameplay.

Save the player game object to a prefab. You now have a basic player entity!

Adding Player Sprite

Polygon Collider 2D

If you want a super precise and custom shaped hitbox, Unity offers a “Polygon Collider 2D” component. It’s less efficient but allows you to set the shape exactly like you want.

The Rigidbody magic

There is one last component to add on our player: a “Rigidbody 2D”.

This will tell to the physics engine how to handle the game object. Furthermore, it will also allow collision events to be raised in scripts.

  1. Select your Player game object in the “Hierarchy”.
  2. Add a “Rigidbody 2D” component.

Now, hit play and observe:

The ship is falling!

Say hello to our beloved gravity. 🙂

As new scenes come with a default gravity and rigidbodies add a mass to an object, the ship is now attracted to the bottom.

The default gravity of Unity is 9.81 , i.e. the earth gravity.

Gravity can be used in some kind of games, but we don’t want to have to handle it here. Fortunately, it is simple to disable gravity on a rigidbody. Just set “Gravity Scale” to 0. That’s it, the ship is flying again.

You may also want to tick the “Fixed Angles” property as we don’t want our ship to rotate because of the physics.

Читать:
Как определить двузначное число в питоне

The complete settings:

Player rigibody settings

Moving the player

Time for some scripting! So far, we didn’t code anything. That’s the power of (love) Unity.

Inside Unity, create a new C# script in your “Scripts” folder. Call it “PlayerScript”.

Remark: you can do it in JavaScript too. As we said before, code snippets will be in C#, but it is quite easy to translate the code from a language to another.

Open your favorite editor or use the “Sync” submenu (Click on “Assets” in the menubar, then on “Sync MonoDevelop Project”) to edit the script.

“Sync MonoDevelop Project”: this submenu is a bit weird. First, the name does not change, even if you have set up another editor.

We also recommend to use this menu the first time you have to script, because Unity will create the solutions and link the Unity libraries in them (for Visual Studio, Xamarin Studio or MonoDevelop).

If you simply open the script instead, the compiler of your IDE will likely catch some errors because it won’t know Unity.

It doesn’t matter because you will never compile directly with it, but it is nice to have the autocompletion on the Unity objects and a first pass on errors.

If you come from XNA, you won’t be lost.

You can define some methods (called “Message” as we are not using C# inheritance system) that Unity will recognize and execute when needed.

Default scripts come with the Start and Update methods. Here is a short list of the most used “Message” functions:

  • Awake() is called once when the object is created. See it as replacement of a classic constructor method.
  • Start() is executed after Awake() . The difference is that the Start() method is not called if the script is not enabled (remember the checkbox on a component in the “Inspector”).
  • Update() is executed for each frame in the main game loop.
  • FixedUpdate() is called at every fixed framerate frame. You should use this method over Update() when dealing with physics (“RigidBody” and forces).
  • Destroy() is invoked when the object is destroyed. It’s your last chance to clean or execute some code.

You also have some functions for the collisions :

  • OnCollisionEnter2D(CollisionInfo2D info) is invoked when another collider is touching this object collider.
  • OnCollisionExit2D(CollisionInfo2D info) is invoked when another collider is not touching this object collider anymore.
  • OnTriggerEnter2D(Collider2D otherCollider) is invoked when another collider marked as a “Trigger” is touching this object collider.
  • OnTriggerExit2D(Collider2D otherCollider) is invoked when another collider marked as a “Trigger” is not touching this object collider anymore.

Fiou… This explanation was a bit boring, but unavoidable. Sorry for that.

Note about the 2D suffix: you should have observed now that almost anything we talked about was suffixed with “2D”. A “Box Collider 2D”, a “Rigidbody 2D”, the “OnCollisionEnter2D” or “OnTriggerEnter2D” methods, etc. These new components or methods have appeared with Unity 4.3.

By using them, you are adopting the new physics engine integrated in Unity 4.3 for 2D games (based on Box2D) instead of the one for 3D games (PhysX). The two engines are sharing similar concepts and objects, but they don’t work exactly the same. If you start to work with one (favor Box2D for 2D games), stick to it. This is why we use all the objects or methods with a “2D” suffix.

We will get back on some of them in details when we will be using them.

For our player script, we will add some simple controls: the arrow keys will move the ship.

(The numbers in the comments refer to the explanations below)

Note about C# conventions: look at the speed member visibility: it’s public. In C#, a member variable should be private in order to keep the internal representation of the class private.

But exposing it as a public variable allows you to modify it in Unity through the “Inspector” pane, even during the game execution. This is a powerful feature of Unity, letting you tweaks the gameplay without coding.

Remember that we are doing scripting here, not classic C# programming. This implies to break some rules and conventions.

Explanations

  1. We first define a public variable that will appear in the “Inspector” view of Unity. This is the speed applied to the ship.
  2. The fields we need.
  3. We use the default axis that can be redefined in “Edit” -> “Project Settings” -> “Input”. This will return a value between [-1, 1] , 0 being the idle state, 1 the right, -1 the left.
  4. We multiply the direction by the speed.
  5. We need to access the rigidbody component, but we can avoid to do it every frame by storing a reference.
  6. We change the rigidbody velocity. This will tell the physic engine to move the game object. We do that in FixedUpdate() as it is recommended to do everything that is physics-related in there.

Tutorial update: if you have read this tutorial before, you may remember that we were using transform.Translate directly. This was working because translations were slow, but it is not recommended since it can mess up the physics (for the physic engine, a translation is like a teleportation, so there is no collision).

Thanks to your feedback, we updated the scripts to help people learn the good practices of game object movement.

Now, attach the script to the game object.

Tip: you can attach a script to a game object by dragging the script from the “Project” view on the game object in the “Hierarchy”. You can also click on “Add Component” and find it manually.

Hit the “Play” button in top of the editor. The ship is moving and your game is running! Congratulations, you have just made the equivalent of a “Hello, World!” for a game 🙂

Try to tweak the speed: click on the player, modify the speed values in the “Inspector” and look at the consequences.

The inspector for a script

Be careful: modifications when the game is executed (or played) are lost when you stop it! It’s a great tool for tweaking the gameplay, but remember what you are doing if you want to keep the changes.

However, this effect is also handy: you can destroy your game completely during the execution to test something new, without being afraid of breaking your real project.

This was the first sign of life in our game! Let’s add more!

The first enemy

A shmup is nothing without tons of enemies to blow up.

Let’s use an innocent octopus, named “Poulpi”:

Poulpi Sprite

(Right click to save the image)

Sprite

Time to create a new sprite! Again:

  1. Copy the image to the “sprites” folder.
  2. Create a new Sprite using this image.
  3. Set the sprite layer to “Enemies”
  4. Change the “Scale” property of the Transform to (0.3, 0.3, 1) .
  5. Add a “Box Collider 2D” with a size of (4, 4) .
  6. Add a “Rigidbody 2D” with a “Gravity Scale” of 0 and “Fixed Angles” ticked.

Save the prefab… and that’s it!

Enemy Sprite in Unity

Script

We will script a simple behavior: the Poulpi will just move in a direction.

Create a new script “MoveScript”.

We could call it “EnemyScript” but we plan to reuse it later in another context.

Note: the modularity provided by Unity’s component-based system offers a great way to separate scripts with different features. Of course, you can still have one giant script doing everything with a lot of parameters. It’s your choice, but we highly recommend against doing that.

We will copy some parts of what we have already written in the “PlayerScript” for movement. We will add another designer (a public member you can alter in the “Inspector”) variable for the direction:

Attach the script to the Poulpi. Hit “Play”: it should move just like below.

If you move the player in front of the enemy, the two sprites will collide. They will just block each other as we didn’t define the collision behavior yet.

Next step

You have learned how to add a player entity, controlled by the keyboard. Then, we created a basic enemy with a rudimentary AI.

Now, we want to destroy that moving thing! And for that, we need ammo!

© 2016 Pixelnest Studio — we craft games and apps

Unity Add Enemies to a 2D Platformer

Creating a Platformer in Unity is relatively easy, but making it with AI support, may not be as straightforward.

In this post, I will be showing how to create a 2D platformer game with an enemy AI.

Generally in 2D platformers, the player can only walk front/back, jump, and in some cases climb up/down the ladder, if the map is multileveled. Knowing that we could use a modular approach where the same controller is shared between the player and the AI.

Step 1: Create the Scripts

Let’s begin by creating all the necessary scripts. Check the source code below:

Ladder2D.cs

PlayerController2D.cs

CameraFollow2D.cs

BotController2D.cs

Step 2: Set up the Player and the Enemies

Now it’s time to set up our player and the enemy AI using the scripts above.

Setting up our Player instance

  • Create a new GameObject and name it «Player»
  • Change the Tag of that object to «Player»
  • Change the object’s layer to 8 (if there is no Layer 8 in the selection, add one by clicking Add Layer. name it «Player»)
  • Create another GameObject, call it «Body» and add a SpriteRenderer component
  • Assign your player Sprite to a «Body» and move it inside «Player» object
  • Select «Player» object and add CapsuleCollider2D, Rigidbody2D and PlayerController2D components
  • Scale the CapsuleCollider2D until it fits the player Sprite

As you can see PlayerController2D has a couple of variables, most of them are self-explanatory, however, one of them need a bit of explanation:

PlayerHP — this value is used in BotController2D to decide whether the AI should run away when its HP is too low.

Use the PlayerHP variable when implementing the attack function (Check void Attack() at the end of the PlayerController2D.cs script).

Setting up player Camera

  • Select the Main Camera and add the CameraFollow2D component
  • Assign the Player into a Target variable
  • Optionally you can tweak the Offset variable (If you don’t want the camera to be centered exactly in the middle)

Setting up a ladder

PlayerController2D also supports climbable Ladders.

Setting up a new ladder is really easy:

  • Create a new GameObject and call it «Ladder»
  • Change its layer to «IgnoreRaycast»
  • Create another game object with a SpriteRenderer and assign a sprite of your ladder and move it inside the Ladder object
  • Add a BoxCollider2D and Ladder2D components to a «Ladder» object
  • Scale the collider dimensions to match the ladder Sprite and mark it as Trigger

Setting up the enemy AI

  • First, go to the Physics2D panel and disable a collision between the Player layer, so the bots and players are not stuck between each other.

  • Duplicate the Player instance
  • Add a BotController2D component
  • The bot is now ready

2D Bot AI Properties

Check the video below to see the enemy AI in action (White instance is our player, Red instances are controlled by the AI):

How to Make a Simple Patrolling Monster for a 2D Platformer in Unity

This article is a part of our 2D Platformer Tutorial Serie. Be sure to check the other articles!

In this article, we’ll be creating an enemy for our 2D platformer in Unity, and implementing a simple behaviour: patrolling from wall to wall. While simple, this is widely used in platformers and other kind of games and the logic can be used in many situations.

Our Proud Snail Guard!

Going from Right to Left

As this is part of our serie on making a platformer, grounded enemies can only go left or right.

Let’s create a new file for our script: “PatrollingWallToWall.cs”, and set some public properties for the movement speed, and whether the monster is going left or right. As they are public, we can set their values from the inspector, but we’ll also set some default values.

What’s more, since our enemies are sprites being displayed, we’ll need to have access to the SpriteRenderer component to flip the sprite when it turns around.

Finally, we’ll need our enemy to move. So, we’ll use the bIsGoingRight boolean to get the direction our ennemy is going, multiply it by the time elapsed and the monster’s movement speed. The result will be used as an input of the transform.Translate method to move our gameobject according to its movement speed and current direction.

We’ll put the logic of detecting walls and turning around in the CheckForWalls function, which we’ll explain in a bit, but for now our class looks like this:

If you put this script on your Monster Game Object, it should move in one direction, great stuff! Now we can have our monster detect walls and turn around.

Turn Around, Vile Creature!

So how do we detect walls? Well, we want the enemy to turn around when it touches a wall, so we’ll be using the simple solution of raycasting.

Raycasting if you don’t know already, consists in creating a ray from an initial position, in a certain direction, for a finite or infinite distance and check for collisions.

The usability for our usecase is obvious: if the monster is going right, check for a collision at a short range. And if there is a collision, check if we are colliding with the ground. If we are, it’s to go back the way we came from! The code goes as follows and should be self explanatory:

Also, we’ll need to add another propriety to our class, to define the raycasting casting distance to avoid our raycast colliding with the instantiator of the raycast (that is, we don’t want the ennemy to detect itself).

To revert the direction in which the monster is going, we are basically doing the same thing as in the Start method: change the value of bIsGoingRight, flip the Sprite, and let our Update loop take care of the rest. We’re done!

To Note: if you are paying attention, you will realize we also substracted Vector3(0f, 0.25f, 0f) in the raycast initial position. We do this to enforce raycasting at an appropriate level: our snail monster takes up almost 2 spaces in the Y axis, so if we raycasting from the Y position of the center of our sprite, we’ll miss the floor and our monster will be stuck going right and trying to find a collision.

Extending this Class

This is a very simple behaviour but what it really is, is a building block for more complex behaviours.

For example, you can modify the raycasting part to check whether the monster is about to fall with simple checks: if there is no ground at the bottom right of the monster, that’s a hole. Or it can be used for a more complex AI; imagine a magician, that would run away when the player comes too close! The appropriate behaviour can be started thanks to raycasting like we did above.

Похожие статьи