"ฉันรู้ว่าฉันไม่รู้อะไรเลย" โสกราตีส
เพื่อใคร: สำหรับชาวไอทีที่ถุยน้ำลายนักพัฒนาทั้งหลายและอยากเล่นเกมของพวกเขา!
เกี่ยวกับอะไร: วิธีเริ่มเขียนเกมใน C/C++ หากคุณต้องการ!
ทำไมคุณควรอ่านสิ่งนี้: การพัฒนาแอพไม่ใช่งานถนัดของฉัน แต่ฉันพยายามเขียนโค้ดทุกสัปดาห์ เพราะฉันรักเกม!
สวัสดีฉันชื่อ
อุตสาหกรรมเกมคอมพิวเตอร์มีขนาดใหญ่มาก มีข่าวลือว่าทุกวันนี้ใหญ่กว่าอุตสาหกรรมภาพยนตร์เสียอีก เกมถูกเขียนขึ้นตั้งแต่ยุคเริ่มต้นของคอมพิวเตอร์โดยใช้มาตรฐานที่ทันสมัย วิธีการพัฒนาที่ซับซ้อนและเป็นพื้นฐาน เมื่อเวลาผ่านไป เอ็นจิ้นของเกมเริ่มปรากฏขึ้นพร้อมกับกราฟิก ฟิสิกส์ และเสียงที่ตั้งโปรแกรมไว้แล้ว พวกเขาช่วยให้คุณมุ่งเน้นไปที่การพัฒนาตัวเกมเองและไม่ต้องกังวลเกี่ยวกับรากฐานของมัน แต่ร่วมกับพวกเขาด้วยเครื่องยนต์ นักพัฒนา "ตาบอด" และลดระดับลง การผลิตเกมนั้นวางอยู่บนสายพานลำเลียง และปริมาณการผลิตเริ่มเหนือกว่าคุณภาพ
ในขณะเดียวกัน เมื่อเล่นเกมของคนอื่น เรามักถูกจำกัดโดยสถานที่ โครงเรื่อง ตัวละคร กลไกของเกมที่คนอื่นคิดขึ้นมา ฉันจึงได้รู้ว่า...
… ถึงเวลาสร้างโลกของคุณเอง อยู่ภายใต้การควบคุมของฉันเท่านั้น โลกที่เราเป็นพระบิดา พระบุตร และพระจิต!
และฉันเชื่ออย่างจริงใจว่าการเขียนเอนจิ้นเกมของคุณเองและเกมบนนั้น คุณจะสามารถเปิดตา เช็ดหน้าต่าง และปั๊มห้องโดยสารของคุณ กลายเป็นโปรแกรมเมอร์ที่มีประสบการณ์และสมบูรณ์มากขึ้น
ในบทความนี้ฉันจะพยายามบอกคุณว่าฉันเริ่มเขียนเกมขนาดเล็กใน C / C ++ ได้อย่างไร ขั้นตอนการพัฒนาคืออะไรและฉันหาเวลาว่างสำหรับงานอดิเรกในสภาพแวดล้อมที่วุ่นวายได้ที่ไหน เป็นอัตนัยและอธิบายกระบวนการเริ่มต้นของแต่ละคน เนื้อหาเกี่ยวกับความโง่เขลาและศรัทธาเกี่ยวกับภาพส่วนตัวของฉันเกี่ยวกับโลกในขณะนี้ กล่าวอีกนัยหนึ่งคือ "ฝ่ายบริหารไม่รับผิดชอบต่อสมองส่วนตัวของคุณ!"
การปฏิบัติ
“ความรู้ที่ปราศจากการฝึกฝนก็ไร้ประโยชน์ การฝึกฝนที่ปราศจากความรู้นั้นเป็นอันตราย” ขงจื๊อ
สมุดบันทึกของฉันคือชีวิตของฉัน!
ดังนั้น ในทางปฏิบัติ ฉันพูดได้ว่าทุกอย่างสำหรับฉันเริ่มต้นจากสมุดบันทึก ฉันไม่ได้จดแค่งานประจำวันของฉันที่นั่น แต่ยังวาด เขียนโปรแกรม ออกแบบแผนผังลำดับงาน และแก้ปัญหา รวมถึงปัญหาทางคณิตศาสตร์ด้วย ใช้แผ่นจดบันทึกเสมอและเขียนด้วยดินสอเท่านั้น มันสะอาด สะดวกสบาย และเชื่อถือได้ IMHO
สมุดบันทึกของฉัน (เต็มแล้ว) นี่คือลักษณะที่ปรากฏ ประกอบด้วยงานประจำวัน ไอเดีย ภาพวาด ไดอะแกรม วิธีแก้ปัญหา การทำบัญชีดำ รหัส และอื่นๆ
ในขั้นตอนนี้ ฉันสามารถทำโปรเจกต์ให้สำเร็จได้สามโปรเจ็กต์ (นี่คือความเข้าใจของฉันเกี่ยวกับ "ขั้นสุดท้าย" เพราะผลิตภัณฑ์ใดๆ
- โครงการ 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
การสาธิตสถาปนิกฉาก 3 มิติ
โครงการแรกไม่ได้ถูกนำไปใช้ใน C/C++ แต่อยู่ใน C# โดยใช้เอนจิ้นเกม Unity เครื่องยนต์นี้ไม่ต้องการฮาร์ดแวร์เท่า
เป้าหมายใน Unity สำหรับฉันไม่ใช่การพัฒนาเกมบางประเภท ฉันต้องการสร้างฉาก 3 มิติด้วยตัวละครบางประเภท เขาหรือเธอ (ฉันจำลองผู้หญิงที่ฉันหลงรัก =) ต้องเคลื่อนไหวและมีปฏิสัมพันธ์กับโลกภายนอก สิ่งสำคัญคือต้องเข้าใจว่า Unity คืออะไร กระบวนการพัฒนาคืออะไร และต้องใช้ความพยายามมากแค่ไหนในการสร้างบางสิ่ง นี่คือที่มาของโครงการ Architect Demo (ชื่อนี้ถูกประดิษฐ์ขึ้นจากเรื่องไร้สาระ) การเขียนโปรแกรม การสร้างแบบจำลอง แอนิเมชัน การทำพื้นผิวทำให้ฉันทำงานทุกวันเป็นเวลาสองเดือน
ฉันเริ่มต้นด้วยวิดีโอแนะนำบน YouTube เกี่ยวกับวิธีสร้างโมเดล 3 มิติใน
สร้างแบบจำลองกระดูกไหปลาร้า คันโยกกระดูกเพิ่มเติม เพื่อให้แอนิเมชันดูเป็นธรรมชาติ หลังจากบทเรียนดังกล่าว คุณจะรู้ว่าผู้สร้างภาพยนตร์แอนิเมชั่นทำงานอะไรมากมาย เพียงเพื่อสร้างวิดีโอความยาว 30 วินาที แต่ภาพยนตร์ 3D อยู่ได้นานหลายชั่วโมง! แล้วเราก็ออกมาจากโรงหนังแล้วพูดว่า "ทะ การ์ตูน/หนังห่วยๆ! พวกเขาน่าจะทำได้ดีกว่านี้…” บัดซบ!
และอีกอย่างหนึ่งเกี่ยวกับการเขียนโปรแกรมในโครงการนี้ เมื่อปรากฎว่าส่วนที่น่าสนใจที่สุดสำหรับฉันคือส่วนทางคณิตศาสตร์ หากคุณเรียกใช้ฉาก (ลิงก์ไปยังพื้นที่เก็บข้อมูลในคำอธิบายโครงการ) คุณจะสังเกตเห็นว่ากล้องหมุนรอบตัวละครหญิงสาวเป็นทรงกลม ในการตั้งโปรแกรมการหมุนกล้องนั้น ฉันต้องคำนวณพิกัดของจุดตำแหน่งบนวงกลม (2D) ก่อนแล้วจึงคำนวณบนทรงกลม (3D) สิ่งที่ตลกคือฉันเกลียดคณิตศาสตร์ที่โรงเรียนและรู้ด้วยเครื่องหมายลบ ส่วนหนึ่งอาจเป็นเพราะที่โรงเรียนพวกเขาไม่ได้อธิบายให้คุณฟังว่าคณิตศาสตร์นี้นำไปใช้ในชีวิตได้อย่างไร แต่เมื่อหมกมุ่นกับเป้าหมาย ความฝัน จิตใจก็ปลอดโปร่ง เผย! และคุณเริ่มมองว่างานที่ซับซ้อนเป็นการผจญภัยที่น่าตื่นเต้น แล้วคุณคิดว่า: "ทำไม *นักคณิตศาสตร์ที่รัก* ปกติบอกไม่ได้ว่าสูตรเหล่านี้เอนเอียงไปทางไหนได้บ้าง"
การคำนวณสูตรสำหรับคำนวณพิกัดของจุดบนวงกลมและทรงกลม (จากสมุดบันทึกของฉัน)
เกมที่ 1
- แพลตฟอร์ม: Windows (ทดสอบบน Windows 7, 10)
- ภาษา: ฉันคิดว่ามันเขียนด้วย C บริสุทธิ์
- เครื่องยนต์เกม: คอนโซล Windows
- แรงบันดาลใจ:
javidx9 - พื้นที่เก็บข้อมูล:
GitHub
เกมงูง่ายๆ
ฉาก 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 ซึ่งกำหนดอัตรานี้
รอบเกม การเขียนโปรแกรมงูในแผ่นจดบันทึก
หากคุณกำลังพัฒนาเกมคอนโซลสัญลักษณ์ การแสดงข้อมูลบนหน้าจอโดยใช้เอาต์พุตสตรีมปกติ '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 รถถังบ้า
- แพลตฟอร์ม: Windows (ทดสอบบน Windows 7, 10)
- ภาษา: C + +
- เครื่องยนต์เกม: คอนโซล Windows
- แรงบันดาลใจ: หนังสือ
เริ่มต้น C++ ผ่านการเขียนโปรแกรมเกม - พื้นที่เก็บข้อมูล:
GitHub
เกมถังบ้า
การพิมพ์ตัวอักษรลงคอนโซลน่าจะเป็นสิ่งที่ง่ายที่สุดที่คุณจะเปลี่ยนเป็นเกมได้ แต่ปัญหาอย่างหนึ่งก็ปรากฏขึ้น: ตัวอักษรมีความสูงและความกว้างต่างกัน (ความสูงมากกว่าความกว้าง) ดังนั้น ทุกอย่างจะดูไม่สมส่วน และการเลื่อนขึ้นหรือลงจะดูเร็วกว่าการเลื่อนไปทางซ้ายหรือขวามาก เอฟเฟ็กต์นี้จะเห็นได้ชัดเจนมากใน "งู" (เกมที่ 1) "รถถัง" (เกม 2) ไม่มีข้อเสียดังกล่าวเนื่องจากเอาต์พุตมีการจัดระเบียบโดยการวาดภาพพิกเซลหน้าจอด้วยสีที่ต่างกัน คุณสามารถพูดได้ว่าฉันเขียนโปรแกรมเรนเดอร์ จริงอยู่นี่ซับซ้อนกว่าเล็กน้อยแม้ว่าจะน่าสนใจกว่ามากก็ตาม
สำหรับเกมนี้คงเพียงพอแล้วที่จะอธิบายถึงระบบของฉันสำหรับการแสดงพิกเซลบนหน้าจอ ฉันคิดว่านี่เป็นส่วนหลักของเกม และทุกสิ่งทุกอย่างที่คุณสามารถคิดขึ้นมาเอง
ดังนั้น สิ่งที่คุณเห็นบนหน้าจอเป็นเพียงชุดของสี่เหลี่ยมสีที่เคลื่อนไหวได้
ชุดสี่เหลี่ยมผืนผ้า
สี่เหลี่ยมแต่ละอันจะแสดงด้วยเมทริกซ์ที่เต็มไปด้วยตัวเลข อย่างไรก็ตาม ฉันสามารถเน้นความแตกต่างที่น่าสนใจอย่างหนึ่งได้ นั่นคือ เมทริกซ์ทั้งหมดในเกมถูกตั้งโปรแกรมเป็นอาร์เรย์หนึ่งมิติ ไม่ใช่สองมิติ แต่เป็นมิติเดียว! อาร์เรย์หนึ่งมิตินั้นง่ายกว่าและเร็วกว่ามากในการทำงานด้วย
ตัวอย่างของเมทริกซ์รถถังเกม
การแสดงเมทริกซ์ของเกมรถถังด้วยอาร์เรย์หนึ่งมิติ
ตัวอย่างเพิ่มเติมของการแทนเมทริกซ์โดยอาร์เรย์หนึ่งมิติ
แต่การเข้าถึงองค์ประกอบของอาร์เรย์นั้นเกิดขึ้นในสองวงราวกับว่ามันไม่ใช่อาร์เรย์หนึ่งมิติ แต่เป็นอาร์เรย์สองมิติ สิ่งนี้เสร็จสิ้นเพราะเรายังคงทำงานกับเมทริกซ์
ข้ามอาร์เรย์หนึ่งมิติในวงสองรอบ 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 เป็นสีเทาเข้ม เป็นต้น ดังนั้นเราจึงสามารถพูดได้ว่าเรามีเมทริกซ์ของสนามเด็กเล่นซึ่งแต่ละหมายเลขเป็นสีต่างๆ
ดังนั้นเราจึงมีเมทริกซ์ตัวเลขของสนามเด็กเล่นทั้งหมดในด้านหนึ่งและบิตแมปสำหรับแสดงภาพในอีกด้านหนึ่ง จนถึงตอนนี้บิตแมป "ว่างเปล่า" - ยังไม่มีข้อมูลเกี่ยวกับพิกเซลของสีที่ต้องการ ซึ่งหมายความว่าขั้นตอนสุดท้ายจะเติมบิตแมปด้วยข้อมูลเกี่ยวกับแต่ละพิกเซลตามเมทริกซ์ตัวเลขของสนามเด็กเล่น ตัวอย่างที่ชัดเจนของการเปลี่ยนแปลงดังกล่าวอยู่ในภาพด้านล่าง
ตัวอย่างการเติมบิตแมป (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 ++ มีขนาดเล็ก น่าสนใจและจัดได้ดี
ใช้เวลาประมาณหกเดือนในการพัฒนาเกมนี้ ฉันเขียนในช่วงพักเที่ยงและอาหารว่างในที่ทำงานเป็นหลัก เขานั่งอยู่ในครัวของสำนักงาน ลงมือกระทืบอาหารและเขียนโค้ด หรือที่บ้านสำหรับอาหารค่ำ ดังนั้นฉันจึงได้ "สงครามครัว" เช่นเคย ฉันใช้สมุดบันทึกอย่างแข็งขัน และทุกสิ่งที่เป็นแนวคิดถือกำเนิดขึ้นในนั้น
ในตอนท้ายของภาคปฏิบัติ ฉันจะดึงโน้ตบุ๊กบางส่วนออกมาสแกน เพื่อแสดงสิ่งที่ฉันกำลังจด วาด นับ ออกแบบ...
การออกแบบภาพรถถัง และคำจำกัดความของจำนวนพิกเซลที่รถถังแต่ละคันควรใช้บนหน้าจอ
การคำนวณอัลกอริทึมและสูตรสำหรับการหมุนของถังรอบแกน
ไดอะแกรมของคอลเลกชันของฉัน (อันที่มีหน่วยความจำรั่วซึ่งน่าจะเป็นไปได้มากที่สุด) คอลเลกชันถูกสร้างขึ้นเป็นรายการที่เชื่อมโยง
และนี่เป็นความพยายามที่ไร้ประโยชน์ในการทำให้ปัญญาประดิษฐ์เข้าสู่เกม
ทฤษฎี
"การเดินทางไกลนับพันลี้ เริ่มต้นด้วยก้าวแรก" (ภูมิปัญญาจีนโบราณ)
ย้ายจากการปฏิบัติไปสู่ทฤษฎีกันเถอะ! คุณหาเวลาให้กับงานอดิเรกของคุณได้อย่างไร?
- กำหนดสิ่งที่คุณต้องการจริงๆ (อนิจจานี่เป็นสิ่งที่ยากที่สุด)
- กำหนดลำดับความสำคัญ
- เสียสละ "สิ่งฟุ่มเฟือย" ทั้งหมดเพื่อลำดับความสำคัญที่สูงขึ้น
- ก้าวไปสู่เป้าหมายของคุณทุกวัน
- อย่าคาดหวังว่าจะมีเวลาว่างสองหรือสามชั่วโมงสำหรับงานอดิเรก
ในอีกด้านหนึ่ง คุณต้องกำหนดสิ่งที่คุณต้องการและจัดลำดับความสำคัญ ในทางกลับกัน เป็นไปได้ที่จะละทิ้งบางกรณี/โครงการที่ให้ความสำคัญเหล่านี้ กล่าวอีกนัยหนึ่งคุณจะต้องเสียสละทุกสิ่งที่ "ฟุ่มเฟือย" ฉันได้ยินมาว่าในชีวิตควรมีกิจกรรมหลักสูงสุดสามอย่าง จากนั้นคุณจะสามารถจัดการกับพวกเขาได้อย่างดีที่สุด และโครงการ/ทิศทางเพิ่มเติมจะเริ่มล้นเกิน แต่ทั้งหมดนี้อาจเป็นอัตนัยและรายบุคคล
มีกฎทองอยู่ข้อหนึ่ง: ไม่มีวันเป็น 0%! ฉันได้เรียนรู้เกี่ยวกับมันในบทความโดยนักพัฒนาอินดี้ หากคุณกำลังทำงานในโครงการ ให้ทำอะไรสักอย่างกับมันทุกวัน และไม่สำคัญว่าคุณจะมีรายได้เท่าไร เขียนโค้ด XNUMX คำหรือ XNUMX บรรทัด ดูวิดีโอแนะนำ XNUMX รายการ หรือตอกตะปูลงบนกระดาน แค่ทำอะไรสักอย่าง ส่วนที่ยากที่สุดคือการเริ่มต้น เมื่อคุณเริ่มแล้ว คุณอาจจะทำได้มากกว่าที่คุณต้องการเล็กน้อย ดังนั้นคุณจะมุ่งไปสู่เป้าหมายอย่างต่อเนื่องและเชื่อฉันอย่างรวดเร็ว ท้ายที่สุดเบรกหลักในทุกสิ่งคือการผัดวันประกันพรุ่ง
และสิ่งสำคัญคือต้องจำไว้ว่าคุณไม่ควรประมาทและละเลย "ขี้เลื่อย" ของเวลาฟรีใน 5, 10, 15 นาที รอ "ท่อนซุง" ขนาดใหญ่ที่กินเวลาหนึ่งหรือสองชั่วโมง คุณกำลังยืนอยู่ในแถว? คิดเกี่ยวกับบางสิ่งบางอย่างสำหรับโครงการของคุณ คุณกำลังขึ้นบันไดเลื่อนหรือไม่? จดบางสิ่งลงในสมุดบันทึก คุณกินบนรถบัสหรือไม่? โอเค อ่านบทความบ้าง ใช้ได้ทุกโอกาส หยุดดูแมวและสุนัขบน YouTube! อย่ายุ่งกับสมองของคุณ!
และสุดท้าย หากหลังจากอ่านบทความนี้แล้วคุณชอบแนวคิดในการสร้างเกมโดยไม่ใช้เอ็นจิ้นเกม ให้จำชื่อ Casey Muratori ผู้ชายคนนี้มี
เคซีย์ยังอธิบายด้วยว่าการพัฒนาเอ็นจิ้นเกมของคุณเองจะทำให้คุณเข้าใจเอ็นจิ้นที่มีอยู่ได้ดีขึ้น ในโลกของกรอบที่ทุกคนพยายามทำให้เป็นอัตโนมัติ คุณจะได้เรียนรู้วิธีสร้าง ไม่ใช่ใช้ เข้าใจธรรมชาติของคอมพิวเตอร์ และคุณยังจะกลายเป็นโปรแกรมเมอร์ที่ฉลาดและเป็นผู้ใหญ่มากขึ้น - เป็นมืออาชีพ
ขอให้โชคดีในเส้นทางที่คุณเลือก! และมาทำให้โลกนี้เป็นมืออาชีพมากขึ้นกันเถอะ
ผู้แต่ง: แกรนกิน อันเดรย์ , DevOps
ที่มา: will.com