Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Прискорений в’їзд в C# & .NET

with 4 comments

Джеймс Сільва і Джон Сідлак

Створення ігор з XNA 2.0

Практичний посібник для самостійного створення ігор

Розділ 1

Екскурс по .NET

Перед тим як почати писати гру, чи будь-яку іншу програму, надзвичайно важливо навчитися програмувати :). Цей розділ містить стислий огляд деяких ключових ідей, які стосуються .NET і мови C#. Він дозволить швидко освоїти програмування .NET на мові C#. Якщо ви маєте певний досвід розробки на базі платформи .NET, ви можете пропустити цей розділ повністю.

Платформа .NET

Керована мова – мова яка компілюється в проміжний код, який потім ще можна редагувати і керувати його виконанням. В основному цей термін використовує Майкрософт при згадці про мови, які реалізують .NET .

.NET (Вимовляється як “дот нет”) називається платформою, тому що це більш ніж якийсь код, середовище програмування, чи набір мов. Платформа складається з множини цілей, розвязаних Майкрософт, щоб захопити кросплатформенну розробку і створити метод що дозволяє прискорити розробку програм. В маркетингових термінах, .NET полегшує роботу розробника, дозволяючи йому зфокусуватись на функціональності, замість конструювання механізмів ядра додатку.

Платформа включає в себе широкий діапазон трьохбуквенних акронімів (ТБА), кілька з яких ви вивчите під час програмування:).

Коли ви, чи якийсь інший програміст пише програму або бібліотеку в .NET, вона компілюється в проміжний код (ассемблер, умовно кажучи). Цей ассемблер, не важливо якого типу, може бути використаний іншими програмами. Це дозволяє розробникам легко посилатись і використовувати код, написаний в різних керованих мовах програмування, таких як C#, Visual Basic .NET (VB .NET), або Managed C++. Це завдяки тому факту, що под написаний в цих мовах компілюється в Загальну Проміжну Мову (Common Intermediate Language (CIL) ), низькорівневу мову, яка трохи нагадує ассемблер. Тим не менш, це не ассемблер, вона репрезентує скоріше код, аніж машинно-залежні інструкції. Той факт, що CIL являє собою фактичний код, а не оптимізований і заплутаний ассемблерний код, дозволяє йому бути дизасембльованим, достатньо просто в мови високого рівня. CIL є важливим проміжним кроком і платформі, тому що він обєднує всі мови в єдиній кастрюлі, надаючи сумісність, тому різні шматки коду можуть звязуватись.

Як використовується CIL, і чому він такий кросплатформенний? Через те, що CIL представляє проміжний шар між високорівневими мовами і машинним кодом, який є залежним від середовища, платформа .NET потребує щось, що може інтерпритувати код, і запускати його. Модулі написані для платформи запускаються Загальним Віртуальним Процесором (Common Language Runtime (CLR) ), який інтерпритує і використовує код CIL синхронно з його виконанням. Приблизна схема показана на Рис. 1. Одним з плюсів інтерпритації під час виконання є те, що це надзвичайно полегшує відлагодження програм. Вона дозволяє розробнику зупинити виконання в будь-який момент і виконувати код крок за кроком.

Код (високорівневі мови)
С# VB.NET MC++
Компілятори
Проміжна мова (CIL)
Common Language Runtime
x86 x64

Рис. 1 Процес створення коду .NET з вихідного коду

Ну а як щодо мов? Ви тепер знаєте, що мови вміщуються в одну кастрюлю яка називається CIL, і що проміжна мова може бути запущена на віртуальному процесорі, але як це все виходить? Виявляється, що клей який тримає мови разом це ще один акронім. Загальна Система Типів (Common Type System (CTS) ) надає базовий рівень типів і функціональності яка є глобальною до всіх керованих мов. Рис. 2 показує як система типів і мови взаємодіють.

CTS (mscorlib.dll)

C#

VB.NET

MC++

Рис. 2 CTS і вихідні коди

CTS надається іншим модулем, mscorlib.dll, на який може посилатись кожен проект .NET. Використовуючи .NET Reflector Лютза Роедера (який можна завантажити з www.aisto.com/roeder/dotnet/), можна подивитись, що mscorlib.dll насправді містить. Якщо ви подивитесь на нього, ви зауважите, всі спільні типи для кожної мови, такі як Boolean, Int32, і Byte. Рис. 3 показує приклад типу Boolean всередині бібліотеки CTS.


Рис. 3 Поверховий огляд mscorlib.dll в .NET Reflector.

Тепер, коли ви розумієте, що дає бібліотека mscorlib.dll, ви знаєте одну частину того, що дає фіговина названа .NET framework. В загальному, framework (інфраструктура по-нашому) – це набір бібліотек, складених з типів, методів, алгоритмів, і ресурсів, які розробники можуть використовувати для створення програм. Перевернувши графік на Рис. 1, ви можете побачити що модулі посилаються і використовують один одного щоб фактично створити програму. Ці бібліотеки і вся ця технологія марні без вміння їх використовувати.

Змінні

Як розробники ми використовуємо змінні, поля, члени, чи як ще ви вирішили називати їх для зберігання всякої фігні. Коли ми хочемо порахувати від одного до десяти, або знати коли користувач клацнув щось, ми використовуємо змінні, щоб зберігати дані. Кожна змінна має те, що ми називаємо типом, який точно визначає, що змінна може містити. Наприклад, замінна типу int, зберігає може містити цілі числа. Змінна типу double чи float може містити десяткові дроби. C# має характерний спосіб оголошення і використання таких змінних. Наприклад, ми додаємо два числа в такий спосіб:

int myValue = 4;
int myValue2 = 3;
int myResult = myValue + myValue2;

Ми оголошуємо змінні пишучи спочатку назву типу, а потім імя змінної. Важливо зауважити, що імя змінної не може починатися з нічого крім латинської букви. Тому наступні оголошення невірні:

int 3myValue;
int #myValue;

Після першого символа, ви можете використовувати числа і символ підкреслювання. Розмір літер не має значення і зазвичай використовується для зручності читання. Правда великі і маленькі букви розрізняються і тому всі змінні описані нижче є окремими змінними.

int my_VALUE;
int m_value;
int myvalue;
int MyValue;

Після опису змінної, ми можемо присвоїти їй значення використовуючи знак рівності. Змінна яку ми встановлюємо завжди зліва від знаку рівності, і значення яке ми генеруємо знаходиться зправа. Тому, в першому прикладі в цій секції, ми присвоїли змінній myResult значення суми змінних myValue і myValue2.

Ми можемо відділити оголошення змінної від встановлення її значення. Ці типи змінних відомі як типи значення відповідно тому, як вони зберігаються в памяті. По суті, є два місця де може зберігатись змінна: стек і керована купа. Типи значення, в основному, зберігаються в стеку, тому що це швидко і підло:). Більші типи, відомі як обєктні, або типи посилань зберігаються в купі і вимагають використання оператора new, як ви можете побачити в прикладах пізніше в цьому розділі. Таблиця 1 показує короткий список простих типів і їх використання.

Таблиця 1 Деякі прості типи .NET.

Тип

Приклад

Використання
bool

bool myBoolean = true;

True або false, представляє біт (0 або 1)
byte

byte myByte = 3;

Розмір вісім бітів. Ціле число між 0 і 255
short

short myShort = 3;

Маленькі цілі числа (від -32768 до 32767). Довжина 16 біт
int

int myValue = 3;

Тридцятидвохрозрядне ціле
double

double myDbl = 3.0;

Дійсне число подвійної точності.
float

float myFloat = 3.0f;

Дійсне число
char

char myCharacter = '3';

Символ
string

string myString = "333";

Багато символів

Що, якщо ми хочемо робити перетворення змінної одного типу в іншу? Існує проблема переходу від наприклад типу int в byte. Коротше кажучи, всі дані всередині int не можуть поміститись в byte, так як і string не може поміститись в char. Тим не менш, в нас є явне зведення типів (type casting), яке допомагає нам вмістити стільки, скільки можливо. Щоб звести змінну до певного типу, ми мусимо написати перед нею назву типу в дужках, як це зроблено на прикладі:


int myInteger = 254;
byte myByte = 1;
myByte = myInteger; // Це помилка!
myByte = (byte)myInteger; // Це зпрацює!

Треба мати на увазі, що коли ми переміщуємось від більш точного типу такого як int чи double, до менш точного як byte або float ми можемо втратити деякі дані. Більше того, коли ми виконуємо математичні операції, ми можемо випадково переповнити, або загубити значення змінної. Давайте переробимо попередній приклад, щоб побачити як воно відбувається:


int myInteger = 254;
byte myByte = 10;
myByte += (byte)myInteger;

В цьому випадку, байт, myByte, насправді прокрутиться крізь 255, і встановиться назад в нуль, тому що 254+10 це більше ніж загальний обєм (255), який може зберігати байт. Подібно char може зберігати тільки один символ з string.

Також ви могли помітити новий спосіб додавання. Можна комбінувати математичні операції і оператор присвоєння і один оператор. Попередній приклад використовує оператор += тому до ми хочемо додавати myInteger до того що myByte вже містить.

Бавитись з змінними може бути цікаво, але щоб повеселитись по справжньому потрібно навчитись створювати і використовувати обєкти.

Обєктно-орієнтоване програмування

C# (вимовляється “сі шарп”) відомий як мова обєктно-орієнтованого програмування (ООП), тому що вона грунтується на здатності форматувати код в секції, які звуться обєктами.

Ви можете уявляти обєкти як будь-що, над чим ви можете зробити якусь дію, або будь-що що має властивість. Якщо думати про наш світ, ми можемо вважати предмети обєктами. Розглянемо ідею подання коробки як обєкта. Ключова ідея ООП – поняття відношень між обєктами. У випадку пачки чаю, ми можемо сказати, що вона є коробкою. Так само як і коробка сірників. Є відношення яке каже нам, що щось може бути класифіковано, як щось більш загальне. Таке відношення називається наслідуванням і є суттю обєктно-орієнтованих мов. Коли обєкт наслідує інший обєкт, він бере деякі з його властивостей і методів, як свої власні.

Далі оригінальна книжка описує обєкт коробку, але це занадто тупий приклад як на мене. А так як ми хочемо писати ігри, то на мою думку обєкт вектор, буде набагато кориснішим. Все таки всі ігри починаються з аналітичної геометрії.


class Vector3d
{
	//Координати
	public double x;
	public double y;
	public double z;
}
class Position: Vector3d
{
	//Кути Ейлера
	public double ax;
	public double ay;
	public double az;
}

Цей код містить наслідування. Вектор включає свої координати. Позиція (якогось предмета) містить координати центру мас предмета і додатково інформацію про орієнтацію в просторі. Ця інформація називається кутами Ейлера, тому що колись Ейлер довів, що будь – яке положення предмета в просторі можна отримати повернувши його на певні кути навколо трьох ортогональних осей. Позиція і вектор перебувають в відношенні наслідування.

Кожен вектор має довжину. Ми можемо додати нове поле і назвати його довжина, але ця інформація буде надлишковою, бо вектор однозначно визначається своїми координатами, і крім того, при зміні координат, нам доведеться також змінювати довжину. Зате ми можемо додати до обєкта метод, який буде кожного разу казати нам довжину вектора.

Перед тим, як ви прочитаєте наступний блок коду, потрібно зрозуміти важливу річ. Ми можемо сказати, що кожен обєкт, може вважатися типом. Тип описує імя обєкта, а також що він містить, і що він може робити. В нашому прикладі ми говоримо, що Vector3d має тип клас і має координати x,y і z. Коли ми оголошуємо метод, ми мусимо дати йому те що розглядається нами як тип результату. Коли метод викликається десь в коді, він робить якісь дії і потім видає якесь значення. Якщо метод не обчислює ніякі значення то тип результату оголошують void що значить порожній. Такий метод не мусить видавати якесь значення.


class Vector3d
{
	// ...
	
	//Довжина вектора
	public double Length()
	{
		return math.sqrt(x*x+y*y+z*z);
	}
	//Довжина вектора в квадраті
	public double LengthSqr()
	{
		return x*x+y*y+z*z;
	}
}

В коді вище описано дві функції. Друга працює набагато швидше, і може використовуватись, коли нам достатньо тільки порівняти довжини. Так як в іграх швидкість має критичне значення, бажано при будь-якій можливості використовувати другу функцію.

І ви вже напевне помітили що всюди використовується слово public. Іншою важливою ідеєю ООП є поняття доступності. В загальному, доступність визначає, хто може робити що і звідки. У всіх попередніх прикладах ми зробили все публічним, тому код ззовні класів Vector3d і Position, може використовувати описані поля. Ось основні види доступності:

  • public: кожен може викликати метод, або використати члена.
  • private: тільки сам клас може бачити, викликати, або використовувати це.
  • protected: доступний для класу і всіх його потомків.
  • internal: подібний до public, але тільки код всередині модуля може використовувати метод або поле.

    Ці обмеження доступу дуже корисні під час написання коду. Нижче буде дано приклад, коли клас Vector3d використовує властивості замість публічних полів щоб зберігати і обслуговувати дані. Властивості – це швидкий шлях описати методи доступу до приватних полів, чи до будь-чого іншого, і можуть містити будь-який стандартний код.

    
    class Vector3d
    {
    	// ...
    	
    	//Довжина вектора (зауважте, назва з маленької букви, тому відрізняється від раніше описаного методу)
    	public double length()
    	{
    		get { return Length(); };
    		set { 
    			double scale=value/Lenght();
    			x*=scale; 
    			y*=scale; 
    			z*=scale;
    			};
    	}
    }
    
    

    Цей шматок коду описує властивість довжини. Читання і запис властивостей здійснюється секціями коду get { ... }; і set { ... }; відповідно. Коли ми хочемо дістати значення властивості, клас дає нам її за допомогою оператора return, а коли хочемо присвоїти властивості значення, це значення передається в клас в змінній value.

    Давайте, ще опишемо метод, який не повертає результат і не вимагає параметрів. Наприклад нормалізація вектора (обрізання його до одиничної довжини).

    
    class Vector3d
    {
    	// ...
    	
    	// Нормалізація
    	public void Normalize()
    	{
    		length = 1;
    	}
    }
    
    

    Вище ми могли бачити ще кілька концепції ООП. Першим є те, що ми можем використовувати для доступу до даних здобувачів (getters) і встановлювачів (setters). Вони, що не дивно, використовуються для здобуття значення властивості і для її встановлення. Вони завжи на похваті дозволяючи нам контролювати доступ до даних.

    Контроль виконання з допомогою булевої логіки (оператор if)

    Булеві значення бувають двох типів. Як їх називають математики “тру” і “фолс” :). В одному з попередніх прикладів ми при зміні довжини вектори допустили важливу помилку. Якщо довжина вектора нуль, то наша програма аварійно завершить роботу. Це повязано з тим що на нуль ділити не можна, і ми в такому випадку не знаємо напрямок вектора. Тому ми мусимо додати в код перевірку довжини:

    
    class Vector3d
    {
    	// ...
    	
    	//Довжина вектора 
    	public double length()
    	{
    		get { return Length(); };
    		set { 
    			double l=Length();
    			if(l==0) return;
    			double scale;
    			scale=value/l;
    			x*=scale; 
    			y*=scale; 
    			z*=scale;
    			};
    	}
    }
    
    

    Тепер якщо довжина вектора нуль, то її не можна міняти за допомогою звичайного присвоєння. В прикладі вище використовується скорочений запис умовного оператора

    
    if(умова) 
    	оператор_що_виконується_коли_умова_тру;
    

    Повний запис виглядає так:

    
    if(умова) 
    	оператор_що_виконується_коли_умова_тру; 
    else 
    	оператор_що_виконується_коли_умова_фолс;
    

    Якщо в умовному операторі треба використати кілька операцій їх складають в так званий складений оператор. Це просто послідовність операторів у фігурних дужках.

    Умовою є будь-який булевий вираз. Булевим виразом є будь-який вираз який приймає тільки булеві значення. Результати роботи операторів = == != мають булевий тип. Як оператор порівняння використовується ==, щоб не плутати його з =. Це дає мовам сімї С перевагу над мовами сімї Алгола, бо статистика каже що оператор присвоєння використовується в програмах в кілька разів частіше ніж оператор порівняння. Того це економить час набору коду на клавіантурі :). Знак оклику “!” означає “не”. Булеві вирази можуть комбінуватися для створення більш складних виразів. Це можна зробити з булевими операторами. Двома основними операторами є І, який щоб повернути результат тру потребує щоб лівий І правий операнд були тру, і АБО, для якого достатньо, щоб лівий АБО правий операнд були тру. В Таблиці 1-2 описується як ви можете їх комбінувати.

    Таблиця 2 Як працюють булеві оператори

    A

    B

    A&&B (І)

    A||B (АБО)
    true

    true

    true

    true
    true

    false

    false

    true
    false

    true

    false

    true
    false

    false

    false

    false

    Наприклад нам потрібно написати функцію яка перевіряє чи дорівнює вектор нулю, не обчислюючи його довжину. Для цього достатньо написати фунцію, яка дивиться чи КОЖНА координата дорівнює нулю.

    
    class Vector2d
    {
    	// ...
    	public bool isZero()
    	{
    		return (x==0)&&(y==0)&&(z==0);
    	}
    }
    
    

    Тепер результат цієї функції можна використовувати в інших умовних операторах чи булевих виразах. Як в одному з попередніх прикладів, де ми скочатку обчислювали довжину. Правда обчислювати її все одно прийшлось, але таке життя :). Зате тепер ми не обчислюємо її марно.

    
    	// ...
    			if(isZero()) return;
    			double l=Length();
    			double scale=value/l;
    	// ...
    
    

    Використання обєкта Vector3d

    Вже давно пора було б відкрити Visual Studio і почати там щось клацати. Тим не менш, якщо ви ще навіть не встановили собі середовище, хочу вас обрадувати: Майкрософт безплатно роздає Visual Studio 2008 Express Edition, так само і пакет до неї XNA, можна безплатно стягнути з www.microsoft.com. Припустимо ви вже зкачали (чи позичили в сусіда диск), і встановили студію. З ХНою можна трохи почекати. Запускаємо її і створюємо новий консольний проект. Для цього є кнопочка десь зліва вгорі, або головне меню File – > New – > Project. Рис.4 показує вікно створення проекту в Візуал Студії, з вибраним шаблоном консольного додатку.


    Рис. 4 Створення консольного проекту в Visual Studio C# 2008

    Коли проект створено, ми маємо бачити зправа вікно яке називається Solution Explorer. Це вікно показує всі файли, які входять до вашого проекту і розв’язку. Розв’язок – це набір з кількох проектів. Кожен проект компілюється в один exe-файл. Якщо ви не бачите це вікно натисніть View -> Solution Explorer. Відкрийте Program.cs подвійним клацанням на ньому в вікні Solution Explorer. Це файл з якого насправді буде запускатись програма. В даний момент він містить єдиний метод, названий Main у класі названому Program.

    Зараз ми маємо додати в проект два файли для наших об’єктів. Це може бути зроблено кількома способами:

    • Клацання правою кнопкою по проекті і вибір Add -> New Item
    • Клацання іконки “Додати новий компонент” в панелі інструментів
    • Вибором меню Project -> Add New Item

    Ви маєте побачити діалогове вікно подібне до того що на рис.5. Виберіть Class, введіть ім’я, і виберіть Add.


    Рис. 5 Додавання до проекту нового класу в Visual Studio C# 2008

    Заповніть поля класу, використовуючи код наданий вище в цьому розділі. Такі самі дії повторіть для класу Position. За те чи знають класи один про одного (вони в різних файлах) можна не хвилюватися. Ми додали файли в проект, і всі класи в файлах знаходяться в одному просторі імен. Коли ви будете писати class Position: Vector3d, тобто що Position унаслідується від Vector3d, після вводу кількох перших літер назви класу, студія сама виведе на екран відому їй назву, яка так починається.

    Тепер, коли ми маємо два файли з двома об’єктами, ми маємо написати код, який би з цим щось робив. Знову відкрийте Program.cs і в методі Main, додайте такий код:

    
                Vector3d vector1=new Vector3d();
                System.Console.WriteLine("vector 1 created");
                System.Console.WriteLine("Coords: ({0},{1},{2})", vector1.x, vector1.y, vector1.z);
                vector1.length = 3;
                System.Console.WriteLine("Coords: ({0},{1},{2})", vector1.x, vector1.y, vector1.z);
                vector1.x = 1;
                vector1.y = 2;
                vector1.z = 3;
                vector1.length = 7;
                System.Console.WriteLine("Coords: ({0},{1},{2}) Length={3}", vector1.x, vector1.y, vector1.z,vector1.length);
    			
                System.Console.WriteLine("Press Enter to exit");
                System.Console.Read();
    

    Зауважте, що ми використали новий оператор, new, який створює зразок кожного об’єкту для нас. Ми можемо використовувати об’єкти тільки після того, як ми їх створили. Після створення об’єкту, ми можемо звертатися до його полів. Через те, що Vector3d це не Position, ми не маємо доступу до кутів Ейлера. Їх взагалі не існує. Але так як Position це Vector3d, то ми маємо через нього доступ до всіх координат.

    В попередньому прикладі можна зустріти фрагмент Console.WriteLine(…);, який викликає статичний метод об’єкту. Статичний (static) метод, або властивість не вимагають створення об’єкту для використання. Вважайте це полем, яке є єдине для всіх об’єктів класу в програмі. В цьому випадку ми використовуємо метод, для виводу тексту в вікно консолі, як показано на Рис. 6.


    Рис. 6 Вивід попереднього прикладу в консоль

    Після закінчення написання коду, виберіть Debug -> Start Without Debugging з меню, або натисніть Ctrl+F5.

    Відлагодження

    Коли ви запускаєте додаток без відлагодження (Start Without Debugging), ви кажете студії під час виконання по можливості ігнорувати помилки. Якщо помилки трапляються, студія не полізе в код, щоб допомогти вам розібратися що відбувається. Також вона проігнорує всі точки зупинки в коді.

    Точки зупинки ( давайте назвемо їх паузами), прості, як сама назва: це місце в коді, де студія зупитить виконання, і залізе в код, дозволяючи вам вручну пройти по ньому крок за кроком. Спробуйте це вставивши паузу в рядок де створюється перший об’єкт. Можна зробити це клацнувши по сірому полі зліва від текстового редактора. Має з’явитись червоний кружечок. Потім просто запустіть програму з відлагодженням, вибравши Debug -> Start Debugging, або натиснувши F5.

    Коли програма запуститься вона негайно стрибне назад до коду, і підсвітить рядок, на якому спинилась. Зараз ви відлагоджуєте код! Переміщайте курсор миші понад різними елементами коду, і ви побачите підказки, які багато чого скажуть про кожен елемент. Якщо ви наведете мишку на vector1 у рядку Vector3d vector1=new Vector3d(); ви побачите як випливе напис null. Це говорить про те що об’єкт класу ще не створений.

    У меню Debug, знайдіть гарячу клавішу для Step Over (покрокове виконання без входу в підпрограми), це напевне F10. Виберіть цей пункт меню, чи натисніть F10. Ви побачите, як код почне виконуватись рядок за рядком. Впродовж покрокового виконання ви можете наводити вказівник миші на різні об’єкти й властивості і бачити як вони змінюються.

    Масиви і цикли

    Тепер уявіть собі гру, в якій тисячі об’єктів, розташування яких задається векторами. Для зберігання всієї цієї інформації використовують масиви.

    Масив, в своїй найпростішій формі – це просто набір елементів, які зберігаються в одному місці. Ми можемо циклічно проходитись по масиві, що дозволить нам відвідати кожен елемент. Можна це зробити через стандартний цикл for:

    
                Vector3d[] vectors = new Vector3d[10];
                for (int i = 0; i < 10; i++)
                    vectors[i] = new Vector3d();
    

    Цей код створює масив з десяти векторів, циклічно проходить по кожному елементу, і створює новий обєкт.

    Кожен об’єкт в масиві має конкретний індекс, або позицію в наборі. В C# масиви мають основу нуль, що означає що в кожному масиві перший елемент має індекс нуль, і останній елемент має індекс що дорівнює довжині масиву мінус одиниця.

    Цикл for може бути поділений на три окремі елементи:

    • Ініціалізація: Встановлює початкові значення
    • Умова продовження: Надає булевий вираз, який визначає чи можна продовжувати виконання циклу.
    • Формула збільшення:Вираз, який змінює щось, так, щоб за певну скінченну кількість ітерацій умова продовження не виконалась.

    Цикли корисні кожного разу, коли нам потрібно обробити багато екземплярів одного типу. Ці об’єкти зберігаються в масивах, списках, або колекціях.

    Є кілька способів описання і використання масивів. Попередній приклад показує один з них. Також є класи, які можуть допомогти в експлутації колекцій. Два важливі класи це Queue (черга), і Stack (стек). Вони знаходяться в просторі імен System.Collections.Generic. Черга відома також під назвою “перший прийшов – перший пішов” ( first-in, first-out (FIFO)), тому об’єкт, який першим покладуть в чергу, першим і буде з неї витягнутий. Це аналогічно чергам реального життя. Стек – протилежність до черги, в ньому той хто перший прийшов піде останнім. Інша назва стеку – магазин. Це може зрозуміти той хто хоч раз заряджав автомат.

    Я тут жарт придумав. Автомат – пристрій який перетворює магазин в чергу. Жарт посередній, але який ілюстративний.

    Замість циклу for, ми можемо використовувати також цикли while або do-while. Цей підхід включає ініціалізацію лічильника циклу. Для масиву з десяти елементів лічильник циклу буде приймати значення від 0 до 9. Різниця між циклами while і do-while, полягає в порядку в якому виконуєтьтся тіло циклу і перевірка умови продовження. Продемонструю на прикладах циклів, дія яких еквівалентна попередньому прикладу з for.

    
                i = 0;
                do
                {
                    vectors[i].x=i;
                    i++;
                } while (i < vectors.Length);
                i = 0;
                while (i < vectors.Length)
                {
                    vectors[i].y = 3 - i;
                    i++;
                }
    

    Правда ці цикли використовуються не так часто як for. Одна властивість мови C# яка спрощує сворення колекцій об’єктів називається конструкція foreach. Буквально означає “для кожного”. Цей метод циклу дозволяє вибирати з колекції певні типи і використовувати їх, без потреби переживати за лічильники. Ось простий приклад:

    
    foreach (Vector3d vec in vectors)
                {
                    vec.length = 4;
                }
    

    Висновок

    Цей розділ мав на меті дати вам посмакувати можливості .NET і C#. В наступних розділах ми застосуємо ідеї обговорені тут для написання ігор. Під час читання цієї книги ключові концепції які ви прочитали тут будуть дуже важливі. На щастя, поки що більше теорії нам не потрібно, і ми можемо почати засмальцьовуватись XNA Framework. Давайте зробимо гру!

    Розділ 2

    Ввідний курс XNA

    Перед тим як почати перекладати цей розділ, хочу сказати одну річ. Мене постійно мучило одне питання: “що таке XNA?”. Ні в одній книжці по XNA, ні навіть в MSDN про це не написано. Але одного разу я таки знайшов відповідь на це питання. При чому відповідь була аналогом “на кпи”. Отже розшифрування абревіатури ХНА українською мовою, “Херня, Не Абревіатура” (“XNA No Abbreviation” мовою оригіналу). Тепер коли ми знаємо з чим працюємо можемо почати.

    Далі я не переклав, бо повернувся до OpenGL.

  • Written by bunyk

    3 Лютого, 2009 at 22:47

    Опубліковано в Кодерство

    Tagged with

    Відповідей: 4

    Subscribe to comments with RSS.

    1. Класна книжка!

      Андрій

      21 Січня, 2010 at 13:13

    2. От вчу троха Шарпу. Якось наткнувся на ОпенГлу постворював я найшпростішгі об’єкти і тд. а вот з чого почати створення гри … ну графічного двигунця не спостерігаю. Верніше такі є але в двох не підходящих мені варантах Шарпа+Діретикс або с++ ‘+’ opengl.
      Можливо підкажете мені якусь альтернативу щоб розбиралось ігробудова в опенглі з прикладами на шарпі?

      23232323

      4 Вересня, 2010 at 10:51

      • Чесно, я не знаю. C# – дітище Microsoft. Як і DirectX. От воний й стараються їх гарно подружити, забиваючи на OpenGL.

        Тому якщо хочете OpenGL – від С++ вам нікуди не подітись. Я так в школі завжди хотів мати книжку про OpenGL на Delphi. І така є (Краснов здаєтсья), але тепер розумію, що краще було б вчити C++ і мати менше головної болі.

        Розбирався з таким движком, але там DirectX: https://bunyk.wordpress.com/2009/02/06/darkgdk-lection1/

        А ще писав свій: https://bunyk.wordpress.com/2009/05/24/trimesh/

        Тільки через брак досвіду, я тоді не знав, що винаходжу велосипед. Раджу прочитати про тривимірні моделі в форматі http://uk.wikipedia.org/wiki/Obj, і завантажувати їх. Тоді можна буде написати гру зі своїм власним движком.

        Якщо я не зовсім відповів на ваше питання – питайте ще. Я так зрозумів ви хотіли перейти від рендерингу примітивів до мешів?

        bunyk

        4 Вересня, 2010 at 11:26

        • Думаю що зрозуміли)
          Мій друг почав працювати з фреймворком хни але ХНУ це все той же майкрософт,а там все завжди платно(рано чи пізно). я же тим часом підключив собі Таофрейм ворк і почав по нет гайдах Рендерингувати… але вот що робити дальше я собі просто не уявляю … та й гайди завжди обриваються на якомусь місці або пропускають декілька ходів своїх дій лишаючи юзера збитого з пантелику, який немаючи надійної основи кидає свої починання і з розчарування пробує пройти StarCraft2…
          Що Ви можете порадити ?..

          23232323

          5 Вересня, 2010 at 15:48


    Залишити коментар

    Цей сайт використовує Akismet для зменшення спаму. Дізнайтеся, як обробляються ваші дані коментарів.