Создание инвентаря персонажа в Unity

Сделать инвентарь не то чтобы сложно, но есть некоторые трудности, которые мы сегодня будем решать. Конечная цель – возможность перетаскивать объекты в ячейки инвентаря, и перетаскивать их из инвентаря обратно в игровой мир. Общая логика такова. В игре есть предметы, которые можно положить, например, в рюкзак. При клике по предмету, его 3D модель – меняется на соответствующую 2D иконку, которую мы можем перемещать на экране. Иконку можно положить в ячейку рюкзака, можно переназначать ячейки, то есть перекладывать иконку с места на место. Далее, любую иконку из инвентаря можно вытащить и переместить в 3D пространство, где она будет заменена на соответствующую 3D модель. Вот, как-то так..

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


Подготовка:
Во-первых, нарисуйте ячейку рюкзака, и именуем иконку как background. Создаем новый UI объект типа Canvas не меняя настройки по умолчанию, а в него добавляем объект типа Image, в качестве источника изображения - делаем иконку ячейки. Настраиваем размер. Теперь, дублируем эту картинку, переименуем в item, затем, делаем дубликат - дочерним оригиналу. Переходим к настройке дочернего объекта. Цепляем на него небольшой скрипт Grid:

using UnityEngine;
using System.Collections;

public class Grid : MonoBehaviour {

	public int ID;
	public int item_id;
	public int icon_id;
	public bool active;

	public void SetID()
	{
		Inventory.grid_id = ID;
	}

	public void ResetID()
	{
		Inventory.grid_id = -1;
	}
}

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

Продолжим. На дочерний объект добавим обработчик событий Add Component > Event > Event Trigger. В обработчик мы добавим два события PointerEnter и PointerExit. Обращаться будем к текущему скрипту Grid на этой картинке. Для PointerEnter - функция SetID, для PointerExit - функция ResetID. Как показано на скриншоте ниже:

Создание инвентаря персонажа в Unity

Настройка ячейки готова. Теперь клонируем родителя и укладываем объекты, делаем рюкзак. Делаем пустой UI, назем его Inventory и перемещаем туда все ячейки:


Внимание! В Inventory не должно быть вложено никаких других объектов, кроме ячеек.

На Inventory вешаем скрипт с таким же названием:

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;

public class Inventory : MonoBehaviour {

	public Transform[] allItems;
	public Sprite[] itemIcon;
	public int iconSize = 50;
	public Sprite background;
	private GameObject[] cell;
	private Texture2D tmpTexture;
	private int iconCoumt;
	private int itemCoumt;
	private GameObject tmpObject;
	private GameObject cell_tmp;
	private Vector3 curPos;
	public static int grid_id;

	void Awake ()
	{
		grid_id = -1;
		cell = new GameObject[transform.childCount];
		for(int j = 0; j < cell.Length; j++)
		{
			cell[j] = transform.GetChild(j).gameObject;
			cell[j].GetComponentInChildren<Grid>().ID = j;
		}
	}

	void Reset()
	{
		if(tmpTexture)
		{
			tmpTexture = null;
			if(grid_id == -1 && !tmpObject)
			{
				// создание объекта с добавлением высоты по Y
				GameObject clone = Instantiate(allItems[itemCoumt].gameObject, curPos + new Vector3(0,100,0), Quaternion.identity) as GameObject;
				RaycastHit hit;
				if (Physics.Linecast (curPos, clone.transform.position, out hit)) 
				{
					// корректировка высоты на поверхности, с учетом размера коллайдера
					clone.transform.position -= new Vector3(0,hit.distance,0);
				}
			}
		}
		if(tmpObject)
		{
			tmpObject.SetActive(true);
			tmpObject = null;
		}
		cell_tmp = null;
	}

	void Update () 
	{
		RaycastHit hit;
		Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if (Physics.Raycast(ray, out hit))
		{
			curPos = hit.point;
			if(Input.GetMouseButton(0))
			{
				if(hit.transform.GetComponent<AddToInventory>() && !tmpTexture)
				{
					tmpObject = hit.transform.gameObject;
					tmpObject.SetActive(false);
					int i = hit.transform.GetComponent<AddToInventory>().itemID;
					for(int j = 0; j < itemIcon.Length; j++)
					{
						// поиск id массива иконок, относительно номера объекта
						string n = itemIcon[j].name.Split(new char[] {'_'}, StringSplitOptions.RemoveEmptyEntries)[0];
						if(n == i.ToString())
						{
							tmpTexture = itemIcon[j].texture;
							iconCoumt = j;
							for(int f = 0; f < allItems.Length; f++)
							{
								// поиск id массива предметов, относительно номера объекта
								n = allItems[f].name.Split(new char[] {'_'}, StringSplitOptions.RemoveEmptyEntries)[0];
								if(n == i.ToString()) itemCoumt = f;
							}
						}
					}
				}
			}
			else
			{
				if(!Input.GetMouseButton(0) && grid_id == -1) Reset();
			}
		}
		else
		{
			if(!Input.GetMouseButton(0) && grid_id == -1) Reset();
		}

		if(Input.GetMouseButtonUp(0) && grid_id > -1 && tmpTexture)
		{
			foreach(GameObject obj in cell)
			{
				GameObject tmp = obj.transform.GetChild(0).gameObject;

				// меняем местами иконки, внутри рюкзака
				if(tmp.GetComponent<Grid>().ID == grid_id && tmp.GetComponent<Grid>().active && cell_tmp) 
				{
					cell_tmp.GetComponent<Grid>().icon_id = tmp.GetComponent<Grid>().icon_id;
					cell_tmp.GetComponent<Grid>().item_id = tmp.GetComponent<Grid>().item_id;
					cell_tmp.GetComponent<Grid>().active = true;
					cell_tmp.GetComponent<Image>().sprite = itemIcon[tmp.GetComponent<Grid>().icon_id];

					tmp.GetComponent<Grid>().item_id = itemCoumt;
					tmp.GetComponent<Grid>().icon_id = iconCoumt;
					tmp.GetComponent<Grid>().active = true;
					tmp.GetComponent<Image>().sprite = itemIcon[iconCoumt];

					Reset();
				}

				// добавление новой иконки в инвентарь
				if(tmp.GetComponent<Grid>().ID == grid_id && !tmp.GetComponent<Grid>().active) 
				{
					tmp.GetComponent<Grid>().item_id = itemCoumt;
					tmp.GetComponent<Grid>().icon_id = iconCoumt;
					tmp.GetComponent<Grid>().active = true;
					tmp.GetComponent<Image>().sprite = itemIcon[iconCoumt];
					Destroy(tmpObject);
				}
			}
			Reset();
		}

		if(Input.GetMouseButtonDown(0) && grid_id > -1 && !tmpTexture)
		{
			foreach(GameObject obj in cell)
			{
				GameObject tmp = obj.transform.GetChild(0).gameObject;

				// выбор иконки из рюкзака
				if(tmp.GetComponent<Grid>().ID == grid_id && tmp.GetComponent<Grid>().active) 
				{
					cell_tmp = tmp;
					iconCoumt = tmp.GetComponent<Grid>().icon_id;
					itemCoumt = tmp.GetComponent<Grid>().item_id;
					tmp.GetComponent<Grid>().active = false;
					tmpTexture = tmp.GetComponent<Image>().sprite.texture;
					tmp.GetComponent<Image>().sprite = background;
				}
			}
		}
	}

	void OnGUI () 
	{
		if(tmpTexture)
		{
			// перемещение иконки на экране
			Vector2 mousePos = Event.current.mousePosition;
			GUI.depth = 999; // поверх остальных элементов
			float shift = iconSize / 2;
			GUI.Label(new Rect(mousePos.x - shift, mousePos.y - shift, iconSize, iconSize), tmpTexture);
		}
	}
}

allItems - массив префабов предметов.

itemIcon - массив спрайтов иконок для предметов.

iconSize - размер иконки во время перемещения по экрану.

background - спрайт ячейки.

Как надо собирать префаб предмета. Во-первых, любой предмет который можно положить в инвентарь должен иметь скрипт AddToInventory:

using UnityEngine;
using System.Collections;

public class AddToInventory : MonoBehaviour {

	public int itemID;
}

itemID - номер для иконки и имени этого префеба.

То есть имя должно иметь вид id_XXX, например, 57_Book, здесь 57 это номер itemID. Разделительный знак "_". При создании иконки для данного предмета, ее имя должно иметь такой же вид, например, 57_BookIcon. Добавлять префабы предметов и спрайты иконок, в массивы, можно в любом порядке, потому что их фильтрация будет делаться по имени.

Скачать и пощупать готовый проект:

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

Улучшенная версия https://null-code.ru/project/180-prodvinutyy-inventar-personazha.html

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

Офлайн
Light 12 июня 2018
vovaustimuk, в улучшенной версии эта функция есть https://null-code.ru/project/180-prodvinutyy-inventar-personazha.html
Офлайн
vovaustimuk 12 июня 2018
А вот если есть массив имен 57_Book, 58_Book, 59_Book как удалить элемент с конкретным именем 58_Book к примеру, или изменить его.
Офлайн
Light 21 февраля 2017
Luiza, без разницы какой объект, если на нем есть скрипт соответствующий и коллайдер. Плюс, нужно проверить, чтобы все элементы массивов префабов и иконок были определены.
Офлайн
Luiza 21 февраля 2017
можете...пожалуйста помочь!!!!!!! как изменить код или что надо сделать, чтобы предмет появлялся именно там где кликнули мышкой, просто когда создается обычный Object , типа куб или сфера, то все работает как на видео, но как вешаешь скрипт на другой предмет из вне, то он закидывается в инвентарий, но когда вытаскиваешь он принимает начальные позиции, и вообще исчезает,почему?и что сделать?
коллайдер который вешается на модель принимает естественно значения и размеры модели...возможно в загвостка...?потому что у создаваемых кубов там значения все по нулям не зависимо как меняешь размер
Офлайн
Andrejus 9 июля 2015
Большое спасибо за ваши уроки. Все они очень полезны.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика