Пишем арканоид на Unity. Механика мяча и платформы


Оглавление (нажмите, чтобы открыть):

Сила мяча в Арканоиде

09.01.2020, 15:18

Большое количество уровней в арканоиде
Делаю арканоид, в игре планирую иметь 50+ различных уровней. Для удобства хочу создать отдельное.

Возвращение мяча в исходное положение и стреляние
Пытаюсь сделать так, чтобы мяч выстрелил, пролетел 4 секунды, возвратился в исходное положение.

Какова средняя сила взаимодействия мяча со стенкой
Мячик массой m=300 г летел со скоростью V1=20 м/с. После удара о стенку отскочил от неё под прямым.

Сила тертя і сила пружності
Ребят, помогите, пожалуйста! Нужно решить одну задачку по физике. Один кінець горизонтально.

Ошибка при столкновении блока и шарика в арканоиде
Доброго времени суток.Проблема в следующем,при столкновении шарика с блоком прерывается работа.

Скрипт на движение 2d персонажа в unity3d. Пишем арканоид на Unity. Механика мяча и платформы

Public GameObject player;
public int speed = 5;

Теперь укажем в методе старта, что это объект, на котором висит скрипт.

Void Start () <
player = (GameObject)this.gameObject;
>

Теперь сделаем само передвижение игрока вперёд при нажатии на «W» или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
>

Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>

Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на «A» или «D».
Я буду использовать «Rotate()». Чтобы поворачивать по оси «Y», я буду использовать «up» и «down». Кстати, для этого ещё надо объявить переменную «public int speedRotation = 3». И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>

Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в «Window» => «Animation». В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;

Теперь в старте добавим клип.

Теперь мы будем его воспроизводить через «CrossFade». Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.

Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации «public AnimationClip anima2;»? так же добавим и переменной «public int jumpSpeed = 50;». И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Всё. Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour <
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Vo courier new font-size: text-align: justify> player = (GameObject)this.gameObject;
animation.AddClip(anima, «animCube»);
>
void Update() <
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade(«animCube»);
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

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

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

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

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

Корабль падает! И как падает! Передвайте привет нашей любимой силе тяжести. По мере того, как сменяются кадры с заранее заданной гравитацией и rigidbodies прибавляет объекту массы, корабль притягивается к нижней части экрана.

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

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

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

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

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

Теперь добавим неприятелей, стремящихся уничтожить наш корабль. Пусть им будет зловещий спрут, названный «Poulpi»:

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

Введение:

1. Шаг

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

public float speed;

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown («Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>

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

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

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.

12. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim: MonoBehaviour <

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool («isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat («speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat («speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool («isJumping» , true );
>
>

Можете проверить сцену.

13. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//ссылочная переменная для звукового файла
public AudioClip footsteps;

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSound: MonoBehaviour <

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

Скачать готовый проект

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

  • Start() : используется для инициализации переменных или параметров, необходимых нам в коде.
  • Update() : вызывается каждый кадр игры, необходим для обновления состояния игры.

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

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

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

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.


Вот, как это можно сделать:

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

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

А вот теперь точно все. Запустите игру и проверьте, все ли работает как положено.

В следующей части

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

Как сделать движение в unity 2d. Пишем арканоид на Unity. Механика мяча и платформы

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

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

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

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

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

Корабль падает! И как падает! Передвайте привет нашей любимой силе тяжести. По мере того, как сменяются кадры с заранее заданной гравитацией и rigidbodies прибавляет объекту массы, корабль притягивается к нижней части экрана.

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

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

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

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

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

Теперь добавим неприятелей, стремящихся уничтожить наш корабль. Пусть им будет зловещий спрут, названный «Poulpi»:

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

Мастер Йода рекомендует:  Напишите метод, который будет подсчитывать количество цифр «2», используемых в записи чисел от 0 до

Итак. Всем привет. И сегодня я расскажу, как сделать простое движение персонажа. Сейчас только от третьего лица. Приступим.
Начнём, пожалуй, с создания персоажа. У меня это будет куб. Кто не знает, как создавать кубы или круги, поясняю — «GameObject» => «CreateOther» => «Cube». Создаём таким же образом камеру и привязываем к кубу (то бишь просто в иерархии перетаскиваем камеру на куб).
Так. Теперь создадим поверхность, по которой персонаж будет ходить. Пусть это будет просто «Plane». Ах, да. В конце урока будет ссылка с исходником по туториалу для тех, кто не понял.
Итак. Теперь создадим скрипт «Move». Добавим переменную игрока и переменную скорости.

Public GameObject player;
public int speed = 5;

Теперь укажем в методе старта, что это объект, на котором висит скрипт.

Void Start () <
player = (GameObject)this.gameObject;
>

Теперь сделаем само передвижение игрока вперёд при нажатии на «W» или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
>

Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>

Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на «A» или «D».
Я буду использовать «Rotate()». Чтобы поворачивать по оси «Y», я буду использовать «up» и «down». Кстати, для этого ещё надо объявить переменную «public int speedRotation = 3». И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>

Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в «Window» => «Animation». В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;

Теперь в старте добавим клип.

Теперь мы будем его воспроизводить через «CrossFade». Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.

Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации «public AnimationClip anima2;»? так же добавим и переменной «public int jumpSpeed = 50;». И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Всё. Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour <
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Vo courier new font-size: text-align: justify> player = (GameObject)this.gameObject;
animation.AddClip(anima, «animCube»);
>
void Update() <
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade(«animCube»);
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

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

Загрузим сцену из первой части. Напомню, что в прошлый раз мы импортировали несколько спрайтов в папку AssetsSprites . На всякий случай, внизу поста еще раз приведу ссылку на спрайты. Среди них должен быть спрайт под названием Run . Мы будем использовать его для создания анимации бега. Для этого нам надо проделать те же действия по превращению одиночного спрайта в коллекцию, как и при создании анимации покоя. Вкратце напомню: выделяем спрайт, в окне Inspector устанавливаем свойство Sprite Mode как Multiple , нажимаем ниже Sprite Editor , нарезаем изображение в режиме Grid или Automatic .

Теперь в окне Hierarchy выбираем Character и переходим в окно Animation . Нажимаем на поле с анимацией Idle и выбираем Create New Clip , чтобы создать анимацию бега. Сохраним файл анимации в папке AssetsAnimations под именем Run .

Новая созданная анимация Run стала текущей в окне Animation . Разворачиваем спрайт Run в окне Project , выделяем все фалы Run_0… Run_9 и перетаскиваем в окно Animation . Установим пока значение Sample равное 24.

Все это мы уже делали в первой части, а теперь будет нечто новое. Перейдем в окно Animator . Сейчас там отображены три анимации: Any State , Idle и Run . Нам предстоит задать условия перехода из анимации Idle в анимацию Run , то есть из состояния покоя в состояние бега. В нижнем левом углу есть поле Parameters . Нажимаем на плюсик, выбираем Float и называем новый параметр как Speed . Тем самым мы создали параметр типа число с плавающей запятой, обозначающий скорость перемещения персонажа. Именно в зависимости от значения этого параметра будет происходить переключение из анимации покоя в анимацию бега. Теперь нажимаем правой кнопкой мыши на анимацию Idle , выбираем Make Transition и нажимаем левой кнопкой мыши на анимацию Run . Между анимациями появится линия со стрелкой. Передвиньте мышкой прямоугольники анимации, если плохо видно. Кликнем по линии со стрелкой. В окне Inspector отобразятся свойства перехода между анимациями. Обратим внимание на низ окна, в раздел Conditions . Кликнем на параметр Exit Time и поменяем его на Speed . Второе поле Greater оставим без изменений, а в третьем введем значение 0.01 . Мы создали условие перехода из анимации покоя в анимацию бега — оно происходит, когда значение параметра скорости становится немногим больше нуля.

Теперь нужно сделать обратный переход — из Run в Idle . Делаем все с точностью наоборот: Make Transition от Run к Idle , выделяем переход, в Conditions устанавливаем SpeedLess0.01 .

Теперь у нас есть две анимации и условия перехода между ними. Но пока ничего работать не будет, потому что все что мы сделали нужно «оживить» при помощи скрипта. Давайте перейдем в окно Project и создадим в папке Assets подпапку Scripts . Добавим в нее новый C# Script , назовем его CharacterControllerScript и откроем на редактирование.

Я приведу полный листинг скрипта с подробными комментариями, а ниже еще поясню, что в нем происходит.
using UnityEngine; using System.Collections; public > /// Начальная инициализация /// private vo > /// Выполняем действия в методе FixedUpdate, т. к. в компоненте Animator персонажа /// выставлено значение Animate Physics = true и анимация синхронизируется с расчетами физики /// private vo , Mathf.Abs(move)); //обращаемся к компоненту персонажа Rig > 0 && !isFacingRight) //отражаем персонажа вправо Flip(); //обратная ситуация. отражаем персонажа влево else if (move /// Метод для смены направления движения персонажа и его зеркального отражения /// private vo >

Итак, мы завели несколько переменных: для задания максимальной скорости перемещения, для определения направления (вправо/влево) и для работы с компонентом Animator . Почти все действия происходят в методе FixedUpdate . В нем мы получаем значение оси Х , которое меняется при нажатии на клавиатуре клавиш влево-вправо или A-D (если не меняли соответствующие настройки проекта!). Затем устанавливаем это значение параметру Speed компонента Animator . Обратите внимание, что мы берем модуль этого значения при помощи метода Mathf.Abs , так как при создании условий перехода между анимациями покоя и бега мы сравниваем значение параметра с положительным числом 0.01 . Нам здесь не важно, в какую сторону бежит персонаж. Важно лишь величина значения. Далее задаем скорость перемещения по оси Х в соответствии со значением максимальной скорости. И, наконец, проверяем, в какую сторону бежит персонаж, и в какую сторону он в этот момент повернут. Если он бежит вправо, а повернут влево — разворачиваем его вправо путем инвертирования его размера по оси Х . И наоборот. Этим нехитрым способом мы избавились от необходимости делать две анимации вместо одной: для бега вправо и для бега влево.

Сохраняем скрипт. В Unity перетаскиваем его на нашего Character в окне Hierarchy . Запускаем игру, нажимаем влево-вправо или A-D.

Капитан Коготь теперь умеет бегать! Скорость анимации получилась быстроватой. Ее можно снизить путем уменьшения значения Sample в окне Animation для анимации Run (значение 12 будет нормально). Если одновременно с игрой у вас видно окно Animator , то вы увидите, что во время покоя работает анимация Idle (бегает синий прогрессбар), а во время бега происходит переход на анимацию Run , и, соответственно, работает она.

На этом пока все. Нам осталось разобраться с прыжками… и узнать при этом еще несколько новых вещей!

Введение:

1. Шаг

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

public float speed;

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown («Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>

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

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

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.

12. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim: MonoBehaviour <

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool («isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat («speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat («speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool («isJumping» , true );
>
>

Можете проверить сцену.

13. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//ссылочная переменная для звукового файла
public AudioClip footsteps;

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSound: MonoBehaviour <

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

Unity 2d движение к цели. Пишем арканоид на Unity

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

  • Start() : используется для инициализации переменных или параметров, необходимых нам в коде.
  • Update() : вызывается каждый кадр игры, необходим для обновления состояния игры.

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

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

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

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:


Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.

Вот, как это можно сделать:

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

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

А вот теперь точно все. Запустите игру и проверьте, все ли работает как положено.

В следующей части

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

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

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

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

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

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

Корабль падает! И как падает! Передвайте привет нашей любимой силе тяжести. По мере того, как сменяются кадры с заранее заданной гравитацией и rigidbodies прибавляет объекту массы, корабль притягивается к нижней части экрана.

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

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

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

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

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

Теперь добавим неприятелей, стремящихся уничтожить наш корабль. Пусть им будет зловещий спрут, названный «Poulpi»:

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

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

Загрузим сцену из первой части. Напомню, что в прошлый раз мы импортировали несколько спрайтов в папку AssetsSprites . На всякий случай, внизу поста еще раз приведу ссылку на спрайты. Среди них должен быть спрайт под названием Run . Мы будем использовать его для создания анимации бега. Для этого нам надо проделать те же действия по превращению одиночного спрайта в коллекцию, как и при создании анимации покоя. Вкратце напомню: выделяем спрайт, в окне Inspector устанавливаем свойство Sprite Mode как Multiple , нажимаем ниже Sprite Editor , нарезаем изображение в режиме Grid или Automatic .

Теперь в окне Hierarchy выбираем Character и переходим в окно Animation . Нажимаем на поле с анимацией Idle и выбираем Create New Clip , чтобы создать анимацию бега. Сохраним файл анимации в папке AssetsAnimations под именем Run .

Новая созданная анимация Run стала текущей в окне Animation . Разворачиваем спрайт Run в окне Project , выделяем все фалы Run_0… Run_9 и перетаскиваем в окно Animation . Установим пока значение Sample равное 24.

Все это мы уже делали в первой части, а теперь будет нечто новое. Перейдем в окно Animator . Сейчас там отображены три анимации: Any State , Idle и Run . Нам предстоит задать условия перехода из анимации Idle в анимацию Run , то есть из состояния покоя в состояние бега. В нижнем левом углу есть поле Parameters . Нажимаем на плюсик, выбираем Float и называем новый параметр как Speed . Тем самым мы создали параметр типа число с плавающей запятой, обозначающий скорость перемещения персонажа. Именно в зависимости от значения этого параметра будет происходить переключение из анимации покоя в анимацию бега. Теперь нажимаем правой кнопкой мыши на анимацию Idle , выбираем Make Transition и нажимаем левой кнопкой мыши на анимацию Run . Между анимациями появится линия со стрелкой. Передвиньте мышкой прямоугольники анимации, если плохо видно. Кликнем по линии со стрелкой. В окне Inspector отобразятся свойства перехода между анимациями. Обратим внимание на низ окна, в раздел Conditions . Кликнем на параметр Exit Time и поменяем его на Speed . Второе поле Greater оставим без изменений, а в третьем введем значение 0.01 . Мы создали условие перехода из анимации покоя в анимацию бега — оно происходит, когда значение параметра скорости становится немногим больше нуля.

Теперь нужно сделать обратный переход — из Run в Idle . Делаем все с точностью наоборот: Make Transition от Run к Idle , выделяем переход, в Conditions устанавливаем SpeedLess0.01 .

Теперь у нас есть две анимации и условия перехода между ними. Но пока ничего работать не будет, потому что все что мы сделали нужно «оживить» при помощи скрипта. Давайте перейдем в окно Project и создадим в папке Assets подпапку Scripts . Добавим в нее новый C# Script , назовем его CharacterControllerScript и откроем на редактирование.

Я приведу полный листинг скрипта с подробными комментариями, а ниже еще поясню, что в нем происходит.
using UnityEngine; using System.Collections; public > /// Начальная инициализация /// private vo > /// Выполняем действия в методе FixedUpdate, т. к. в компоненте Animator персонажа /// выставлено значение Animate Physics = true и анимация синхронизируется с расчетами физики /// private vo , Mathf.Abs(move)); //обращаемся к компоненту персонажа Rig > 0 && !isFacingRight) //отражаем персонажа вправо Flip(); //обратная ситуация. отражаем персонажа влево else if (move /// Метод для смены направления движения персонажа и его зеркального отражения /// private vo >

Итак, мы завели несколько переменных: для задания максимальной скорости перемещения, для определения направления (вправо/влево) и для работы с компонентом Animator . Почти все действия происходят в методе FixedUpdate . В нем мы получаем значение оси Х , которое меняется при нажатии на клавиатуре клавиш влево-вправо или A-D (если не меняли соответствующие настройки проекта!). Затем устанавливаем это значение параметру Speed компонента Animator . Обратите внимание, что мы берем модуль этого значения при помощи метода Mathf.Abs , так как при создании условий перехода между анимациями покоя и бега мы сравниваем значение параметра с положительным числом 0.01 . Нам здесь не важно, в какую сторону бежит персонаж. Важно лишь величина значения. Далее задаем скорость перемещения по оси Х в соответствии со значением максимальной скорости. И, наконец, проверяем, в какую сторону бежит персонаж, и в какую сторону он в этот момент повернут. Если он бежит вправо, а повернут влево — разворачиваем его вправо путем инвертирования его размера по оси Х . И наоборот. Этим нехитрым способом мы избавились от необходимости делать две анимации вместо одной: для бега вправо и для бега влево.

Сохраняем скрипт. В Unity перетаскиваем его на нашего Character в окне Hierarchy . Запускаем игру, нажимаем влево-вправо или A-D.

Капитан Коготь теперь умеет бегать! Скорость анимации получилась быстроватой. Ее можно снизить путем уменьшения значения Sample в окне Animation для анимации Run (значение 12 будет нормально). Если одновременно с игрой у вас видно окно Animator , то вы увидите, что во время покоя работает анимация Idle (бегает синий прогрессбар), а во время бега происходит переход на анимацию Run , и, соответственно, работает она.

На этом пока все. Нам осталось разобраться с прыжками… и узнать при этом еще несколько новых вещей!

Пишем арканоид на Unity. Механика мяча и платформы

Public GameObject player;
public int speed = 5;

Теперь укажем в методе старта, что это объект, на котором висит скрипт.

Void Start () <
player = (GameObject)this.gameObject;
>

Теперь сделаем само передвижение игрока вперёд при нажатии на «W» или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
>

Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>

Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на «A» или «D».
Я буду использовать «Rotate()». Чтобы поворачивать по оси «Y», я буду использовать «up» и «down». Кстати, для этого ещё надо объявить переменную «public int speedRotation = 3». И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>

Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в «Window» => «Animation». В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;

Теперь в старте добавим клип.

Теперь мы будем его воспроизводить через «CrossFade». Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.

Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации «public AnimationClip anima2;»? так же добавим и переменной «public int jumpSpeed = 50;». И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Всё. Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour <
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Vo courier new font-size: text-align: justify> player = (GameObject)this.gameObject;
animation.AddClip(anima, «animCube»);
>
void Update() <
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade(«animCube»);
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Введение:

1. Шаг

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Мастер Йода рекомендует:  Разработка архитектуры масштабного приложения Vue.js Javascript

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

public float speed;

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour <

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown («Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>

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

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

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.

12. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim: MonoBehaviour <

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool («isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat («speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat («speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool («isJumping» , true );
>
>

Можете проверить сцену.

13. Step

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//ссылочная переменная для звукового файла
public AudioClip footsteps;

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSound: MonoBehaviour <

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

Скачать готовый проект

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)


Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

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

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

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

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

Корабль падает! И как падает! Передвайте привет нашей любимой силе тяжести. По мере того, как сменяются кадры с заранее заданной гравитацией и rigidbodies прибавляет объекту массы, корабль притягивается к нижней части экрана.

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

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

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

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

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

Теперь добавим неприятелей, стремящихся уничтожить наш корабль. Пусть им будет зловещий спрут, названный «Poulpi»:

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

Что можно приготовить из кальмаров: быстро и вкусно

*Unity* — очень мощный, прогрессивный движок с большим потенциалом. Он обладает множеством уже встроенных функций (в том числе и физическим движком *NvidiaPhysX*), которые нам, пользователям, прописывать вручную не придется. 🙂
В этой небольшой статье я бы хотел обсудить физические возможности движка. Итак, начнем:

Rigidbody
=
= Что это такое? =
За функцией *Rigidbody* скрывается Абсолютно Твердое Тело (*АТТ*). Если объяснять грубо и понятно, то *АТТ* в физике и механике — это идеальное твердое тело, которое под воздействием силы не может менять свои свойства, но может (под ее воздействием) перемещаться в 3х измерениях (вниз, вверх, вперед и т.д., т.е. в наших X-Y-Z осях), а также вращаться в 3х измерениях (опять же по осям X-Y-Z).

В *Unity*, как и в других игровых движках (опять же называю их именно «игровыми» движками грубо), *Rigidbody* используется для различных объектов, с которыми мы можем взаимодействовать, толкая, пиная и т.п. Подобные объекты под нашим влиянием будут далее под воздействием гравитации кататься, передвигаться и сталкиваться с другими предметами.

Какое применение мы можем найти этой функции? =
К примеру, для создания автомобиля, кроме *Rigidbody* нам понадобятся 4 Wheel Collider «а и *код* (*скрипт*) , применяющий силовое воздействия к колесам, в зависимости от нажатых клавиш.

  • *Mass* — Масса нашего объекта в килограммах . Рекомендуется не ставить значения массы в 100 раз больше или меньше масс других *АТТ*.
  • *Drag* — Насколько тело подвержено сопротивлению воздуха, когда оно движется под воздействием сил. При значении *0* сопротивления нет, а бесконечное значение мгновенно остановит наш объект.
  • Angular Drag — Насколько тело подвержено сопротивлению воздуха, когда оно вращается под воздействием сил. При значении *0* сопротивления нет, а бесконечное значение мгновенно прекратит вращение нашего объекта.
  • Use Gravity — При включении, объект становится подвержен влиянию гравитации.
  • Is Kinematic — При включении, объект становится не подвержен влиянию физического движка и может изменяться только его функцией *Transform*. Это может быть полезно для создания движущихся платформ, к примеру.
  • *Interpolate* — Применяется только в случае, если движения вашего АТТ кажутся вам странными или неуклюжими и т.п.:
  1. None: Интерполяция не применяется
  2. Interpolate: По-сравнению с трансформацией предыдущего кадра (*фрейма*) , следующий будет сглажен.
  3. Extrapolate: Трансформация текущего кадра сглаживается, по-сравнению с оценочной (примерной) трансформацией следующего.
  • Freeze Rotation — Запрещает любое вращение, как скриптовое, так и при столкновениях. Однако, вращение можно будет выполнять функцией //transform.Rotate()
  • Collision Detection — Используется для того, чтобы быстро-движущиеся объекты не проходили сквозь другие объекты, не находя Collision «ов (специальная «сетка» на объектах, которой они сталкиваются друг с другом и с игроком).
  1. Discrete: Значение по-умолчанию для того, чтобы наш объект «замечал» все другие объекты, с которыми может столкнуться.
  2. Continuous: Используйте Discrete Сollision с динамическими объектами столкновения (у которых имеется *АТТ*), а Continuous Сollision для статических MeshCollider «ов (без *АТТ*). Режим Continuous Dynamic использует Continuous Сollision для одного конкретного *АТТ*. Остальные *АТТ* будут использовать режим _Discrete_. (Это сильно скажется на нагрузке физического движок, просто оставьте _Discrete_, если не возникает проблем со столкновением быстрых объектов)
  3. Continuous Dynamic: Используется для объектов в режиме _Continuous_ или Continuous Dynamic Collision . Continuous Сollision также будет использоваться для статических MeshCollider «ов (без *АТТ*). Для всех остальных используется режим _Discrete_. Используется для быстро движущихся объектов.

Как мы можем использовать эту функцию? =
= Базовые знания.
Чтобы использовать *АТТ*, нам нужен уже созданный игровой объект (*GameObject*), кликнув на нем, мы проходим в меню по следующему пути: Components — Physics — Rigidbody . Все, *АТТ* добавлено! 🙂
Теперь объект подвержен гравитации, к нему можно применять силы с помощью скриптов, но для того, чтобы объект вел себя именно так, как вам нужно, следует добавить *Collider* или *Joint*.

Код правит миром.
В скрипте манипулировать нашим объектом теперь мы будем с помощью функций AddForce() и AddTorque() .
Так как я в *Unity* применяю *JavaScript*, мои примеры будут с ним, ссылки на другие примеры скриптинга (на C# или *Boo*) вы найдете ниже, в пункте Дополнительная информаия по АТТ .

// Функция раскручивает объект вокруг заданной оси. // 1 тип: function AddTorque (torque: Vector3, mode: ForceMode = ForceMode.Force) : vo >

АТТ взаимодействует с объектами.
Для правильной работы наших *АТТ* их нужно снабдить Collider «ами (или Collision «ами, как вам будет угодно ^.^).
Подробно о коллайдерах читайте ниже.

Размер имеет значение!
Соблюдайте размеры вашего объекта, ведь они гораздо более значимы даже массы *АТТ*. Если ваш объект движется неправильно, висит в воздухе или не сталкивается, попробуйте настроить его величину (не *АТТ*, а самого объекта). При импортировании модели из 3D редактора ее размеры сохраняются, так что будьте внимательны на стадии моделирования и соблюдайте размеры всех моделей.

Дополнительная информация по АТТ =
На этом, описывать *АТТ* или *Rigidbody*, я, пожалуй, закончу. Однако, есть пара подсказок, специально для тех, кто до сюда долистал:)

  1. Стандартный размер куба в *Unity* равен 1 метру , поэтому, проверять размер ваших моделей по нему очень удобно. Чтобы создать куб, выберите в меню GameObject — Create Other — Cube
  2. Относительный показатель *Mass* определяет, как два объекта будут взаимодействовать друг с другом.
  3. *Mass* не влияет на скорость падения с высоты, для этих целей используйте *Drag*.
  4. Чем выше значения *Drag*, тем больше весит предмет. стандартные значения варьируются от 0.001 (твердый кусок металла) до 10 (перышко).
  5. Если вам нужно изменять объект как с помощью скриптов, так и с помощью физики, добавьте к нему *АТТ* с параметром *Kinematic*.

Посмотреть скриптовые примеры воздействия внешних сил на объект с функцией *АТТ* можно по следующим ссылкам:
*AddForce*
*AddTorque*

Для изменения скриптового примера кликните на тексте с названием языка программирования!

Colliders
=
= Что это такое? =
В предыдущем разделе мы рассмотрели принцип работы *Rigidbody* и упомянули так называемые *коллайдеры*. *Коллайдер* для нас — вспомогательный объект в виде сетки простой примитивной или, наоборот, сложной формы, который находится вокруг нашей модели или части модели и взаимодействует с другими объектами, если те тоже окружены коллайдерами.
Чтобы наглядно объяснить знатокам редактора мира *Warcraft 3*, представьте себе импортированную нами модель, которой мы в редакторе дудадов не присвоили текстуры путей — это будет наш объект; а роль коллайдеров тут будут играть блокираторы пути вокруг модели. Естественно, это довольно грубое сравнение, ведь в *Unity* они гораздо более функциональны. Что-ж, рассмотрим поподробнее.

Виды коллайдеров. =
Коллайдеры добавляются через меню Component — Physics . Есть несколько видов:

  • Box Collider — в форме куба.
  • Sphere Collider — в форме сферы.
  • Capsule Collider — в форме капсулы.
  • Mesh Collider — автоматически создает коллайдер по форме сетки объекта, не может сталкиваться с другими коллайдерами этого же типа. В основном используется для статических объектов, например, окружение гоночной трассы.
  • Wheel Collider — используется для колес, очень полезная вещь.
  • Compound Collider — комбинации примитивов, которые вместе действуют как один. Чтобы создать такой сложный коллайдер нужно к нашему базовому коллайдеру добавить дочерние объекты, а к ним уже привязать по примитиву. Таким образом, к примеру, очень удобно делаются простенькие коллайдеры для машин.

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

* *Material* — Показывает, как коллайдер взаимодействует с остальными объектами, при этом присваивая физический материал, например, металл, лед и т.п.
* Is Trigger — Если параметр включен, то на объект воздействует скрипт, а не физика.
* *Size* — Размер коллайдера по осям X-Y-Z.
* *Center* — Положение коллайдера, относительно локальных координат объекта.

* *Radius* — Радиус сферы, заменяет параметр *Size*.
* Остальные параметры без изменений.

  • *Капсула* (параметры заменяют размер)

* *Radius* — Толщина капсулы.
* *Height* — Высота цилиндрической части коллайдера (без скругленных оснований).
* *Direction* — Направление коллайдера, относительно локальных координат объекта.

  • Mesh Collider (параметры заменяют размер)

* *Mesh* — Выбор нужного меша для создания коллайдера.
* Smooth Sphere Collisions — Включение этой функции сглаживает поверхность коллайдера. Использовать следует на гладких поверхностях, к примеру, наклонный ландшафт без лишней углоатости, по которому должны скатываться сферы.
* *Convex* — При включении позволяет нашему коллайдеру сталкиваться с другими такими же. Convex Mesh Collider «ы ограничены до 255 трианглов .

  • Wheel Collider (параметры заменяют размер)

* *Radius* — Радиус колеса.
* Suspension Distance — Максимальная дистания увеличения подвески колеса. Подвеска всегда увеличивается вниз по локальной оси *Y*.
* Suspension Spring — Подвеска пытается достигнуть указанной точки, используя различные силы.

  1. Spring: Пытается достигнуть указанной точки (позиции). Чем выше параметр, тем быстрее она достигается.
  2. Damper: Смягчает, замедляет скорость движения подвески. Чем выше значение, тем медленнее двигается амортизатор.
  3. Target Position: Полный «путь», который может «пройти» подвеска. *0* означает полностью расправленный амортизатор, а *1* — полностью сжатый. Значением по-умолчанию является 0, что соответствует обычной автомобильной подвеске..

* *Mass* — Масса колеса.
* Forward/Sideways Friction — Параметры трения при простом качении колеса и при качении боком (такое бывает в заносах или при дрифте).

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

  • Start() : используется для инициализации переменных или параметров, необходимых нам в коде.
  • Update() : вызывается каждый кадр игры, необходим для обновления состояния игры.

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

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

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

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.

Вот, как это можно сделать:

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

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

А вот теперь точно все. Запустите игру и проверьте, все ли работает как положено.

В следующей части

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

Мой странный творческий путь занес меня в разработку игр. Благодаря отличной студенческой программе от IT-компании, название которой СостоИт из одной Греческой МАленькой буквы, сотрудничающей с нашим университетом, удалось собрать команду, родить документацию и наладить Agile разработку игры под присмотром высококлассного QA-инженера (здравствуйте, Анна!)

Без особо долгих размышлений, в качестве движка был выбран Unity. Это замечательный движок, на котором действительно быстро и легко можно сделать очень плохую игру, в которую, в здравом уме, никто и никогда не будет играть. Чтобы создать хорошую игру, все же придется перелопатить документацию, вникнуть в некоторые особенности и набраться опыта разработки.

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

Пару слов о том, как она сделана.
Сделана с помощью Blender и пары скриптов на питоне. На время съемки, в углу экрана находились 16 квадратиков, цвет которых кодировал 32 бита числа с плавающей запятой — вращение телефона в данный момент времени. R, G — данные, B — четность. 0 — 0, 255 — 1. Снятое на компьютере видео разбивалось на кадры с помощью ffmpeg, каждому кадру рендера в соответствие ставился расшифрованный угол. Такой формат позволил пережить любое сжатие в процессе съемки и поборол тот факт, что все программы имеют несколько разные представления о течении времени. В реальности игра играется так же как и на рендере.

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

Проблема 1: Бесконечность
Проблема 2: Генерация уровня

Есть несколько основных подходов к строительству endless runner»ов:

  1. Использование готовых сегментов уровня, которые стыкуются случайным образом. Так сделано, например, в Subway Surfers. Это просто реализовать, но игрок к этому быстро привыкает и знает, к чему готовиться, что скучно.
  2. Уровень — просто прямая, на которой случайным образом расставляются препятствия. Так сделано в Joypack Joyride и Temple Run. В нашем случае, это сильно ограничило бы количество маневров.
  3. Все генерируется случайным образом. Самый сложный, непредсказуемый и интересный для игрока вариант.

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

Структура уровня

Летим мы в пещере, она имеет пол и потолок — пару блоков, элементарных строительных единиц. Блоки объединяются в сегменты, которые бесшовно стыкуются друг с другом. Сегменты, как единое целое, вращаются вокруг самолета и двигаются по его вектору скорости, создавая иллюзию полета. Если сегмент выходит из поля зрения камеры — он очищается от блоков, пристыковывается к последнему сегменту уровня и заполняется новыми блоками, согласно указаниям генератора. Совокупность таких сегментов — и есть уровень.

Опытные Unity-разработчики могли вполне оправданно поморщиться, прикинув объем работ и все возможные подводные камни. Но на словах все просто, а опыта разработки у меня не было…

Основные Законы Физики в Unity

1. Коллайдеры не должны двигаться, вращаться, включаться\выключаться и менять размер.
2. Если объект движется или вращается — он должен быть твердым телом т.е. иметь компонент Rigidbody.
3. Если объект является твердым телом — двигаться и вращаться он должен через методы твердого тела.
Есть три уровня управления твердым телом:

Что остается за бортом? Включение\выключение объекта и масштаб. Я не знаю, есть ли способ изменить размер объекта, не смущая движок. Вполне возможно, что нет. Выключение объекта проходит безболезненно, а включение… да, вызывает пересчет физики, в окрестностях включенного объекта. Поэтому старайтесь не включать одновременно слишком много объектов, растяните этот процесс во времени, чтобы пользователь не заметил.

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

Есть еще одна особенность Unity, не относящаяся к физике, но достойная упоминания: динамическое создание и удаление объектов через методы Instantiate/Destroy — БЕЗУМНО медленный процесс. Я боюсь себе даже представить, что там происходит под капотом во время создания объекта. Если вам нужно создавать и удалять что-то динамически — используйте фабрики и заправляйте их нужными объектами во время загрузки игры. Instantiate должен вызываться в крайнем случае — если у фабрики вдруг закончились свободные объекты, а про Destroy забудьте навсегда — все созданное должно использоваться повторно.

Применение законов на практике

Уровень, очевидно, должен вращаться и двигаться.
Облегчим себе жизнь навечно, разместив ось вращения уровня — самолетик — в начале координат. Теперь мы сможем вычислять расстояние от точки до него, вычисляя длину вектора координат точки. Мелочь, а приятно.
Совместное движение объектов легко реализуется через иерархию объектов в Unity, потому что дети являются частью родителя. Например, описанная структура уровня логично реализуется следующим образом:
— Ось вращения
— — \ Уровень
— — — \ Сегмент 1
— — — — \ Блок 1 (Collider)
— — — — \ .
— — — — \ Блок N
— — — \ Сегмент 2 .
— — — \ Сегмент 3 .
— — — \ Сегмент 4 .
(Можно даже обойтись без объекта уровня)

Скрипт на оси получает данные с гироскопа и выставляет ей соответствующий угол… И нарушает сразу множество правил, потому что вращение передастся по иерархии на коллайдеры, что сведет физический движок с ума. Придется делать ось твердым телом и вращать ее через соответствующий метод. Но что с движением уровня? Очевидно, что ось вращения и объект уровня перемещаться не будут, каждый сегмент нужно двигать персонально, иначе мы сталкиваемся с проблемой бесконечности. Значит, твердыми телами должны быть сегменты. Но у нас уже есть твердое тело выше в иерархии и твердое тело не может быть частью твердого тела. Логичная и элегантная иерархия не подходит, все придется делать руками — и вращение, и перемещение, без использования объекта для оси вращения. Будьте готовы к такому, если у вас уникальные геймплейные фичи.

Если двигать непосредственно сегменты пришлось бы и так, то вращать их придется вынужденно. Основная сложность в том, что в физическом движке Unity нет метода «вращать объект вокруг произвольной точки» (он есть у Transform, но не искушайтесь). Есть только «вращать вокруг своего центра». Это логично, потому что вращение вокруг произвольной оси — одновременно и вращение, и движение, а это две разные операции. Но его можно имитировать. Сначала вращаем сегмент вокруг своей оси, потом вращаем координаты «своей оси» вокруг самолета. Благодаря тому, что самолет у нас в начале координат, не придется вспоминать даже школьную геометрию и лезть в википедию, в Unity уже все есть. Достаточно перевести угол поворота в кватернион и умножить его на координаты точки. Кстати, узнал я об этом прямо во время написания статьи, до этого использовалась матрица поворота.

У нас есть враги, которые отталкивают самолет в стену, надеясь убить. Есть щит, который отталкивает самолет от стен, помогая выжить. Реализовано это тривиально — есть вектор смещения, который каждый кадр прибавляется к координатам каждого сегмента и сбрасывается после этого. Любой желающий пнуть самолетик, через специальный метод, может оставить вектор своего пинка, который прибавится к этому вектору смещения.

Мастер Йода рекомендует:  Сохраняем данные пользователя в браузере с помощью IndexedDB

В конечном итоге, настоящие координаты сегмента, каждый кадр, вычисляются центром управления движением уровня как-то так:
Vector3 position = segment.CachedRig > После всех вычислений и костылей, необходимых для работы точной стыковки сегментов при регенерации, segment.truePosition отправляется в метод MovePosition твердого тела сегмента.

Выводы

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

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

Unity — очень мощный, прогрессивный движок с большим потенциалом. Он обладает множеством уже встроенных функций (в том числе и физическим движком NvidiaPhysX ), которые нам, пользователям, прописывать вручную не придется. 🙂
В этой небольшой статье я бы хотел обсудить физические возможности движка. Итак, начнем:

Rigidbody

Что это такое?

За функцией Rigidbody скрывается Абсолютно Твердое Тело (АТТ ). Если объяснять грубо и понятно, то АТТ в физике и механике — это идеальное твердое тело, которое под воздействием силы не может менять свои свойства, но может (под ее воздействием) перемещаться в 3х измерениях (вниз, вверх, вперед и т.д., т.е. в наших X-Y-Z осях), а также вращаться в 3х измерениях (опять же по осям X-Y-Z).

В Unity , как и в других игровых движках (опять же называю их именно «игровыми» движками грубо), Rigidbody используется для различных объектов, с которыми мы можем взаимодействовать, толкая, пиная и т.п. Подобные объекты под нашим влиянием будут далее под воздействием гравитации кататься, передвигаться и сталкиваться с другими предметами.

Какое применение мы можем найти этой функции?

К примеру, для создания автомобиля, кроме Rigidbody нам понадобятся 4 Wheel Collider «а и код (скрипт ) , применяющий силовое воздействия к колесам, в зависимости от нажатых клавиш.

Настраиваемые характеристики

  • Mass — Масса нашего объекта в килограммах . Рекомендуется не ставить значения массы в 100 раз больше или меньше масс других АТТ .
  • Drag — Насколько тело подвержено сопротивлению воздуха, когда оно движется под воздействием сил. При значении сопротивления нет, а бесконечное значение мгновенно остановит наш объект.
  • Angular Drag — Насколько тело подвержено сопротивлению воздуха, когда оно вращается под воздействием сил. При значении сопротивления нет, а бесконечное значение мгновенно прекратит вращение нашего объекта.
  • Use Gravity — При включении, объект становится подвержен влиянию гравитации.
  • Is Kinematic — При включении, объект становится не подвержен влиянию физического движка и может изменяться только его функцией Transform . Это может быть полезно для создания движущихся платформ, к примеру.
  • Interpolate — Применяется только в случае, если движения вашего АТТ кажутся вам странными или неуклюжими и т.п.:
    1. None: Интерполяция не применяется
    2. Interpolate: По-сравнению с трансформацией предыдущего кадра (фрейма ) , следующий будет сглажен.
    3. Extrapolate: Трансформация текущего кадра сглаживается, по-сравнению с оценочной (примерной) трансформацией следующего.
  • Freeze Rotation — Запрещает любое вращение, как скриптовое, так и при столкновениях. Однако, вращение можно будет выполнять функцией transform.Rotate()
  • Collision Detection — Используется для того, чтобы быстро-движущиеся объекты не проходили сквозь другие объекты, не находя Collision «ов (специальная «сетка» на объектах, которой они сталкиваются друг с другом и с игроком).
    1. Discrete: Значение по-умолчанию для того, чтобы наш объект «замечал» все другие объекты, с которыми может столкнуться.
    2. Continuous: Используйте Discrete Сollision с динамическими объектами столкновения (у которых имеется АТТ ), а Continuous Сollision для статических MeshCollider «ов (без АТТ ). Режим Continuous Dynamic использует Continuous Сollision для одного конкретного АТТ . Остальные АТТ будут использовать режим Discrete . (Это сильно скажется на нагрузке физического движок, просто оставьте Discrete , если не возникает проблем со столкновением быстрых объектов)
    3. Continuous Dynamic: Используется для объектов в режиме Continuous или Continuous Dynamic Collision . Continuous Сollision также будет использоваться для статических MeshCollider «ов (без АТТ ). Для всех остальных используется режим Discrete . Используется для быстро движущихся объектов.

Как мы можем использовать эту функцию?

Базовые знания.

Чтобы использовать АТТ , нам нужен уже созданный игровой объект (GameObject ), кликнув на нем, мы проходим в меню по следующему пути: Components — Physics — Rigidbody . Все, АТТ добавлено! 🙂
Теперь объект подвержен гравитации, к нему можно применять силы с помощью скриптов, но для того, чтобы объект вел себя именно так, как вам нужно, следует добавить Collider или Joint .


Код правит миром.

В скрипте манипулировать нашим объектом теперь мы будем с помощью функций AddForce() и AddTorque() .
Так как я в Unity применяю JavaScript , мои примеры будут с ним, ссылки на другие примеры скриптинга (на C# или Boo ) вы найдете ниже, в пункте Дополнительная информаия по АТТ .

// Функция раскручивает объект вокруг заданной оси. // 1 тип: function AddTorque (torque: Vector3, mode: ForceMode = ForceMode.Force) : vo >

АТТ взаимодействует с объектами.

Для правильной работы наших АТТ их нужно снабдить Collider «ами (или Collision «ами, как вам будет угодно ^.^).
Подробно о коллайдерах читайте ниже.

Размер имеет значение!

Соблюдайте размеры вашего объекта, ведь они гораздо более значимы даже массы АТТ . Если ваш объект движется неправильно, висит в воздухе или не сталкивается, попробуйте настроить его величину (не АТТ , а самого объекта). При импортировании модели из 3D редактора ее размеры сохраняются, так что будьте внимательны на стадии моделирования и соблюдайте размеры всех моделей.

Дополнительная информация по АТТ

На этом, описывать АТТ или Rigidbody , я, пожалуй, закончу. Однако, есть пара подсказок, специально для тех, кто до сюда долистал:)

  1. Стандартный размер куба в Unity равен 1 метру , поэтому, проверять размер ваших моделей по нему очень удобно. Чтобы создать куб, выберите в меню GameObject — Create Other — Cube
  2. Относительный показатель Mass определяет, как два объекта будут взаимодействовать друг с другом.
  3. Mass не влияет на скорость падения с высоты, для этих целей используйте Drag .
  4. Чем выше значения Drag , тем больше весит предмет. стандартные значения варьируются от 0.001 (твердый кусок металла) до 10 (перышко).
  5. Если вам нужно изменять объект как с помощью скриптов, так и с помощью физики, добавьте к нему АТТ с параметром Kinematic .

Colliders

Что это такое?

В предыдущем разделе мы рассмотрели принцип работы Rigidbody и упомянули так называемые коллайдеры . Коллайдер для нас — вспомогательный объект в виде сетки простой примитивной или, наоборот, сложной формы, который находится вокруг нашей модели или части модели и взаимодействует с другими объектами, если те тоже окружены коллайдерами.
Чтобы наглядно объяснить знатокам редактора мира *Warcraft 3*, представьте себе импортированную нами модель, которой мы в редакторе дудадов не присвоили текстуры путей — это будет наш объект; а роль коллайдеров тут будут играть блокираторы пути вокруг модели. Естественно, это довольно грубое сравнение, ведь в Unity они гораздо более функциональны. Что-ж, рассмотрим поподробнее.

Виды коллайдеров.

Коллайдеры добавляются через меню Component — Physics . Есть несколько видов:

  • Box Collider — в форме куба.
  • Sphere Collider — в форме сферы.
  • Capsule Collider — в форме капсулы.
  • Mesh Collider — автоматически создает коллайдер по форме сетки объекта, не может сталкиваться с другими коллайдерами этого же типа. В основном используется для статических объектов, например, окружение гоночной трассы.
  • Wheel Collider — используется для колес, очень полезная вещь.
  • Compound Collider — комбинации примитивов, которые вместе действуют как один. Чтобы создать такой сложный коллайдер нужно к нашему базовому коллайдеру добавить дочерние объекты, а к ним уже привязать по примитиву. Таким образом, к примеру, очень удобно делаются простенькие коллайдеры для машин.

Настраиваемые характеристики

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

  • Куб
    • Material — Показывает, как коллайдер взаимодействует с остальными объектами, при этом присваивая физический материал, например, металл, лед и т.п.
    • Is Trigger — Если параметр включен, то на объект воздействует скрипт, а не физика.
    • Size — Размер коллайдера по осям X-Y-Z.
    • Center — Положение коллайдера, относительно локальных координат объекта.
  • Сфера
    • Radius — Радиус сферы, заменяет параметр Size .
    • Остальные параметры без изменений.
  • Капсула (параметры заменяют размер)
    • Radius — Толщина капсулы.
    • Height — Высота цилиндрической части коллайдера (без скругленных оснований).
    • Direction — Направление коллайдера, относительно локальных координат объекта.
  • Mesh Collider (параметры заменяют размер)
    • Mesh — Выбор нужного меша для создания коллайдера.
    • Smooth Sphere Collisions — Включение этой функции сглаживает поверхность коллайдера. Использовать следует на гладких поверхностях, к примеру, наклонный ландшафт без лишней углоатости, по которому должны скатываться сферы.
    • Convex — При включении позволяет нашему коллайдеру сталкиваться с другими такими же. Convex Mesh Collider «ы ограничены до 255 трианглов .
  • Wheel Collider (параметры заменяют размер)
  • Radius — Радиус колеса.
  • Suspension Distance — Максимальная дистания увеличения подвески колеса. Подвеска всегда увеличивается вниз по локальной оси Y .
  • Suspension Spring — Подвеска пытается достигнуть указанной точки, используя различные силы.
  1. Spring:// Пытается достигнуть указанной точки (позиции). Чем выше параметр, тем быстрее она достигается.
  2. Damper:// Смягчает, замедляет скорость движения подвески. Чем выше значение, тем медленнее двигается амортизатор.
  3. Target Position:// Полный «путь», который может «пройти» подвеска. означает полностью расправленный амортизатор, а 1 — полностью сжатый. Значением по-умолчанию является 0, что соответствует обычной автомобильной подвеске..
  • Mass — Масса колеса.
  • Forward/Sideways Friction — Параметры трения при простом качении колеса и при качении боком (такое бывает в заносах или при дрифте).

Физика шара в арканоиде?

Пинка дай когда скорость снижается Addforce — cсылка
скорость шара в 2d пространстве — ccылка

еще варианты
1. Массу убрать на 0 (не помню можно ли)
2. Linear Drag — Коэффициент натяжения влияющий на смещение позиции. ставим в 1. 0 — эт отключения
3. Angular Drag -Коэффициент натяжения влияющий на вращение объекта (думаю с помощью этого можно без остановочно крутить объект вокруг своей оси))).
4. Edit>Project setting> Physic2d — Gravity X,Y = 0; а поумолчанию стоит -9.81 (хотя тог да бы объект не останавливался а падал) хначит наверно отключено

Пишем арканоид на Unity. Механика мяча и платформы. Microsoft XNA: Арканоид шаг за шагом

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

  • Start() : используется для инициализации переменных или параметров, необходимых нам в коде.
  • Update() : вызывается каждый кадр игры, необходим для обновления состояния игры.

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

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

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

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.

Вот, как это можно сделать:

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

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

А вот теперь точно все. Запустите игру и проверьте, все ли работает как положено.

В следующей части

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

Несколько дней назад, бороздя просторы великого и могучего Интернета, наткнулся на Microsoft XNA Studio. Не то чтобы услышал об этом фреймворке в первый раз, но все предыдущие разы как-то проходил мимо, времени разбираться не было совершенно.
В этот раз что-то меня дернуло покопаться поглубже. Справедливо рассудив что для знакомства с библиотекой лучшего метода чем реализовать что нибудь на нем нет, а также имея в распоряжении свободный вечер, решил написать что нибудь простенькое, например любимый мною с детства Arkanoid (Brick Out), не корысти ради, а ознакомления для.

Это моя первая статья на хабре, убедительно прошу ногами не пинать

Смысл данной статьи показать как легко можно начать создавать свои игры при помощи XNA и, собственно, дать стимул для дальнейшего изучения этой платформы. Посему, на полноценную игру не претендует, графика — никакая, как и художник из меня. Да и физика могла бы быть пореалистичнее, но это уже выходит за рамки данной статьи, уверен что интересующиеся разработкой игр найдут немало достойных (и не очень) материалов в сети.

Итак, что же такое Microsoft XNA?

Microsoft XNA это набор инструментов и библиотека для разработки мультиплатформенных 2D и 3D игр в управляемой среде Microsoft Managed Runtime Environment. Поддерживаются платформы Windows, Microsoft Xbox 360 и Microsoft Zune. Теоретически писать можно на любом.Net языке, в любой IDE, но оффициально поддерживаются только C# и XNA Game Studio Express и все версии Visual Studio 2005 и выше. XNA также дает возможность портировать игры на поддерживаемые платформы с минимальными изменениями.

Последняя версия на момент написания статьти – Microsoft XNA Game Studio 3.1 (73.2 MB)

Создание проекта

Создадим новый проект – XNA Game Studio 3.1 – Windows Game (3.1)

Мастер создаст скелет игры:

Самый большой интерес для нас представляет файл Game1.cs, в котором определен класс Game1, наследованный от Microsoft.Xna.Framework.Game, где мы и будем разрабатывать нашу игру.
В классе Game1 переопределены следующие методы Game:

Void Initialize() – Вызывается единожды, для инициализации ресурсов до начала игры
void LoadContent() – Вызывается единожды, используется для загрузки контента (спрайты и т.д.)
void UnloadContent() – Вызывается единожды, используется для выгрузки контента
void Update(GameTime gameTime) – В этом методе реализуется собственно логика игры, обработка коллизий, обработка событий клавиатуры или джойстика, проигрывание аудио и т.д.
void Draw(GameTime gameTime) – Вызывается для прорисовки игрового поля.

На данный момент скомпилированная игра выглядит вот так

Добавление контента

Добавим игровые ресурсы, в данном случае картинки фона кирпича, ракетки и мячика – Content (Right Click) -> Add -> Existing Item…

Обратите внимание на свойство Asset Name, его мы используем для создания обьекта Texture2D необходимого для дальнейшей анимации.

Рисуем фон игрового поля

Загрузим изображение для фона игрового поля:

  1. private Rectangle _viewPortRectangle; // Границы игрового поля
  2. private Texture2D _background; // Фон игрового поля
  3. // Границы игрового поля
  4. _viewPortRectangle = new Rectangle(0, 0,
  5. graphics.GraphicsDevice.Viewport.W >(@»background» );
  1. GraphicsDevice.Clear(Color.CornflowerBlue);
  2. spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
  3. // Рисуем фон
  4. spriteBatch.Draw(_background, _viewPortRectangle, Color.White);
  5. spriteBatch.End();
  6. base .Draw(gameTime);

* This source code was highlighted with Source Code Highlighter .

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

Создание игрового обьекта

Создадим класс GameObject инкапсулирующий любой из наших игровых обьектов:

  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics ;
  3. namespace Arkanoid
  4. public class GameObject
  5. public Texture2D Sprite < get ; set ; >// Спрайт
  6. public Vector2 Position; // Положение
  7. public Vector2 Velocity; // Скорость
  8. public int Width < get < return Sprite.Width; >> // Ширина
  9. public int Height < get < return Sprite.Height; >> // Высота
  10. public bool IsAlive < get ; set ; >// Жив ли обьект
  11. public Rectangle Bounds // Границы обьекта
  12. return new Rectangle((int )Position.X, (int )Position.Y, Width, Height);
  13. // Разворачивание движения по горизонтальной оси
  14. public vo >// Разворачивание движения по вертикальной оси
  15. public vo > * This source code was highlighted with Source Code Highlighter .

Отрисовка и анимация ракетки

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

  1. private GameObject _paddle; // Ракетка
  2. protected override void LoadContent()
  3. // Создание ракетки, начальное положение в середине игрового поля, повыше нижнего края
  4. _paddle = new GameObject(Content.Load

(@»paddle» ));

  • _paddle.Position = new Vector2((_viewPortRectangle.Width — _paddle.Width) / 2,
  • _viewPortRectangle.Height — _paddle.Height — 20);
  • * This source code was highlighted with Source Code Highlighter .

    Отрисовка ракетки на экране

    1. protected override void Draw(GameTime gameTime)
    2. spriteBatch.Draw(_paddle.Sprite, _paddle.Position, Color.White);

    * This source code was highlighted with Source Code Highlighter .

    На данном этапе, если скомпилировать приложение, получим что-то вроде этого:

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

    1. KeyboardState keyboardState = Keyboard.GetState();
    2. // Двигаем ракетку вправо
    3. if (keyboardState.IsKeyDown(Keys.Right))
    4. _paddle.Position.X += 6f;
    5. // Двигаем ракетку влево
    6. if (keyboardState.IsKeyDown(Keys.Left))
    7. _paddle.Position.X -= 6f;
    8. // Ограничиваем движение ракетки игровым полем
    9. _paddle.Position.X = MathHelper.Clamp(_paddle.Position.X, 0, _viewPortRectangle.Width — _paddle.Width);

    * This source code was highlighted with Source Code Highlighter .

    Отрисовка кирпичей

    Создадим массив GameObject представляющий кирпичи которые собственно и будем разбивать

    1. private int _brickPaneW >// Сколько кипричей рисовать в ширину
    2. private int _brickPaneHeight = 5; // Сколько кипричей рисовать в высоту
    3. private Texture2D _brickSprite; // Спрайт кирпича
    4. private GameObject[,] _bricks; // Массив кирпичей

    * This source code was highlighted with Source Code Highlighter .

    Добавим следующий код в метод LoadContent()

    1. protected override void LoadContent()
    2. // Создание массива кирпичей
    3. _brickSprite = Content.Load

    (@»brick» );

  • _bricks = new GameObject[_brickPaneW >
  • * This source code was highlighted with Source Code Highlighter .

    Отрисовка массива кирпичей, отисовка производится если кирпич “жив”, т.е. не разбит мячем

    1. protected override void Draw(GameTime gameTime)
    2. // Рисуем кирпичи
    3. if (brick.IsAlive)
    4. spriteBatch.Draw(brick.Sprite, brick.Position, Color.White);

    * This source code was highlighted with Source Code Highlighter .

    На данном этапе игровое поле выглядит следующим образом

    Отрисовка мячика

    Создаем обьект мячика

    1. private GameObject _ball; // Мячик
    2. protected override void LoadContent()
    3. // Создание мячика, начальное положение в середине на ракетке,
    4. // начальное направление — вправо, вверх
    5. _ball = new GameObject(Content.Load

    (@»ball» ));

  • _ball.Position = new Vector2((_viewPortRectangle.W >
  • * This source code was highlighted with Source Code Highlighter .

    Для анимации мячика добавим новый метод UpdateBall(), и его вызов в в метод Update(). Данный метод нам понадобится в дальнейшем для обработки столкновений мячика с кирпичами и ракеткой

    1. private void UpdateBall()
    2. protected override void Update(GameTime gameTime)
    3. // Двигаем мячик
    4. UpdateBall();

    * This source code was highlighted with Source Code Highlighter .

    Для отрисовки мячика добавим следующий код в метод Draw()

    1. protected override void Draw(GameTime gameTime)
    2. // Рисуем мячик
    3. spriteBatch.Draw(_ball.Sprite, _ball.Position, Color.White);

    * This source code was highlighted with Source Code Highlighter .

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

    Обработка столкновений

    Создадим новый метод определяющий место столкновения обьектов и меняющий направление полета мяча.

    1. // Определение стороны столкновения и отражение направления полета мячика
    2. public void Collide(GameObject gameObject, Rectangle rect2)
    3. // Обьект столкнулся сверху или снизу, отражаем направление полета по горизонтали
    4. if (rect2.Left // Обьект столкнулся слева или справа, отражаем направление полета по вертикали
    5. else if (rect2.Top * This source code was highlighted with Source Code Highlighter .

    Добавим следующий код в метод UpdateBall()

    1. private void UpdateBall()
    2. // Будущее положение мяча, нужно для предотвращения «залипания» мяча на поверхности обьекта
    3. Rectangle nextRect = new Rectangle((int )(_ball.Position.X + _ball.Velocity.X),
    4. (int )(_ball.Position.Y + _ball.Velocity.Y),
    5. _ball.Width, _ball.Height);
    6. // Столкновение с верхним краем игрового поля
    7. if (nextRect.Y // При сталкивании мяча с нижним краем игрового поля, мячик «умирает»
    8. if (nextRect.Y >= _viewPortRectangle.Height — nextRect.Height)
    9. _ball.IsAlive = false ;
    10. // Столкновение мячика с левым или правым краем игрового поля
    11. if ((nextRect.X >= _viewPortRectangle.W >// Столкновение мячика с ракеткой
    12. if (nextRect.Intersects(_paddle.Bounds))
    13. Collide(_ball, _paddle.Bounds);
    14. // Столкновение мячика с кирпичами
    15. foreach (var brick in _bricks)
    16. if (nextRect.Intersects(brick.Bounds) && brick.IsAlive)
    17. brick.IsAlive = false ;
    18. Coll > * This source code was highlighted with Source Code Highlighter .

    Итак, что получилось

    Конечно физика в игре, мягко говоря, никакая, мячик иногда залипает при столкновении с движущейся ракеткой. Но, повторюсь, смысл данной статьи знакомство со средой Microsoft XNA Game Studio, и, надо сказать, она отлично справляется с рутиной, освобождая время разработчика для фокусировки внимания на логике игры.

    Теги: Добавить метки

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

    Ещё хотелось бы отметить, что я не знаю основную аудиторию и не могу изложить материал так, чтобы было интересно всем..

    Арканоид на 39 строк — согласитесь, звучит многообещающе; некоторым, наверное, даже не верится. Но такое возможно.

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

    Написан он на PlayBasic, для запуска кода можно скачать бесплатную версию по этой ссылке и самим убедиться, что он работает:

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

    Пару слов наперед, основной цикл программы содержится между do и Loop, то есть построение карты происходит постоянно, когда цикл заканчивается, массив bl() содержит информацию о блоке т. е. он по сути говорит стоит ли сейчас рисовать блок или нет, и если блок активный, то проверяем столкновения. Стоит заметить одну особенность: столкновения просчитываются не сразу, то есть если наш мяч только задел блок, но в цикле For до него не дошли, то ничего не произойдет. Из этого следует, что наш мяч в худшем случае может уйти в блок на 2 пикселя.Вот эта маленькая ошибка и дала сделать арканоид на 39 строк.

    Ой, забыл упомянуть ещё о самом важном: LockBuffer/UnLockBuffer — это говорит о том, что карта выводится на экран сразу же, иными словами, одним объектом. В принципе, этого можно было избежать, но для того, чтобы программа выводила изображение быстрее, нужно закрывать буфер.

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

    Для лентяев прикрепил ещё исходник с игрой:

    Создание игр на Unity. Часть 2 — Игровая физика и код.

    Дубликаты не найдены

    Спасибо! Мне очень приятно что вам понравились эти уроки и моя игра 🙂

    Запустил Unity, создал новый проект, добавил картинку и запихнул на неё свой скрипт и работает!

    Скорее всего вы допустили ошибку когда копировали код из моего файла. В идеале, нужно было перетащить мой скрипт в Unity и оттуда перетащить его на персонажа.

    1. Вам говорят то, что есть на самом деле, что проект уже содержит скрипт(класс) с таким именем и из-за этого возникает конфликт.

    2. Скорее всего, вы дали вашему скрипту название не такое как у класса который описан в скрипте «Move_Player».
    Та же ошибка высветилась у меня, когда я переименовал свой скрипт.

    Мой совет, создайте новый проект, добавьте вашего героя, перетащите мой скрипт в Unity пустую область внизу(в папку), а затем перетащите его на своего героя. Не меняйте ему(скрипту) название(если захотите сменить, меняйте название класса и внутри скрипта) . Обязательно добавьте ему компоненты о которых рассказано в уроке:
    Rigidbody 2D, Animator, SpriteRenderer.

    Unity3d Tank Tutorial: Ходовая часть (Урок 1. Основы механики транспортного средства)

    Вступление

    Итак вы уже не новички в Unity, вы умеете создавать сцену, расставлять объекты на сцене, создавать terrain, делать префабы и тд… и главное — работать со скриптами, либо вы уже изучили статьи: Unity3D для начинающих — Туториал 1 и Unity3d script basics. Все эти знания вам пригодятся ведь в этом уроке мы двинемся намного дальше.

    А именно: в первой части этого урока вы узнаете что такое Wheel Collider, как с помощью него управлять транспортным средством и создать реалистичное поведение подвески автомобиля, во второй части урока, на основе всего этого я покажу как сделать ходовую часть танка с соответствующей физикой и контроллерами.

    Собственно то что вы видите на изображении сверху (это будет результат данного урока) вы можете опробовать «вживую» прямо в браузере. Хотите сделать это сами? Тогда добро пожаловать под кат

    Перед тем как начать рассказывать об основах моделирования механики автомобиля на Unity я не могу не отметить что на официальном сайте уже есть уроки на эту тему например здесь. Правда на протяжении всего этого даются лишь указания на то, какой скрипт прикрепить к какому объекту и лишь изредка объясняют чтонибудь полезное, в третьей части урока наконец то объясняют как работает главный скрипт, хотя по моему это надо было делать в самой первой части, и начинать объяснять с того момента как работают wheel collider’ы и как они взаимодействуют с rigidbody, в итоге я сделал вывод что данный урок не рассчитан на новичков в Unity и хочу это исправить.

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

    1. Создаем «Автомобиль»

    Для начала проделайте стандартные процедуры, создайте сцену, создайте terrain, либо используйте уже готовые, затем создайте пустой Game Object(GO), (GameObject->Create Empty), назовем его какнибудь оригинально, например Car.

    Затем создайте куб (GameObject->Create Other -> Cube) примените к нему какой нибудь материал из стандартных, чтобы его было лучше видно. Представим себе что это кузов нашего автомобиля, и растянем его с помощью Scale по ширине и длине так чтобы передняя часть этого кузова смотрела вдоль оси Z (синяя ось, именно она официально считается передом в мире Unity) затем перетянем наш Cube на объект Car во вкладке Hierarchy, чтобы он стал дочерним объекту Car. Перейдем на сам объект Car и добавим ему Rigidbody (Component -> Physics -> Rigidbody). Назначим ему соответствующий вес, примерно 1500 кг., кузов автомобиля готов.

    Помимо кузова у автомобиля должны быть колеса, теперь создайте цилиндр (GameObject->Create Other -> Cylinder), используйте все тот же Scale, придайте ему вид колеса, затем разверните его по оси Z на 90 градусов (важно! Только по оси Z!).

    Переименуем наш только что созданный цилиндр в Wheel Forward Left, установим колесо на свое место, тоесть спереди и слева от нашего куба, (повторяю, передом в Unity считается положительная чать оси Z).

    Перетянем Wheel Forward Left на объект Car. Назначим колесу текстуру по детальнее чтобы лучше видеть вращение колеса. Теперь скопируем наше колесо (Правой кнопкой по Wheel Forward Left и Duplicate), назовем Wheel Back Left и поставим на законное место, по аналогии поступите с остальными двумя колесами.

    Итак, наш суперкар почти готов! Поднимите его немного над поверхностью terrain’а и нажмите Play, автомобиль упадет на землю и встанет колом на колеса, о мягкой подвеске ему еще только мечтать, выходите из Play mode. Как видите у наших колес имеется компонент под названием Capsule Collider, а у кузова Box Collider, я не буду рассказывать в этом уроке что такое коллизии и как на основе них рассчитать положение объекта в пространстве, объясню проще: если у объекта имеется какой – либо из простых collider’ов (Box, Capsule, Mesh,…) то этот объект может взаимодействовать с другими объектами содержащими Rigidbody и один или несколько collider’ов, в свою очередь объект содержащий Rigidbody будет вычислять свою позицию на основе столкновений всех подчиненных ему collider’ов и назначенных им физических материалов.

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

    А пока что выберите каждое из наших колес и удалите у них Capsule Collider (Правой кнопкой по нему и Remove Component). Нажмите Play, теперь автомобиль больше не стоит на колесах, они прошли сквозь террейн и взаимодействует с поверхностью у нас теперь только кузов.

    2. Добавляем Wheel Colliders

    Итак что же такое этот загадочный Wheel Collider? Давайте разбираться. Создайте пустой GameObject назовите его WCollider Forward Left, теперь добавьте к нему компонент Wheel Collider (Component -> Physics -> Wheel Collider), он выглядит как окружность с отрезком внутри, он может быть слишком большим или слишком маленьким по сравнению с вашим колесом, все зависит от того насколько вы увлеклись использованием scale. К счастью у него есть параметр Radius, изменяя данный параметр подгоните его под радиус своего колеса, затем создайте новый префаб (Assets -> Create -> Prefab) назовите его WCollider затем перетяните WCollider Forward Left на префаб. Мы создали префаб для удобства, так как коллайдеров у нас будет столько же сколько колес, и чтобы не изменять параметры каждого, будем изменять параметры префаба, остальные коллайдеры унаследуют его свойства. Теперь делаем стандартную процедуру, перетаскиваем WCollider Forward Left на объект Car и помещаем в центр переднего левого колеса, дублируйте его 3 раза переименуйте и переместите в соответствии с другими колесами.

    Нажмите Play, автомобиль упадет и опять встанет на колеса (кстати если колеса все равно проходят сквозь террейн, это значит что автомобиль падает на землю с очень большой скоростью, и вам просто напросто нужно уменьшить расстояние до земли, либо увеличите параметр Drag у Rigidbody). Как видите результат не сильно отличается от того где у нас на колёсах стояли Capsule Colliders, все правильно, потому, что мы не задали нашим Wheel Collider’ам никаких параметров.

    Итак, выйдите из Game Mode, выберите наш префаб WCollider, поехали меняем свойства компонента Wheel Collider:

    1. Suspension Distanse – по сути это длина пружины нашей подвески, ставим 0.15
    2. Suspension Spring -> Spring – жесткость подвески, чем больше вес нашего Rigidbody, тем больше должна быть жесткость, ставим 9000
    3. Suspension Spring -> Damper – Смягчитель подвески, большее значение заставляет пружину двигаться медленнее, ставим 100
    4. Mass – масса колеса, оставляем 1
    5. Forward Friction – «передняя» сила трения колеса, оставляем как есть
    6. Sideways Friction – «боковая» сила трения колеса, полезно если хотим реализовать дрифт автомобиля, оставляем как есть

    Итого у нас получилось:
    (Не смотрите на радиус, у вас он может быть другой, главное чтобы окружность совпадала с вашим колесом)

    Итак, нажмите Play сейчас, посмотрите, наш автомобиль ведет себя теперь совсем по другому, теперь он пружинит от поверхности террейна, а если вы поставите его на склон какой нибудь горки, он покатится с неё, вот так у нас работают Wheel Collider’ы.

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

    3. Управляем Wheel Collider’ами

    В этом уроке я буду писать скрипты на C#, простите меня JavaScript’еры, он мне привычнее, я думаю вы разберетесь.

    Создаем новый С# скрипт (Assets -> Create -> C Sharp Script), назовем его CarController, открываем и напишем следующее:

    1. Главный класс скрипта должен называться точно так же как и файл скрипта, иначе компилятор выдаст ошибку.
    2. Массив передних коллайдеров.
    3. Массив задних коллайдеров.
    4. Будем использовать функцию Start() для инициализации.
    5. Как то в уроке Unity3d script basics я говорил что для физического взаимодействия с объектами лучше использовать функцию FixedUpdate(), нежели функцию Update().

    Затем перетяните скрипт на объект Car, как вы можете видеть в инспекторе, у нас в скрипте есть два поля, собственно это массивы которые мы объявили, в них надо перетянуть наши коллайдеры следующим образом.

    Далее работаем с нашими коллайдерами, дополняем скрипт:

    Теперь можете нажать Play, и используя кнопки W,S или стрелки вперед — назад, привести в движение нашу «формулу один», а кнопками A,D, или стрелками влево – вправо, поворачивать.

    Давайте же разберемся что делает этот скрипт:

    1. Максимальный угол поворота колес.
    2. Максимальный крутящий момент передающийся на колесо.
    3. Максимальный тормозной момент.
    4. Функция GetAxis() класса Input ждет события которое возникает когда мы нажимаем на клавиши движения на контроллере, либо двигаем стики джойстика, функция принимает направление виртуальной оси, (например «Vertical» – это клавиши W,S, либо движение джойстика вперед – назад) и возвращает число от -1 до 1, где -1 – движение назад либо влево, (клавиша S в «Vertical» оси, D в «Horizontal») 0 – оси не активны и 1 – движение вперед, либо вправо (клавиша W в «Vertical» оси, A в «Horizontal», либо движение стика джойстика влево — вправо).
    5. Передаем результаты полученные от виртуальных осей в функцию CarMove().
    6. Для каждого Wheel Collider’а находящегося в массиве WColForward мы изменяем переменную steerAngle, (угол поворота колеса) умножая её на значение полученное с горизонтальной оси.
    7. Если вертикальная ось у нас в положении покоя (тоесть если мы не давим на клавиши W или S) то изменяем переменную коллайдера brakeTorque, которая отвечает за силу торможения, это нужно для того чтобы автомобиль не двигался по инерции если мы не нажимаем на клавиши движения.
    8. В других случаях, (если мы нажимаем на клавиши W или S) обнуляем силу торможения, а затем изменяем переменную motorTorque, (крутящий момент колеса) умножая её на значение полученное с вертикальной оси, вследствие чего наш автомобиль начинает ускоряться.

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

    Давайте обо всем по порядку.

    4. Центр тяжести

    Задается он удивительно просто, во первых нам надо создать пустой GO, назовем его Center of mass, затем перетянуть его на объект Car, и разместить его приблизительно там где вы считаете он должен быть, например чтобы моё авто не переворачивалось при повороте на высокой скорости мне пришлось сделать его вот так:

    У вас он может располагаться по другому, все зависит от геометрических размеров Box Collider’а нашего кузова, так что по экспериментируйте с центром тяжести, но для начала дополните наш скрипт:

    1. Объявите переменную: public Transform COM.
    2. Перетащите GO Center of mass на поле COM в скрипте.
    3. Внутри функции Start() напишите следующую строчку: rig > Теперь можете нажать Play и проверить результат.

    5. «Оживляем» колеса

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

    Для того чтобы оживить колесо, нам необходимо вычислять позицию и угол его вращения в каждом фиксированном кадре, в этом нам опять поможет чудесный WheelCollider, его метод GetGroundHit(), который способен вернуть структуру WheelHit в которой в свою очередь содержится точка соприкосновения коллайдера и террейна (переменная point). Благодаря методу GetGroundHit() мы можем вычислить позицию колеса на основе движения пружины подвески. Ну а что касается угла поворота – это совсем просто, в WheelCollider’е есть float переменная rpm, это аббревиатура от rotation per minute, на её основе мы и можем определить угол вращения колеса.

    Переходим собственно к скрипту, он вырос, потолстел и теперь выглядит так:

    Скопируйте его, вставьте в свой скрипт, затем во вкладке hierarchy выберите наш объект Car, как вы можете видеть в инспекторе у нас появились новые переменные и массивы в скрипте, в массивы wheelsF и wheelsB необходимо передать передние и задние колеса соответственно, (колеса а не Wheel Collier’ы!) как сделаете это нажмите Play. Если колеса уходят под террейн то поменяйте значение переменной wheelRadius, оно должно примерно совпадать с радиусом ваших коллайдеров.

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

    Если же они крутятся у вас не по той оси, или в другую сторону, то вам следует перечитать п. 1 где мы создавали автомобиль, я там говорил о том что важно повернуть колеса именно по оси Z на 90 градусов далее я объясню вам почему. Давайте разберем скрипт:

    1. Создаем массивы которые будут хранить Transform наших колес.
    2. Данные переменные нам пригодятся, ниже объясню для чего.
    3. Создадим класс который будет содержать нужную нам информацию о каждом нашем колесе, а именно:
    4. Transform колеса;
    5. Wheel Collider Колеса;
    6. Стартовую позицию колеса;
    7. Угол вращения колеса.
    8. Объявляем массив wheels c типом WheelData.
    9. Передаем в массив wheels необходимые нам данные, для этого я написал функцию SetupWheels().
    10. Функция SetupWheels() принимает Transform колеса и его WheelCollider, передает в переменные содержащиеся в классе WheelData необходимые нам данные и возвращает его.
    11. Напишем функцию UpdateWheels() в которой будет вычисляться позиция и угол поворота наших колес.
    12. Запоминаем переменную fixedDeltaTime класса Time она нужна нам для того чтобы вращение колеса было равномерно растянуто по времени.
    13. Для каждого элемента массива wheels выполняем следующие операции:
    14. Создаем переменную класса WheelHit (о ней я рассказывал выше);
    15. Запоминаем локальную позицию колеса (локальная позиция – это позиция относительно родительских координат, глобальная – относительно мировых);
    16. Если WheelCollider колеса сталкивается с поверхностью террейна (либо чего нибудь другого);
    17. То из координаты Y локальной позиции колеса вычитаем Dot() между вектором с началом в точке в которой коллайдер соприкасается с поверхностью террейна (hit.point) и концом в текущей позиции колеса (w.wheelTransform.position) и между вектором направленным вверх относительно объекта Car (transform.up) и из всего этого вычитаем еще и переменную wheelRadius чтобы колесо заняло правильное место. (Если из вышесказанного вы не поняли ни слова, не расстраивайтесь большинство людей не понимает этого с первого раза, для этого вам нужно хорошо знать что такое Dot product и как он связан с перечисленными выше векторами, либо просто знайте что позиция колеса должна вычисляться именно так);
    18. Если WheelCollider не касается поверхности террейна. То из координаты Y начальной локальной позиции колеса отнимаем wheelOffset, благодаря этому наши колеса не улетают в неизвестном направлении когда автомобиль падает с высоты или лежит на «спине»;
    19. Применяем измененную позицию колеса к его текущей позиции;
    20. Вычисляем угол «вращения» колеса, используя функцию Repeat() класса Mathf, данная функция помогает нам держать угол в интервале от 0 до 360 градусов, сам же угол мы вычисляем благодаря не хитрой формуле (w.rotation + delta * w.col.rpm * 360.0f / 60.0f) где мы собственно к текущему углу поворота прибавляем дельту времени умноженную на число поворотов в минуту хранящееся в коллайдере и умноженную на 360/60.
    21. Применяем к текущим локальным углам поворота получившийся результат, в этом нам помогает функция Euler() класса Quaternion которая возвращает кватернион в Эйлеровых углах (как бы не было страшно слово кватернион я советую вам абстрагироваться и воспринимать его как структуру хранящую локальные и глобальные углы поворота, хотя означает оно совсем другое, здесь я не буду рассказывать что именно, так просто будет понятнее). Первым аргументом (тоесть угол вокруг оси X) мы передаем наш вычисленный угол «вращения» колеса, вторым аргументом (угол вокруг оси Y) мы передаем угол поворота коллайдера, и третьим аргументом (угол по оси Z, теперь понимаете почему в пункте 1 было важно повернуть колеса именно вокруг оси Z) предаем константу 90.0f.

    Заключение

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

    Ну а в следующей части урока я как и обещал расскажу о том как построить механику гусениц танка, также я расскажу о методах его моделирования в 3D редакторе и немного про экспорт модели из него и импорт в Unity ну и естественно я не буду вас заставлять моделировать то что вы видели в данном демо, а предоставлю уже готовую модель. Спасибо за внимание и удачи в изучении Unity3d.

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