This article has been localized into Czech by the community.
In this article series, we're building a complete Snake game from scratch. It makes sense to start with the Introduction and then work your way through the articles one by one, to get the full understanding.
If you want to get the complete source code for the game at once, to get started modifying and learning from it right now, consider downloading all our samples!
Přidávání jídla pro hada
V této fázi série článků o SnakeWPF už máme jako herní plochu šachovnicové pozadí a po něm se pohybuje půvabně vypadající zelený had. Jak bylo zmíněno v úvodu, cílem hry je, aby had snědl nějaké jídlo - v naší verzi to budou červená jablka!
Takže nyní je čas začít přidávat do herní oblasti nějaké jídlo. Uděláme to tak, že náhodně přidáme červený kruh někde uvnitř hranic plátna GameArea, ale musíme se ujistit, že jej neumisťujeme na jedno z čtverců, které jsou již obsazeny neustále rostoucím hadem. Jinými slovy, jedním z nejdůležitějších aspektů umístění jablka na herní plochu je kód, který rozhoduje o další pozici. Zde je kód, který použijeme právě pro to:
private Point GetNextFoodPosition()
{
int maxX = (int)(GameArea.ActualWidth / SnakeSquareSize);
int maxY = (int)(GameArea.ActualHeight / SnakeSquareSize);
int foodX = rnd.Next(0, maxX) * SnakeSquareSize;
int foodY = rnd.Next(0, maxY) * SnakeSquareSize;
foreach(SnakePart snakePart in snakeParts)
{
if((snakePart.Position.X == foodX) && (snakePart.Position.Y == foodY))
return GetNextFoodPosition();
}
return new Point(foodX, foodY);
}
Nezapomeňte také přidat tento řádek na začátek deklarace třídy Window společně s ostatními poli/konstantami:
public partial class SnakeWPFSample : Window
{
private Random rnd = new Random();
......
Takže, abychom rychle vysvětlili kód: Opět používáme konstantu SnakeSquareSize k pomoci s výpočtem další pozice pro naše jídlo, ve spojení s třídou Random, která nám dá náhodnou pozici X a Y. Jakmile ji máme, procházíme všechny současné části hada a kontrolujeme, zda jejich pozice odpovídá souřadnicím X a Y, které jsme právě vytvořili - pokud ano, znamená to, že jsme narazili na oblast momentálně obsazenou hadem, a poté požádáme o novou pozici jednoduše opětovným voláním metody (čímž se tato metoda stává rekurzivní).
To také znamená, že tato metoda se může sama volat neomezeně mnohokrát a teoreticky vést k nekonečné smyčce. Mohli bychom provést nějakou kontrolu, ale nemělo by to být nutné, protože by to vyžadovalo, aby byl had tak dlouhý, že by nezůstal žádný prázdný prostor - můj odhad je, že hra skončí dříve, než se to stane.
S tím na místě jsme připraveni přidat kód, který přidá jídlo na nově vypočítanou pozici - budeme to dělat z metody nazvané DrawSnakeFood(). Díky veškeré práci, která už byla zpracována metodou GetNextFoodPosition(), je to poměrně jednoduché, ale nejprve se ujistěte, že deklarujete pole použité k uložení odkazu na jídlo, stejně jako SolidColorBrush použitý k vykreslení jablka, společně s ostatními deklaracemi polí/konstant:
public partial class SnakeWPFSample : Window
{
private UIElement snakeFood = null;
private SolidColorBrush foodBrush = Brushes.Red;
......
Zde je implementace metody:
private void DrawSnakeFood()
{
Point foodPosition = GetNextFoodPosition();
snakeFood = new Ellipse()
{
Width = SnakeSquareSize,
Height = SnakeSquareSize,
Fill = foodBrush
};
GameArea.Children.Add(snakeFood);
Canvas.SetTop(snakeFood, foodPosition.Y);
Canvas.SetLeft(snakeFood, foodPosition.X);
}
Jak bylo slíbeno, je to velmi jednoduché - jakmile máme pozici, jednoduše vytvoříme novou instanci Ellipse a opět použijeme konstantu SnakeSquareSize, abychom zajistili, že má stejnou velikost jako dlaždice pozadí i každá část hada. Odkaz na instanci Ellipse uložíme do pole snakeFood, protože jej později budeme potřebovat.
S tím na místě opravdu potřebujeme jen zavolat metodu DrawSnakeFood(), abychom viděli výsledek naší práce. To se stane ve dvou situacích: Na začátku hry a když had "sní" jídlo (o tom více později). Prozatím přidejme volání této metody do naší metody StartNewGame():
private void StartNewGame()
{
snakeLength = SnakeStartLength;
snakeDirection = SnakeDirection.Right;
snakeParts.Add(new SnakePart() { Position = new Point(SnakeSquareSize * 5, SnakeSquareSize * 5) });
gameTickTimer.Interval = TimeSpan.FromMilliseconds(SnakeStartSpeed);
// Draw the snake and the snake food
DrawSnake();
DrawSnakeFood();
// Go!
gameTickTimer.IsEnabled = true;
}
To je vše! Pokud nyní hru spustíte, měli byste vidět, že had konečně má nějaké jídlo, za kterým může jít:
Docela dost práce na to, abyste na obrazovce umístili červenou tečku, že?
Shrnutí
V tomto článku jsme konečně přidali na stůl nějaké jídlo, aby si ho had mohl chytit, ale stále je co dělat: Musíme být schopni ovládat hada a musíme vědět, když had na něco narazí (na zeď, vlastní ocas nebo jídlo). Více o tom v dalším článku.