จะสร้างเกมที่ไม่มี OOP ได้อย่างไร? [ปิด]


10

ฉันกำลังศึกษาการพัฒนาเกมและฝึกทำเกม

ฉันใช้ OOP เป็นจำนวนมากในเกมของฉัน ตัวอย่างเช่นขีปนาวุธแต่ละตัวที่ถูกยิงเป็นตัวอย่างของMissileวัตถุและเพิ่มเข้าไปในรายการของMissileวัตถุ รถถังแต่ละคันในเกมนั้นเป็นTankวัตถุ เป็นต้น

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

มันยากสำหรับฉันที่จะจินตนาการว่าเกม (ซึ่งซับซ้อนกว่า Pac-Man) สามารถตั้งโปรแกรมในภาษาที่ไม่ใช่ OO (ไม่มีการดูหมิ่นผู้เขียนโปรแกรมที่ไม่ใช่ OO แน่นอน) ไม่เพียง แต่จะใช้เวลานานแค่ไหน แต่ส่วนใหญ่ในแง่ของวิธีการออกแบบเกมด้วยวิธีนี้

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

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

ถ้าเป็นเช่นนั้นคุณช่วยให้ฉันทราบได้อย่างไรตัวอย่างเช่นการตรวจจับการชนระหว่างรถถังและขีปนาวุธ N สามารถทำได้โดยไม่ต้องใช้ OOP?


6
นี่เป็นคำถามเชิงปรัชญาหรือไม่? แม้ว่าคุณจะไม่เรียกรถถังของคุณว่า "วัตถุ" คุณอาจต้องการ "เอนทิตี", "นักแสดง", "ตัวแทน", "โครงสร้าง" หรือชื่ออื่น ๆสำหรับแนวคิดเดียวกันซึ่งเป็นชุดของ คุณลักษณะและพฤติกรรมที่ประกอบเป็นวัตถุทรงลูกบาศก์หมุนด้วยป้อมปืนที่สามารถยิงสิ่งต่าง ๆ ได้เรียกว่ารถถัง ภาษาการเขียนโปรแกรมจะมีวิธีที่แตกต่างกันในการทำให้ความคิดแบบเดียวกันนี้เป็นจริง แต่ในที่สุดมันจะเป็นรถถัง
Anko

เกมหลายเกมใช้ระบบที่อิงกับคอมโพเนนต์ตามที่คำตอบนี้อธิบาย: gamedev.stackexchange.com/a/31491/9366
John McDonald

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

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

คำตอบ:


16

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

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

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

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

ในการโปรแกรมเชิงฟังก์ชันทุกฟังก์ชั่นจะต้องคำนวณค่าส่งคืนจากข้อมูลที่ส่งผ่านเท่านั้น ไม่มีการอ่านจาก "สถานะโลก"

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

บทความบล็อกชุดนี้มีความคิดเพิ่มเติมเกี่ยวกับการเขียนเกมในสไตล์การใช้งาน:

http://prog21.dadgum.com/23.html

บทความนี้ตอบคำถามของ "shell hits a tank" โดยเฉพาะ:

http://prog21.dadgum.com/189.html

ในความเป็นจริงเพียงแค่อ่านบล็อกทั้งหมด มีสิ่งดีๆอยู่ที่นั่นและบทความก็สั้น


12

โปรแกรมเชิงวัตถุใด ๆ สามารถ refactored เป็นโปรแกรมกระบวนงานโดยแทนที่คลาสทั้งหมดด้วยโครงสร้างและแปลงฟังก์ชันสมาชิกทั้งหมดเป็นฟังก์ชันสแตนด์อะโลนซึ่งใช้วัตถุซึ่งจะthisเป็นอาร์กิวเมนต์

ดังนั้น

 missile.setVelocity(100);

กลายเป็น

 setMissileVelocity(missile, 100);

หรือเมื่อฟังก์ชันนั้นเล็กน้อยคุณก็ทำได้

 missile.velocity = 100;

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

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

struct Missile {
     int x;
     int y;
     int velocity;
}

Missile missiles[256];

กลายเป็น

int missileX[256];
int missileY[256];
int missileVelocities[256];

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

function updateMissilePosition(int index) {
     missileX[index] += missileVelocity[index];
}

1
แต่missileเป็นตัวอย่างของวัตถุ ในแบบที่ไม่ใช่ OOP ไม่มีกรณีฉันถูกต้องหรือไม่ ถ้าเป็นเช่นนั้นคุณจะทำ setMissileVelocity (missile, 100) ได้อย่างไร?
user3150201

1
@ user3150201 คุณไม่ถูกต้องทั้งหมด ภาษาที่ไม่ใช่ OOP ส่วนใหญ่ (และฉันขอโต้แย้งเพียงเกี่ยวกับสิ่งที่เหมาะสำหรับการพัฒนาเกมที่จริงจัง) รองรับโครงสร้าง โครงสร้างเป็นเหมือนคลาสซึ่งไม่มีอะไรเลยยกเว้นตัวแปรสาธารณะ ดังนั้นมันจะช่วยให้คุณสร้างชนิดMissileซึ่งเป็นโครงสร้างที่มีหลายสาขาเช่นx, y, และangle velocity
Philipp

@ user3150201 อัปเดตคำตอบพร้อมกับส่วนเกี่ยวกับวิธีการทำโดยไม่มีโครงสร้าง
Philipp

Nice ตอบ Philipp แม้ว่าฉันไม่เข้าใจว่าทำไมคนจะไม่ต้องการเขียนโปรแกรมเชิงวัตถุ เป็นการยากที่จะอ่านภาษาที่ไม่ใช่ OOP และอาจทำให้หงุดหงิด รหัสสามารถเป็นระเบียบในเวลาไม่นาน
Zhafur

2
@Zhafur คุณรู้หรือไม่ว่าคำสั่งของคุณเป็น Flamebait อันยิ่งใหญ่ใช่ไหม?
Philipp

6

ฉันทำมันดังต่อไปนี้:

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

...

class Entity //let's say you had 100 instances of this
{
   int a;
   char b;
   function foo() 
   {
      .../*can access 'this' herein*/
   }
}

คุณจะแทนที่ด้วย

int a[100];
char b[100];
function foo(int index);

thisเพื่อที่คุณจะผ่านในขณะนี้ดัชนีในการทำงานที่จะได้รับสิ่งที่มักจะเป็น

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการสร้างหน่วยงานอื่น ๆ เป็นอาร์เรย์ของ structs หรือวิทยาการดูมิกเวสต์วิวัฒนาการลำดับชั้นของคุณ


0

นอกเหนือจากคำตอบที่มีอยู่คุณอาจต้องการทราบวิธีการทำ polymorphism ในภาษาขั้นตอน

มีสองวิธี:

การจัดเก็บประเภท

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

วิธีอื่นคือ:

การจัดเก็บพอยน์เตอร์ของฟังก์ชัน

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

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

ด้วยการอนุญาตให้ตั้งค่าแต่ละฟังก์ชั่นอย่างอิสระคุณจะได้รูปแบบกลยุทธ์ฟรี


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

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