TOC

This article is currently in the process of being translated into Polish (~98% done).

Creating a Game: SnakeWPF:
Chapter introduction:

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!

Adding food for the Snake

Teraz w serii artykułów o SnakeWPF, mamy teraz tło szachownicy jako powierzchnię gry, oraz ślicznie wyglądający zielony wąż poruszający się po nim. Jednak, jak wzmiankowano w introdukcji, cel gry to żeby wąż zjadł jakieś jedzenie - w naszej wersji będą to czerwone jabłka!

Więc teraz jest czas na dodanie trochę jabłek do powierzchni gry. Zrobimy to, losowo dodając czerwone kółka gdzieś wewnątrz granic Płótna GameArea, ale musimy upewnić się, że nie umieścimy tego w jednych z kwadracików szachownicy, który został już zajęty przez stale powiększającego się węża. W innych słowach, jednym z najpotrzebniejszych aspektów umieszczenia jabłka na powierzchni gry jest kod, który decyduję jego następną pozycję. Oto kod, który użyjemy, żeby właśnie to zrobić:

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);
}

Upewnij się, żeby dodać też tą linijkę kodu na górze deklaracji klasy Window, z resztą stałych:

public partial class SnakeWPFSample : Window
{
    private Random rnd = new Random();
    ......

Więc, żeby szybko wyjaśnić ten kod: Znowu używamy stałą SnakeSquareSize, aby pomóc nam kalkulować następną pozycję naszego jedzenia, w kombinacji z klasą Random, co nam da losową pozycję X i Y. Kiedy ją mamy, przechodzimy przez wszystkie części węża i sprawdzamy, czy ich pozycja pasuje do koordynatów X i Y, które dopiero stworzyliśmy - jeśli to jest prawda, to znaczy, że wylosowana pozycja jest zajmowana przez węża, więc prosimy o nową pozycję, przez znowu wywoływanie metody (robiąc to rekursywną metodą).

To też znaczy, że ta metoda może się wywoływać nieskończenie wiele i, w teorii, rezultować w nieskończonej pętli. Moglibyśmy zrobić trochę sprawdzania, ale nie jest to potrzebne, ponieważ to by wymagało tego, żeby węż był taki długi, że wszystkie kwadraciki są przez niego zajęte - mój zakład to to, że gra już by się skończyła, zanim to się by stało.

Z tym, jesteśmy gotowi dodać kod, który doda jedzenie w nowo-skalkulowanej pozycji - zrobimy to metodą o nazwie DrawSnakeFood(). Dzięki pracy już handlowanej przez GetNextFoodPosition(), jest to bardzo łatwe, lecz najpierw, pamiętaj żeby deklarować pole użyte, żeby zapisać odniesienie do tego jedzenia, i SolidColorBrush użyte, żeby narysować jabłko, z innymi deklaracjami stałych:

public partial class SnakeWPFSample : Window  
{  
    private UIElement snakeFood = null;  
    private SolidColorBrush foodBrush = Brushes.Red;
    ......

Oto implementacja tej 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 obiecano, jest to bardzo proste - jak mamy już pozycję, po prostu tworzymy nową Elipsę i znowu używamy stałą SnakeSquareSize, aby się upewnić, że Elipsa ma ten sam rozmiar, co 1 kwadracik szachownicy w tle i każda część węża. Zapisujemy odniesienie do Elipsy w polu snakeFood, ponieważ potem potrzebujemy je.

Z tym, już tylko musimy wywołać metodę DrawSnakeFood(), aby zobaczyć efekty naszej pracy. To będzie zrobione w dwóch sytuacjach: na początku gry i kiedy węż "zje" jabłko (o tym później). Na razie, wywołajmy ją w naszej metodzie 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 wszystko! Jeśli teraz zaczniesz grę, powinieneś/powinnaś zobaczyć, że wąż w końcu ma jabłko do zjedzenia:

Całkiem sporo roboty, żeby umieścić czerwoną kropkę na ekranie, co nie?

Podsumowanie

W tym artykule, w końcu dodaliśmy trochę jedzenia na stół dla węża, żeby złapał, ale dalej jest dużo roboty: musimy mieć możliwość kontrolowania węża, i musimy wiedzieć, kiedy coś dotknie (ścianę, swój własny ogon lub jabłko). Więcej o tym w następnym artykule.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!