Рисуем с физикой Unity5

unity-iconВ прошлый раз мы рисовали и делали линии физическим телом, используя haxeflixel. Сегодня сделаем почти тоже самое используя Unity5. Но повторятся мы не будем и набросаем прототип бесконечного раннера.

circleСоздаем героя.

Не будем усложнять и сделаем нашего героя доблестным кругом с тремя отметками, дабы чувствовалась скорость вращения. (Добавляем Sprite Renderer с нашим мега-крутым кругом)

Добавим герою компоненты RigidBody2d и CircleCollider2d. И вот этот простой скрипт, задающий скорость вращения:

using UnityEngine;
using System.Collections;

//этот скрипт требует наличие RigidBody2d
[RequireComponent (typeof (Rigidbody2D))] 

public class Hero : MonoBehaviour {

	private Rigidbody2D body;
        //Максимальная скорость вращения
	private const float MAX_ANGULAR_VEL = - 1400;

	void Awake () 
	{
                //Кэшируем Rigidbody2D
		body = gameObject.GetComponent<Rigidbody2D> ();
	}
	
	void Update () 
	{
               //Каждый кадр добавляем крутящий момент
		body.AddTorque (MAX_ANGULAR_VEL/10);
              //Ограничиваем крутящий момент максимальным значением
		if (body.angularVelocity < MAX_ANGULAR_VEL) 
		{
			body.angularVelocity = MAX_ANGULAR_VEL;
		}
	}

}

Теперь немного доработаем камеру. Добавим скрипт

using UnityEngine;
using System.Collections;

public class SimpleCameraMoving : MonoBehaviour 
{
	//Делаем так, чтобы наше private поле было видно в инспекторе
	[SerializeField]
	private Transform Hero;
	
	private Vector2 _startPoint;

	void Awake()
	{
		//Запоминаем начальное положение героя
		_startPoint = Hero.position;
	}
	
	void Update () 
	{
		//двигаем камеру за героем, 
		//сохраняя положение героя относительно камеры
		transform.position = new Vector3( Hero.position.x - _startPoint.x/2, 
		                                 transform.position.y, transform.position.z);
	}
}

Это простейший скрипт слежения за объектом с сохранением относительного расположения (чтобы герой был не по центру экрана, а в том месте, где мы его располагаем изначально). Не забываем в инспекторе перетянуть нашего героя в поле Hero.

Теперь создаем объект, в котором мы будем рисовать.

2015-03-15 19-45-29 Main.unity - DrawLineExample - WebGL (Personal)Здесь нам понадобятся:

— компонент LineRenderer , для которого необходимо создать материал. Материалу можно не задавать текстуру, а шейдер выставить Particles/Additive.

— компонент EdgeCillider2d — который и будет отвечать за нашу физику.

Настройки можно посмотреть на скриншоте. Поэкспериментировать самим — тоже не будет лишним.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent (typeof (EdgeCollider2D), typeof(LineRenderer))] 
public class DrawLine : MonoBehaviour 
{
	private LineRenderer line;
	private bool isMousePressed;
	private List<Vector2> poinsOfLine;
	private Vector3 mousePos;
	private EdgeCollider2D collider;

	void Awake()
	{
		//кэшируем компоненты
		line = gameObject.GetComponent<LineRenderer>();
		line.SetVertexCount(0);
		isMousePressed = false;
		poinsOfLine = new List<Vector2>();
		collider = gameObject.GetComponent<EdgeCollider2D> ();
	}

	void Update () 
	{
		if(Input.GetMouseButtonDown(0))
		{
			//если нажата кнопка мыши
			isMousePressed = true;
			//удаляем отрисовку линии
			line.SetVertexCount(0);
			//чистим сохраненные точки
			poinsOfLine.Clear();
			//отключаем физику
			collider.enabled = false;
		}
		else if(Input.GetMouseButtonUp(0))
		{
			isMousePressed = false;
		}
		if(isMousePressed)
		{
			mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
			mousePos.z=0;
			// ограничение, которое позволяет рисовать только слева направо
			if (poinsOfLine.Count > 0 && mousePos.x < poinsOfLine[poinsOfLine.Count - 1].x)
			{
				return;
			}
			//сохраняем текущее расположение мыши
			poinsOfLine.Add (mousePos);
			//передаем точки для отрисовки в linerenderer
			line.SetVertexCount (poinsOfLine.Count);
			line.SetPosition (poinsOfLine.Count - 1, (Vector3)poinsOfLine [poinsOfLine.Count - 1]);
			if (poinsOfLine.Count > 1)
			{
				//создаем физику по нашим точкам
				collider.points = poinsOfLine.ToArray();
				collider.enabled = true;
			}
		}
	}
}

Если в двух словах, то скрипт ждет пока кнопка мыши будет нажата, после этого каждый кадр записывает координаты мыши. По этим координатам отрисовывается линия. Так же эти точки передаются в edge collider, где по ним создается физика.

При беглом осмотре кода в глаза бросаются бесконечно растущие значения координат и разрастающиеся листы и массивы — все это в боевом проекте, при длительных игровых сессиях, приведет к неприятным последствиям. Но мы не забываем. что это прототип. Переписывать и оптимизировать будем когда начнем писать игру =)

Собственно это все, что я хотел рассказать.

Также я добавил на камеру bloom из standart assets (кстати, они в unity 5 бесплатные). И объект пола привязанный к камере, что бы наш доблестный герой не проваливался. Посмотреть, что получилось можно здесь WebGL (советую поставить Daft Punk на фоне =) )

UPD: У некоторых возникли проблемы с WebGL , вот билд с использованием UnityPlayer.

Проект на github’е