danilaxxl danilaxxl

CollectableItemData.cs

[CreateMenuItem(fileName = "newItem", menuName = "Data/Items/Collectable", order = 51]

GoloGames GoloGames

vadya_ivan, рад, что вам игра показалась интересной : )

P.S. Кстати уже доступна бесплатная демо-версия в Steam

vadya_ivan vadya_ivan

Визуал, задумка, музыка , механики, все в цель

GoloGames GoloGames

Ato_Ome, спасибо за позитивные эмоции, будем стараться : )

Ato_Ome Ato_Ome

Потрясающий результат, все так четенько, плавненько)
То ли саунд, то ли плавность напомнили мне игрушку World of Goo, удачи вам в разработке и сил побольше дойти до релиза!)

Cute Fox Cute Fox

Graphics are a little cool, good HD content. But this game doesn't cause nary interest me.
However the game is well done.

GMSD3D GMSD3D

Почему действие после всех условий выполняется?
[step another object]

Zemlaynin Zemlaynin

Jusper, Везде, но наугад строить смысла нет. Нужно разведать сперва территорию на наличие ресурсов.

Jusper Jusper

Zemlaynin, а карьеры можно будет везде запихать?
Или под них "особые" зоны будут?

Zemlaynin Zemlaynin

Это так скажем тестовое строительство, а так да у города будет зона влияния которую нужно будет расширять.

Jusper Jusper

А ссылка есть?

Jusper Jusper

Я не оч понял из скриншота, как вообще работает стройка. У игрока будет как бы поле строительства?

split97 split97

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

split97 split97

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

ViktorJaguar ViktorJaguar

Почему я нигде не могу найти нормальный туториал, где покажут как экипировать предмет (например, меч) в определенную (выделенную под оружие) ячейку???

Логотип проекта Программирование

Generic-типы

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

Самая соль generic-типов кроется в универсальности - это такие типы, на месте которых может находиться... Да почти любой другой тип. Если мы, конечно, укажем любой.

Если вы уже использовали язык для написания хоть каких-нибудь задач, вам наверняка знаком тип List<T>, позволяющий хранить значения. Так, например, тип List<int> хранит в себе числа, а тип List<string> хранит строки. Фактически, список очень похож на массив, за единственной разницей - мы не указываем для него точное количество хранимых данных, его размер является динамичным.
Тип List<T> - классический пример использования Generic-типа.

Следующий код демонстрирует некоторые возможности класса, на случай если вы слышите про это впервые:

var strs = new List<string>(); //Создаем список строк
strs.Add("первая строка"); //Добавляем строку 'первая строка'
strs.Add("вторая строка"); //Добавляем строку 'вторая строка'
var c = strs[1]; //Запишет в 'c' значение "вторая строка"

var ints = new List<int>(); //Создаем список чисел
ints.Add(10); //Записываем в список значение 10
ints.Add(15); //Записываем в список значение 15
var i = strs[1]; //Запишет в i значение "15"

Этот пример уже может рассказать кое-что о классе List - в нем мы можем хранить данные разных типов (о чем я уже писал ранее). Как раз эта возможность и обеспечивается generic-типом, делая класс List универсальней.
Generic-типы объявляются в треугольных скобках, туда же и подставляется значение типа, например:

public class MyClass<T> //Описан класс MyClass с generic-типом T
{
    //Пока что пустое тело класса
}
var myClass = new MyClass<int>(); //Объявляем экземпляр класса MyClass подставляя тип int

Логично, что сам по себе generic-тип в заголовке классов нам погоды не делает. В случае с нашим классом MyClass<T> мы можем подставлять тип T в теле класса, чтобы произвести необходимые операции с этим типом:

public class MyClass<T> 
{
    private T value; //Мы можем подставлять его в качестве типа в любое место внутри класса. в котором мы его объявили

    public T GetValue() 
    {
        return value;
    }
}

Однако generic-типы можно объявить не только для всего класса, но и для отдельного метода. Например:

public class MyClass
{
    private object value;

    public T GetValue<T>() 
    {
        return (T)value;
    }
}

Бывают случаи, когда нам нужно указывать больше одно generic-типа. В этом случае мы перечисляем их через запятую:

public TOutput MyFunction<TInput,TOutput>(TInput input) //Используем больше одного generic-типа.
{
    //Тело функции
}

Ну что ж, возьмем простой пример и посмотрим, как вызываются методы с Generic типом. А вот и пример:

public void MyFunction<T>(T data) 
{
    //Тело функции
}

Для данного примера вызов функции (предполагается что вызываем в том же классе) будет вот таким:

MyFunction<MyType>(value);

При этом наши данные в переменной value должны наследоваться от MyType.
В таких тривиальных примерах, однако, вовсе не обязательно указывать Generic-тип, если компилятор видит что value имеет тип, который можно подставить в качестве T - он подставит его автоматически (да и по функции в принципе логично, что Generic-тип это тип, присущий параметру data.
Иначе говоря, такой пример можно записать еще проще:

MyFunction(value);

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

Так же Generic-тип может использоваться для делегата, однако я упущу этот момент в данной статье и оставлю его для статьи про делегаты, но вы можете самостоятельно ознакомиться с этим случаем вот здесь

Ограничение Generic-типа

Что ж, вероятно я уже успел показать все возможные варианты для подстановки generic-типа. Но зачастую наш generic-тип должен представлять какой-то более-менее конкретный тип.
Что это подразумевает?
Наш generic-тип изначально подразумевает любой тип. Но если нам, например, нужно разрешить для подстановки только классы Apple и Banana, наследуемые от класса Fruct - мы должны произвести дополнительные манипуляции.
Generic-типы ограничиваются при помощи ключевого слова where.
На следующих примерах показано место нахождения данного оператора:

public class MyClass<T> where T : struct
{
    //Тело класса
}
public void MyFunction<T1, T2>(T1 arg1, T2 arg2) 
    where T1 : Apple
    where T2 : Banana, new() 
//where пишется для каждого параметра отдельно, разделяясь разве что пробелами
//Однако несколько ограничений для одного параметра пишутся через запятую
{
    //Тело функции
}

Всего имеется 6 типов ограничений:

  • where T: struct

Тип должен быть значением. Такими являются например типы int, bool, float и все прочие типы, не имеющие значения null (все структуры).

  • where T : class

Тип должен быть классом. Такие типы могут иметь значение null, и имеют ряд своих вкусностей. Например, только ограничив тип до класса мы можем использовать оператор as для нашего Generic-типа. Так же, помимо самих классов под этим подразумеваются все остальные ссылочные типы - интерфейсы, массивы, делегаты.

  • where T : new()

Тип должен иметь открытый конструктор без параметров. При использовании с другими ограничениями ограничение new() должно устанавливаться последним.

  • where T : <любой наш класс>

Тип должен наследоваться от указанного класса или быть этим классом.

  • where T : <любой интерфейс>

Тип должен наследоваться от указанного интерфейса или быть им. Таких ограничений можно поставить несколько для одного параметра (так как мы можем наследоваться от нескольких интерфейсов). Интерфейсы так же могут содержать как ограничиваемый Generic-тип, так или любой другой.

  • where T1 :T2

Generic-тип T1 должен быть представлен generic-типом T2 или наследоваться от него.

Как несложно заметить - все случаи кроме :new() - это самые обычные случаи наследования. Единственное что в этих вариантах разное - показаны разные случаи применения этого наследования.

Значение по умолчанию

Бывают случаи, когда нам нужно вывести значение по умолчанию для нашего типа.
Что такое значение по умолчанию?
Для обычных классов это null, для int - 0, для bool - false (и далее по аналогии).
Для таких действий используется ключевое слово default(T):
Например:

public T GetDefaulForType<T>() 
{
    return default(T);
}

Данный пример возвращает значение по умолчанию для типа T.

Заключение

Вот такая вот мини-статья вышла. Здесь разобраны далеко не все случаи применения Generic-типов, однако, если вам хочется углубиться в данную тему - вы можете зайти на MSDN и прочитать о Generic-типах более развернутую информацию.
Мы разобрали что такое Generic-типы, куда они пишутся, на что заменяются. Узнали как эти типы можно ограничить и как вывести значение по умолчанию.
Я оставляю данную статью без конкретных примеров - их вы сможете придумать сами.

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

Спасибо за прочтение.

Смотрите также:


Комментарии



Познавательная статья, поставлю два жирных плюса.

а в с++ это называется шаблон

icedragoxx, да, но сделаны они совершенному по разному механизму. Поэтому тут они Generic-типы, а в тех же плюсах - шаблоны.
Но смысл в них один и тот же

Справка