เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

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

Skillbox แนะนำ: หลักสูตรภาคปฏิบัติสองปี "ฉันเป็นนักพัฒนาเว็บ PRO".

เราเตือนคุณ: สำหรับผู้อ่าน "Habr" ทุกคน - ส่วนลด 10 rubles เมื่อลงทะเบียนในหลักสูตร Skillbox ใด ๆ โดยใช้รหัสส่งเสริมการขาย "Habr"

ทำไมต้องเป็นสนิม?

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

ทำไมต้องเป็นเกมและเป็นเกมประเภทไหน?

การสร้างเกมเป็นเรื่องสนุก! ฉันหวังว่าจะมีเหตุผลมากกว่านี้ แต่สำหรับโครงการ "บ้าน" ฉันเลือกหัวข้อที่ไม่เกี่ยวข้องกับงานประจำของฉันมากเกินไป นี่คือเกมอะไร? ฉันต้องการสร้างบางอย่างเช่นเครื่องจำลองเทนนิสที่ผสมผสานระหว่าง Cities Skylines, Zoo Tycoon, Prison Architect และเทนนิสเข้าด้วยกัน โดยทั่วไปแล้วกลายเป็นเกมเกี่ยวกับสถาบันสอนเทนนิสที่มีคนมาเล่น

การฝึกอบรมทางเทคนิค

ฉันต้องการใช้ Rust แต่ฉันไม่รู้ว่าจะต้องใช้พื้นฐานมากเพียงใดในการเริ่มต้น ฉันไม่ต้องการเขียนตัวเชเดอร์พิกเซลและใช้การลากและวาง ดังนั้นฉันจึงมองหาโซลูชันที่ยืดหยุ่นที่สุด

ฉันพบแหล่งข้อมูลที่เป็นประโยชน์ที่ฉันแบ่งปันกับคุณ:

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

โครงสร้างเกม

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

เมื่อคิดทุกอย่างแล้วฉันก็เริ่มทำงาน

การสร้างเกม

จุดเริ่มต้น: วงกลมและนามธรรม

ฉันเอาตัวอย่างจาก ggez และได้วงกลมบนหน้าจอ มหัศจรรย์! ตอนนี้มีนามธรรมบางอย่าง ฉันคิดว่ามันคงจะดีถ้าเป็นนามธรรมออกไปจากแนวคิดของวัตถุในเกม แต่ละออบเจ็กต์จะต้องถูกเรนเดอร์และอัปเดตตามที่ระบุไว้ที่นี่:

// the game object trait
trait GameObject {
    fn update(&mut self, _ctx: &mut Context) -> GameResult<()>;
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()>;
}
 
// a specific game object - Circle
struct Circle {
    position: Point2,
}
 
 impl Circle {
    fn new(position: Point2) -> Circle {
        Circle { position }
    }
}
impl GameObject for Circle {
    fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
        Ok(())
    }
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        let circle =
            graphics::Mesh::new_circle(ctx, graphics::DrawMode::Fill, self.position, 100.0, 2.0)?;
 
         graphics::draw(ctx, &circle, na::Point2::new(0.0, 0.0), 0.0)?;
        Ok(())
    }
}

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

mpl event::EventHandler for MainState {
    fn update(&mut self, context: &mut Context) -> GameResult<()> {
        // Update all objects
        for object in self.objects.iter_mut() {
            object.update(context)?;
        }
 
        Ok(())
    }
 
    fn draw(&mut self, context: &mut Context) -> GameResult<()> {
        graphics::clear(context);
 
        // Draw all objects
        for object in self.objects.iter_mut() {
            object.draw(context)?;
        }
 
        graphics::present(context);
 
        Ok(())
    }
}

main.rs เป็นสิ่งจำเป็นเนื่องจากมีโค้ดทุกบรรทัด ฉันใช้เวลาเล็กน้อยในการแยกไฟล์และปรับโครงสร้างไดเร็กทอรีให้เหมาะสม นี่คือสิ่งที่ดูเหมือนหลังจากนั้น:
ทรัพยากร -> นี่คือที่ซึ่งเนื้อหาทั้งหมดอยู่ (รูปภาพ)
สิ่งอำนวยความสะดวก
- เอนทิตี
— game_object.rs
— วงกลม.อาร์เอส
— main.rs -> ลูปหลัก

ผู้คน พื้น และรูปภาพ

ขั้นตอนต่อไปคือการสร้างวัตถุเกม Person และโหลดรูปภาพ ทุกอย่างควรสร้างจากกระเบื้องขนาด 32*32 แผ่น

เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

สนามเทนนิส

หลังจากศึกษาลักษณะของสนามเทนนิสแล้ว ฉันก็ตัดสินใจสร้างจากกระเบื้องขนาด 4*2 ในตอนแรกคุณสามารถสร้างภาพขนาดนี้หรือรวม 8 แผ่นแยกกัน แต่แล้วฉันก็พบว่ามีเพียงสองแผ่นที่ไม่ซ้ำใครเท่านั้นที่จำเป็น และนี่คือเหตุผล

โดยรวมแล้วเรามีไพ่สองใบดังกล่าว: 1 และ 2

แต่ละส่วนของสนามประกอบด้วยช่อง 1 หรือช่อง 2 สามารถวางได้ตามปกติหรือพลิก 180 องศา

เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

โหมดการก่อสร้างขั้นพื้นฐาน (การประกอบ)

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

แต่เรายังต้องจำไว้ว่า 1 และ 2 หมายถึงอะไร ดังนั้นฉันจึงเพิ่มโครงร่างเพื่อให้ชัดเจนว่าวัตถุใดถูกเลือก นี่คือสิ่งที่ดูเหมือน

เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

คำถามเกี่ยวกับสถาปัตยกรรมและการปรับโครงสร้างใหม่

ตอนนี้ฉันมีวัตถุในเกมหลายอย่าง: ผู้คน, สนามและพื้น แต่เพื่อให้ wireframes ทำงานได้ แต่ละเอนทิตีของออบเจ็กต์จะต้องได้รับการบอกว่าออบเจ็กต์นั้นอยู่ในโหมดสาธิตหรือว่าเฟรมนั้นถูกวาดอย่างง่าย ๆ หรือไม่ ซึ่งไม่สะดวกมากนัก

สำหรับฉันดูเหมือนว่าสถาปัตยกรรมจำเป็นต้องได้รับการปรับปรุงใหม่ในลักษณะที่เปิดเผยข้อจำกัดบางประการ:

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

ฉันค้นคว้าเพิ่มเติมและค้นพบสถาปัตยกรรม ECS - ระบบส่วนประกอบเอนทิตีซึ่งใช้กันทั่วไปในเกม นี่คือประโยชน์ของ ECS:

  • ข้อมูลถูกแยกออกจากตรรกะ
  • องค์ประกอบแทนมรดก
  • สถาปัตยกรรมที่เน้นข้อมูลเป็นศูนย์กลาง

ECS โดดเด่นด้วยแนวคิดพื้นฐานสามประการ:

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

หลังจากศึกษาแล้ว เห็นได้ชัดว่า ECS สามารถแก้ไขปัญหาต่อไปนี้ได้:

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

นี่คือสิ่งที่เกิดขึ้นหลังจากนำ ECS ไปใช้

ทรัพยากร -> นี่คือที่ซึ่งเนื้อหาทั้งหมดอยู่ (รูปภาพ)
สิ่งอำนวยความสะดวก
- ส่วนประกอบ
—position.rs
— person.rs
— Tennis_court.rs
— floor.rs
- wireframe.rs
— mouse_tracked.rs
- ทรัพยากร
—mouse.rs
- ระบบ
— rendering.rs
— ค่าคงที่.rs
— utils.rs
— world_factory.rs -> ฟังก์ชั่นโรงงานโลก
— main.rs -> ลูปหลัก

เรามอบหมายคนให้กับศาล

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

ฉันทำอะไรลงไป:

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

เล่น Rust ใน 24 ชั่วโมง: ประสบการณ์การพัฒนาตนเอง

ข้อสรุปถึง

ฉันสนุกกับการเล่นเกมง่ายๆ นี้มาก ยิ่งกว่านั้น ฉันดีใจที่ฉันใช้ Rust ในการเขียน เพราะ:

  • สนิมให้สิ่งที่คุณต้องการ
  • มีเอกสารที่ยอดเยี่ยม Rust ค่อนข้างหรูหรา
  • ความสม่ำเสมอนั้นเจ๋ง
  • คุณไม่จำเป็นต้องหันไปพึ่งการโคลน การคัดลอก หรือการกระทำอื่นที่คล้ายกัน ซึ่งฉันมักจะทำในภาษา C++
  • ตัวเลือกใช้งานง่ายมากและจัดการกับข้อผิดพลาดได้เป็นอย่างดี
  • หากสามารถคอมไพล์โปรเจ็กต์ได้ ก็จะทำงานได้ 99% และตรงตามที่ควร ฉันคิดว่าข้อความแสดงข้อผิดพลาดของคอมไพเลอร์ดีที่สุดที่ฉันเคยเห็น

การพัฒนาเกมใน Rust เพิ่งเริ่มต้น แต่มีชุมชนที่มั่นคงและค่อนข้างใหญ่อยู่แล้วที่ทำงานเพื่อเปิด Rust ให้กับทุกคน ดังนั้นฉันจึงมองอนาคตของภาษาด้วยการมองโลกในแง่ดี และรอคอยผลงานร่วมกันของเรา

Skillbox แนะนำ:

ที่มา: will.com

เพิ่มความคิดเห็น