การประหยัด / โหลดเกมของรัฐ?


12

วิธีหรืออัลกอริทึมที่ใช้มากที่สุดสำหรับการบันทึกสถานะของเกม (โปรไฟล์), ไฟล์ข้อความฐานข้อมูลจะมีวิธีการเข้ารหัสและสิ่งที่เกี่ยวข้องได้อย่างไร

ฉันเห็น Caesar IV ใช้ mySQL

ข้อเสนอแนะใด ๆ

คำตอบ:


20

ฉันค่อนข้างแน่ใจว่ามันมักจะทำในรูปแบบที่เป็นกรรมสิทธิ์ (ไบนารี) เพียงแค่เขียนตัวแปรแต่ละตัวจากสิ่งที่สถานะเกมที่คุณใช้เป็นไฟล์หรืออ่านไฟล์นั้นกลับเข้าไปในอินสแตนซ์ของ struct ใน C ++ ตัวอย่างเช่นคุณสามารถปฏิบัติต่อวัตถุเช่นอาร์เรย์ของไบต์และเพียงแค่เขียน () ลงในไฟล์หรือ fread () จากไฟล์และโยนกลับเข้าไปในรูปแบบวัตถุ

หากคุณใช้ Java หรือภาษาอื่นคุณสามารถเลือกใช้serializationเพื่อให้งานง่ายขึ้น คำอธิบาย Java อยู่ที่ด้านล่างของคำตอบนี้ ภาษาอื่น ๆ (ระดับสูงกว่า C ++) มีไลบรารี่อนุกรมหรือฟังก์ชั่นในตัวเช่นกันซึ่งคุณควรเลือกใช้ ว่าไม่มีประสิทธิภาพประจำอนุกรมอาจจะไม่มีพื้นที่ว่างในฮาร์ดดิสก์ในปัจจุบันมีราคาถูกโดยเฉพาะอย่างยิ่งเมื่อรัฐเกมที่ไม่ควรจะมีขนาดใหญ่มากที่ทั้งหมดและจะป้องกันไม่ให้คุณจากการเขียนและการรักษากิจวัตรอนุกรมของคุณเอง

คุณควรอย่างยิ่งที่ไม่ได้ใช้ MySQL (แค่อ่านประโยคแรกของรีวิวนี้ ) หากคุณต้องการจริงๆฐานข้อมูลเชิงสัมพันธ์ด้วยเหตุผลบางอย่างใช้SQLite ; มันเป็นระบบฐานข้อมูลที่มีน้ำหนักเบาและมีอยู่ในไฟล์ฐานข้อมูลเดียว แต่สำหรับเกมส่วนใหญ่ฐานข้อมูลเชิงสัมพันธ์ไม่ใช่วิธีที่จะไปและ บริษัท ที่พยายามใช้พวกเขามักจะใช้มันเป็นตารางการค้นหาคีย์ - ค่าแทนที่จะเป็นฐานข้อมูลเชิงสัมพันธ์ที่แท้จริง

การเรียงลำดับของการเข้ารหัสไฟล์ดิสก์ภายในใด ๆ ที่เป็นเพียง obfuscation ; แฮ็กเกอร์ใด ๆ ก็จะดมกลิ่นข้อมูลทันทีหลังจากที่โปรแกรมของคุณถอดรหัส ฉันเป็นการส่วนตัวกับสิ่งนั้นโดยเฉพาะกับเกมที่มีผู้เล่นหนึ่งคน มุมมองของฉันคือเจ้าของเกม (ควรให้ความสำคัญกับลูกค้า) ควรได้รับอนุญาตให้แฮ็คที่เกมหากพวกเขาต้องการ ในบางกรณีมันสามารถสร้างความรู้สึกที่ดีขึ้นของชุมชนและ "mods" สามารถพัฒนาขึ้นสำหรับเกมของคุณซึ่งนำพาลูกค้ามาหาคุณ ตัวอย่างล่าสุดที่นึกถึงคือPortal ใน mod mod ที่เพิ่งเปิดตัว มันเผยแพร่ในเว็บไซต์ข่าวนักเล่นเกมทั่วอินเทอร์เน็ตและคุณสามารถเดิมพันมันทำให้ยอดขายของ Minecraft เพิ่มขึ้น


ถ้าด้วยเหตุผลบางอย่างที่คุณคลั่งไคล้มากพอที่จะใช้ Java สำหรับการพัฒนาเกมเช่นฉันนี่เป็นคำอธิบายสั้น ๆ เกี่ยวกับการทำให้เป็นอันดับใน Java:

เก็บข้อมูลสถานะเกมทั้งหมดของคุณไว้ในคลาสเดียวทำให้คลาสเป็นอนุกรมโดยการSerializableใช้งานใช้transientคำสำคัญถ้าคุณผสมตัวแปรอินสแตนซ์พิเศษเข้ากับคลาส (ออบเจ็กต์ชั่วคราวไม่ต่อเนื่อง) และใช้ObjectOutputStreamเพื่อเขียนObjectInputStreamไฟล์ . แค่นั้นแหละ.


2
Hehe, The Witcher ไม่ได้เข้ารหัสข้อมูลของพวกเขา ง่ายมากที่จะเปิดไฟล์บันทึกเกมในโปรแกรมแก้ไข hex, ยุ่งกับมันเล็กน้อยและรับเจี๊ยบการ์ดเปล่าทั้งหมด ... โอ้พระเจ้าฉันขอโทษด้วย!
แอนโธนี

ฉันใช้. NET binary serialization สำหรับการบันทึกเกมและ C # อาจเป็นแพลตฟอร์มที่เหมาะสมกว่า Java เล็กน้อยสำหรับการพัฒนาเกม ฉันชอบวิธีบันทึกกราฟวัตถุทั้งหมดโดยอัตโนมัติ สิ่งนี้เคยยากกว่านี้มาก แน่นอนว่าตอนนี้มีความท้าทายในการแยกชิ้นส่วนที่ไม่จำเป็นออกเช่นพื้นผิว แต่นั่นไม่ใช่เรื่องใหญ่ที่จะทำให้สำเร็จ
BlueMonkMN

ฉันไม่เห็นด้วยที่ C # ได้รับความนิยมมากกว่า Java ในการพัฒนาเกมเล็กน้อย มีเหตุผลมากกว่านี้แสดงถึงความเป็นส่วนตัวและในฐานะนักพัฒนาทั้ง XNA และ Java ฉันชอบ Java อย่าลังเลที่จะแสดงคำแนะนำเกี่ยวกับการทำให้เป็นอันดับใน C # ด้วยหากคุณต้องการฉันไม่เคยทำ แต่ฉันสามารถแก้ไขมันเป็นคำตอบของฉัน การทำให้เป็นอันดับของ Java จะบันทึกกราฟวัตถุทั้งหมดและคำสำคัญ 'ชั่วคราว' ในตัวแปรไม่รวมส่วนที่ไม่จำเป็นเช่นพื้นผิว สมาชิกที่ไม่ได้อยู่ชั่วคราวใด ๆ จะต้องเป็น Serializable หรือคุณสามารถเขียนเมธอด writeObject แบบกำหนดเองเพื่อรับสิ่งนั้น
Ricket

ผักดองของไพ ธ อนจะบันทึกกราฟวัตถุทั้งหมดให้คุณเช่นกันและใช้งานได้ง่าย เมื่อถึงเวลาที่ต้องทำให้หมดความเป็นคุณคุณจะถูกนำกลับไปยังวัตถุที่มีความชุ่มชื้นอย่างเต็มที่และง่ายดายเหมือนพาย: docs.python.org/library/pickle.html
drhayes

เมื่อใช้ตัวจัดรูปแบบไบนารีในตัวการยกเว้นบางฟิลด์จากการทำให้เป็นอนุกรมใน C # /. NET นั้นง่ายพอ ๆ กับการตกแต่งด้วยแอตทริบิวต์ [NonSerialized] อย่างไรก็ตามสิ่งที่มองข้ามได้ง่ายคือเหตุการณ์ที่คอมไพเลอร์สร้างขึ้น (เช่นเหตุการณ์ใด ๆ ที่ไม่มีตัวดำเนินการเพิ่ม / ลบแบบกำหนดเอง) สร้างเขตข้อมูลสำรองเพื่อจัดเก็บสมาชิกของพวกเขา ดังนั้นจึงเป็นเรื่องง่ายที่จะตั้งใจ (และไม่ทราบ) รวมตัวจัดการเหตุการณ์ในกราฟวัตถุที่ต่อเนื่องกัน ในการหลีกเลี่ยงสิ่งนี้คุณต้องเพิ่มแอตทริบิวต์ NonSerialized ให้กับการประกาศเหตุการณ์ แต่คุณต้องเพิ่มตัวระบุ "field:":[field: NonSerialized]
Mike Strobel

3

หากคุณกำลังเขียนรหัสของตัวเองพูดใน C ++ คุณสามารถใช้ไฟล์ไบนารี ไฟล์ไบนารีให้รูปแบบการเข้ารหัสผ่านการทำให้งงงวย แต่ดังที่บันทึกไว้ทั่ว internets นั่นเป็นรูปแบบความปลอดภัยที่อ่อนแอมาก

หรือคุณสามารถใช้RapidXMLเช่นถ้าคุณต้องการโซลูชันที่มนุษย์สามารถอ่านได้

หากคุณกำลังใช้งานเฟรมเวิร์กบางประเภทให้มองหาฟังก์ชั่นการสนับสนุนไฟล์ HTH


0

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

  1. อ่านไฟล์ในหน่วยความจำ
  2. พอยเตอร์ชี้ไปที่บัฟเฟอร์กับชนิดของวัตถุ

มันเร็ว แต่เป็นเรื่องที่น่าเบื่อในการรักษาเฉพาะแพลตฟอร์มและไม่ยืดหยุ่น

เมื่อเร็ว ๆ นี้ฉันเคยเห็นเกมสองสามเกมใช้ SQLite คนที่ฉันพูดคุยดูเหมือนจะชอบ


0

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

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

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

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


1
ในฐานะที่เป็นโน้ตย่อ: การใช้งานฟังก์ชั่น "บันทึก" และ "โหลด" สำหรับแต่ละเวอร์ชั่นของเกมจะกลายเป็นฝันร้ายของการบำรุงรักษาอย่างรวดเร็ว ฉันได้พบวิธีแก้ปัญหาที่ดีกว่าคือการฝังหมายเลขรุ่นเขียนฟังก์ชั่น "บันทึก / โหลด" สำหรับเวอร์ชั่นปัจจุบันของเกมและเขียนฟังก์ชั่น "การแปลง" จากเวอร์ชันไม่ล่าสุดเป็นเวอร์ชันปัจจุบัน จากนั้นให้ฟังก์ชั่นการแปลงทั้งหมดของคุณอยู่เสมอ การพยายามโหลดเกมสิบเวอร์ชันเก่าจะเรียกใช้ฟังก์ชันการแปลงสิบชุดตามลำดับจากนั้นฟังก์ชัน "โหลดรุ่นเกมปัจจุบัน" แบบเนทีฟ
ZorbaTHut

ง่ายกว่ามากในการรักษาระยะยาว - การรักษาฟังก์ชั่น "โหลดทุกไฟล์เกมก่อนหน้า" จะเปลี่ยนเป็นการดำเนินการแบบเวลาพหุนามอย่างรวดเร็ว
ZorbaTHut

ในเกมที่ฉันทำมามันไม่ซับซ้อน - แทนที่จะเก็บหลาย ๆ วิธีการโหลด / บันทึกวิธีเดียวใช้หมายเลขรุ่นเพื่อกำหนดว่าจะอ่านและเขียนไบต์ใด สิ่งนี้ทำได้ง่ายยิ่งขึ้นถ้าคุณไม่เพียง แต่เขียนโครงสร้าง แต่ใช้การโหลดและบันทึกเป็นการดำเนินการที่ระดับชนิดข้อมูลดั้งเดิม (เช่น ReadByte / ReadFload / etc) จากนั้นถ้าคุณเพิ่มสมาชิกใหม่คุณสามารถทำสิ่งที่ชอบถ้า (รุ่น> 10) {someNewByte = ReadByte (); } การใช้งานด้วยวิธีนี้ทำให้การสนับสนุนแพลตฟอร์ม endian ต่าง ๆ ง่ายขึ้นเช่นกัน
kevin42

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

0

หากคุณสามารถใช้รูปแบบเดียวกับที่คุณใช้ในการจัดเก็บระดับของคุณมันเป็นโบนัส

ตัวอย่างเช่นเกมอย่างเช่น Peggle อาจมีเค้าโครงบอร์ดเริ่มต้นจำนวนลูกคะแนนปัจจุบัน (0 สำหรับบอร์ดเริ่มต้น) เป็นต้นจากนั้นเกมที่บันทึกไว้สามารถใช้รูปแบบเดียวกันได้ทุกประการ

หากคุณใช้รูปแบบเดียวกันเกมบันทึกและโหลดระดับสามารถแบ่งปันรหัสทำให้งานของคุณง่ายขึ้น!

สำหรับเกมที่มีไฟล์แผนที่ขนาดใหญ่จริง ๆ เกมบันทึกสามารถรวมไฟล์แผนที่ได้โดยการอ้างอิง ไฟล์ระดับเริ่มต้นอาจทำสิ่งเดียวกันแม้ว่าจะทำให้การกลับมาที่แผนที่นั้นง่ายขึ้นด้วยเหตุผลบางอย่างเรื่องราวมีตัวละครกลับมาที่เดิมยกเว้น NPC บางตัวตายและมีศพอยู่ทั้งหมด เกิน.

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