Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Në këtë artikull, do të flas për përvojën time personale në zhvillimin e një loje të vogël me Rust. Krijimi i versionit funksional zgjati rreth 24 orë (përgjithësisht kam punuar në mbrëmje ose gjatë fundjavave). Loja ende është larg përfundimit, por mendoj se përvoja do të jetë e dobishme. Do të flas për atë që kam mësuar dhe disa vëzhgime që kam bërë gjatë ndërtimit të lojës nga e para.

Skillbox rekomandon: Kursi praktik dyvjeçar «Unë jam një zhvillues web PRO».

Kujtojmë: për të gjithë lexuesit e «Habra» — zbritje prej 10,000 rublesh për regjistrimin në çdo kurs Skillbox me kodin promovues «Habr».

Pse Rust?

E zgjodha këtë gjuhë sepse kam dëgjuar shumë mirë për të dhe po shoh që po bëhet gjithnjë e më e njohur në fushën e zhvillimit të lojërave. Para se të shkruaja lojën, kisha një përvojë të vogël në zhvillimin e aplikacioneve të thjeshta me Rust. Kjo ishte pikërisht e mjaftueshme për të ndjerë një liri të caktuar gjatë shkruarjes së lojës.

Pse një lojë dhe cila lojë?

Krijimi i lojërave është argëtim! Do doja që të ishin më shumë arsye, por për projektet «shtëpiake», zgjedh tema që nuk janë shumë të lidhura me punën time të zakonshme. Cila është loja? Doja të krijoja diçka si një simulator tenisi, ku bashkohen Cities Skylines, Zoo Tycoon, Prison Architect dhe vetë tenisi. Në përgjithësi, doli një lojë për një akademi tenisi, ku njerëzit vijnë për të luajtur.

Përgatitja teknike

Doja të përdorja Rust, por nuk dija saktësisht se sa shumë duhet të filloja nga e para. Nuk doja të shkruaja piksel shader dhe të përdorja drag-n-drop, kështu që kërkoja zgjidhje më fleksibël.

Gjeta disa burime të dobishme që po i ndaj me ju:

Studjova disa motorë lojërash Rust, përzgjedhjen përfundimtare e bëra me Piston dhe ggez. Këto i kisha hasur gjatë punës në projektin e mëparshëm. Në fund zgjodha ggez, sepse më dukej më e përshtatshme për realizimin e një loje të vogël 2D. Struktura modulare e Piston-it është shumë e ndërlikuar për një zhvillues fillestar (ose ata që punojnë për herë të parë me Rust).

Struktura e lojës

Kalova pak kohë duke menduar për arkitekturën e projektit. Hapi i parë është të krijoj «tokën», njerëzit dhe këndet e tenisit. Njerëzit duhet të lëvizin nëpër kënde dhe të presin. Lojtarët duhet të kenë aftësi që përmirësohen me kalimin e kohës. Për më tepër, duhet të ekzistojë një redaktor që lejon shtimin e njerëzve dhe këndeve të rinj, por kjo nuk është më falas.

Pasi e mendova gjithçka, fillova punën.

Krijimi i lojës

Fillimi: rrethkthes dhe abstrahime

Mora një shembull nga ggez dhe arrita të kem një rreth në ekran. E çuditshme! Tani pak abstrahime. Më dukej se ishte mirë të abstrahoja nga ideja e objektit të lojës. Çdo objekt duhet të merret me renderim dhe përditësim, siç është treguar këtu:

// 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(())
    }
}

Ky copë kodit më lejoi të siguroj një listë të shkëlqyer objektesh që mund të përditësoj dhe renderoj në një cikël të barabartë

mpl event::EventHandler për MainState {
    fn update(&mut self, context: &mut Context) -> GameResult<()> {
        \/\/ Përditëso të gjithë objektet
        për objekt në self.objects.iter_mut() {
            objekt.update(context)?;
        }

        Ok(())
    }

    fn draw(&mut self, context: &mut Context) -> GameResult<()> {
        graphics::clear(context);

        \/\/ NDraw gjithë objektet
        për objekt në self.objects.iter_mut() {
            objekt.draw(context)?;
        }

        graphics::present(context);

        Ok(())
    }
}

main.rs është e nevojshme sepse aty ndodhen të gjitha rreshtat e kodit. Kalova pak kohë për të ndarë skedarët dhe për të optimizuar strukturën e direktorive. Këtu është si duket gjithçka pas kësaj:
resources -> këtu janë të gjitha asetet (imazhet)
src
— entitetet
— game_object.rs
— circle.rs
— main.rs -> cikli kryesor

Njerëzit, katet dhe imazhet

Hapi tjetër është krijimi i objektit të lojës Person dhe ngarkimi i imazheve. Të gjitha duhet të ndërtohen mbi baza flakësh 32*32.

Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Fushat e tenisit

Pas hulumtimit se si duken fushat e tenis, vendosa të bëj ndërtimin e tyre nga flakë 4*2. Fillimisht mund të kisha bërë një imazh të tillë ose të bashkoja 8 flakë të veçanta. Por më vonë kuptova se ishin të nevojshme vetëm dy flakë unike, dhe ja pse.

Ne kemi gjithsej dy flakë të tilla: 1 dhe 2.

Çdo seksion i fushës përbëhet nga flakë 1 ose flakë 2. Ato mund të pozicionohen si zakonisht ose të jenë të kthyer në 180 gradë.

Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Mënyra kryesore e ndërtimit

Pas arritjes së renderimit të fushave, njerëzve dhe hartave, kuptova se më nevojitej edhe një mënyrë bazë ndërtimi. E realizova kështu: kur shtypet butoni — objekti është i zgjedhur dhe klikimi e vendos atë në vendin e duhur. Pra, butoni 1 lejon zgjedhjen e fushës, ndërsa butoni 2 lejon zgjedhjen e lojtarit.

Por duhet të kujtoj se çfarë do të thotë 1 dhe 2, kështu që shtova një wireframe për ta bërë të qartë se cili objekt është i zgjedhur. Këtu është si duket.

Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Pyetje për arkitekturën dhe refaktorizimin

Tani kam kam kam kam kam, por të punojnë wireframes, çdo entitet objekti duhet të informohet nëse objektet vetë janë në modin e demonstrimit, ose thjesht është vizatuar një kornizë. Kjo nuk është shumë e përshtatshme.

Më duket se duhet të ripërcaktohet arkitektura që të identifikohen disa kufizime:

  • prania e një entiteti që i tregon dhe përditëson vetveten është një problem, pasi ky entitet nuk do të mund "ta dijë" se çfarë duhet të renderojë - imazhi dhe wireframe;
  • mungesa e një instrumenti për ndarjen e pronave dhe sjelljes ndërmjet entiteteve të veçanta (shembuj - prona is_build_mode ose vizatimi i sjelljes). Mund të përdorej trashëgimia, megjithëse në Rust nuk ka një mënyrë normale për ta realizuar këtë. Ajo që më nevojitej me të vërtetë ishte kompozimi;
  • një instrument për interaksionin e entiteteve me njëri-tjetrin ishte i nevojshmi, për t'i caktuar njerëzit në lëndina;
  • entitetet vetë përbënin një përzierje të të dhënave dhe logjikës, e cila shpejt dilte jashtë kontrollit.

Kam bërë një studim të mëtejshëm dhe kam zbuluar arkitekturën ECS — Sistemi i Komponentëve të Entiteteve, i cili përdoret zakonisht në lojëra. Ja përparësitë e ECS:

  • të dhënat janë të ndara nga logjika;
  • kompozimi në vend të trashëgimisë;
  • arkitekturë e orientuar drejt të dhënave.

Për ECS karakterizohen tre koncepte bazë:

  • entitetet — tip objekti, në të cilin referohet identifikuesi (mund të jetë një lojtar, një top ose diçka tjetër);
  • komponentët — përbërësit e entiteteve. Shembuj — komponenti i renderimit, pozita dhe të tjera. Këto janë depo të të dhënave;
  • sistemet — ato përdorin si objektet ashtu edhe komponentët, përveçse përmbajnë sjelljen dhe logjikën, të cilat bazohen në këto të dhëna. Shembuj — sistemi i renderimit, që kalon përmes të gjitha entiteteve me komponentë për renderim dhe merret me vizatimin.

Pas studimit është bërë e qartë se ECS zgjidh problemet si:

  • aplikimi i kompozimit në vend të trashëgimisë për organizimin sistematik të entiteteve;
  • çlirimi nga kaosi i kodit përmes sistemeve të menaxhimit;
  • përdorimi i metodave si is_build_mode për të ruajtur logjikën e wireframe në të njëjtin vend - në sistemin e renderimit.

Ja çfarë është arritur pas implementimit të ECS.

resources -> këtu janë të gjitha asetet (imazhet)
src
— komponentët
— position.rs
— person.rs
— tennis_court.rs
— floor.rs
— wireframe.rs
— mouse_tracked.rs
— burimet
— mouse.rs
— sistemet
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> funksionet e fabrikës së botës
— main.rs -> cikli kryesor

Caktojmë njerëzit në fushat

ECS e bëri jetën më të lehtë. Tashmë pata një rrugë sistematike për të shtuar të dhëna në entitete dhe për të shtuar logjikë të bazuar në këto të dhëna. Kjo, nga ana tjetër, mundësoi organizimin e shpërndarjes së njerëzve në fusha.

Çfarë bëra:

  • shtova të dhënat mbi fushat e caktuara në Person;
  • shtova të dhënat mbi njerëzit e shpërndarë në TennisCourt;
  • shtova sistemin e përzgjedhjes së fushave, i cili analizojnë njerëzit dhe lokacionet, zbulon fushat e disponueshme dhe shpërndan lojtarët mbi to;
  • shtova sistemin e lëvizjes së personave, i cili i kërkon njerëzit e caktuar në fusha, dhe nëse ata nuk janë aty, dërgon njerëzit aty ku nevojitet.

Lojërat me Rust për 24 orë: eksperience personale e zhvillimit

Të shohim përfundimet

Më pëlqeu shumë të punoja mbi këtë lojë të thjeshtë. Më shumë se kaq, jam e kënaqur që përdora Rust për ta shkruar, sepse:

  • Rust ofron atë që nevojitet;
  • ka dokumentacion të shkëlqyer, Rust është shumë eleganten;
  • qëndrueshmëria është e shkëlqyer;
  • nuk është e nevojshme të përdorim klonimin, kopjimin ose veprime të ngjashme, gjë që shpesh e bëja në C++;
  • Options janë shumë të përshtatshme për t'u punuar, gjithashtu trajtojnë shkaktarët e gabimeve në mënyrë të shkëlqyer;
  • nëse projekti arrin të kompilojë, në 99% të rasteve ai funksionon ashtu siç duhet. Mesazhet e gabimeve të kompilerit, mendoj se janë më të mirat që kam parë.

Zhvillimi i lojërave në Rust është vetëm duke filluar. Por tashmë ekziston një komunitet stabil dhe mjaft i madh, që po punon për ta bërë Rust të hapur për të gjithë. Prandaj, shikoj përpara me optimizëm për të ardhmen e gjuhës, duke pritur me padurim për rezultatet e punës sonë të përbashkët.

Skillbox rekomandon:

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster