Kolejny tutorial nt. XNA 4358 0

O temacie

Autor Ezzam

Zaczęty 11.09.2012 roku

Wyświetleń 4358

Odpowiedzi 0

Ezzam

Ezzam

Użytkownicy
posty391
Propsy367
  • Użytkownicy
Po jakiejś tam przerwie zdecydowałem się napisać kolejny tutek dotyczący XNA.

W tym tutorialu
  • Omówienie i wykorzystanie Rayów
  • To samo, tylko z BoundingBoxami
  • Sortowanie list
  • Parę innych pierdół
Na końcu będziemy mieć coś na kształt strzelanki. A więc do roboty.

1. Rozpoczęcie pracy
Należy zrobić nowy projekt i dodać w nim następujące pola:
       Point mousePosition;
        float angle;
        SpriteFont font;
        Texture2D texture;
        Point center;
        Random random;
        Boolean canShoot;
Nazwy pól mówią same za siebie. Do przechowywania pozycji kursora wybrałem Point zamiast Vector2 z powodu, że Point operuje na wartościach int, a Vector2 na float. Jako że myszka operuje na intach, nie potrzebujemy wektora do zapisywania jej pozycji.

Nowym polom należy nadać wartości w metodzie LoadContent():
           mousePosition = new Point(0, 0);
            angle = 0;
            font = Content.Load<SpriteFont>("Font");
            texture = Content.Load<Texture2D>("white");
            center = new Point(graphics.PreferredBackBufferWidth / 2, graphics.PreferredBackBufferHeight / 2);
            random = new Random();
            canShoot = true;
Oczywiście trzeba stworzyć nowego SpriteFonta. Jako teksturę należy wziąć biały piksel. PreferredBackBuffer Height oraz Width określają wymiary okna gry.

Przyda się również widoczny kursor:
           IsMouseVisible = true;
2. Metody Update() oraz Draw()
Do tej metody dodajemy:
           mousePosition.X = Mouse.GetState().X;
            mousePosition.Y = Mouse.GetState().Y;
Dzięki czemu aktualna pozycja myszki jest zapisana w polu mousePosition, oraz
           angle = (float)Math.Atan2(mousePosition.Y - center.Y, mousePosition.X - center.X);Tutaj trochę trygonometrii.

Dzięki metodzie Math.Atan2 obliczamy kąt (pomiędzy -π a π, wyrażony w radianach) między dwoma punktami w przestrzeni - w tym przypadku między pozycją myszki a środkiem okna gry.

Teraz czas na uzupełnienie metody Draw():
           spriteBatch.Begin();

            spriteBatch.DrawString(font, angle.ToString(), new Vector2(10, 10), Color.White);

            spriteBatch.End();
Czyli po prostu wyświetlamy obliczany na bieżąco kąt.

3. Klasa Target
Tworzymy nową klasę w pliku Target.cs:
   class Target
    {
        public Rectangle Rectangle;
        Color Color;
        BoundingBox BoundingBox;

        public Target(Rectangle rectangle,
                        Color color,
                        BoundingBox boundingBox)
        {
            Rectangle = rectangle;
            Color = color;
            BoundingBox = boundingBox;
        }

        public void Draw(SpriteBatch spriteBatch, Texture2D texture)
        {
            spriteBatch.Draw(texture, Rectangle, Color);
        }
    }
W tym przypadku zamiast stworzyć pole tektury w klasie, będziemy dostarczać ją jako argument metody Draw() (każdy obiekt będzie miał identyczną teksturę). BoundingBox omówię przy inicjalizacji obiektów stworzonej właśnie klasy, czyli za krótką chwilę.

4. Omówienie BoundingBoxów i uzupełnienie Game1.cs
Tworzymy nowe pole w Game1.cs i inicjalizujemy je w LoadContent():
       List<Target> targetList;            targetList = new List<Target>();W metodzie LoadContent() piszemy:
           for (int i = 0; i <= 9; i++)
            {
                int x = random.Next(0, 785);
                int y = random.Next(0, 465);

                Target target = new Target(new Rectangle(x, y, 32, 32), Color.White,
                                            new BoundingBox(new Vector3(x, y, 0), new Vector3(x + 16, y + 16, 0)));

                targetList.Add(target);
            }
Prawie wszystko powinno być zrozumiałe - losujemy liczby x oraz y, tworzymy nowy obiekt klasy Target i dodajemy go do listy. Kłopoty może sprawiać BoundingBox, a więc omówię go poniżej.

BoundingBox jest określany dwoma trójwymiarowymi wektorami - wyznaczają one minimalny oraz maksymalny punkt BoundingBoxa. Chociaż jest to obiekt trójwymiarowy, można go użyć w grach 2D, ustawiając wartość "z" obu wektorów na 0 (albo cokolwiek, ważne żeby wartość "z" wszystkich obiektów 3D była jednakowa).

Dzięki temu ustawieniu, nasz box ma 16 pikseli szerokości, 16 pikseli długości i 0 pikseli głębokości.

Wyświetlmy teraz stworzone obiekty. W tym celu dodajmy do metody Draw():
           foreach (Target target in targetList)
            {
                target.Draw(spriteBatch, texture);
            }

5. Ray - co to i po co
Do metody Update() dopiszmy:
           if (Mouse.GetState().LeftButton == ButtonState.Pressed && canShoot)
            {
                Ray ray = new Ray(new Vector3(center.X, center.Y, 0), new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0));
                canShoot = false;
            }

            if (Mouse.GetState().LeftButton == ButtonState.Released && !canShoot)
            {
                canShoot = true;
            }
Znów powinno być zrozumiałe wszystko oprócz nowości, którą w tym przypadku jest Ray. Ray jest linią, która rozpoczyna się w podanym punkcie przestrzeni i dąży w danym kierunku. W ten sposób są symulowane np. pociski w FPSach.

6. Kolizje między Rayem a BoundingBoxem
W tym tutorialu, przy trafieniu celu rayem będzie zmieniany jego kolor. Dopisujemy do Target.cs metodę:
       public Boolean CheckForRayCollisions(Ray ray, Random random)
        {
            float? collision;
            collision = ray.Intersects(BoundingBox);

            if (collision != null)
            {
                Color = new Color(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
                return true;
            }
            else
            {
                return false;
            }
        }
Metoda Ray.Intersects na pozór jest podobna do Rectangle.Intersects, jednak ta druga zwraca wartość boolean, a pierwsza wartość float?. Znak zapytania po float to skrót: float? to to samo co Nullable<float>. Wartością zwracaną przez Ray.Intersects jest długość raya podczas kolizji z jakimkolwiek BoundingBoxem, BoundingSphere'em lub BoundingFrustrumem. Można to łatwo przekształcić na booleana - jeśli kolizja następuje, wartość zmiennej collision jest różna od null.

Teraz należy zaktualizować Game1.cs. W metodzie Update() pod kodem odpowiadającym za wysyłanie raya wpisujemy:
               foreach (Target target in targetList)
                {
                    if (target.CheckForRayCollisions(ray, random))
                    {
                        break;
                    }
                }
Jeśli zostaje wykryta kolizja, wybijamy się z pętli (nie chcemy trafiać wielu celów naraz).

7. Sortowanie list
Przy odpaleniu gierki można zobaczyć problem. Jeśli na drodze raya stoją dwa cele, kolorowany jest ten leżący wyżej w indeksie listy - nie ten, który jest najbliżej środka okna. Żeby to poprawić, trzeba posortować listę. W tym celu dodajemy nowe pole do klasy Target:
       public float DistanceToCenter;W Game1.cs w metodzie LoadContent() aktualizujemy kod inicjalizacji celów. Nad poleceniem dodania obiektu do listy dopisujemy:                                        
               target.DistanceToCenter = Vector2.Distance(new Vector2(center.X, center.Y),
                                                            new Vector2(target.Rectangle.Center.X, target.Rectangle.Center.Y));
Dzięki temu mamy coś, według czego możemy sortować listę obiektów klasy Target. Teraz należy przystosować samą klasę do bycia sortowaną:
   class Target : IComparable<Target>
    {
Dzięki temu możemy wprowadzić sortowanie z użyciem IComparable. Teraz do klasy należy dodać nową metodę:
       public int CompareTo(Target other)
        {
            return this.DistanceToCenter.CompareTo(other.DistanceToCenter);
        }
Teraz mamy jak posortować obiekty. W Game1.cs pod pętlą for, w której tworzymy cele dopisujemy:
           targetList.Sort();
Posłowie
Tego by było na tyle. Jeśli macie jakieś pytania lub uwagi, piszcie na PW albo w temacie.

Źródło projektu z tutoriala: https://dl.dropbox.com/u/67704253/Xna%20Tutorial/3/source3.zip
 


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry