Skip to content

Commit

Permalink
Update chapter-07-complex-loops.md
Browse files Browse the repository at this point in the history
  • Loading branch information
bokoo authored Jan 6, 2019
1 parent 9c38768 commit fcff193
Showing 1 changed file with 1 addition and 125 deletions.
126 changes: 1 addition & 125 deletions chapter-07-complex-loops.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Глава 7.1. По-сложни цикли тест
# Глава 7.1. По-сложни цикли


След като научихме какво представляват и за какво служат **`for` циклите**, сега предстои да се запознаем с **други видове цикли**, както и с някои **по-сложни конструкции за цикъл**. Те ще разширят познанията ни и ще ни помагат в решаването на по-трудни и по-предизвикателни задачи. По-конкретно, ще разгледаме как се ползват следните програмни конструкции:
Expand Down Expand Up @@ -605,127 +605,3 @@ catch
}
// Ако int.Parse(…) гръмне, ще се изпълни catch { … } блокът
```


## Упражнения: уеб приложения с по-сложни цикли

Сега вече знаем как да повтаряме група действия, използвайки **цикли**. Нека направим нещо интересно: да си направим **уеб базирана игра**. Да, истинска игра, с графика, с гейм логика. Да се позабавляваме. Ще бъде сложно, но ако не разберете нещо как точно работи, няма проблем. Сега още навлизаме в програмирането. Има време, ще напреднете с технологиите. Засега следвайте стъпките.

### Празно Visual Studio решение (Blank Solution)

Създайте празно решение **(Blank Solution)** във Visual Studio, за да организирате кода от задачите за упражнение. Целта на този **blank solution** e да съдържа **по един проект за всяка задача** от упражненията.

![](/assets/old-images/chapter-7-images/00.Blank-visual-studio-01.png)

Задайте **да се стартира по подразбиране текущия проект** (не първият в решението). Кликнете с десен бутон на мишката върху **Solution 'Complex-Loops'** -> [**Set StartUp Projects…**] -> [**Current selection**].

![](/assets/old-images/chapter-7-images/00.Set-current-selection-01.png)


### Задача: уеб игра „Обстреляй плодовете!“

**Условие**: Да се разработи **ASP.NET MVC уеб приложение** – игра, в която играчът **стреля по плодове**, подредени в таблица. Успешно уцелените плодове изчезват, а играчът получава точки за всеки уцелен плод. При уцелване на **динамит**, плодовете се взривяват и играта свършва (както във Fruit Ninja).
Стрелбата се извършва по колони, отгоре надолу или отдолу нагоре, а местоположението на удара (колоната под обстрел) се задава чрез скролер (scroll bar). Заради неточността на скролера, играчът не е съвсем сигурен по коя колона ще стреля. Така при всеки изстрел има шанс да не улучи и това прави играта по-интересна (подобно на прашката в Angry Birds).

Играта ни трябва да изглежда по този начин:

![](/assets/old-images/chapter-7-images/15.Fruits-01.png)

![](/assets/old-images/chapter-7-images/15.Fruits-02.png)

Следват стъпките за имплементация на уеб приложението “Обстреляй плодовете!”.

Във Visual Studio създаваме ново **ASP.NET MVC уеб приложение** с език C++. Добавяме нов проект от [**Solution Explorer**] → [**Add**] → [**New Project…**]. Задаваме смислено име, например “**Fruits-Web-Game**:

![](/assets/old-images/chapter-7-images/15.Fruits-03.png)

След това избираме тип на уеб приложението "MVC":

![](/assets/old-images/chapter-7-images/15.Fruits-04.png)

Сега създаваме контролите за играта. Целта е да добавим **скролиращи ленти** (scroll bars), с които играчът се прицелва, и бутон за старт на **нова игра**. Затова трябва да редактираме файла **`Views/Home/Index.cshtml`**. Изтриваме всичко в него и въвеждаме кода от картинката:

![](/assets/old-images/chapter-7-images/15.Fruits-05.png)

Този код създава уеб форма **`<form>`** със скролер (поле) **`position`** за задаване на число в интервала [**0 … 100**] и бутон [**Fire Top**] за изпращане на данните от формата към сървъра. Действието, което ще обработи данните, се казва **`Home/FireTop`**, което означава метод **`FireTop`** в контролер **`Home`**, който се намира във файла **`HomeController.cs`**. Следват още две подобни форми с бутони [**Fire Bottom**] и [**New Game**].

Сега трябва да подготвим плодовете за рисуване в изгледа (view). Добавяме следния код в контролера: **`Controllers/HomeController.cs`**:

![](/assets/old-images/chapter-7-images/15.Fruits-06.png)

Горният код дефинира полета за **брой редове, брой колони**, за **таблицата с плодовете** (игралното поле), за натрупаните от играча **точки** и информация дали играта е активна или е **свършила** (поле **`gameOver`**). Игралното поле е с размери 9 колони на 3 реда и съдържа за всяко поле текст какво има в него: **`apple`, `banana`, `orange`, `kiwi`, `empty` или `dynamite`**.
Главното действие **`Index()`** подготвя игралното поле за чертане като записва във **`ViewBag`** структурата елементите на играта и извиква изгледа, който ги чертае в страницата на играта в уеб браузъра като HTML.

Трябва да генерираме случайни плодове. За да направим това, трябва да напишем метод **`GenerateRandomFruits()`** с кода от картинката по-долу. Този код записва в таблицата (матрицата) **`fruits`** имена на различни картинки и така изгражда игралното поле. Във всяка клетка от таблицата се записва една от следните стойности: **`apple`, `banana`, `orange`, `kiwi`, `empty` или `dynamite`**. След това, за да се нарисува съответното изображение в изгледа, към текста от таблицата ще се долепи **`.png`** и така ще се получи името на файла с картинката, която да се вмъкне в HTML страницата като част от игралното поле. Попълването на игралното поле (9 колони с по 3 реда) става в изгледа **`Index.cshtml`** с два вложени **`for`** цикъла (за ред и за колона).

За да се генерират случайни плодове за всяка клетка се генерира **случайно число** между 0 и 8 (вж. класа **`Random`** в .NET). Ако числото e 0 или 1, се слага **pple`**, ако е между 2 и 3, се слага **`banana`** и т.н. Ако числото е 8, се поставя **`dynamite`**. Така плодовете се появяват 2 пъти по-често отколкото динамита. Ето и кода:

![](/assets/old-images/chapter-7-images/15.Fruits-07.png)

**Добавяме картинките** за играта.

От [**Solution Explorer**] създаваме папка **"images"** в коренната директория на проекта. Използваме менюто [**Add**] &rarr; [**New Folder**].

Сега добавяме **картинките** за играта (те са част от файловете със заданието за този проект и могат да бъдат свалени от [тук](https://github.com/SoftUni/Programming-Basics-Book-CSharp-BG/tree/master/assets/chapter-7-assets)). Копираме ги от Windows Explorer и ги поставяме в папката **"images"** в [**Solution Explorer**] във Visual Studio с **copy/paste**.
![](/assets/old-images/chapter-7-images/15.Fruits-08.png)

Чертане на плодовете в **`Index.cshtml`**:

За да **начертаем игралното поле** с подовете, трябва да завъртим **два вложени цикъла** (за редовете и за колоните). Всеки ред се състои от 9 на брой картинки, всяка от които съдържа **`apple`, `banana`** или друг плод, или празно **`empty`**, или динамит **`dynamite`**. Картинките се чертаят като се отпечата HTML таг за вмъкване на картинка от вида на **`<img src="/images/apple.png" />`**. Девет картинки се подреждат една след друга на всеки от редовете, а след тях се преминава на нов ред с **`<br>`**. Това се повтаря три пъти за трите реда. Накрая се отпечатват точките на играча. Ето как изглежда **кодът** за чертане на игралното поле и точките:

![](/assets/old-images/chapter-7-images/15.Fruits-09.png)

Обърнете внимание на жълтите символи **`@`** – те служат за превключване между езика **C++** и езика **HTML** и идват от **Razor** синтаксиса за рисуване на динамични уеб страници.

Следва да нагласим текстовете във файла **`/Views/Shared/_Layout.cshtml`**. Заменяме **`My ASP.NET Application`** с по-подходящ текст, напр. **`Fruits`**:

![](/assets/old-images/chapter-7-images/15.Fruits-10.png)

Стартираме проекта с [**Ctrl+F5**] и му се порадвайте. Очаква се да бъде генерирано случайно игрово поле с плодове с размери 9 на 3 и да се визуализира в уеб страницата чрез поредица картинки:

![](/assets/old-images/chapter-7-images/15.Fruits-11.png)

Сега играта е донякъде направена: игралното поле се генерира случайно и се визуализира успешно (ако не сте допуснали грешка някъде). Остава да се реализира същината на играта: **стрелянето по плодовете**.

За целта добавяме действията [**Reset**] и [**Fire Top**] / [**Fire Bottom**] в контролера **`HomeController.cs`**:

![](/assets/old-images/chapter-7-images/15.Fruits-12.png)

Горният код дефинира три действия:
* **`Reset()`** – стартира нова игра, като генерира ново случайно игрално поле с плодове и експлозиви, нулира точките на играча и прави играта валидна **(`gameOver = false`)**. Това действие е доста просто и може да се тества веднага с [**Ctrl+F5**], преди да се напишат другите.
* **`FireTop(position)`** – стреля по ред **0** на позиция **`position`** (число от 0 до 100). Извиква се стреляне в посока **надолу** (+1) от ред **`0`** (най-горния). Самото стреляне е по-сложно като логика и ще бъде разгледано след малко.
* **`FireBottom(position)`** – стреля по ред **2** на позиция **`position`** (число от 0 до 100). Извиква се стреляне в посока **нагоре** (-1) от ред **2** (най-долния).

Имплементираме "стрелянето" – метода **`Fire(position, startRow, step)`**:

![](/assets/old-images/chapter-7-images/15.Fruits-13.png)

Стрелянето работи по следния начин: първо се изчислява номера на колоната **`col`**, към която играчът се е прицелил. Входното число от скролера (между 0 и 100) се намалява до число между 0 и 8 (за всяка от 9-те колони). Номерът на реда **row** е или 0 (ако изстрелът е отгоре) или броят редове минус едно (ако изстрелът е отдолу). Съответно посоката на стрелба (стъпката) е **1** (надолу) или **-1** (нагоре).

За да се намери къде изстрелът поразява плод или динамит, се преминава в цикъл през всички клетки от игралното поле в прицелената колона и от първия до последния атакуван ред. Ако се срещне плод, той изчезва (замества се с **`empty`**) и се дават точки на играча. Ако се срещне **`dynamite`**, играта се отбелязва като свършила.

Оставаме на по-запалените да имплементират по-сложно поведение, например да се дават различни точки при уцелване на различен плод, да се реализира анимация с експлозия (това не е твърде лесно), да се взимат точки при излишно стреляне в празна колона и подобни.

**Тестваме** какво работи до момента като стартираме с [**Ctrl+F5**]:
* **Нова игра** &rarr; бутонът за нова игра трябва да генерира ново игрално поле със случайно разположени плодове и експлозиви и да нулира точките на играча.
* **Стреляне отгоре** &rarr; стрелянето отгоре трябва да премахва най-горният плод в уцелената колона или да предизвиква край на играта при динамит. Всъщност при край на играта все още нищо няма да се случва, защото в изгледа този случай още не се разглежда.
* **Стреляне отдолу** &rarr; стрелянето отдолу трябва да премахва най-долния плод в уцелената колона или да прекратява играта при уцелване на динамит.

![](/assets/old-images/chapter-7-images/15.Fruits-01.png)

За момента при **"Край на играта"** нищо не се случва. Ако играчът уцели динамит, в контролера се отбелязва, че играта е свършила **(`gameOver = true`)**, но този факт не се визуализира по никакъв начин. За да заработи приключването на играта, е необходимо да добавим няколко проверки в изгледа:

![](/assets/old-images/chapter-7-images/15.Fruits-14.png)

![](/assets/old-images/chapter-7-images/15.Fruits-15.png)

Кодът по-горе проверява дали е свършила играта и показва съответно контролите за стреляне и игралното поле (при активна игра) или картинка с експлодирали плодове при край на играта.

След промяната в кода на изгледа стартираме с [**Ctrl+F5**] и **тестваме** играта отново:

![](/assets/old-images/chapter-7-images/15.Fruits-16.png)

Този път при уцелване на динамит, трябва да се появи дясната картинка и да се позволява единствено действието "нова игра" (бутонът [**New Game**]).

Сложно ли беше? Успяхте ли да направите играта? Ако не сте успели, спокойно, това е сравнително сложен проект, който включва голяма доза не изучавана материя. Ако искате уеб игричката да ви тръгне в ръцете, **гледайте видеото** в началото на тази глава и следвайте стъпките от него. Там приложението е направено на живо с много обяснения. Или питайте за конкретни проблеми във **форума на СофтУни**: https://softuni.bg/forum.

0 comments on commit fcff193

Please sign in to comment.