DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร

"ฉันรู้ว่าฉันไม่รู้อะไรเลย" โสกราตีส

เพื่อใคร: สำหรับชาวไอทีที่ถุยน้ำลายนักพัฒนาทั้งหลายและอยากเล่นเกมของพวกเขา!

เกี่ยวกับอะไร: วิธีเริ่มเขียนเกมใน C/C++ หากคุณต้องการ!

ทำไมคุณควรอ่านสิ่งนี้: การพัฒนาแอพไม่ใช่งานถนัดของฉัน แต่ฉันพยายามเขียนโค้ดทุกสัปดาห์ เพราะฉันรักเกม!

สวัสดีฉันชื่อ อันเดรย์ แกรนกินฉันเป็น DevOps ที่ Luxoft การพัฒนาแอปพลิเคชันไม่ใช่งานพิเศษของฉัน แต่ฉันพยายามเขียนโค้ดทุกสัปดาห์ เพราะฉันรักเกม!

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

ในขณะเดียวกัน เมื่อเล่นเกมของคนอื่น เรามักถูกจำกัดโดยสถานที่ โครงเรื่อง ตัวละคร กลไกของเกมที่คนอื่นคิดขึ้นมา ฉันจึงได้รู้ว่า...

… ถึงเวลาสร้างโลกของคุณเอง อยู่ภายใต้การควบคุมของฉันเท่านั้น โลกที่เราเป็นพระบิดา พระบุตร และพระจิต!

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

ในบทความนี้ฉันจะพยายามบอกคุณว่าฉันเริ่มเขียนเกมขนาดเล็กใน C / C ++ ได้อย่างไร ขั้นตอนการพัฒนาคืออะไรและฉันหาเวลาว่างสำหรับงานอดิเรกในสภาพแวดล้อมที่วุ่นวายได้ที่ไหน เป็นอัตนัยและอธิบายกระบวนการเริ่มต้นของแต่ละคน เนื้อหาเกี่ยวกับความโง่เขลาและศรัทธาเกี่ยวกับภาพส่วนตัวของฉันเกี่ยวกับโลกในขณะนี้ กล่าวอีกนัยหนึ่งคือ "ฝ่ายบริหารไม่รับผิดชอบต่อสมองส่วนตัวของคุณ!"

การปฏิบัติ

“ความรู้ที่ปราศจากการฝึกฝนก็ไร้ประโยชน์ การฝึกฝนที่ปราศจากความรู้นั้นเป็นอันตราย” ขงจื๊อ

สมุดบันทึกของฉันคือชีวิตของฉัน!


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

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
สมุดบันทึกของฉัน (เต็มแล้ว) นี่คือลักษณะที่ปรากฏ ประกอบด้วยงานประจำวัน ไอเดีย ภาพวาด ไดอะแกรม วิธีแก้ปัญหา การทำบัญชีดำ รหัส และอื่นๆ

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

  • โครงการ 0: นี่คือฉาก 3D ของ Architect Demo ที่เขียนด้วยภาษา C# โดยใช้เอนจิ้นเกม Unity สำหรับแพลตฟอร์ม macOS และ Windows
  • เกม 1: เกมคอนโซล Simple Snake (ทุกคนรู้จักกันในชื่อ "Snake") สำหรับ Windows เขียนด้วยภาษาซี
  • เกม 2: เกมคอนโซล Crazy Tanks (ทุกคนรู้จักกันในชื่อ "Tanks") เขียนใน C ++ (โดยใช้คลาส) และใน Windows แล้ว

โครงการ 0 การสาธิตสถาปนิก

  • แพลตฟอร์ม: Windows (Windows 7, 10), Mac OS (OS X El Capitan เวอร์ชัน 10.11.6)
  • ภาษา: C#
  • เครื่องยนต์เกม: เอกภาพ
  • แรงบันดาลใจ: ดาร์ริน ไลล์
  • พื้นที่เก็บข้อมูล: GitHub

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
การสาธิตสถาปนิกฉาก 3 มิติ

โครงการแรกไม่ได้ถูกนำไปใช้ใน C/C++ แต่อยู่ใน C# โดยใช้เอนจิ้นเกม Unity เครื่องยนต์นี้ไม่ต้องการฮาร์ดแวร์เท่า Unreal Engineและดูเหมือนว่าฉันจะติดตั้งและใช้งานได้ง่ายขึ้นด้วย ฉันไม่ได้พิจารณาเครื่องยนต์อื่น

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

ฉันเริ่มต้นด้วยวิดีโอแนะนำบน YouTube เกี่ยวกับวิธีสร้างโมเดล 3 มิติใน เครื่องปั่น. Blender เป็นเครื่องมือฟรีที่ยอดเยี่ยมสำหรับการสร้างแบบจำลอง 3 มิติ (และอีกมากมาย) ที่ไม่ต้องติดตั้ง และนี่คือความตกใจรอฉันอยู่ ... ปรากฎว่าการสร้างแบบจำลอง, แอนิเมชั่น, พื้นผิวเป็นหัวข้อแยกต่างหากที่คุณสามารถเขียนหนังสือได้ โดยเฉพาะอย่างยิ่งสำหรับตัวละคร ในการจำลองนิ้วมือ ฟัน ดวงตา และส่วนอื่นๆ ของร่างกาย คุณจะต้องมีความรู้ด้านกายวิภาคศาสตร์ กล้ามเนื้อของใบหน้าจัดเรียงอย่างไร? ผู้คนเคลื่อนไหวอย่างไร? ฉันต้อง "ใส่" กระดูกในแต่ละแขน ขา นิ้ว ข้อนิ้ว!

สร้างแบบจำลองกระดูกไหปลาร้า คันโยกกระดูกเพิ่มเติม เพื่อให้แอนิเมชันดูเป็นธรรมชาติ หลังจากบทเรียนดังกล่าว คุณจะรู้ว่าผู้สร้างภาพยนตร์แอนิเมชั่นทำงานอะไรมากมาย เพียงเพื่อสร้างวิดีโอความยาว 30 วินาที แต่ภาพยนตร์ 3D อยู่ได้นานหลายชั่วโมง! แล้วเราก็ออกมาจากโรงหนังแล้วพูดว่า "ทะ การ์ตูน/หนังห่วยๆ! พวกเขาน่าจะทำได้ดีกว่านี้…” บัดซบ!

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

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

เกมที่ 1

  • แพลตฟอร์ม: Windows (ทดสอบบน Windows 7, 10)
  • ภาษา: ฉันคิดว่ามันเขียนด้วย C บริสุทธิ์
  • เครื่องยนต์เกม: คอนโซล Windows
  • แรงบันดาลใจ: javidx9
  • พื้นที่เก็บข้อมูล: GitHub

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
เกมงูง่ายๆ

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

และเรามีอะไรที่ง่ายและรวดเร็ว? ถูกต้องคอนโซลและ 2D แม่นยำยิ่งขึ้น แม้กระทั่งคอนโซลและสัญลักษณ์ ฉันเริ่มมองหาแรงบันดาลใจบนอินเทอร์เน็ตอีกครั้ง (โดยทั่วไปแล้ว ฉันถือว่าอินเทอร์เน็ตเป็นสิ่งประดิษฐ์ที่มีการปฏิวัติและอันตรายที่สุดในศตวรรษที่ XNUMX) ฉันขุดวิดีโอของโปรแกรมเมอร์คนหนึ่งที่สร้างคอนโซล Tetris และในเกมของเขาเขาตัดสินใจที่จะตัด "งู" ลง จากวิดีโอ ฉันได้เรียนรู้เกี่ยวกับสิ่งพื้นฐานสองอย่าง นั่นคือ game loop (ที่มีฟังก์ชันพื้นฐานสามส่วน / ส่วน) และเอาต์พุตไปยังบัฟเฟอร์

ลูปของเกมอาจมีลักษณะดังนี้:

int main()
   {
      Setup();
      // a game loop
      while (!quit)
      {
          Input();
          Logic();
          Draw();
          Sleep(gameSpeed);  // game timing
      }
      return 0;
   }

รหัสแสดงฟังก์ชั่น main() ทั้งหมดในครั้งเดียว และรอบเกมจะเริ่มขึ้นหลังจากความคิดเห็นที่เกี่ยวข้อง มีสามฟังก์ชันพื้นฐานในลูป: Input(), Logic(), Draw() ขั้นแรกให้ป้อนข้อมูล ป้อนข้อมูล (ควบคุมการกดแป้นพิมพ์เป็นหลัก) จากนั้นประมวลผลข้อมูลที่ป้อน ลอจิก จากนั้นแสดงบนหน้าจอ - วาด และทุกเฟรม ภาพเคลื่อนไหวถูกสร้างขึ้นด้วยวิธีนี้ เหมือนการ์ตูนเลย โดยปกติการประมวลผลข้อมูลอินพุตจะใช้เวลามากที่สุด และเท่าที่ฉันทราบ จะเป็นตัวกำหนดอัตราเฟรมของเกม แต่ที่นี่ฟังก์ชัน Logic() นั้นเร็วมาก ดังนั้น อัตราเฟรมจะต้องถูกควบคุมโดยฟังก์ชัน Sleep() ด้วยพารามิเตอร์ gameSpeed ​​ซึ่งกำหนดอัตรานี้

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
รอบเกม การเขียนโปรแกรมงูในแผ่นจดบันทึก

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

รับบัฟเฟอร์หน้าจอ (ถ้าฉันอาจพูดได้):

// create screen buffer for drawings
   HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0,
 							   NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
   DWORD dwBytesWritten = 0;
   SetConsoleActiveScreenBuffer(hConsole);

ส่งออกโดยตรงไปยังหน้าจอของเส้นคะแนนเส้นหนึ่ง (เส้นสำหรับแสดงคะแนน):

// draw the score
   WriteConsoleOutputCharacter(hConsole, scoreLine, GAME_WIDTH, {2,3}, &dwBytesWritten);

ตามทฤษฎีแล้ว เกมนี้ไม่มีอะไรซับซ้อน สำหรับฉันแล้ว ดูเหมือนว่าจะเป็นตัวอย่างที่ดีของเกมระดับเริ่มต้น รหัสถูกเขียนในไฟล์เดียวและจัดเรียงเป็นหลายฟังก์ชัน ไม่มีชนชั้น ไม่มีมรดก คุณสามารถดูทุกอย่างในซอร์สโค้ดของเกมได้โดยไปที่ที่เก็บบน GitHub

เกม 2 รถถังบ้า

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
เกมถังบ้า

การพิมพ์ตัวอักษรลงคอนโซลน่าจะเป็นสิ่งที่ง่ายที่สุดที่คุณจะเปลี่ยนเป็นเกมได้ แต่ปัญหาอย่างหนึ่งก็ปรากฏขึ้น: ตัวอักษรมีความสูงและความกว้างต่างกัน (ความสูงมากกว่าความกว้าง) ดังนั้น ทุกอย่างจะดูไม่สมส่วน และการเลื่อนขึ้นหรือลงจะดูเร็วกว่าการเลื่อนไปทางซ้ายหรือขวามาก เอฟเฟ็กต์นี้จะเห็นได้ชัดเจนมากใน "งู" (เกมที่ 1) "รถถัง" (เกม 2) ไม่มีข้อเสียดังกล่าวเนื่องจากเอาต์พุตมีการจัดระเบียบโดยการวาดภาพพิกเซลหน้าจอด้วยสีที่ต่างกัน คุณสามารถพูดได้ว่าฉันเขียนโปรแกรมเรนเดอร์ จริงอยู่นี่ซับซ้อนกว่าเล็กน้อยแม้ว่าจะน่าสนใจกว่ามากก็ตาม

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

ดังนั้น สิ่งที่คุณเห็นบนหน้าจอเป็นเพียงชุดของสี่เหลี่ยมสีที่เคลื่อนไหวได้

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
ชุดสี่เหลี่ยมผืนผ้า

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

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
ตัวอย่างของเมทริกซ์รถถังเกม

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
การแสดงเมทริกซ์ของเกมรถถังด้วยอาร์เรย์หนึ่งมิติ

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
ตัวอย่างเพิ่มเติมของการแทนเมทริกซ์โดยอาร์เรย์หนึ่งมิติ

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

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
ข้ามอาร์เรย์หนึ่งมิติในวงสองรอบ Y คือรหัสแถว X คือรหัสคอลัมน์

โปรดทราบว่าแทนที่จะใช้ตัวระบุเมทริกซ์ทั่วไป i, j ผมใช้ตัวระบุ x และ y ดังนั้นสำหรับฉันแล้วดูเหมือนว่าจะเจริญตาและชัดเจนขึ้นสำหรับสมอง นอกจากนี้ สัญกรณ์ดังกล่าวทำให้สามารถฉายภาพเมทริกซ์ที่ใช้บนแกนพิกัดของภาพสองมิติได้อย่างสะดวก

ตอนนี้เกี่ยวกับพิกเซล สี และการแสดงผล ฟังก์ชัน StretchDIBits (ส่วนหัว: windows.h; Library: gdi32.lib) ใช้สำหรับเอาต์พุต เหนือสิ่งอื่นใด ต่อไปนี้จะถูกส่งไปยังฟังก์ชันนี้: อุปกรณ์ที่แสดงรูปภาพ (ในกรณีของฉัน นี่คือคอนโซล Windows) พิกัดของการเริ่มต้นแสดงรูปภาพ ความกว้าง / ความสูง และรูปภาพ ตัวเองในรูปแบบของบิตแมป (บิตแมป) แทนด้วยอาร์เรย์ของไบต์ บิตแมปเป็นอาร์เรย์ของไบต์!

ฟังก์ชัน StretchDIBits() ในที่ทำงาน:

// screen output for game field
   StretchDIBits(
               deviceContext,
               OFFSET_LEFT, OFFSET_TOP,
               PMATRIX_WIDTH, PMATRIX_HEIGHT,
               0, 0,
               PMATRIX_WIDTH, PMATRIX_HEIGHT,
               m_p_bitmapMemory, &bitmapInfo,
               DIB_RGB_COLORS,
               SRCCOPY
               );

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

การสร้างบิตแมปหน่วยความจำ m_p_bitmap:

// create bitmap
   int bitmapMemorySize = (PMATRIX_WIDTH * PMATRIX_HEIGHT) * BYTES_PER_PIXEL;
   void* m_p_bitmapMemory = VirtualAlloc(0, bitmapMemorySize, MEM_COMMIT, PAGE_READWRITE);

บิตแมปประกอบด้วยชุดของพิกเซล ทุก ๆ สี่ไบต์ในอาร์เรย์คือพิกเซล RGB หนึ่งไบต์ต่อค่าสีแดง หนึ่งไบต์ต่อค่าสีเขียว (G) และหนึ่งไบต์ต่อค่าสีน้ำเงิน (B) นอกจากนี้ยังมีหนึ่งไบต์ต่อการเยื้อง สามสีนี้ - แดง / เขียว / น้ำเงิน (RGB) - ผสมกันในสัดส่วนที่ต่างกัน - และจะได้สีพิกเซลที่ได้

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

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

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
ตัวอย่างการเติมบิตแมป (Pixel matrix) ด้วยข้อมูลตามเมทริกซ์ตัวเลข (Digital matrix) ของสนามแข่งขัน (ดัชนีสีไม่ตรงกับดัชนีในเกม)

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

รหัสใช้ตัวชี้และการดำเนินการระดับบิตซึ่งอาจเข้าใจได้ยาก ดังนั้นฉันแนะนำให้คุณอ่านแยกกันว่าโครงสร้างดังกล่าวทำงานอย่างไร

กรอกบิตแมปด้วยข้อมูลตามเมทริกซ์ตัวเลขของสนามเด็กเล่น:

// set pixel map variables
   int colorIndex;
   COLORREF color;
   int pitch;
   uint8_t* p_row;
 
   // arrange pixels for game field
   pitch = PMATRIX_WIDTH * BYTES_PER_PIXEL;     // row size in bytes
   p_row = (uint8_t*)m_p_bitmapMemory;       //cast to uint8 for valid pointer arithmetic
   							(to add by 1 byte (8 bits) at a time)   
   for (int y = 0; y < PMATRIX_HEIGHT; ++y)
   {
       uint32_t* p_pixel = (uint32_t*)p_row;
       for (int x = 0; x < PMATRIX_WIDTH; ++x)
       {
           colorIndex = mainDigitalMatrix[y * PMATRIX_WIDTH + x];
           color = Utils::GetColor(colorIndex);
           uint8_t blue = GetBValue(color);
           uint8_t green = GetGValue(color);
           uint8_t red = GetRValue(color);
           uint8_t pixelPadding = 0;
 
           *p_pixel = ((pixelPadding << 24) | (red << 16) | (green << 8) | blue);
           ++p_pixel;
       }
       p_row += pitch;
   }

ตามวิธีการที่อธิบายไว้ข้างต้น รูปภาพ (เฟรม) หนึ่งภาพจะถูกสร้างขึ้นในเกม Crazy Tanks และแสดงบนหน้าจอในฟังก์ชัน Draw() หลังจากลงทะเบียนการกดแป้นพิมพ์ในฟังก์ชัน Input() และการประมวลผลที่ตามมาในฟังก์ชัน Logic() ภาพใหม่ (เฟรม) จะถูกสร้างขึ้น จริงอยู่ วัตถุในเกมอาจมีตำแหน่งที่แตกต่างกันอยู่แล้วในสนามแข่งขัน ดังนั้น จึงถูกดึงไปยังตำแหน่งอื่น นี่คือวิธีที่อนิเมชั่น (การเคลื่อนไหว) เกิดขึ้น

ในทางทฤษฎี (หากคุณไม่ได้ลืมอะไรไป) การทำความเข้าใจลูปของเกมจากเกมแรก (“งู”) และระบบการแสดงพิกเซลบนหน้าจอจากเกมที่สอง (“รถถัง”) คือทั้งหมดที่คุณต้องเขียน ของเกม 2D ของคุณสำหรับ Windows ไร้เสียง! 😉ส่วนที่เหลือเป็นเพียงการบินแฟนซี

แน่นอนว่าเกม "Tanks" ได้รับการออกแบบให้ซับซ้อนกว่า "Snake" มาก ฉันใช้ภาษา C++ อยู่แล้ว นั่นคือฉันอธิบายอ็อบเจกต์เกมต่างๆ ด้วยคลาส ฉันสร้างคอลเลกชันของตัวเอง - คุณสามารถดูโค้ดได้ใน headers/Box.h อย่างไรก็ตาม คอลเลกชั่นนี้น่าจะมีหน่วยความจำรั่ว ตัวชี้ที่ใช้ ทำงานร่วมกับหน่วยความจำ ฉันต้องบอกว่าหนังสือเล่มนี้ช่วยฉันได้มาก เริ่มต้น C++ ผ่านการเขียนโปรแกรมเกม. นี่เป็นการเริ่มต้นที่ดีสำหรับผู้เริ่มต้นใน C ++ มีขนาดเล็ก น่าสนใจและจัดได้ดี

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

ในตอนท้ายของภาคปฏิบัติ ฉันจะดึงโน้ตบุ๊กบางส่วนออกมาสแกน เพื่อแสดงสิ่งที่ฉันกำลังจด วาด นับ ออกแบบ...

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
การออกแบบภาพรถถัง และคำจำกัดความของจำนวนพิกเซลที่รถถังแต่ละคันควรใช้บนหน้าจอ

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

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

DevOps C++ และ "สงครามครัว" หรือ ฉันเริ่มเขียนเกมขณะรับประทานอาหารได้อย่างไร
และนี่เป็นความพยายามที่ไร้ประโยชน์ในการทำให้ปัญญาประดิษฐ์เข้าสู่เกม

ทฤษฎี

"การเดินทางไกลนับพันลี้ เริ่มต้นด้วยก้าวแรก" (ภูมิปัญญาจีนโบราณ)

ย้ายจากการปฏิบัติไปสู่ทฤษฎีกันเถอะ! คุณหาเวลาให้กับงานอดิเรกของคุณได้อย่างไร?

  1. กำหนดสิ่งที่คุณต้องการจริงๆ (อนิจจานี่เป็นสิ่งที่ยากที่สุด)
  2. กำหนดลำดับความสำคัญ
  3. เสียสละ "สิ่งฟุ่มเฟือย" ทั้งหมดเพื่อลำดับความสำคัญที่สูงขึ้น
  4. ก้าวไปสู่เป้าหมายของคุณทุกวัน
  5. อย่าคาดหวังว่าจะมีเวลาว่างสองหรือสามชั่วโมงสำหรับงานอดิเรก

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

มีกฎทองอยู่ข้อหนึ่ง: ไม่มีวันเป็น 0%! ฉันได้เรียนรู้เกี่ยวกับมันในบทความโดยนักพัฒนาอินดี้ หากคุณกำลังทำงานในโครงการ ให้ทำอะไรสักอย่างกับมันทุกวัน และไม่สำคัญว่าคุณจะมีรายได้เท่าไร เขียนโค้ด XNUMX คำหรือ XNUMX บรรทัด ดูวิดีโอแนะนำ XNUMX รายการ หรือตอกตะปูลงบนกระดาน แค่ทำอะไรสักอย่าง ส่วนที่ยากที่สุดคือการเริ่มต้น เมื่อคุณเริ่มแล้ว คุณอาจจะทำได้มากกว่าที่คุณต้องการเล็กน้อย ดังนั้นคุณจะมุ่งไปสู่เป้าหมายอย่างต่อเนื่องและเชื่อฉันอย่างรวดเร็ว ท้ายที่สุดเบรกหลักในทุกสิ่งคือการผัดวันประกันพรุ่ง

และสิ่งสำคัญคือต้องจำไว้ว่าคุณไม่ควรประมาทและละเลย "ขี้เลื่อย" ของเวลาฟรีใน 5, 10, 15 นาที รอ "ท่อนซุง" ขนาดใหญ่ที่กินเวลาหนึ่งหรือสองชั่วโมง คุณกำลังยืนอยู่ในแถว? คิดเกี่ยวกับบางสิ่งบางอย่างสำหรับโครงการของคุณ คุณกำลังขึ้นบันไดเลื่อนหรือไม่? จดบางสิ่งลงในสมุดบันทึก คุณกินบนรถบัสหรือไม่? โอเค อ่านบทความบ้าง ใช้ได้ทุกโอกาส หยุดดูแมวและสุนัขบน YouTube! อย่ายุ่งกับสมองของคุณ!

และสุดท้าย หากหลังจากอ่านบทความนี้แล้วคุณชอบแนวคิดในการสร้างเกมโดยไม่ใช้เอ็นจิ้นเกม ให้จำชื่อ Casey Muratori ผู้ชายคนนี้มี สถาน. ในส่วน "ดู -> ตอนก่อนหน้า" คุณจะพบวิดีโอสอนฟรีที่น่าทึ่งเกี่ยวกับวิธีสร้างเกมระดับมืออาชีพตั้งแต่เริ่มต้น คุณสามารถเรียนรู้บทเรียน Intro to C for Windows XNUMX บทเรียนได้มากกว่าการเรียน XNUMX ปีที่มหาวิทยาลัย (มีคนเขียนเกี่ยวกับเรื่องนี้ในความคิดเห็นใต้วิดีโอ)

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

ขอให้โชคดีในเส้นทางที่คุณเลือก! และมาทำให้โลกนี้เป็นมืออาชีพมากขึ้นกันเถอะ

ผู้แต่ง: แกรนกิน อันเดรย์, DevOps



ที่มา: will.com