Понедельник, 23 января 2017, 03:29

Приветствую Вас Гость

Меню сайта
Категории каталога
Создание игр [298]
Статьи об общих понятиях связанных с созданием игр.
Программирование [66]
Гайды по программированию на разных ЯП.
Движки и Гейммейкеры [120]
Статьи о программах для создания игр, уроки и описания.
Софт [27]
Различные программы, в том числе в помощь игроделам.
2D-графика [7]
Уроки по рисованию, растр, пиксель-арт, создание спрайтов и пр.
3D-графика [8]
Уроки по моделированию, ландшафт, модели, текстурирование и пр.
Моддинг игр [4]
Модификация компьютерных игр, создание дополнений, перевод, хакинг.
Игры [65]
Статьи об играх, в том числе и сделанных на гейммейкерах.
Разное [53]
Статьи, которые не вошли в определённые разделы.
Наш опрос
Какую консоль нового поколения вы планируете купить?
Всего ответов: 331
Главная » Статьи » Создание игр

Создание простого Drag&Drop инвентаря в Unity на C#. Часть 1
Всем привет. Представляю вашему вниманию небольшой урок посвященный созданию Drag&Drop инвентаря. Через текст тяжело все передать и обьяснить, с видео все намного проще. Но я все таки попытаюсь написать все, как можно подробней.
Вот небольшое видео, где показано, как работает инвентарь.

На написание этой статьи меня подвигло то, что очень часто создать инвентарь для начинающих программистов является доволи сложным делом(для меня именно так и было). И вот я решил попробовать сделать инвентарь как можно коротким в плане кода. Конечно, что бы создать полноценный инвентарь понадобится много времени, но прочитав данный урок, я надеюсь, вы все поймете и у вас будет от чего «отталкиваться» при создании своего инвентаря. В этой части урока мы создадим простой инвентарь с возможность перемещения предметов внутри инвентаря.
Способ, описанный в этом уроке, является всего лишь одним из десятков способов создания инвентаря. Так что поехали…
Для начала создадим и настроем сцену. Разместим на ней Plane (создадим некую поверхность) и Directional Light.

Настроим камеру, что бы сцену было видно.

Приступаем к скриптингу.
Создаем новый скрипт с именем Item, где будем хранить все характеристики предмета. Их у нас будет целых две :): название предмета и его иконка. Думаю для начала этого хватит, вы по желанию можете любые переменные и значения добавлять. Приступим к редактированию скрипта. Во-первых наш класс ничего не наследует поэтому удаляем MonoBehaviour.Создаем две переменные типа Texture2D и string, которые будут содержать иконку и название предмета. Наш скрипт выглядит так:
Код
using UnityEngine;
using System.Collections;

[System.Serializable]
public class Item{

  public Texture2D Textura; //текстура иконки
  public string Name; //название
}

Обязательно добавляем [System.Serializable]
Создаем еще один скрипт и называем его ItemData. В нем будем хранить предметы, а так же создавать их для инвентаря. Первым делом подключаем пространство имен System.Collections.Generic, что бы можно было использовать списки.
Код:
Код

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

public class ItemData : MonoBehaviour {

  public static ItemData _ItemData; //паттерн Singelton
  public List<Item> Items = new List<Item>(); //списк в котором хранятся предметы

  void Awake()
  {
  _ItemData = this;
  }
   
  void Start () {
   
  }
   
  void Update () {
   
  }
}


Создадим публичный метод который возвращает Item и принимает int. И присвоим переменным значения
Код

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

public class ItemData : MonoBehaviour {

  public static ItemData _ItemData; //паттерн Singelton
  public List<Item> Items = new List<Item>(); //списк в котором хранятся предметы

  void Awake()
  {
  _ItemData = this;
  }
   
  void Start () {
   
  }
   
  void Update () {
   
  }

  //генерация предмета
  public Item ItemGen(int win_id)
  {
  Item item = new Item();
  item.Name = Items[win_id].Name;
  item.Textura = Items[win_id].Textura;
  return item;
  }
}



Вешаем наш скрипт на камеру (в принципе не важно куда его вешать) В инспекторе создаем 4 предмета. Называем их и задаем иконки и названия.

Теперь перейдем непосредственно к созданию инвентаря. Создаем скрипт и называем его Inventory. Создаем переменные отвечающие за размер ячеек, окна инвентаря и кол-во ячеек. У нас будет 6 колонок по 4 ячейки, итого 24 ячейки.
Код

using UnityEngine;
using System.Collections;

public class Inventory : MonoBehaviour {

  const int INVENTORY_WINDOW_ID = 1; //id окна инвентаря

  public float ButtonWidth = 40; //высота ячейки
  public float ButtonHeight = 40; //ширина ячейки

  int invRows = 6; //количество колонок
  int invColumns = 4; //количество столбцов
  Rect inventoryWindowRect = new Rect(10, 10,
  170, 265); //область окна
   
  void Start () {
   
  }
   
  void Update () {
   
  }
}


Добавляем еще несколько вспомогательных переменных для возможности передвигать предметы и создаем словарь содержащий наши предметы и принимающий в качестве ключа int.
(не забываем добавить System.Collections.Generic для работы со словарями).
Код

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

public class Inventory : MonoBehaviour {

  const int INVENTORY_WINDOW_ID = 1; //id окна инвентаря

  public float ButtonWidth = 40; //высота ячейки
  public float ButtonHeight = 40; //ширина ячейки

  int invRows = 6; //количество колонок
  int invColumns = 4; //количество столбцов
  Rect inventoryWindowRect = new Rect(10, 10,
  230, 265); //область окна
  bool isDraggable; //возможно ли перемещение предмета
  Item selectItem; //вспомогательная переменная куда заносим предмет инвентаря
  Texture2D dragTexture; //текстура которая отображается при перетягивании предмета в инвентаре

  Dictionary<int, Item> InventoryPlayer = new Dictionary<int, Item>(); //словарь содержащий предметы инвентаря

  void Start () {
   
  }
   
  void Update () {
   
  }
}


Далее создаем окно и ячейки. Ячейки будем создавать через циклы.
-Первый цикл необходим для дальнейшей проверки ключа в словаре.
-Второй для создания ячеек по вертикале (как вы помните у нас 6 колонок)
-Третий для создание ячеек по горизонтали (у нас 4 столбца)
Нам необходимо пронумеровать каждую ячейку , поэтому используя теорему «По Качану» я вывел формулы для нумерования ячеек (x + y * invColumns).
Собственно сам код:
Код

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

public class Inventory : MonoBehaviour {

  const int INVENTORY_WINDOW_ID = 1; //id окна инвентаря

  public float ButtonWidth = 40; //высота ячейки
  public float ButtonHeight = 40; //ширина ячейки

  int invRows = 6; //количество колонок
  int invColumns = 4; //количество столбцов
  Rect inventoryWindowRect = new Rect(10, 10,
  230, 265); //область окна
  bool isDraggable; //перемещается ли айтем?
  Item selectItem; //вспомогательная переменная куда заносим предмет инвентаря
  Texture2D dragTexture; //текстура которая отображается при перетягивании предмета в инвентаре

  Dictionary<int, Item> InventoryPlayer = new Dictionary<int, Item>(); //словарь содержащий предметы инвентаря

  void Start () {
   
  }
   
  Update is called once per frame
  void Update () {
   
  }

  void OnGUI()
  {
  inventoryWindowRect = GUI.Window(INVENTORY_WINDOW_ID, inventoryWindowRect, firstInventory, "INVENTORY"); //создаем окно
  }

  void firstInventory(int id)
  {
  for (int y = 0; y < invRows; y++)
  {
  for (int x = 0; x < invColumns; x++)
  {
  GUI.Button(new Rect(50 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), (x + y * invColumns).ToString(),"itemInfo-InfoBG");  
  }
  }
  }  
}


Вешаем наш скрипт на камеру и запускаем игру. Вы должны увидеть нечто подобное.

Продолжаем создавать наш инвентарь . Теперь мы создадим перемещение предметов внутри инвентаря и добавим парочку предметов для теста.
Вот сам код. Думаю обьяснять ничего не надо, все закомментировано.
Код

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

public class Inventory : MonoBehaviour {

  const int INVENTORY_WINDOW_ID = 1; //id окна инвентаря

  public float ButtonWidth = 40; //высота ячейки
  public float ButtonHeight = 40; //ширина ячейки

  int invRows = 6; //количество колонок
  int invColumns = 4; //количество столбцов
  Rect inventoryWindowRect = new Rect(10, 10,
  170, 265); //область окна
  bool isDraggable; //перемещение предмета
  Item selectItem; //вспомогательная переменная куда заносим предмет инвентаря
  Texture2D dragTexture; //текстура которая отображается при перетягивании предмета в инвентаре
   
  Dictionary<int, Item> InventoryPlayer = new Dictionary<int, Item>(); //словарь содержащий предметы инвентаря

  void Start () {
  //добавляем предметы в инвентарь
  InventoryPlayer.Add(0, ItemData._ItemData.ItemGen(0));
  InventoryPlayer.Add(1, ItemData._ItemData.ItemGen(1));
  InventoryPlayer.Add(2, ItemData._ItemData.ItemGen(2));
  InventoryPlayer.Add(3, ItemData._ItemData.ItemGen(3));
  }
   
  // Update is called once per frame
  void Update () {
   
  }

  void OnGUI()
  {
  inventoryWindowRect = GUI.Window(INVENTORY_WINDOW_ID, inventoryWindowRect, firstInventory, "INVENTORY"); //создаем окно
  }

  void firstInventory(int id)
  {
  for (int i = 0; i < 24; i++)
  {
  for (int y = 0; y < invRows; y++)
  {
  for (int x = 0; x < invColumns; x++)
  {
  if (InventoryPlayer.ContainsKey(x + y * invColumns))//проверяем содеоржится ли ключ с данным значением
  {
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), new GUIContent(InventoryPlayer[x + y * invColumns].Textura), "button"))
  {
  if (!isDraggable)
  {
  dragTexture = InventoryPlayer[x + y * invColumns].Textura;//присваиваем нашой текстуре которая должна отображаться при перетаскивании, текстуру предмета
  isDraggable = true;//возможность перемещать предмет
  selectItem = InventoryPlayer[x + y * invColumns];//присваиваем вспомогательной переменной наш предмет
  InventoryPlayer.Remove(x + y * invColumns);//удаляем из словаря предмет
  }
  }
  }
  else
  {
  if (isDraggable)
  {
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button"))
  {
  InventoryPlayer.Add(x + y * invColumns, selectItem);//добавляем предмет который перетаскиваем в словарь
  //обнуляем переменные
  isDraggable = false;
  selectItem = null;
  }
  }
  else
  {
  GUI.Label(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button");
  }
  }
  }
  }
  }
   
  }
}



Опять запускаем игру и видим приблизительно вот такое:

Пробуем перетаскивать предметы в инвентаре. При нажатии на предмет он должен исчезать, после при нажатии на пустую ячейку он появляется в нужной ячейке. Нас это не устраивает и нам нужно, что бы было видно иконку при переносе предмета.
Поэтому создадим новое окно где будет отображаться иконка, когда мы перетаскиваем предмет.
Код

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

public class Inventory : MonoBehaviour {

  const int INVENTORY_WINDOW_ID = 0; //id окна инвентаря
  const int INVENTORY_TEXTURE_ID = 1; //id окна с иконкой
  public float ButtonWidth = 40; //высота ячейки
  public float ButtonHeight = 40; //ширина ячейки

  int invRows = 6; //количество колонок
  int invColumns = 4; //количество столбцов
  Rect inventoryWindowRect = new Rect(10, 10,
  170, 265); //область окна
  Rect inventoryBoxRect = new Rect(); //область окна с изображением иконки
  bool isDraggable; //перемещение предмета
  Item selectItem; //вспомогательная переменная куда заносим предмет инвентаря
  Texture2D dragTexture; //текстура которая отображается при перетягивании предмета в инвентаре

  Dictionary<int, Item> InventoryPlayer = new Dictionary<int, Item>(); //словарь содержащий предметы инвентаря

  void Start () {
  //добавляем предметы в инвентарь
  InventoryPlayer.Add(0, ItemData._ItemData.ItemGen(0));
  InventoryPlayer.Add(1, ItemData._ItemData.ItemGen(1));
  InventoryPlayer.Add(2, ItemData._ItemData.ItemGen(2));
  InventoryPlayer.Add(3, ItemData._ItemData.ItemGen(3));
  }
   
  // Update is called once per frame
  void Update () {
   
  }

  void OnGUI()
  {
  inventoryWindowRect = GUI.Window(INVENTORY_WINDOW_ID, inventoryWindowRect, firstInventory, "INVENTORY"); //создаем окно
  if (isDraggable)
  {
  inventoryBoxRect = GUI.Window(INVENTORY_TEXTURE_ID, new Rect(Event.current.mousePosition.x + 1, Event.current.mousePosition.y + 1, 40, 40), insert, "", "box");

  }
  }

  //окно с изображением иконки
  void insert(int id)
  {
  GUI.BringWindowToFront(INVENTORY_TEXTURE_ID);//выводим на передний план окно с иконкой
  GUI.DrawTexture(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 40, 40), dragTexture);//рисуем текстуру иконки
  }

  //окно с инвентарем
  void firstInventory(int id)
  {
  for (int y = 0; y < invRows; y++)
  {
  for (int x = 0; x < invColumns; x++)
  {
  if (InventoryPlayer.ContainsKey(x + y * invColumns))//проверяем содеоржится ли ключ с данным значением
  {
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), new GUIContent(InventoryPlayer[x + y * invColumns].Textura), "button"))
  {
  if (!isDraggable)
  {
  dragTexture = InventoryPlayer[x + y * invColumns].Textura;//присваиваем нашой текстуре которая должна отображаться при перетаскивании, текстуру предмета
  isDraggable = true;//возможность перемещать предмет
  selectItem = InventoryPlayer[x + y * invColumns];//присваиваем вспомогательной переменной наш предмет
  InventoryPlayer.Remove(x + y * invColumns);//удаляем из словаря предмет
  }
  }
  }
  else
  {
  if (isDraggable)
  {
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button"))
  {
  InventoryPlayer.Add(x + y * invColumns, selectItem);//добавляем предмет который перетаскиваем в словарь
  //обнуляем переменные
  isDraggable = false;
  selectItem = null;
  }
  }
  else
  {
  //делаем ячейки не выделяемыми
  GUI.Label(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button");
  }
  }
  }
  }
  GUI.DragWindow();  
  }  
}


Запускаем и пробуем перемещать предметы внутри инвентаря. Все должно работать. На этом буду заканчивать первую часть урока.
Вывод: В этом уроке мы создали прототип инвентаря с возможность Drag&Drop. Правда полноценным инвентарем это тяжело назвать это скорее каркас для инвентаря, при чем очень простой, который уместился в 100 строк кода.
Почему я использовал именно словарь. Потому, что я очень люблю работать с ними ) Ну еще очень удобно считывать значения. Есть конечно недостатки у словарей: главная из которых НЕ возможность сериализовать словарь стандартными методами, но это легко можно обойти. Существует так же мнение, что словари работают «медленней», чем их аналоги. В принципе можно использовать вместо словаря список, хэш-таблицу или динамический массив Но как я уже говорил выше со словарями удобно работать.
Мы создавали инвентарь с помощью стандартного UnityGUI, что конечно сказалось на оптимизации (37 Draw Calls). На NGUI и подобных ассетах инвентарь создается еще проще. Лично я люблю боль и поэтому пользуюсь родным GUI .Ну а если серьезно, я использую собственное решение.
Заключение: В последующих уроках мы создадим всплывающие подсказки с описанием предметов, окно экипировки и разделение предметов по типу(оружие, броня и т.д), НПС с магазином, подбор предметов с земли и сундуков, конечно если вам будет это интересно.
Сам исходник Клац
Категория: Создание игр | Добавил: beril (30 апреля 2014) | Автор: Шевченко Денис
Просмотров: 16485 | Комментарии: 13 | Рейтинг: 4.4/8 |
Теги: урок, Unity, юнити уроки, инвентарь, Разработка игр, Rpg, юнити, Drag&Drop, C#, U3D
Дополнительные опции:
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:

Игровые объявления и предложения:
Если вас заинтересовал материал «Создание простого Drag&Drop инвентаря в Unity на C#. Часть 1», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела. Предлагаются такие схожие материалы: Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.

Всего комментариев: 13
+0-
13 totl   (24 июля 2015 17:44)
Сори, Start
Код

  void Start () {
  //добавляем предметы в инвентарь
  InventoryPlayer.Add(0, ItemData._ItemData.ItemGen(0));
  InventoryPlayer.Add(1, ItemData._ItemData.ItemGen(1));
  InventoryPlayer.Add(2, ItemData._ItemData.ItemGen(2));
  InventoryPlayer.Add(3, ItemData._ItemData.ItemGen(3));
  }  

на
Код

void Start () {  //добавляем предметы в инвентарь
  inventoryWindowRect=new Rect (10, 10,ButtonWidth*invColumns+10, ButtonHeight*invRows+25);
  for(int i=0;i<ItemData._ItemData.Items.Count;i++){
  InventoryPlayer.Add(i, ItemData._ItemData.ItemGen(i));
  }
}  

+0-
12 totl   (24 июля 2015 17:39)
Очень хороший пример, решил вот зарегаться, сказать "Спасибо!!!".
Так же добавить пару своих поправок по inventory.
В объявлении заменил
Код

  Rect inventoryWindowRect = new Rect(10, 10, 170, 265); //область окна

на
Код

  Rect inventoryWindowRect; //область окна

и Start
Код

void Start () {  //добавляем предметы в инвентарь
  inventoryWindowRect=new Rect (10, 10,ButtonWidth*invColumns+10, ButtonHeight*invRows+25);
  for(int i=0;i<ItemData._ItemData.Items.Count;i++){
  InventoryPlayer.Add(i, ItemData._ItemData.ItemGen(i));
  }
}

на
Код

void Start () {  //добавляем предметы в инвентарь
for(int i=0;i<ItemData._ItemData.Items.Count;i++){
  InventoryPlayer.Add(i, ItemData._ItemData.ItemGen(i));
}
}


1) Добавление эл-тов в массив через цикл(исключении ошибки выхода за пределы индекса массива, если в ItemData добавить меньше 4-х предметов(или не прописывать для большого кол-ва предметов Add))
2)Автоматический размер окна инвентаря.

+0-
11 PATCH1   (10 апреля 2015 14:37)
Мечи из линейки?)))DDD

+0-
10 Niels_Bor   (08 апреля 2015 23:05)
Вот в этом месте, если конкретно
Код

  if(Input.GetMouseButtonDown(0) && IsInRect(Input.mousePosition,Workspace))  
  {  

  Instantiate(selectItem.prefab,Input.mousePosition, Quaternion.identity);  
  isDraggable = false;  
  selectItem = null;  
  }  

+0-
9 Niels_Bor   (08 апреля 2015 23:02)
Вопрос автору. Я позаимствовал код и попытался чуть-чуть подогнать под себя. Так вот, мне нужно, чтобы при переносе итема в некоторую область, он появлялся там уже как префаб. Я объявил переменную вида Transform в item.cs. Но метод instantiate, который я вызываю из другого скрипта не срабатывает, говорит на месте префаба нет. Вот...
Код
if (InventoryPlayer.ContainsKey(x + y * invColumns))//проверяем содеоржится ли ключ с данным значением  
  {  
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), new GUIContent(InventoryPlayer[x + y * invColumns].Textura), "button"))  
  {  
  if (!isDraggable)  
  {  
  dragTexture = InventoryPlayer[x + y * invColumns].Textura;//присваиваем нашой текстуре которая должна отображаться при перетаскивании, текстуру предмета  
  isDraggable = true;//возможность перемещать предмет  
  selectItem = InventoryPlayer[x + y * invColumns];//присваиваем вспомогательной переменной наш предмет  
  InventoryPlayer.Remove(x + y * invColumns);//удаляем из словаря предмет  
  }  
  }  
  }  
  else  
  {  
  if (isDraggable)  
  {  
  if (GUI.Button(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button"))  
  {  
  InventoryPlayer.Add(x + y * invColumns, selectItem);//добавляем предмет который перетаскиваем в словарь  
  //обнуляем переменные  
  isDraggable = false;  
  selectItem = null;  
  }  
  else
  {
  if(Input.GetMouseButtonDown(0) && IsInRect(Input.mousePosition,Workspace))
  {

  //Instantiate(*selectItem.prefab_pointer,Input.mousePosition, Quaternion.identity);
  isDraggable = false;  
  selectItem = null;  
  }
  
  }
  }  
  else  
  {  
  //делаем ячейки не выделяемыми  
  GUI.Label(new Rect(5 + (x * ButtonHeight), 20 + (y * ButtonHeight), ButtonWidth, ButtonHeight), "", "button");  
  }  
  }

+0-
7 silver52rus   (25 сентября 2014 14:41)
silver52rusАвтору +, только нашол одну непонятную вещь: зачем делать 3 цикла когда 2 заглаза хватает, на сколько я понимаю первй цикл отвечает за прозрачность,наверно есть мение ресурсоёмкие способы,полностью не стал его убирать,снизил с 24 до 3,чуть-чуть просвечивает но зато фпс вместо 65 стал 75.

p.s. или я чёт не доганяю?).....

+0-
8 beril   (29 сентября 2014 01:14)
berilДа ты прав, в последнем коде 3 цикла, хотя в предыдущих вставках кода их 2.
Просто изначально, было 3 цикла(я по ощибке 3 сделал), но я тоже заметил сильный упадок производительности, и 1 удалил, который случайно туда попал. Видимо не везде отредактировал

+1-
3 alexsilent   (11 мая 2014 05:54)
alexsilentСпасибо добрый человек, обычно я использую ЯвуСкрипт, думаю смогу перевести без проблем с C#.

+1-
2 Gefak   (03 мая 2014 09:27)
Не понимаю я этих Drag&Drop инвентарей. 90% уроков по созданию инвентаря начинается с настройки как раз графической части. И обычно дальше этого не заходит, следующих уроков и не дождешься. А мне важно было создать инвентарь списком (что удобнее, как по мне. Гораздо рациональнее, больше информации. Кому нужны иконки? Казуальщина, но это так, мысли в слух)
Гдеж ты был раньше...
Замечательный урок. Go on, не останавливайся
(за транслит тоже наругал бы, но это совсем мелочь. Просто textura выглядит ооочень коряво, а всего-то нужно одну букву заменить)

+0-
4 beril   (14 мая 2014 01:08)
berilПродолжение обязательно будет
Р.с Я не совсем понял насчет транслита

+0-
5 rak   (23 мая 2014 10:44)
Надоело ждать моего урока?))

+0-
6 NEBR   (25 июня 2014 18:42)
NEBRимелась ввиду последняя буква (texturE)

+1-
1 Novatorvlad   (01 мая 2014 06:33)
NovatorvladВот это полезно. В свое время тоже намучался.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
10 случайных движков
  • BlitzMax
  • Adobe Flash
  • MegaKerma
  • Sparrow
  • Jolt3d!
  • Xenko
  • Sploder!
  • Aleph One
  • ZDoom
  • uranEngine
  • Друзья сайта
    Игровой форум GFAQ.ru Перевод консольных игр
    GameDev, Уроки OpenGL, Программирование, Создать Minecraft
    Все права сохранены. GcUp.ru © 2008-2017 | Free GIF Animator Рейтинг