Posts Tagged ‘xna’

Militaria w grze cz.3 – strzelanie

niedziela, Wrzesień 19th, 2010

Dzisiaj opiszę pokrótce moją ostatnią zmianę, czyli to jak realizuję strzelanie w grze. Jak wspomniałem w poprzednim poście mam obiekt GameVehicle (pojazd), który posiada obiekty Bullets (pociski). Przyjąłem narazie, że taki pocisk może znajdować się w kilku stanach:

/// <summary>
/// Stan pocisku
/// </summary>
public enum BulletState
{
    /// <summary>
    /// Przygotowany
    /// </summary>
    Prepared,
    /// <summary>
    /// Odpalony
    /// </summary>
    Started,
    /// <summary>
    /// Po trafieniu
    /// </summary>
    Hit,
    /// <summary>
    /// Poza planszą
    /// </summary>
    Outside
}

i że jego zachowanie zależy właśnie od tego, w jakim stanie się znajduje. Na początku, w konstruktorze wehikułu tworze odpowiednią ilość pocisków z ustawionym stanem „Prepared”, a potem w metodzie Update wehikułu rozpatruję przypadki zachowania każdego z pocisków – wszystkim wystrzelonym zmieniam pozycję, wszystkim odpalonym uaktualniam stan, a wszystkie poza planszą właściwie mógłbym tu usuwać… zamieszczam kod poniżej:

public override void Update(GameTime gameTime)
{
    //kierunek wystrzału (TODO: wyznaczyć namierzenie)
    Vector3 fireDirection = new Vector3(0, 0, -0.3f);
    //poruszam już wystrzelonymi pociskami
    foreach (Bullet fire in this.bullets.FindAll(a => a.State == BulletState.Started))
    {
        fire.Position += fireDirection;
    }
    //odpalam nowy pocisk, po wciśnięciu lewego przycisku myszy
    if (this.input.MouseState.LeftButton == ButtonState.Pressed)
    {
        var fired = this.bullets.Find(a => a.State == BulletState.Prepared);
        if (fired != null)
        {
            fired.State = BulletState.Started;
        }
    }
    base.Update(gameTime);
}

Takie podejście „stanowe” daje mi przy okazji możliwość ograniczenia rysowania pocisków, które nie są wystrzelone. Wystarczy wtedy zmodyfikować metodę „Draw” dla pocisku:

public override void Draw()
{
    //rysuję tylko pociski, które są już w stanie przynajmniej wystrzelonym:)
    if (this.State != BulletState.Prepared)
    {
        base.Draw();
    }
}

Teoretycznie wszystko idzie zgodnie w planem… pozostała mi jeszcze sprawa przyspieszenia działania odrysowywania obiektów oraz kwesta celowania i namierzania (np. bierzemy pod uwagę miejsce kliknięcia myszka, a nie tylko sam fakt przyciśnięcia lewego przycisku). Na 99% zajmę się wymyślaniem tego w kolejnej odsłonie… chyba, że znane są Wam jakieś ogólnie przyjęte algorytmy namierzania/celowania i ew. kontroli ruchu pocisku?;]

Rozszerzalność świata w grach 3D

czwartek, Sierpień 19th, 2010

Próbując jak najlepiej odzwierciedlić świat rzeczywisty w swojej grze natknąłem się na tematykę generowania terenu oraz tak zwanego SKYBOX-a. Otóż, istnieje pewien bardzo prosty i ciekawy zarazem trick, który potrafi uczynić świat 3D stworzony w naszej grze jeszcze bardziej przestrzennym. Cały „chwyt” polega na tym, żeby stworzyć odpowiednio duży sześcian naszej przestrzeni i z każdej strony go oteksturować – gracz ma wtedy wrażenie, jakby znajdował się pośrodku jakiejś ogromnej przestrzeni:) W świetny i przejrzysty sposób opisał to w swoim artykule ‘Riemers’ tutaj :

http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2/Skybox.php

i to właśnie na jego przykładzie wzorowałem się na początku tworzenia świata – nic dodać, nic ująć. Przykład zaczerpnięty i zastosowany w mojej grze wygląda całkiem obiecująco – gdziekolwiek się nie obróci kamerą widać horyzont.

Niestety ten przykład, pomimo dopasowanych świetnie tekstur nie porywa ich jakością. Ponieważ przetrawienie owego tutoriala zajęło mi trochę czasu, dzisiejszy wpis będzie krótszy, co nie znaczy, że moje postępy są czy będą mniejsze. W procesie tworzenia gry sporo czasu poświęca się czasem na „dogranie” modeli, tekstur, danych itp. rzeczy zanim zacznie się to wszystko oprogramowywać.

Kolejnym etapem moich prac będzie próba uzyskania lepszego efektu – natrafiłem już na bardzo ciekawy blog z zupełnie darmowymi i dobrymi jakościowo teksturami: http://blenderartists.org/forum/showthread.php?t=24038. Jest na nim pewien opis tego jak zaadoptować inny „opakowywacz” świata, jakim może być tzw. SKYDOM (kula, zamiast wspomnianego sześcianu). Interesująco wyglądałaby perspektywa zaaplikowania i znajdowania się pośrodku kuli – po prostu pełna przestrzeń.

Na koniec zdradzę jeszcze jedną rzecz – moją grą zainteresował… pisarz. I to nawet niejeden! Jak dobrze pójdzie, istnieje szansa, że powstanie całkiem długa i ciekawa fabuła odzwierciedlająca klimat tworzonej przeze mnie gry (tudzież gra będzie musiała się dostosować do klimatu narzuconego przez fabułę;]). Zupełnie jak reżyser do scenariusza… dam znać co z tego wszystkiego wyjdzie.

Animacje modeli w XNA

środa, Sierpień 11th, 2010

Tym razem będzie trochę o animacjach modeli:) Kolejny etap w tworzeniu mojej gry polega bowiem właśnie na zapoznaniu się z tą funkcjonalnością. Wspaniale jest móc dodawać do sceny kolejne modele i miło jest cieszyć oko urozmaicającym się światem gry. Jak się jednak okazuje, można zrobić więcej… można zasymulować ich poruszanie się!

Mechanizm ten właściwie nie jest w żaden sposób związany usilnie z samą technologią XNA, ale w jakże przejrzysty sposób (kolejny już raz) przełożony właśnie na jej podwórko. Dotyczy po prostu sposobu, w jaki zbudowane mogą być obiekty 3D. Obiekty takie skonstruowane powinny być blokowo tak, aby każdy blok mógł być osobnym modelem, który też może składać z mniejszych bloków itd. Mając dostęp do pewnego bloku, a więc pojedynczej części, możemy na niej robić przeróżne rzeczy (przesuwać, obracać, skalować). W ten sposób powstają ciekawe efekty i nasz interakcyjny świat „ruszających” się modeli.

Cała ta struktura drzewiasta modelu w XNA przechowywana jest w prosty sposób w klasie Microsoft.Xna.Framework.Graphics.Model:

Jak widać mamy tam zarówno propertę ‘Meshes’ jak i ‘Bones’, przechowującą obiekty ModelBone. Każdy taki blok (właściwie powinienem mówić chyba „kość”:) ma swoją macierz transformacji w układzie parenta. Tym samym chcąc przesunąć, obrócić bądź przeskalować taki obiekt robimy to w odniesieniu do jego rodzica. Wszystko jasne i klarowne.

Ja też wykorzystałem to w pewien sposób w implementacji mojej gry. Mianowicie skoro mój helikopter już ma fruwać…to naturalnym faktem jest przecież to, że powinien utrzymywać go w powietrzu obrotowy ruch śmigła. I do zaimplementowanie tego wszystko się sprowadziło. Wystarczyło jedynie przeszukać wśród wszystkich „kości” (w tym modelu jest ich całe 25, a moje śmigło złozone było aż z dwóch części) modelu helikoptera te reprezentujące śmigło i obrócić je wokół osi Y. Konkretnie zrobiłem dwie rzeczy:

//w metodzie LoadContent()
//zapamiętałem "kośći" śmigieł oraz ich transformację
heli.Model = Content.Load<Model>("Models\\Helikopter\\helnwsm1");
this.choopBone = heli.Model.Bones[16]; //smiglo cz.1 (klasa ModelBone)
this.choopBone2 = heli.Model.Bones[18]; //smiglo cz.2 (klasa ModelBone)
this.choopRotation = choopBone.Transform; //(macierz transformacji)

oraz

//w metodzie Update()
 Vector3 move = objects.ActiveObject.Position;
//obliczyłem nową macierz obrotu (jak już pisałem we wcześniejszym poście
//musiałem najpierw przesunąć, potem obrócić, i znowu przesunąć)
this.choopBone.Transform =
   Matrix.CreateTranslation(-move) *
   Matrix.CreateRotationY(rot) *
   Matrix.CreateTranslation(move);
//tę samą macierz stosujemy do drugiej części śmigła
this.choopBone2.Transform = this.choopBone.Transform;

No dobra, okłamałem Was. Tak powinno być, ale Prawie tak było… zmarnowałem przez mój głupi model helikoptera chyba ze 3h na to, żeby wywnioskować, że jest on trochę skopany ;/ Konkretnie, to ten kod powyżej obracał mi śmigło wokół jakiegoś dziwnego punktu w odniesieniu do parenta – środek śmigła nie był wycentrowany w tym modelu, do diaska!. Poprawiłem to poprzez stworzenie wektora poprawiającego i dodanie go do przesunięcia, czyli mój kod powyżej usprawniłem tak:

Vector3 correction = -0.091f *
new Vector3((float)Math.Sin(MathHelper.ToRadians(totalRotation)), 0, (float) Math.Cos(MathHelper.ToRadians(totalRotation)));
Vector3 move = objects.ActiveObject.Position + correction;

Wymyślenie sposobu na odkrycie tej tajemniczej stałej i obrócenie jej o macierz obrotu o całkowity kąt obrotu helikoptera… pozostawiam już samemu sobie jako tajemnicę:) A autorowi modelu 3D tegoż helikoptera chcę tylko powiedzieć: I tak Cię pokonałem skurczybyku:>!

Jak widać, wszystko tutaj śmiga, dopóki mamy ładne modele – jakże poważna jest zatem rola grafików, projektantów i artystów w procesie tworzenia gry. Mój drugi model, czyli auto, składa się tylko z dwóch bloków i niestety niewiele mogę tutaj w kwestii animacji podziałać. A tak bardzo chciałem móc też obracać kołami podczas poruszania się nim. Cóż, pozostaje mi chyba tylko wymienić go na inny.

Grę ściągnąć i podziwiać można tutaj:
http://www.kamilhawdziejuk.pl/gra/GameXna_11082010.exe
Żeby działało, to dodatkowo trzeba sobie ściągnąć następujący pakiet:
Microsoft XNA Framework Redistributable 3.1

Tematyka animacji modeli jest bardzo rozbudowana. Od strony programistycznej istnieją dwie metody: animowanie klatkami oraz animowanie szkieletem. To tę drugą zastosowałem w przykładzie mojej gry. Osobom zainteresowanym szczególnie natomiast polecam rewelacyjny wręcz przykład zastosowania tego mechanizmu, którego źródła można podejrzeć w jednym z tutoriali Microsoftu na XNA Creators:
http://creators.xna.com/en-US/tutorial/skinnedmodelextensions.
Jeśli uda mi się coś takiego przełożyć w zgrabny sposób do swojego projektu, to będę bardzo zadowolony. I może o tym będzie jeden z kolejnych postów:)