Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Sa artikulong ito ay pag-uusapan ko ang aking personal na karanasan sa pagbuo ng isang maliit na laro sa Rust. Tumagal ng humigit-kumulang 24 na oras upang lumikha ng isang gumaganang bersyon (kadalasan ay nagtatrabaho ako sa gabi o sa katapusan ng linggo). Ang laro ay malayo sa tapos, ngunit sa tingin ko ang karanasan ay magiging kapakipakinabang. Ibabahagi ko ang aking natutunan at ilang mga obserbasyon na ginawa ko habang binubuo ang laro mula sa simula.

Inirerekomenda ng Skillbox ang: Dalawang taong praktikal na kurso "Ako ay isang PRO web developer".

Pinapaalala namin sa iyo: para sa lahat ng mga mambabasa ng "Habr" - isang diskwento na 10 rubles kapag nag-enroll sa anumang kurso sa Skillbox gamit ang code na pang-promosyon ng "Habr".

Bakit Rust?

Pinili ko ang wikang ito dahil marami na akong narinig na magagandang bagay tungkol dito at nakikita kong nagiging mas at mas popular ito sa pagbuo ng laro. Bago isulat ang laro, wala akong karanasan sa pagbuo ng mga simpleng application sa Rust. Ito ay sapat lamang upang bigyan ako ng pakiramdam ng kalayaan habang isinusulat ang laro.

Bakit ang laro at anong uri ng laro?

Ang paggawa ng mga laro ay masaya! Nais kong magkaroon ng higit pang mga kadahilanan, ngunit para sa mga proyektong "tahanan" ay pinipili ko ang mga paksa na hindi masyadong malapit na nauugnay sa aking regular na trabaho. Anong laro ito? Gusto kong gumawa ng parang tennis simulator na pinagsasama ang Cities Skylines, Zoo Tycoon, Prison Architect at tennis mismo. Sa pangkalahatan, ito ay naging isang laro tungkol sa isang tennis academy kung saan pumupunta ang mga tao upang maglaro.

Teknikal na pagsasanay

Gusto kong gamitin ang Rust, ngunit hindi ko alam kung gaano karaming batayan ang kakailanganin upang magsimula. Hindi ko nais na magsulat ng mga pixel shader at gumamit ng drag-n-drop, kaya naghahanap ako ng mga pinaka-flexible na solusyon.

Nakakita ako ng mga kapaki-pakinabang na mapagkukunan na ibinabahagi ko sa iyo:

Nag-explore ako ng ilang Rust game engine, sa huli ay pinili ko ang Piston at ggez. Nadatnan ko sila habang gumagawa ng isang nakaraang proyekto. Sa huli, pinili ko ang ggez dahil tila mas angkop ito para sa pagpapatupad ng isang maliit na 2D na laro. Masyadong kumplikado ang modular na istraktura ng Piston para sa isang baguhan na developer (o isang taong nagtatrabaho sa Rust sa unang pagkakataon).

Istruktura ng laro

Ilang oras akong nag-iisip tungkol sa arkitektura ng proyekto. Ang unang hakbang ay ang paggawa ng "lupa", mga tao at mga tennis court. Ang mga tao ay kailangang lumipat sa paligid ng mga korte at maghintay. Ang mga manlalaro ay dapat magkaroon ng mga kasanayan na umuunlad sa paglipas ng panahon. Dagdag pa, dapat mayroong isang editor na nagpapahintulot sa iyo na magdagdag ng mga bagong tao at hukuman, ngunit hindi na ito libre.

Matapos kong pag-isipan ang lahat, nagsimula akong magtrabaho.

Paglikha ng laro

Simula: Circles at Abstractions

Kumuha ako ng isang halimbawa mula sa ggez at nakakuha ng isang bilog sa screen. Kahanga-hanga! Ngayon ilang abstraction. Naisip ko na magiging maganda ang abstract mula sa ideya ng isang bagay na laro. Ang bawat bagay ay dapat i-render at i-update gaya ng nakasaad dito:

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

Ang piraso ng code na ito ay nagbigay sa akin ng magandang listahan ng mga bagay na maaari kong i-update at i-render sa isang pantay na magandang loop.

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

kailangan ang main.rs dahil naglalaman ito ng lahat ng linya ng code. Gumugol ako ng kaunting oras sa paghihiwalay ng mga file at pag-optimize ng istraktura ng direktoryo. Ganito ang hitsura pagkatapos noon:
mapagkukunan -> dito naroroon ang lahat ng mga asset (mga larawan)
SRC
- mga entidad
— game_object.rs
— bilog.rs
— main.rs -> pangunahing loop

Mga tao, sahig at mga larawan

Ang susunod na hakbang ay lumikha ng object ng laro ng Tao at mag-load ng mga larawan. Ang lahat ay dapat na binuo batay sa 32*32 tile.

Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Mga korte ng tennis

Pagkatapos pag-aralan kung ano ang hitsura ng mga tennis court, nagpasya akong gawin ang mga ito mula sa 4*2 tile. Sa una, posible na gumawa ng isang imahe ng ganitong laki, o upang magkasama 8 hiwalay na mga tile. Ngunit pagkatapos ay natanto ko na dalawang natatanging tile lamang ang kailangan, at narito kung bakit.

Sa kabuuan mayroon kaming dalawang ganoong tile: 1 at 2.

Ang bawat seksyon ng court ay binubuo ng tile 1 o tile 2. Maaari silang ilagay bilang normal o i-flip 180 degrees.

Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Basic construction (assembly) mode

Pagkatapos kong makamit ang pag-render ng mga site, tao at mapa, napagtanto ko na kailangan din ng basic assembly mode. Ipinatupad ko ito tulad nito: kapag pinindot ang pindutan, napili ang bagay, at inilalagay ito ng pag-click sa nais na lugar. Kaya, pinapayagan ka ng button 1 na pumili ng court, at pinapayagan ka ng button 2 na pumili ng player.

Ngunit kailangan pa rin nating tandaan kung ano ang ibig sabihin ng 1 at 2, kaya nagdagdag ako ng wireframe para malinawan kung aling bagay ang napili. Ito ang hitsura nito.

Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Mga tanong sa arkitektura at refactoring

Ngayon ay mayroon na akong ilang bagay sa laro: mga tao, court at sahig. Ngunit para gumana ang mga wireframe, kailangang sabihin sa bawat entity ng object kung ang mga object mismo ay nasa demonstration mode, o kung ang isang frame ay simpleng iginuhit. Ito ay hindi masyadong maginhawa.

Para sa akin, ang arkitektura ay kailangang pag-isipang muli sa paraang nagpapakita ng ilang mga limitasyon:

  • Ang pagkakaroon ng entity na nagre-render at nag-a-update mismo ay isang problema dahil ang entity na iyon ay hindi magagawang "malaman" kung ano ang dapat nitong i-render - isang imahe at isang wireframe;
  • kakulangan ng tool para sa pagpapalitan ng mga katangian at gawi sa pagitan ng mga indibidwal na entity (halimbawa, ang is_build_mode na property o pag-render ng gawi). Posibleng gumamit ng mana, bagama't walang tamang paraan para ipatupad ito sa Rust. Ang talagang kailangan ko ay ang layout;
  • isang tool para sa pakikipag-ugnayan sa pagitan ng mga entity ay kailangan upang magtalaga ng mga tao sa mga korte;
  • ang mga entity mismo ay pinaghalong data at lohika na mabilis na nawala sa kontrol.

Gumawa ako ng ilang karagdagang pananaliksik at natuklasan ang arkitektura ECS - Entity Component System, na karaniwang ginagamit sa mga laro. Narito ang mga benepisyo ng ECS:

  • ang data ay hiwalay sa lohika;
  • komposisyon sa halip na mana;
  • arkitektura na nakasentro sa datos.

Ang ECS ​​ay nailalarawan sa pamamagitan ng tatlong pangunahing konsepto:

  • entity - ang uri ng bagay na tinutukoy ng identifier (maaaring ito ay isang manlalaro, bola, o iba pa);
  • mga bahagi - binubuo ng mga ito ang mga entity. Halimbawa - bahagi ng pag-render, mga lokasyon at iba pa. Ito ay mga bodega ng data;
  • system - ginagamit nila ang parehong mga bagay at bahagi, kasama ang pag-uugali at lohika na batay sa data na ito. Ang isang halimbawa ay isang sistema ng pag-render na umuulit sa lahat ng mga entity na may mga bahagi ng pag-render at ginagawa ang pag-render.

Matapos itong pag-aralan, naging malinaw na nilulutas ng ECS ​​ang mga sumusunod na problema:

  • gamit ang layout sa halip na pamana upang sistematikong ayusin ang mga entidad;
  • pag-alis ng code jumble sa pamamagitan ng mga control system;
  • gamit ang mga pamamaraan tulad ng is_build_mode upang panatilihin ang logic ng wireframe sa parehong lugar - sa sistema ng pag-render.

Ito ang nangyari pagkatapos ipatupad ang ECS.

mapagkukunan -> dito naroroon ang lahat ng mga asset (mga larawan)
SRC
- mga bahagi
—posisyon.rs
— tao.rs
— tennis_court.rs
— sahig.rs
- wireframe.rs
— mouse_tracked.rs
- mapagkukunan
—mouse.rs
- mga sistema
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> world factory function
— main.rs -> pangunahing loop

Nagtatalaga kami ng mga tao sa mga korte

Pinadali ng ECS ​​ang buhay. Ngayon ay nagkaroon ako ng isang sistematikong paraan upang magdagdag ng data sa mga entity at magdagdag ng lohika batay sa data na iyon. At ito, sa turn, ay naging posible upang ayusin ang pamamahagi ng mga tao sa mga korte.

Ano ang nagawa ko:

  • nagdagdag ng data tungkol sa mga nakatalagang hukuman sa Tao;
  • nagdagdag ng data tungkol sa mga ipinamahagi na tao sa TennisCourt;
  • idinagdag ang CourtChoosingSystem, na nagbibigay-daan sa iyong pag-aralan ang mga tao at korte, makita ang mga available na court at ipamahagi ang mga manlalaro sa kanila;
  • nagdagdag ng isang PersonMovementSystem, na naghahanap ng mga taong nakatalaga sa mga hukuman, at kung wala sila roon, pagkatapos ay magpapadala ng mga tao kung saan sila dapat naroroon.

Paglalaro ng Rust sa loob ng 24 na oras: karanasan sa personal na pag-unlad

Lagom

Talagang nasiyahan ako sa pagtatrabaho sa simpleng larong ito. Bukod dito, natutuwa ako na ginamit ko si Rust para isulat ito, dahil:

  • Binibigyan ka ng kalawang kung ano ang kailangan mo;
  • mayroon itong mahusay na dokumentasyon, ang kalawang ay medyo eleganteng;
  • ang pagkakapare-pareho ay cool;
  • hindi mo kailangang gumamit ng pag-clone, pagkopya o iba pang katulad na pagkilos, na madalas kong ginagawa sa C++;
  • Napakadaling gamitin ng mga opsyon at napakahusay na pangasiwaan ang mga error;
  • kung nagawang i-compile ang proyekto, 99% ng oras na gumagana ito, at eksakto sa nararapat. Sa tingin ko ang mga mensahe ng error ng compiler ang pinakamahusay na nakita ko.

Nagsisimula pa lang ang pagbuo ng laro sa Rust. Ngunit mayroon nang matatag at medyo malaking komunidad na nagtatrabaho upang buksan ang Rust sa lahat. Samakatuwid, tinitingnan ko ang kinabukasan ng wika nang may optimismo, na umaasa sa mga resulta ng ating karaniwang gawain.

Inirerekomenda ng Skillbox ang:

Pinagmulan: www.habr.com

Magdagdag ng komento