Làm thế nào để tôi sắp xếp các sprite isometric theo đúng thứ tự?


19

Trong trò chơi 2D từ trên xuống thông thường, người ta có thể sử dụng trục y màn hình để sắp xếp hình ảnh. Trong ví dụ này, các cây được sắp xếp hợp lý nhưng các bức tường đẳng cự thì không:

Hình ảnh ví dụ: được sắp xếp theo màn hình y

Tường 2 là một pixel bên dưới tường 1 do đó nó được vẽ sau tường 1 và kết thúc ở trên cùng.

Nếu tôi sắp xếp theo trục y isometric, các bức tường sẽ xuất hiện theo đúng thứ tự nhưng các cây không:

Hình ảnh ví dụ: được sắp xếp theo isometric y

Làm thế nào để tôi làm điều này một cách chính xác?


3
Âm thanh như bạn gặp phải các vấn đề phổ biến trong Thuật toán của Họa sĩ. Giải pháp "phổ biến" là sử dụng z-buffer =). Một số cách giải quyết bao gồm sử dụng trung tâm đối tượng làm khóa sắp xếp thay vì một số góc.
Jari Komppa

Câu trả lời:


12

Các trò chơi Isometric có chức năng 3D, do đó, bên trong, bạn nên lưu trữ tọa độ 3D cho từng thực thể trong trò chơi. Các tọa độ thực tế bạn chọn là tùy ý, nhưng giả sử X và Y là hai trục trên mặt đất và Z nằm trên mặt đất lên không trung.

Trình kết xuất sau đó cần chiếu nó thành 2D để vẽ các thứ trên màn hình. "Isometric" là một hình chiếu như vậy. Chiếu từ 3D sang 2D isometric khá đơn giản. Giả sử trục X đi từ trên cùng bên trái sang dưới cùng bên phải và xuống một pixel cho mỗi hai pixel ngang. Tương tự, trục Y đi từ trên phải sang dưới cùng bên trái. Trục Z đi thẳng lên. Để chuyển đổi từ 3D sang 2D thì chỉ là:

function projectIso(x, y, z) {
    return {
        x: x - y,
        y: (x / 2) + (y / 2) - z
    };
}

Bây giờ đến câu hỏi ban đầu của bạn, sắp xếp. Bây giờ chúng tôi đang làm việc với các đối tượng của mình trực tiếp trong 3D, việc sắp xếp trở nên đơn giản hơn nhiều. Trong không gian tọa độ của chúng ta ở đây, sprite xa nhất có tọa độ x, y và z thấp nhất (tức là cả ba trục đều chỉ ra từ màn hình). Vì vậy, bạn chỉ cần sắp xếp chúng theo tổng của những người:

function nearness(obj) {
    return obj.x + obj.y + obj.z;
}

function closer(a, b) {
    if (nearness(a) > nearness(b)) {
        return "a";
    } else {
        return "b";
    }
}

Để tránh sắp xếp lại các thực thể của bạn mỗi khung hình, hãy sử dụng sắp xếp pigeonhole, chi tiết tại đây .


1
Tôi biết điều này đã cũ, một khởi đầu tốt nhưng bạn có biết làm thế nào để có thể kết hợp các giới hạn 3d của một đối tượng không chỉ đơn giản là bản dịch của nó. Khi chúng chồng lấp, việc phân loại độ sâu trở nên phức tạp hơn.
Cướp

4

Giả sử rằng các họa tiết của bạn chiếm các bộ gạch là hình chữ nhật (nếu chúng chiếm các tập tùy ý, thì bạn không thể vẽ chính xác tất cả trong trường hợp chung), vấn đề là không có mối quan hệ tổng thứ tự giữa các phần tử, vì vậy bạn không thể sắp xếp họ sử dụng một loại sẽ dẫn đến so sánh O (nlogn).

Lưu ý rằng đối với bất kỳ hai đối tượng A và B, A phải được vẽ trước B (A <- B), B nên được vẽ trước A (B <- A) hoặc chúng có thể được vẽ theo bất kỳ thứ tự nào. Họ tạo thành một trật tự một phần. Nếu bạn tự vẽ một vài ví dụ với 3 đối tượng chồng chéo, bạn có thể nhận thấy rằng mặc dù đối tượng thứ 1 và thứ 3 không thể trùng nhau, do đó không có sự phụ thuộc trực tiếp, thứ tự vẽ của chúng phụ thuộc vào đối tượng thứ 2 nằm giữa chúng - tùy thuộc vào cách bạn đặt nó, bạn sẽ có được các đơn đặt hàng bản vẽ khác nhau. Tóm lại - các loại truyền thống không hoạt động ở đây.

Một giải pháp là sử dụng phép so sánh (được đề cập bởi Dani) và so sánh từng đối tượng với nhau để xác định các phụ thuộc của chúng và tạo thành một biểu đồ phụ thuộc (sẽ là DAG). Sau đó thực hiện sắp xếp tô pô trên biểu đồ để xác định thứ tự vẽ. Nếu không có quá nhiều đối tượng, điều này có thể đủ nhanh (nó O(n^2)).

Một giải pháp khác là sử dụng cây tứ giác (để cân bằng - giả ) và lưu trữ hình chữ nhật của tất cả các đối tượng vào đó.

Sau đó lặp qua tất cả các đối tượng X và sử dụng cây tứ giác để kiểm tra xem có bất kỳ đối tượng Y nào trong dải phía trên đối tượng X bắt đầu bằng góc ngoài cùng bên trái và kết thúc với góc ngoài cùng bên phải của đối tượng X - cho tất cả Y, Y < - X. Như thế này, bạn vẫn sẽ phải tạo thành một biểu đồ và sắp xếp theo cấu trúc liên kết.

Nhưng bạn có thể tránh nó. Bạn sử dụng danh sách các đối tượng Q và một bảng các đối tượng T. Bạn lặp lại tất cả các vị trí có thể nhìn thấy từ các giá trị nhỏ hơn đến lớn hơn trên trục x (một hàng), đi từng hàng trên trục y. Nếu có một góc dưới cùng của một đối tượng tại vị trí đó, hãy thực hiện quy trình trên để xác định các phụ thuộc. Nếu một đối tượng X phụ thuộc vào một số đối tượng Y khác nằm phía trên nó (Y <- X) và mọi Y như vậy đã có trong Q, hãy thêm X vào Q. Nếu có một số Y không có trong Q, hãy thêm X vào T và biểu thị rằng Y <- X. Mỗi khi bạn thêm một đối tượng vào Q, bạn sẽ loại bỏ các phụ thuộc của các đối tượng đang chờ xử lý trong T. Nếu tất cả các phụ thuộc bị xóa, một đối tượng từ T sẽ được chuyển đến Q.

Chúng tôi giả định rằng các họa tiết đối tượng không nhìn ra các khe của chúng ở phía dưới, bên trái hoặc bên phải (chỉ ở trên cùng, giống như cây trong ảnh của bạn). Điều này sẽ cải thiện hiệu suất cho một số lượng lớn các đối tượng. Cách tiếp cận này sẽ một lần nữa O(n^2), nhưng chỉ trong trường hợp xấu nhất bao gồm các vật thể có kích thước kỳ lạ và / hoặc cấu hình kỳ lạ của các vật thể. Trong hầu hết các trường hợp, nó O(n * logn * sqrt(n)). Biết chiều cao của các họa tiết của bạn có thể loại bỏ sqrt(n), bởi vì bạn không phải kiểm tra toàn bộ sọc ở trên. Tùy thuộc vào số lượng đối tượng trên màn hình, bạn có thể thử thay thế cây tứ giác bằng một mảng cho biết vị trí nào được lấy (có ý nghĩa nếu có nhiều đối tượng).

Cuối cùng, vui lòng kiểm tra mã nguồn này để biết một số ý tưởng: https://github.com/axel22/sages/blob/master/src/gui/scala/name/brijest/sages/gui/Canvas.scala


2

Tôi không nghĩ có một giải pháp toán học. Bạn có thể không có đủ dữ liệu trong thế giới 2D mà các vật phẩm của bạn đang sống. Nếu các bức tường của bạn được nhân đôi trên X, chúng sẽ theo thứ tự "chính xác". Sau đó, một lần nữa bạn có thể thực hiện kiểm tra chồng chéo với hộp giới hạn của hình ảnh bằng cách nào đó, nhưng đây là khu vực tôi không quen thuộc.

Có lẽ bạn nên sắp xếp theo màn hình Y trên mỗi ô và nói rằng bất cứ điều gì phức tạp hơn là "vấn đề thiết kế". Ví dụ: nếu bạn là tác giả của nội dung, chỉ cần nói với các nhà thiết kế của bạn thuật toán sắp xếp và đẩy wall2 2 pixel lên để khắc phục sự cố. Đó là cách chúng tôi phải sửa nó trong trò chơi isometric mà tôi đã làm việc. Điều này có thể bao gồm lấy các vật phẩm "dài" và chia chúng thành các khối có kích thước bằng gạch.

Nếu bạn đang cho phép người dùng chỉnh sửa nội dung, điều hoàn toàn an toàn cần làm là làm cho mọi thứ đều dựa trên và tối đa một ô lớn. Bằng cách đó bạn tránh được vấn đề. Bạn có thể có được bằng cách làm cho mọi thứ lớn hơn một ô, nhưng có thể chỉ khi nó vuông. Tôi đã không chơi xung quanh với điều đó.


2

Phân loại isometric hoàn hảo là khó. Nhưng đối với cách tiếp cận đầu tiên, để sắp xếp đúng các mục của bạn, bạn nên sử dụng chức năng so sánh phức tạp hơn với từng đối tượng chồng chéo. Hàm này phải kiểm tra điều kiện này: Một đối tượng chồng chéo "a" nằm sau "b" nếu:

(a.poseX + a.sizeX <= b.poseX) hoặc (a.poseY + a.sizeY <= b.poseY) hoặc (a.poseZ + a.sizeZ <= b.poseZ)

Tất nhiên, đây là một ý tưởng đầu tiên cho việc thực hiện isometric ngây thơ. Đối với kịch bản phức tạp hơn (nếu bạn muốn xoay chế độ xem, vị trí trên mỗi pixel trên trục z, v.v.), bạn sẽ cần kiểm tra thêm các điều kiện.


+1, nếu bạn có các ô có chiều rộng / chiều cao khác nhau, hãy xem chức năng so sánh trong câu trả lời này.
mucaho

2

Tôi sử dụng một công thức rất đơn giản, hoạt động tốt với công cụ isometric nhỏ của tôi trong OpenGL:

Mỗi đối tượng của bạn (cây, gạch lát sàn, ký tự, ...) có vị trí X và Y trên màn hình. Bạn cần bật TESTING KIỂM TRA và tìm giá trị Z tốt cho từng giá trị. Bạn có thể chỉ cần làm như sau:

z = x + y + objectIndex

Tôi sử dụng và chỉ số khác nhau cho sàn và các đối tượng sẽ ở trên sàn (0 cho sàn và 1 cho tất cả các đối tượng có chiều cao). Điều này sẽ làm việc tốt.



1

Nếu bạn so sánh các giá trị y ở cùng một vị trí x, nó sẽ hoạt động mọi lúc. Vì vậy, đừng so sánh trung tâm với trung tâm. Thay vào đó, so sánh trung tâm của một sprite với cùng một vị trí x trên sprite khác.

nhập mô tả hình ảnh ở đây

Nhưng, điều này đòi hỏi một số dữ liệu hình học cho mỗi sprite. Nó có thể dễ dàng như hai điểm từ bên trái sang bên phải mô tả ranh giới thấp hơn cho sprite. Hoặc, bạn có thể phân tích dữ liệu hình ảnh họa tiết và tìm pixel đầu tiên không trong suốt.

Một cách tiếp cận dễ dàng hơn là chia tất cả các sprite thành ba nhóm: đường chéo dọc theo trục x, đường chéo dọc theo trục y và phẳng. Nếu hai đối tượng đều có đường chéo dọc theo cùng một trục, hãy sắp xếp chúng dựa trên trục khác.


0

Bạn cần gán id duy nhất cho tất cả các đối tượng cùng loại. Sau đó, bạn sắp xếp tất cả các đối tượng theo vị trí của chúng và vẽ các nhóm đối tượng theo thứ tự id của chúng. Vì vậy, đối tượng 1 trong nhóm A sẽ không bao giờ rút tiền đối tượng 2 trong nhóm A, v.v.


0

Đây thực sự không phải là một câu trả lời, nhưng chỉ là một bình luận và bình chọn mà tôi muốn đưa ra cho câu trả lời của axel22 này tại đây /gamedev//a/8181/112940

Tôi không đủ danh tiếng để bình chọn cũng như bình luận các câu trả lời khác, nhưng đoạn thứ hai trong câu trả lời của anh ta có lẽ là điều quan trọng nhất mà mọi người nên biết khi cố gắng sắp xếp các thực thể trong một trò chơi isometric mà không dựa vào 3D "hiện đại" các kỹ thuật như bộ đệm Z.

Trong động cơ của tôi, tôi muốn làm những thứ "trường học cũ", 2D thuần túy. Và tôi đã dành rất nhiều thời gian để làm hỏng bộ não của mình khi cố gắng tìm ra lý do tại sao cuộc gọi "sắp xếp" của tôi (trong trường hợp của tôi là c ++ std :: sort) không hoạt động chính xác trên một số cấu hình bản đồ nhất định.

Chỉ khi tôi nhận ra rằng đây là một tình huống "trật tự một phần" thì tôi mới có thể giải quyết nó.

Cho đến nay, tất cả các giải pháp làm việc tôi tìm thấy trên web đã sử dụng một số cách sắp xếp tôpô để giải quyết vấn đề một cách chính xác. Sắp xếp topo dường như là con đường để đi.

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.