Một cách tuyệt vời để làm Z-index cho các thành phần XNA?


7

Tôi đang cố gắng để kết xuất một số yếu tố trong trò chơi của tôi. Đầu tiên, tôi kết xuất họa tiết (kết cấu của chính các hộp văn bản, v.v.). Sau đó, tôi kết xuất các nguyên thủy (viền xung quanh các điều khiển, v.v.). Sau đó, tôi kết xuất văn bản.

Tuy nhiên, bằng cách đó, điều này mang lại một kết quả kỳ lạ trong giao diện người dùng của tôi khi hiển thị các chú giải công cụ (bằng cách di chuột qua một trường văn bản), như trong ảnh chụp màn hình bên dưới.

Ảnh chụp màn hình

Do thứ tự vẽ, các đường viền xung quanh cửa sổ được vẽ sau khi kết cấu, mà (đối với chú giải công cụ xuất hiện khi chuột của tôi ở trên trường văn bản) làm cho nó trông lạ.

Câu trả lời:


6

Nếu mỗi cái này là riêng biệt DrawableGameComponents, bạn nên đặt thuộc DrawOrdertính của từng thành phần để chúng vẽ theo đúng thứ tự.

Để làm cho nó dễ quản lý hơn khi bạn thêm nhiều thành phần, DrawOrdernên là enum:

/* DisplayLayer.cs */
public enum DisplayLayer
{
    Background, //back-layer
    Particles,
    Player,
    MenuBack,
    MenuFront //front-layer
}

public class MyComponent : DrawableGameComponent
{
    public MyComponent(Game game) : base(game)
    {
        this.DrawOrder = (int)DisplayLayer.Background;
    }

    /* etc. */
}

Nếu tất cả điều này được rút ra trong một lần duy nhất DrawableGameComponent, thì bạn nên nghe lời khuyên của @ Andrew và chỉ cần vẽ chúng theo đúng thứ tự. Nếu vì lý do nào đó bạn không thể làm điều đó, bạn vẫn có thể có sự rõ ràng của enums khi sử dụng bằng layerDepthcách đơn giản hóa giá trị của giá trị enumnằm trong khoảng từ 0 đến 1:

/* DisplayLayer.cs */
public enum DisplayLayer
{
    MenuFront, //front-layer
    MenuBack,
    Player,
    Particles,
    Background, //back-layer
    MAX_LAYER   //Do not use this as a layer
}

public void Draw()
{
    spriteBatch.Begin(SpriteSortMode.BackToFront);
    foreach(Thingy thingy in thingys)
        spriteBatch.Draw(/* blah blah */, (float)thingy.DisplayLayer/(float)DisplayLayer.MAX_LAYER);
    spriteBatch.End();
}

(Thứ tự của enumđảo ngược vì layerDepthsử dụng số thấp hơn cho lớp trước thay vì lớp sau)


6

http://msdn.microsoft.com/en-us/l Library / ff433989.aspx

public void Draw (
         Texture2D texture,
         Vector2 position,
         Nullable<Rectangle> sourceRectangle,
         Color color,
         float rotation,
         Vector2 origin,
         Vector2 scale,
         SpriteEffects effects,
         float layerDepth
)


layerDepth Độ sâu của một lớp. Theo mặc định, 0 đại diện cho lớp phía trước và 1 đại diện cho lớp phía sau. Sử dụng SpriteSortMode nếu bạn muốn các họa tiết được sắp xếp trong khi vẽ.
Ví dụ bạn có: Mẫu, và trong nhãn thức, các nút
Vì vậy, cho các yếu tố con bạn có thể thêm vào layerDepth một số giá trị
Ví dụ: Mẫu A có con: Mẫu số B và một số nút, Mẫu số B chỉ có nút
Mẫu A - 1,0
Buttons trong mẫu A - 1,5
Mẫu B trong Mẫu A - 1.5
Nút ở dạng B - 2

Đối với Hộp thoại - bạn có thể lưu trữ một số giá trị lớn hơn


4
Một vài lưu ý cho phương pháp này: phạm vi hợp lệ của layerDepth(tôi khá chắc chắn) là 0 đến 1, vì vậy bạn phải ở trong phạm vi đó. Ngoài ra, tất cả các bản vẽ sẽ cần phải được thực hiện trong một đợt sprite (giữa BeginEnd). Cuối cùng: điều đáng nói là phương pháp này không mang lại lợi ích hiệu suất nào hơn là chỉ đơn giản là vẽ mọi thứ theo đúng thứ tự ngay từ đầu.
Andrew Russell

6

Tôi sẽ đưa ra câu trả lời đơn giản và khá rõ ràng, và đó chỉ là vẽ mọi thứ theo đúng thứ tự ngay từ đầu .

Để mô phỏng một ví dụ về những gì tôi muốn nói:

// Assuming you have sorted windowList by Z-order, using one of the many
// existing sorting mechanisms provided by the framework such as List<T>.Sort().
foreach(var window in windowList)
    window.Draw();

// in your Window class:
public void Draw()
{
    this.DrawBackground();
    this.DrawBorders();
    this.DrawText();
}

Có một lý do cụ thể, thuyết phục nào khiến bạn không vẽ các cửa sổ của mình theo cách này không?


Tôi đoán rằng, như anh ta nói trong câu hỏi của mình, đó là bởi vì anh ta đang thực hiện cả SpriteBatch và các cuộc gọi nguyên thủy, và do đó anh ta muốn kết hợp chúng lại với nhau, đó không thực sự là một ý tưởng tồi. Tôi dường như nhớ lại rằng ngay cả như vậy, SpriteBatch sẽ thực hiện tất cả các cuộc gọi dù thế nào đi nữa, vì vậy tôi khá chắc chắn rằng tùy chọn tham quan sẽ là cùng một sự khôn ngoan hoàn hảo. Nó cũng có ý nghĩa hơn.
Jonathan Connell

@ 3nixios Tôi đoán lý do của anh ấy là vì hiệu suất quá - nhưng sau đó tôi ngay lập tức đề nghị rằng đó là tối ưu hóa sớm. Là GUI của anh ấy thực sự hoạt động rất tệ? Và việc hợp nhất các lô có thực sự là lựa chọn tối ưu chính xác? Cũng SpriteBatchkhông thể hàng loạt thay đổi kết cấu - vì vậy phương pháp của tôi có khả năng chậm hơn phương thức của anh ấy nếu việc triển khai của anh ấy được tối ưu hóa đúng cách.
Andrew Russell

Và phương pháp của anh ấy là khả thi - nhân tiện. Nhưng thật khó để thực hiện chính xác - bao gồm cả việc hình thành nó thành một câu trả lời hay. Vì vậy, nó có thể không xứng đáng với nỗ lực đạt được hiệu suất nhỏ - và do đó nó sẽ là câu trả lời sai. (Phiên bản ngắn là: sử dụng bộ đệm Z.)
Andrew Russell

Tôi hoàn toàn đồng ý :)
Jonathan Connell

Tôi không làm theo lý do tại sao cách tiếp cận trên ngăn cản bạn SpriteBatchgộp tất cả các hoạt động của mình lại với nhau. Chỉ cần sửa đổi các phương thức vẽ để chấp nhận SpriteBatchnhư là một tham số. Sau đó, trong phương thức "Vẽ" cơ bản nhất, cuộc gọi đầu tiên SpriteBatch.Begin()- sau đó gọi "Vẽ" trên Windows (chuyển vàoSpriteBatch , chúng sẽ sử dụng và truyền vào từng đứa trẻ) - sau đó là vòng lặp, trong hầu hết các cơ sở Phương pháp "Vẽ", gọi SpriteBatch.End(). . . (0,02 đô la của tôi: Tôi cá là anh ấy không sử dụng đồ vật và toàn bộ có lẽ là một mớ hỗn độn về thủ tục trong Gamelớp chính của anh ấy .)
BrainSlugs83
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.