Làm thế nào để đảm bảo luôn có một con đường có thể đi bộ cho kẻ thù trong trò chơi phòng thủ tháp?


7

Tôi đang làm một trò chơi phòng thủ tháp 2D. Cho đến nay tôi có một mảng 2d hoạt động như một lưới cho trò chơi của tôi. Tôi có thể đặt các tòa tháp lên nó, chạy kẻ thù và một số thứ kéo và bắn tháp.

Bây giờ tôi đang phải đối mặt với một vấn đề trong logic vị trí tháp. Tôi muốn rằng luôn có một lối đi cho kẻ thù, có nghĩa là người dùng không thể chặn đường hoàn toàn bằng cách đặt tháp. Ví dụ. nếu người dùng đặt các tháp theo chiều dọc trên bản đồ, thuật toán phải ngăn vị trí của một tòa tháp sẽ hoàn thành đường thẳng đứng. Hoặc theo bất kỳ cách nào khác, phải có ít nhất một không gian trống (có thể đi bộ) để kẻ thù có thể trốn thoát.

Logic hiện tại của tôi kiểm tra theo mọi hướng bất cứ khi nào tháp được đặt. Nếu có một tháp hướng lên trên, nó sẽ gọi lại chức năng tương tự trên tháp phía trên cho đến khi chạm vào tường. Nó trả về 1 cho tường hướng lên và 5 cho tường hướng xuống và trả về chức năng (tháp lên / xuống) nếu có tháp. đây là mã:

int checkCollision(tower)
{                           
    if( there is a  tower up) 
    return checkCollision(up tower);

    if(there is a tower down) 
    return checkCollision(down tower);                                      

            ......all directions.....       

    if( there is a wall on UP )     
        return 1;

    if( there is a wall DOWN ) 
        return 5;

        ....all walls......

    return 0;   
}   

Bây giờ điều tôi muốn là, đồng thời kiểm tra xem có một bức tường phía bắc và bức tường phía nam hay kiểm tra bất kỳ hướng nào khác với bất kỳ khả năng nào khác (như lên xuống, lên chéo, xuống chéo ... và không) cho phép người dùng đặt một tòa tháp vì cần có một nơi còn lại cho kẻ thù.

Tôi không hài lòng với mã của tôi tại thời điểm này. Ý tôi là mã của tôi nói với tôi rằng một bức tường được tìm thấy nhưng làm thế nào tôi có thể kiểm tra xem một bức tường được tìm thấy theo một hướng và một bức tường cũng được tìm thấy ở một hướng khác? Tôi không muốn đi vào các khả năng như:

if(checkCollision(tower) == 1 && checkCollision(tower) == 5) 
  "You cannot place"

Tôi muốn một cái gì đó như:

    if( any combination of more than 2 wall found and there is entry/exit point in between)  //so it is wall to wall
    "You cant place"

Tôi cũng đã thử các cờ tính toán trước nếu có các bức tường ở hai bên (như lên xuống, chéo lên, v.v.) sau đó không cho phép người dùng đặt tháp nhưng điều đó vẫn không hoạt động.


Các đường dẫn của bạn luôn có cùng chiều rộng (tức là hai ô rộng)?
Richard Marskell - Drackir

Câu trả lời:


23

Sẽ không đơn giản hơn khi sử dụng thuật toán tìm đường để kiểm tra xem AI có còn lộ trình rõ ràng không? Có lẽ bạn đã sử dụng một cái để làm cho kẻ thù điều hướng từ lối vào đến lối ra, vì vậy chỉ cần chạy nó với tháp được thêm vào, và nếu thất bại thì tháp không được phép.


bạn có thể cho tôi một số tài liệu tham khảo về thuật toán như vậy, thường được sử dụng trong các trò chơi phòng thủ tháp không?
Syed

Không cụ thể về phòng thủ tháp, nhưng đây là phần giới thiệu tốt cho người mới bắt đầu về A * và cách xử lý chuyên sâu hơn . Nếu bạn đang sử dụng một công cụ có thể sẽ có triển khai A * cho nó và có khá nhiều thư viện tìm đường bạn có thể sử dụng. Cụ thể về phòng thủ tháp, câu trả lời cho câu hỏi này khẳng định có một thuật toán tốt hơn là A *, nhưng tôi không quen với nó
SimonW

Tôi chưa mã hóa thuật toán để chạy kẻ thù từ đầu đến cuối vì tôi nghĩ việc đặt lưới nên được thực hiện trước. Tôi đã mệt mỏi khi thử kiểm tra tường trên tường như được mô tả ở trên vì nó sẽ theo dõi tòa tháp cho đến khi tìm thấy bên trên / bên dưới / bên phải / bên trái, tôi muốn tạo trò chơi giống như 'người chạy trường'. Bạn nghĩ gì khi tiếp tục thử kiểm tra tường hoặc chuyển sang một số thuật toán khác? Tôi thực sự bế tắc trong công việc của mình: | em sử dụng công cụ trò chơi Unity3D
Syed

1
Kế hoạch bình thường của tôi khi làm một trò chơi là đưa mọi phần về trạng thái có thể chơi tối thiểu, sau đó đi từ đó. Điều đó có nghĩa là bỏ qua những điều khó khăn như cấm người chơi chặn đường, và thay vào đó hãy đảm bảo rằng bạn có thể gửi kẻ thù từ đầu đến cuối, và người chơi có thể bắn vào họ. Khi bạn đã có một trò chơi bạn có thể thắng hoặc thua, hãy làm bất cứ điều gì làm cho nó vui / không bị phá vỡ. Lặp lại cho đến khi tuyệt vời.
SimonW

1
Để có được đường dẫn vào Unity, bạn có thể xem dự án miễn phí này . Nếu bạn không có nhiều kinh nghiệm, thư viện là một cách tuyệt vời để giảm thời gian bạn bị mất điều kiện bởi những thứ nhàm chán. Lấy mã từ mọi nơi và mọi nơi để có thể chơi trò chơi của bạn và lo lắng về việc sửa nó sau này.
SimonW

3

Tôi giả sử bạn đã có một số mã (sử dụng một cái gì đó như thuật toán A * ) cho kẻ thù để tìm đường đến đích của chúng. Mỗi khi người chơi cố gắng đặt một tòa tháp, bạn có thể đặt một chướng ngại vật tạm thời ở vị trí của tòa tháp và chạy mã tìm đường để kiểm tra xem vẫn sẽ có một con đường cho kẻ thù.

Bạn có thể tối ưu hóa điều này theo nhiều cách khác nhau. Ví dụ: nếu tòa tháp mới được đặt chỉ chạm vào tối đa một chướng ngại vật hiện có, nó không thể chặn đường đi. Bạn cũng có thể lưu kết quả của các lần kiểm tra trước (ít nhất là cho đến khi có gì đó thay đổi), để nếu người chơi thử cùng một vị trí nhiều lần, bạn không phải kiểm tra lại mỗi lần.

Ngoài ra có một số kỹ thuật chỉ hoạt động trong một số trường hợp. Ví dụ:

  • Nếu các vị trí có thể của các tòa tháp không trùng nhau, bạn có thể sử dụng thuật toán tìm cầu để tìm chính xác vị trí nào sẽ chặn đường đi của kẻ thù.
  • Nếu sân chơi là hai chiều, có một mẹo thông minh dựa trên thực tế là tồn tại một con đường rõ ràng từ bên trái sang bên phải nếu và chỉ khi không tồn tại một bức tường liên tục từ trên xuống dưới. Do đó, bạn có thể gắn nhãn cho mỗi tháp (hoặc chướng ngại vật khác) tùy theo đó, nếu có, bên nào của sân chơi, nó được kết nối với một bức tường.

    Duy trì các nhãn này khi các tòa tháp mới được thêm vào rất dễ dàng và nhanh chóng. Nếu một tòa tháp mới liên kết hai bên với nhau, nó sẽ chặn đường đi của kẻ thù. Tất nhiên, nếu một tòa tháp bị xóa, bạn vẫn phải tính toán lại các nhãn, nhưng bạn chỉ cần làm điều đó khi một tòa tháp thực sự bị phá hủy, thay vì mỗi khi người chơi chỉ di chuyển con trỏ qua một vị trí tiềm năng cho một tòa tháp mới.


1

Tôi đồng ý với SimonW rằng bạn chỉ nên chạy thuật toán đường dẫn của mình. Để hoàn thiện, đây là một mẹo được sử dụng bởi các bản đồ Starcraft / Warcraft TD, không có cách nào để kiểm tra xem thuật toán đường dẫn có vượt qua / thất bại hay không.

Giả sử kẻ thù có thể đến bất cứ nơi nào từ đỉnh của khu vực có thể xây dựng và phải di chuyển đến bất cứ nơi nào bên dưới khu vực có thể xây dựng được; và có những bức tường ở bên trái / phải. Thực hiện lấp đầy tất cả các tháp chạm vào bức tường bên trái. Nếu bất kỳ tòa tháp nào được tìm thấy chạm vào bức tường bên phải, đường dẫn sẽ bị chặn.


0

nó nên giống

bool checkCollision(tower)
{
if(there is tower above)
  return checkCollision(tower above);
if(there is tower below)
  return checkCollision(tower below);
...
...
...
if(wall above)
  return 1;
if(wall below)
  return 5;
...
...
...
return 0;
}

sau đó trong mã của bạn, nơi bạn muốn kiểm tra xem có cho phép đặt tháp hay không:

if(!checkCollision(tower above) && !checkCollision(tower below) && !checkCollision(tower left)...[check all sides]...)
  //You can place the tower
else
  //You cannot place the tower

Ngoài ra, thay đổi thuật toán của bạn để thêm khả năng trả về tọa độ của khối tường được tìm thấy liền kề với chuỗi tháp. Kiểm tra xem cùng một bức tường gạch đã được trả lại và loại bỏ sẽ cho phép bạn đi qua các vòng của tháp.

Ý tôi là theo vòng lặp của tháp (đừng bận tâm đến nghệ thuật ascii của tôi):

--------------------------
|                        |
|   TT                   |
|TTTTTTTTT               |
|       X T              |
|       T                |
|                        |
En                       Ex
|                        |
|                        |
|                        |
|________________________|

Nó sẽ không cho phép bạn đặt một tòa tháp tại X. Tháp bên trên, tháp trên đường chéo, tháp bên phải và tháp bên dưới sẽ báo cáo va chạm tường, tuy nhiên tọa độ của gạch ốp tường sẽ giống nhau. Đây là những gì bạn cần phải sàng lọc là tốt.


0

Thật dễ dàng, tôi mới xây dựng chương trình tìm đường dẫn đầu tiên của mình ngày hôm nay, tôi mất hơn 2 giờ và ngoài việc khai báo các biến, nó chỉ có 27 dòng mã bao gồm cả dấu ngoặc đóng.

lập trình trong đường dẫn của bạn một mảng cho tất cả các bức tường thực sự của bạn và một mảng cho tất cả các bức tường giả của bạn, nếu người chơi muốn tạo một tòa tháp trên một không gian, thì không gian được chọn là một bức tường giả định; Chạy đường dẫn của bạn để bao gồm các bức tường giả định, nếu chương trình quay lại với một đường dẫn được tìm thấy thì tòa tháp có thể được xây dựng, nếu không thì tòa tháp sẽ không được phép xây dựng.

Chúc mừng

Đây là mã của tôi,

function PathFind(){

var keepgoing:Number=1;
var count:Number=1;
var smallcount:Number=0;
var keepgoing2:Boolean=false;
var startX:Array=[];
var startY:Array=[];
startX[0]=new Array();
startX[1]=new Array();
startY[0]=new Array();
startY[1]=new Array();
startX[0][1] = disc.loca;
startY[0][1] = disc.locb;
startX[1][1] = String(disc.loca)+"$";
startY[1][1] = String(disc.locb)+"$";


for(var c:Number=1; c<=keepgoing; c++){
    smallcount=0;
    for (var a:Number=1; a<=3; a++){
        for (var b:Number=1; b<=3; b++){
            if (a==2 || b==2){
                if(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].valid==true && SpaceII[startX[0][c]+(a-2)][startY[0][c]+(b-2)]==true){
                    count++;
                    smallcount++;
                    SpaceII[startX[0][c]+(a-2)][startY[0][c]+(b-2)]=false;
                    startX[0][count]=Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDx;
                    startY[0][count]=Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDy;
                    startX[1][count]=startX[1][c]+String(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDx)+"$";
                    startY[1][count]=startY[1][c]+String(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDy)+"$";
                    if(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].goal==true){
                        keepgoing2=true;
                        disc.stringA = startX[1][count].toString();
                        disc.stringB = startY[1][count].toString();
                        //thisText.text=startX[1][count] + "%" + startY[1][count] + "*";
                        success=true;
                    }                       
                }
            }
        }
    }
    if(keepgoing2==true){
        c = keepgoing;
    } else {
        keepgoing = keepgoing + smallcount;
    }
}

}

Về cơ bản, mã của tôi sẽ tạo ra một chuỗi các chuỗi X & Y, sau đó các đơn vị di chuyển của tôi kế thừa các chuỗi ghép nối thành công đầu tiên và sau đó chúng chỉ xử lý các chuỗi một phân đoạn một lần. Mỗi tọa độ bị phá vỡ bằng "$".

Và điều tuyệt vời ở đoạn mã trên là 'giữ lại' sẽ chỉ lớn hơn kích thước lưới và trở nên hiệu quả hơn với nhiều tháp được đặt, hiệu quả của nó được tối đa hóa khi chỉ có một đường dẫn được thiết lập.

Nếu bạn cần bất kỳ sự giúp đỡ nào với những gì tôi đã ở trên đây cho bạn, hãy cho tôi biết.

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.