Làm cách nào để vẽ và lưu trữ bản đồ giống Zelda trong công cụ trò chơi tùy chỉnh?


8

Tôi có một nhiệm vụ ở trường, nơi tôi phải vẽ một bản đồ 2D từ một trong những trò chơi zelda đầu tiên, cùng với một số họa tiết hoạt hình. Bây giờ tôi có các họa tiết để làm việc, tôi gặp khó khăn khi vẽ bản đồ. Đây là những gì nó sẽ giống:

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

Đây là Bộ xếp hình mà chúng ta phải sử dụng để vẽ bản đồ (mỗi ô có kích thước 32x32 pixel):

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

Chúng tôi làm việc trong một công cụ trò chơi tùy chỉnh mà giáo viên của chúng tôi đã làm cho chúng tôi.

Để vẽ một bitmap, chúng tôi sử dụng lệnh này: GAME_ENGINE.DrawBitmap ([Tên], x.cord (trên khung vẽ), y.cord (trên khung vẽ), x.cord (trên Gạch), y.cord (trên Gạch lát), số lượng pixel bạn muốn cắt ra khỏi Gạch (Độ rộng), lượng pixel bạn muốn cắt ra khỏi Gạch (Chiều cao).

Nếu tôi sử dụng lệnh này, tôi sẽ vẽ gạch cầu thang (trên cùng bên trái) trên khung vẽ: GAME_ENGINE.DrawBitmap ([Tên], 200, 200, 0, 0, 32, 32);

Vì vậy, tôi phát hiện ra rằng với một vòng lặp lồng nhau, bạn có thể vẽ bản đồ 2D trên khung vẽ, đây là mã tôi đã sử dụng cho điều đó:

for (int y = 0; y < 10; y++)
{
    for (int x = 0; x < 16; x++)
    {
        GAME_ENGINE.DrawBitmap(Link_Level, 128 + (x * 32), 0 + (y * 32), 0, 0, 32, 32);
    }
}

Nhưng rõ ràng sau đó nó vẽ một bản đồ 16 x 10 chỉ gồm một ô.

Câu hỏi của tôi là: Làm thế nào tôi có thể sử dụng tương tự cho vòng lặp nhưng bằng cách nào đó cho nó biết gạch nào sẽ vẽ trên vị trí chính xác?

Bất kỳ trợ giúp sẽ được đánh giá cao!


Lưu trữ mỗi ô dưới một id số nguyên, sau đó x và y của nó. Vì vậy, bạn có thể có một tệp như: 1,2,2 dòng mới 4,23,44 dòng mới 6, 55,23, v.v.
Krythic

Sau đó tải và lưu trữ tệp đó trong Danh sách / Vector / ArrayList và chỉ cần truy vấn danh sách bằng cách sử dụng bộ chỉ mục mảng.
Krythic

Bạn cũng có thể thử tạo một hàm tham số biểu thị chỉ số thời gian. Cấp, điều đó sẽ vô cùng khó khăn để viết với số học thuần túy.
dùng64742

Câu trả lời:


3

Đây là nơi mà tilemap của bạn sẽ được sử dụng, ví dụ như bạn tạo một mảng các ô

int level[5][5] = {
    1, 1, 1, 1, 1
    1, 0, 0, 0, 1
    1, 0, 0, 0, 1
    1, 0, 0, 0, 1
    1, 1, 1, 1, 1
}

Trong đó 0 có thể là cỏ và 1 có thể là nước:

Sử dụng vòng lặp của bạn sau đó:

for (int y = 0; y < 10; y++)
{
    for (int x = 0; x < 16; x++)
    {
       switch(level[y][x])
       {
       case 0: // Grass
            GAME_ENGINE.DrawBitmap(GRASS, 128 + (x * 32), 0 + (y * 32), 0, 0, 32, 32);
            break;
       case 1: // Water
            GAME_ENGINE.DrawBitmap(WATER, 128 + (x * 32), 0 + (y * 32), 0, 0, 32, 32);
            break;
       }
    }
}


Tôi nghĩ rằng mã của bạn thiếu tọa độ thực tế của ô đã chọn.
Tyyppi_77

4
@ Tyyppi_77 Điều đó đúng nhưng tôi có thể tự điền vào đó :)
S. Neut

Tôi thích phương pháp này nhất là thành thật mặc dù tôi gặp lỗi ở chức năng chuyển đổi. Tôi nhận được lỗi này: Sai số chỉ số bên trong []; Dự kiến ​​2
S. Neut

5
Sự dư thừa của việc có một cuộc gọi bốc thăm trong mỗi caselà xấu xí. Ít nhất bạn nên giảm switchchỉ ảnh hưởng đến một biến duy nhất mô tả ô (mặc dù vẫn có các lựa chọn thay thế tốt hơn).
CodeInChaos

1
Tôi nghĩ rằng đây sẽ là một câu trả lời tốt hơn nếu cóvar tile = null; ... case 0: tile = GRASS; break; case 1: tile = WATER; break; ... GAME_ENGINE.DrawBitmap(tile, 128 + (x * 32), 0 + (y * 32), 0, 0, 32, 32);
sirdank

7

Tôi sẽ khuyên bạn nên lưu trữ dữ liệu ô vuông (trong trường hợp này là id 0cho trên cùng bên trái và 1bên phải và vv) trong một mảng. Sử dụng id để xác định sprite nào bạn sẽ sử dụng. Ví dụ:

int[,] map = new int[4, 5]{{ 0,  0,  0,  0, 0 },
                           { 0, 19, 19, 19, 0 },
                           { 0, 19, 19, 19, 0 },
                           { 0,  0,  0,  0, 0 }};

for (int y = 0; y < 4; y++) {
    for (int x = 0; x < 5; x++) {
        GAME_ENGINE.DrawBitmap(Link_Level, 128 + (x * 32), 0 + (y * 32), (map[y, x] % 12) * 32, (map[y, x] / 12) * 32, 32, 32);
    }
}

12đến từ số lượng gạch bạn có theo chiều ngang trong ô của bạn. Mã ở trên nên vẽ bản đồ 5x4 của cầu thang bao quanh nước.

EDIT: Mặc dù vậy, tôi không thực sự chắc chắn tên "Link_Level" là gì.


Link_Level đề cập đến biến tải bitmap từ thư mục tài sản của dự án. Trước tiên, bạn tạo biến bằng lệnh này: private Bitmap [Var biến_Name] = null. Sau đó, bạn tải nó bằng lệnh này: [Var biến_Name] = new Bitmap ("[Tên của tệp png"); Cảm ơn các phản ứng nhanh chóng bằng cách này!
S. Neut

@ S.Neut Ah lol được rồi, điều đó có ý nghĩa ngay bây giờ. Và bạn được chào đón: D
Greffin28

3

Một bổ sung nhỏ cho các câu trả lời được cung cấp: nếu bạn có bản đồ rất lớn bạn không có hơn 256 loại gạch trên mỗi bản đồ (bao gồm cả ô trống), nó có thể giúp bạn tiết kiệm rất nhiều ram để sử dụng bytethay vì intmảng kiểu.

Vì vậy, thay vì

int[,] map = new int[6400, 8000]

bạn sẽ sử dụng

byte[,] map = new byte[6400, 8000]

Nhưng sau đó, nếu bạn có những bản đồ khổng lồ như vậy, bạn cũng có thể xem xét việc tải các khối bản đồ vào bộ nhớ thay vì toàn bộ bản đồ. Một lưu ý khác: tải chunk có thể không hiệu quả với bạn nếu có những thứ liên tục diễn ra trên toàn bản đồ và bạn cần xử lý tất cả mọi lúc. Nhưng đó là một chủ đề hoàn toàn khác để xem xét khi thiết kế một trò chơi bản đồ lát gạch.


Trên bản đồ lớn.

Có thể đến một lúc nào đó tốc độ khung hình của bạn giảm xuống và có thể là do bạn có một bản đồ khá lớn và bạn đang vẽ toàn bộ, với những phần lớn của nó nằm ngoài màn hình, nhưng vẫn sử dụng hết tài nguyên phần cứng của bạn. Để tránh điều đó, hãy tính hình chữ nhật hiển thị và chỉ vẽ các ô, chỉ mục tương ứng với bên trong của hình chữ nhật đó.


2

Điều này phụ thuộc vào mức độ linh hoạt mà bạn cần hệ thống.

Điều mà hầu hết các trò chơi làm là chúng lưu trữ dữ liệu bản đồ trong một tệp dữ liệu cấp độ bên ngoài. Điều này có thể sử dụng trình soạn thảo cấp độ có sẵn và định dạng tệp cấp độ của nó (Tiled) hoặc trình chỉnh sửa tùy chỉnh (có thể chỉ là trình soạn thảo văn bản) với định dạng tùy chỉnh, có thể là định dạng XML, JSON hoặc tùy chỉnh.

Để tải dữ liệu bản đồ, bạn sẽ đọc máng tệp và lưu trữ nội dung của tệp trong một mảng 2D mà sau đó bạn có thể truy cập.

Một cách đơn giản hơn cho một dự án nhỏ là chỉ mã hóa mảng 2D bản đồ thành mã nguồn của trò chơi.

Dù sao, một khi bạn có dữ liệu bản đồ của mình trong một mảng 2D, tất cả những gì bạn cần làm là tìm kiếm loại hình xếp tại ô bạn hiện đang hiển thị.

for (int y = 0; y < 10; y++)
{
    for (int x = 0; x < 16; x++)
    {
        int xTile = MapData[y][x].x * 32;
        int yTile = MapData[y][x].y * 32;
        GAME_ENGINE.DrawBitmap(Link_Level, 128 + (x * 32), 0 + (y * 32), xTile , yTile , 32, 32);
    }
}

Dưới đây MapDatalà một mảng 2D bao gồm một đối tượng có các thành viên x và y xác định "chỉ mục" 2 chiều của ô trong ô xếp. Có nghĩa là bạn sẽ định nghĩa một ô là ô thứ năm trên hàng thứ hai làm ví dụ.

Bây giờ, trong khi phương pháp này khá đơn giản, nó có thể hơi tẻ nhạt hoặc lặp đi lặp lại. Vì vậy, bạn có thể muốn xác định các loại ô trong một lớp (hoặc chỉ xem các ô đó là số nguyên và tính toán vị trí ô chính xác dựa trên chúng). Một lớp tiện ích đơn giản với các trường như static global Vec2 StairCase = new Vec2(0, 0);sẽ giúp xác định bản đồ dễ dàng hơn.

Tóm lại, đối với một dự án nhỏ như mã hóa cứng này, một mảng 2D xác định giao diện bản đồ đó sẽ ổn. Nếu bạn dự định mở rộng trò chơi sau này, tôi sẽ khuyên bạn nên sử dụng tệp dữ liệu ngoà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.