Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Tässä artikkelissa puhun henkilökohtaisesta kokemuksestani pienen pelin kehittämisestä Rustissa. Toimivan version luominen kesti noin 24 tuntia (työskentelin pääasiassa iltaisin tai viikonloppuisin). Peli ei ole vielä läheskään valmis, mutta uskon, että kokemus on palkitseva. Kerron, mitä olen oppinut ja joitain havaintoja, joita tein rakentaessani peliä tyhjästä.

Skillbox suosittelee: Kahden vuoden käytännön kurssi "Olen PRO-verkkokehittäjä".

Muistutamme sinua: kaikille "Habrin" lukijoille - 10 000 ruplan alennus ilmoittautuessaan mille tahansa Skillbox-kurssille "Habr" -tarjouskoodilla.

Miksi Rust?

Valitsin tämän kielen, koska olen kuullut siitä paljon hyvää ja näen sen olevan yhä suositumpi pelikehityksessä. Ennen pelin kirjoittamista minulla oli vähän kokemusta yksinkertaisten sovellusten kehittämisestä Rustissa. Tämä riitti vain antamaan minulle vapauden tunteen pelin kirjoittamisen aikana.

Miksi peli ja millainen peli?

Pelien tekeminen on hauskaa! Toivon, että syitä olisi enemmän, mutta "kotiprojekteihin" valitsen aiheita, jotka eivät liity liian läheisesti tavanomaiseen työhöni. Mikä peli tämä on? Halusin tehdä jotain tennissimulaattorin kaltaista, jossa yhdistyvät Cities Skylines, Zoo Tycoon, Prison Architect ja itse tennis. Yleisesti ottaen se osoittautui peliksi tennisakatemiasta, johon ihmiset tulevat pelaamaan.

Tekninen koulutus

Halusin käyttää Rustia, mutta en tiennyt tarkalleen, kuinka paljon pohjatyötä sen käynnistäminen vaatisi. En halunnut kirjoittaa pikselivarjostimia ja käyttää drag-n-dropia, joten etsin joustavimpia ratkaisuja.

Löysin hyödyllisiä resursseja, jotka jaan kanssasi:

Tutkin useita Rust-pelimoottoreita ja valitsin lopulta Pistonin ja ggezin. Törmäsin niihin työskennellessäni edellisen projektin parissa. Lopulta valitsin ggezin, koska se tuntui sopivammalta pienen 2D-pelin toteuttamiseen. Männän modulaarinen rakenne on liian monimutkainen aloittelevalle kehittäjälle (tai sellaiselle, joka työskentelee Rustin kanssa ensimmäistä kertaa).

Pelin rakenne

Mietin jonkin aikaa projektin arkkitehtuuria. Ensimmäinen askel on tehdä "maa", ihmiset ja tenniskentät. Ihmisten täytyy liikkua tuomioistuimissa ja odottaa. Pelaajilla tulee olla taitoja, jotka kehittyvät ajan myötä. Lisäksi pitäisi olla editori, jonka avulla voit lisätä uusia ihmisiä ja tuomioistuimia, mutta tämä ei ole enää ilmaista.

Kun kaikki oli mietitty, ryhdyin töihin.

Pelin luominen

Alku: Ympyrät ja abstraktiot

Otin esimerkin ggezistä ja sain ympyrän näytölle. Mahtavaa! Nyt vähän abstraktioita. Ajattelin, että olisi mukavaa vetäytyä pois ideasta peliobjektista. Jokainen objekti on renderöitävä ja päivitettävä tässä kuvatulla tavalla:

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

Tämä koodinpätkä antoi minulle mukavan luettelon objekteista, jotka voin päivittää ja renderöidä yhtä hienossa silmukassa.

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 on välttämätön, koska se sisältää kaikki koodirivit. Vietin vähän aikaa tiedostojen erottamiseen ja hakemistorakenteen optimointiin. Tältä se näytti sen jälkeen:
resurssit -> tässä on kaikki omaisuus (kuvat)
src
- kokonaisuuksia
- game_object.rs
— circle.rs
— main.rs -> pääsilmukka

Ihmiset, lattiat ja kuvat

Seuraava askel on luoda henkilöpeliobjekti ja ladata kuvia. Kaikki tulee rakentaa 32*32 laattojen pohjalta.

Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Tenniskentät

Tutkittuani, miltä tenniskentät näyttävät, päätin tehdä ne 4*2-laatoista. Aluksi oli mahdollista tehdä tämän kokoinen kuva tai koota 8 erillistä laattaa. Mutta sitten tajusin, että tarvitaan vain kaksi ainutlaatuista laattaa, ja tässä miksi.

Yhteensä meillä on kaksi tällaista laattaa: 1 ja 2.

Jokainen kentän osa koostuu laatasta 1 tai laatta 2. Ne voidaan asettaa normaalisti tai kääntää 180 astetta.

Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Perusrakenne (kokoonpano) -tila

Kun onnistuin saamaan aikaan sivustojen, ihmisten ja karttojen renderöinnin, tajusin, että myös peruskokoonpanotila tarvitaan. Toteutin sen näin: kun painiketta painetaan, objekti valitaan ja napsautus asettaa sen haluttuun paikkaan. Joten painikkeella 1 voit valita kentän ja painikkeella 2 voit valita pelaajan.

Mutta meidän on silti muistettava, mitä 1 ja 2 tarkoittavat, joten lisäsin rautalankakehyksen tehdäkseni selväksi, mikä kohde on valittu. Tältä se näyttää.

Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Arkkitehtuuri- ja refaktorointikysymykset

Nyt minulla on useita peliesineitä: ihmisiä, kenttiä ja lattioita. Mutta jotta metallikehykset toimisivat, jokaiselle objektioliolle on kerrottava, ovatko objektit itse esittelytilassa vai piirretäänkö kehys yksinkertaisesti. Tämä ei ole kovin kätevää.

Minusta tuntui, että arkkitehtuuria oli harkittava uudelleen tavalla, joka paljasti joitain rajoituksia:

  • Entiteetti, joka renderöi ja päivittää itsensä, on ongelma, koska se ei pysty "tietämään", mitä sen on tarkoitus renderöidä - kuvan ja kehyksen;
  • työkalun puute ominaisuuksien ja käyttäytymisen vaihtamiseksi yksittäisten entiteettien välillä (esimerkiksi is_build_mode-ominaisuus tai käyttäytymisen renderöinti). Periytymistä olisi mahdollista käyttää, vaikka rustissa ei olekaan oikeaa tapaa toteuttaa sitä. Mitä todella tarvitsin, oli ulkoasu;
  • tarvittiin työkalu tahojen väliseen vuorovaikutukseen ihmisten määräämiseksi tuomioistuimiin;
  • itse entiteetit olivat sekoitus dataa ja logiikkaa, joka karkasi nopeasti käsistä.

Tein lisää tutkimusta ja löysin arkkitehtuurin ECS - Entity Component System, jota käytetään yleisesti peleissä. Tässä ECS:n edut:

  • data on erotettu logiikasta;
  • koostumus perinnön sijaan;
  • tietokeskeinen arkkitehtuuri.

ECS:lle on ominaista kolme peruskäsitettä:

  • entiteetit - objektin tyyppi, johon tunniste viittaa (se voi olla pelaaja, pallo tai jokin muu);
  • komponentit - kokonaisuudet koostuvat niistä. Esimerkki - renderöintikomponentti, sijainnit ja muut. Nämä ovat tietovarastoja;
  • järjestelmät - ne käyttävät sekä objekteja että komponentteja sekä sisältävät käyttäytymistä ja logiikkaa, jotka perustuvat näihin tietoihin. Esimerkki on renderöintijärjestelmä, joka iteroi läpi kaikki entiteetit renderöintikomponenteilla ja tekee hahmontamisen.

Tutkittuaan sitä kävi selväksi, että ECS ratkaisee seuraavat ongelmat:

  • asettelun käyttäminen perinnön sijasta kokonaisuuksien järjestämiseen systeemisesti;
  • päästä eroon koodisekalaista ohjausjärjestelmien avulla;
  • käyttämällä menetelmiä, kuten is_build_mode, pitämään rautalankalogiikka samassa paikassa - renderöintijärjestelmässä.

Näin tapahtui ECS:n käyttöönoton jälkeen.

resurssit -> tässä on kaikki omaisuus (kuvat)
src
- komponentit
-position.rs
— person.rs
- tennis_court.rs
- floor.rs
- wireframe.rs
- mouse_tracked.rs
- resurssit
-hiiri.rs
- järjestelmät
- rendering.rs
- vakiot.rs
- utils.rs
- world_factory.rs -> maailman tehdastoiminnot
— main.rs -> pääsilmukka

Osoitamme ihmisiä tuomioistuimiin

ECS on helpottanut elämää. Nyt minulla oli systemaattinen tapa lisätä dataa entiteettiin ja lisätä logiikkaa näiden tietojen perusteella. Ja tämä puolestaan ​​mahdollisti ihmisten jakautumisen tuomioistuinten kesken.

Mitä olen tehnyt:

  • lisätyt tiedot henkilölle määrätyistä tuomioistuimista;
  • lisäsi tietoja hajautetuista ihmisistä TennisCourtiin;
  • lisätty CourtChoosingSystem, jonka avulla voit analysoida ihmisiä ja tuomioistuimia, havaita käytettävissä olevat kentät ja jakaa pelaajia niille;
  • lisätty PersonMovementSystem, joka etsii tuomioistuimiin määrätyt henkilöt, ja jos he eivät ole paikalla, lähettää ihmiset sinne, missä heidän on oltava.

Rustin pelaaminen 24 tunnissa: henkilökohtainen kehityskokemus

Yhteenvetona

Nautin todella työskentelystä tämän yksinkertaisen pelin parissa. Lisäksi olen iloinen, että käytin sen kirjoittamiseen Rustia, koska:

  • Ruoste antaa sinulle mitä tarvitset;
  • siinä on erinomainen dokumentaatio, ruoste on melko tyylikäs;
  • konsistenssi on viileä;
  • sinun ei tarvitse turvautua kloonaamiseen, kopiointiin tai muihin vastaaviin toimiin, mitä tein usein C++:ssa;
  • Vaihtoehdot ovat erittäin helppokäyttöisiä ja käsittelevät virheitä erittäin hyvin;
  • jos projekti pystyttiin kääntämään, niin se toimii 99% ajasta ja juuri niin kuin pitääkin. Mielestäni kääntäjän virheilmoitukset ovat parhaita näkemiäni.

Pelin kehitys Rustissa on vasta alussa. Mutta siellä on jo vakaa ja melko suuri yhteisö, joka pyrkii avaamaan Rustin kaikille. Siksi katson kielen tulevaisuuteen optimistisesti ja odotan innolla yhteisen työmme tuloksia.

Skillbox suosittelee:

Lähde: will.com

Lisää kommentti