> For the complete documentation index, see [llms.txt](https://engin.gitbook.io/y2obn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://engin.gitbook.io/y2obn/master.md).

# HiddenImageGame

Cílem úkolu je vytvořit jednoduchou hru, kde po spuštění se objeví formulář zakrytý čtverečkovanou mřížkou. Po kliku myší na jednotlivé čtverečky tyto mizí a pod nimi se objevuje obrázek, který je třeba uhodnout.

Myšlenka realizace: Využijeme jednoduchý formulář, který bude mít na své ploše nakreslený obrázek. Obrázek bude pokrytý čtvercovými prvky *Label* s nápisy indexů (1, 2, 3, ...). Po kliku na konkrétní prvek *Label* se tento skryje a tím se budou odhalovat kousky obrázku pod ním.

## Implementace příkladu

### 1. Příprava projektu

Nejdříve je třeba vytvořit nový projekt v *Visual Studio.* V okně stačí mít otevřený formulář.&#x20;

Dále je třeba si někam na disk připravit nějaký větší obrázek.

### 2. Příprava formuláře

V nově otevřené aplikaci máme otevřený návrhový editor formuláře.

V okně návrhu formuláře dvakrát klikneme na plochu formuláře, což otevře kód formuláře přímo s vytvořenou metodou *Form1\_Load*.

{% code title="Form1.cs" %}

```csharp
using System;
using System.Drawing;
using System.Windows.Forms;

namespace HiddenImageGame
{
  public partial class Form1 : Form
  {    
    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
     
    }    
  }
}

```

{% endcode %}

Do metody zatím nebudeme nic vpisovat, vytvoříme si ale na formuláři 3 konstanty, které budou měnit vzhled vytvářené aplikace reprezentující šířku/výšku jednoho překrývajícího prvku (ovlivňuje tedy počet čtverečků na na ploše formuláře), velikost písma na čtverečku a také obrázek, který bude na pozadí. Kód umístíme dovnitř třídy, ale vně všech jejich metod (tedy například za řádek 8 předchozího výpisu):

```csharp
private const int SIDE_SIZE = 150;
private const int FONT_SIZE = 24;
private const string IMAGE_FILE_NAME = @"C:\c0744caf5f.jpg";
```

### 3. Nastavení obrázku formuláře na pozadí

Aby byl výsledný kód přehledný, budou jednotlivé stavební bloky psány do samostatných metod, které se následně seskládají dohromady.

Nejdříve je třeba nastavít cestu obrázku do proměnné, následně obrázek načíst a vložit ho do formuláře. Poslední volbou je nastavení způsobu zobrazení obrázku - *Zoom*, která zajistí, že obrázek se vhodně přizpůsobí velikosti formuláře a přitom zachová poměr stran obrázku. Vše provedeme ve vlastní funkci *LoadAndSetImage()* (budeme ji volat později ve *Form1\_Load()*.

```csharp
    private void LoadAndSetImage()
    {
      string imageFile = IMAGE_FILE_NAME;
      Image img = Image.FromFile(imageFile);
      this.BackgroundImage = img;
      this.BackgroundImageLayout = ImageLayout.Zoom;
    }
```

### 4. Vytvořený čtvercové překrývací sítě z prvků Label

Dalším krokem bude vytvoření funkce, která vytvoří překrývací síť z prvků label. Realizaci opět rozdělíme do funkcí:

* jedna pomocná funkce bude realizovat skrytí čtverečku, na který se kliklo;
* další funkce bude obecně vytvářet jeden čtvereček - *Label* - na základě parametru a přidá jej na formulář,
* třetí funkce se postará o pokrytí celého formuláře s využitím předchozí funkce.

#### 4.1 Funkce pro skrytí čtverečku po kliku

Funkce pro skrytí čtverečku - *Label* - po kliku je velmi jednoduchá. Jedná se vlastně o klasickou funkci zachytávající událost kliku s tím, že ale tentokrát bude vytvořen jen její kód (k jednotlivým prvkům *Label* bude připojena později a jinak). Do funkce vstupuje parametr *sender*, ve kterém je uložen *Label*, na který se kliklo. Funkce přetypuje obecný *sender* na *label* a následně jej skryje:

```csharp
    private void label_Click(object sender, EventArgs e)
    {
      Label label = (Label)sender;
      label.Visible = false;
    }
```

#### 4.2 Funkce pro obecné vytvoření čtverečku

Funkce pro vytvoření čtverečku přijme 3 parametry:

* x, y jako souřadnice, na které má být prvek umístěn,
* index jako číslo, které se má na prvku zobrazit.

```csharp
    private void GenerateOneLabel(int x, int y, int index)
    {
      Label label = new Label();
      label.Location = new Point(x, y);
      label.Size = new Size(SIDE_SIZE, SIDE_SIZE);
      label.Font = new Font(Font.FontFamily, FONT_SIZE, FontStyle.Bold);
      label.Text = index.ToString();
      label.TextAlign = ContentAlignment.MiddleCenter;
      label.BorderStyle = BorderStyle.FixedSingle;
      
      label.Click += label_Click;

      this.Controls.Add(label);
    }
```

Funkce vytvoří nový popisek do proměnné *label*, nastaví mu postupně pozici (location), velikost (size), font jako tučný s danou velikostí (font), samotný text a také zarovnání textu (na střed; jinak by se text zobrazil vlevo nahoře, což by nevypadalo hezky) a nakonec obrys (borderStyle;, aby bylo možno poznat, kde jsou hranice mezi jednotlivými čtverečky).

Speciální oprací je zde přiřazení události *Click* pro daný *Label* s využitím operátoru +=. Je důležité si také povšimnout, že na pravé straně výrazu je název funkce (*label\_Click*), ale nejsou za ním závorky!

Nakonec se vytvořený *label* přidá do kolekce prvků na formuláři.

#### 4.3 Funkce pro vytvoření celé čtvercové sítě

Dalším krokem je vytvoření funkce, která pokryje celý formulář čtvercovou sítí.

```csharp
    private void GenerateHidingLabels()
    {
      int x = 0;
      int y = 0;
      int index = 0;
      Rectangle screenSize = ClientRectangle;

      while (x < screenSize.Height)
      {
        while (y < screenSize.Width)
        {
          index++;
          GenerateOneLabel(y, x, index);
          y += SIDE_SIZE;
        }
        x += SIDE_SIZE;
        y = 0;
      }
    }
```

Funkce zjistí rozměr formuláře. Proměnné x a y reprezentují aktuální souřadnici, (0;0) je levý horní roh. V cyklu přes *x* a *y* postupně zvyšuje jejich hodnoty o *SIDE\_SIZE*, tj. a pro každou kombinaci (x,y) vygeneruje jeden čtvereček. Přitom také pro každý čtvereček zvyšuje číselný index, který se na daném čtverečku zobrazí. Cykly trvají, dokud se *x* nebo *y* nedostanou mimo rozsah formuláře.

### 5 Začlenění funkcí do celé aplikace

Posledním krokem je začlenění výše uvedených funkcí do celého formuláře.&#x20;

Jednotlivé volání funkcí se vepíše do *Form1\_Load()*, přičemž se (volitelně) ještě před nastavením formulář nastaví jako maximalizovaný (přes celou obrazovku).

```csharp
private void Form1_Load(object sender, EventArgs e)
{
  WindowState = FormWindowState.Maximized; // maximalizace okna
  GenerateHidingLabels(); // vygenerování čtvercové sítě, viz kap. 3
  LoadAndSetImage(); // nahrání obrázku na pozadí formuláře, viz kap. 4
}
```

### Výsledný kód formuláře Form1.cs

{% tabs %}
{% tab title="Výsledný kód třídy Form1.cs" %}

```csharp
using System;
using System.Drawing;
using System.Windows.Forms;

namespace HiddenImageGame
{
  public partial class Form1 : Form
  {
    private const int SIDE_SIZE = 150;
    private const int FONT_SIZE = 24;
    private const string IMAGE_FILE_NAME = @"C:\...\caf5f.jpg";

    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      WindowState = FormWindowState.Maximized;
      GenerateHidingLabels();
      LoadAndSetImage();
      Visible = true;
    }

    private void LoadAndSetImage()
    {
      string imageFile = IMAGE_FILE_NAME;
      Image img = Image.FromFile(imageFile);
      BackgroundImage = img;
      BackgroundImageLayout = ImageLayout.Zoom;
    }

    private void GenerateHidingLabels()
    {
      int x = 0;
      int y = 0;
      int index = 0;
      Rectangle screenSize = ClientRectangle;

      while (x < screenSize.Height)
      {
        while (y < screenSize.Width)
        {
          index++;
          GenerateOneLabel(y, x, index);
          y += SIDE_SIZE;
        }
        x += SIDE_SIZE;
        y = 0;
      }
    }

    private void GenerateOneLabel(int x, int y, int index)
    {
      Label label = new Label();
      label.Location = new Point(x, y);
      label.Size = new Size(SIDE_SIZE, SIDE_SIZE);
      label.Text = index.ToString();
      label.BorderStyle = BorderStyle.FixedSingle;
      label.TextAlign = ContentAlignment.MiddleCenter;
      label.Font = new Font(Font.FontFamily, FONT_SIZE, FontStyle.Bold);
      label.Click += label_Click;

      this.Controls.Add(label);
    }

    private void label_Click(object sender, EventArgs e)
    {
      Label label = (Label)sender;
      label.Visible = false;
    }
  }
}

```

{% endtab %}
{% endtabs %}

## Spuštění aplikace

Nyní lze aplikaci spustit. Po spuštění se objeví formulář, s ohledem na velikost boxu (*SIDE\_SIZE*) rychle nebo pomaleji vykreslí jednotlivé čtverečky. Po kliku na čtverečky jednotlivé čtverečky mizí a zobrazuje se obrázek schovaný pod nimi.

Ve funkční aplikaci lze dále experimentovat s nastavením velikosti čtverečkové sítě (*SIDE\_SIZE*), nebo velikostí fontu písma (*FONT\_SIZE*).

### Úkoly k procvičení

1. Zkuste nahradit cykly *while* ve funkci *GenerateHidingLabels()* za implementaci pomocí konstrukce *for*.
2. Udělejte čtverečkovou sít vlastní barvou pozadí i písma (*ForeColor* a *BackgroundColor*).
3. Najděte (Google apod.), co znamená, když se řetězec deklaruje pomocí prefixu `@` před uvozovkami (tj. například `@"bubla"`namísto `"bubla"`).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://engin.gitbook.io/y2obn/master.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
