Podstawy XNA - Ruch elementów
Autor: Piotr Bubacz
Opublikowano: 2012-03-29
Jednym z podstawowych elementów gry jest ruch elementów. Ruch ten może bazować na ramkach lub na czasie. Jeśli w naszej aplikacji będziemy bazowali na ramkach, to wpływ na pozycję elementu będzie miał nie tylko upływający czas gry, ale również obciążenie urządzenia. Jeżeli system będzie zbyt obciążony, to zaczniemy „gubić” ramki, przez co przesunięcie elementu nie będzie zależało od czasu, a od liczby utraconych ramek. W przypadku animacji, bazującej na czasie gry (od ostatniego wyświetlenia), przesunięcie elementu zawsze zależy od upływu czasu. W tym artykule dowiesz się, jak poruszać elementy w oparciu o ramki oraz czas.
Przed wykonaniem zadań powinieneś:
- znać podstawy języka C#,
- wiedzieć, jak utworzyć nowy projekt XNA,
- potrafić wyświetlić obraz na ekranie.
Po wykonaniu zadań nauczysz się:
- poruszać elementy w grze w oparciu o ramki oraz czas.
Implementacja
Celem naszej aplikacji będzie wczytanie tekstury, przedstawiającej piłeczkę, oraz poruszenie jej w oparciu o ramki i czas. Wynik zadań został przedstawiony na Rys. 1.
Rys. 1. Ruch piłek na ekranie.
W celu poruszenia elementów na ekranie musimy wykonać następujące kroki:
- dodać do projektu Content plik graficzny,
- dodać obiekt przedstawiający teksturę do klasy Game1,
- wczytać teksturę do wcześniej utworzonego obiektu w metodzie LoadContent(),
- wyświetlić obrazek przedstawiający nasze obiekty w metodzie Draw(),
- poruszyć elementy na ekranie w metodzie Update().
Dodawanie tekstury piłeczki do aplikacji
W pierwszym kroku musimy dodać pliki graficzne piłeczki do projektu.
- Utwórz nowy projekt i nazwij go "RuchElementow". W tym celu:
- uruchom Visual Studio,
- wybierz File -> New -> Project,
- z kategorii XNA Game Studio 4.0 wybierz projekt Windows Game (4.0),
- w polu Name wpisz RuchElementow.
- Pobierz pliki niezbędne do wykonania ćwiczenia:
- pobierz plik KursXNA.zip,
- rozpakuj archiwum w dowolnym katalogu,
- w strukturze katalogów odnajdź plik pilka.png.
- Dodaj pliki do projektu:
- w oknie Solution Explorer naciśnij prawym przyciskiem myszy na " RuchElementowContent (Content)" (Rys. 3.),
- wybierz Add -> Existing Item,
- wybierz plik pilka.png i naciśnij przycisk Add.
Wczytanie grafiki do obiektu klasy Texture2D
W kroku drugim, obraz piłeczki musi zostać wczytany do obiektu klasy Texture2D, który będzie reprezentował naszą teksturę.
- Dodaj nowy obiekt typu Texture2D do klasy Game1:
- otwórz plik Game1.cs,
- w klasie Game1, poniżej linii SpriteBatch spriteBatch; dodaj:
Texture2D pilka;
- Wczytaj teksturę do nowo utworzonego obiektu „pilka”:
- przejdź do metody LoadContent(), po linijce // TODO wpisz następujący kod:
pilka = Content.Load<Texture2D>("pilka");
Wyświetlenie elementów
Teraz możemy wyświetlić dwie piłki, które później będziemy animowali różnymi metodami.
- Dodaj pola odpowiedzialne za prędkość poruszania piłki:
- w klasie Game1, poniżej linii Texture2D pilka; dodaj:
float vPilki1X, vPilki1Y, vPilki2X, vPilki2Y;
- Dodaj obiekty klasy Rectangle:
- w klasie Game1, poniżej wcześniej dodanej linii dodaj:
Rectangle recPilka1, recPilka2;
- Określ pozycje i wielkość obiektów klasy Rectangle:
- w metodzie LoadContent(), poniżej linii pilka = Content.Load<Texture2D>("pilka"); dodaj:
recPilka1 = new Rectangle(10, 10, pilka.Width * 2, pilka.Height * 2);
recPilka2 = new Rectangle(100, 100, pilka.Width * 2, pilka.Height * 2);
- Określ prędkości przesuwania obiektów:
vPilki2X = vPilki2Y = 0.25f;
vPilki1X = vPilki1Y = 3;
- Wyświetl piłki na ekranie:
- przejdź do metody Draw (), po linijce // TODO wpisz następujący kod:
spriteBatch.Begin();
spriteBatch.Draw(pilka, recPilka1, Color.White);
spriteBatch.Draw(pilka, recPilka2, Color.Green);
spriteBatch.End();
- Sprawdź działanie aplikacji:
- zapisz zmiany,
- wciśnij F5 lub wybierz Debug->Start Debugging,
- sprawdź, czy Twoja aplikacja wyświetliła obrazki tak, jak na Rys. 2.
Rys. 2. Pozycja startowa piłek.
Animacja bazująca na ramkach
Animacja 2D, bazująca na ramkach, wymaga zdefiniowania zmiennych, związanych z prędkością przesuwania elementów na ekranie w płaszczyźnie X i Y. Przesunięcie obliczane jest w każdym wywołaniu metody Update() poprzez odpowiednie dodanie tych prędkości do aktualnej pozycji obiektu, a następnie wyświetlane jest w nowej pozycji w metodzie Draw(). Prędkość może być dodatnia lub ujemna, w zależności od kierunku poruszania się obiektu.
- Porusz pierwszą piłką:
- przejdź do metody Update(), po linijce // TODO wpisz następujący kod:
recPilka1.X += (int)vPilki1X;
recPilka1.Y += (int)vPilki1Y;
- Sprawdź działanie aplikacji:
- zapisz zmiany,
- wciśnij F5 lub wybierz Debug->Start Debugging.
Informacja |
Piłka porusza się i po chwili opuszcza obszar gry. Dzieje się tak, ponieważ nie zdefiniowaliśmy ograniczeń dla niej. Musimy określi warunki „odbicia” piłki od krawędzi okna – zmiany prędkości na przeciwną. |
- Dodaj sprawdzenie, czy piłka dotknęła krawędzi ekranu, jeśli tak, to odpowiednio zmień kierunek poruszania:
- poniżej dodanego kodu dodaj:
if (recPilka1.X < 0 || recPilka1.X + recPilka1.Width > GraphicsDevice.Viewport.Width) {
vPilki1X = -vPilki1X;
}
if (recPilka1.Y < 0 || recPilka1.Y + recPilka1.Height > GraphicsDevice.Viewport.Height) {
vPilki1Y = -vPilki1Y;
}
// animacja bazująca na czasie
- Sprawdź działanie aplikacji:
- zapisz zmiany,
- wciśnij F5 lub wybierz Debug->Start Debugging.
Animacja bazująca na czasie
Animacja 2D, bazująca na czasie, wymaga zdefiniowania zmiennych, związanych z prędkością przesuwania elementów na ekranie w płaszczyźnie X i Y oraz informacji o czasie, jaki upłynął od ostatniej zmiany. Czas ten możemy bardzo prosto uzyskać za pomocą właściwości gameTime.ElapsedGameTime.TotalMilliseconds. Przemnażając czas i prędkość otrzymujemy drogę – przesunięcie piłki na ekranie.
- Porusz pierwszą piłką:
- przejdź do metody Update(), po linijce // animacja bazująca na czasie wpisz następujący kod:
recPilka2.X += (int)(gameTime.ElapsedGameTime.TotalMilliseconds * vPilki2X);
recPilka2.Y += (int)(gameTime.ElapsedGameTime.TotalMilliseconds * vPilki2Y);
- Dodaj sprawdzenie, czy piłka dotknęła krawędzi ekranu, jeśli tak, to odpowiednio zmień kierunek poruszania:
- poniżej dodanego kodu dodaj:
if (recPilka2.X < 0 || recPilka2.X + recPilka2.Width > GraphicsDevice.Viewport.Width) {
vPilki2X = -vPilki2X;
}
if (recPilka2.Y < 0 || recPilka2.Y + recPilka2.Height > GraphicsDevice.Viewport.Height) {
vPilki2Y = -vPilki2Y;
}
- Sprawdź działanie aplikacji:
- zapisz zmiany,
- wciśnij F5 lub wybierz Debug->Start Debugging.
- sprawdź, czy obie piłki poruszają się na ekranie.
Podsumowanie
W tym artykule nauczyliśmy się ożywiać świat gry. Znamy różnicę między animacją, bazującą na czasie, a ramkach. Wiemy, że wszędzie tam, gdzie można, powinniśmy wykorzystywać animację bazującą na czasie, aby uniknąć zwalniania akcji gry.
W kolejnym artykule dowiemy się, jak sterować elementami za pomocą klawiatury .
Zadanie
W celu utrwalenia nabytej wiedzy wykonaj proste zadanie. Dodaj kolejnego duszka i spróbuj go poruszać na ekranie obiema metodami. Włącz w systemie zadanie, znacznie obciążające komputer (np. kompresja wideo), i sprawdź różnicę w zachowaniu obu animacji.