Các đơn vị sinh sản trong một thế giới được tạo ra bởi tiếng ồn Perlin?


16

Có một số vấn đề mà tôi gặp phải trong trò chơi dựa trên tiếng ồn Perlin của mình. Hãy nhìn vào ảnh chụp màn hình đính kèm bên dưới.

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

Các khu vực màu trắng bạn nhìn thấy là các bức tường, và các khu vực màu đen có thể đi bộ. Hình tam giác ở giữa là người chơi.

Tôi đã triển khai vật lý trong trò chơi này bằng cách vẽ nó lên một kết cấu (pixel trắng hoặc đen), và sau đó lấy nó từ CPU.

Tuy nhiên, bây giờ tôi đứng trước một vấn đề khác. Tôi muốn các đơn vị (hoặc creep, bất cứ thứ gì bạn gọi chúng) xuất hiện liên tục, ở rìa màn hình. Vấn đề ở đây là trong trò chơi cuối cùng, sẽ có một "sương mù chiến tranh" không cho phép người chơi nhìn xa đến thế.

Tôi hình dung rằng tôi chỉ có thể quét các pixel ở cạnh màn hình và xem kết cấu vật lý của chúng có màu đen không, và sau đó sinh ra các thứ ngẫu nhiên ở đó. Tuy nhiên, nếu bạn nhìn lần thứ hai vào ảnh chụp màn hình, có (ở góc trên bên trái) một ví dụ về nơi tôi sẽ không muốn những con creep sinh sản (vì chúng sẽ không thể tiếp cận người chơi từ đó) .

Có thể bằng cách nào đó để GPU xác định những điểm sinh sản này cho tôi, hoặc một số cách khác nhau? Tôi nghĩ về việc tạo ra các vectơ giữa điểm được đề xuất ở rìa màn hình và người chơi, sau đó theo dõi nó cứ sau 10 voxels, và xem liệu một bức tường có va chạm hay không, trước khi sinh ra một đơn vị ở đó.

Tuy nhiên, giải pháp đề xuất ở trên có thể quá tốn CPU.

Bất kỳ đề nghị về vấn đề này?

Lưu ý 1 Đối với các đơn vị sinh ra, tôi không muốn sử dụng bất kỳ hình thức tìm đường nào để tránh va chạm vào tường khi các đơn vị này chạy về phía người chơi. Do đó, các đơn vị phải sinh sản ở rìa màn hình, tại vị trí mà việc đi theo đường thẳng về phía người chơi sẽ không va chạm với bất kỳ bức tường nào.


1
Bản đồ có di chuyển xung quanh với người chơi không, hay người chơi di chuyển xung quanh trong bản đồ? Đó là, bản đồ sẽ được thay đổi? Nếu không, tôi khuyên bạn nên điền vào tất cả các điểm không thể truy cập ở thế hệ, để bạn không cần phải lo lắng về chúng.
dlras2

Nếu người chơi đang di chuyển, các đơn vị sẽ cần một phương pháp tìm đường. Nếu bạn muốn các khu vực lõm bạn sẽ gặp vấn đề này và bạn phải cung cấp một giải pháp cho đơn vị di chuyển đang cố gắng tiếp cận một người chơi đang di chuyển ... hay còn gọi là tìm đường.
Blau

1
Hoặc, để đặt bình luận của Blau theo cách khác: Câu hỏi của bạn chắc chắn không có câu trả lời hợp lệ (ngoài trường hợp tầm thường của bản đồ không có gạch ốp tường / pixel nào) nếu người chơi có thể di chuyển. Nó vẫn yêu cầu bạn xác định ý của bạn với "đường thẳng" để có câu trả lời nếu người chơi đứng yên.
Martin Sojka

Câu trả lời:


3

Có một thuật toán khá hữu ích cho công việc này, hiệu quả hơn nhiều so với thuật toán lũ trong tình huống này (độ phức tạp của nó là thời gian chạy tỷ lệ với kích thước ranh giới thay vì vùng ngập nước): đó là thuật toán hình vuông diễu hành. Khái niệm này rất đơn giản: bắt đầu từ vị trí người chơi (điểm giữa màn hình), chọn hướng và đi bộ cho đến khi bạn tìm thấy một bức tường. Khi bạn va chạm với tường, bạn bắt đầu thuật toán: bạn chọn một hướng (lên hoặc xuống) và bắt đầu diễu qua ranh giới của khu vực này, làm nổi bật các pixel. Điều này cung cấp cho bạn ranh giới bên trong cho khu vực được phép. Sau đó, bạn chỉ cần kiểm tra xem các điểm ứng cử viên cho các đơn vị sinh sản có nằm trên ranh giới này hay không.

Đây là nguyên tắc bạn nên tuân theo để chạy ranh giới:

http://en.wikipedia.org/wiki/File:Marchsquares.png (meh tôi chưa thể đăng ảnh)

Mô tả Wikipedia (mặc dù nó phức tạp hơn nhiều vì nó được sử dụng với các ứng dụng khác):

http://en.wikipedia.org/wiki/Marching_squares


10

Tạo một vùng lũ từ vị trí của người chơi; mỗi khu vực "ngập" sau đó là một khu vui chơi hợp lệ và tất cả các khu vực khác là những bức tường.

EDIT: Đối với yêu cầu bổ sung "có thể tiếp cận theo đường thẳng", hãy nhớ rằng trong một không gian riêng biệt , bạn phải xác định thêm một chút nữa. Ví dụ: tất cả các đường dẫn ở trên có thể là một "đường thẳng" hợp lệ trong một môi trường như vậy và tôi đã thấy tất cả chúng được sử dụng trong một trò chơi vào lúc này hay lúc khác:

biến thể "đường thẳng"

Cụ thể, hầu hết những người không giao hoán - có nghĩa là chỉ vì bạn có thể tiếp cận B từ A theo "đường thẳng" không có nghĩa là bạn cũng có thể tiếp cận A từ B; không phải là điều ngược lại nhất thiết phải đúng

Ngoài ra, có câu hỏi về cách bạn xử lý chuyển động chéo nếu một hoặc cả hai điểm "bên" bị chặn.


Điều này có thể được thực hiện hoàn toàn trong HLSL không?
Mathias Lykkegaard Lorenzen

@Mathias Lykkegaard Lorenzen: Vâng, nghi ngờ bằng cách thực hiện từng bước của thuật toán như một trình đổ bóng pixel và kết xuất giữa hai mục tiêu kết cấu chẳng hạn, nhưng ... tại sao ? Dù sao bạn cũng sẽ cần thông tin từ thuật toán trên CPU, để tìm đường dẫn ít nhất.
Martin Sojka

1
@Mathias Lykkegaard Lorenzen: Tuy nhiên, điều đó hơi khác so với những gì bạn yêu cầu. Trong trường hợp này: Làm thế nào để bạn xác định một "đường thẳng", đưa ra lược đồ phân vùng không gian riêng biệt của bạn?
Martin Sojka

2
ngay cả khi bạn không muốn sử dụng tính năng tìm đường, yêu cầu cpu thực hiện công việc lấp đầy là có thể, hãy nhớ rằng bạn chỉ cần gọi lũ lụt một lần và sau đó bạn sẽ có kết cấu gồm 3 màu xác định tường, không gian trống và không gian sinh sản. đối với kết cấu 4096x4096, sẽ mất ít hơn một giây để cpu hoàn thành công việc lấp đầy.
Ali1S 232

1
Vấn đề là bạn chỉ phải chạy vùng lũ này một lần và ngay cả khi địa hình của bạn thay đổi trong khi chơi trò chơi, bạn chỉ phải cập nhật các phần bị ảnh hưởng và có lũ lụt chạy qua chúng rất nhanh.
TravisG

1

Làm thế nào về việc chỉ để sinh sản xảy ra? Tôi không thấy bất kỳ vấn đề cụ thể trong đó.


Và nếu chúng sinh ra sau một bức tường thì sao? Làm thế nào bạn sẽ làm cho họ tiếp cận người chơi?
Mathias Lykkegaard Lorenzen

1
nó có thể là một vấn đề nếu trò chơi có một kịch bản để tiêu diệt tất cả kẻ thù và nó sinh ra 50 kẻ thù, nhưng một số ít đã sinh ra sau bức tường. Người chơi sẽ không thể giết kẻ thù và kịch bản sẽ không kết thúc.
Lie Ryan

1
Các đơn vị khác vẫn có thể không đến được với người chơi tùy thuộc vào cách người chơi di chuyển sau khi họ sinh ra, bạn sẽ phải xuất hiện một số đơn vị trong cả hai trường hợp.
aaaaaaaaaaaa

sương mù chiến tranh sẽ bao trùm những sinh sản
điên rồ

1
Dù sao thì nó cũng không hoạt động khi người chơi di chuyển.
aaaaaaaaaaaa

1

nếu điều quan trọng đối với bạn là chỉ đánh dấu các điểm bằng một đường thẳng hợp lệ cho trình phát thì bạn có thể sử dụng thuật toán như sau (đó là mã c ++), nó tiêu thụ nhiều hơn so với lũ lụt thông thường. có thể có một số lỗi nhỏ (tôi sẽ rất vui nếu có ai sửa chúng) vì tôi đã không tự kiểm tra mã nhưng bạn sẽ hiểu.

void straightlineFill(Point startPoint, Texture target)
{
    queue<Point> pointQueue;
    for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(startPoint.x + dx, startPoint.y + dy));
    while (!pointQueue.empty())
    {
        point front = pointQueue.front();
        pointQueue.pop();
        if (target.pixelAt(front) == COLOR_SPAWNABLE||
            target.pixelAt(front) == COLOR_WALL||
            target.pixelAt(front) == COLOR_NOT_SPAWNABLE)
                continue;
        taraget.setPixelAt(front, colorFilled); 
        for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(front.x + dx, front.y + dy));
        // up until now was the normal floodfill code
        // and here is the part that will do the real straight line checking

        // lineDX & lineDY will keep how much the line we are checking is skewed
        int lineDX = front.x - startPoint.x;
        int lineDY = front.y - startPoint.y;

        // step will show us how much we have to travel to reach each point of line
        point step;
        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDX < 0)
                step = point(-1,0);
            if (lineDX == 0)
                if (lineDY < 0)
                    step = point(0,-1);
                else
                    step = point(0,1);
            if (lineDX > 0)
                step = point(1,0);
        }

        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDY < 0)
                step = point(0,-1);
            if (lineDY == 0)
                if (lineDX < 0)
                    step = point(-1,0);
                else
                    step = point(1,0);
            if (lineDY > 0)
                step = point(0,1);
        }

        // moved will keep how much we have traveled so far, it's just some value that will speed up calculations and doesn't have any mathematical value
        point moved = 0;

        // spawnable will keep if the current pixel is a valid spawnpaint

        bool spawnable = true;

        // now we will travel on the straight line from player position to the edges of the map and check if whole line is valid spawn points or not.

        while (target.isInside(front))
        {
            front = front + step;
            moved = moved + point(step.x * lineDX, step.y * lineDY);
            if (step.x != 0 && moved.x < moved.y)
            {
                moved.x = moved.x - lineDY * sign(lineDY);
                front.y = front.y + sign(lineDY);
            }
            if (step.y != 0 && moved.y < moved.x)
            {
                moved.y = moved.y - lineDX * sign(lineDX);
                front.x = front.x + sign(lineDX);
            }

            if (target.getPixelAt(front) == COLOR_WALL)
                spawnable = false;

            if (spawnable)
            {
                target.setPixelAt(front,COLOR_SPAWNABLE);
                for (int dx = -1;dx <=1;dx ++)
                    for(int dy = -1;dy <=1;dy++)
                        if(dx != 0 && dy != 0)
                            pointQueue.push(point(front.x + dx, front.y + dy));             
            }
            else
            {
                target.setPixelAt(front,COLOR_NOT_SPAWNABLE);
            }
        }
    }
}

1

Bạn có thể tô màu bản đồ bằng các màu đại diện cho các khu vực lồi ..., bằng cách này bạn có thể sinh ra đơn vị của mình nếu nằm trong cùng khu vực. Hoặc bạn có thể tìm kiếm dễ dàng hơn cho các khu vực có thể tiếp cận.

Đây là dữ liệu tĩnh để bạn có thể xác định trước nó.

bạn phải điền vào các điểm tìm kiếm hình ảnh trong đó có sự thay đổi từ lồi sang lồi, nhìn trực quan có vẻ dễ tìm, bạn có hai tình huống:

  1. Ngang: Trường hợp màu cam sang màu xanh thay đổi.
  2. Dọc: Trường hợp màu đỏ thay đổi màu xanh lá cây và màu cam.

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


Điều này không hoạt động. Nhìn vào phía dưới bên phải, cụ thể là các đốm màu trong khu vực màu đỏ. Nó hoàn toàn lồi nên không có thay đổi nào để sử dụng màu khác nhưng rõ ràng không có đường thẳng nào tồn tại từ đáy của màu đỏ ở cạnh phải đến phần ngoài cùng bên phải của màu đỏ ở cạnh dưới.
Loren Pechtel

@Loren Pechtel cái này được làm bằng tay, bạn nói đúng, có lỗi ở đó, đó là lỗi của tôi, nhưng bạn có thể nhận ra đó là tình huống tương tự khi chuyển từ màu cam sang màu xanh.
Blau

@Loren Pechtel, xin lưu ý rằng objetive là tránh sinh sản ở những khu vực như màu vàng. Phương pháp này đảm bảo rằng nếu bạn thả kẻ thù trong cùng khu vực có chứa người chơi, điều này có thể tiếp cận được. Tất nhiên, nó có thể khó thực hiện, nhưng ý tưởng là hợp lệ.
Blau

Bản sửa đổi của bạn không giúp được gì. Hai điểm trên một đường cong lồi sẽ không bao giờ có một đường thẳng hợp pháp giữa chúng, khoảng thời gian. Nhiều bộ phận sẽ không giúp đỡ.
Loren Pechtel

vui lòng kiểm tra định nghĩa của lồi liên quan đến các khu vực hoặc tập hợp các điểm ... vi.wikipedia.org/wiki/Convex
Blau

1

Đây là thứ mà tôi thực sự đã sử dụng trong trò chơi của riêng mình (thế giới tạo ra tiếng ồn đơn giản 2d, gần như chính xác như của bạn) - Rays. Bắt đầu tại trình phát, xác định hướng (ngẫu nhiên nếu bạn muốn) và đi dọc theo đường đó cho đến khi bạn nhấn một cái gì đó (cạnh màn hình HOẶC tiểu hành tinh). Nếu bạn nhấn vào cạnh của màn hình (và không phải là một tiểu hành tinh / đốm trắng), thì bạn biết rằng có một đường thẳng, mở từ mép màn hình đến trình phát. Sau đó sinh ra một con quái vật tại điểm bạn đánh. Nếu bạn va vào một tiểu hành tinh, hãy làm lại bài kiểm tra.


0

Một giải pháp khác (không phải GPU) bạn có thể sử dụng là tìm đường dẫn. Trước khi vẽ bản đồ, tìm đường đi từ mỗi điểm sinh sản tiềm năng ở mỗi cạnh của bản đồ và xem liệu có đường dẫn đến trung tâm không. Tìm kiếm đường dẫn * khá ổn về chi phí / hiệu suất, nhưng bạn có thể làm điều này trước khi trò chơi bắt đầu nếu đó là một vấn đề.

Bất kỳ điểm sinh sản nào không có đường dẫn đều có thể được đưa vào danh sách loại trừ; hoặc ngược lại (bất kỳ điểm nào có đường dẫn đều có thể được đưa vào danh sách đưa vào).

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.