Joc în Rust în 24 de ore: experiența personală de dezvoltare

Joc în Rust în 24 de ore: experiența personală de dezvoltare

În acest articol, voi povesti despre experiența mea personală în dezvoltarea unui mic joc pe Rust. Crearea versiunii funcționale a durat aproximativ 24 de ore (predominant am lucrat seara sau în weekend). Jocul este încă departe de a fi finalizat, dar consider că experiența va fi utilă. Voi povesti ce am învățat și despre câteva observații făcute în construirea jocului de la zero.

Skillbox recomandă: Curs practic de doi ani „Sunt dezvoltator web PRO”.

Vă reamintim: pentru toți cititorii „Habr” — reducere de 10.000 de ruble la înscrierea la orice curs Skillbox cu codul de promovare „Habr”.

De ce Rust?

Am ales acest limbaj deoarece am auzit multe lucruri bune despre el și observ că devine din ce în ce mai popular în domeniul dezvoltării de jocuri. Înainte de a scrie jocul, am avut o experiență limitată în dezvoltarea de aplicații simple pe Rust. Aceasta a fost suficientă pentru a simți o anumită libertate în timpul scrierii jocului.

De ce un joc și despre ce fel de joc este vorba?

Crearea de jocuri este distractivă! Mi-aș fi dorit să fie mai multe motive, dar pentru proiectele „de casă” aleg teme care nu sunt foarte legate de munca mea obișnuită. Ce fel de joc? Am vrut să fac ceva de genul unui simulator de tenis, unde se îmbină Cities Skylines, Zoo Tycoon, Prison Architect și, desigur, tenis. În general, a ieșit un joc despre o academie de tenis, unde oamenii vin să joace.

Pregătire tehnică

Am vrut să folosesc Rust, dar nu știam exact de la ce „zero” trebuie să încep lucrul. Nu voiam să scriu shader-e pixelate și să folosesc drag-n-drop, așa că am căutat cele mai flexibile soluții.

Am găsit resurse utile pe care le împărtășesc cu voi:

Am studiat câteva motoare de jocuri Rust, alegând în cele din urmă Piston și ggez. M-am întâlnit cu ele în timpul lucrului la proiectul anterior. În final, am ales ggez, deoarece a părut mai potrivit pentru realizarea unui mic joc 2D. Structura modulară a Piston este prea complexă pentru un dezvoltator începător (sau pentru cineva care lucrează pentru prima dată cu Rust).

Structura jocului

Am dedicat puțin timp gândindu-mă la arhitectura proiectului. Primul pas este să fac „pământul”, oamenii și terenurile de tenis. Oamenii trebuie să se deplaseze pe terenuri și să aștepte. Jucătorii trebuie să aibă abilități care se dezvoltă în timp. În plus, trebuie să existe un editor care să permită adăugarea de noi persoane și terenuri, dar asta nu e gratuit.

După ce am gândit totul, am început lucrul.

Crearea unui joc

Început: cercuri și abstracții

Am luat un exemplu din ggez și am obținut un cerc pe ecran. Uimitor! Acum, câteva abstracții. Mi s-a părut bine să mă abțin de la ideea de obiect de joc. Fiecare obiect trebuie să fie redat și actualizat, așa cum este specificat aici:

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

Această secțiune de cod mi-a permis să obțin o listă excelentă de obiecte pe care le pot actualiza și reda într-un ciclu nu mai puțin excelent.

mpl event::EventHandler for MainState {
    fn update(&mut self, context: &mut Context) -> GameResult {
        // Actualizează toate obiectele
        for object in self.objects.iter_mut() {
            object.update(context)?;
        }

        Ok(())
    }

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

        // Desenează toate obiectele
        for object in self.objects.iter_mut() {
            object.draw(context)?;
        }

        graphics::present(context);

        Ok(())
    }
}

main.rs este necesar deoarece conține toate liniile de cod. Am dedicat puțin timp pentru a împărți fișierele și a optimiza structura directorilor. Iată cum a arătat totul după aceasta:
resources -> acesta este locul unde se află toate activele (imagini)
src
— entities
— game_object.rs
— circle.rs
— main.rs -> bucla principală

Oameni, etaje și imagini

Următorul pas este crearea obiectului de joc Person și încărcarea imaginilor. Totul trebuie să fie construit pe baza plăcilor de dimensiune 32*32.

Joc în Rust în 24 de ore: experiența personală de dezvoltare

Terenuri de tenis

După ce am studiat cum arată terenurile de tenis, am decis să le fac din plăci de 4*2. La început, putea fi creată o imagine de această dimensiune sau se puteau combina 8 plăci separate. Dar ulterior am realizat că sunt necesare doar două plăci unice și iată de ce.

Avem în total două plăci de acest tip: 1 și 2.

Fiecare secțiune a terenului constă din placa 1 sau placa 2. Acestea pot fi plasate în mod obișnuit sau pot fi întoarse cu 180 de grade.

Joc în Rust în 24 de ore: experiența personală de dezvoltare

Modul principal de construcție (asamblează)

După ce am reușit să obțin redarea terenurilor, oamenilor și hartelor, am realizat că este necesar și un mod de bază de asamblare. L-am implementat astfel: când butonul este apăsat, obiectul este selectat, iar un clic îl plasează în locul dorit. Astfel, butonul 1 permite selectarea terenului, iar butonul 2 permite selectarea jucătorului.

Dar trebuie să ne amintim ce înseamnă 1 și 2, așa că am adăugat un wireframe pentru a fi clar ce obiect este selectat. Iată cum arată.

Joc în Rust în 24 de ore: experiența personală de dezvoltare

Întrebări despre arhitectură și refactorizare

Acum am câteva obiecte de joc: oameni, terenuri și etaje. Dar pentru ca wireframe-urile să funcționeze, fiecare entitate trebuie să comunice dacă obiectele în sine sunt în modul de demonstrație sau dacă este doar o ramă desenată. Nu este foarte convenabil.

Mi s-a părut că trebuie reexaminată arhitectura pentru a evidenția anumite limitări:

  • prezența unei entități care se autoafişează și se actualizează este o problemă, deoarece această entitate nu va putea "afla" ce trebuie să redare — imaginea și wireframe-ul;
  • absența unui instrument de schimb de proprietăți și comportamente între entități distincte (exemplu — proprietatea is_build_mode sau redarea comportamentului). S-ar fi putut folosi moștenirea, deși în Rust nu există o modalitate normală de a o implementa. Ceea ce aveam cu adevărat nevoie era compunerea;
  • un instrument pentru interacțiunea entităților între ele era necesar pentru a asigna oameni pe terenuri;
  • însăși entitățile reprezintă un amestec de date și logică, ceea ce rapid ieșea de sub control.

Am efectuat o cercetare suplimentară și am descoperit arhitectura ECS — Sistem de Componente Entitate, care este folosită de obicei în jocuri. Iată avantajele ECS:

  • datele sunt separate de logică;
  • compunerea în loc de moștenire;
  • arhitectură orientată pe date.

Pentru ECS, sunt caracteristice trei concepte de bază:

  • entități — tipul de obiect la care se referă un identificator (aceasta poate fi un jucător, o minge sau altceva);
  • componente — din care sunt compuse entitățile. Exemplu — componenta de redare, de poziționare și altele. Acestea sunt depozite de date;
  • sistemele — ele utilizează atât obiecte, cât și componente, plus conțin comportament și logică, care se bazează pe aceste date. Un exemplu — un sistem de redare, care parcurge toate entitățile cu componente pentru redare și se ocupă de desenare.

După studiu, a devenit clar că ECS rezolvă aceste probleme:

  • aplicarea compunerii în locul moștenirii pentru organizarea sistematică a entităților;
  • eliminarea amestecului de cod prin sisteme de gestionare;
  • folosirea metodelor precum is_build_mode, pentru a păstra logica wireframe-ului în același loc — în sistemul de redare.

Iată ce a ieșit după implementarea ECS.

resources -> acesta este locul unde se află toate activele (imagini)
src
— componente
— position.rs
— person.rs
— tennis_court.rs
— floor.rs
— wireframe.rs
— mouse_tracked.rs
— resurse
— mouse.rs
— sisteme
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> funcțiile fabricii de lume
— main.rs -> bucla principală

Atribuim oamenii la terenuri

ECS mi-a făcut viața mai ușoară. Acum aveam o modalitate sistematică de a adăuga date la entități și de a adăuga logică bazată pe aceste date. Iar asta, la rândul său, a permis organizarea distribuită a oamenilor pe terenuri.

Ce am făcut:

  • am adăugat date despre terenurile desemnate în Person;
  • am adăugat date despre persoanele distribuite în TennisCourt;
  • am adăugat CourtChoosingSystem, care permite analiza oamenilor și terenurilor, identificarea terenurilor disponibile și distribuirea jucătorilor pe acestea;
  • am adăugat sistemul PersonMovementSystem, care caută persoanele desemnate pe terenuri și, dacă nu sunt acolo, trimite persoanele unde trebuie.

Joc în Rust în 24 de ore: experiența personală de dezvoltare

Încheiem

Mi-a plăcut foarte mult să lucrez la acest joc simplu. Mai mult, sunt mulțumită că am folosit Rust pentru a-l scrie, deoarece:

  • Rust îți oferă ceea ce ai nevoie;
  • are o documentație excelentă, Rust este foarte elegant;
  • permanența este fantastică;
  • nu trebuie să recurg la clonare, copiere sau alte acțiuni similare, ceea ce făceam adesea în C++;
  • Options sunt foarte convenabile de utilizat, de asemenea gestionează erorile foarte bine;
  • dacă proiectul a reușit să se compileze, atunci în 99% din cazuri acesta funcționează așa cum trebuie. Mesajele de eroare ale compilatorului sunt, cred, cele mai bune pe care le-am întâlnit.

Dezvoltarea jocurilor în Rust abia începe. Dar deja există o comunitate stabilă și destul de mare, care lucrează pentru a deschide Rust pentru toată lumea. Așadar, privesc cu optimism spre viitorul limbajului, așteptând cu nerăbdare rezultatele muncii noastre comune.

Skillbox recomandă:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster