วางไข่หน่วยในโลกที่ทำโดยเสียง Perlin?


16

มีปัญหาบางอย่างที่ฉันเจอในเกมที่ใช้เสียงรบกวนของ Perlin ดูภาพหน้าจอที่แนบมาด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่

พื้นที่สีขาวที่คุณเห็นนั้นเป็นผนังและพื้นที่สีดำสามารถเดินได้ สามเหลี่ยมที่อยู่ตรงกลางคือผู้เล่น

ฉันใช้ฟิสิกส์ในเกมนี้โดยวาดลงบนพื้นผิว (พิกเซลสีขาวหรือสีดำ) แล้วนำมันมาจากซีพียู

อย่างไรก็ตามตอนนี้ฉันยืนอยู่กับปัญหาที่แตกต่างกันในมือ ฉันต้องการหน่วย (หรือครีปสิ่งที่คุณเรียกพวกเขา) เพื่อวางไข่อย่างต่อเนื่องที่ขอบของหน้าจอ ประเด็นที่นี่คือในเกมสุดท้ายจะมี "หมอกแห่งสงคราม" ที่ไม่อนุญาตให้ผู้เล่นมองเห็นได้ไกล

ฉันคิดว่าฉันสามารถสแกนพิกเซลที่ขอบของหน้าจอและดูว่าพื้นผิวฟิสิกส์ของพวกเขาเป็นสีดำหรือไม่จากนั้นจะวางไข่แบบสุ่มที่นั่น อย่างไรก็ตามถ้าคุณลองดูภาพหน้าจอที่สองมี (ที่มุมบนซ้าย) ตัวอย่างที่ฉันไม่ต้องการให้ครีพวางไข่ (เนื่องจากพวกเขาไม่สามารถเข้าถึงผู้เล่นได้จากที่นั่น) .

เป็นไปได้ไหมที่ GPU จะกำหนดจุดกำเนิดของสิ่งเหล่านี้ให้ฉันหรือวิธีอื่น? ฉันคิดเกี่ยวกับการทำเวกเตอร์ระหว่างจุดที่เสนอที่ขอบของหน้าจอและผู้เล่นจากนั้นติดตามมันทุกๆ 10 voxels และดูว่ากำแพงชนกันหรือไม่ก่อนที่จะวางไข่ที่หน่วยหนึ่ง

อย่างไรก็ตามโซลูชันที่เสนอข้างต้นอาจมี CPU มากเกินไป

ข้อเสนอแนะเกี่ยวกับเรื่องนี้?

หมายเหตุ 1 สำหรับยูนิตที่วางไข่ฉันไม่ต้องการใช้รูปแบบการค้นหาแบบใดเพื่อหลีกเลี่ยงการชนกันของกำแพงเนื่องจากยูนิตเหล่านี้วิ่งไปทางเครื่องเล่น ดังนั้นหน่วยจะต้องวางไข่ที่ขอบของหน้าจอในสถานที่ที่เดินเป็นเส้นตรงเข้าหาผู้เล่นจะไม่ชนกับกำแพงใด ๆ


1
แผนที่เคลื่อนที่ไปรอบ ๆ พร้อมกับเครื่องเล่นหรือไม่หรือเครื่องเล่นเคลื่อนที่ไปรอบ ๆ ในแผนที่หรือไม่? นั่นคือแผนที่จะเปลี่ยนหรือไม่ ถ้าไม่ฉันขอแนะนำให้กรอกข้อมูลในจุดที่ไม่สามารถเข้าถึงได้ทั้งหมดในรุ่นเพื่อที่คุณไม่ต้องกังวลเกี่ยวกับพวกเขา
dlras2

หากผู้เล่นกำลังเคลื่อนที่หน่วยจะต้องมีวิธีการค้นหาเส้นทาง หากคุณต้องการพื้นที่เว้าคุณจะมีปัญหานี้และคุณต้องจัดหาวิธีแก้ปัญหาสำหรับหน่วยเคลื่อนที่ที่พยายามเข้าถึงผู้เล่นที่กำลังเคลื่อนที่ ... รู้จักการค้นหาเส้นทาง
Blau

1
หรือเพื่อแสดงความคิดเห็นของ Blau อีกทางหนึ่ง: คำถามของคุณไม่มีคำตอบที่ถูกต้อง (นอกเหนือจากเรื่องเล็กน้อยของแผนที่ที่ไม่มีแผ่นกระเบื้อง / พิกเซลติดผนังเลย) หากผู้เล่นสามารถเคลื่อนไหวได้ มันยังต้องการให้คุณกำหนดสิ่งที่คุณหมายถึงด้วย "เส้นตรง" เพื่อให้ได้คำตอบหากผู้เล่นอยู่กับที่
Martin Sojka

คำตอบ:


3

มีอัลกอริทึมที่มีประโยชน์สำหรับงานนี้ค่อนข้างมีประสิทธิภาพมากกว่าอัลกอริธึมอุทกภัยในสถานการณ์นี้ (ความซับซ้อนของรันไทม์นั้นแปรผันตามขนาดขอบเขตแทนที่จะเป็นพื้นที่น้ำท่วม): เป็นอัลกอริธึมกำลังสองของการเดิน แนวคิดง่าย: เริ่มต้นจากตำแหน่งผู้เล่น (จุดกึ่งกลางหน้าจอ) เลือกทิศทางและเดินจนกว่าคุณจะพบกำแพง เมื่อคุณชนกับกำแพงคุณจะเริ่มอัลกอริทึม: คุณเลือกการวางแนว (ขึ้นหรือลง) และเริ่มเดินข้ามขอบเขตของพื้นที่นี้โดยไฮไลต์พิกเซล สิ่งนี้ทำให้คุณมีขอบเขตภายในสำหรับพื้นที่ที่อนุญาต หลังจากนั้นคุณเพียงแค่ตรวจสอบว่าคะแนนผู้สมัครสำหรับหน่วยวางไข่อยู่ในขอบเขตนี้หรือไม่

นี่คือหลักการที่คุณควรปฏิบัติตามสำหรับการรันขอบเขต:

http://en.wikipedia.org/wiki/File:Marchsquares.png (ฉันยังไม่สามารถโพสต์รูปได้)

คำอธิบาย Wikipedia (แม้ว่าจะมีความซับซ้อนมากขึ้นเพราะมันใช้กับแอปพลิเคชันอื่น ๆ ในใจ):

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


10

ทำให้การเติมน้ำท่วมจากตำแหน่งของผู้เล่น; ทุกพื้นที่ "น้ำท่วม" จะเป็นพื้นที่เล่นที่ถูกต้องและอื่น ๆ ทั้งหมดเป็นกำแพง

แก้ไข: สำหรับข้อกำหนดเพิ่มเติมที่ "เข้าถึงได้ในแนวเส้นตรง" โปรดทราบว่าในพื้นที่ที่ไม่ต่อเนื่องคุณต้องกำหนดสิ่งนี้เพิ่มเติมอีกเล็กน้อย ตัวอย่างเช่นเส้นทางทั้งหมดข้างต้นอาจเป็น "เส้นตรง" ที่ถูกต้องในสภาพแวดล้อมดังกล่าวและฉันได้เห็นพวกเขาทั้งหมดที่ใช้ในเกมในบางจุดหรืออื่น ๆ :

ตัวแปร "เส้นตรง"

โดยเฉพาะอย่างยิ่งส่วนใหญ่ไม่ใช่การสลับ - ซึ่งหมายความว่าเพียงเพราะคุณสามารถเข้าถึง B จาก A ใน "เส้นตรง" ไม่ได้หมายความว่าคุณสามารถเข้าถึง A จาก B ได้เช่นกัน ไม่เป็นความจริงที่ตรงกันข้าม

นอกจากนี้ยังมีคำถามว่าคุณจะจัดการกับการเคลื่อนไหวในแนวทแยงได้อย่างไรหากจุด "ด้าน" หนึ่งจุดหรือทั้งสองจุดปิดกั้นอยู่


สิ่งนี้สามารถนำมาใช้ทั้งหมดใน HLSL หรือไม่?
Mathias Lykkegaard Lorenzen

@Mathias Lykkegaard Lorenzen: ใช่ในความสงสัยโดยการทำขั้นตอนของอัลกอริทึมเป็น Shader พิกเซลแต่ละคนและการแสดงผลระหว่างสองเป้าหมายเนื้อเช่น แต่ ... ทำไม ? คุณอาจต้องการข้อมูลจากอัลกอริทึมบน CPU อยู่แล้วสำหรับการค้นหาเส้นทางอย่างน้อยที่สุด
Martin Sojka

1
@Mathias Lykkegaard Lorenzen: นั่นแตกต่างจากที่คุณขอเล็กน้อย ในกรณีนี้: คุณจะกำหนด "เส้นตรง" ได้อย่างไรโดยใช้การแบ่งพื้นที่ว่างของสคีมา
Martin Sojka

2
แม้ว่าคุณไม่ต้องการใช้การบอกกล่าวการขอให้ cpu ทำงาน floodfill เป็นไปได้โปรดจำไว้ว่าคุณต้องเรียก floodfill เพียงครั้งเดียวจากนั้นคุณจะมีพื้นผิวที่กำหนดผนัง 3 สีพื้นที่ว่างและช่องว่างที่วางได้ สำหรับพื้นผิว 4096x4096 จะใช้เวลาน้อยกว่าวินาทีสำหรับซีพียูเพื่อทำงานที่เต็มไปด้วยน้ำท่วม
Ali1S232

1
ประเด็นก็คือคุณต้องเรียกใช้การเติมน้ำท่วมครั้งนี้เพียงครั้งเดียวและแม้ว่าภูมิประเทศของคุณจะเปลี่ยนไปในขณะที่เล่นเกมคุณจะต้องอัปเดตส่วนที่ได้รับผลกระทบและมีน้ำท่วมไหลผ่านพวกเขาซึ่งรวดเร็ว
TravisG

1

แล้วปล่อยให้เกิดขึ้นได้อย่างไร ฉันไม่เห็นปัญหาใด ๆ ในเรื่องนั้น


และถ้าพวกเขาวางไข่ด้านหลังกำแพงล่ะ คุณจะทำให้พวกเขาเข้าถึงผู้เล่นได้อย่างไร?
Mathias Lykkegaard Lorenzen

1
มันอาจเป็นปัญหาหากเกมมีสถานการณ์ที่จะฆ่าศัตรูทั้งหมดและมันจะวางไข่ศัตรู 50 ตัว แต่มีเพียงไม่กี่ตัวที่วางอยู่ด้านหลังกำแพง ผู้เล่นจะไม่สามารถฆ่าศัตรูได้และสถานการณ์จะไม่จบลง
Lie Ryan

1
หน่วยอื่น ๆ ยังคงไม่สามารถเข้าถึงผู้เล่นได้ทั้งนี้ขึ้นอยู่กับว่าผู้เล่นเคลื่อนที่อย่างไรหลังจากวางไข่คุณจะต้องปลดบางหน่วยในทั้งสองกรณี
aaaaaaaaaaaa

หมอกแห่งสงครามจะครอบคลุมการวางไข่เส็งเคร็ง
KRB

1
นั่นจะไม่ทำงานเมื่อผู้เล่นย้าย
aaaaaaaaaaaa

1

หากเป็นสิ่งสำคัญสำหรับคุณที่จะทำเครื่องหมายเฉพาะจุดด้วยเส้นตรงที่ถูกต้องกับผู้เล่นคุณสามารถใช้อัลกอริทึมดังต่อไปนี้ (เป็นรหัส c ++) มันกินมากกว่าน้ำท่วมปกติ อาจมีข้อบกพร่องเล็กน้อย (ฉันจะดีใจถ้ามีคนแก้ไข) เนื่องจากฉันไม่ได้ทดสอบโค้ดด้วยตัวเอง แต่คุณจะได้รับความคิด

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

คุณสามารถเติมแผนที่ด้วยสีที่แสดงถึงพื้นที่นูน ... วิธีนี้คุณสามารถวางไข่ยูนิตของคุณหากอยู่ในพื้นที่เดียวกัน หรือคุณสามารถค้นหาพื้นที่ที่เข้าถึงได้ง่ายขึ้น

นี่คือข้อมูลคงที่เพื่อให้คุณสามารถ precalc ได้

คุณต้องเติมจุดค้นหาภาพที่มีการเปลี่ยนแปลงจากการคุมตัวเป็นนูนมองเห็นเป็นเรื่องง่ายที่จะหาคุณมีสองสถานการณ์:

  1. แนวนอน: ตำแหน่งที่ส้มเปลี่ยนเป็นสีน้ำเงิน
  2. แนวตั้ง: ตำแหน่งที่สีแดงเปลี่ยนไปเป็นสีเขียวและสีส้ม

ป้อนคำอธิบายรูปภาพที่นี่


มันใช้งานไม่ได้ ดูที่ด้านล่างขวาโดยเฉพาะหยดในพื้นที่สีแดง มันนูนทั้งหมดดังนั้นจึงไม่มีการเปลี่ยนแปลงใด ๆ ที่จะทำให้สีอื่น ๆ ถูกนำมาใช้ แต่เห็นได้ชัดว่าไม่มีเส้นตรงจากด้านล่างของสีแดงบนขอบด้านขวาเป็นส่วนขวาสุดของสีแดงที่ขอบด้านล่าง
Loren Pechtel

@ Loren Pechtel นี้ทำด้วยมือคุณถูกต้องมีข้อผิดพลาดที่นั่นมันเป็นความผิดของฉัน แต่คุณสามารถตระหนักได้ว่าเป็นสถานการณ์เดียวกันกับที่การเปลี่ยนสีส้มเป็นสีฟ้า
Blau

@ Loren Pechtel เตือนว่า objetive หลีกเลี่ยงการวางไข่ในพื้นที่เช่นสีเหลือง วิธีการนี้ทำให้มั่นใจได้ว่าหากคุณปล่อยศัตรูในพื้นที่เดียวกับที่มีผู้เล่น แน่นอนว่ามันอาจเป็นเรื่องยากที่จะใช้ แต่ความคิดนั้นถูกต้อง
Blau

การแก้ไขของคุณไม่ได้ช่วย จุดสองจุดบนเส้นโค้งนูนจะไม่มีเส้นตรงที่ถูกต้องระหว่างจุดนั้น หน่วยงานเพิ่มเติมจะไม่ช่วย
Loren Pechtel

โปรดตรวจสอบคำจำกัดความของนูนที่อ้างอิงถึงพื้นที่หรือชุดของจุด ... en.wikipedia.org/wiki/Convex
Blau

1

นี่คือสิ่งที่ฉันใช้จริงในเกมของฉัน (2d simplex noise ที่สร้างขึ้นในโลกเกือบจะเหมือนกับของคุณ) - Rays เริ่มที่โปรแกรมเล่นพิจารณาการวางแนว (สุ่มถ้าคุณต้องการ) และไปตามบรรทัดนั้นจนกว่าคุณจะตีอะไร (ขอบของหน้าจอหรือดาวเคราะห์น้อย) หากคุณกดที่ขอบของหน้าจอ (ไม่ใช่ดาวเคราะห์น้อย / หยดสีขาว) แสดงว่าคุณมีเส้นตรงที่เปิดได้จากขอบของหน้าจอไปยังเครื่องเล่น จากนั้นวางไข่สัตว์ประหลาดในจุดที่คุณโจมตี หากคุณกดปุ่มดาวเคราะห์น้อยทำการทดสอบอีกครั้ง


0

โซลูชันอื่นที่ไม่ใช่ GPU ที่คุณสามารถใช้ได้คือการค้นหาเส้นทาง ก่อนที่จะวาดแผนที่ให้หาเส้นทางจากจุดวางไข่แต่ละจุดที่ขอบของแผนที่และดูว่ามีเส้นทางไปยังกึ่งกลางหรือไม่ การค้นหาเส้นทาง * นั้นถือว่าใช้ได้ในราคา / ประสิทธิภาพ แต่คุณสามารถทำสิ่งนี้ได้ก่อนที่เกมจะเริ่มต้นหากเป็นปัญหา

จุดวางไข่ใด ๆ ที่ไม่มีเส้นทางสามารถใส่รายการยกเว้นได้ หรือในทางกลับกัน (จุดใดก็ได้ที่มีเส้นทางสามารถใส่ในรายการการรวม)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.