2011-02-09 12 views
5

Mam więc tę klasę paneli. To trochę jak okno, w którym można zmienić rozmiar, zamknąć, dodać przyciski, suwaki itp. Podobnie jak ekran stanu w Morrowind, jeśli któryś z was pamięta. Zachowanie, którego pragnę, polega na tym, że gdy duszek znajduje się poza granicami panelu, nie zostaje wyciągnięty, a jeśli jest częściowo na zewnątrz, tylko część wewnątrz zostanie narysowana. Więc to, co teraz robi, to najpierw prostokąt, który reprezentuje granice panelu, a prostokąt dla sprite'a, znajduje prostokąt przecięcia między tymi dwoma, a następnie tłumaczy to przecięcie na lokalne współrzędne prostokąta i używa dla tego prostokąta źródłowego:. Działa i jest tak inteligentny, jak uważam, że kod jest nieporozumieniem, że istnieje lepszy sposób na zrobienie tego. Ponadto, przy tej konfiguracji nie mogę wykorzystać globalnej macierzy transformacji dla mojej kamery 2D, wszystko w "świecie" musi zostać przekazane argumentowi kamery do narysowania. Tak czy inaczej, oto kod mam:
na skrzyżowaniu:Jak wykonać obcinanie na obróconych prostokątach?

 public static Rectangle? Intersection(Rectangle rectangle1, Rectangle rectangle2) 
    { 
     if (rectangle1.Intersects(rectangle2)) 
     { 
      if (rectangle1.Contains(rectangle2)) 
      { 
       return rectangle2; 
      } 
      else if (rectangle2.Contains(rectangle1)) 
      { 
       return rectangle1; 
      } 
      else 
      { 
       int x = Math.Max(rectangle1.Left, rectangle2.Left); 
       int y = Math.Max(rectangle1.Top, rectangle2.Top); 
       int height = Math.Min(rectangle1.Bottom, rectangle2.Bottom) - Math.Max(rectangle1.Top, rectangle2.Top); 
       int width = Math.Min(rectangle1.Right, rectangle2.Right) - Math.Max(rectangle1.Left, rectangle2.Left); 
       return new Rectangle(x, y, width, height); 
      } 
     } 
     else 
     { 
      return null; 
     } 
    } 

i faktycznie rysowania na panelu:

public void DrawOnPanel(IDraw sprite, SpriteBatch spriteBatch) 
    { 
     Rectangle panelRectangle = new Rectangle(
      (int)_position.X, 
      (int)_position.Y, 
      _width, 
      _height); 
     Rectangle drawRectangle = new Rectangle(); 

     drawRectangle.X = (int)sprite.Position.X; 
     drawRectangle.Y = (int)sprite.Position.Y; 
     drawRectangle.Width = sprite.Width; 
     drawRectangle.Height = sprite.Height; 

     if (panelRectangle.Contains(drawRectangle)) 
     { 
      sprite.Draw(
       spriteBatch, 
       drawRectangle, 
       null); 
     } 
     else if (Intersection(panelRectangle, drawRectangle) == null) 
     { 
      return; 
     } 
     else if (Intersection(panelRectangle, drawRectangle).HasValue) 
     { 
      Rectangle intersection = Intersection(panelRectangle, drawRectangle).Value; 

      if (Intersection(panelRectangle, drawRectangle) == drawRectangle) 
      { 
       sprite.Draw(spriteBatch, intersection, intersection); 
      } 
      else 
      { 
       sprite.Draw(
        spriteBatch, 
        intersection, 
        new Rectangle(
         intersection.X - drawRectangle.X, 
         intersection.Y - drawRectangle.Y, 
         intersection.Width, 
         intersection.Height)); 
      } 
     } 
    } 

więc myślę, że moje pytanie jest, czy istnieje lepszy sposób to zrobić to?

Aktualizacja: Właśnie się dowiedziałem o właściwości ScissorRectangle. Wydaje się, że to dobry sposób na zrobienie tego; wymaga on utworzenia obiektu RasterizerState i przekazania go do obciążenia spritebatch.Begin, które je akceptuje. Wydaje się jednak, że to może być najlepszy zakład. Jest tam także Viewport, który mogę najwyraźniej zmienić. Myśli? :)

+0

Proponuję użyć bardziej jednoznacznego sformułowania w pytaniu, coś w stylu "Jak wykonać obcinanie na obróconych prostokątach?". – Joh

+0

Och, wow, nawet nie myślałem o rotacji. Dzięki –

Odpowiedz

1

Istnieje kilka sposobów na ograniczenie rysunku do części ekranu. Jeśli obszar jest prostokątny (co wydaje się być tutaj w tym przypadku), można ustawić widok (patrz GraphicsDevice) na powierzchni panelu.

W przypadku obszarów nieprostokątnych można użyć bufora szablonu lub użyć niektórych sztuczek z buforem głębi. Narysuj kształt powierzchni w buforze szablonu lub buforze głębi, ustaw stan renderowania tak, aby rysował tylko piksele znajdujące się w kształcie, który właśnie wyrenderowałeś w buforze szablonu/głębi, a następnie wyrenderuj twoje sprite'y.

1

Jednym ze sposobów jest kolizja w trybie prostym na piksel. Chociaż jest to zły pomysł, jeśli sprite są duże lub liczne, może to być bardzo łatwy i szybki sposób, aby wykonać zadanie za pomocą małych duszków. Najpierw należy wykonać krąg ograniczający lub sprawdzenie kolizyjnego prostokąta kwadratowego względem panelu, aby sprawdzić, czy konieczne jest nawet wykrywanie piksela.

Następnie utwórz metodę zawierającą, która sprawdza, czy pozycja, skala i obrót duszka układają się tak głęboko w panelu, że muszą być całkowicie zamknięte przez panel, więc nie potrzebujesz kolizji na piksel. w tym wypadku. Można to zrobić całkiem łatwo, po prostu tworząc kwadrat ograniczający, który ma szerokość i wysokość długości przekątnej sprite'a i sprawdzając, czy nie ma kolizji z tym.

Wreszcie, jeśli oba te elementy zawiodą, musimy wykonać kolizję na piksel. Przejrzyj i sprawdź każdy piksel w ikonce, aby zobaczyć, czy znajduje się w granicach panelu. Jeśli nie jest ustawiony, wartość alfa piksela na 0.

To wszystko.

Powiązane problemy