วิธีเก็บข้อมูลแผนที่ 2D ที่ไม่มีขีด จำกัด หรือไม่?


29

ฉันมี platformer 2D ที่สามารถจัดการชิ้นส่วนที่มีขนาด 100 ถึง 100 แผ่นในขณะนี้พิกัดก้อนจะถูกเก็บไว้เป็นเวลานานดังนั้นนี่เป็นข้อ จำกัด เพียงแผนที่เท่านั้น (maxlong * maxlong) ทุกตำแหน่งเอนทิตี้และอื่น ๆ นั้นเกี่ยวข้องกับชิ้นงานดังนั้นจึงไม่มีข้อ จำกัด

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


2
บางโครงสร้างข้อมูลที่คุณสามารถมองเข้าไปหาแรงบันดาลใจมากขึ้นการฝึกอบรมเบาบางและ(หลาย) ตารางหน้า
Andrew Russell

ลำดับความสำคัญต่ำ: คุณสามารถอธิบายได้ไหมว่าชนิดข้อมูล "ยาว" เป็น 32- หรือ 64- บิต?
Randolf Richardson

2
@ Randolf ระบุว่านี่คือ C # สันนิษฐานว่าเขาหมายถึง C # longซึ่งเป็น 64- บิต (maxlong จึงเป็นInt64.MaxValue)
Andrew Russell

Notch มีสิ่งที่น่าสนใจที่จะพูดเกี่ยวกับแผนที่ที่ไม่มีที่สิ้นสุดใน Minecraft ในบล็อกของเขาที่นี่: notch.tumblr.com/post/3746989361/terrain-generation-part-1
dlras2

คำตอบ:


17

สร้างรูปแบบแผนที่ที่กำหนดเองสำหรับเกมของคุณ ง่ายกว่าที่คุณคิด เพียงใช้คลาส BinaryWriter ก่อนอื่นให้เขียนส่วนหัวเป็นสองสาม ints หรือ uints ข้อมูลที่จะรวมไว้ในส่วนหัว:

  • รูปแบบไฟล์สตริง / เลขอาถรรพ์ของคุณ
  • start / end / size ของ chunks ที่อธิบายในไฟล์นี้

และยัง (และนี่มาถึงส่วนที่สำคัญด้านประสิทธิภาพ

  • ints ที่อธิบายตำแหน่งเริ่มต้นภายในไฟล์ ดังนั้นคุณไม่ต้องค้นหาชิ้นเฉพาะ

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

จากนั้นเมื่อคุณต้องการโหลดชิ้นข้อมูลเฉพาะคุณจะต้องค้นหาภายในดัชนี เมื่อคุณได้รับตำแหน่งให้ตั้งค่า fileStream.Position = PositionOfChunkFromIndex และคุณสามารถโหลดได้

มันคือทั้งหมดที่เกี่ยวกับการออกแบบของรูปแบบไฟล์ที่มีส่วนหัวอธิบายเนื้อหาของไฟล์ที่มีประสิทธิภาพมากที่สุด

เพียงบันทึกไฟล์ด้วยนามสกุลที่กำหนดเองที่คุณสร้างขึ้นและไปที่นั่น

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


12
เป็นค่าชี้ให้เห็นว่าถ้าคุณกำลังจะแก้ไขไฟล์นี้ได้ทันทีคุณจะต้องการส่วนหัว / ดัชนีคงที่หรือภายนอกขนาดเช่นคุณสามารถเพิ่มชิ้นไปยังไฟล์โดยไม่ต้องเขียน ไฟล์ทั้งหมด (เนื่องจากการเปลี่ยนแปลงออฟเซ็ต)
Andrew Russell

ณ จุดนี้คุณไม่ได้ใช้ฐานข้อมูล flatfile หรือไม่
Ape-inago

13

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

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

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

ฉันยังไม่ได้ใช้เพื่อจัดเก็บข้อมูลลงในไฟล์ แต่มันเป็นปัญหาที่น่าสนใจและฉันอาจจัดการปัญหาต่อไป


นี่คือต้นไม้ที่ขยายได้ใช่มั้ย ฉันพลาดอะไรไป
kaoD

2
การปรับปรุงที่ใหญ่ที่สุดเหนือต้นไม้ที่ขยายได้คือ 'โหนด' บางโหนดของต้นไม้ซึ่งมีประชากรหนาแน่นมาก (ค่าเริ่มต้น 70%) ไปเป็นอาร์เรย์ 2 มิติแทนที่จะทำให้มันมีโครงสร้างเหมือนต้นไม้ สิ่งนี้ทำให้คุณมีความเร็วในการค้นหาอาร์เรย์โดยไม่มีขนาด (อนันต์) ของอาร์เรย์อนันต์
dlras2

ทั้งใบไม้และโหนดด้านในใช่มั้ย ความคิดที่น่าสนใจอาจให้ผลลัพธ์ที่ดีฉันจะลองถ้าฉันต้องการสิ่งนี้ Btw, +1 สำหรับการแจกโค้ดและคำตอบด่วน! Oh, และหน่วยทดสอบทำเกินไปฉัน (เศร้า) ไม่เคยทำในโครงการส่วนบุคคลของฉัน :)
kaoD

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

1
ฉันไม่เห็นมันขอโทษ! ฉันยังต้องการทำให้มันสะอาดขึ้น แต่ฉันค่อย ๆ ปรับปรุงโค้ดบางส่วนระหว่างชั้นเรียนและการบ้านเพื่อที่จะไม่อยู่พักหนึ่ง สำหรับตอนนี้ตัวอย่างเก่าและไม่สวยอยู่ที่นี่: j.mp/qIwKYtโดยไม่สวยฉันหมายถึงบางส่วนต้องการคำอธิบายมากมายดังนั้นอย่าลืมอ่าน README และรู้สึกฟรีเพื่อถามคำถามที่นี่หรือ ทางอีเมล.
dlras2

3

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

  PostgreSQL (ฟรีและโอเพนซอร์ส)
  http://www.postgresql.org/

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

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

ฉันสังเกตเห็นว่าบางเกมเก็บ "แคช" ของข้อมูลแผนที่ในฮาร์ดไดรฟ์ในเครื่องหลังจากได้รับเป็นครั้งแรก (ไม่ต้องสงสัยเลยว่าจะลด I / O เครือข่าย) เช่น Ashen Empires:

  Ashen Empires (เล่นฟรีใช้งาน 2D ที่สวยงาม)
  http://www.ashenempires.com/

การติดตามการประทับเวลา "อัปเดตล่าสุด" กับแต่ละก้อน / ไทล์จะเป็นประโยชน์เช่นกันเนื่องจากที่ซึ่งข้อมูลที่เก็บไว้ในเครื่องพร้อมใช้งานแบบสอบถาม SQL อาจรวมส่วนเพิ่มเติมของ "WHERE timestamp_column> $ local_timestamp" เพื่อรับเฉพาะชิ้นส่วน ดาวน์โหลดแล้ว (ข้อดีสองประการของการประหยัดแบนด์วิดท์เช่นนี้คือลดต้นทุนการเชื่อมต่อและความล่าช้าน้อยลงสำหรับผู้เล่นของคุณซึ่งจะเห็นได้ชัดเจนขึ้นเมื่อเกมของคุณได้รับความนิยม)

สกรีนช็อตจาก Ashen Empires (ตัวละครสองสามตัวอยู่ที่ธนาคารท้องถิ่นและจากลักษณะของกระดูกเหล่านั้นที่อยู่บนพื้นดูเหมือนว่าสัตว์ประหลาดโครงกระดูกสองสามตัวต้องเดินเข้ามาและถูกสังหารโดยทหารยามของเมืองในท้องถิ่น):

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


2

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

ในทางทฤษฎีคุณสามารถทำแผนที่ไม่มีที่สิ้นสุดอย่างแท้จริงซึ่งจะบันทึกเป็นไฟล์ขนาดเล็กมากด้วยวิธีนี้


@Josh Petrie ขอบคุณสำหรับการแก้ไขภาษา / โวหารที่สำคัญและยิ่งใหญ่สำหรับโพสต์ของฉัน น่าเสียดายที่ฉันไม่สามารถลงคะแนนแก้ไข :-D
รหัส sh

1

มีวิธีใดบ้างที่คุณสามารถแบ่งชิ้นส่วน (บางส่วนของ 'ทวีป / ประเทศ' ในโลกของคุณ)? ดังนั้นบางทีคุณอาจมีไฟล์ดัชนีบางชนิดที่ช่วยให้คุณค้นหาไฟล์ย่อย / ส่วนใดของไฟล์ที่ใหญ่กว่าที่คุณต้องการโหลดเพื่อให้มีหน่วยความจำในไฟล์ ...


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

0

คุณสามารถนำไอเดียจาก Minecraft แต่เดิมพวกเขามีไฟล์ต่ออัน ตอนนี้พวกเขาใช้รูปแบบ MCRegion ซึ่งกลุ่มจะแบ่งเป็น 32x32 พื้นที่และเก็บหนึ่งในนั้นต่อไฟล์

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