Làm thế nào để đối phó với hình ảnh lớn tùy ý trong các trò chơi 2D?


13

Câu hỏi

Khi bạn có một trò chơi 2D sử dụng hình ảnh thực sự lớn (lớn hơn phần cứng của bạn có thể hỗ trợ), bạn sẽ làm gì? Có lẽ có một số giải pháp thú vị cho vấn đề này chưa từng xảy ra với tôi trước đây.

Về cơ bản tôi đang làm việc trên một loại nhà sản xuất trò chơi phiêu lưu đồ họa. Đối tượng mục tiêu của tôi là những người có ít hoặc không có kinh nghiệm phát triển trò chơi (và lập trình). Nếu bạn đang làm việc với một ứng dụng như vậy, bạn sẽ không thích nó xử lý vấn đề bên trong hơn là bảo bạn "chia nhỏ hình ảnh của bạn" chứ?

Bối cảnh

Người ta biết rằng card đồ họa áp đặt một loạt các hạn chế về kích thước của họa tiết mà họ có thể sử dụng. Chẳng hạn, khi làm việc với XNA, bạn bị giới hạn ở kích thước kết cấu tối đa là 2048 hoặc 4096 pixel tùy thuộc vào cấu hình bạn chọn.

Thông thường, điều này không gây ra nhiều vấn đề trong các trò chơi 2D vì hầu hết trong số chúng có các cấp độ có thể được xây dựng từ các mảnh nhỏ hơn (ví dụ: gạch hoặc các họa tiết biến đổi).

Nhưng hãy nghĩ về một vài trò chơi phiêu lưu đồ họa cổ điển (ví dụ Đảo Khỉ). Các phòng trong các trò chơi phiêu lưu đồ họa thường được thiết kế tổng thể, với rất ít hoặc không có phần lặp lại, giống như một họa sĩ làm việc trên một phong cảnh. Hoặc có lẽ là một trò chơi như Final Fantasy 7 sử dụng nền tảng kết xuất sẵn lớn.

Một số trong những phòng này có thể có kích thước khá lớn, thường xuyên trải rộng từ ba màn hình trở lên. Bây giờ nếu chúng ta xem xét các nền tảng này trong bối cảnh của một trò chơi độ nét cao hiện đại, chúng sẽ dễ dàng vượt quá kích thước kết cấu được hỗ trợ tối đa.

Bây giờ, giải pháp rõ ràng cho vấn đề này là chia nền thành các phần nhỏ hơn phù hợp với yêu cầu và vẽ chúng cạnh nhau. Nhưng bạn có nên (hoặc nghệ sĩ của bạn) phải là người chia tách tất cả các kết cấu của bạn?

Nếu bạn đang làm việc với API cấp cao, có lẽ không nên chuẩn bị để xử lý tình huống này và thực hiện phân tách và lắp ráp các kết cấu bên trong (như là một quy trình trước như Đường ống nội dung của XNA hoặc trong thời gian chạy)?

Biên tập

Đây là những gì tôi đã nghĩ, từ quan điểm thực hiện XNA.

Công cụ 2D của tôi chỉ yêu cầu một tập hợp con rất nhỏ của chức năng Texture2D. Tôi thực sự có thể giảm nó xuống giao diện này:

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

Phương thức bên ngoài duy nhất tôi sử dụng dựa trên Texture2D là SpriteBatch.Draw () để tôi có thể tạo cầu nối giữa chúng bằng cách thêm phương thức mở rộng:

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

Điều này sẽ cho phép tôi sử dụng ITexture thay thế cho nhau bất cứ khi nào tôi sử dụng Texture2D trước đó.

Sau đó, tôi có thể tạo ra hai triển khai khác nhau của ITexture, ví dụ: Chính quy và Công cụ lớn, trong đó Chính quy đơn giản sẽ bao bọc một Texture2D thông thường.

Mặt khác, LargeTexture sẽ giữ một Danh sách của Texture2D tương ứng với một trong những mảnh được tách ra của hình ảnh đầy đủ. Phần quan trọng nhất là việc gọi Draw () trên LargeTexture sẽ có thể áp dụng tất cả các phép biến đổi và vẽ tất cả các phần như thể chúng chỉ là một hình ảnh liền kề nhau.

Cuối cùng, để làm cho toàn bộ quá trình trở nên trong suốt, tôi sẽ tạo một lớp trình tải kết cấu hợp nhất sẽ hoạt động như một Phương thức xuất xưởng. Nó sẽ lấy đường dẫn của kết cấu làm tham số và trả về một ITexture có thể là một Kiểu thông thường hoặc LargeTexture tùy thuộc vào kích thước hình ảnh vượt quá giới hạn hay không. Nhưng người dùng không cần biết đó là cái gì.

Một chút quá mức hoặc nó có vẻ ổn?


1
Chà, nếu bạn muốn thực hiện việc chia nhỏ hình ảnh, hãy mở rộng Đường ống nội dung để thực hiện việc đó theo chương trình. Không phải tất cả các chức năng tồn tại để bao gồm mọi kịch bản đơn lẻ và đến một lúc nào đó bạn sẽ phải tự mở rộng nó. Chia tách âm thanh cá nhân giống như giải pháp đơn giản nhất, khi đó bạn có thể xử lý các loại hình ảnh giống như bản đồ ô vuông, có rất nhiều tài nguyên trên đó.
DMan

Làm điều đó trên các đường ống nội dung là cách tiếp cận hợp lý nhất. Nhưng trong trường hợp của tôi, tôi cần tải hình ảnh của mình khi chạy và tôi đã tìm ra giải pháp thời gian chạy (đó là lý do tại sao tôi đã hỏi câu hỏi này ngày hôm qua). Nhưng vẻ đẹp thực sự đến từ việc lấy "bản đồ gạch" này và khiến nó hoạt động như một kết cấu bình thường. Tức là bạn vẫn có thể chuyển nó sang spritebatch để vẽ và bạn vẫn có thể chỉ định vị trí, góc quay, tỷ lệ, hình chữ nhật src / Dest, v.v ... Bây giờ tôi mới đi được nửa đường :)
David Gouveia

Nhưng sự thật mà nói, tôi đã ở một thời điểm mà tôi tự hỏi liệu tất cả những gì thực sự có giá trị hay tôi chỉ nên đưa ra cảnh báo cho người dùng nói với anh ta rằng kích thước hình ảnh được hỗ trợ tối đa là 2048x2048 và được thực hiện với nó.
David Gouveia

Nó thực sự phụ thuộc vào bạn về thiết kế. Nếu bạn hoàn thành dự án và bạn không thể cuộn giữa các phòng thì sẽ tốt hơn nếu không hoàn thành trình chỉnh sửa cho phép bạn cuộn các kết cấu lớn: D
Aleks

Ẩn nó trong API nghe có vẻ là một cách hay để làm cho cuộc sống của các tác giả trò chơi dễ dàng hơn. Có lẽ tôi sẽ triển khai nó trong các lớp Đa giác (sprite) và Texture, và không phải trường hợp đặc biệt là các hình ảnh nhỏ hơn, mà chỉ làm cho chúng thành một ô có kích thước 1x1. Vì vậy, lớp kết cấu là một nhóm kết cấu mô tả tất cả các ô và có bao nhiêu hàng / cột. Sau đó, lớp Polygon xem xét thông tin này để tự phân tách và vẽ từng ô với kết cấu phù hợp. Theo cách đó, nó cùng một lớp. Điểm thưởng nếu lớp sprite của bạn chỉ vẽ các ô hiển thị và các nhóm kết cấu không tải họa tiết cho đến khi cần.
uliwitness

Câu trả lời:


5

Tôi nghĩ rằng bạn đang đi đúng hướng. Bạn phải chia hình ảnh thành các mảnh nhỏ hơn. Vì bạn làm nhà sản xuất trò chơi, bạn không thể sử dụng đường dẫn Nội dung của XNA. Trừ khi nhà sản xuất của bạn giống như một Công cụ vẫn sẽ yêu cầu các nhà phát triển sử dụng Visual Studio. Vì vậy, bạn cần xây dựng các thói quen của riêng bạn sẽ thực hiện việc chia tách. Bạn thậm chí nên xem xét phát trực tuyến các mảnh một chút trước khi nó trở nên rõ ràng để bạn vẫn không đặt giới hạn số lượng bộ nhớ video mà người chơi nên có.

Có một số thủ thuật bạn có thể làm đặc biệt cho các trò chơi phiêu lưu. Tôi tưởng tượng giống như tất cả các trò chơi phiêu lưu cổ điển, bạn sẽ có một vài lớp họa tiết này để ... nhân vật của bạn có thể đi sau cái cây hoặc tòa nhà ...

Nếu bạn muốn các lớp này có hiệu ứng paralaxing thì khi bạn tách gạch của bạn chỉ cần bỏ qua tất cả các mờ một lần. Ở đây bạn cần nghĩ về kích thước của gạch. Các ô nhỏ hơn sẽ thêm quản lý chi phí và thực hiện các cuộc gọi, nhưng sẽ ít dữ liệu hơn trong đó các ô lớn hơn sẽ thân thiện với GPU hơn nhưng sẽ có nhiều độ trong mờ.

Nếu bạn không có hiệu ứng làm tê liệt thì thay vì bao phủ toàn bộ cảnh bằng 2-4 hình ảnh khổng lồ có độ sâu 32 bit, bạn có thể tạo chỉ một độ sâu 32 bit. Và bạn có thể có một lớp stenciling hoặc độ sâu sẽ chỉ có 8 bit cho mỗi pixel.

Tôi biết điều này nghe có vẻ khó quản lý tài sản của các nhà phát triển trò chơi nhưng thực tế không phải như vậy. Ví dụ: nếu bạn có một con đường có 3 cây và người chơi đi sau 2 trong số chúng và phía trước cây thứ ba và phần còn lại của nền ... Chỉ cần tạo bố cục cảnh theo cách bạn muốn trong trình chỉnh sửa của mình và sau đó trong một xây dựng bước từ nhà sản xuất trò chơi của bạn, bạn có thể nướng những hình ảnh khổng lồ này (những viên gạch nhỏ của một hình ảnh lớn).

Về cách các trò chơi cổ điển đã làm điều đó. Tôi không chắc họ có thể đã thực hiện các thủ thuật tương tự nhưng bạn phải nhớ rằng tại thời điểm màn hình là 320x240, các trò chơi có 16 màu mà khi sử dụng họa tiết palattelized cho phép bạn mã hóa 2 pixel trong một byte. Nhưng đây không phải là cách các kiến ​​trúc hiện tại hoạt động như vậy: D

Chúc may mắn


Cảm ơn, rất nhiều ý tưởng rất thú vị ở đây! Tôi thực sự đã thấy kỹ thuật lớp stprint được sử dụng trước đây trong Adventure Game Studio. Đối với ứng dụng của tôi, tôi đang làm mọi thứ hơi khác một chút. Phòng không nhất thiết phải có một hình nền. Thay vào đó, có một bảng hình ảnh mà người dùng đã nhập và lớp nền / tiền cảnh. Người dùng có thể tự do kéo và thả các mảnh vào phòng để tạo ra nó. Vì vậy, nếu anh ta muốn, anh ta cũng có thể sáng tác ra những mảnh nhỏ hơn mà không cần phải tạo ra các đối tượng trò chơi không tương tác. Mặc dù không có thị sai, vì chỉ có hai lớp đó.
David Gouveia

Và tôi đã xem các tệp dữ liệu cho Monkey Island Special Edition (bản làm lại của HQ). Mỗi nền được chia thành chính xác 1024x1024 mảnh (ngay cả khi một phần lớn của hình ảnh không được sử dụng). Dù sao, hãy kiểm tra chỉnh sửa của tôi để biết những gì trong tâm trí để làm cho toàn bộ quá trình minh bạch.
David Gouveia

Tôi có thể sẽ chọn một cái gì đó hợp lý hơn như 256x256. Bằng cách này, tôi sẽ không lãng phí tài nguyên và nếu sau đó quyết định triển khai phát trực tuyến, nó sẽ tải các khối hợp lý hơn. Có thể tôi đã không giải thích nó đủ tốt nhưng tôi đề nghị bạn có thể nướng tất cả các đối tượng trò chơi tĩnh nhỏ này thành kết cấu lớn. Những gì bạn sẽ lưu là, trong trường hợp bạn có kết cấu nền lớn, tất cả các pixel được bao phủ bởi các đối tượng tĩnh ở trên.
Aleks

Tôi thấy, do đó, hợp nhất tất cả các đối tượng tĩnh vào nền, sau đó phân tách và tạo một tập bản đồ kết cấu. Tôi cũng có thể nướng mọi thứ khác vào tập bản đồ kết cấu theo lối suy nghĩ đó. Đó cũng là một ý tưởng hay. Nhưng tôi sẽ để nó lại sau, vì hiện tại tôi không có bất kỳ bước "xây dựng" nào, tức là cả trình soạn thảo và ứng dụng khách trò chơi đều chạy trên cùng một công cụ và cùng định dạng dữ liệu.
David Gouveia

Tôi thích cách tiếp cận stprint nhưng nếu tôi làm trình chỉnh sửa trò chơi phiêu lưu thì có lẽ tôi sẽ không sử dụng nó ... Có lẽ bởi vì nếu tôi xây dựng công cụ như vậy tôi sẽ dành cho các nhà phát triển trò chơi. Vâng, nó có ưu và nhược điểm. Ví dụ, bạn có thể sử dụng một hình ảnh khác mà trên đó các bit có thể xác định các kích hoạt trên mỗi pixel hoặc nếu bạn có một số hoạt hình nước, bạn có thể dễ dàng khắc nó ra. Lưu ý: Một đề xuất không liên quan kỳ lạ nhìn vào sơ đồ Trạng thái / Hoạt động của UML cho tập lệnh của bạn.
Aleks

2

Cắt chúng ra để chúng không còn lớn tùy ý, như bạn nói. Không có phép thuật. Những trò chơi 2D cũ đó đã làm điều đó hoặc chúng được kết xuất trong phần mềm, trong trường hợp đó không có giới hạn phần cứng nào ngoài kích thước RAM. Đáng chú ý là nhiều trò chơi 2D thực sự không có nền tảng lớn, chúng chỉ cuộn chậm để cảm thấy rất lớn.

Những gì bạn đang muốn làm trong nhà sản xuất trò chơi phiêu lưu đồ họa của bạn là xử lý trước những hình ảnh lớn đó trong một số bước "xây dựng" hoặc "tích hợp" trước khi trò chơi được đóng gói để chạy.

Nếu bạn muốn sử dụng API và thư viện hiện có thay vì tự viết, tôi khuyên bạn nên chuyển đổi những hình ảnh lớn đó thành các ô trong quá trình "xây dựng" đó và sử dụng công cụ gạch 2D, trong đó có nhiều công cụ.

Nếu bạn muốn sử dụng các kỹ thuật 3D của riêng mình, bạn vẫn có thể muốn chia thành các ô và sử dụng API 2D được thiết kế tốt và nổi tiếng để viết thư viện 3D của riêng bạn cho điều đó, theo cách này, bạn được đảm bảo ít nhất là bắt đầu với một thiết kế API tốt và ít thiết kế hơn yêu cầu từ phía bạn.


Làm điều đó vào thời gian xây dựng sẽ rất lý tưởng ... Nhưng trình soạn thảo của tôi cũng sử dụng XNA để kết xuất, nó không chỉ là công cụ. Điều đó có nghĩa là một khi người dùng nhập hình ảnh và kéo nó vào một căn phòng, XNA sẽ có thể hiển thị nó. Vì vậy, dillema lớn của tôi là liệu thực hiện phân tách trong bộ nhớ khi tải nội dung, hoặc trên đĩa khi nhập nội dung. Ngoài ra, việc chia nhỏ hình ảnh thành nhiều tệp có nghĩa là tôi sẽ cần một cách để lưu trữ những thứ này một cách khác nhau, trong khi thực hiện nó trong bộ nhớ trong thời gian chạy sẽ không yêu cầu bất kỳ thay đổi nào đối với các tệp dữ liệu của trò chơi.
David Gouveia

1

Nếu bạn quen thuộc với cách một hình tứ giác trong thực tế trực quan, tôi đã sử dụng một phương pháp cắt các hình ảnh lớn chi tiết thành các hình ảnh nhỏ tương đối giống với hình ảnh chứng minh / hình ảnh của một hình tứ giác. Tuy nhiên, tôi đã làm theo cách đó để cắt các khu vực cụ thể có thể được mã hóa hoặc nén khác nhau dựa trên màu sắc. Bạn có thể sử dụng phương pháp này và làm những gì tôi mô tả, vì nó cũng hữu ích.

Trong thời gian chạy, việc cắt chúng sẽ tạm thời cần thêm bộ nhớ và khiến thời gian tải bị chậm lại. Tôi sẽ nói mặc dù điều đó phụ thuộc vào việc bạn quan tâm nhiều hơn đến bộ nhớ vật lý hay thời gian tải của trò chơi người dùng được thực hiện với trình chỉnh sửa của bạn.

Thời gian tải / chạy: Cách mà tôi sẽ tiến hành tải chỉ là cắt nó thành các mảnh có kích thước tương ứng. Tuy nhiên, tài khoản cho một pixel ở hầu hết các pixel nếu đó là số pixel lẻ, không ai thích hình ảnh của họ bị cắt, đặc biệt là những người dùng thiếu kinh nghiệm có thể không biết rằng nó không hoàn toàn phụ thuộc vào họ. Làm cho chúng một nửa chiều rộng HOẶC một nửa chiều cao (hoặc thứ 3, thứ 4 bất kể) lý do không thành hình vuông hoặc 4 phần (2 hàng 2 cột) là vì nó sẽ làm cho bộ nhớ lát gạch nhỏ hơn vì bạn sẽ không lo lắng về cả x và y cùng một lúc (và tùy thuộc vào số lượng hình ảnh lớn như vậy, nó có thể khá quan trọng)

Trước khi ra tay / Tự động: Trong trường hợp này, tôi thích ý tưởng cho người dùng lựa chọn lưu trữ nó trong một hình ảnh hoặc lưu trữ dưới dạng các phần riêng biệt (một hình ảnh nên được mặc định). Lưu trữ hình ảnh dưới dạng .gif sẽ hoạt động rất tốt. Hình ảnh sẽ nằm trong một tệp, và thay vì mỗi khung hình là một hình ảnh động, nó sẽ giống như một kho lưu trữ nén của tất cả cùng một hình ảnh (về cơ bản là cái mà một .gif là gì). Nó sẽ cho phép dễ dàng vận chuyển tệp vật lý, dễ tải:

  1. Đó là một tập tin duy nhất
  2. Tất cả các tệp sẽ có định dạng gần như giống hệt nhau
  3. Bạn có thể dễ dàng chọn thời điểm VÀ nếu cắt nó thành các kết cấu riêng lẻ
  4. Có thể dễ dàng truy cập các hình ảnh riêng lẻ hơn nếu chúng đã ở trong một tệp .gif được tải vì nó sẽ không yêu cầu nhiều tập tin hình ảnh trong bộ nhớ

Ồ và nếu bạn sử dụng phương thức .gif, bạn nên thay đổi phần mở rộng tệp thành một thứ khác (.gif -> .kittens) để bớt nhầm lẫn khi .gif của bạn hoạt hình giống như một tệp bị hỏng. (đừng lo lắng về tính hợp pháp của điều đó, .gif là một định dạng mở)


Xin chào và cảm ơn bạn đã bình luận của bạn! Xin lỗi nếu tôi hiểu nhầm nhưng không phải là những gì bạn viết chủ yếu liên quan đến nén và lưu trữ? Trong trường hợp này, tất cả những gì tôi thực sự lo lắng là người dùng ứng dụng của tôi có thể nhập bất kỳ hình ảnh nào và công cụ (trong XNA) có khả năng tải và hiển thị bất kỳ hình ảnh nào khi chạy . Tôi đã quản lý để giải quyết nó đơn giản bằng cách sử dụng GDI để đọc các phần khác nhau của hình ảnh thành các Kết cấu XNA riêng biệt và bọc chúng trong một lớp hoạt động giống như một kết cấu thông thường (nghĩa là hỗ trợ vẽ và biến đổi toàn bộ).
David Gouveia

Nhưng vì tò mò, bạn có thể giải thích thêm về tiêu chí nào bạn đã sử dụng để chọn khu vực nào của hình ảnh đi vào từng phần không?
David Gouveia

Một số có thể nằm trên đầu bạn nếu bạn ít kinh nghiệm xử lý hình ảnh. Nhưng về cơ bản, tôi đã mô tả việc cắt hình ảnh thành các phân đoạn. Và đúng vậy, điểm .gif đã mô tả cả lưu trữ và tải, nhưng nó có nghĩa là một phương pháp để bạn cắt hình ảnh, và sau đó lưu trữ nó trên máy tính. Nếu bạn lưu nó dưới dạng gif tôi đã nói rằng bạn có thể cắt nó thành các hình ảnh riêng lẻ, sau đó lưu nó dưới dạng gif hoạt hình, với mỗi lần cắt hình ảnh được lưu thành các khung hình động riêng biệt. Nó hoạt động tốt và tôi thậm chí đã thêm các tính năng khác mà nó có thể giúp đỡ.
Joshua Hedges

Hệ thống tứ giác như tôi mô tả hoàn toàn được nêu là một tài liệu tham khảo, vì đó là nơi tôi có ý tưởng từ đó. Mặc dù thay vì tập trung một câu hỏi có thể sử dụng được cho những độc giả có thể gặp vấn đề tương tự, chúng ta nên sử dụng tin nhắn riêng nếu bạn muốn biết thêm.
Joshua Hedges

Roger, tôi có một phần về việc sử dụng các khung GIF làm kho lưu trữ các loại. Nhưng tôi cũng tự hỏi, không phải GIF là một định dạng được lập chỉ mục với bảng màu hạn chế sao? Tôi chỉ có thể lưu trữ toàn bộ hình ảnh RGBA 32bpp trong mỗi khung hình? Và tôi tưởng tượng quá trình tải nó kết thúc thậm chí còn phức tạp hơn, vì XNA không hỗ trợ điều này.
David Gouveia

0

Điều này sẽ nghe có vẻ rõ ràng, nhưng, tại sao không chia phòng của bạn thành những mảnh nhỏ hơn? Chọn một kích thước tùy ý sẽ không va đầu vào bất kỳ card đồ họa nào (như 1024x1024, hoặc có thể lớn hơn) và chỉ phá vỡ các phòng của bạn thành nhiều mảnh.

Tôi biết rằng điều này tránh được vấn đề, và thành thật mà nói, đây là một vấn đề rất thú vị để giải quyết. Dù sao, đây là một giải pháp tầm thường, có thể làm việc một số thời gian cho bạn.


Tôi nghĩ rằng tôi có thể đã đề cập đến lý do ở đâu đó trong chủ đề này, nhưng vì tôi không chắc chắn tôi sẽ lặp lại. Về cơ bản vì đây không phải là một trò chơi mà là một nhà sản xuất trò chơi cho công chúng nói chung (nghĩ rằng một cái gì đó có cùng phạm vi với nhà sản xuất RPG), vì vậy thay vì buộc giới hạn kích thước kết cấu khi người dùng nhập tài sản của riêng họ, có thể xử lý tốt việc tách và khâu tự động phía sau hậu trường mà không bao giờ làm phiền họ với các chi tiết kỹ thuật về giới hạn kích thước kết cấu.
David Gouveia

Được rồi, điều đó có ý nghĩa. Xin lỗi, tôi đoán tôi đã bỏ lỡ điều đó.
tro999
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.