Камера 2D + движение в рамках границ

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


Подготовка персонажа:

Камера 2D + движение в рамках границ

По умолчанию, "лицо" персонажа, должно смотреть вправо, при условии отсутствия вращения объекта.

Подготовка карты:
Чтобы установить границы, внутри которых может двигаться камера. Для этого просто добавляем на сцену обычный спрайт-квадрат, назовем его Bounds Map (не забываем указать этот объект в поле скрипта), ставим по центру карты и увеличиваем до нужного размера. После настройки, делаем его невидимым, чтобы не мешал.

Далее на камеру вешаем:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Camera))]

public class Camera2DFollowTDS : MonoBehaviour {

	private enum Mode {Player, Cursor};

	[SerializeField] private Mode face; // вектор смещения, относительно "лица" персонажа или положения курсора
	[SerializeField] private float smooth = 2.5f; // сглаживание при следовании за персонажем
	[SerializeField] private float offset; // значение смещения (отключить = 0)
	[SerializeField] private SpriteRenderer boundsMap; // спрайт, в рамках которого будет перемещаться камера
	[SerializeField] private bool useBounds = true; // использовать или нет, границы для камеры

	private Transform player;
	private Vector3 min, max, direction;
	private static Camera2DFollowTDS _use;
	private Camera cam;

	public static Camera2DFollowTDS use
	{
		get{ return _use; }
	}

	void Awake()
	{
		_use = this;
		cam = GetComponent<Camera>();
		cam.orthographic = true;
		FindPlayer();
		CalculateBounds();
	}

	// переключатель, для использования из другого класса
	public void UseCameraBounds(bool value)
	{
		useBounds = value;
	}

	// найти персонажа, если он был уничтожен, а потом возрожден
	// для вызова из другого класса, пишем: Camera2DFollowTDS.use.FindPlayer();
	public void FindPlayer()
	{
		player = GameObject.FindGameObjectWithTag("Player").transform;
		if(player) transform.position = new Vector3(player.position.x, player.position.y, transform.position.z);
	}

	// если в процессе игры, было изменено разрешение экрана
	// или параметр "Orthographic Size", то следует сделать вызов данной функции повторно
	public void CalculateBounds()
	{
		if(boundsMap == null) return;
		Bounds bounds = Camera2DBounds();
		min = bounds.max + boundsMap.bounds.min;
		max = bounds.min + boundsMap.bounds.max;
	}

	Bounds Camera2DBounds()
	{
		float height = cam.orthographicSize * 2;
		return new Bounds(Vector3.zero, new Vector3(height * cam.aspect, height, 0));
	}

	Vector3 MoveInside(Vector3 current, Vector3 pMin, Vector3 pMax)
	{
		if(!useBounds || boundsMap == null) return current;
		current = Vector3.Max(current, pMin);
		current = Vector3.Min(current, pMax);
		return current;
	}

	Vector3 Mouse()
	{
		Vector3 mouse = Input.mousePosition;
		mouse.z = -transform.position.z;
		return cam.ScreenToWorldPoint(mouse);
	}

	void Follow()
	{
		if(face == Mode.Player) direction = player.right; else direction = (Mouse() - player.position).normalized;
		Vector3 position = player.position + direction * offset;
		position.z = transform.position.z;
		position = MoveInside(position, new Vector3(min.x, min.y, position.z), new Vector3(max.x, max.y, position.z));
		transform.position = Vector3.Lerp(transform.position, position, smooth * Time.deltaTime);
	}

	void LateUpdate()
	{
		if(player)
		{
			Follow();
		}
	}
}

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

Скачать скрипт:

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

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

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

Онлайн
Light 15 июля 2017
Давуд Ахмедов, я проверял демо, всё работает без проблем.
Офлайн
Light,
как может быть ошибка если я кроме того что скрипт на камеру поставил,добавил bound,и увеличил smooth может быть ошибка?
Онлайн
Light 14 июля 2017
Давуд Ахмедов, если ошибок нет в скрипте, значит ошибся ты, а где именно, я не могу знать. Проверяй, смотри демо.
Офлайн
Light,
камера за курсором не следует(
Скрипт не изменял ОШИБОК НЕТУ!
Онлайн
Light 8 июня 2017
Давуд Ахмедов, https://null-code.ru/solution/179-delaem-umnuyu-2d-kameru.html
Офлайн
Light,
А нельзя ли их сделать в большом количестве эти Bounds map?Чтобы можно было их несколько сделать или больше
Онлайн
Light 6 апреля 2017
Артур Ступников, добавил второй вариант скрипта. Еще на Rigidbody нужно включить Interpolate.
Офлайн
Артур Ступников,
решил, просто значение smooth увеличивать надо.
Офлайн
кинул скрипт на объект.все работает, но когда персонаж быстро движется то его движения будто прерываются.такое ощущение что камера пытается его догнать,и получается что персонаж двигается как то рывками.
Офлайн
cry_san 19 января 2017
Есть идея получше. Плавный зум и скрол по границам с помощью мыши (как в стратегиях). Добавьте на камеру этот скрипт:
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика