Пятница, 17.11.2017, 23:13
Приветствую Вас Гость | RSS

Кузница миров

Меню сайта
Категории раздела
Мои статьи [2]
Курс : "Основы С++ для начинающих программистов игр." [25]
WindMill Engine [3]
XNA4 RPG [0]
Перевод туториалов но созданию RPG на C# c XNA4.
C# & Leadwerks [5]
Программирование Leadwerks Engine на языке С# с помощью врапера Le.NET.

Каталог статей и уроков

Главная » Статьи » Курс : "Основы С++ для начинающих программистов игр."

2.1 Совершенствуем "Осаду"
2 : Продолжаем обучение.


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

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
<BR>10 < 7 < 5<BR><BR>


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

Code
<BR>false  < 5<BR><BR>


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

Code
<BR>false < true<BR><BR>


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

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

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

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

if else


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

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


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

Code
<BR>if (условие)<BR>       Блок кода  <BR><BR>


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

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


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

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

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

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


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

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

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

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

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

switch


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

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

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

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


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

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

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

Оператор switch поочередно сравнивает переданное ему значение Переменной со стоящим после оператора case значением. Если оно идентично, то выполняется соответствующий блок кода. После чего срабатывает оператор break, который прекращает работу оператора выбора. Если случайно забыть поставить break, то программа продолжит сравнивать значения, даром тратя время.
Если необходимое значение не найдено, то выполняется блок кода заданный по умолчанию, то есть стоящий после оператора default. Кстати, если значение по умолчанию не нужно, то default можно и не задавать.
Есть еще одна особенность оператора выбора, связанная с использованием оператора break. Допустим, что вам необходимо чтобы в двух или больше ситуациях был выполнен один блок кода. В этом случае используется такой синтаксис:
Code
<BR>switch (Переменная)<BR>{<BR>case Значение 1:  <BR>case Значение 2: Блок кода; break;<BR>}<BR><BR>

Здесь после первого значения отсутствует break, а это означает что
Code
<BR>Блок кода; break;<BR><BR>


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

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


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

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


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

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


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

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


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

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

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

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

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


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

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

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

Code
<BR>#include <iostream><BR>using namespace std;<BR><BR>int main( void )  // главная функция программы<BR>{      <BR>  setlocale( LC_ALL, "Russian" ); // задействование русского языка<BR>   <BR>  int Draco=2;    // переменная для Дракона<BR>  int Golem=4;    // голем<BR>  int Arrows=3;    // лучник<BR>  int Peasant=1;    // крестьянин<BR>  int i=0;  // переменная для хранения введенного игроком числа<BR><BR>  // Вывод вступительного текста<BR>  cout << "После долгого, долгого перехода вы наконец-то добрались к окресностям форта,\n";<BR>  cout << "который приказом короля вам велено захватить.\n";<BR>  cout << "Но, как выяснилось, форт хорошо охраняется:\n\n";<BR>  cout << "Южные ворота охраняет Дракон.\n";<BR>  cout << "Северную стену - Голем.\n";<BR>  cout << "На восточной расположились лучники,\n" ;<BR>  cout << "а на западной - крестьяне.\n\n";<BR>  cout << "Ваша армия состоит из\n";<BR>  cout << "1. Асасинов\n";<BR>  cout << "2. Магов\n";<BR>  cout << "3. Латников\n";<BR>  cout << "4. Катапульты\n\n";<BR>  cout << "(Для выбора вариант ответа вводите соответствующий номер и нажимаете ENTER.\n";<BR>  cout << "Выбрать войска можно только один раз.)\n\n";<BR>  cout << "Кого вы отправите против Дракона?\n";<BR>  cin >> i;    // получение данных от игрока<BR>  Draco = Draco - i;  // вычисление результата для Дракона<BR>  cout << "Кого вы отправите против Голема?\n";<BR>  cin >> i;    // получение данных от игрока<BR>  Golem = Golem - i;  // вычисление результата для Голема<BR>  cout << "Кого вы отправите против лучников?\n";<BR>  cin >> i;    // получение данных от игрока<BR>  Arrows = Arrows - i;    // вычисление результата для Лучников<BR>  cout << "Кого вы отправите против крестьян?\n";<BR>  cin >> i;    // получение данных от игрока<BR>  Peasant = Peasant - i;    // вычисление результата для Крестьян<BR><BR>  // Вывод результата вместе с условиями выиграша<BR>  cout << "У противника осталось " << Draco << " Драконов,"<BR>   << Golem << " Големов, "<< Arrows << " Лучников, "<< Peasant <<  <BR>   " Крестьян\n\n";<BR><BR>  if(Draco==0&&Golem==0&&Arrows==0&&Peasant==0)    // проверка результата боя<BR>  {<BR>   cout << "ВЫ ОДЕРЖАЛИ ДОБЛЕСНУЮ ПОБЕДУ";  <BR>  }<BR>  else<BR>  {<BR>   cout << "ВЫ ПОЛУЧИЛИ СОКРУШИТЕЛЬНОЕ ПОРАЖЕНИЕ";<BR>  }<BR><BR>  cin.get();    // ожидание нажатия клавиши<BR>  cin.get();    // ожидание нажатия клавиши<BR>  return 0;    // возвращение значения, и завершение программы<BR>}<BR><BR>

Категория: Курс : "Основы С++ для начинающих программистов игр." | Добавил: nilrem (24.10.2011)
Просмотров: 670 | Комментарии: 1 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0