
Në këtë artikull, do të flas për përvojën time personale në zhvillimin e një loje të vogël me Rust. Ndërsa krijova versionin funksional, më mori rreth 24 orë (kryesisht punova në mbrëmje ose gjatë fundjavës). Loja është ende larg përfundimit, por mendoj se përvoja do të jetë e dobishme. Do të tregoj se çfarë kam mësuar dhe disa vëzhgime të bëra gjatë ndërtimit të lojës nga zero.
Skillbox rekomandon: Kurs praktik dyvjeçar .
KujtojmĂ«: pĂ«r tĂ« gjithĂ« lexuesit e "Habra" â zbritje prej 10,000 rublej pĂ«r regjistrimin nĂ« çdo kurs Skillbox me kodin promocional "Habr".
Pse Rust?
Zgjodha këtë gjuhë sepse kam dëgjuar shumë të mira për të dhe shoh se po bëhet gjithnjë e më popullore 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 loja dhe çfarë loje?
Krijimi i lojĂ«rave Ă«shtĂ« argĂ«tues! Do doja tĂ« kishte mĂ« shumĂ« arsye, por pĂ«r projektet «shtĂ«piake», zgjedh tema qĂ« nuk janĂ« shumĂ« tĂ« lidhura me punĂ«n time tĂ« zakonshme. ĂfarĂ« loje? DĂ«shiroja tĂ« bĂ«ja diçka si njĂ« simulues tenisi, ku kombinohen Cities Skylines, Zoo Tycoon, Prison Architect dhe vetĂ« tenisi. NĂ« pĂ«rgjithĂ«si, ndihesha se kisha krijuar njĂ« lojĂ« pĂ«r njĂ« akademi tenisi, ku njerĂ«zit vijnĂ« pĂ«r tĂ« luajtur.
Përgatitja teknike
Dëshiroja të përdor Rust, por nuk e dija saktësisht se sa «nga zero» do të duhej të filloja punën. Nuk doja të shkruaja shader pikselësh dhe të përdorja drag-and-drop, prandaj kërkoja zgjidhje sa më fleksibile.
Gjeta disa burime të dobishme që po i ndaj me ju:
- â njĂ« listĂ« e elementeve tĂ« nevojshme pĂ«r zhvillimin e lojĂ«rave me Rust;
Studova disa motorë lojërash Rust, duke e zgjedhur përfundimisht Piston dhe ggez. I takova këto ndërsa punoja në projektin e mëparshëm. Në fund, zgjodha ggez, pasi më dukej më e përshtatshme për realizimin e një loje të vogël 2D. Strukturimi modular i Piston është shumë i komplikuar për një zhvillues fillestar (apo për dikë që punon për herë të parë me Rust).
Struktura e lojës
Kaluova pak kohĂ« duke menduar pĂ«r arkitekturĂ«n e projektit. Hapi i parĂ« â tĂ« krijoja «tokat», njerĂ«zit dhe kortet e tenisit. NjerĂ«zit duhet tĂ« lĂ«vizin nĂ«pĂ«r kurte dhe tĂ« presin. LojtarĂ«t duhet tĂ« kenĂ« aftĂ«si qĂ« pĂ«rmirĂ«sohen me kalimin e kohĂ«s. Gjithashtu, duhet tĂ« ketĂ« njĂ« redaktor qĂ« lejon shtimin e njerĂ«zve dhe korteve, por kjo tashmĂ« nuk Ă«shtĂ« falas.
Pasi mendova gjithçka, fillova punën.
Krijimi i një loje
Fillimi: rrethana dhe abstraksione
Mora njĂ« shembull nga ggez dhe arrita njĂ« rreth nĂ« ekran. Ma çudit! Tani disa abstraksione. MĂ« dukej e dobishme tĂ« shkĂ«putesha nga ideja e objektit tĂ« lojĂ«s. Ădo objekt duhet tĂ« jetĂ« i renderuar dhe i pĂ«rditĂ«suar, siç Ă«shtĂ« parashikuar 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 pjesë kodi më lejon të kem një listë të shkëlqyer objektesh, të cilat mund t'i përditësoj dhe t'i renderoj në një cikël po aq të shkëlqyer.
mpl event::EventHandler për MainState {
fn update(&mut self, context: &mut Context) -> GameResult<()> {
// Përditëso të gjitha objektet
për objekt në self.objects.iter_mut() {
objekt.update(context)?;
}
Ok(())
}
fn draw(&mut self, context: &mut Context) -> GameResult<()> {
graphics::clear(context);
// Vizato të gjitha 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 optimizuar strukturën e dosjeve. Kështu dukej pas kësaj:
resources -> këtu ndodhen të gjitha asetet (imazhet)
src
â entitetet
â game_object.rs
â circle.rs
â main.rs -> cikli kryesor
Njerëzit, katet dhe imazhet
Hapi tjetĂ«r â krijimi i objektit tĂ« lojĂ«s Person dhe ngarkimi i imazheve. TĂ« gjitha duhet tĂ« ndodhin nĂ« bazĂ« tĂ« pllakatave me madhĂ«si 32*32.

Kortet e tenisit
Duke studiuar se si duken kortet e tenisit, vendosa t'i bëj ato nga pllakat 4*2. Fillimisht, mund të bëja një imazh të tillë ose të përbëja bashkë 8 pllaka të veçanta. Por pastaj e kuptova se nevojiten vetëm dy pllakat unike, dhe ja pse.
Kemi dy pllaka të tilla: 1 dhe 2.
Ădo seksion i kortit pĂ«rbĂ«het nga pllaka 1 ose pllaka 2. Ato mund tĂ« vendosen si zakonisht ose tĂ« kthehen 180 gradĂ«.

Rejimi kryesor i ndërtimit (montimit)
Pasi arrita tĂ« realizoj renderimin e fushave, njerĂ«zve dhe hartave, kuptova se nevojitej gjithashtu njĂ« rejim bazĂ« ndĂ«rtimi. E realizova kĂ«shtu: kur shtypet butoni â objekti zgjidhet, dhe klikimi e vendos atĂ« nĂ« vendin e dĂ«shiruar. Pra, butoni 1 lejon tĂ« zgjidhet korti, ndĂ«rsa butoni 2 lejon tĂ« zgjidhet lojtari.
Por duhet ta mbajtur mend se çfarë përfaqësojnë 1 dhe 2, prandaj shtova një wireframe për të qartësuar se cili objekt është i zgjedhur. Kështu duket.

Pyetje mbi arkitekturën dhe rifaktorizimin
Tani kam kam kam kam kam. Por të punuaren e wireframes, çdo entitet objekti duhet të informohet nëse vetë objektet janë në modin për të treguar, apo vetëm është vizatuar një kornizë. Kjo nuk është shumë e përshtatshme.
Më duket se duhet të rishqyrtohet arkitektura në mënyrë që të evidentohen disa kufizime:
- prania e njĂ« entiteti qĂ« tregon dhe pĂ«rditĂ«son veten â Ă«shtĂ« njĂ« problem, sepse ky entitet nuk do tĂ« jetĂ« nĂ« gjendje tĂ« "kuptojĂ«" se çfarĂ« duhet tĂ« renderizojĂ« â imazhin ose wireframe-in;
- mungesa e njĂ« instrumenti pĂ«r ndarjen e pronave dhe sjelljes midis entiteteve tĂ« veçanta (shembuj â pronĂ«sia is_build_mode ose vizatimi i sjelljes). Do tĂ« ishte e mundur tĂ« pĂ«rdorej trashĂ«gimia, megjithĂ«se nĂ« Rust nuk ka njĂ« mĂ«nyrĂ« normale pĂ«r ta realizuar atĂ«. Ajo qĂ« mĂ« duhej vĂ«rtet â ishte kompozita;
- një instrument për ndërveprimin e entiteteve gjithashtu ishte i nevojshëm, për të caktuar njerëzit në fusha;
- vetë entitetet përbënin një përzierje të të dhënave dhe logjikës, gjë që shumë shpejt dilte jashtë kontrollit.
Kam bërë një studim të mëtejshëm dhe kam zbuluar arkitekturën , i cili zakonisht përdoret në lojëra. Ja përfitimet e ECS:
- të dhënat ndahen nga logjika;
- kompozita në vend të trashëgimisë;
- arkitekturë e fokusuar në të dhëna.
Për ECS, karakterizohen tre koncepte bazë:
- entitetet â njĂ« tip objekti, ndaj tĂ« cilit referohet njĂ« identifikues (kjo mund tĂ« jetĂ« njĂ« lojtar, njĂ« top ose diçka tjetĂ«r);
- komponentĂ«t â nga tĂ« cilĂ«t pĂ«rbĂ«hen entitetet. Shembuj â komponenti i renderimit, pozita dhe tĂ« tjera. KĂ«to janĂ« depo tĂ« dhĂ«nash;
- sistemet â ato pĂ«rdorin si objektet ashtu edhe komponentĂ«t, pĂ«rveçse pĂ«rmbajnĂ« sjellje dhe logjikĂ« qĂ« bazohen nĂ« kĂ«to tĂ« dhĂ«na. Shembull â sistemi i renderimit, i cili shqyrton tĂ« gjithĂ« entitetet me komponentĂ« pĂ«r renderim dhe merret me vizatimin.
Pas studimit doli se ECS zgjidh këto probleme:
- aplikaimi i kompozitës në vend të trashëgimisë për organizimin sistematik të entiteteve;
- zhbërja e kaosit të kodit përmes sistemeve të menaxhimit;
- pĂ«rdorimi i metodave si is_build_mode pĂ«r tĂ« mbajtur logjikĂ«n e wireframe-it nĂ« tĂ« njĂ«jtin vend â nĂ« sistemin e renderimit.
Ja çfarë u arrit pas integrimit të ECS.
resources -> këtu ndodhen të gjitha asetet (imazhet)
src
â komponentĂ«
â position.rs
â person.rs
â tennis_court.rs
â floor.rs
â wireframe.rs
â mouse_tracked.rs
â burime
â mouse.rs
â sisteme
â rendering.rs
â constants.rs
â utils.rs
â world_factory.rs -> funksionet e fabrikĂ«s sĂ« botĂ«s
â main.rs -> cikli kryesor
Caktojmë njerëzit në fusha
ECS e bëri jetën më të lehtë. Tani kisha një rrugë sistematike për të shtuar të dhëna në entitete dhe për të shtuar logjikën e bazuar në këto të dhëna. Kjo, nga ana tjetër, lehtësoi shpërndarjen e njerëzve në fusha.
Ajo që bëra:
- shtova të dhënat për fusha të caktuara në Person;
- shtova të dhëna për njerëzit e shpërndarë në TennisCourt;
- shtova CourtChoosingSystem, e cila lejon analizimin e njerëzve dhe fushave, identifikimin e fushave të disponueshme dhe shpërndarjen e lojtarëve atje;
- shtova sistemin PersonMovementSystem, i cili kërkon njerëzit e caktuar në fusha, dhe nëse ata nuk janë aty, i dërgon njerëzit atje ku duhet.

Përmbledhje
Më pëlqeu shumë të punoj mbi këtë lojë të thjeshtë. Gjithashtu, jam e kënaqur që e shkrova atë në Rust, sepse:
- Rust ju jep atë që ju nevojitet;
- ka dokumentacion të shkëlqyer, Rust është shumë elegant;
- qĂ«ndrueshmĂ«ria â Ă«shtĂ« e shkĂ«lqyer;
- nuk është e nevojshme të mbështetesha në klonim, kopjim ose veprime të tjera të ngjashme, që unë shpesh bëja në C++;
- Options janë shumë të dobishme për punë, gjithashtu trajtojnë mjaft mirë gabimet;
- nëse projekti u kompilua me sukses, në 99% ai funksionon ashtu siç duhet. Mesazhet e gabimit të kompilatorit, mendoj se janë më të mirat që kam parë.
Zhvillimi i lojërave në Rust sapo ka filluar. Por tashmë ekziston një komunitet i qëndrueshëm dhe mjaft i madh që punon për ta hapur Rust për të gjithë. Prandaj, shikoj me optimizëm të ardhmen e gjuhës, duke pritur me padurim rezultatet e punës sonë të përbashkët.
Skillbox rekomandon:
- Kurs online .
- Kurs praktik .
- Kurs praktik njëvjeçar .
Burimi: habr.com
