Понедельник, 01 Июля 2024, 12:35

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

[ Новые сообщения · Игроделы · Правила · Поиск ]
Результаты поиска
nilremДата: Пятница, 11 Сентября 2009, 17:54 | Сообщение # 201 | Тема: Обсуждение курса "Основы С++ для начинающих..."
Просветленный разум
Сейчас нет на сайте
Тема предназначена специально для обсуждения курса Основы С++ для начинающих программистов игр. Вопросы, замечания, предложения, пожелания - все сюда.

Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 17:55 | Сообщение # 202 | Тема: Обсуждение курса "Основы С++ для начинающих..."
Просветленный разум
Сейчас нет на сайте
Лог удаленных из основной темы сообщений:

Quote (CARI)
nilrem, Спасибо, я думаю особенно это будет интересно для начинающих. Вот у меня такой вопрос я использую Borland C++ 6 но в нём не катит Quote (nilrem)setlocale( LC_ALL, "Russian" ); что бы русский текст отображало с чем это может быть связано?

Quote (Vinchensoo)
nilrem, у меня вопрос по компилятору Microsoft Visual c++ и Microsofr visual Studio одно и тоже или нет?

Quote (nilrem)
Quote (CARI)я использую Borland C++ 6 но в нём не катит setlocale( LC_ALL, "Russian" ); Я не специалист в C++ Builder, но могу предположить что он, да еще и такая древняя версия, не поддерживает локали. В таком случае нужно проводить перекодировку каждой строки текста вручную с помощью функции CharToOem(новый вариант CharToOemA, это если старый не работает). Для работы с ней необходимо подключить заголовочный файл windows.h. Пример использования: Code      char src[10];      char dest[10];      strcpy(src,"Cтрока");      CharToOem(src,dest);  // или CharToOemA(src,dest);      cout << src << "\n";      cout << dest; Quote (Vinchensoo)Microsoft Visual c++ и Microsofr visual Studio одно и тоже или нет? Если не вдаваться во всякие подробности то ответ - ДА.

Quote (Vinchensoo)
Если не вдаваться во всякие подробности то ответ - ДА. спс CARI, а какую версию билдера юзаешь?

Quote (CARI)
nilrem, Сбасибо за разъяснение Vinchensoo, вышеже написано Quote (CARI)Borland C++ 6 Шестой

Quote (CARI)
Хочу внести свою лепту (вставить свои пять копеек) ). Также что бы программа в конце не закрывалась можно подключить библиотеку conio.h и в конце перед return 0; написать getche (); Code*** #include < conio.h > int main () { ** getche (); return 0; }

Quote (CARI)
nilrem можеш скинуть ссылку Microsoft Visual Studio Team System 2008 а то ненашол эту прогу в микрософт.ру и ещё когда будет следующий урок?

Quote (break-roma)
break-roma, на торренте ищи...

Quote (break-roma)
я то нашол но он на английском,ты знаеш где есть на русском?

Quote (Dark_Falcon)
Quotenilrem можеш скинуть ссылку Microsoft Visual Studio Team System 2008 а то ненашол эту прогу в микрософт.ру http://msdn.microsoft.com/ru-ru....=18:329 http://www.microsoft.com/visualstudio/en-us/try/default.mspx Правда нужно быть зарегистрированным.

Quote (break-roma)
спаибо! ща попробуюДобавлено (06.09.2009, 20:31)---------------------------------------------а где можно скачать Microsoft Visual Studio Team System 2008 через торрент на руском?

Quote (Vinchensoo)
break-roma, ввести в поиске на www.torrents.ru. Я качал оттуда, она там есть...


Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 18:23 | Сообщение # 203 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Статья 2 : Продолжаем обучение.

Здравствуйте, уважаемые, жаждущие знаний, читатели. Прошло довольно много времени, у меня наконец то выдалась свободная минутка и я продолжаю начатое знакомство с языком программирования С++. Надеюсь что вы не теряли времени даром, поскольку делать столь длительные перерывы в обучении не то что не желательно, а даже вредно. Есть такое крылатое выражение – «Учится, все равно, что грести против течения, только перестанешь и тебя гонит назад». Поскольку писать уроки в спринтерском темпе у меня вряд ли получится, дабы исключить такие длительные перерывы и утолить жажду знаний, советую найти где-нибудь книгу по программированию. Могу посоветовать «С++ для чайников», брать что либо серьезнее не рекомендую, поскольку могут возникнуть проблемы с пониманием материала, вследствие чего вы оставите книгу пылится где-то на полке и плюнете на саму мысль об обучении С++. Все таки это не самый легкий для изучения язык.
Ладно, хватит пудрить мозги, пора грести против течения.

1. Совершенствуем «Осаду»

Созданная на прошлом уроке игра работала не совсем корректно. Кроме того что все расчеты в ней очень примитивные, она еще и предлагала игроку самому решать выиграл он или проиграл. Сейчас мы будем это исправлять. Конечно, для этого нам необходимо освоить новый материал. Как я уже говорил на прошлом уроке, нужно ставить перед собой конкретные задачи.
На данный момент это:
1. Проверить, остались ли у замка защитники.
2. В зависимости от полученного результата, вывести соответствующее сообщение.

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

Логические операторы и операторы сравнения

Помните что такое логический тип данных. Это такая вещь, которая может иметь только два значения истина или ложь(true или false, ведь на русском компилятор не понимает).
Логический оператор помещается между двумя аргументами(переменными), и в результате совершения определенных действий над ними возвращает логическое значение.

Вот перечень логических операторов:

! – оператор НЕ. Он применяется всего к одной переменной, изменяя ее логическое значение на противоположное.
Пример:
!true возвратит false
!false возвратит true
(заметьте, после восклицательного знака пробела нет )

&& - оператор И. Возвращает true если оба аргумента истинны. В любом другом случае возвращает ложь.
Пример:
true && true возвратит true
true && false возвратит false
false && false возвратит false

|| - оператор ИЛИ. Возвращает true если один из аргументов истина.
Пример:
true || true возвратит true
true || false возвратит true
false || false возвратит false

Откуда берутся приведенные в примерах true и false. Чаще всего они появляются в результате работы логических операторов, которые также являются операторами сравнения.

> - оператор больше. Возвращает true если значение левого аргумента больше чем у правого.
Пример:
10 > 5 возвратит true
10 > 10 возвратит false
10 > 15 возвратит false

>= - оператор больше или равно. Возвращает true если значение левого аргумента больше или равно правому.
Пример:
10 >= 5 возвратит true
10 >= 10 возвратит true
10 >= 15 возвратит false

< - оператор меньше. Возвращает true если значение левого аргумента меньше чем у правого.
Пример:
10 < 5 возвратит false
10 < 10 возвратит false
10 < 15 возвратит true

<= - оператор меньше или равно. Возвращает true если значение левого аргумента меньше или равно правому.
Пример:
10 <= 5 возвратит false
10 <= 10 возвратит true
10 <= 15 возвратит true

== - оператор равно. Возвращает true если значение левого аргумента равно правому. Важно не путать с арифметическим оператором присваивания =. Эта ошибка очень часто встречается у начинающих, и не только, программистов. Компилятор на нее никак не реагирует, в следствии чего возникает много неприятностей, поэтому необходимо быть внимательным.
Пример:
10 == 5 возвратит false
10 == 10 возвратит true
10 = 10 ничего не возвратит, так как это оператор присваивания.

!= - оператор не равно. Возвращает true если значение левого аргумента не равно правому.
Пример:
10 != 5 возвратит true
10 != 10 возвратит false

Как и в случае с арифметическими операторами, логические также имеют приоритет.
Как это ни странно, наивысший приоритет имеет !. Далее идут операторы сравнения, они изложены попарно в порядке снижения приоритета. За ними идут && и ||. Операторы с одинаковым приоритетом выполняются слева направо. Не буду приводить вам никаких примеров с приоритетами, кто захочет - разберется сам, а кто не захочет – будет пользоваться скобками.
Теперь я приведу вам один интересный пример. Компилятор С++ допускает такое выражение:

Code

10 < 7 < 5

Как вы думаете, что будет возвращено после вычисления этого выражения?
Если смотреть с точки зрения математики, то это выражение должно быть ложным. Но мы будем рассматривать его с точки зрения логики программирования.
Начнем разбор. В соответствии с одинаковыми приоритетами сначала будут сравниваться 10 и 7, а затем их результат будет сравнен с цифрой 5. В результате первой операции будет получено значение false, поэтому выражение примет такой вид:

Code

false  < 5

Как же нам теперь сравнить логическое значение с числовым. Помните, я при знакомстве с типами данных упоминал, что если значение есть то это true, а если его нет, то это false. Учитывая это наше выражение примет такой вид:

Code

false < true

Теперь вы должны запомнить, согласно здравой логики наличие значения(конечно, если это не ноль) всегда больше чем его отсутствие, то есть true больше чем false, поэтому наше выражение истинно и оператор сравнения возвратит true. Вот так то.
Кстати, я нигде не видел использования приведенного выше трио, так что все рассуждения приведены здесь в общеобразовательных целях. Если вы в них ничего не поняли, то это не страшно.

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

Операторы ветвления, выбора и условный оператор.

Операторами выбора называются операторы, которые в результате проверки определенных условий выбирают какое действие, будет выполнятся дальше.
Существует два вида операторов выбора: пара if else и switch.

if else

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

Code

if (условие)
{
   Блок кода  
}

Работает оператор так. Сначала проверяется условие, если оно истинно то выполняется Блок кода. Если условие ложно, то код пропускается.
Если в блоке кода находится всего одна строка, то фигурные скобки можно не ставить. Пример:

Code

if (условие)
       Блок кода  

Если, как и в нашем случае, необходимо проверить несколько значений, то используется несколько операторов if

Code

if (условие)
{
   Блок кода  
}
if (условие)
{
   Блок кода  
}
if (условие)
{
   Блок кода  
}

Но в этом случае все последующие условия будут проверяться даже если какое-то из предыдущих оказалось истинным. Чтобы избежать это используется полный вариант оператора ветвления. Вот его синтаксис:

Code

if (условие)
{
   Блок кода  
}
else  
{  
   Блок кода  
}


В этом случае Блок кода после else будет выполнен, только если условие ложно.
Поэтому если сделать так:

Code

if (условие)
{
   Блок кода  
}
else  
{  
if (условие)
{
   Блок кода  
}
if (условие)
{
   Блок кода  
}
}

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

Code

if (условие)  // первый оператор
{
   Блок кода первого оператора
}
else  
{  
if (условие)    //второй
{
   Блок кода второго
}
else
{
if (условие)    //третий
{
    Блок кода третьего
}
}
}

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

Code

  if(a==5)
   cout<<"Введенное число равно пяти";
  else
  {
   if(a>5)
    cout<<"Введенное число больше пяти";
   else
   {
    if(a<5)
     cout<<"Введенное число меньше пяти";
   }
}


Пройдемся по примеру. Допустим, что переменная а это некоторое введенное пользователем значение от 0 до 10. Сначала проверяется условие первого оператора. Если а равно 5 то оно истинно и выполняется блок кода первого оператора, выводится сообщение "Введенное число равно пяти". Если условие ложно, допустим что это 3, то срабатывает оператор else и проверяется условие второго оператора if(a>5). Поскольку и это выражение оказывается ложным, программа переходит к третьему условию if(a<5), которое является истинным, в результате чего появляется сообщение "Введенное число меньше пяти", что и соответствует действительности.

switch

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

Code

if(a==0)
cout<<"Введенное число равно 0";
else
{
  if(a==1)
   cout<<"Введенное число равно 1 ";
  else
  {
   if(a==2)
    cout<<"Введенное число равно 2 ";
   else
   {
    if(a==3)
     cout<<"Введенное число равно 3 ";
    else
    {
     if(a==4)
      cout<<"Введенное число равно 4 ";
     else
     {
      if(a==5)
       cout<<"Введенное число равно 5 ";
      else
      {
       if(a==6)
        cout<<"Введенное число равно 6 ";
       else
       {
        if(a==7)
         cout<<"Введенное число равно 7 ";
        else
        {
         if(a==8)
          cout<<"Введенное число равно 8 ";
         else
         {
          if(a==9)
                              cout<<"Введенное число равно 9 ";
          else
          {
                              if(a==10)
                              cout<<"Введенное число равно 10 ";
          }
         }
        }
       }
      }
     }
    }
   }
  }
}


Ужас, правда. Для упрощения обработки таких вот однотипных условий, когда проверяются различные варианты одной переменной, используется оператор выбора – switch.
Вот так будет выглядеть предыдущий пример с использованием оператора switch:

Code

switch (a)
{
case 0: cout<<"Введенное число равно 0"; break;
case 1: cout<<"Введенное число равно 1"; break;
case 2: cout<<"Введенное число равно 2"; break;
case 3: cout<<"Введенное число равно 3"; break;
case 4: cout<<"Введенное число равно 4"; break;
case 5: cout<<"Введенное число равно 5"; break;
case 6: cout<<"Введенное число равно 6"; break;
case 7: cout<<"Введенное число равно 7"; break;
case 8: cout<<"Введенное число равно 8"; break;
case 9: cout<<"Введенное число равно 9"; break;
case 10: cout<<"Введенное число равно 10"; break;
}

Разницу чувствуете)

Вот его синтаксис:

Code

switch (Переменная)
{
case Значение 1: Блок кода; break;
case Значение 2:
Блок кода;
break;

default:
Блок кода;  
}


Оператор switch поочередно сравнивает переданное ему значение Переменной со стоящим после оператора case значением. Если оно идентично, то выполняется соответствующий блок кода. После чего срабатывает оператор break, который прекращает работу оператора выбора. Если случайно забыть поставить break, то программа продолжит сравнивать значения, даром тратя время.
Если необходимое значение не найдено, то выполняется блок кода заданный по умолчанию, то есть стоящий после оператора default. Кстати, если значение по умолчанию не нужно, то default можно и не задавать.
Есть еще одна особенность оператора выбора, связанная с использованием оператора break. Допустим, что вам необходимо чтобы в двух или больше ситуациях был выполнен один блок кода. В этом случае используется такой синтаксис:
Code

switch (Переменная)
{
case Значение 1:  
case Значение 2: Блок кода; break;
}


Здесь после первого значения отсутствует break, а это означает что
Code

Блок кода; break;

Будут выполнены для обоих значений.

Условный оператор

Ну и напоследок говоря об операторах ветвления нельзя не упомянуть условный оператор - ?:. По сути это сокращенная запись того же if else.
Вот его синтаксис:

Code

(Условие) ? Выражение 1 : Выражение 2

Ключевыми в приведенной выше строке есть вопросительный знак и двоеточие. А работает оператор так. Сначала вычисляется условие, если оно истинно то срабатывает выражение 1, если условие ложно, то выполняется выражение 2.
Особенностью условного оператора есть то, что выражения должно быть коротким, и весь оператор не должен разбиваться на несколько строк. При этом, в отличии от предыдущих операторов ветвления, условный оператор можно применять в самых неожиданных местах внутри кода. При необходимости я это продемонстрирую, а сейчас просто приведу небольшой пример.

Code

X = (I  > 5) ? 20 : 40;  

Если I больше 5, то Х будет присвоено 20, во всех остальных случаях 40.
Вот так бы выглядел этот пример с использованием if.

Code

if(I  > 5)
{
  X =20;
}
else
{
  X =40;
}

Теперь, на конец хотелось бы сделать небольшое пояснение относительно терминологии. Я использовал три термина: оператор ветвления для if else, оператор выбора для switch и условный оператор для ?:. Так вот, в разной литературе любым из этих терминов может называться любой из перечисленный операторов. Вот такое дело. Я так и не смог определится, кому принадлежит конкретный термин. Далее по тексту я буду использовать приведенные названия применительно к каждому конкретному оператору.
На этом знакомство с операторами ветвления закончено. Теперь мы можем внести изменения в нашу первую игру.

Корректируем «Осаду».
Открываем в студии проект с игрой осада и переходим к исходному коду. Как это сделать вы должны уже знать с первого урока. Находим там такие строки:

Code

  // Вывод результата вместе с условиями выиграша
  cout << "У противника осталось " << Draco << " Драконов,"
   << Golem << " Големов, "<< Arrows << " Лучников, "<< Peasant <<  
   " Крестьян\n." << "Если войска остались - ВЫ ПРОИГРАЛИ";


Именно здесь нам необходимо внести соответствующие изменения, чтобы победителя выбрала программа. Делается это следующим образом. Удаляем из предыдущей строки

Code

<< "Если войска остались - ВЫ ПРОИГРАЛИ"

Поставив вместо нее изученный оператор ветвления.

Code

if(Draco==0&&Golem==0&&Arrows==0&&Peasant==0)    // проверка результата боя
  {
   cout << "ВЫ ОДЕРЖАЛИ ДОБЛЕСНУЮ ПОБЕДУ";  
  }
  else
  {
   cout << "ВЫ ПОЛУЧИЛИ СОКРУШИТЕЛЬНОЕ ПОРАЖЕНИЕ";
  }


Как мы видим здесь, в первой строчке выполняется проверка равно ли количество оставшихся войск нолю. Делается это с помощью операторов сравнения и логического оператора И. Напомню, что согласно приоритета сразу проверяется равенство, а после начинает свою работу оператор &&. Если условие истинно, то выводится сообщение о победе, а если ложно – о поражении.
Теперь вы можете откомпилировать измененную программу и, если вы не допустили ошибки, программа заработает и в конце вам будет конкретно указано победили вы или проиграли.
Вот код всей программы:

Code

#include <iostream>
using namespace std;

int main( void )  // главная функция программы
{      
  setlocale( LC_ALL, "Russian" ); // задействование русского языка
   
  int Draco=2;    // переменная для Дракона
  int Golem=4;    // голем
  int Arrows=3;    // лучник
  int Peasant=1;    // крестьянин
  int i=0;  // переменная для хранения введенного игроком числа

  // Вывод вступительного текста
  cout << "После долгого, долгого перехода вы наконец-то добрались к окресностям форта,\n";
  cout << "который приказом короля вам велено захватить.\n";
  cout << "Но, как выяснилось, форт хорошо охраняется:\n\n";
  cout << "Южные ворота охраняет Дракон.\n";
  cout << "Северную стену - Голем.\n";
  cout << "На восточной расположились лучники,\n" ;
  cout << "а на западной - крестьяне.\n\n";
  cout << "Ваша армия состоит из\n";
  cout << "1. Асасинов\n";
  cout << "2. Магов\n";
  cout << "3. Латников\n";
  cout << "4. Катапульты\n\n";
  cout << "(Для выбора вариант ответа вводите соответствующий номер и нажимаете ENTER.\n";
  cout << "Выбрать войска можно только один раз.)\n\n";
  cout << "Кого вы отправите против Дракона?\n";
  cin >> i;    // получение данных от игрока
  Draco = Draco - i;  // вычисление результата для Дракона
  cout << "Кого вы отправите против Голема?\n";
  cin >> i;    // получение данных от игрока
  Golem = Golem - i;  // вычисление результата для Голема
  cout << "Кого вы отправите против лучников?\n";
  cin >> i;    // получение данных от игрока
  Arrows = Arrows - i;    // вычисление результата для Лучников
  cout << "Кого вы отправите против крестьян?\n";
  cin >> i;    // получение данных от игрока
  Peasant = Peasant - i;    // вычисление результата для Крестьян

  // Вывод результата вместе с условиями выиграша
  cout << "У противника осталось " << Draco << " Драконов,"
   << Golem << " Големов, "<< Arrows << " Лучников, "<< Peasant <<  
   " Крестьян\n\n";

  if(Draco==0&&Golem==0&&Arrows==0&&Peasant==0)    // проверка результата боя
  {
   cout << "ВЫ ОДЕРЖАЛИ ДОБЛЕСНУЮ ПОБЕДУ";  
  }
  else
  {
   cout << "ВЫ ПОЛУЧИЛИ СОКРУШИТЕЛЬНОЕ ПОРАЖЕНИЕ";
  }

  cin.get();    // ожидание нажатия клавиши
  cin.get();    // ожидание нажатия клавиши
  return 0;    // возвращение значения, и завершение программы
}



Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 19:00 | Сообщение # 204 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
2. Оформление кода

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

Отступы
Итак начнем. Первое очень нам нужно узнать, и на что вы уже возможно обратили внимание, это отступы. Вот несколько рекомендаций:
Отступы в строках необходимо располагать так, чтобы логически связанные блоки кода выглядели единой группой.
Между этими группами можно оставлять пустую строку. Кроме того эту группу можно выделить, заключив ее в фигурные скобки.
При этом открывающую и закрывающую скобку нужно располагать в отдельных строках и на одной линии по вертикали, то есть друг под другом.
Все вложенные блоки кода, например в операторе ветвления необходимо писать с отступом, при этом, на каждый новый уровень вложения нужно добавляться новый отступ.
Все, что я здесь описал вы могли видеть в приведенных ранее примерах кода. Кроме того Среда разработки будет вам в этом всячески помогать. Главное при этом ей не мешать.

Комментарии
О комментария мы уже говорили, но хотелось бы дать еще несколько советов:
Самое важное – комментарий должен быть наиболее содержательным, чтобы и через неделю и через год вы смогли понять что он означает и разобраться в коде.
Избегайте избыточного комментирования, используйте их только если это действительно нужно.
Например:

Code

a=5;    // присвоение переменной а значения 5

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

Именование переменных
Ну и поговорим немного об именах переменных. О том, какие они должны быть, я уже рассказывал. Теперь я поведаю о касающемся этой темы стандарте, получившей название Венгерская нотация. Многое в ней вам будет еще не понятно, но я не решился разбивать ее на части. Да к тому же пользоваться этим соглашением или нет, решать вам. Я так и не смог себя приучить к некоторым положениям этой нотации.

Вот текст документа:


Соглашение об идентификаторах в программе.
Данный документ предназначен для изложения основных достоинств о формальном формировании идентификаторов.
При введении нового идентификатора в программу, хороший программист учитывает следующие факторы:
1. мнемоническое значение: идентификатор должен легко запоминаться
2. смысловое значение: роль идентификатора должна быть ясна из его названия
3. преемственность: часто рассматривается как чисто эстетическая идея, но все же, похожие объекты должны иметь похожие идентификаторы.
4. скорость решения: придумывание, ввод и редактирование идентификатора не должны занимать слишком много времени, идентификатор не должен быть слишком длинным.
Выбор имен может стать задачей, поглощающей лишнее время у разработчика. Часто идентификатор, удовлетворяющий одним условиям противоречит другим. Кроме того, поддержать преемственность имен иногда бывает достаточно трудно.
Преимущества Соглашений
Данные соглашения об идентификаторах обеспечивают удобную технологию для формирования имен, удовлетворяющих вышеупомянутым критериям. Основной идеей является передача основных характеристик идентификатора как части в его названии. Эта простая идея, безусловно, требует уточнения (что, например, предполагается под "критерием", что делать если они(критерии) не уникальны?). Однако, давайте сначала оговорим общие положения.
Названия будут мнемоническими в строго определенном смысле: идентификатор будет очевиден для того, кто помнит название характеристики или принцип его построения.
Названия имеют смысловое значение: должна быть возможность отобразить любое название в наборе характеристик.
Названия будут непротиворечивы, так как произведены теми же самыми правилами.
Построение названий будет производится механически, следовательно быстро.
Выражения в программе могут быть проверены на преемственность методами, похожими на обычные измерения свойств объекта.
Правила обозначения
Предлагаются следующие правила обозначения:
1) Описание характеристики идентификатора входит в идентификатор. Удобной пунктуацией является указание характеристики перед названием, с разделением их (началом названия с большой буквы в Cи, например: rowFirst: row - характеристика, Fist - название).
2) Название отличают идентификаторы, имеющие один и тот же тип и существующие в одном контексте. Контекстом может являться как система в целом, так и блок, процедура, структура данных в зависимости от среды программирования. Если существует стандартное название, оно должно быть использовано. Выбор должен быть максимально простым, так как требуется уникальность идентификатора только в пределах определенного контекста.
3) Простые типы названы короткими тегами, которые выбраны программистом. Такие теги должны быть интуитивно понятны большинству программистов.
Тег должен быть коротким для выполнения четвертого условия (фактора), введенного нами выше. Названия составных типов должны включать имена составляющих. Существуют стандартные схемы построения указателя и массива. Другие типы данных могут быть определены произвольно. Например префикс p используется для указателей. В принципе, соглашения могут быть обогащены в соответствии с новыми схемами типов данных. Однако стандартные конструкции могут послужить еще долгое время. Следует отметить что поля структур не должны участвовать в формировании префикса, так как в этом случае конструкции более чем с двумя полями были бы просто не читаемыми. Более важна передача в префиксе для структуры ее сути, зависимой не от набора полей, а от способа ее использования.
Я рекомендую использование нового тега для каждой новой структуры данных. Тег с некоторой пунктуацией (первая или все заглавные буквы) тоже может и должен использоваться как имя типа для структуры. Использование новых тегов так же оправдано в тех случаях, когда это влияет на удобочитаемость программы.
Мой опыт показывает, что теги более трудны для выбора по сравнению с названиями. Когда необходим новый тег, первым желанием бывает использовать короткий, наглядный, общий и универсальный термин как имя типа. Это - почти всегда ошибка. Нельзя резервировать наиболее полезные термины и фразы для частных целей конкретной задачи или даже версии. Как правило любой универсальный термин одинаково применим ко многим типам, даже в той же самой программе.
Обратите внимание, что, как правило, очевидный выбор для названия, является и самым правильным. Причиной этому является то, что название должно быть уникально в рамках значительно меньшего по сравнению с тегом контекста. Так как названия, как правило, не участвуют в формировании других названий, им не требуется быть особенно короткими.
Например мы создаем графическую программу. В данном случае у нас существует тип данных "цвет". Естественным желанием является сделать префикс color для обозначения цвета. Однако при детальном рассмотрении может оказаться, что применение термина color более удобно в приложении к названию, например: LineColor. Для обозначения цвета более выгодным является сокращение, например clr. clrDefault.
Обозначение для упрощения написания.
Правильное формирование идентификаторов должно позволить нескольким программистам независимо создавать программу для решения одной задачи. Каждый программист должен знать правила именования, иначе будет невозможно организовать взаимодействие. Такой эксперимент бесполезен при рассмотрении крупного проекта, однако представляет из себя четкую цель. Результатом является возможность понимать и исправлять программу, написанную другим человеком. Такой результат достижим при надлежащем использовании общеопределенных соглашений. Именно поэтому процесс документирования тегов крайне важен.
Обозначение для процедур.
К сожалению, простое понятие квалифицированных напечатанных тэгов не работает для названий процедуры. Некоторые процедуры не получают параметров или не возвращают значения. Контексты названий процедур имеют тенденцию быть большими. Следующий набор специальных правил для процедур может работать весьма удовлетворительно:
1) Названия процедур должны отличаться от других названий пунктуацией, например, всегда начинаясь с заглавной буквы (тогда как тэги характеристик других идентификаторов пишутся строчными буквами).
2) Начинайте название процедуры с тега типа возвращаемого значения, если таковое существует.
3) Выразите действие процедуры в одном или двух словах. Слова должны быть разделены пунктуацией для более простого разбора читателем (обычный метод заключается в использовании заглавных инициалов для каждого слова).
4) В конец названия можно добавить список тегов некоторых или всех формальных параметров, если есть смысл.
Последний пункт противоречит более ранним замечаниям по описанию структуры данных. Если параметры процедуры будут изменены, то это повлечет за собой изменение имени и всех точек вызова процедуры. Однако такое изменение может быть использовано для проверки того, что все точки вызова измененной процедуры будут также выполнены корректно. В случае же со структурами данных, добавление или изменение поля не оказывает решающего влияния на использование типа данных. В случае если процедура имеет один или два параметра использование тегов упростит выбор имени.
1. Некоторые примеры для названий процедуры
Описание Название
InitSy Берет sy как его параметр и инициализирует его.
OpenFn fn - параметр. Процедура "откроет" fn. Никакое значение не будет возвращено.
FcFromBnRn Возвращает fc, для переданной пары Bn,Rn (Названия не передают нам информации о типе данных для Fc, Rn, Bn).
Далее приведен список стандартных конструкций, X и Y замещают произвольные теги.

2. Стандартные конструкции типа
pX Указатель на X.
dX Различие между двумя образцами типа X. X + dX имеет тип X.
cX Индекс образцов типа X.
mpXY Массив Ys, индексированного по X.
rgX Массив Xs.
iX Индекс массива rgX.
grpX Группа Xs, сохраненных последовательно. Используется когда X элементы имеют переменный размер и не применима стандартная индексация. Элементы X индексируются способом, отличным от обычного.
bX относительное смещение к типу X. Используется для обращений к полям переменной длины в структурах. Смещение может быть указано в байтах или словах, в зависимости от вида индексации.
cbX Размер X в байтах.
cwX Размер X в словах.
C конструкциями такого типа существует одна проблема. Например, является ли pfc собственно тегом или это указатель на fc. Ответ на такой вопрос может дать только человек, знакомый с принятой в рамках контекста системой именования.
Далее приведены стандартные имена. X замещает любой тег типа, записанный в нижнем регистре.

3. Стандартные спецификаторы
XFirst первый элемент в упорядоченном наборе X
XLast последний элемент в упорядоченном наборе X
XLim строгий верхний предел набора значений X. Границей цикла должно быть X < XLim.
XMax строгий верхний предел набора значений X. Если X начинается с 0, то XMax равен числу различных значений X.
XT временное значение X.

4. Некоторые базовые типы
f Флажок (Булева переменная, логическое значение). Используемое название должно относиться к истинному состоянию. Исключение: константы fTrue и fFalse.
w Машинное слово
ch Символ, обычно в тексте ASCII.
b Байт
sz Указатель на строку терминированную нулем (ASCIZ)

5. Базовые префиксы типов данных Win32
g_ префикс для глобальной переменной
m_ префикс для переменной класса
c константа (префикс для типа) const
l длинный (префикс для типа) far, long
p указатель (префикс для типа) *
ch char char
b байт BYTE, unsinged char
w 16-битное слово (2 байта) WORD, unsigned short
dw 32-битное слово (4 байта) DWORD, unsigned long
n,i целое int
flt с плавающей точкой float
dbl с плавающей точкой double
f логическое BOOL
sz ASCIZ строка char[]
psz ASCIZ строка char *
pcsz константа ASCIZ строка const char *
pv произвольный указатель void *
ppv указатель на произвольный указатель void **
h хендл HANDLE, void *
unk OLE объект IUnknown
punk указатель на OLE объект IUnknown *
disp Automation объект IDispatch
pdisp указатель на Automation объект IDispatch *


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

3. Игра «Лабиринт»

Как всегда, начинаем с планирования.

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

Как это будет реализовано.
Реализовано это, как и в прошлый раз, будет в виде диалога. Программа сначала выводит небольшое сюжетное введение, а затем последовательно запрашивает у вас данные. Лабиринт разбит на сектора, каждая из которых имеет свой номер. Поскольку нумерация по горизонтали и вертикали одинакова, программа сначала спрашивает направление движения(по горизонтали или по вертикали), а затем номер сектора. От выбора будет зависеть продолжение игры или проигрыш. В случае продолжения лабиринт обновляется, указывая на новую позицию игрока. При выводе текста должны быть подсказки по управлению программой.

Что для этого понадобится.
Вот тут я вас обрадую. Все что нужно вы уже знаете. Поэтому вам понадобится только терпение, сообразительность и внимание поскольку программа содержит свыше 400 строк кода. Правда 50 строк, в небольшой вариации, повторяются шесть раз.

Приступаем. Вспоминаем первый урок, открываем студию и создаем новый проект, который я назвал labyrinth. Затем добавляем в него файл исходного кода и начинаем писать программу.
Для этого может скопировать исходный код из нашей игры «Осада», и удалить оттуда, из главной функции main все, кроме строчки

Code

setlocale( LC_ALL, "Russian" );

Она нам еще понадобится.
Далее объявляем четыре переменные:

Code

  int i;    // переменная для направления
  int num;    // номер сектора
  bool GameOver = false;    // эта переменная сигнализирует о проигрыше.
  int goRes;    // вариант проигрыша


Первые две используются для получения данных при вводе. Вторая, логическая переменная GameOver, меняет свое значение в случае возникновения проигрышной ситуации. Переменной сразу же присваивается значение. В принципе в данном случае этого можно и не делать, поскольку при его отсутствии, переменная все равно считается ложной. Как только она становится истинной весь дальнейший код начинает игнорироваться.
В переменной goRes будет содержатся информация о способе проигрыша. Может он произошел в результате введения некорректных данных, может вы попали в ловушку и т.д.
После переменных выводится небольшое сюжетное введение, дается пояснение по управлению программой и выводится план лабиринта. Я не буду это здесь иллюстрировать, можете посмотреть дальше в коде всей программы.
Перемещение по лабиринту происходит в виде последовательных шагов. Далее в коде идет основная конструкция нашей программы, в которой производится обработка каждого шага:

Code

// Шаг № 1
if(!GameOver)
{
// Ввод информации о перемещении
cout << "Как вы будете двигаться, по горизонтали[Введите 1] или по вертикали[2]?\n";
cin >> i;
cout << "Укажите номер сектора, куда вы желаете переместится?\n";
cin >> num;

  if(i == 1)   //Если движение по горизонтали
  {
   switch(num)  //обработка номера сектора
   {
   case 1:
    goRes = 6;
    GameOver = true;
    break;
   case 2:  
   case 3:  
    goRes = 4;
    GameOver = true;
    break;
   default:  // значение по умолчанию, если введено некорректное значение
    goRes = 2;
    GameOver = true;
   }
  }
  else  
  {
   if(i == 2)   //Если движение по вертикали
   {
    switch(num)  //обработка номера сектора
    {
    case 1:  
    case 3:  
     goRes = 5;
     GameOver = true;
     break;
    case 2:  
     cout << "\nВы благополучно продвинулись вперед по подземелью\n";
     cout << "  ____ \n";
     cout << "3|   | |\n";
     cout << "2|0|___|\n";
     cout << "1|_____|\n";
     cout << "  1 2 3\n";
     break;
    default:   // значение по умолчанию, если введено некорректное значение
     goRes = 2;
     GameOver = true;
    }
   }
   else   // если введено некорректное значение
   {
    goRes = 1;
    GameOver = true;
   }
  }
}


В самом начале находится оператор ветвления, который проверяет состояние переменной GameOver.

Code

if(!GameOver)

Дальнейший код мог бы исполняться, только если условие истинно. Тогда как переменная GameOver ложная. Поставленный логический оператор !(НЕ) и превращает ложь в правду.
Вообще-то в первом шаге эта проверка не нужна, но чтобы в дальнейшем иметь возможность просто скопировать эти строки дальше, я и поставил его с самого начала. Ведь правильной работе он не мешает.
После проверки, происходит ввод информации и присвоение ее соответствующим переменным. Далее с помощью все того же оператора ветвления происходит проверка первой переменной – i для направления движения, и выполняется соответствующий блок кода для конкретной сектора. Эта проверка построена по уже знакомому принципу, последующая проверка производится только если первое условие ложное. Также обрабатывается и вариант, когда оба условия не правильные, то есть если введено некорректное значение.
Проверка сектора производится с помощью оператора switch.

Code

   switch(num)  //обработка номера сектора
   {
   case 1:
    goRes = 6;
    GameOver = true;
    break;
   case 2:  
   case 3:  
    goRes = 4;
    GameOver = true;
    break;
   default:  // значение по умолчанию, если введено некорректное значение
    goRes = 2;
    GameOver = true;
   }

В зависимости от введенного номера и текущей ситуации, то есть положения в лабиринте, в операторе case происходят действия определения проигрыша. Если эта проигрышная ситуация возникает то переменной GameOver присваивается значение true, а переменной goRes значение варианта проигрыша. А если введенные данные некорректные, то в этом случае срабатывает вариант по умолчанию.
И только один вариант должен быть правильным. В этом случае программа выводит подтверждение о правильности хода, и обновленный план лабиринта с изменившейся позицией игрока:

Code

    case 2:  
     cout << "\nВы благополучно продвинулись вперед по подземелью\n";
     cout << "  ____ \n";
     cout << "3|   | |\n";
     cout << "2|0|___|\n";
     cout << "1|_____|\n";
     cout << "  1 2 3\n";
     break;


С кодом одного шага разобрались, теперь необходимо его размножить и внести изменения, соответствующие правильному движению по лабиринту. У меня это шесть шагов.
После совершения всех шагов находится код вывода результата:

Code
    if(GameOver)
  {
   switch (goRes)
   {
   case 1:
    cout << "\nВы выбрали иное направление, и попытались проломить головой пол,\n"
      << "если бы у вас были мозги, то они бы растеклись по полу\n";
    break;
   case 2:
    cout << "\nБлин, вы цифры знаете, или со зрением проблемы.\n"
      << "Вобщем, вы достали из ножен свой топор и им застрелились.\n";
    break;
   case 3:
    cout << "\nВы сделали неосторожный шаг назад \n"
      << "и свалились в бездонную пропасть.\n";
    break;
   case 4:
    cout << "\nВы попали в ловушку\n"
      << "Расколов каменный пол, стальные колья пронзили ваши тела\n";
    break;
   case 5:
    cout << "\nВы попали в ловушку\n"
      << "Зловонная жижа заполнила коридор. Вы захлебнулись\n";
    break;
   case 6:
    cout << "\nВы попали в ловушку\n"
      << "Стены подземелья сомкнулись, растерев вас в пыль\n";
    break;
   }

   cout << "\nВ темных закоулках страшного подземелья вас подстерегла смерть.\n"
    << "ВЫ ПРОИГРАЛИ!\n";
  }
  else
  {
   cout << "\nНу вот и свет в конце тонеля. Вы вышли из лабиринта. Поздравляю.\n"
    << "ПОБЕДА!\n";
  }


Здесь вновь проверяется переменная GameOver. Но на этот раз в ее настоящем значении, без логического оператора.

Code
if(GameOver)

Если ее значение – истина, то это означает, что в игре возникла ситуация, когда игрок проиграл. Поэтому дальше производится проверка переменной и вывод соответствующего ей значения.

Code

   switch (goRes)
   {
   case 1:
    cout << "\nВы выбрали иное направление, и попытались проломить головой пол,\n"
      << "если бы у вас были мозги, то они бы растеклись по полу\n";
    break;
   case 2:
    cout << "\nБлин, вы цифры знаете, или со зрением проблемы.\n"
      << "Вобщем, вы достали из ножен свой топор и им застрелились.\n";
    break;
   case 3:
    cout << "\nВы сделали неосторожный шаг назад \n"
      << "и свалились в бездонную пропасть.\n";
    break;
   case 4:
    cout << "\nВы попали в ловушку\n"
      << "Расколов каменный пол, стальные колья пронзили ваши тела\n";
    break;
   case 5:
    cout << "\nВы попали в ловушку\n"
      << "Зловонная жижа заполнила коридор. Вы захлебнулись\n";
    break;
   case 6:
    cout << "\nВы попали в ловушку\n"
      << "Стены подземелья сомкнулись, растерев вас в пыль\n";
    break;
   }

Конечно, можно было сделать вывод этих сообщений в том месте кода, где мы присваивали переменной goRes значение. Но в таком случае размер программы стал бы значительно больше, контролировать ее стало бы труднее. Да и появись в тексте сообщения ошибка, ее бы пришлось править везде, а так только в одном месте.
После вывода это сообщения программа выводит еще одно, финальное:

Code

   cout << "\nВ темных закоулках страшного подземелья вас подстерегла смерть.\n"
    << "ВЫ ПРОИГРАЛИ!\n";


Это в случае проигрыша. А если вы выиграли то:

Code

  else
  {
   cout << "\nНу вот и свет в конце тонеля. Вы вышли из лабиринта. Поздравляю.\n"
    << "ПОБЕДА!\n";
  }


Ну а завершают нашу программу уже знакомые:

Code

  cin.get();    // ожидание нажатия клавиши
  cin.get();    // ожидание нажатия клавиши
  return 0;    // возвращение значения, и завершение программы



Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 19:05 | Сообщение # 205 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
4. Послесловие

Еще один урок позади. С практической точки зрения он был намного сложнее. Но я надеюсь, что у вас все получилось. А если возникли какие-то проблемы – обращайтесь, спрашивайте. Я всегда готов помочь. Но напоминаю, вопросы задавать только в рамках этого курса.
К этой лекции прикреплены файлы проектов с обеими играми: модифицированной «Осадой» и «Лабиринтом». Но я бы порекомендовал вам набрать все самостоятельно. Конечно, объем кода в лабиринте для начинающего может показаться огромным. Но ведь чем больше практики, тем быстрее прогресс. Страуструп, автор языка С++, говорил что программист хорошо изучит только те аспекты языка программирования, которые чаще всего использует. Ну это и так понятно.
Кроме того, возможно, что на форуме программистов не очень много, тогда как на получившиеся игры наверное хотели бы посмотреть все.

Поэтому выкладываю ссылки на екзешники:
Осадаhttp://fabermun.at.ua/cpp/siege.rar
Лабиринт - http://fabermun.at.ua/cpp/labyrinth.rar
На этом все.
До встречи.

Прикрепления: SiegeLabyrinth_.rar (11.5 Kb)


Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 19:11 | Сообщение # 206 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Статья 3: Повторение – мать учения.

Здравствуйте. Не волнуйтесь. Специально возвращаться к ранее изученному материалу нам не придется, поскольку и так в каждом последующем уроке мы будем использовать все, что выучили раньше. А как же иначе. Все что я вам рассказываю это самые основы, стержень языка, который наличествует в программе любой сложности. А повторение я упомянул по той причине, что сейчас мы будем учить способ, с помощью которого в языке C++ можно многократно, циклически выполнять одни и те же действия. Например, в прошлом уроке один блок кода выполнялся шесть раз. Этого можно было избежать, если бы вы были знакомы с методами организации циклов.

1. Ин и Де

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

Code

А = 5;
А++;    // А станет равно шести
А--;    // А вновь станет равно пяти

Эта запись аналогична следующей:

Code

А = 5;
А = А + 1;    // А станет равно шести
А = А - 1;    // А вновь станет равно пяти


И результат работы обеих примеров идентичный. Просто использование инкременты и декременты проще. Но есть еще одна особенность. Эти операторы могут находится не только после, но и до переменной

Code

--А;
++А;

Подобный вариант записи операторов называется префиксным, тогда как предыдущий - постфиксным.
Результат работы обоих вариантов идентичный, а вот способ этой самой работы кардинально отличается
Если в выражении встречается инкремента или декремента в префиксной записи, то есть перед переменной, то значение переменной сразу уменьшается или увеличивается на единицу. Если запись постфиксная, то сначала выражение вычисляется полностью, игнорируя инкременту/декременту, и только затем эта переменная увеличивается или уменьшается на единицу.
Чтобы лучше это понять приведу соответствующий пример:

Code

int x=1, y;
y=(x++) * 5;

Здесь сначала х умножится на пять, значение будет присвоено у, а затем сработает инкремента и х увеличится на единицу. В результате у == 5, х == 2.
Обратите внимание на использование скобок. Если этого не сделать, то компилятор потеряется в нагромождении операторов. Про ошибку он не скажет, но вот результат будет непредсказуемый.
Ну и пример для префиксной записи:

Code

int x=1, y;
y=(++x) * 5;

В этом случае сначала х будет увеличен, а затем умножен на 5. В результате у == 10, х == 2.

Надеюсь, что вам все понятно.
Кроме того как эти операторы работают, необходимо знать что префиксная их запись работает быстрее чем постфиксная. И вот почему:

Code

y=(x++) * 5;

Когда при выполнении программы с этой строкой доходит очередь до инкременты, создается временная переменная, в которую записывается новое, увеличенное значение х. А потом, после вычисления выражения значение временной переменной обратно присваивается х. Естественно на все это тратится лишнее время. Чисто теоретически это выглядит так:

Code

int temp;    // создается временная переменная
temp=x+1;    // ей присваивается увеличенный х, при этом сам х не меняется.
y=x*5;  // х умножается 5, результат присваивается у
x=temp;  // х присваивается значение временной переменной

Конечно, если оператор выполняется всего один раз, то затраты времени не ощутимы, а вот если это где-то в цикле повторяется несколько сотен а то и тысяч раз, то это уже совсем другое дело.

Раз мы уже упомянули способы упрощения и улучшения кода, расскажу вам еще и о вариантах оператора присвоения.
Запись:

Code

А = А + 1;

Можно упростить так:

Code

А+=1;

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

Code

А-=5;
А*=10;
А/=3;

Эти записи идентичны следующим:

Code

А = А - 5;
А = А * 10;
А = А / 3;

2. Циклы

В языке с ++ есть несколько способов организации циклов.
Самый простой из них это так называемый цикл с предусловием.

while

Как можно понять их названия цикл с предусловием, прежде чем цикл будет выполняться, проверяется некое условие.

Вот синтаксис этого цикла:

Code

while( условие )
{
  Тело цикла  
}


Слово while – переводится с английского как "пока", а всю логику цикла можно передать так. Пока условие истинно, блок кода, содержащийся в теле цикла(это такой термин), будет выполнен, и если условие продолжает оставаться истинным, он будет выполнен снова и снова.
Поэтому если необходимо завершить цикл, нужно изменить условие так, чтобы оно стало ложным, ну или оно станет ложным в процессе, или воспользоваться уже знаком нам оператором break.
Вот два примера.
Первый, где меняется условие:

Code

#include <iostream>
using namespace std;

void main ()
{
  setlocale( LC_ALL, "Russian" );
   
  int i=0;   // переменная для подсчета циклов
  while(i<100000)  // если i меньше 100000, цикл выполняется
  {
   i++;   // счетчик циклов увеличивается на единицу
  }

  cout<<"Все. Нажмите Enter для выхода...";    // это, чтобы мы знали, что циклы закончились
  cin.get();
}

Здесь, как только цикл выполнится определенное количество раз, постепенно увеличивающаяся переменная изменит условие продолжения цикла, и он больше не будет выполняться.

Второй, с использованием оператора break:

Code

#include <iostream>
using namespace std;

void main ()
{
  setlocale( LC_ALL, "Russian" );
   
  int i=0;   // переменная для подсчета циклов
  while(true)   // бесконечный цикл
  {
   if (i==100000)    // если выполнено 100000 циклов
    break;  // цикл прерывается
   i++;   // иначе счетчик циклов увеличивается на единицу
  }

  cout<<"Все. Нажмите Enter для выхода...";    // это, чтобы мы знали, что циклы закончились
  cin.get();
}


ПОДОБНЫЙ СПОСОБ ЗАВЕРШЕНИЯ ЦИКЛА Я НЕ РЕКОМЕНДУЮ. Лучше опираться только на условие, иначе чревато разного рода неприятностями.

В последнем примере также продемонстрирован способ организации бесконечного цикла:

Code

while(true)

Здесь условие уже определено как истинное, и изменить его невозможно, следовательно выйти из этого цикла можно только с помощью break или return, но последняя инструкция вообще завершит работу программы.

do…while

У цикла с предусловием есть брат, которого называют цикл с постусловием. Отличаются они тем, что в цикле с предусловием это самое условие проверяется с самого начала, и если оно ложно, цикл выполняться не будет вообще, тогда как проверка условия в цикле с постусловием происходит только после его первого выполнения. То есть, в не зависимости от условия, цикл будет выполнен как минимум один раз. Бывают моменты, когда подобное необходимо. Во всем остальном эти циклы идентичны.
Вот синтаксис:

Code

  do    
  {
   Тело цикла  
  }
  while(условие);

  

Обратите внимание. Здесь после

Code

while(условие);

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

for

Приводя примеры для предыдущих циклов, я использовал в программе счетчики. Следующий способ организации цикла уже предполагает подобного счетчика. Если предыдущие циклы могли выполнятся неопределенное количество раз, то в цикле с использованием оператора for количество повторений задается с самого начала. Кстати, именно этому циклу отдает предпочтение большинство программистов.

Синтаксис таков:

Code

for(инициализация счетчиков; условие; увеличение счетчика)
{
  Тело цикла
}

Как видно непосредственно в операторе for происходит инициализация счетчика, там же выполняется проверка условия, и там же происходит увеличение счетчика. Все собрано в одном месте, что, несомненно, очень удобно.
Этот синтаксис можно заменить аналогичной записью цикла while:

Code

инициализация счетчиков
while( условие )
{
  {
   Тело цикла  
  }
увеличение счетчика
}

И подобный вариант уже был проиллюстрирован в примере.
А теперь приведу пример, чтобы лучше понять цикл for:

Code

#include <iostream>
using namespace std;

void main ()
{
  setlocale( LC_ALL, "Russian" );
   
  for(int i=0;i<20;i++)   
  {
   cout<<i<<"\n";  // вывод значения счетчика
  }

  cout<<"Все. Нажмите Enter для выхода...";  // это, чтобы мы знали, что циклы закончились
  cin.get();
}


Опишу как этот пример работает.
В операторе for в месте для инициализации объявляется переменная i, которой сразу же присваивается начальное значение 0. Эта часть цикла будет выполнена только один раз. Далее происходит проверка условия, в данном случае это i<20. В данный момент оно истинно, поэтому выполняется тело цикла со следующим кодом:

Code

cout<<i<<"\n";  // вывод значения счетчика


здесь просто выводится текущее значение счетчика.
После этого выполняется последняя часть оператора for, в которой значение счетчика увеличивается на единицу.

Code

i++

Далее вновь проверяется условие и если оно по-прежнему истинно – все повторяется.

Отмечу, что как в случае с while, условие в цикле for не обязательно должно относится к счетчикам.
Как и с оператором while, с оператором for также возможна организация бесконечного цикла. Для этого достаточно оставить все поля пустыми:

Code

for(;;)
{
  Тело цикла
}



При работе с циклом for используется еще один оператор – continue.
С английского переводится - "продолжить", и делает он то же, что и означает.
Как только в теле цикла встречается этот оператор, оставшийся код пропускается и программа переходит к оператору увеличения счетчика.
Приведу пример:

Code

  for(int i=0;i<4;i++)   
  {
   if(i==2)  // если i равно 2
    continue;    // срабатывает этот оператор

   cout<<i<<"\n";  // вывод значения счетчика
  }

Здесь, когда i станет равно 2, сработает оператор continue, в результате чего строка

Code
  
cout<<i<<"\n";  // вывод значения счетчика

будет опущена, и цикл начнется заново с увеличенным на единицу значением i. Это если условие не станет ложным.

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

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


Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 19:57 | Сообщение # 207 | Тема: SONIC TEAM 2009
Просветленный разум
Сейчас нет на сайте
Quote (Vinchensoo)
Тема закрыта, пошел флуд о несостоятельности автора)

В таком случае нужно наказывать флудеров, а не закрывать тему.

ПРЕДУПРЕЖДЕНИЕ!
За флуд в разделе "Команды" буду раздавать баны.


Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 11 Сентября 2009, 20:50 | Сообщение # 208 | Тема: Пишем конструктор игр на Delphi
Просветленный разум
Сейчас нет на сайте
Quote (Viruz)
уже начал искать учебник....подобного рода знаешь еще учебники?

Есть неплохая книга, да и похоже - единственная, по разработке инструментария к движку.
По сути этот инструментарий можно приравнять к конструктору.
Но книга на английском и С#.
Game Engine Toolset Development


Windmill 2

WindMill 2D Game Engine
nilremДата: Воскресенье, 13 Сентября 2009, 07:39 | Сообщение # 209 | Тема: Turbo Game Studio
Просветленный разум
Сейчас нет на сайте
Прочитай правила раздела и внеси соответствующие изменения в первый пост.
Иначе - замечание.


Windmill 2

WindMill 2D Game Engine
nilremДата: Воскресенье, 13 Сентября 2009, 16:57 | Сообщение # 210 | Тема: Обсуждение курса "Основы DirectX"
Просветленный разум
Сейчас нет на сайте
Ну на самом деле из всего СДК нужны только 3 мб.
Но все равно учить индивидуально я никого не собираюсь.
Нет времени.


Windmill 2

WindMill 2D Game Engine
nilremДата: Воскресенье, 13 Сентября 2009, 22:48 | Сообщение # 211 | Тема: Бан....бан....бан
Просветленный разум
Сейчас нет на сайте
Правила обычно, но не всегда, читают только после того, как получили первое замечание.
Так что тема может оказаться полезной.
Возможно, просмотрев ее кто-то обратит внимание и на правила.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 03:26 | Сообщение # 212 | Тема: Shadow Town
Просветленный разум
Сейчас нет на сайте
Quote (FERAMON)
Как сценарист-ты полный нуль.

Держи подобные высказывания при себе.
Замечание.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 11:08 | Сообщение # 213 | Тема: Скриншоты...
Просветленный разум
Сейчас нет на сайте
Сухарик,
20% замечание
за создание бессмысленной темы в разделе "Проекты в разработке".
Тема закрыта.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 11:32 | Сообщение # 214 | Тема: Бан лог
Просветленный разум
Сейчас нет на сайте
Kolosus
Замечание + 14 дней Бан за нарушение правил - оскорбление.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 12:20 | Сообщение # 215 | Тема: Борьба за существование
Просветленный разум
Сейчас нет на сайте
Тема больше о проекте, чем о команде. Перенес в соответствующий раздел.

Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 12:32 | Сообщение # 216 | Тема: Количество Полигонов В Современных Играх?
Просветленный разум
Сейчас нет на сайте
Вот аналогичная тема - http://gcup.ru/forum/26-1191-1
Пошел оффтоп. Тема закрыта.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 14:13 | Сообщение # 217 | Тема: Нужны - программисты, моделлеры, 3D художники...
Просветленный разум
Сейчас нет на сайте
Quote (NECROMANT)
Диздок обрел вес в 40кб.

Ну так может покажешь, иначе о объеме и говорить не стоит.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 15:02 | Сообщение # 218 | Тема: Нужен художник
Просветленный разум
Сейчас нет на сайте
Viruz,
Изометрия(изометрическая прекция), 2.5D а также вид 3/4 это одно и то же.
Прежде чем о чем то говорить, нужно удостовериться в своих словах.

http://ru.wikipedia.org/wiki/Изометрическая_проекция


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 15:35 | Сообщение # 219 | Тема: Нужен художник
Просветленный разум
Сейчас нет на сайте
Quote (Девяностых)
Отрицаешь?

Нет.
Я тебя случайно зацепил.
Кстати, описанная тобой особенность не является отличительной чертой таких игр. Я ее всего раз видел в Симах.


Windmill 2

WindMill 2D Game Engine
nilremДата: Среда, 16 Сентября 2009, 16:28 | Сообщение # 220 | Тема: Как постичь азы
Просветленный разум
Сейчас нет на сайте
Quote (Vinchensoo)
лень.ру

Хороший, кстати, сайт. Сам туда часто захожу.


Windmill 2

WindMill 2D Game Engine
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг