Уроки - Форум Игроделов
Ср, 24 Апр 2024, 13:46 
 
Приветствую Вас Гость Главная | Регистрация | Вход
Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум Игроделов » ПРОГРАММИРОВАНИЕ » С# » Уроки
Уроки
seamanДата: Пт, 07 Дек 2012, 15:23 | Сообщение # 1
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Краткая заметка в ответ.

Наследование "на пальцах".

Все в школе изучали на биологии классы, отряды, семейства... Даже если Вы не помните что это такое, Вам должно быть понятно значение слова "Млекопитающие". Это животные, которые выкармливают детенышей молоком. Это их общая черта, которая отличает их от других классов. Можно вести класс:
Code
class Mlekopitajuchie
{
          bool mleko = true;
          bool liveRod = true;
}

второе что их отличает - они живородящие. Для этих двух отличий мы вводим две переменные, которое у всех млекопитающих true. У иных существ эти переменные false.

Классы делятся на отряды. Наследование!

У класса млекопитающих есть 20 отрядов. Всем этим отрядам присущи две указанные черты млекопитающих, но у каждого отряда есть свои какие-то отличительные черты.
Например хищники. Их отличительная особенность - они охотятся на других животных и питаются их мясом. В отличие от них насекомоядные понятно питаются насекомыми. Большинство грызунов питается травами, плодами и семенами растений, корнями и даже древесиной.
Соответственно можно перечислить возможные типы пищи:
Code
enum Food
{
          Meat;
          Vegetable;
...
}

И отличать отряды по этому признаку. Однако не нужно забывать, что все они не прекращают быть млекопитающими. Поэтому у них должны быть упомянутые выше две переменные, отличающие млекопитающих. Можно, конечно ввести кучу классов по числу отрядов и у них всех ввести те же самые переменные, что у класса "Млекопитающие". Однако выгоднее будет использовать уже написанный код. Для этого вводится понятие "наследование". Класс, который наследуется от другого класса включает в себя автоматом все переменные и методы этого класса. "Наследует" их.
Т.о. классы "Хищники" и грызуны будут:
Code
class Predator : Mlekopitajuchie
{
         Food meal = Food.Meat;
}
class Rodent : Mlekopitajuchie
{
         Food meal = Food.Vegetable;
}

Наследование записывается так ": имя класса от которого наследуемся".
Как видим мы не указали переменные mleko и liveRod, однако мы спокойно можем их использовать и у классов Predator и Rodent - они их унаследовали от Mlekopitajuchie!
Аналогично можно определить все остальные классы млекопитающих.
Совершенно аналогично все и относительно функций. У млекопитающих можно ввести функцию "Кормление". В которой, например, прибавлять энергию детенышу. Все млекопитающие,- и хищники и грызуны будут иметь эту функцию!

Виртуальные функции. Полиморфизм!

Все млекопитающие питаются. Соответственно в класс можно ввести функцию Eat. Все млекопитающие в детстве питаются молоком. Поэтому в этой функции проверяем есть ли поблизости молоко. Если есть уменьшаем количество молока и прибавляем энергию млекопитающему. Это общее поведение для всех млекопитающих.
Code
void Eat()
{
          if(milk > 0)
          {
              milk -= eatMilk;
              energy += ener;
          }
}

Однако у каждого отряда в пищевом поведении взрослой особи есть свои особенности.
Поэтому в классе "Хищники" нужно изменить функцию Eat. В данном случае проверяем возраст особи и если он больше определенного значения вместо поиска молока начинаем искать мясо. Если же меньше этого значения = ищем молоко.
Code
void Eat()
{
          if(age > minAge) eatMeat();
          else base.Eat();
}

здесь видим новую запись - "base." - таким образом вызываются функции из класса от которого наследовались.

Спросите - а где виртуальные функции? Дело в том, что очень часто нам не важно какого конкретно отряда животное. Поэтому вместо параметра функции типа Predator можно передать Mlekopitajuchie. Все Predator являются также и Mlekopitajuchie. Поэтому даже если в функцию будет передано значение типа Predator - ошибки не будет. Однако если мы вдруг в такой функции вызовем функцию Eat, то будет вызвана функция из класса Mlekopitajuchie, хотя у нас на самом деле Predator. Хотелось бы, чтобы при этом вызывалась соответствующая переданному значению функция. Вот тут приходят на помощь виртуальные функции. Переопределим функции так:
"Млекопитающие"
Code
virtual void Eat()
{
          if(milk > 0)
          {
              milk -= eatMilk;
              energy += ener;
          }
}

"Хищники"
Code
override void Eat()
{
          if(age > minAge) eatMeat();
          else base.Eat();
}

Здесь в Млекопитающие - функция определена как виртуальная, а в Хищники - как переопределенная.
Если теперь мы введем функцию:
Code
void Proba(Mlekopitajuchie animal)
{
          Eat();
}

То внутри ее будет вызвана Eat, соответствующая тому, что мы передадим в качестве параметра. Если Хищник - то будет искать мясо, если Грызун, то растения.
Ощущаете удобство?

Сорри, если несколько сумбурно - пишу на работе, второпях. Дергают и отвлекают. dry
 
СообщениеКраткая заметка в ответ.

Наследование "на пальцах".

Все в школе изучали на биологии классы, отряды, семейства... Даже если Вы не помните что это такое, Вам должно быть понятно значение слова "Млекопитающие". Это животные, которые выкармливают детенышей молоком. Это их общая черта, которая отличает их от других классов. Можно вести класс:
Code
class Mlekopitajuchie
{
          bool mleko = true;
          bool liveRod = true;
}

второе что их отличает - они живородящие. Для этих двух отличий мы вводим две переменные, которое у всех млекопитающих true. У иных существ эти переменные false.

Классы делятся на отряды. Наследование!

У класса млекопитающих есть 20 отрядов. Всем этим отрядам присущи две указанные черты млекопитающих, но у каждого отряда есть свои какие-то отличительные черты.
Например хищники. Их отличительная особенность - они охотятся на других животных и питаются их мясом. В отличие от них насекомоядные понятно питаются насекомыми. Большинство грызунов питается травами, плодами и семенами растений, корнями и даже древесиной.
Соответственно можно перечислить возможные типы пищи:
Code
enum Food
{
          Meat;
          Vegetable;
...
}

И отличать отряды по этому признаку. Однако не нужно забывать, что все они не прекращают быть млекопитающими. Поэтому у них должны быть упомянутые выше две переменные, отличающие млекопитающих. Можно, конечно ввести кучу классов по числу отрядов и у них всех ввести те же самые переменные, что у класса "Млекопитающие". Однако выгоднее будет использовать уже написанный код. Для этого вводится понятие "наследование". Класс, который наследуется от другого класса включает в себя автоматом все переменные и методы этого класса. "Наследует" их.
Т.о. классы "Хищники" и грызуны будут:
Code
class Predator : Mlekopitajuchie
{
         Food meal = Food.Meat;
}
class Rodent : Mlekopitajuchie
{
         Food meal = Food.Vegetable;
}

Наследование записывается так ": имя класса от которого наследуемся".
Как видим мы не указали переменные mleko и liveRod, однако мы спокойно можем их использовать и у классов Predator и Rodent - они их унаследовали от Mlekopitajuchie!
Аналогично можно определить все остальные классы млекопитающих.
Совершенно аналогично все и относительно функций. У млекопитающих можно ввести функцию "Кормление". В которой, например, прибавлять энергию детенышу. Все млекопитающие,- и хищники и грызуны будут иметь эту функцию!

Виртуальные функции. Полиморфизм!

Все млекопитающие питаются. Соответственно в класс можно ввести функцию Eat. Все млекопитающие в детстве питаются молоком. Поэтому в этой функции проверяем есть ли поблизости молоко. Если есть уменьшаем количество молока и прибавляем энергию млекопитающему. Это общее поведение для всех млекопитающих.
Code
void Eat()
{
          if(milk > 0)
          {
              milk -= eatMilk;
              energy += ener;
          }
}

Однако у каждого отряда в пищевом поведении взрослой особи есть свои особенности.
Поэтому в классе "Хищники" нужно изменить функцию Eat. В данном случае проверяем возраст особи и если он больше определенного значения вместо поиска молока начинаем искать мясо. Если же меньше этого значения = ищем молоко.
Code
void Eat()
{
          if(age > minAge) eatMeat();
          else base.Eat();
}

здесь видим новую запись - "base." - таким образом вызываются функции из класса от которого наследовались.

Спросите - а где виртуальные функции? Дело в том, что очень часто нам не важно какого конкретно отряда животное. Поэтому вместо параметра функции типа Predator можно передать Mlekopitajuchie. Все Predator являются также и Mlekopitajuchie. Поэтому даже если в функцию будет передано значение типа Predator - ошибки не будет. Однако если мы вдруг в такой функции вызовем функцию Eat, то будет вызвана функция из класса Mlekopitajuchie, хотя у нас на самом деле Predator. Хотелось бы, чтобы при этом вызывалась соответствующая переданному значению функция. Вот тут приходят на помощь виртуальные функции. Переопределим функции так:
"Млекопитающие"
Code
virtual void Eat()
{
          if(milk > 0)
          {
              milk -= eatMilk;
              energy += ener;
          }
}

"Хищники"
Code
override void Eat()
{
          if(age > minAge) eatMeat();
          else base.Eat();
}

Здесь в Млекопитающие - функция определена как виртуальная, а в Хищники - как переопределенная.
Если теперь мы введем функцию:
Code
void Proba(Mlekopitajuchie animal)
{
          Eat();
}

То внутри ее будет вызвана Eat, соответствующая тому, что мы передадим в качестве параметра. Если Хищник - то будет искать мясо, если Грызун, то растения.
Ощущаете удобство?

Сорри, если несколько сумбурно - пишу на работе, второпях. Дергают и отвлекают. dry

Автор - seaman
Дата добавления - 07 Дек 2012 в 15:23
MaURooney10Дата: Вт, 18 Дек 2012, 13:47 | Сообщение # 2
 
Сообщений: 659
Награды: 3
Репутация: 123
Статус: Offline
отличные уроки! как раз конкретно на юнити сел)
 
Сообщениеотличные уроки! как раз конкретно на юнити сел)

Автор - MaURooney10
Дата добавления - 18 Дек 2012 в 13:47
seamanДата: Пн, 23 Сен 2013, 08:12 | Сообщение # 3
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Шарп не поддерживает множественное наследование. Т.е. нельзя напрямую сделать "Динотабурет". Однако есть обходной маневр. В шарпе есть такая штука - "Интерфейс". Класс может реализовывать много разных интерфейсов.
Наиболее просто понять что такое интерфейс можно взглянув на какой-нибудь универсальный блок питания. Обычно у таких блоков шнур на конце которого несколько разных разъемов. Один можно воткнуть в мобильник, другой в какой-нибудь плейер. Эти разъемы и есть интерфейсы.
Интерфейс записывается так:
Код
public interface IName
{
     bool MyFunc(float par);
}

Т.е. подобно классу. Только у функций в нем нет тела (операторов, которые что-то делают). Также у них не может быть модификаторов доступа (public).
Тело функции Вы записываете в классе, который реализовывает этот интерфейс. Потому и говорят "реализовывает", а не наследует. У наследуемого класса функции уже что-то делают, у интерфейса только определена их сигнатура (т.е. имя, входные параметры и что возвращает). А что делать определяется в классе, реализующем интерфейс.
С одной стороны такая структура уменьшает повторное использование кода. Реализацию, даже если она одинаковая приходится писать во всех классах, реализующих интерфейс.
С другой стороны это все же позволяет имитировать множественное наследование.
Например у нас есть класс и интерфейс
Код
class Dino
{
    public virtual void Eat(float){}
}
interface ITaburet
{
    bool SitDown();
}

И есть классы наследующие от Dino и реализующий интерфейс табурета
Код
class DiplodokTab : Dino, ITaburet
{
    public bool SitDown(){return true;}
}

class TiranosaurTab : Dino, ITaburet
{
    public bool SitDown(){return false;}
}

Можно как в первом топике использовать все преимущества наследования и переопределить метод Eat. Можно с другой стороны где-то написать функцию, которая получает флаг - можно ли на нем сидеть так:
Код
public bool Sit(ITaburet myDino)
{
    return myDino.SitDown();
}

Почему можно? Потому что любой класс, который реализует интерфейс ITaburet обязан иметь функцию SitDown!
Тогда если мы в нее передадим экземпляр класса диплодок - она вернет "да", а если тиранозавр - вернет "нет".
PS: Как обычно слегка сумбурно, т.к. на ходу пишу.
 
СообщениеШарп не поддерживает множественное наследование. Т.е. нельзя напрямую сделать "Динотабурет". Однако есть обходной маневр. В шарпе есть такая штука - "Интерфейс". Класс может реализовывать много разных интерфейсов.
Наиболее просто понять что такое интерфейс можно взглянув на какой-нибудь универсальный блок питания. Обычно у таких блоков шнур на конце которого несколько разных разъемов. Один можно воткнуть в мобильник, другой в какой-нибудь плейер. Эти разъемы и есть интерфейсы.
Интерфейс записывается так:
Код
public interface IName
{
     bool MyFunc(float par);
}

Т.е. подобно классу. Только у функций в нем нет тела (операторов, которые что-то делают). Также у них не может быть модификаторов доступа (public).
Тело функции Вы записываете в классе, который реализовывает этот интерфейс. Потому и говорят "реализовывает", а не наследует. У наследуемого класса функции уже что-то делают, у интерфейса только определена их сигнатура (т.е. имя, входные параметры и что возвращает). А что делать определяется в классе, реализующем интерфейс.
С одной стороны такая структура уменьшает повторное использование кода. Реализацию, даже если она одинаковая приходится писать во всех классах, реализующих интерфейс.
С другой стороны это все же позволяет имитировать множественное наследование.
Например у нас есть класс и интерфейс
Код
class Dino
{
    public virtual void Eat(float){}
}
interface ITaburet
{
    bool SitDown();
}

И есть классы наследующие от Dino и реализующий интерфейс табурета
Код
class DiplodokTab : Dino, ITaburet
{
    public bool SitDown(){return true;}
}

class TiranosaurTab : Dino, ITaburet
{
    public bool SitDown(){return false;}
}

Можно как в первом топике использовать все преимущества наследования и переопределить метод Eat. Можно с другой стороны где-то написать функцию, которая получает флаг - можно ли на нем сидеть так:
Код
public bool Sit(ITaburet myDino)
{
    return myDino.SitDown();
}

Почему можно? Потому что любой класс, который реализует интерфейс ITaburet обязан иметь функцию SitDown!
Тогда если мы в нее передадим экземпляр класса диплодок - она вернет "да", а если тиранозавр - вернет "нет".
PS: Как обычно слегка сумбурно, т.к. на ходу пишу.

Автор - seaman
Дата добавления - 23 Сен 2013 в 08:12
seamanДата: Чт, 11 Июн 2015, 20:23 | Сообщение # 4
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Начал записывать цикл уроков по программированию на C# под Unity.


 
СообщениеНачал записывать цикл уроков по программированию на C# под Unity.



Автор - seaman
Дата добавления - 11 Июн 2015 в 20:23
seamanДата: Вс, 14 Июн 2015, 15:17 | Сообщение # 5
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
4 урок - if, while for
 
Сообщение4 урок - if, while for

Автор - seaman
Дата добавления - 14 Июн 2015 в 15:17
seamanДата: Вт, 16 Июн 2015, 17:12 | Сообщение # 6
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline

Перечисления, swich, значение null, передача параметров по ссылке, тайминг, вектора, значение параметра по умолчанию.
 
Сообщение
Перечисления, swich, значение null, передача параметров по ссылке, тайминг, вектора, значение параметра по умолчанию.

Автор - seaman
Дата добавления - 16 Июн 2015 в 17:12
seamanДата: Чт, 18 Июн 2015, 21:01 | Сообщение # 7
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline

Работа с Enum, создание массивов, получение элемента массива. Приведение типов. Решение проблемы со стрельбой очередью.
 
Сообщение
Работа с Enum, создание массивов, получение элемента массива. Приведение типов. Решение проблемы со стрельбой очередью.

Автор - seaman
Дата добавления - 18 Июн 2015 в 21:01
seamanДата: Пт, 19 Июн 2015, 14:39 | Сообщение # 8
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline

Все о корутинах, foreach, инкремент, декремент.
 
Сообщение
Все о корутинах, foreach, инкремент, декремент.

Автор - seaman
Дата добавления - 19 Июн 2015 в 14:39
seamanДата: Вт, 23 Июн 2015, 16:43 | Сообщение # 9
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Восьмой урок по программированию на C# под Unity.
ООП - инкапсуляция, наследование, полиморфизм. Интерфейсы. Комптоненты.
 
СообщениеВосьмой урок по программированию на C# под Unity.
ООП - инкапсуляция, наследование, полиморфизм. Интерфейсы. Комптоненты.

Автор - seaman
Дата добавления - 23 Июн 2015 в 16:43
seamanДата: Чт, 25 Июн 2015, 17:45 | Сообщение # 10
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Девятый урок по программированию на C# под Unity. Практика. Начинаем создавать игру.

Создание атласа спрайтов, настройка их в Юнити. Создание спрайтовых анимаций. Создание контроллера анимаций. Первоначальная настройка сцен.
 
СообщениеДевятый урок по программированию на C# под Unity. Практика. Начинаем создавать игру.

Создание атласа спрайтов, настройка их в Юнити. Создание спрайтовых анимаций. Создание контроллера анимаций. Первоначальная настройка сцен.

Автор - seaman
Дата добавления - 25 Июн 2015 в 17:45
seamanДата: Вс, 28 Июн 2015, 18:35 | Сообщение # 11
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
10 урок - практика.

Продолжаем создание игры. Курсор выбора меню, менеджер игры. Константы. Загрузка уровней. Сохранение, восстановление данных с помощью PlayerPrefs. Операторы минус-равно, плюс-равно... Свойства класса - геттер/сеттер. Запуск аудио. Action - передача метода в качестве параметра.
 
Сообщение10 урок - практика.

Продолжаем создание игры. Курсор выбора меню, менеджер игры. Константы. Загрузка уровней. Сохранение, восстановление данных с помощью PlayerPrefs. Операторы минус-равно, плюс-равно... Свойства класса - геттер/сеттер. Запуск аудио. Action - передача метода в качестве параметра.

Автор - seaman
Дата добавления - 28 Июн 2015 в 18:35
seamanДата: Вт, 30 Июн 2015, 21:26 | Сообщение # 12
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Урок 11 - практика часть 3.

Продолжаем создавать игру. Рефакторинг кода. Статические методы. List. Создание спрайта рантайм. Генерация уровня по текстовому файлу.
 
СообщениеУрок 11 - практика часть 3.

Продолжаем создавать игру. Рефакторинг кода. Статические методы. List. Создание спрайта рантайм. Генерация уровня по текстовому файлу.

Автор - seaman
Дата добавления - 30 Июн 2015 в 21:26
seamanДата: Ср, 01 Июл 2015, 15:08 | Сообщение # 13
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Урок 12.
Коротенький урок, в котором я описываю вкраце как настроить проект для использования с системой контроля версий. На битбакет создал репозиторий по Battle City. Ссылку ищите на моем сайте http://devunity.tk
 
СообщениеУрок 12.
Коротенький урок, в котором я описываю вкраце как настроить проект для использования с системой контроля версий. На битбакет создал репозиторий по Battle City. Ссылку ищите на моем сайте http://devunity.tk

Автор - seaman
Дата добавления - 01 Июл 2015 в 15:08
seamanДата: Вт, 14 Июл 2015, 23:55 | Сообщение # 14
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Урок 13.
Продолжаем делать игру. Генерируем танки игроков. Реализация стрельбы.
 
СообщениеУрок 13.
Продолжаем делать игру. Генерируем танки игроков. Реализация стрельбы.

Автор - seaman
Дата добавления - 14 Июл 2015 в 23:55
seamanДата: Пт, 17 Июл 2015, 23:14 | Сообщение # 15
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Урок 14. Практика часть 5.
Singleton, статические классы, Generic, методы расширения, спавн, щит танка, генерация танков врагов.
 
СообщениеУрок 14. Практика часть 5.
Singleton, статические классы, Generic, методы расширения, спавн, щит танка, генерация танков врагов.

Автор - seaman
Дата добавления - 17 Июл 2015 в 23:14
seamanДата: Вс, 19 Июл 2015, 16:24 | Сообщение # 16
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Урок 15. Практика часть 6.
SendMessage, делегаты, события, шаблон "Наблюдатель". Смерть танчиков...
 
СообщениеУрок 15. Практика часть 6.
SendMessage, делегаты, события, шаблон "Наблюдатель". Смерть танчиков...

Автор - seaman
Дата добавления - 19 Июл 2015 в 16:24
seamanДата: Пн, 14 Сен 2015, 22:24 | Сообщение # 17
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
16 урок - исправление ошибок.
 
Сообщение16 урок - исправление ошибок.

Автор - seaman
Дата добавления - 14 Сен 2015 в 22:24
Форум Игроделов » ПРОГРАММИРОВАНИЕ » С# » Уроки
  • Страница 1 из 1
  • 1
Поиск:
Загрузка...

Game Creating CommUnity © 2009 - 2024