กำลังสร้างแผนที่ย่อย


25

ฉันกำลังเขียนโปรแกรมเกมแบบเรียงต่อกันและมีพื้นฐานบางอย่าง (หญ้าดิน ฯลฯ ) แต่ฉันไม่สามารถหาวิธีสร้างแผนที่แบบสุ่มที่ดีเพราะเมื่อฉันเลือกแบบสุ่มจริงๆถ้าเป็นไทล์ ควรเป็นหญ้า / สิ่งสกปรกฉันได้สิ่งนี้:

รูปภาพในเกม

ฉันเข้าใจว่าทำไมสิ่งนี้ถึงเกิดขึ้น แต่สิ่งที่ฉันต้องการคือการสร้างพื้นที่ต่อเนื่องของหญ้าหรือดินอย่างต่อเนื่อง บางสิ่งที่เหมาะสมกว่านี้:

ผลลัพธ์ที่ต้องการ


1
นอกเหนือจากคำตอบที่เสนอคุณสามารถเขียนโปรแกรมหุ่นยนต์อัตโนมัติของคุณเองเพื่อสร้างแผนที่ดังกล่าว การปรับเปลี่ยนกฎของหุ่นยนต์คุณสามารถสร้างพฤติกรรมที่แตกต่างกันมากนำไปสู่แผนที่ประเภทต่าง ๆ ตัวอย่างเช่น gievn หุ่นยนต์ 2d ที่คล้ายกับชีวิตกฎน้ำท่วมอาจนำไปสู่ ​​"มหาสมุทรและหมู่เกาะ" (เช่นภาพของคุณด้านบน) และกฎอย่าง 1267/17 อาจนำไปสู่ห้องแล็บที่สวยงาม
Manu343726

คำตอบ:


19

สิ่งที่คุณสามารถทำได้คือสร้างแผนที่ Voronoi แบบสุ่ม:

  1. การเลือกแบบสุ่มcenter points(ดูจุดดำ) และตัดสินใจแบบสุ่มว่าเป็นหญ้าหรือดิน
  2. จากนั้นดูกระเบื้องทั้งหมดให้ตรวจสอบว่าใกล้กับcenter pointสิ่งสกปรกหรือหญ้าหรือไม่
  3. ทำ!

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

คุณสามารถปรับปรุงในเรื่องนี้โดยการแบ่งออกcenter pointsเป็นislandsด้วยอัลกอริทึมที่:

  1. คัดสรรกลุ่มเล็ก ๆ ของและกำหนดให้พวกเขาเป็นcenters pointsleaders
  2. วนซ้ำเพิ่มจุดกึ่งกลางที่ไม่อยู่ติดกันแบบสุ่มในแต่ละเทิร์น
  3. ทำ!

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


1
ขอบคุณ แต่ดูเหมือนจะเป็นทางออกที่ยากมาก
Vilda

2
นี่ไม่ใช่ทางออกที่ยากมาก center pointsครั้งแรกที่สุ่มเลือก จากนั้นตัดสินใจว่าพวกเขาเป็นหญ้าหรือดิน ทีนี้วนรอบอาร์เรย์และตัดสินใจว่าแต่ละไพ่อยู่ใกล้กับจุดสกปรกหรือจุดหญ้าหรือไม่ บางทีบอกฉันว่าส่วนไหนที่ท้าทาย?
wolfdawn

การวัดระยะทาง อย่างไรก็ตามฉันจะพยายามและแจ้งให้คุณทราบ
Vilda

ตกลงดังนั้นฉันได้สร้างบางจุดสำเร็จแล้ว ( dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png ) และอื่น ๆ ทั้งชั้นเรียนของฉันสำหรับการสร้างรูปลักษณ์เช่นนี้dropbox.com/s/pxhn902xqrhtli4/gen.java แต่มันก็ยังไม่ทำงาน
Vilda

3
@ViliX ลิงก์ของคุณเสีย
Artur Czajka

24

คุณสามารถใช้เสียงเพอร์ลินซึ่งเป็นมาตรฐานที่ใช้สำหรับการสร้างแผนที่ความสูง เสียงเพอร์ลินในเกม

จากนั้นคุณสามารถใช้ความสูงเป็นที่ปรึกษาโอกาสที่หญ้า / ดินจะเกิดขึ้นในพื้นที่หนึ่งของแผนที่จะสูงเท่าใด

ตัวอย่าง (ค่าเสียงรบกวน Perlin จาก 0-256): หากค่ามากกว่า 200 โอกาสที่หญ้าจะถูกวางไว้คือ 80% (ดิน 20%) หากค่าอยู่ระหว่าง 100 ถึง 200 โอกาสที่หญ้าจะถูกวางไว้ 50% (ความสกปรกยัง 50%) หากค่าต่ำกว่า 100 โอกาสที่หญ้าจะถูกวางไว้ที่ 20% (ดิน 80%)


เอาล่ะสมมติว่าฉันมีอาร์เรย์ [] [] ของโฟลต (ความน่าจะเป็น 0-1) และฉันสามารถใช้มันเพื่อวางไข่แผ่นกระเบื้องที่มีความน่าจะเป็น แต่ฉันจะเติมอาร์เรย์ความน่าจะเป็นนี้ได้อย่างไร อาร์เรย์คือ (สมมติว่า) 400x200 วิธีเติมค่าความน่าจะเป็นเป็นอย่างไร?
Vilda

เขาแนะนำให้เติมด้วยเสียงเพอร์ลิน (แทนที่จะเป็นเสียงสีขาวเหมือนเหรียญพลิก)
wolfdawn

ใช่ แต่ฉันจะประสบความสำเร็จได้อย่างไร
วิลดา

ลิงก์ที่ฉันโพสต์สามารถลบคำถามนี้ได้ ขั้นแรกให้สร้างเสียงรบกวนจากนั้นจึงปรับลดเสียงรบกวนผลลัพธ์จะเป็นอาร์เรย์ 2 มิติที่คุณสามารถใช้สำหรับการสร้างแผนที่ย่อยต่อไป ลิงก์
Klitz

มันเป็นคำตอบที่ดีมาก แต่แทบจะไม่ได้ผลลัพธ์ที่คล้ายกับที่คุณนำเสนอ
wolfdawn

8

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

http://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664

นี่คือรุ่นของฉันของวิธีการเซลลูลาร์ออโตเริ่มต้นด้วยการกรอกตารางด้วยการสุ่มแล้วเรียกใช้กฎออโตมาตาแบบ Cullular

  • หากเซลล์มีชีวิตมีเพื่อนบ้านน้อยกว่าสองคนมันจะตาย
  • หากเซลล์ที่มีชีวิตมีเพื่อนบ้านสองหรือสามคนมันจะมีชีวิตอยู่
  • หากเซลล์ชีวิตมีเพื่อนบ้านมากกว่าสามชีวิตมันจะตาย
  • หากเซลล์ที่ตายแล้วมีเพื่อนบ้านที่อาศัยอยู่สามคนมันจะมีชีวิต

และมันก็ดูเหมือนถ้ำ

ดัชนีสามารถแปลงเป็นตำแหน่ง x & y และกลับด้วยรหัสนี้

public int TileIndex(int x, int y)
{
    return y * Generator.Instance.Width + x;
}
public Vector2 TilePosition(int index)
{
    float y = index / Generator.Instance.Width;
    float x = index - Generator.Instance.Width * y;
    return new Vector2(x, y);
}

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

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

private int GetAdjacentCount(List<bool> list, Vector2 p)
{
    int count = 0;
    for (int y = -1; y <= 1; y++)
    {
        for (int x = -1; x <= 1; x++)
        {
            if (!((x == 0) && (y == 0)))
            {
                Vector2 point = new Vector2(p.x + x, p.y + y);
                if (PathFinder.Instance.InsideMap(point))
                {
                    int index = PathFinder.Instance.TileIndex(point);
                    if (list[index])
                    {
                        count++;
                    }
                }
                else
                {
                    count++;
                }
            }
        }
    }
    return count;
}
private List<bool> GetCellularList(int steps, float chance, int birth, int death)
{
    int count = _width * _height;
    List<bool> list = Enumerable.Repeat(false, count).ToList();
    for (int y = 0; y < _height; y++)
    {
        for (int x = 0; x < _width; x++)
        {
            Vector2 p = new Vector2(x, y);
            int index = PathFinder.Instance.TileIndex(p);
            list[index] = Utility.RandomPercent(chance);
        }
    }
    for (int i = 0; i < steps; i++)
    {
        var temp = Enumerable.Repeat(false, count).ToList();
        for (int y = 0; y < _height; y++)
        {
            for (int x = 0; x < _width; x++)
            {
                Vector2 p = new Vector2(x, y);
                int index = PathFinder.Instance.TileIndex(p);
                if (index == -1) Debug.Log(index);
                int adjacent = GetAdjacentCount(list, p);
                bool set = list[index];
                if (set)
                {
                    if (adjacent < death)
                        set = false;
                }
                else
                {
                    if (adjacent > birth)
                        set = true;
                }
                temp[index] = set;
            }
        }
        list = temp;
    }
    if ((steps > 0) && Utility.RandomBool())
        RemoveSmall(list);
    return list;
}

2
โปรดอธิบายว่าโค้ดของคุณทำอะไรได้บ้างแทนที่จะโพสต์ตัวอย่างโค้ดและลิงค์ของโค้ดเอง คำตอบของคุณควรอยู่ในตัวเองดังนั้นแม้ว่าลิงก์จะพังก็ยังใช้ได้
คดีฟ้องร้องกองทุนโมนิก้า

6

เลือกจุดบนแผนที่ วางประเภทไทล์ที่ต้องการด้วยค่าฐานเช่น 40 ติดตามตำแหน่งที่คุณวางไทล์ที่คุณต้องการ เพิ่มจุดเริ่มต้นลงในรายการ

สำหรับแต่ละจุดในรายการนี้คุณเยี่ยมชมเพื่อนบ้านทั้งหมด ในขณะที่คุณมีพลังงานเหลือพอ (เริ่มที่ 40) เพิ่มไทล์ที่ต้องการและเพิ่มลงในรายการที่จะเข้าเยี่ยมชม ให้กระเบื้องใหม่ใช้พลังงานน้อยลงตามที่คุณกำหนด ที่ง่ายที่สุด = การลดแบบสุ่ม หลังจากคุณเยี่ยมชมไทล์จากรายการให้ลบออก เริ่มต้นใหม่อีกครั้งโดยไปที่ใด ๆ ที่ไม่ได้เข้าชม แต่สร้างแล้ว

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