Создание 2D персонажа в Unity3D.
Поиск

Создание 2D персонажа в Unity3D.

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

Вжух-вжух и ты бегаешь и прыгаешь! 

В интернете можно найти десятки начатых новичками тем, о том, как создать персонажа для 2D (да и не только) игры, да так, чтобы у него была чувствительность к «силе» нажатия на кнопку прыжка, да и еще чтобы он не застревал в стенах при прижках.

Знакомые вещи, не правда ли?  Ведь в родных 2D примерах создают вполне себе красивого робота-персонажа, анимированного, но неуклюжего.

В данном уроке я хочу предложить свою реализацию простого, но при этом, достаточно гибкого в настройке персонажа, который умеет бодро передвигаться, прыгать, в зависимости от длины нажатия, и при этом, не застревать «в текстурах»

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

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

Решаем первый вопрос: передвижение по горизонтали.

Скорость передвижения описываем в функции FixedUpdate, т.к. содержимое этой функции обновляется фиксированное количество раз в секунду (К слову, как правило, с физикой и анимациями работают в этой функции, а не в Update

heroMove = Input.GetAxis ("Horizontal");

heroBody.velocity = new Vector2(heroMove * maxSpeed, heroBody.velocity.y);

HeroMove — float переменная, отвечающая за направление, 

HeroBody — Rigidbody2D компонент нашего персонажа

maxSpeed — публичная float переменная, определяющая максимальную скорость передвижения персонажа.

Решаем второй вопрос: прыжок с силой прыжка.

Реализаций в интернете масса. Я поступил с прыжком так, как это раньше делал в Flash проектах, работая с бородатым CitrusEngine. Этот метод заключается в просчете количества кадров, на которых была зажата кнопка прыжка и придание силы прыжка уже во время прыжка. Что это нам даст: достаточно высокую чувствительность к прыжку, а так же отсутствие заторможенности при начале прыжка. Вот этот код мы уже помещаем в Update (хотя можно и в FixedUpdate)

if (onGround) {
	if (Input.GetKeyDown (KeyCode.Z)) {
		heroBody.AddForce (new Vector2 (0f, jumpForce), ForceMode2D.Impulse);
		jumpValue = 1;
	}
}
if (Input.GetKey (KeyCode.Z) && jumpValue > 0 && jumpValue < jumpMax) {
	if (onGround) {
		jumpValue = 0;
	}
	heroBody.AddForce (new Vector2 (0f, jumpForce), ForceMode2D.Force);
	jumpValue++;
}
if (jumpValue > jumpMax-1) {
	jumpValue = 0;
}

onGroud — булевая переменная, определяющая, стоит ли персонаж на земле. 

jumpForce — сила прыжка, публичная переменная. 

jumpValue — количество кадров, в которых будет продолжаться прыжок.

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

 

И так, что же мы получаем: Наш персонаж прыгает с помощью импульса на минимальную высоту (jumpForce) и пока он летит вверх — просчитывается дальнейшая высота прыжка, к нему применяется дополнительная сила. Как только мы усилились на максимальное количество кадров в прыжке — дополнительная сила больше не применяется и персонаж спускается вниз.

Решаем третий вопрос: стоим ли мы на земле?

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

Создается для начала пустое тело, которое размещается в ногах персонажа. Для удобства можно выбрать ему иконку. Назовем его GroundCheck. Теперь переходим к коду персонажа. Определяем четыре публичные переменные:

public Transform groundCheck;
public float groundRadius = 0.2f;
public bool onGround;
public LayerMask whatIsGround;

Для начала нужно перенести своего персонажа на отдельный слой. Нажимаем на Add Layer в инспекторе, создаем нужный слой, к примеру «Player»,  и выбираем его. 

В появившееся в инспекторе свойство Ground Check типа Transform переносим наш объект groundCheck. А в Ground Radius нужно будет подобрать нужный вам радиус от центра объекта до точки соприкосновения с землей. В свойстве What is Ground нужно указать те слои, с которых мы можем прыгать. Слой Player выбирать не нужно, остальные уже по вашему усмотрению. 

Теперь в функции FixedUpdate вводим следующую строку:

onGround = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround);

Она определит, имеются ли точки пересечения между groundCheck и другими объектами из выбранных слоев в радиусе groundRadius

Теперь мы знаем — стоит ли наш персонаж на земле или нет.

Решаем четвертый вопрос: как не застрять в стене?

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

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

Как определить касание в стене расписывать не буду. Перейдем к материалам для настройки трения.

Нам нужно создать 2 физических материала, в которых мы укажем Friction 0.4 (по умолчанию) и 0. 

Теперь в коде указываем две переменных:

public PhysicsMaterial2D forGroundMaterial;
public PhysicsMaterial2D forWallMaterial;

Перетаскиваем наши два материала к персонажу в инспектор. В FixedUpdate прописываем следующую строку: 

heroBody.sharedMaterial = (!onWall || !onGround) ? forWallMaterial : forGroundMaterial;

Если мы не у стены или не на земле — мы отключаем трение. Таким образом, если игрок врежется в воздухе в стену — он не застрянет.

 

Как-то так все вопросы решили :)  Скачать можно с гитхаба тут