Как сделать веревку в 2D?

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


Добавляем на сцену пустой объект, назовем его Anchor, на него добавляем компонент Rigidbody 2D, готово. Данный объект будет служить якорем, за который и будет зацепляться наша веревка.

Идем дальше. Добавляем на сцену спрайт круг, с именем Node. На объект вешаем 2D коллайдер и Hinge Joint 2D, автоматически добавиться Rigidbody 2D, и у этого компонента параметры Linear Drag и Angular Drag, ставим на 0.5, чтобы веревка выглядела более правдоподобно.

Еще на сцену нужно добавить два Line Renderer, один для веревки, а другой для луча указателя.

Теперь на сцену добавляем скрипт:

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

public class RopeControl : MonoBehaviour {

	[SerializeField] private Rigidbody2D anchor; // объект к которому будет цепляться первый узел из цепочки
	[SerializeField] private HingeJoint2D node; // узлы цепи
	[SerializeField] private Transform player; // трансформ от которого идет построение цепи
	[SerializeField] private LayerMask layerMask; // маска объектов на которые можно прицепиться
	[SerializeField] [Range(0, 10)] private int correction; // коррекция длинны
	[SerializeField] private float nodeDistance = 4; // расстояние между узлами цепи (чем оно меньше, тем больше самих узлов)
	[SerializeField] private LineRenderer ropeLine; // линия между узлами
	[SerializeField] private LineRenderer targetLine; // линия указатель
	private float sise, distance;
	private Vector3 direction, curPos;
	private Vector2 mousePosition;
	private RaycastHit2D hit;
	private Rigidbody2D rope;
	private HingeJoint2D lastNode;
	private List<Transform> arr = new List<Transform>();

	void Awake()
	{
		anchor.bodyType = RigidbodyType2D.Static;
		node.gameObject.SetActive(false);
		sise = node.GetComponent<CircleCollider2D>().radius * nodeDistance;
	}

	void Update()
	{
		mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
		
		if(Input.GetMouseButtonDown(0))
		{
			if(CanUse(mousePosition))
			{
				if(rope != null) Destroy(rope.gameObject);
				arr = new List<Transform>();
				rope = Instantiate(anchor, hit.point, Quaternion.identity);
				rope.name = "Rope";
				curPos = rope.transform.position;
				arr.Add(rope.transform);
				
				while(true) // цикл создания узлов цепи
				{
					HingeJoint2D clone = Instantiate(node) as HingeJoint2D;

					if(lastNode != null)
					{
						curPos = lastNode.transform.position + direction * sise;
						clone.connectedBody = lastNode.GetComponent<Rigidbody2D>();
					}
					else
					{
						clone.connectedBody = rope;
					}

					arr.Add(clone.transform);
					clone.transform.position = curPos;
					clone.transform.parent = rope.transform;
					clone.gameObject.SetActive(true);
					lastNode = clone;

					if(Vector3.Distance(rope.transform.position, lastNode.transform.position) > distance - correction) break; // выход из цикла
				}

				ropeLine.positionCount = arr.Count;
				lastNode = null;
			}
		}

		if(arr.Count > 0)
		{
			RopeLineUpdate();
		}

		TargetLineUpdate();
	}

	void TargetLineUpdate()
	{
		RaycastHit2D target = Physics2D.Linecast(player.position, mousePosition, layerMask);

		if(target.transform != null)
		{
			targetLine.positionCount = 2;
			targetLine.SetPosition(0, player.position);
			targetLine.SetPosition(1, target.point);
		}
		else
		{
			targetLine.positionCount = 0;
		}
	}

	void RopeLineUpdate()
	{
		for(int i = 0; i < arr.Count; i++)
		{
			ropeLine.SetPosition(i, arr[i].transform.position);
		}
	}

	bool CanUse(Vector3 position)
	{
		hit = Physics2D.Linecast(player.position, position, layerMask);

		if(hit.transform != null)
		{
			distance = Vector2.Distance(player.position, hit.point);
			direction = (player.position - position).normalized;
			direction.z = 0;
			return true;
		}

		return false;
	}
}


Скачать демо проект:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 5.6.0

Комментариев 8

Офлайн
Большое спасибо за урок!!!У меня 1 проблема Unity 5.0.0f выходит ошибка с надписью
UnityEngine.Rigidbody2D не содержит определение для freezeRotation не удалось найти метод расширения freezeRotation
Офлайн
Light 2 мая 2017
Давуд Ахмедов, все проекты пишутся для актуальной версии, на момент публикации.
Офлайн
А как сделать чтобы персонаж когда кидает веревку прицеплялся к концу веревки?Я имею ввиду тарзанки
Офлайн
Light 13 июня 2017
Давуд Ахмедов, повесить на перса HingeJoint2D, а потом в скрипте включать его и цеплять к последнему узлу самой веревки.
Офлайн
Light,
тогда персонаж будет просто телепортироваться к веревке.Я думал все вот так получится как тут в конец а там он просто создает веревку и никак на нее не реагирует Например вот тут у него получилась тарзанка как я себе и представлял https://www.youtube.com/watch?v=DTFgQIs5iMY&t=260s
Я как вот тут сделал хотел
Офлайн
Light 14 июня 2017
Давуд Ахмедов, я говорил о логическом направлении, куда копать, как говориться. Потому что, если веревка состоит из определенных узлов, то и перс должен быть таким же узлом по сути. Чтобы всё работало как надо, нужно переделывать частично код и взаимодействие с самой веревкой.

Если тебе для игры нужна тарзанка, можешь сделать заказ, пиши в ЛС.
Офлайн
Light,
я имею ввиду через простой 1 Line Renderer а не через узлы
Например если нажать кнопку E у появляется Line Renderer и у персонажа включается Distance Joint 2D и при этом чтобы Line Renderer и Distance join 2D с её точкой цепления перемещались вместе с персонажем
А если отпустить кнопку E то это все отключается
Я думал урок таким будет а не просто создание никак не реагирующей на персонажа веревки
Офлайн
TEEAAA 2 ноября 2017
Давуд Ахмедов,
есть на сайте урок
про тарзанку только вроде крюк-кошка , но принцип тот же
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика